From ecd88b2e27db5074dd6e2071861ba7d6cfea7d8f Mon Sep 17 00:00:00 2001 From: "pakintada@gmail.com" Date: Sun, 21 Jan 2024 15:18:33 +0700 Subject: [PATCH] fix show toppingset unmatch index --- .../src/app/core/services/recipe.service.ts | 10 + .../recipe-details.component.ts | 201 ++++++++++++------ .../recipe-list/recipe-list.component.ts | 2 +- .../recipe-topping.component.ts | 51 ++++- server/data/data.go | 2 +- server/routers/recipe.go | 28 +++ 6 files changed, 218 insertions(+), 76 deletions(-) diff --git a/client/src/app/core/services/recipe.service.ts b/client/src/app/core/services/recipe.service.ts index 730d7b5..bd0ad3d 100644 --- a/client/src/app/core/services/recipe.service.ts +++ b/client/src/app/core/services/recipe.service.ts @@ -274,4 +274,14 @@ export class RecipeService { } ); } + + async getRawRecipeOfProductCode(country: string, filename: string, productCode: string): Promise> { + return this._httpClient.get<{}>( + environment.api + '/recipes/' + country + '/' + filename + '/' + productCode + '/raw_full', + { + withCredentials: true, + responseType: 'json', + } + ); + } } diff --git a/client/src/app/features/recipes/recipe-details/recipe-details.component.ts b/client/src/app/features/recipes/recipe-details/recipe-details.component.ts index 8f3e030..a03055c 100644 --- a/client/src/app/features/recipes/recipe-details/recipe-details.component.ts +++ b/client/src/app/features/recipes/recipe-details/recipe-details.component.ts @@ -2,7 +2,7 @@ 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 { 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'; @@ -20,28 +20,29 @@ 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 - ] + 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'; @@ -56,7 +57,7 @@ export class RecipeDetailsComponent implements OnInit { recipeOriginalDetail!: typeof this.recipeDetailForm.value; - commit_msg :string = ""; + commit_msg: string = ''; // department: string = this._route.parent!.snapshot.params['department']; @@ -86,20 +87,21 @@ export class RecipeDetailsComponent implements OnInit { disable: false, }); - repl = [] - tpl = [] + 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$ = ( + await this._recipeService.getRecipeDetail(this.productCode) + ).pipe(first()); this.recipeDetail$.subscribe((detail) => { - // console.log('Recipe Detail', detail); this.recipeDetailForm.patchValue(detail); @@ -107,18 +109,41 @@ export class RecipeDetailsComponent implements OnInit { 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._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) => { + ( + 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 @@ -145,32 +170,57 @@ export class RecipeDetailsComponent implements OnInit { console.log('confirm save'); // get username - let username:string = "" + 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, - // isShow: null, - // disable: null, - recipes: [ - ...(this.repl.length <= 0 ? [] : this.repl) - ], - ToppingSet: [ - ...(this.tpl.length <= 0 ? [] : this.tpl) - ] - } - + 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)], + }; // TODO: update value in targeted recipe console.log('to_send', to_send); @@ -182,14 +232,11 @@ export class RecipeDetailsComponent implements OnInit { } ); console.log('Sending changes'); - void this._router.navigate(['/'+this.department+'/recipes']); - - - + void this._router.navigate(['/' + this.department + '/recipes']); }, }; - onKeyUpCommitMsg(e: any){ + onKeyUpCommitMsg(e: any) { this.commit_msg = e.target.value; } @@ -198,7 +245,7 @@ export class RecipeDetailsComponent implements OnInit { message: 'Do you want to close without saving?', confirmCallBack: () => { console.log('confirm close'); - this._router.navigate(['/'+this.department+'/recipes']); + this._router.navigate(['/' + this.department + '/recipes']); }, }; @@ -206,7 +253,7 @@ export class RecipeDetailsComponent implements OnInit { if (this.isValueChanged) { this.showConfirmSaveModal.emit(true); } else { - this._router.navigate(['/'+this.department+'/recipes']); + this._router.navigate(['/' + this.department + '/recipes']); } } @@ -214,7 +261,7 @@ export class RecipeDetailsComponent implements OnInit { if (this.isValueChanged) { this.showConfirmCloseModal.emit(true); } else { - this._router.navigate(['/'+this.department+'/recipes']); + this._router.navigate(['/' + this.department + '/recipes']); } } @@ -225,9 +272,21 @@ export class RecipeDetailsComponent implements OnInit { } onRecipeListFormChange(repl: unknown[]) { - console.log('Recipe List Form Changed', repl); + // 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]); + } + } + + // console.log('Recipe List Form Changed', this.repl, this.tpl); this.isValueChanged ||= repl != undefined; } @@ -235,16 +294,16 @@ export class RecipeDetailsComponent implements OnInit { // 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); + isEditable() { + return this._userService + .getCurrentUser()! + .permissions.includes(UserPermissions.EDITOR); } - onProductCodeChange(event: any) { - if(event.target.value != ""){ + if (event.target.value != '') { this.changedProductCode = event.target.value; } } @@ -252,10 +311,10 @@ export class RecipeDetailsComponent implements OnInit { // Submenus selectedSubProductCode: string | undefined = undefined; hasSubmenu = () => this.submenus != null && this.submenus!.length > 0; - listSubMenuProductcodes = () => this.submenus!.map((recipe) => recipe.productCode); + listSubMenuProductcodes = () => + this.submenus!.map((recipe) => recipe.productCode); selectSubmenu(productCode: string) { - if (this.selectedSubProductCode == productCode) { this.selectedSubProductCode = undefined; console.log('Unselected submenu', productCode); @@ -265,4 +324,6 @@ export class RecipeDetailsComponent implements OnInit { this.selectedSubProductCode = productCode; console.log('Selected submenu', productCode); } + + } diff --git a/client/src/app/features/recipes/recipe-details/recipe-list/recipe-list.component.ts b/client/src/app/features/recipes/recipe-details/recipe-list/recipe-list.component.ts index 3b3d905..21749fe 100644 --- a/client/src/app/features/recipes/recipe-details/recipe-list/recipe-list.component.ts +++ b/client/src/app/features/recipes/recipe-details/recipe-list/recipe-list.component.ts @@ -423,7 +423,7 @@ export class RecipeListComponent implements OnInit { return inRange(8111, 8130, convertFromInterProductCode(materialId)); }; - getToppingSlotNumber = (mat: number) => convertFromInterProductCode(mat) - 8110; + getToppingSlotNumber = (mat: number) => convertFromInterProductCode(mat) - 8110 - 1 ; isStringParamExist = (i: number) => { let rawStringParam = this.recipeListData.at(i).get('StringParam')?.value; diff --git a/client/src/app/features/recipes/recipe-details/recipe-topping/recipe-topping.component.ts b/client/src/app/features/recipes/recipe-details/recipe-topping/recipe-topping.component.ts index 4b1c807..4378166 100644 --- a/client/src/app/features/recipes/recipe-details/recipe-topping/recipe-topping.component.ts +++ b/client/src/app/features/recipes/recipe-details/recipe-topping/recipe-topping.component.ts @@ -74,10 +74,10 @@ export class RecipeToppingComponent implements OnInit { ) ).subscribe((data) => { this._toppingSetOriginalArray = data; - // console.log('ToppingSet', data); + console.log('ToppingSet', data, this.index, data.length >= this.index!, data[0]); // check length of toppingList if in range with given index - if (this.index && data.length >= this.index!) { + if (data.length >= this.index!) { this.toppingList.push( this._formBuilder.group({ isUse: data[this.index!].isUse, @@ -87,6 +87,8 @@ export class RecipeToppingComponent implements OnInit { }) ); } + + console.log('ToppingSet', this.toppingList); }); // get all topping @@ -119,8 +121,25 @@ export class RecipeToppingComponent implements OnInit { // emit value changes this.toppingForm.valueChanges.subscribe((value) => { - console.log('emit value', value, 'for index: ', this.index! - 1); - this.toppingSetChange.emit([this.index! - 1, this.toppingList.value]); + console.log('emit value', value, 'for index: ', this.index! ); + + // transform data + this.toppingList.value.forEach((value: any) => { + value = this.transformToppingsetStructure(value); + }); + + // extend lifetime of data + let newMapping = this.toppingList.value.map((value: { + isUse: boolean; + groupID: string; + defaultIDSelect: string; + ListGroupID: string[]; + }) => this.transformToppingsetStructure(value)); + + // add debug here! + console.log('newMapping', newMapping); + + this.toppingSetChange.emit([this.index! , newMapping]); }); } @@ -156,4 +175,28 @@ export class RecipeToppingComponent implements OnInit { } }); } + + transformToppingsetStructure = (value: any) => { + + if(value.defaultIDSelect == null){ + value.defaultIDSelect = 0; + } else { + value.defaultIDSelect = parseInt(value.defaultIDSelect); + } + + if(!Array.isArray(value.ListGroupID)){ + value.ListGroupID = [parseInt(value.groupID), 0, 0, 0]; + } + + if(value.groupID == null){ + value.groupID = '0'; + } + + return { + isUse: value.isUse, + groupID: value.groupID, + defaultIDSelect: value.defaultIDSelect, + ListGroupID: value.ListGroupID, + }; + }; } diff --git a/server/data/data.go b/server/data/data.go index a74285e..2ec5073 100644 --- a/server/data/data.go +++ b/server/data/data.go @@ -365,7 +365,7 @@ func (d *Data) SetValuesToRecipe(base_recipe []models.Recipe01, recipe models.Re for k, v := range recipe01_Map { if !reflect.DeepEqual(base_recipe01_Map[k], v) { - d.taoLogger.Log.Debug("SetValuesToRecipe", zap.Any("key", k)) + d.taoLogger.Log.Debug("SetValuesToRecipe", zap.Any("key", k), zap.Any("old", base_recipe01_Map[k]), zap.Any("new", v)) base_recipe01_Map[k] = v } } diff --git a/server/routers/recipe.go b/server/routers/recipe.go index f0a5886..385ef7b 100644 --- a/server/routers/recipe.go +++ b/server/routers/recipe.go @@ -61,6 +61,9 @@ func (rr *RecipeRouter) Route(r chi.Router) { r.Get("/{country}/{filename}/{product_code}/submenus", rr.getSubmenusOfRecipe) + // fetch raw recipe json + r.Get("/{country}/{filename}/{product_code}/raw_full", rr.getRawRecipeOfProductCode) + r.Get("/{country}/{filename}/json", rr.getRecipeJson) r.Post("/edit/{country}/{filename}", rr.updateRecipe) @@ -546,6 +549,31 @@ func (rr *RecipeRouter) getSubmenusOfRecipe(w http.ResponseWriter, r *http.Reque json.NewEncoder(w).Encode(submenus) } +// get raw recipe +func (rr *RecipeRouter) getRawRecipeOfProductCode(w http.ResponseWriter, r *http.Request) { + + countryID := chi.URLParam(r, "country") + filename := chi.URLParam(r, "filename") + productCode := chi.URLParam(r, "product_code") + + // debug + rr.taoLogger.Log.Debug("RecipeRouter.getRawRecipeOfProductCode", zap.Any("countryID", countryID), zap.Any("filename", filename), zap.Any("productCode", productCode)) + + w.Header().Add("Content-Type", "application/json") + + recipe, err := rr.data.GetRecipe01ByProductCode(filename, countryID, productCode) + + if err != nil { + http.Error(w, err.Error(), http.StatusNotFound) + return + } + + // return recipe + rr.taoLogger.Log.Debug("RecipeRouter.getRawRecipeOfProductCode", zap.Any("recipe", recipe)) + + json.NewEncoder(w).Encode(recipe) +} + func (rr *RecipeRouter) doMergeJson(w http.ResponseWriter, r *http.Request) { // TODO: v2, change to binary instead if !APIhandler(w, r) {