update recipe detail and recipe detail list

This commit is contained in:
Kenta420 2023-11-24 17:47:44 +07:00
parent 8b45ed53ee
commit d52cad09fd
16 changed files with 947 additions and 458 deletions

View file

@ -1,16 +1,16 @@
<div class="p-4">
<form class="grid grid-cols-3 gap-4 mb-4" [formGroup]="recipeDetail">
<form class="grid grid-cols-3 gap-4 mb-4" [formGroup]="recipeDetailForm">
<div
class="block col-span-1 p-6 bg-white border border-gray-200 rounded-lg shadow"
>
<div *ngIf="isLoaded; else indicator" [@inOutAnimation]>
<div class="flex flex-wrap">
<h5 class="mb-2 text-xl font-bold text-gray-900">
{{ recipeDetail.value.name }}
{{ recipeDetailForm.getRawValue().name }}
</h5>
<h5 class="mb-2 px-3 text-xl font-bold text-gray-900">|</h5>
<h5 class="mb-2 text-xl font-bold text-gray-900">
{{ recipeDetail.value.otherName }}
{{ recipeDetailForm.getRawValue().otherName }}
</h5>
</div>
<div class="flex items-center mb-2">
@ -18,7 +18,8 @@
<p class="text-sm text-gray-500">Last Modify</p>
<p class="ml-2 text-sm text-gray-900">
{{
recipeDetail.value.lastModified | date : "dd/MM/yyyy HH:mm:ss"
recipeDetailForm.getRawValue().lastModified
| date : "dd/MM/yyyy HH:mm:ss"
}}
</p>
</div>
@ -109,11 +110,13 @@
</div>
</div>
<div
class="col-span-3 min-h-[500px] max-h-[500px] overflow-auto mb-4 rounded bg-white border border-gray-200 shadow"
class="col-span-3 overflow-auto mb-4 rounded bg-white border border-gray-200 shadow"
>
<app-recipe-list
[matRecipeList]="materialListIds$"
[parentForm]="recipeDetail"
[parentForm]="recipeDetailForm"
[productCode]="productCode"
[actionRecord]="actionRecord"
[recipeDetailOriginal]="recipeOriginalDetail"
></app-recipe-list>
</div>
<div class="grid grid-cols-2 gap-4 mb-4">

View file

