355 lines
11 KiB
TypeScript
355 lines
11 KiB
TypeScript
import { CommonModule, DatePipe } from '@angular/common';
|
|
import { Component, EventEmitter, OnInit } from '@angular/core';
|
|
import { FormBuilder, FormsModule, ReactiveFormsModule } from '@angular/forms';
|
|
import { ActivatedRoute, Router, RouterLink } from '@angular/router';
|
|
import { Observable, first, map } from 'rxjs';
|
|
import { RecipeService } from 'src/app/core/services/recipe.service';
|
|
import { ConfirmModal } from 'src/app/shared/modal/confirm/confirm-modal.component';
|
|
import { animate, style, transition, trigger } from '@angular/animations';
|
|
import { RecipeListComponent } from './recipe-list/recipe-list.component';
|
|
import {
|
|
Recipe01,
|
|
RecipeDetail,
|
|
RecipeDetailMat,
|
|
Topping,
|
|
ToppingSet,
|
|
} from 'src/app/core/models/recipe.model';
|
|
import { ActionRecord } from 'src/app/shared/actionRecord/actionRecord';
|
|
import { UserService } from 'src/app/core/services/user.service';
|
|
import { UserPermissions } from 'src/app/core/auth/userPermissions';
|
|
import { ToppingService } from 'src/app/core/services/topping.service';
|
|
|
|
import { copy, transformToTSV } from 'src/app/shared/helpers/copy';
|
|
import { isEqual } from 'lodash';
|
|
|
|
@Component({
|
|
selector: 'app-recipe-details',
|
|
templateUrl: './recipe-details.component.html',
|
|
standalone: true,
|
|
animations: [
|
|
trigger('inOutAnimation', [
|
|
transition(':enter', [
|
|
style({ opacity: 0 }),
|
|
animate('1s ease-out', style({ opacity: 1 })),
|
|
]),
|
|
]),
|
|
],
|
|
imports: [
|
|
CommonModule,
|
|
RouterLink,
|
|
ReactiveFormsModule,
|
|
ConfirmModal,
|
|
DatePipe,
|
|
RecipeListComponent,
|
|
FormsModule,
|
|
],
|
|
})
|
|
export class RecipeDetailsComponent implements OnInit {
|
|
title: string = 'Recipe Detail';
|
|
|
|
recipeDetail$!: Observable<RecipeDetail>;
|
|
|
|
isLoaded: boolean = false;
|
|
isMatLoaded: boolean = false;
|
|
|
|
actionRecord: ActionRecord<RecipeDetail | RecipeDetailMat> =
|
|
new ActionRecord();
|
|
|
|
recipeOriginalDetail!: typeof this.recipeDetailForm.value;
|
|
|
|
commit_msg: string = '';
|
|
|
|
//
|
|
department: string = this._route.parent!.snapshot.params['department'];
|
|
|
|
constructor(
|
|
private _formBuilder: FormBuilder,
|
|
private _route: ActivatedRoute,
|
|
private _router: Router,
|
|
private _recipeService: RecipeService,
|
|
private _toppingService: ToppingService,
|
|
private _userService: UserService
|
|
) {}
|
|
|
|
productCode!: any;
|
|
changedProductCode: string | undefined = undefined;
|
|
|
|
recipeDetailForm = this._formBuilder.group({
|
|
productCode: '',
|
|
name: '',
|
|
otherName: '',
|
|
description: '',
|
|
otherDescription: '',
|
|
lastModified: new Date(),
|
|
price: 0,
|
|
isUse: false,
|
|
isShow: false,
|
|
disable: false,
|
|
});
|
|
|
|
repl = [];
|
|
tpl = [];
|
|
|
|
toppingSet: ToppingSet[] | null = null;
|
|
submenus: Recipe01[] | null = null;
|
|
|
|
rawRecipe: {} | undefined | null = undefined;
|
|
|
|
async ngOnInit() {
|
|
this.productCode = this._route.snapshot.params['productCode'];
|
|
|
|
this.recipeDetail$ = (
|
|
await this._recipeService.getRecipeDetail(this.productCode)
|
|
).pipe(first());
|
|
this.recipeDetail$.subscribe((detail) => {
|
|
// console.log('Recipe Detail', detail);
|
|
|
|
this.recipeDetailForm.patchValue(detail);
|
|
this.isLoaded = true;
|
|
this.recipeOriginalDetail = { ...this.recipeDetailForm.getRawValue() };
|
|
});
|
|
|
|
this._recipeService
|
|
.getSubMenus(
|
|
await this._recipeService.getCurrentCountry(),
|
|
this._recipeService.getCurrentFile(),
|
|
this.productCode
|
|
)
|
|
.subscribe((data) => {
|
|
console.log('Submenus', data);
|
|
this.submenus = data;
|
|
});
|
|
|
|
this.recipeDetailForm.valueChanges.subscribe(this.onRecipeDetailFormChange);
|
|
|
|
(
|
|
await this._toppingService.getToppingsOfRecipe(
|
|
this.department,
|
|
this._recipeService.getCurrentFile(),
|
|
this.productCode
|
|
)
|
|
).subscribe((data) => {
|
|
this.toppingSet = data;
|
|
// console.log('Toppings', data);
|
|
});
|
|
|
|
// get full raw value of this recipe
|
|
(
|
|
await this._recipeService.getRawRecipeOfProductCode(
|
|
this.department,
|
|
this._recipeService.getCurrentFile(),
|
|
this.productCode
|
|
)
|
|
).subscribe((data) => {
|
|
console.log('Raw Recipe', data);
|
|
this.rawRecipe = data;
|
|
});
|
|
|
|
// snap recipe detail form value
|
|
|
|
this.actionRecord.registerOnAddAction((currAction, allAction) => {
|
|
if (currAction.type === 'recipeListData') {
|
|
switch (currAction.action) {
|
|
case 'add':
|
|
break;
|
|
case 'delete':
|
|
break;
|
|
}
|
|
}
|
|
console.log('Action Record', allAction);
|
|
});
|
|
}
|
|
|
|
showConfirmSaveModal: EventEmitter<boolean> = new EventEmitter<boolean>();
|
|
showConfirmCloseModal: EventEmitter<boolean> = new EventEmitter<boolean>();
|
|
|
|
confirmSave = {
|
|
title: 'The changes detected!',
|
|
message: 'Do you want to save changes?',
|
|
confirmCallBack: async () => {
|
|
console.log('confirm save');
|
|
|
|
// get username
|
|
let username: string = '';
|
|
|
|
username = this._userService.getCurrentUser()!.name;
|
|
|
|
// diff with rawValue, then send
|
|
|
|
let to_send = {
|
|
edit_by: username,
|
|
commit_msg: this.commit_msg,
|
|
productCode:
|
|
this.changedProductCode == undefined
|
|
? this.productCode
|
|
: this.changedProductCode,
|
|
name:
|
|
this.recipeDetailForm.getRawValue().name !=
|
|
this.recipeOriginalDetail.name
|
|
? this.recipeDetailForm.getRawValue().name
|
|
: this.recipeOriginalDetail.name,
|
|
otherName:
|
|
this.recipeDetailForm.getRawValue().otherName !=
|
|
this.recipeOriginalDetail.otherName
|
|
? this.recipeDetailForm.getRawValue().otherName
|
|
: this.recipeOriginalDetail.otherName,
|
|
description:
|
|
this.recipeDetailForm.getRawValue().description !=
|
|
this.recipeOriginalDetail.description
|
|
? this.recipeDetailForm.getRawValue().description
|
|
: this.recipeOriginalDetail.description,
|
|
otherDescription:
|
|
this.recipeDetailForm.getRawValue().otherDescription !=
|
|
this.recipeOriginalDetail.otherDescription
|
|
? this.recipeDetailForm.getRawValue().otherDescription
|
|
: this.recipeOriginalDetail.otherDescription,
|
|
LastChange:
|
|
this.recipeDetailForm.getRawValue().lastModified !=
|
|
this.recipeOriginalDetail.lastModified
|
|
? this.recipeDetailForm.getRawValue().lastModified
|
|
: this.recipeOriginalDetail.lastModified,
|
|
price:
|
|
this.recipeDetailForm.getRawValue().price !=
|
|
this.recipeOriginalDetail.price
|
|
? this.recipeDetailForm.getRawValue().price
|
|
: this.recipeOriginalDetail.price,
|
|
isUse: (this.rawRecipe as any).isUse,
|
|
isShow: (this.rawRecipe as any).isShow,
|
|
disable: (this.rawRecipe as any).disable,
|
|
recipes: [...(this.repl.length <= 0 ? [] : this.repl)],
|
|
SubMenu: [...(this.rawRecipe! as any).SubMenu!],
|
|
ToppingSet: [...(this.rawRecipe as any).ToppingSet],
|
|
};
|
|
|
|
this.concatNoEditKeyToMap(this.rawRecipe, to_send);
|
|
|
|
console.log('to_send', to_send);
|
|
this._recipeService.editChanges(
|
|
await this._recipeService.getCurrentCountry(this.department),
|
|
this._recipeService.getCurrentFile(),
|
|
{
|
|
...to_send,
|
|
}
|
|
);
|
|
console.log('Sending changes');
|
|
void this._router
|
|
.navigate(['/' + this.department + '/recipes'])
|
|
.then(() => {
|
|
window.location.reload();
|
|
});
|
|
},
|
|
};
|
|
|
|
onKeyUpCommitMsg(e: any) {
|
|
this.commit_msg = e.target.value;
|
|
}
|
|
|
|
confirmClose = {
|
|
title: 'The changes will be lost!',
|
|
message: 'Do you want to close without saving?',
|
|
confirmCallBack: () => {
|
|
console.log('confirm close');
|
|
this._router.navigate(['/' + this.department + '/recipes']);
|
|
},
|
|
};
|
|
|
|
onPressConfirmSave() {
|
|
if (this.isValueChanged) {
|
|
this.showConfirmSaveModal.emit(true);
|
|
} else {
|
|
this._router.navigate(['/' + this.department + '/recipes']);
|
|
}
|
|
}
|
|
|
|
onPressConfirmClose() {
|
|
if (this.isValueChanged) {
|
|
this.showConfirmCloseModal.emit(true);
|
|
} else {
|
|
this._router.navigate(['/' + this.department + '/recipes']);
|
|
}
|
|
}
|
|
|
|
isValueChanged: boolean = false;
|
|
|
|
onRecipeDetailFormChange(recipeDetail: typeof this.recipeDetailForm.value) {
|
|
// console.log('Recipe Detail Form Changed', recipeDetail);
|
|
}
|
|
|
|
onRecipeListFormChange(repl: unknown[]) {
|
|
// console.log('Recipe List Form Changed', repl);
|
|
this.repl = repl[1] as never[];
|
|
this.tpl = repl[0] as never[];
|
|
|
|
// check length of toppinglist
|
|
console.log(
|
|
'tpl length',
|
|
this.tpl.length,
|
|
'original length',
|
|
(this.rawRecipe! as any).ToppingSet.length
|
|
);
|
|
for (let ti = 0; ti < this.tpl.length; ti++) {
|
|
// check at the same index
|
|
if (!isEqual(this.tpl[ti][0], (this.rawRecipe as any).ToppingSet[ti])) {
|
|
console.log(
|
|
'topping list changed',
|
|
ti,
|
|
this.tpl[ti][0],
|
|
(this.rawRecipe as any).ToppingSet[ti]
|
|
);
|
|
// update raw recipe
|
|
(this.rawRecipe as any).ToppingSet[ti] = this.tpl[ti][0];
|
|
console.log(
|
|
'after update topping',
|
|
(this.rawRecipe as any).ToppingSet[ti]
|
|
);
|
|
}
|
|
}
|
|
|
|
// console.log('Recipe List Form Changed', this.repl, this.tpl);
|
|
this.isValueChanged ||= repl != undefined;
|
|
}
|
|
|
|
onToppingListChange(tpl: unknown[]) {
|
|
// console.log('Topping List Form Changed', tpl);
|
|
this.tpl = tpl as never[];
|
|
this.isValueChanged ||= tpl != undefined;
|
|
}
|
|
|
|
isEditable() {
|
|
return this._userService
|
|
.getCurrentUser()!
|
|
.permissions.includes(UserPermissions.EDITOR);
|
|
}
|
|
|
|
onProductCodeChange(event: any) {
|
|
if (event.target.value != '') {
|
|
this.changedProductCode = event.target.value;
|
|
}
|
|
}
|
|
|
|
// Submenus
|
|
selectedSubProductCode: string | undefined = undefined;
|
|
hasSubmenu = () => this.submenus != null && this.submenus!.length > 0;
|
|
listSubMenuProductcodes = () =>
|
|
this.submenus!.map((recipe) => recipe.productCode);
|
|
|
|
selectSubmenu(productCode: string) {
|
|
if (this.selectedSubProductCode == productCode) {
|
|
this.selectedSubProductCode = undefined;
|
|
console.log('Unselected submenu', productCode);
|
|
return;
|
|
}
|
|
|
|
this.selectedSubProductCode = productCode;
|
|
console.log('Selected submenu', productCode);
|
|
}
|
|
|
|
// concat remaining unused keys
|
|
concatNoEditKeyToMap(source: any, target: any) {
|
|
for (const key of Object.keys(source)) {
|
|
if (!Object.keys(target).includes(key)) {
|
|
target[key] = source[key];
|
|
}
|
|
}
|
|
}
|
|
}
|