From 29a1a82cfbe1b6e10367cfa63e65f0c9064e5569 Mon Sep 17 00:00:00 2001 From: "pakintada@gmail.com" Date: Tue, 24 Feb 2026 17:32:51 +0700 Subject: [PATCH] update brew route Signed-off-by: pakintada@gmail.com --- .../recipe-details/recipe-detail.svelte | 26 +- .../components/recipe-editor-dialog.svelte | 13 +- src/lib/core/handlers/messageHandler.ts | 35 +++ src/lib/core/stores/recipeStore.ts | 3 + src/lib/data/mockup.ts | 0 src/lib/data/recipeDef.ts | 0 src/lib/data/recipeService.ts | 140 +++++++++++ src/routes/(authed)/departments/+page.svelte | 8 + src/routes/(authed)/entry/+page.svelte | 229 ++++++++---------- .../(authed)/recipe/overview/+page.server.ts | 2 +- .../(authed)/recipe/overview/+page.svelte | 11 +- src/routes/+page.svelte | 80 +----- 12 files changed, 344 insertions(+), 203 deletions(-) delete mode 100644 src/lib/data/mockup.ts delete mode 100644 src/lib/data/recipeDef.ts create mode 100644 src/lib/data/recipeService.ts diff --git a/src/lib/components/recipe-details/recipe-detail.svelte b/src/lib/components/recipe-details/recipe-detail.svelte index 0e42f0c..3509a51 100644 --- a/src/lib/components/recipe-details/recipe-detail.svelte +++ b/src/lib/components/recipe-details/recipe-detail.svelte @@ -8,14 +8,18 @@ import { columns, type RecipelistMaterial } from './columns'; import { get, readable, writable } from 'svelte/store'; - import { materialFromMachineQuery } from '$lib/core/stores/recipeStore'; + import { materialFromMachineQuery, materialFromServerQuery } from '$lib/core/stores/recipeStore'; import { generateIcing } from '$lib/helpers/icingGen'; import { machineInfoStore } from '$lib/core/stores/machineInfoStore'; import MachineInfo from '../machine-info.svelte'; import { v4 as uuidv4 } from 'uuid'; // - let { recipeData, onPendingChange }: { recipeData: any; onPendingChange: any } = $props(); + let { + recipeData, + onPendingChange, + refPage + }: { recipeData: any; onPendingChange: any; refPage: string } = $props(); let menuName: string = $state(''); @@ -31,9 +35,12 @@ if (materialSnapshot) { let d_cnt = 0; for (let rpl of data) { - let mat = materialSnapshot.filter( - (x: any) => x['id'].toString() === rpl['materialPathId'].toString() - )[0]; + let mat = + refPage == 'brew' + ? materialSnapshot.filter( + (x: any) => x['id'].toString() === rpl['materialPathId'].toString() + )[0] + : materialSnapshot[rpl['materialPathId']]; // console.log('mat filter get', Object(mat), Object.keys(mat)); @@ -99,7 +106,14 @@ if (recipeData) { menuName = recipeData['name'] ?? (recipeData['otherName'] ? recipeData['otherName'] : 'Not set'); - materialSnapshot = get(materialFromMachineQuery); + + if (refPage == 'overview') { + materialSnapshot = get(materialFromServerQuery); + } else if (refPage == 'brew') { + materialSnapshot = get(materialFromMachineQuery); + } + + console.log(`detail : ${JSON.stringify(recipeData)}`); recipeListMatState = remappingToColumn(recipeData['recipes']); // save old value\ diff --git a/src/lib/components/recipe-editor-dialog.svelte b/src/lib/components/recipe-editor-dialog.svelte index 5d478e0..7c4e326 100644 --- a/src/lib/components/recipe-editor-dialog.svelte +++ b/src/lib/components/recipe-editor-dialog.svelte @@ -1,5 +1,5 @@ @@ -89,7 +98,7 @@ - + {:else}{/if} diff --git a/src/lib/core/handlers/messageHandler.ts b/src/lib/core/handlers/messageHandler.ts index 3f399ff..c4110c0 100644 --- a/src/lib/core/handlers/messageHandler.ts +++ b/src/lib/core/handlers/messageHandler.ts @@ -1,12 +1,14 @@ import { get, writable } from 'svelte/store'; import { addNotification, notiStore } from '../stores/noti'; import { + materialFromServerQuery, recipeData, recipeDataError, recipeLoading, recipeOverviewData, recipeStreamMeta } from '../stores/recipeStore'; +import { buildOverviewFromServer } from '$lib/data/recipeService'; export const messages = writable([]); @@ -82,6 +84,39 @@ const handlers: Record void> = { }, stream_data_end: (p) => { recipeLoading.set(false); + + // build overview for recipe from server + // + + buildOverviewFromServer(); + }, + stream_data_extra: (p) => { + // extended data from server, may be extra infos + // + // expected last stream_id + count + let exid = p.exid; + let extp = p.extp; + let ex_payload = p.payload; + + if (extp) { + // know type + switch (extp) { + case 'matset': + let curr_mat_query = get(materialFromServerQuery); + // ex_payload has chunks of material setting + for (let m of ex_payload) { + let mid = m.id; + curr_mat_query[mid] = m; + } + + materialFromServerQuery.set(curr_mat_query); + break; + case 'topplist': + break; + case 'toppgrp': + break; + } + } }, stream_patch_update: (p) => {} }; diff --git a/src/lib/core/stores/recipeStore.ts b/src/lib/core/stores/recipeStore.ts index b5ce0f4..91ca57e 100644 --- a/src/lib/core/stores/recipeStore.ts +++ b/src/lib/core/stores/recipeStore.ts @@ -21,6 +21,9 @@ export const recipeFromMachine = writable(null); export const recipeFromMachineLoading = writable(false); export const recipeFromMachineError = writable(null); +export const recipeFromServerQuery = writable({}); +export const materialFromServerQuery = writable({}); + // NOTE: must not have any nested structures // { recipe: {}, materials: {}, toppings: { groups: {}, lists: {} } } export const recipeFromMachineQuery = writable({}); diff --git a/src/lib/data/mockup.ts b/src/lib/data/mockup.ts deleted file mode 100644 index e69de29..0000000 diff --git a/src/lib/data/recipeDef.ts b/src/lib/data/recipeDef.ts deleted file mode 100644 index e69de29..0000000 diff --git a/src/lib/data/recipeService.ts b/src/lib/data/recipeService.ts new file mode 100644 index 0000000..6391194 --- /dev/null +++ b/src/lib/data/recipeService.ts @@ -0,0 +1,140 @@ +import { + materialFromServerQuery, + recipeData, + recipeFromServerQuery, + recipeOverviewData +} from '$lib/core/stores/recipeStore'; +import { get } from 'svelte/store'; + +import type { RecipeOverview } from '../../routes/(authed)/recipe/overview/columns'; + +function getMenuStatus(ms: number): RecipeOverview['status'] { + switch (ms) { + case 0: + return 'ready'; + case 2: + return 'obsolete'; + case 11: + return 'pending/online'; + case 12: + return 'pending/offline'; + default: + return 'drafted'; + } +} + +function getMenuCategory(pd: string): string { + // [country_code]-[category_code]-[drink_Type]-[id] + let pd_spl = pd.split('-'); + let category = pd_spl[1] ?? ''; + + if (category) { + if (category.endsWith('1')) { + let result = 'coffee'; + if (category === '01') { + result += ',v1'; + } else { + result += ',v2+'; + } + + return result; + } else if (category.endsWith('2')) { + return 'tea'; + } else if (category.endsWith('3')) { + return 'milk'; + } else if (category.endsWith('4')) { + return 'whey'; + } else if (category.endsWith('5')) { + return 'soda'; + } else if (category == '99') { + return 'special'; + } + } + return 'unknown'; +} + +function getDrinkType(pd: string): string { + // [country_code]-[category_code]-[drink_Type]-[id] + let pd_spl = pd.split('-'); + let drink_type = pd_spl[2] ?? ''; + + if (drink_type) { + if (drink_type.endsWith('1')) { + return 'hot'; + } else if (drink_type.endsWith('2')) { + return 'cold / iced'; + } else if (drink_type.endsWith('3')) { + return 'smoothie / frappe'; + } + } + + return ''; +} + +// set material used in recipe to tags for using in filter +function getMainMaterialOfRecipe(rp: any): string { + let recipeList = rp['recipes'] ?? []; + let mat_lists = ''; + + for (let rpl of recipeList) { + let mat_id = rpl['materialPathId']; + let mat_in_use = rpl['isUse']; + + if (mat_in_use && !mat_lists.includes(mat_id)) { + mat_lists += mat_id + ','; + } + } + + mat_lists = mat_lists.substring(0, mat_lists.length - 1); + + return mat_lists; +} + +function buildTags(rp: any): string { + let result = ''; + + result += getMenuCategory(rp['productCode']); + + let dt = getDrinkType(rp['productCode']); + let mats = getMainMaterialOfRecipe(rp); + + if (dt !== '') result += ',' + dt; + if (mats !== '') result += ',' + mats; + + return result; +} + +function buildOverviewFromServer() { + let server_recipe01 = get(recipeData); + let result = []; + + let r01_query: any = {}; + + if (server_recipe01) { + recipeOverviewData.set([]); + for (let rp of server_recipe01) { + result.push({ + productCode: rp['productCode'] ?? '', + name: rp['name'] ? rp['name'] : (rp['otherName'] ?? ''), + description: rp['desciption'] ? rp['desciption'] : (rp['otherDescription'] ?? ''), + tags: buildTags(rp), + status: getMenuStatus(rp['MenuStatus']) + }); + + r01_query[rp['productCode']] = rp; + } + + let currentQuery = get(recipeFromServerQuery); + let currentMaterial = get(materialFromServerQuery); + + currentQuery = { + recipe: r01_query, + material: currentMaterial + }; + + recipeOverviewData.set(result); + recipeFromServerQuery.set(currentQuery); + } +} + +export { buildOverviewFromServer }; diff --git a/src/routes/(authed)/departments/+page.svelte b/src/routes/(authed)/departments/+page.svelte index dc1bd30..aed44df 100644 --- a/src/routes/(authed)/departments/+page.svelte +++ b/src/routes/(authed)/departments/+page.svelte @@ -43,8 +43,16 @@ enabledAccessibleCountries = userCurrentPerms .filter((x) => x.startsWith('document.read')) .map((x) => x.split('.')[2]); + + if (enabledAccessibleCountries.length == 1) { + onCountrySelected(enabledAccessibleCountries[0]); + } }, 1000); } + + if (enabledAccessibleCountries.length == 1) { + onCountrySelected(enabledAccessibleCountries[0]); + }