@ -1,32 +1,25 @@
import { DatePipe, NgFor, NgIf } from '@angular/common';
import { CommonModule, DatePipe } from '@angular/common';
import { Component, EventEmitter, OnInit } from '@angular/core';
import {
FormArray,
FormControl,
FormGroup,
ReactiveFormsModule,
} from '@angular/forms';
import { FormBuilder, ReactiveFormsModule } from '@angular/forms';
import { ActivatedRoute, Router, RouterLink } from '@angular/router';
import { isEqual } from 'lodash';
import { BehaviorSubject, Subject, finalize, map } from 'rxjs';
import { Observable, first } 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 { MaterialService } from 'src/app/core/services/material.service';
import { RecipeMetaData, RecipeDetail } from 'src/app/shared/types/recipe';
import { RecipeListComponent } from './recipe-list/recipe-list.component';
import {
RecipeListComponent,
RecipeListDataFormGroup,
} from './recipe-list/recipe-list.component';
import { MatRecipe } from 'src/app/core/models/recipe.model';
RecipeDetail,
RecipeDetailMat,
} from 'src/app/core/models/recipe.model';
import { Action, ActionRecord } from 'src/app/shared/actionRecord/actionRecord';
import { isEqual } from 'lodash';
@Component({
selector: 'app-recipe-details',
templateUrl: './recipe-details.component.html',
standalone: true,
imports: [
NgIf,
NgFor,
CommonModule,
RouterLink,
ReactiveFormsModule,
ConfirmModal,
@ -44,88 +37,65 @@ import { MatRecipe } from 'src/app/core/models/recipe.model';
})
export class RecipeDetailsComponent implements OnInit {
title: string = 'Recipe Detail';
recipeMetaData: RecipeMetaData | null = null;
originalRecipeDetail: BehaviorSubject<RecipeDetail | null> =
new BehaviorSubject<RecipeDetail | null>(null);
matForRecipeList = this.originalRecipeDetail.pipe(
map((x) => x?.recipe.recipes)
);
recipeDetail$!: Observable<RecipeDetail>;
isLoaded: boolean = false;
isMatLoaded: boolean = false;
actionRecord: ActionRecord<RecipeDetail | RecipeDetailMat> =
new ActionRecord();
recipeOriginalDetail!: typeof this.recipeDetailForm.value;
constructor(
private _formBuilder: FormBuilder,
private _route: ActivatedRoute,
private _router: Router,
private _recipeService: RecipeService
) {}
recipeDetail = new FormGroup({
productCode: new FormControl<string>(''),
name: new FormControl<string>(''),
otherName: new FormControl<string>(''),
description: new FormControl<string>(''),
otherDescription: new FormControl<string>(''),
lastModified: new FormControl<Date>(new Date()),
price: new FormControl<number>(0),
isUse: new FormControl<boolean>(false),
isShow: new FormControl<boolean>(false),
disable: new FormControl<boolean>(false),
productCode!: string;
recipeDetailForm = this._formBuilder.group({
productCode: '',
name: '',
otherName: '',
description: '',
otherDescription: '',
lastModified: new Date(),
price: 0,
isUse: false,
isShow: false,
disable: false,
recipeListData: this._formBuilder.array([]),
});
materialListIds$: Subject<{
ids: number[];
matRecipeList: MatRecipe[];
}> = new Subject<{
ids: number[];
matRecipeList: MatRecipe[];
}>();
ngOnInit() {
this._recipeService
.getRecipesById(this._route.snapshot.params['productCode'])
.pipe(finalize(() => {}))
.subscribe(({ recipe, recipeMetaData }) => {
this.title = recipe.name + ' | ' + recipe.productCode;
this.recipeDetail.patchValue({
productCode: recipe.productCode,
name: recipe.name,
otherName: recipe.otherName,
description: recipe.Description,
otherDescription: recipe.otherDescription,
lastModified: recipe.LastChange,
price: recipe.cashPrice,
isUse: recipe.isUse,
isShow: recipe.isShow,
disable: recipe.disable,
});
this.originalRecipeDetail.next({
recipe: {
lastModified: recipe.LastChange,
productCode: recipe.productCode,
name: recipe.name,
otherName: recipe.otherName,
description: recipe.Description,
otherDescription: recipe.otherDescription,
price: recipe.cashPrice,
isUse: recipe.isUse,
isShow: recipe.isShow,
disable: recipe.disable,
},
recipes: recipe.recipes,
});
this.productCode = this._route.snapshot.params['productCode'];
const ids = recipe.recipes?.map((recipe) => recipe.materialPathId);
this.materialListIds$.next({
ids: ids || [],
matRecipeList: recipe.recipes || [],
});
this.recipeDetail$ = this._recipeService
.getRecipeDetail(this.productCode)
.pipe(first());
this.recipeDetail$.subscribe((detail) => {
this.recipeDetailForm.patchValue(detail);
this.isLoaded = true;
this.recipeOriginalDetail = { ...this.recipeDetailForm.getRawValue() };
});
this.recipeMetaData = recipeMetaData;
this.isLoaded = true;
});
// 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>();
@ -137,13 +107,13 @@ export class RecipeDetailsComponent implements OnInit {
confirmCallBack: () => {
console.log('confirm save');
// TODO: update value in targeted recipe
this._recipeService.editChanges(
this._recipeService.getCurrentCountry(),
this._recipeService.getCurrentFile(),
{
...this.recipeDetail,
}
);
// this._recipeService.editChanges(
// this._recipeService.getCurrentCountry(),
// this._recipeService.getCurrentFile(),
// {
// ...this.recipeDetail,
// }
// );
console.log('Sending changes');
this._router.navigate(['/recipes']);
},
@ -176,8 +146,8 @@ export class RecipeDetailsComponent implements OnInit {
get isValueChanged() {
return !isEqual(
this.recipeDetail.value,
this.originalRecipeDetail.getValue()?.recipe
this.recipeOriginalDetail,
this.recipeDetailForm.getRawValue()
);
}
}

View file

@ -1,7 +1,7 @@
<table class="table" [formGroup]="parentForm">
<thead>
<tr class="bg-gray-200">
<th class="px-6 py-3">Enable</th>
<th class="px-6 py-3">Action</th>
<th class="px-6 py-3">Material ID</th>
<th class="px-6 py-3">Material Name</th>
<th class="px-6 py-3">MixOrder</th>
@ -11,55 +11,57 @@
<th class="px-6 py-3">Syrup Gram</th>
<th class="px-6 py-3">Syrup Time</th>
<th class="px-6 py-3">Water Cold</th>
<th class="px-6 py-3">Water Hot</th>
<th class="px-6 py-3">Water Yield</th>
</tr>
</thead>
<tbody formArrayName="recipes" *ngIf="isMatLoaded">
<tr
*ngFor="let mat of recipeListData.controls; let i = index"
class="bg-white la border-b hover:bg-secondary"
>
<div formGroupName="{{ i }}">
<td class="px-6 py-4 font-medium text-gray-900 whitespace-nowrap">
<label>
<input
type="checkbox"
class="toggle toggle-sm"
formControlName="enable"
/>
</label>
</td>
<td class="px-6 py-4 font-medium text-gray-900 whitespace-nowrap">
<input type="text" class="input" formControlName="id" />
</td>
<td class="px-6 py-4 font-medium text-gray-900 whitespace-nowrap">
<input type="text" class="input" formControlName="name" />
</td>
<td class="px-6 py-4 font-medium text-gray-900 whitespace-nowrap">
<input type="text" class="input" formControlName="mixOrder" />
</td>
<td class="px-6 py-4 font-medium text-gray-900 whitespace-nowrap">
<input type="text" class="input" formControlName="stirTime" />
</td>
<td class="px-6 py-4 font-medium text-gray-900 whitespace-nowrap">
<input type="text" class="input" formControlName="powderGram" />
</td>
<td class="px-6 py-4 font-medium text-gray-900 whitespace-nowrap">
<input type="text" class="input" formControlName="powderTime" />
</td>
<td class="px-6 py-4 font-medium text-gray-900 whitespace-nowrap">
<input type="text" class="input" formControlName="SyrupGram" />
</td>
<td class="px-6 py-4 font-medium text-gray-900 whitespace-nowrap">
<input type="text" class="input" formControlName="SyrupTime" />
</td>
<td class="px-6 py-4 font-medium text-gray-900 whitespace-nowrap">
<input type="text" class="input" formControlName="waterCold" />
</td>
<td class="px-6 py-4 font-medium text-gray-900 whitespace-nowrap">
<input type="text" class="input" formControlName="waterHot" />
</td>
</div>
<tbody
formArrayName="recipeListData"
*ngFor="let mat of recipeListData.controls; let i = index"
>
<tr class="bg-white la border-b hover:bg-secondary" formGroupName="{{ i }}">
<td class="px-6 py-4 font-medium text-gray-900 whitespace-nowrap">
<button
class="btn btn-primary"
(click)="deleteRecipeData(i)"
type="button"
>
Delete
</button>
<button class="btn btn-primary" (click)="addRecipeData()" type="button">
Add
</button>
</td>
<td class="px-6 py-4 font-medium text-gray-900 whitespace-nowrap">
<input type="text" class="input" formControlName="materialID" />
</td>
<td class="px-6 py-4 font-medium text-gray-900 whitespace-nowrap">
<input type="text" class="input" formControlName="name" />
</td>
<td class="px-6 py-4 font-medium text-gray-900 whitespace-nowrap">
<input type="text" class="input" formControlName="mixOrder" />
</td>
<td class="px-6 py-4 font-medium text-gray-900 whitespace-nowrap">
<input type="text" class="input" formControlName="powderGram" />
</td>
<td class="px-6 py-4 font-medium text-gray-900 whitespace-nowrap">
<input type="text" class="input" formControlName="powderTime" />
</td>
<td class="px-6 py-4 font-medium text-gray-900 whitespace-nowrap">
<input type="text" class="input" formControlName="syrupGram" />
</td>
<td class="px-6 py-4 font-medium text-gray-900 whitespace-nowrap">
<input type="text" class="input" formControlName="syrupTime" />
</td>
<td class="px-6 py-4 font-medium text-gray-900 whitespace-nowrap">
<input type="text" class="input" formControlName="waterCold" />
</td>
<td class="px-6 py-4 font-medium text-gray-900 whitespace-nowrap">
<input type="text" class="input" formControlName="waterYield" />
</td>
<td class="px-6 py-4 font-medium text-gray-900 whitespace-nowrap">
<input type="text" class="input" formControlName="stirTime" />
</td>
</tr>
</tbody>
</table>

View file

@ -2,13 +2,18 @@ import { NgFor, NgIf } from '@angular/common';
import { Component, Input, OnInit } from '@angular/core';
import {
FormArray,
FormBuilder,
FormControl,
FormGroup,
ReactiveFormsModule,
} from '@angular/forms';
import { Observable } from 'rxjs';
import { MatRecipe } from 'src/app/core/models/recipe.model';
import { MaterialService } from 'src/app/core/services/material.service';
import { first } from 'rxjs';
import {
RecipeDetail,
RecipeDetailMat,
} from 'src/app/core/models/recipe.model';
import { RecipeService } from 'src/app/core/services/recipe.service';
import { Action, ActionRecord } from 'src/app/shared/actionRecord/actionRecord';
export interface RecipeListDataFormGroup {
id: FormControl<number | null>;
@ -31,97 +36,86 @@ export interface RecipeListDataFormGroup {
imports: [NgIf, NgFor, ReactiveFormsModule],
})
export class RecipeListComponent implements OnInit {
@Input({ required: true }) matRecipeList!: Observable<{
ids: number[];
matRecipeList: MatRecipe[];
}>;
@Input({ required: true }) parentForm!: FormGroup;
@Input({ required: true }) actionRecord!: ActionRecord<
RecipeDetail | RecipeDetailMat
>;
recipeListData!: FormArray<FormGroup<RecipeListDataFormGroup>>;
@Input({ required: true }) recipeDetailOriginal!: any;
@Input({ required: true }) productCode!: string;
isMatLoaded: boolean = false;
constructor(private _materialService: MaterialService) {}
constructor(
private _recipeService: RecipeService,
private _formBuilder: FormBuilder
) {}
ngOnInit(): void {
this.matRecipeList.subscribe((x) => {
this._materialService.getMaterialCodes(x.ids).subscribe((data) => {
const matList = x.matRecipeList
.map((item) => {
for (let i = 0; i < data.length; i++) {
if (item.materialPathId === 0) {
return {
id: 0,
name: '',
enable: item.isUse,
mixOrder: item.MixOrder,
stirTime: item.stirTime,
powderGram: item.powderGram,
powderTime: item.powderTime,
syrupGram: item.syrupGram,
syrupTime: item.syrupTime,
waterCold: item.waterCold,
waterHot: item.waterYield,
};
}
if (item.materialPathId === data[i].materialID) {
return {
id: data[i].materialID,
name: data[i].PackageDescription,
enable: item.isUse,
mixOrder: item.MixOrder,
stirTime: item.stirTime,
powderGram: item.powderGram,
powderTime: item.powderTime,
syrupGram: item.syrupGram,
syrupTime: item.syrupTime,
waterCold: item.waterCold,
waterHot: item.waterYield,
};
}
}
return {
id: item.materialPathId,
name: '',
enable: item.isUse,
mixOrder: item.MixOrder,
stirTime: item.stirTime,
powderGram: item.powderGram,
powderTime: item.powderTime,
syrupGram: item.syrupGram,
syrupTime: item.syrupTime,
waterCold: item.waterCold,
waterHot: item.waterYield,
};
})
.sort((a, b) => {
return a.id === 0 ? 1 : a.id > b.id ? 1 : -1;
});
this.recipeListData = new FormArray<FormGroup<RecipeListDataFormGroup>>(
matList.map((item) => {
return new FormGroup<RecipeListDataFormGroup>({
id: new FormControl<number>(item.id),
name: new FormControl<string>(item.name),
enable: new FormControl<boolean>(item.enable),
mixOrder: new FormControl<number>(item.mixOrder),
stirTime: new FormControl<number>(item.stirTime),
powderGram: new FormControl<number>(item.powderGram),
powderTime: new FormControl<number>(item.powderTime),
syrupGram: new FormControl<number>(item.syrupGram),
syrupTime: new FormControl<number>(item.syrupTime),
waterCold: new FormControl<number>(item.waterCold),
waterHot: new FormControl<number>(item.waterHot),
});
})
);
this.parentForm.addControl('recipes', this.recipeListData);
console.log(this.parentForm);
this._recipeService
.getRecipeDetailMat(this.productCode)
.pipe(first())
.subscribe(({ result }) => {
if (this.recipeDetailOriginal)
this.recipeDetailOriginal.recipeListData = result;
else this.recipeDetailOriginal = { recipeListData: result };
result.forEach((recipeDetailMat: RecipeDetailMat) => {
this.recipeListData.push(
this._formBuilder.group({
materialID: recipeDetailMat.materialID,
name: recipeDetailMat.name,
enable: recipeDetailMat.isUse,
mixOrder: recipeDetailMat.mixOrder,
stirTime: recipeDetailMat.stirTime,
powderGram: recipeDetailMat.powderGram,
powderTime: recipeDetailMat.powderTime,
syrupGram: recipeDetailMat.syrupGram,
syrupTime: recipeDetailMat.syrupTime,
waterCold: recipeDetailMat.waterCold,
waterYield: recipeDetailMat.waterYield,
})
);
});
this.isMatLoaded = true;
});
});
}
get recipeListData(): FormArray {
return this.parentForm.get('recipeListData') as FormArray;
}
addRecipeData(): void {
const newRecipeDetailMat: RecipeDetailMat = {
materialID: 0,
name: '',
mixOrder: 0,
feedParameter: 0,
feedPattern: 0,
isUse: false,
materialPathId: 0,
powderGram: 0,
powderTime: 0,
stirTime: 0,
syrupGram: 0,
syrupTime: 0,
waterCold: 0,
waterYield: 0,
};
this.recipeListData.push(this._formBuilder.group(newRecipeDetailMat));
this.actionRecord.addAction(
new Action('add', newRecipeDetailMat, 'recipeListData')
);
}
deleteRecipeData(index: number): void {
const recipeDetailMat: RecipeDetailMat =
this.recipeListData.at(index).value;
this.recipeListData.removeAt(index);
this.actionRecord.addAction(
new Action('delete', recipeDetailMat, 'recipeListData')
);
}
}