RomainMarecat/slate

View on GitHub
src/shared/admin/product/product-edit/product-edit.component.ts

Summary

Maintainability
C
1 day
Test Coverage
File `product-edit.component.ts` has 330 lines of code (exceeds 250 allowed). Consider refactoring.
import { Component, OnInit, TemplateRef, ViewChild } from '@angular/core';
import { FormArray, FormGroup } from '@angular/forms';
import { ActivatedRoute, Router } from '@angular/router';
import { DocumentReference } from '@firebase/firestore-types';
import { UploadTaskSnapshot } from '@firebase/storage-types';
import { TableColumn } from '@swimlane/ngx-datatable';
import { debounceTime, take } from 'rxjs/operators';
import { Attribute } from '../../../attribute/attribute';
import { AttributeService } from '../../../attribute/attribute.service';
import { Category } from '../../../category/category';
import { CategoryService } from '../../../category/category.service';
import { ImageProductComponent } from '../../../media/cloudinary/image-product/image-product.component';
import { Media } from '../../../media/media';
import { Offer } from '../../../offer/offer';
import { Partner } from '../../../partner/partner';
import { PartnerService } from '../../../partner/partner.service';
import { AlertService } from '../../../popup/alert.service';
import { Product } from '../../../product/shared/product';
import { ProductService } from '../../../product/shared/product.service';
import { StringService } from '../../../util/string.service';
import { OfferService } from '../../shared/offer/offer.service';
import { ProductFormType } from '../../shared/product/form-product';
 