Country Selection

diff --git a/src/routes/(authed)/entry/+page.svelte b/src/routes/(authed)/entry/+page.svelte index cbc03f5..4f4e4b7 100644 --- a/src/routes/(authed)/entry/+page.svelte +++ b/src/routes/(authed)/entry/+page.svelte @@ -1,138 +1,119 @@ -
-
-

Module Selection

+
+

Module Selection

- -
- - {#if perms.filter((x) => x.startsWith("document.read") || x.startsWith("document.write")).length > 0} - - {/if} +
+ + {#if perms.filter((x) => x.startsWith('document.read') || x.startsWith('document.write')).length > 0} + + {/if} - - {#if perms.filter((x) => x.startsWith("tools")).length > 0} - - {/if} -
+ + {#if perms.filter((x) => x.startsWith('tools')).length > 0} + + {/if} +
- {#if perms.filter((x) => x.startsWith("document.read") || x.startsWith("document.write") || x.startsWith("tools")).length == 0} + {#if perms.filter((x) => x.startsWith('document.read') || x.startsWith('document.write') || x.startsWith('tools')).length == 0} +

+ No modules are available. Please check your account with admin. +

+ {/if} -

No modules are available. - Please check your account with admin.

- - {/if} - -
- - -
- - - -
-
\ No newline at end of file +
+ +
+
+ diff --git a/src/routes/(authed)/recipe/overview/+page.server.ts b/src/routes/(authed)/recipe/overview/+page.server.ts index 229e7f6..9fb0976 100644 --- a/src/routes/(authed)/recipe/overview/+page.server.ts +++ b/src/routes/(authed)/recipe/overview/+page.server.ts @@ -4,7 +4,7 @@ import { get } from 'svelte/store'; export async function load({ cookies, params }) { let dep = cookies.get('department'); - console.log('load recipe ', dep); + console.log('load recipe ', dep, params); let recipes = await getRecipes(); recipes = get(recipeData); diff --git a/src/routes/(authed)/recipe/overview/+page.svelte b/src/routes/(authed)/recipe/overview/+page.svelte index 354156c..766f9a1 100644 --- a/src/routes/(authed)/recipe/overview/+page.svelte +++ b/src/routes/(authed)/recipe/overview/+page.svelte @@ -6,7 +6,13 @@ import DataTable from './data-table.svelte'; import { columns, type RecipeOverview } from './columns'; import { onDestroy, onMount } from 'svelte'; - import { loadRecipe, recipeData } from '$lib/core/stores/recipeStore.js'; + import { + loadRecipe, + recipeData, + recipeFromServerQuery, + recipeOverviewData, + referenceFromPage + } from '$lib/core/stores/recipeStore.js'; import { sendMessage } from '$lib/core/handlers/ws_messageSender.js'; import { auth } from '$lib/core/stores/auth.js'; import { get } from 'svelte/store'; @@ -16,7 +22,7 @@ recipes: [] }); - let unsubRecipeData = recipeData.subscribe((rd) => { + let unsubRecipeData = recipeOverviewData.subscribe((rd) => { if (rd) { data.recipes = rd == null ? [] : rd; } @@ -25,6 +31,7 @@ onMount(async () => { // do load recipe // loadRecipe(); + referenceFromPage.set('overview'); await getRecipes(); }); diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index 12c1d86..8ba4b46 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -10,78 +10,22 @@ import { TerminalComponent } from '$lib/components/ui/terminal'; import { onMount } from 'svelte'; import { goto } from '$app/navigation'; - import { auth } from '$lib/core/client/firebase'; + import { auth as authStore } from '$lib/core/stores/auth'; + import { auth } from '$lib/core/client/firebase'; + import { get } from 'svelte/store'; - // const device = await usb.requestDevice({ - // filters: [ - // { - // vendorId: 0x18d1 - // } - // ] - // }); + onMount(() => { + let existed_account = get(authStore); + let current_user_logged = auth.currentUser; + console.log( + `has acc ${JSON.stringify(existed_account)}, from session: ${JSON.stringify(current_user_logged)}` + ); - let recipe: any | undefined = undefined; - - async function test_adb() { - try { - if (!('usb' in navigator)) { - throw new Error('WebUSB not supported, try using fallback'); - } - - await adb.connnectViaWebUSB(); - - let instance = adb.getAdbInstance(); - - if (instance) { - console.log('create instance ok'); - let result = await adb.executeCmd( - 'am start -n com.forthvending.coffeemain/com.forthvending.coffeemain.MainActivity' - ); - console.log(result); - } - } catch (e) { - console.error(e); + if (existed_account || current_user_logged) { + goto('/entry'); } - } - - async function test_send_command() { - try { - if (!('usb' in navigator)) { - throw new Error('WebUSB not supported, try using fallback'); - } - - let instance = adb.getAdbInstance(); - - if (instance) { - let txt = document.getElementById('cmd-input') as HTMLInputElement; - - console.log('instance existed, ', txt.value); - let result = await adb.executeCmd(txt.value ?? ''); - console.log(result); - } - } catch (e) { - console.error(e); - } - } - - async function test_pull_recipe_dev() { - try { - if (!('usb' in navigator)) { - throw new Error('WebUSB not supported, try using fallback'); - } - let instance = adb.getAdbInstance(); - if (instance) { - let result = await adb.pull('/sdcard/coffeevending/cfg/recipe_branch_dev.json'); - let payload = JSON.parse(result ?? ''); - console.log(payload); - recipe = payload; - alert('pull completed!'); - } - } catch (e) { - console.error(`[PULL] ${e}`); - } - } + });