add carousel & test submenu

This commit is contained in:
pakintada@gmail.com 2024-01-15 11:48:25 +07:00
parent edcccaaab9
commit 7102f644d4
7 changed files with 242 additions and 314 deletions

View file

@ -197,24 +197,22 @@ export class RecipeService {
) )
.subscribe({ .subscribe({
next(value) { next(value) {
console.log( value); console.log(value);
}, },
}); });
} }
getSavedTmp(country: string, filename:string) { getSavedTmp(country: string, filename: string) {
console.log("loading saved .tmp* file", country, filename) console.log('loading saved .tmp* file', country, filename);
// do split filename // do split filename
filename = filename.split('_')[1]; filename = filename.split('_')[1];
// this._user.getCurrentUser().subscribe((user) => { // this._user.getCurrentUser().subscribe((user) => {
// this.user = user.user; // this.user = user.user;
// }) // })
return this._httpClient return this._httpClient.get<string[]>(
.get<string[]>( environment.api + ('/recipes/saved/' + country + '/' + filename),
environment.api + ("/recipes/saved/"+ country + "/" + filename),
{ {
withCredentials: true, withCredentials: true,
} }
@ -225,4 +223,21 @@ export class RecipeService {
// }, // },
// }); // });
} }
getSubMenus(country: string, filename: string, productCode: string) {
return this._httpClient.get<Recipe01[]>(
environment.api +
'/recipes/' +
country +
'/' +
filename +
'/' +
productCode +
'/submenus',
{
withCredentials: true,
responseType: 'json',
}
);
}
} }

View file

@ -1,9 +1,26 @@
<div class="p-4 overflow-auto h-[90vh]"> <div class="p-4 overflow-auto h-[90vh]">
<form class="grid grid-cols-3 gap-4 mb-4" [formGroup]="recipeDetailForm"> <form [formGroup]="recipeDetailForm">
<!-- carousel -->
<div class="carousel carousel-center space-x-8">
<div id="name" class="carousel-item w-1/2">
<div <div
class="block col-span-1 p-6 bg-white border border-gray-200 rounded-lg shadow" class="block p-6 bg-white border border-gray-200 rounded-lg shadow w-full"
> >
<div *ngIf="isLoaded; else indicator" [@inOutAnimation]> <div *ngIf="isLoaded; else indicator" [@inOutAnimation]>
<!-- productCode -->
<div>
<input
class="input input-bordered input-xs text-lg text-gray-900 my-2"
type="text"
name="productCode"
[value]="productCode"
(keyup)="onProductCodeChange($event)"
[disabled]="!isEditable()"
/>
</div>
<div class="flex flex-wrap"> <div class="flex flex-wrap">
<h5 class="mb-2 text-xl font-bold text-gray-900"> <h5 class="mb-2 text-xl font-bold text-gray-900">
{{ recipeDetailForm.getRawValue().name }} {{ recipeDetailForm.getRawValue().name }}
@ -13,17 +30,6 @@
{{ recipeDetailForm.getRawValue().otherName }} {{ recipeDetailForm.getRawValue().otherName }}
</h5> </h5>
<!-- productCode -->
<div>
<input
class="input text-lg text-gray-900 my-2"
type="text"
name="productCode"
[value]="productCode"
(keyup)="onProductCodeChange($event)"
[disabled]="!isEditable()"
/>
</div>
</div> </div>
<div class="flex items-center mb-2"> <div class="flex items-center mb-2">
<div class="flex items-center"> <div class="flex items-center">
@ -46,7 +52,7 @@
</div> </div>
<div <div
class="block col-span-2 p-6 bg-white border border-gray-200 rounded-lg shadow min-h-[300px]" class="block p-6 bg-white border border-gray-200 rounded-lg shadow min-h-[300px] w-full"
> >
<div <div
*ngIf="isLoaded; else indicator" *ngIf="isLoaded; else indicator"
@ -55,7 +61,9 @@
> >
<div class="flex items-center"> <div class="flex items-center">
<label class="label text-base mr-3 w-max" <label class="label text-base mr-3 w-max"
><span class="label-text text-base mr-3 w-max">Name:</span></label ><span class="label-text text-base mr-3 w-max"
>Name:</span
></label
> >
<input <input
type="text" type="text"
@ -99,217 +107,57 @@
formControlName="otherDescription" formControlName="otherDescription"
/> />
</div> </div>
<div *ngIf="hasSubmenu()">
<div *ngFor="let sub of listSubMenuProductcodes()">
<button class="btn btn-sm btn-primary m-2" (click)="selectSubmenu(sub)">{{sub}}</button>
</div> </div>
</div> </div>
</div>
</div>
</div>
<div id="recipeList" class="carousel-item w-full">
<div <div
class="col-span-3 overflow-auto h-[75vh] mb-4 rounded bg-white border border-gray-200 shadow" class="overflow-auto h-[75vh] mb-4 rounded bg-white border border-gray-200 shadow w-1/2"
> >
<app-recipe-list <app-recipe-list
[productCode]="productCode" [productCode]="productCode"
[isSubMenu]="false"
(recipeListFormChange)="onRecipeListFormChange($event)" (recipeListFormChange)="onRecipeListFormChange($event)"
></app-recipe-list> ></app-recipe-list>
</div> </div>
<!-- TODO: do topping -->
</div>
<div id="toppingSet" class="carousel-item w-full">
<div class="overflow-auto h-[75vh] mb-4 rounded bg-white border border-gray-200 shadow">
<app-recipe-toppingset <app-recipe-toppingset
[productCode]="productCode" [productCode]="productCode"
(toppingSetChange)="onToppingListChange($event)" (toppingSetChange)="onToppingListChange($event)"
></app-recipe-toppingset> ></app-recipe-toppingset>
<div class="grid grid-cols-2 gap-4 mb-4">
</div>
</div>
</div>
<!-- try pop up modal -->
<!-- TODO: do topping -->
<div <div
class="flex items-center justify-center rounded bg-gray-50 h-28 dark:bg-gray-800" class="sticky bottom-0 col-span-3 max-w-screen-lg flex justify-end bg-white rounded-full drop-shadow-2xl p-3"
> >
<p class="text-2xl text-gray-400 dark:text-gray-500">
<svg <div class="flex justify-center w-full start-0 py-2">
class="w-3.5 h-3.5" <a href="{{department}}/recipe/{{productCode}}#name" class="btn btn-xs">1</a>
aria-hidden="true" <a href="{{department}}/recipe/{{productCode}}#recipeList" class="btn btn-xs">2</a>
xmlns="http://www.w3.org/2000/svg" <a href="{{department}}/recipe/{{productCode}}#toppingSet" class="btn btn-xs">3</a>
fill="none"
viewBox="0 0 18 18"
>
<path
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M9 1v16M1 9h16"
/>
</svg>
</p>
</div> </div>
<div
class="flex items-center justify-center rounded bg-gray-50 h-28 dark:bg-gray-800"
>
<p class="text-2xl text-gray-400 dark:text-gray-500">
<svg
class="w-3.5 h-3.5"
aria-hidden="true"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 18 18"
>
<path
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M9 1v16M1 9h16"
/>
</svg>
</p>
</div>
<div
class="flex items-center justify-center rounded bg-gray-50 h-28 dark:bg-gray-800"
>
<p class="text-2xl text-gray-400 dark:text-gray-500">
<svg
class="w-3.5 h-3.5"
aria-hidden="true"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 18 18"
>
<path
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M9 1v16M1 9h16"
/>
</svg>
</p>
</div>
<div
class="flex items-center justify-center rounded bg-gray-50 h-28 dark:bg-gray-800"
>
<p class="text-2xl text-gray-400 dark:text-gray-500">
<svg
class="w-3.5 h-3.5"
aria-hidden="true"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 18 18"
>
<path
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M9 1v16M1 9h16"
/>
</svg>
</p>
</div>
</div>
<div
class="flex items-center justify-center h-48 mb-4 rounded bg-gray-50 dark:bg-gray-800"
>
<p class="text-2xl text-gray-400 dark:text-gray-500">
<svg
class="w-3.5 h-3.5"
aria-hidden="true"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 18 18"
>
<path
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M9 1v16M1 9h16"
/>
</svg>
</p>
</div>
<div class="grid grid-cols-2 gap-4">
<div
class="flex items-center justify-center rounded bg-gray-50 h-28 dark:bg-gray-800"
>
<p class="text-2xl text-gray-400 dark:text-gray-500">
<svg
class="w-3.5 h-3.5"
aria-hidden="true"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 18 18"
>
<path
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M9 1v16M1 9h16"
/>
</svg>
</p>
</div>
<div
class="flex items-center justify-center rounded bg-gray-50 h-28 dark:bg-gray-800"
>
<p class="text-2xl text-gray-400 dark:text-gray-500">
<svg
class="w-3.5 h-3.5"
aria-hidden="true"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 18 18"
>
<path
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M9 1v16M1 9h16"
/>
</svg>
</p>
</div>
<div
class="flex items-center justify-center rounded bg-gray-50 h-28 dark:bg-gray-800"
>
<p class="text-2xl text-gray-400 dark:text-gray-500">
<svg
class="w-3.5 h-3.5"
aria-hidden="true"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 18 18"
>
<path
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M9 1v16M1 9h16"
/>
</svg>
</p>
</div>
<div
class="flex items-center justify-center rounded bg-gray-50 h-28 dark:bg-gray-800"
>
<p class="text-2xl text-gray-400 dark:text-gray-500">
<svg
class="w-3.5 h-3.5"
aria-hidden="true"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 18 18"
>
<path
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M9 1v16M1 9h16"
/>
</svg>
</p>
</div>
</div>
<div
class="sticky bottom-0 col-span-3 flex justify-end bg-white rounded-full drop-shadow-2xl p-3"
>
<!-- <div> Commit Message </div> --> <!-- <div> Commit Message </div> -->
<!-- <p class="text-2xl mr-8 text-gray-400 dark:text-gray-500">Commit Message</p> --> <!-- <p class="text-2xl mr-8 text-gray-400 dark:text-gray-500">Commit Message</p> -->
<input <input

View file

@ -92,6 +92,7 @@ export class RecipeDetailsComponent implements OnInit {
tpl = [] tpl = []
toppingSet: ToppingSet[] | null = null; toppingSet: ToppingSet[] | null = null;
submenus: Recipe01[] | null = null;
ngOnInit() { ngOnInit() {
this.productCode = this._route.snapshot.params['productCode']; this.productCode = this._route.snapshot.params['productCode'];
@ -101,13 +102,18 @@ export class RecipeDetailsComponent implements OnInit {
.pipe(first()); .pipe(first());
this.recipeDetail$.subscribe((detail) => { this.recipeDetail$.subscribe((detail) => {
console.log('Recipe Detail', detail); // console.log('Recipe Detail', detail);
this.recipeDetailForm.patchValue(detail); this.recipeDetailForm.patchValue(detail);
this.isLoaded = true; this.isLoaded = true;
this.recipeOriginalDetail = { ...this.recipeDetailForm.getRawValue() }; this.recipeOriginalDetail = { ...this.recipeDetailForm.getRawValue() };
}); });
this._recipeService.getSubMenus(this._recipeService.getCurrentCountry(), this._recipeService.getCurrentFile(), this.productCode).subscribe((data) => {
console.log('Submenus', data);
this.submenus = data;
});
this.recipeDetailForm.valueChanges.subscribe(this.onRecipeDetailFormChange); this.recipeDetailForm.valueChanges.subscribe(this.onRecipeDetailFormChange);
@ -243,4 +249,21 @@ export class RecipeDetailsComponent implements OnInit {
this.changedProductCode = 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);
}
} }

View file

@ -54,7 +54,8 @@
<td <td
class="m-2 px-4 py-4 font-medium text-gray-900 whitespace-nowrap" class="m-2 px-4 py-4 font-medium text-gray-900 whitespace-nowrap"
*ngIf=" *ngIf="
displayByCond(i, 'syrupGram', 'not-zero', { compare: undefined }) displayByCond(i, 'syrupGram', 'not-zero', { compare: undefined }) &&
getTypeForRecipeListAtIndex(i)['category'] == 'syrup'
" "
> >
<div class="flex items-center space-x-2 bg-purple-300 rounded-md"> <div class="flex items-center space-x-2 bg-purple-300 rounded-md">

View file

@ -40,6 +40,7 @@ import {
}) })
export class RecipeListComponent implements OnInit { export class RecipeListComponent implements OnInit {
@Input({ required: true }) productCode!: string; @Input({ required: true }) productCode!: string;
@Input() isSubMenu: boolean = false;
@Output() recipeListFormChange = new EventEmitter<unknown[]>(); @Output() recipeListFormChange = new EventEmitter<unknown[]>();
materialList: MaterialCode[] = []; materialList: MaterialCode[] = [];

View file

@ -426,6 +426,24 @@ func (d *Data) GetToppingsOfRecipe(countryID, filename string, productCode strin
return recipe.ToppingSet, nil return recipe.ToppingSet, nil
} }
func (d *Data) GetSubmenusOfRecipe(countryID, filename, productCode string) ([]models.Recipe01, error) {
recipe, err := d.GetRecipe01ByProductCode(filename, countryID, productCode)
if err != nil {
d.taoLogger.Log.Error("Error when read recipe file, Return default recipe", zap.Error(err))
return []models.Recipe01{}, err
}
submenu := recipe.SubMenu
if submenu == nil {
return []models.Recipe01{}, fmt.Errorf("no submenu")
}
return submenu, nil
}
func (d *Data) GetCountryNameByID(countryID string) (string, error) { func (d *Data) GetCountryNameByID(countryID string) (string, error) {
for _, country := range d.Countries { for _, country := range d.Countries {
if country.CountryID == countryID { if country.CountryID == countryID {

View file

@ -59,6 +59,8 @@ func (rr *RecipeRouter) Route(r chi.Router) {
r.Get("/{country}/{filename}/{product_code}/toppings", rr.getToppingsOfRecipe) r.Get("/{country}/{filename}/{product_code}/toppings", rr.getToppingsOfRecipe)
r.Get("/{country}/{filename}/{product_code}/submenus", rr.getSubmenusOfRecipe)
r.Get("/{country}/{filename}/json", rr.getRecipeJson) r.Get("/{country}/{filename}/json", rr.getRecipeJson)
r.Post("/edit/{country}/{filename}", rr.updateRecipe) r.Post("/edit/{country}/{filename}", rr.updateRecipe)
@ -520,6 +522,26 @@ func (rr *RecipeRouter) getToppingsOfRecipe(w http.ResponseWriter, r *http.Reque
json.NewEncoder(w).Encode(topps) json.NewEncoder(w).Encode(topps)
} }
func (rr *RecipeRouter) getSubmenusOfRecipe(w http.ResponseWriter, r *http.Request) {
countryID := chi.URLParam(r, "country")
filename := chi.URLParam(r, "filename")
productCode := chi.URLParam(r, "product_code")
w.Header().Add("Content-Type", "application/json")
submenus, err := rr.data.GetSubmenusOfRecipe(countryID, filename, productCode)
rr.taoLogger.Log.Debug("RecipeRouter.getSubmenusOfRecipe", zap.Any("submenus", len(submenus)))
if err != nil {
http.Error(w, err.Error(), http.StatusNotFound)
return
}
json.NewEncoder(w).Encode(submenus)
}
func (rr *RecipeRouter) doMergeJson(w http.ResponseWriter, r *http.Request) { func (rr *RecipeRouter) doMergeJson(w http.ResponseWriter, r *http.Request) {
// TODO: v2, change to binary instead // TODO: v2, change to binary instead
if !APIhandler(w, r) { if !APIhandler(w, r) {