`ProductEditComponent` has 40 functions (exceeds 20 allowed). Consider refactoring.
@Component({
selector: 'app-product-edit',
templateUrl: './product-edit.component.html',
styleUrls: ['./product-edit.component.scss']
})
export class ProductEditComponent implements OnInit {
form: FormGroup;
product: Product;
editorConfig: any;
medias: Media[] = [];
partners: Partner[] = [];
readonly headerHeight = 50;
readonly rowHeight = 50;
columns: TableColumn[];
categories: Category[] = [];
selected: Category[] = [];
isLoading = false;
@ViewChild('checkboxHeader', {static: false}) checkboxHeader: TemplateRef<any>;
@ViewChild('checkboxCell', {static: false}) checkboxCell: TemplateRef<any>;
@ViewChild(ImageProductComponent, {static: false}) imageProductComponent: ImageProductComponent;
imageStorageConfig: any;
downloadURL: string;
_attributesModel: any[] = [];
isSaving = false;
 
constructor(private activatedRoute: ActivatedRoute,
private router: Router,
private productService: ProductService,
private alertService: AlertService,
private categoryService: CategoryService,
private attributeService: AttributeService,
private partnerService: PartnerService,
private offerService: OfferService) {
}
 
/**
* Init component
*/
ngOnInit() {
this.createForm();
this.getProduct();
this.createColumns();
this.createEditorConfig();
this.getCategories();
this.getAttributes();
this.getPartners();
}
 
/**
* Create image configuration
*/
createImageStorageConfig() {
this.imageStorageConfig = {
model: this.product.key,
alt: this.product.name,
};
}
 
/**
* product form
*/
createForm() {
const formType = new ProductFormType(this.product);
this.form = formType.getForm();
}
 
/**
* get product from route key
*/
getProduct() {
this.activatedRoute.params.subscribe((value: {key: string}) => {
if (value.key) {
const key = value.key;
this.productService.getProduct(key)
.subscribe((product: Product) => {
this.product = product;
this.createForm();
this.createImageStorageConfig();
this.product.offers.forEach((offerKey: string) => {
this.offerService.getOffer(offerKey).subscribe((offer: Offer) => {
this.offers.push(ProductFormType.newOffer(offer));
});
});
setTimeout(() => {
this.observeUpdate();
}, 2000);
});
}
});
}
 
/**
* observe form change
*/
observeUpdate() {
this.form.valueChanges
.pipe(
debounceTime(800)
)
.subscribe((value) => {
if (value.name) {
const slug = StringService.slugify(value.name);
this.form.patchValue({name: value.name, slug, alias: value.name});
}
});
}
 
/**
* create all category columns
*/
createColumns() {
this.columns = [{
width: 50,
sortable: false,
canAutoResize: false,
draggable: false,
resizeable: false,
cellTemplate: this.checkboxCell,
headerTemplate: this.checkboxHeader,
}, {
prop: 'key',
name: 'key',
flexGrow: 1
}, {
prop: 'name',
name: 'name',
flexGrow: 1
}, {
prop: 'published',
name: 'published',
flexGrow: 1
}];
}
 
/**
* editor config for description product
*/
createEditorConfig() {
this.editorConfig = {
editable: true,
spellcheck: false,
// 'height': '5rem',
minHeight: '10rem',
placeholder: 'Contenu de la description...',
translate: 'no',
toolbar: []
};
}
 
/**
* images array changes function of emitter
*/
onImagesChange(images: Array<string>) {
this.form.patchValue({
images
});
this.alertService.toast('media order changed');
}
 
/**
* image change function of emitter
*/
onImageChange(media: Media) {
this.medias.push(media);
this.form.patchValue({
images: this.medias.map((image: Media) => image.key)
});
this.alertService.toast('media saved');
}
 
onImageRefChanged(task: UploadTaskSnapshot) {
task.ref.getDownloadURL().then((downloadURL => {
this.downloadURL = downloadURL;
}),
(err) => {
this.alertService.show(err);
});
}
 
/**
* reset all form control
*/
reset() {
this.medias = [];
this.selected = [];
this.imageProductComponent.clearUpload();
this.form.reset({
name: '',
translations: {
fr: ''
},
offers: [],
description: '',
published: true,
images: [],
});
}
 
/**
* save the product and their offers
*/
saveProduct() {
this.isSaving = true;
if (this.form.valid) {
const offers = (this.form.value).offers;
this.product = {
...this.product,
...this.form.value,
...{offers: offers.filter((o) => o.key && o.key !== '').map((offer) => offer.key)},
...{keywords: this.form.controls.name.value.toLowerCase().split(' ')}
};
this.updateProduct(offers);
}
}
 
updateProduct(offers: Offer[]) {
if (this.product.key) {
if (this.product.published === true) {
this.product.published_at = Math.floor(Date.now() / 1000) as unknown as any;
}
this.productService.updateProduct(this.product)
.subscribe((doc) => {
this.isSaving = false;
this.saveOffer(offers, {id: this.product.key});
}, (err) => {
this.isSaving = false;
this.addError(err);
});
} else {
this.productService.createProduct(this.product)
.subscribe((doc: DocumentReference) => {
this.isSaving = false;
this.saveOffer(this.form.get('offers').value, doc);
}, (err) => {
this.isSaving = false;
this.addError(err);
});
}
}
 
/**
* save an offer in db
*/
saveOffer(offers: Offer[], doc: {id: string}) {
offers.forEach((offer: Offer) => {
// Set product value id
offer.product = doc.id;
 
if (offer.key) {
this.offerService.updateOffer(offer).then(() => {
this.addFinally();
}, (err) => this.addError(err));
} else {
offer.published_at = Math.floor(Date.now() / 1000) as unknown as any;
this.offerService.createOffer(offer).then((res) => {
this.addProductOffer(res.id);
}, (err) => this.addError(err));
}
});
}
 
/**
* delete an offer
*/
deleteOffer(index: number) {
this.offers.removeAt(index);
}
 
/**
* add a new offer in form Array control
*/
addProductOffer(key: string) {
this.product.offers.push(key);
this.productService.updateProduct(this.product).subscribe((doc) => {
this.addFinally();
}, (err) => this.addError(err));
}
 
/**
* error function to toast error on all subcriber
*/
addError(err) {
this.alertService.toast(`product error ${err}`);
}
 
/**
* After the product saved
*/
addFinally() {
this.alertService.toast(`product saved ${this.product.translations.fr}`);
this.reset();
this.router.navigate(['/admin/product']);
}
 
/**
* subscribe to attributes
*/
getAttributes() {
this.attributeService.getAttributes()
.pipe(
take(1)
)
.subscribe((attributes: Attribute[]) => {
this._attributesModel = attributes.map((attribute: Attribute) => {
return {label: attribute.translations.fr, options: attribute.terms};
});
});
}
 
/**
* subscribe to categories
*/
getCategories() {
this.categoryService.getCategories()
.subscribe((categories: Category[]) => {
this.categories = categories;
});
}
 
/**
* On select add reinit and add category in selection array
*/
onSelect({selected}) {
this.selected = [];
this.selected.push(...selected);
}
 
/**
* Add a new category in product
*/
addCategory() {
this.selected.forEach((category: Category) => {
this.form.patchValue({category: category.key});
this.alertService.toast('categorie selectionnée');
});
}
 
/**
* subscribe to partners list
*/
getPartners() {
this.partnerService.getPartners()
.subscribe((partners: Partner[]) => {
this.partners = partners;
});
}
 
/**
* push a ne offer in form array offers
*/
addOfferForm() {
if (this.product && typeof this.product.offers === 'undefined') {
this.product.offers = [];
}
this.offers.push(ProductFormType.newOffer());
}
 
/**
* get offers controls cast to FormArray
*/
get offers(): FormArray {
return this.form.get('offers') as FormArray;
}
 
get name() {
return this.form.get('name');
}
 
set name(name) {
this.form.patchValue({name});
}
 
get description() {
return this.form.get('description');
}
 
set description(description) {
this.form.patchValue({description});
}
 
get category() {
return this.form.get('category');
}
 
set category(category) {
this.form.patchValue({category});
}
 
get fr() {
return this.form.get('translations').get('fr');
}
 
set fr(fr) {
this.form.get('translations').patchValue({fr});
}
 
get published() {
return this.form.get('published');
}
 
set published(published) {
this.form.patchValue({published});
}
 
get attributes() {
return this.form.get('attributes');
}
 
set attributes(attributes) {
this.form.patchValue({attributes});
}
 
get attributesModel() {
return this._attributesModel;
}
 
set attributesModel(attributesModel) {
this._attributesModel = attributesModel;
}
}