diff --git a/ISSUES.txt b/ISSUES.txt index 005e4a5..279018a 100644 --- a/ISSUES.txt +++ b/ISSUES.txt @@ -1,14 +1,13 @@ Idea, Issue, Work Tracking [TODO] -- [] #10: [MenuCreation] recipe fill in until maximum limit (30) -- [] #11: Bring android app to front (`/brew` -> do swap to brew app, `/sheet` -> do swap to xml engine app) -- [] #12: [MenuCreation] Adjust input per material type + [Pending] -- [-] #7: material & menu creation - > Menu creation ready! +- [] #3: Save value to recipe +- [] #6: display all recipes with materials from csv [material usages with product code] +- [] #7: material & menu creation - [] #9: show & edit price [Rejected] @@ -20,7 +19,5 @@ Idea, Issue, Work Tracking - [x] #2: Send change value from editing in recipe to machine - [x] #5: revert value on close dialog recipe - [x] #8: change recipe version -- [x] #3: Save value to recipe -- [x] #6: display all recipes with materials from csv [material usages with product code] diff --git a/bun.lockb b/bun.lockb deleted file mode 100755 index 9851d42..0000000 Binary files a/bun.lockb and /dev/null differ diff --git a/src/lib/components/app-sidebar.svelte b/src/lib/components/app-sidebar.svelte index 34de1f0..d7475dd 100644 --- a/src/lib/components/app-sidebar.svelte +++ b/src/lib/components/app-sidebar.svelte @@ -12,7 +12,6 @@ CupSodaIcon, Shield, FileSpreadsheet, - DollarSign, MonitorSmartphone, PlusCircle, ImageUp, @@ -136,12 +135,6 @@ url: '/departments', icon: FileSpreadsheet, requirePerm: 'document.write.*' - }, - { - title: 'PriceSlot', - url: '/departments', - icon: DollarSign, - requirePerm: 'document.write.*' } ] } @@ -235,7 +228,7 @@ onclick={(e) => { if (nav.title === 'Sheet') { e.preventDefault(); - referenceFromPage.set(sub.title === 'PriceSlot' ? 'priceslot' : 'sheet'); + referenceFromPage.set('sheet'); goto(sub.url); } }} diff --git a/src/lib/components/recipe-details/recipe-detail.svelte b/src/lib/components/recipe-details/recipe-detail.svelte index 455dcfd..77673d0 100644 --- a/src/lib/components/recipe-details/recipe-detail.svelte +++ b/src/lib/components/recipe-details/recipe-detail.svelte @@ -5,7 +5,6 @@ import Input from '$lib/components/ui/input/input.svelte'; import Button from '$lib/components/ui/button/button.svelte'; import Spinner from '$lib/components/ui/spinner/spinner.svelte'; - import Checkbox from '$lib/components/ui/checkbox/checkbox.svelte'; import { Badge } from '$lib/components/ui/badge/index'; import * as Item from '$lib/components/ui/item/index'; import { createEventDispatcher, onDestroy, onMount } from 'svelte'; @@ -16,7 +15,6 @@ import { get, readable, writable } from 'svelte/store'; import { currentEditingRecipeProductCode, - lastRequestSheetPrice, latestRecipeToppingData, materialFromMachineQuery, materialFromServerQuery, @@ -29,8 +27,6 @@ import { addNotification } from '$lib/core/stores/noti'; import { env } from '$env/dynamic/public'; import { sendCommand, sendReset } from '$lib/core/brew/command'; - import { sendCommandRequest } from '$lib/core/handlers/ws_messageSender'; - import { needPermission } from '$lib/core/handlers/permissionHandler'; import { isAdbWriterAvailable } from '$lib/core/stores/adbWriter'; import { sendToAndroid } from '$lib/core/stores/adbWriter'; import { departmentStore } from '$lib/core/stores/departments'; @@ -46,10 +42,6 @@ let menuName: string = $state(''); let menuCurrentPrice: number = $state(0); let isMenuHideByPrice: boolean = $state(false); - let sheetPriceValue: number | null = $state(null); - let showSheetPrice: boolean = $state(false); - let canEditSheetPrice: boolean = $state(false); - let sheetPriceRawCell: any = $state(null); let materialSnapshot: any = $state(); let machineInfoSnapshot: any = $state(); @@ -59,8 +51,6 @@ let toppingSlotState: any = $state([]); - let unsubSheetPrice: (() => void) | null = null; - const recipeDetailDispatch = createEventDispatcher(); function remappingToColumn(data: any[]): RecipelistMaterial[] { @@ -183,22 +173,6 @@ } } - function saveSheetPrice() { - if (!canEditSheetPrice || sheetPriceValue === null) return; - sendCommandRequest('sheet', { - country: get(departmentStore), - content: [ - { - product_code: productCode, - new_price: sheetPriceValue, - cell_coord: sheetPriceRawCell?.coord - } - ], - param: 'price', - action: 'update' - }); - } - async function checkChanges(productCode: string, original: any) { // console.log('old', original, 'updated', recipeListMatState); if (recipeListOriginal.length == 0) { @@ -214,26 +188,6 @@ } } - function updateSheetPrice(sheetData: any) { - if (!productCode) return; - const country = get(departmentStore); - if (!country) return; - - const sheetEntry = sheetData[country]?.[productCode]; - if (sheetEntry && typeof sheetEntry === 'object' && sheetEntry?.value) { - sheetPriceRawCell = sheetEntry; - const parsed = parseInt(sheetEntry.value); - if (!isNaN(parsed) && parsed !== menuCurrentPrice) { - sheetPriceValue = parsed; - showSheetPrice = true; - return; - } - } - - sheetPriceValue = null; - showSheetPrice = false; - } - onMount(() => { machineInfoSnapshot = get(machineInfoStore); @@ -283,19 +237,8 @@ } catch (e) {} } - // save old value + // save old value\ } - - canEditSheetPrice = needPermission('document.write.*'); - - updateSheetPrice(get(lastRequestSheetPrice)); - unsubSheetPrice = lastRequestSheetPrice.subscribe((data) => { - updateSheetPrice(data); - }); - }); - - onDestroy(() => { - if (unsubSheetPrice) unsubSheetPrice(); }); @@ -328,108 +271,25 @@ Info about this menu - - - - Basic Information - - -
-
- - -
-
- - -
-
-
-
+ +
+ + + + +
- - - - - - Additional Recipe Data - - - {#if recipeData} -
-
- - - {recipeData.LastChange ?? 'N/A'} - -
-
- - { - const input = e.target as HTMLInputElement | null; - if (input && input.value !== '') { - const value = parseInt(input.value); - if (!isNaN(value)) { - recipeData.total_time = value; - // Notify parent of change - onPendingChange({ - target: 'recipeData', - ref_pd: productCode, - value: { ...recipeData, total_time: value } - }); - } - } - }} - /> -
-
- -
-
- - { - const input = e.target as HTMLInputElement | null; - if (input) { - recipeData.uriData = input.value; - onPendingChange({ - target: 'recipeData', - ref_pd: productCode, - value: { ...recipeData, uriData: input.value } - }); - } - }} - /> -
-
- {:else} -

No recipe data available

- {/if} -
-
+
+ + + +
+
diff --git a/src/lib/components/recipe-editor-dialog.svelte b/src/lib/components/recipe-editor-dialog.svelte index e593d4b..8ee583d 100644 --- a/src/lib/components/recipe-editor-dialog.svelte +++ b/src/lib/components/recipe-editor-dialog.svelte @@ -30,7 +30,6 @@ machineInfoStore, updateMachineStatus } from '$lib/core/stores/machineInfoStore'; - import { formatCustomDate } from '$lib/helpers/formatDate'; const isDesktop = new MediaQuery('(min-width: 768px)'); @@ -126,7 +125,7 @@ ready_to_send_brew.push(new_change); - callback_revert_value_if_not_save = async (save: any) => { + callback_revert_value_if_not_save = (save: any) => { if (!save) { latestRecipeToppingData.set(topping_value_for_revert); console.log('revert change', get(latestRecipeToppingData)); @@ -142,16 +141,6 @@ // currentData['ToppingSet'] = latestRecipeToppingData; // console.log('current data', currentData); - let curr_user = get(auth); - - let user_info: any; - if (curr_user) { - user_info = { - displayName: curr_user.displayName, - email: curr_user.email, - uid: curr_user.uid - }; - } if (get(referenceFromPage) == 'brew') { // send change to machine @@ -175,29 +164,11 @@ data: ready_to_send_brew[0] } }); - - let country = await adb.pull('/sdcard/coffeevending/country/short'); - let box_id = await adb.pull('/sdcard/coffeevending/.bid'); - - // update last change - // format 16-Feb-2026 10:31:18 - let date = new Date(); - let formatted = formatCustomDate(date); - ready_to_send_brew[0].LastChange = formatted; - - sendMessage({ - type: 'save_recipe', - payload: { - user_info, - country: `${country?.toLowerCase() ?? 'unknown'}_${box_id ?? ''}`, - values: ready_to_send_brew[0] - } - }); } else if (get(referenceFromPage) == 'overview') { sendMessage({ type: 'save_recipe', payload: { - user_info, + user: get(auth)?.displayName ?? 'unknown', country: get(departmentStore) ?? 'unknown', values: currentData } @@ -351,33 +322,31 @@ $effect(() => { // interval check 1s // machine - if (refPage === 'brew') { - interval_get_machine_status = setInterval(() => { - if ( - getMachineStatus() == undefined || - getMachineStatus() == null || - $machineInfoStore?.status === undefined - ) { - // set default now - updateMachineStatus(''); + interval_get_machine_status = setInterval(() => { + if ( + getMachineStatus() == undefined || + getMachineStatus() == null || + $machineInfoStore?.status === undefined + ) { + // set default now + updateMachineStatus(''); + } + + console.log( + 'machine status pinging recipe editor dialog', + getMachineStatus(), + $machineInfoStore?.status + ); + + // update machine status + // check-connection + sendToAndroid({ + type: 'check-connection', + payload: { + start: new Date().toLocaleTimeString() } - - console.log( - 'machine status pinging recipe editor dialog', - getMachineStatus(), - $machineInfoStore?.status - ); - - // update machine status - // check-connection - sendToAndroid({ - type: 'check-connection', - payload: { - start: new Date().toLocaleTimeString() - } - }); - }, 1000); - } + }); + }, 1000); }); onDestroy(() => { diff --git a/src/lib/core/handlers/adbPayloadHandler.ts b/src/lib/core/handlers/adbPayloadHandler.ts index fbc3f2b..8d6f63d 100644 --- a/src/lib/core/handlers/adbPayloadHandler.ts +++ b/src/lib/core/handlers/adbPayloadHandler.ts @@ -1,4 +1,3 @@ -import { get } from 'svelte/store'; import { updateMachineStatus } from '../stores/machineInfoStore'; import { addNotification } from '../stores/noti'; import { @@ -7,7 +6,6 @@ import { } from '../services/androidRecipeExportService'; import { handleIncomingMessages } from './messageHandler'; import { setMenuSaved, setMenuSaveError } from '../stores/menuSaveStore'; -import { recipeFromMachineQuery } from '../stores/recipeStore'; type AdbPayload = { type: string; payload: any }; @@ -106,21 +104,9 @@ async function handleAdbPayload(raw_payload: string) { let plist = payload.payload.split('/'); let pd = plist[0] ?? ''; let total_time = plist[1] ?? ''; - let mode_ref = plist[2] ?? ''; // update recipe data store console.log('brewing finish', pd, 'total time', total_time); - - // update recipe from brew now - let recipeDevSnapshot = get(recipeFromMachineQuery) ?? {}; - let recipe01Snap = recipeDevSnapshot['recipe']; - if (recipe01Snap) { - recipe01Snap[pd].total_time = - mode_ref != 'sim' ? total_time : recipe01Snap[pd].total_time; - - recipeDevSnapshot['recipe'] = recipe01Snap; - recipeFromMachineQuery.set(recipeDevSnapshot); - } } break; diff --git a/src/lib/core/handlers/messageHandler.ts b/src/lib/core/handlers/messageHandler.ts index 61cd6a3..1f8c69b 100644 --- a/src/lib/core/handlers/messageHandler.ts +++ b/src/lib/core/handlers/messageHandler.ts @@ -2,7 +2,6 @@ import { get, writable } from 'svelte/store'; import { addNotification, notiStore } from '../stores/noti'; import { currentRecipeVersionsSelector, - lastRequestSheetPrice, materialFromServerQuery, priceRecipeData, recipeData, @@ -10,8 +9,6 @@ import { recipeLoading, recipeOverviewData, recipeStreamMeta, - streamingRawData, - streamingRawMeta, toppingGroupFromServerQuery, toppingListFromServerQuery } from '../stores/recipeStore'; @@ -39,16 +36,13 @@ import { type RecipeVersion } from '$lib/models/recipe_version.model'; import { goto } from '$app/navigation'; import { socketAlreadySendHeartbeat, socketConnectionOfflineCount } from '../stores/websocketStore'; import type { RecipePrice } from '$lib/models/price.model'; -import { sendCommandRequest, sendMessage } from './ws_messageSender'; +import { sendMessage } from './ws_messageSender'; import { auth as authStore } from '../stores/auth'; -import { v4 as uuidv4 } from 'uuid'; -import { handleSheetResponseFromNoti } from './sheetNotiHandler'; export const messages = writable([]); type WSMessage = { type: string; payload: any }; -// MAXIMUM LIMIT = 1814355 const handlers: Record void> = { chat: (p) => messages.update((m) => [...m, p]), ping: (p) => console.log('ping from server'), @@ -317,9 +311,6 @@ const handlers: Record void> = { } // Default notification handling - let from_service = p.from ?? ''; - let ref_service = p.ref ?? ''; - if (target) { let currentUsername = auth.currentUser?.displayName; if (currentUsername && currentUsername === target) { @@ -362,92 +353,12 @@ const handlers: Record void> = { console.log('get price length: ', content.length); let current_price = get(priceRecipeData); - let lastRequestPriceInstance = get(lastRequestSheetPrice); - let saved_product_code_to_get_from_sheet = []; - let current_meta = get(recipeStreamMeta); - lastRequestPriceInstance[current_meta?.country ?? 'unknown'] = {}; for (const c of content) { current_price[c.ProductCode] = c.NewPrice + (c.StringParam ? `,${c.StringParam}` : ''); - lastRequestPriceInstance[current_meta?.country ?? 'unknown'][c.ProductCode] = ''; - saved_product_code_to_get_from_sheet.push({ - product_code: c.ProductCode - }); } priceRecipeData.set(current_price); - - console.log('check length', saved_product_code_to_get_from_sheet.length); - // set command request to stream mode so - let request_id = uuidv4(); - - lastRequestPriceInstance[request_id] = current_meta?.country ?? ''; - let current_streaming_instance = get(streamingRawData); - current_streaming_instance[request_id] = ''; - streamingRawData.set(current_streaming_instance); - - sendCommandRequest('sheet', { - country: current_meta?.country ?? '', - content: saved_product_code_to_get_from_sheet, - param: 'price', - stream: true, - request_id - }); - - lastRequestSheetPrice.set(lastRequestPriceInstance); }, - // raw_stream: (p) => { - // let streamRawInstance = get(streamingRawData); - // let sub_type = p.sub_type; - // let request_id = p.request_id; - // let size_per_chunk = p.size_per_chunk; - // let total_chunks = p.total_chunks; - // let idx = p.idx; - - // switch (sub_type) { - // case 'price': - // streamingRawMeta.set({ - // id: request_id, - // total_size: total_chunks, - // chunk_size: size_per_chunk, - // progress: 0 - // }); - // break; - // case 'chunk_price': - // streamingRawMeta.set({ - // id: request_id, - // total_size: total_chunks, - // chunk_size: size_per_chunk, - // progress: idx - // }); - - // let raw_payload = p.raw ?? ''; - // streamRawInstance[request_id] += raw_payload; - // streamingRawData.set(streamRawInstance); - - // break; - // case 'end_price': - // let lastRequestPriceInstance = get(lastRequestSheetPrice); - // let country = lastRequestPriceInstance[request_id]; - - // try { - // let raw_payload = JSON.parse(streamRawInstance[request_id]); - // let ref_from_raw = raw_payload.payload.ref ?? ''; - // let from_service_raw = raw_payload.payload.from ?? ''; - // let parsed_payload = raw_payload.payload ?? ''; - - // if (from_service_raw == 'sheet-service') { - // handleSheetResponseFromNoti(parsed_payload, ref_from_raw, country); - // delete streamRawInstance[request_id]; - // streamingRawData.set(streamRawInstance); - // } - // } catch (e) { - // console.log(`end price process error: ${e}`); - // } - - // break; - // default: - // } - // }, heartbeat: (p) => { socketConnectionOfflineCount.set(0); socketAlreadySendHeartbeat.set(0); @@ -484,14 +395,5 @@ export function handleIncomingMessages(raw: string) { addNotification('ERR:No response from server'); return; } - - // raw streaming type - // if (msg.type.startsWith('raw_stream')) { - // // convert - // let sub_type = msg.type.replace('raw_stream_', ''); - // msg.payload.sub_type = sub_type; - // msg.type = 'raw_stream'; - // } - handlers[msg.type]?.(msg.payload); } diff --git a/src/lib/core/handlers/sheetNotiHandler.ts b/src/lib/core/handlers/sheetNotiHandler.ts deleted file mode 100644 index f3c95fa..0000000 --- a/src/lib/core/handlers/sheetNotiHandler.ts +++ /dev/null @@ -1,79 +0,0 @@ -import { get } from 'svelte/store'; -import { lastRequestSheetPrice } from '../stores/recipeStore'; - -export interface PayloadFromSheet { - header: string[]; - key: string; - payload?: GristCell[]; -} - -export interface GristCell { - cells?: { - coord: { - col: number; - row: number; - }; - value: string; - }[]; - row_index?: number; -} - -const PRICE_SHEET_DEFINITION_BY_COUNTRY: any = { - ltu: { - expect_header: ['Name', 'Price in Euro'], - get_header_idx: (x: string[]) => { - let result = []; - for (const header of PRICE_SHEET_DEFINITION_BY_COUNTRY['ltu'].expect_header) { - let found = x.findIndex((y) => y == header); - result.push(found); - } - - return result; - } - } -}; - -export function handleSheetResponseFromNoti(raw_payload: any, ref: string, country?: string) { - switch (ref) { - case 'price': - let price_contents: PayloadFromSheet[] = raw_payload.content; - console.log(`price content length: ${price_contents.length}`); - let header_idx = PRICE_SHEET_DEFINITION_BY_COUNTRY[country ?? 'unknown'].get_header_idx( - price_contents[0].header - ); - console.log(`header idx: ${header_idx}`); - - let lastRequestSheetInstance = get(lastRequestSheetPrice); - let products = lastRequestSheetInstance[country ?? 'unknown']; - - for (let c of price_contents) { - let curr_product_code = c.key; - // price idx should be last - let price_idx = header_idx[header_idx.length - 1]; - let price_rows = c.payload; - if (!price_rows) { - continue; - } - // get last because last row will always override - let expected_row = price_rows[price_rows.length - 1]; - if (expected_row != undefined && expected_row.cells != undefined) { - let price_col = expected_row.cells[price_idx]; - products[curr_product_code] = price_col; - console.log(`[handleSheetPrice][country] ${curr_product_code} --> ${price_col}`); - } else { - console.log( - `[handleSheetPrice][country] ${curr_product_code} not found cell, ${JSON.stringify(price_rows)}` - ); - } - } - - lastRequestSheetInstance[country ?? 'unknown'] = products; - lastRequestSheetPrice.set({ - ...lastRequestSheetInstance, - products - }); - - break; - default: - } -} diff --git a/src/lib/core/services/sheetService.ts b/src/lib/core/services/sheetService.ts index 8fb6c39..2e15f35 100644 --- a/src/lib/core/services/sheetService.ts +++ b/src/lib/core/services/sheetService.ts @@ -18,29 +18,6 @@ export function requestCatalogs(country: string): boolean { }); } -export function requestPriceSlots(country: string): boolean { - return sendCommandRequest('sheet', { - country: country, - param: 'priceslot' - }); -} - -export function updatePriceSlot( - country: string, - content: { - slot: number; - name: string; - description: string; - products: { product_code: string; price: number | null; row_index?: number }[]; - } -): boolean { - return sendCommandRequest('sheet', { - country: country, - content: content, - param: 'update/priceslot' - }); -} - export function enterRoom(country: string, catalog: string): boolean { return sendCommandRequest('sheet', { country: country, diff --git a/src/lib/core/stores/recipeStore.ts b/src/lib/core/stores/recipeStore.ts index ac21a3a..0a97cc2 100644 --- a/src/lib/core/stores/recipeStore.ts +++ b/src/lib/core/stores/recipeStore.ts @@ -23,17 +23,6 @@ export const recipeOverviewData = writable(null); export const materialData = writable(); // price from recipe repo export const priceRecipeData = writable<{ [key: string]: any }>({}); -export const lastRequestSheetPrice = writable<{ [key: string]: any }>({}); - -// Streaming raw -export const streamingRawData = writable<{ [key: string]: any }>({}); -export const streamingRawMeta = writable<{ - id: string; - total_size: number; - chunk_size: number; - progress: number; - country?: string; -} | null>(null); // machine recipe export const recipeFromMachine = writable(null); diff --git a/src/lib/core/stores/sheetStore.ts b/src/lib/core/stores/sheetStore.ts index eb2d626..5a2e0dc 100644 --- a/src/lib/core/stores/sheetStore.ts +++ b/src/lib/core/stores/sheetStore.ts @@ -17,24 +17,6 @@ export interface CatalogsResponse { export const sheetCatalogs = writable([]); export const sheetCatalogsLoading = writable(false); -export interface PriceSlotProduct { - product_code: string; - name: string; - price: number | null; - row_index?: number; -} - -export interface PriceSlot { - slot: number; - name: string; - description: string; - products: PriceSlotProduct[]; -} - -export const priceSlots = writable>({}); -export const priceSlotsLoading = writable(false); -export const priceSlotsError = writable(null); - export const countryPrimaryLanguageMap: Record = { THAI: 'Thai', tha: 'Thai', diff --git a/src/lib/core/stores/websocketStore.ts b/src/lib/core/stores/websocketStore.ts index 720fb7e..d43e064 100644 --- a/src/lib/core/stores/websocketStore.ts +++ b/src/lib/core/stores/websocketStore.ts @@ -10,7 +10,6 @@ import { permission } from './permissions'; let socket: WebSocket | null = null; let reconnectTimeout: any; -let socketCheck: any; const ENABLE_WS_DEBUG: boolean = false; export const socketConnectionOfflineCount = writable(0); @@ -96,7 +95,7 @@ export function connectToWebsocket(id_token?: string) { console.log(socket); // heartbeat 10s - socketCheck = setInterval(() => { + setInterval(() => { if (get(socketAlreadySendHeartbeat) > 0) { let heartbeat_may_offline_count = get(socketConnectionOfflineCount); @@ -144,8 +143,6 @@ export function connectToWebsocket(id_token?: string) { socketStore.set(null); socket = null; - clearInterval(socketCheck); - if (auth.currentUser && !socket) { console.log('try reconnect websocket ...'); // retry again diff --git a/src/lib/core/types/outMessage.ts b/src/lib/core/types/outMessage.ts index f51bd46..ff24f95 100644 --- a/src/lib/core/types/outMessage.ts +++ b/src/lib/core/types/outMessage.ts @@ -36,10 +36,9 @@ export type OutMessage = | { type: 'save_recipe'; payload: { - user_info: any; + user: string; country: string; values: any; - plugins?: string; }; } | { diff --git a/src/lib/helpers/formatDate.ts b/src/lib/helpers/formatDate.ts deleted file mode 100644 index 9015264..0000000 --- a/src/lib/helpers/formatDate.ts +++ /dev/null @@ -1,18 +0,0 @@ -export function formatCustomDate(date: Date): string { - const formatter = new Intl.DateTimeFormat('en-GB', { - day: '2-digit', - month: 'short', - year: 'numeric', - hour: '2-digit', - minute: '2-digit', - second: '2-digit', - hour12: false - }); - - // Extract all the formatted parts into an object - const parts = formatter.formatToParts(date); - const partMap = Object.fromEntries(parts.map((p) => [p.type, p.value])); - - // Construct your exact string: 16-Feb-2026 10:31:18 - return `${partMap.day}-${partMap.month}-${partMap.year} ${partMap.hour}:${partMap.minute}:${partMap.second}`; -} diff --git a/src/routes/(authed)/+layout.svelte b/src/routes/(authed)/+layout.svelte index 926c2d3..34b2e1b 100644 --- a/src/routes/(authed)/+layout.svelte +++ b/src/routes/(authed)/+layout.svelte @@ -104,7 +104,7 @@ if (adbReconnectTriedForUid !== currentUser.uid && !adb.getAdbInstance()) { adbReconnectTriedForUid = currentUser.uid; - // void tryAutoConnect(); + void tryAutoConnect(); } }); diff --git a/src/routes/(authed)/departments/+page.svelte b/src/routes/(authed)/departments/+page.svelte index 77ce3d9..e2e80f6 100644 --- a/src/routes/(authed)/departments/+page.svelte +++ b/src/routes/(authed)/departments/+page.svelte @@ -25,9 +25,7 @@ console.log(get(departmentStore)); departmentStore.set(cnt); - if (refPage === 'priceslot') { - await goto(`/sheet/priceslot/${cnt}`); - } else if (refPage === 'sheet') { + if (refPage === 'sheet') { await goto(`/sheet/overview/${cnt}`); } else { await goto('/recipe/overview'); diff --git a/src/routes/(authed)/recipe/material/+page.svelte b/src/routes/(authed)/recipe/material/+page.svelte index e7beba8..e69de29 100644 --- a/src/routes/(authed)/recipe/material/+page.svelte +++ b/src/routes/(authed)/recipe/material/+page.svelte @@ -1,842 +0,0 @@ - - -
-
-
-
-

- Android Recipe -

-

Material Setting

- - {#if loadedRecipePath} -

Loaded: {loadedRecipePath}

- {/if} -
- -
- -
-
-
- -
-
-
-
Total materials
-
{materials.length}
-
-
-
-
Active materials
-
{activeMaterialCount}
-
-
-
-
Channels in use
-
{channelSummary.length}
-
-
- - - - - {existingMaterial ? 'Edit Material' : 'Add Material'} - - Create or update one MaterialSetting entry. The JSON preview shows the payload - before saving to Android. - - - -
- - - {existingMaterial ? 'Edit Material' : 'Add Material'} - - - {#if existingMaterial} -
- Material ID {form.id} already exists. Saving will update this MaterialSetting. -
- {/if} - -
-
- - -
-
- - -
-
- - -
-
- -
-
- - -
-
- - -
-
- -
-
- - -
-
- - -
-
- -
-
- - -
-
- - -
-
- - -
-
- -
- - -

- Examples: refill=$bag,sum=$gram,rec=$gram, - refill=$L,sum=$ml,rec=$ml -

-
- -
-
- - -
-
- - -
-
- -
-
- - -
-
- - -
-
- - -
-
- - -
-
- -
- - - - - -
- -
- - -
- -
- - - -
-
-
- - - - Preview JSON - - Payload that will be upserted into MaterialSetting. - - - -
{previewJson}
-
-
-
-
-
- - - -
-
- Existing Materials - - Use Edit to update a material, or Delete to remove it after confirmation. - -
- -
-
- -
- -
- {#each channelSummary as channel} - - {channel.label}: {channel.count} - - {/each} -
-
-
- {#if loading} -
- - Loading materials from Android... -
- {:else if !devRecipe} -
Connect and load recipe first.
- {:else if filteredMaterials.length === 0} -
No materials found.
- {:else} - -
- {#each filteredMaterials as material} -
- {material.id} - {material.materialName || '-'} - {material.materialOtherName || '-'} - {material.pathOtherName || '-'} - - {(material.isUse as boolean) !== false ? 'Use' : 'Not use'} - -
- - -
-
- {/each} -
- {/if} -
-
-
- - - - - Delete Material? - - This will remove the material from MaterialSetting in the Android recipe JSON. - - - - {#if pendingDeleteMaterial} -
-
Material
-
{pendingDeleteMaterial.id}
-
- {pendingDeleteMaterial.materialName || - pendingDeleteMaterial.materialOtherName || - 'Unnamed'} -
-
- {/if} - -
- - -
-
-
-
diff --git a/src/routes/(authed)/recipe/topping/+page.svelte b/src/routes/(authed)/recipe/topping/+page.svelte index c0e2a25..e69de29 100644 --- a/src/routes/(authed)/recipe/topping/+page.svelte +++ b/src/routes/(authed)/recipe/topping/+page.svelte @@ -1,1071 +0,0 @@ - - -
-
-
-
-

- Android Recipe -

-

Topping

- - {#if loadedRecipePath} -

Loaded: {loadedRecipePath}

- {/if} -
- - -
-
- -
-
-
-
ToppingList
-
{toppingList.length}
-
-
-
-
Active list items
-
{activeListCount}
-
-
-
-
ToppingGroup
-
{toppingGroups.length}
-
-
- - - -
-
- {activeTab === 'list' ? 'Topping List' : 'Topping Group'} - - Switch between list items and groups. Edit/Delete actions are explicit per row. - -
-
- - -
-
-
- -
- - {#if activeTab === 'list'} - - {:else} - - {/if} -
- -
- {#if loading} -
- - Loading toppings from Android... -
- {:else if !devRecipe} -
Connect and load recipe first.
- {:else if activeTab === 'list'} - {#if filteredToppingList.length === 0} -
No topping list items found.
- {:else} - -
- {#each filteredToppingList as item} -
- {item.id} - {item.name || '-'} - {item.otherName || '-'} - - {(item.isUse as boolean) !== false ? 'Use' : 'Not use'} - -
- - -
-
- {/each} -
- {/if} - {:else if filteredToppingGroups.length === 0} -
No topping groups found.
- {:else} - -
- {#each filteredToppingGroups as group} -
- {group.groupID} - {group.name || '-'} - {group.otherName || '-'} - {group.idInGroup || '-'} - - {(group.inUse as boolean) !== false ? 'Use' : 'Not use'} - -
- - -
-
- {/each} -
- {/if} -
-
-
- - - - - {existingListItem ? 'Edit Topping' : 'Add Topping'} - Manage one item inside ToppingList. - - -
- - -
-
- - -
-
- - -
-
- - -
-
- -
-
- - -
-
- - -
-
- - - -
-
-
-
Recipe steps
-
- Some toppings need multiple recipe JSON steps, such as sugar plus stir. -
-
- -
- -
- {#each listForm.recipeSteps as step, index} -
-
-
Step {index + 1}
-
- - -
-
- -
-
- - -
-
- - -
-
- - -
-
- -
- - -
-
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- -
- - -
-
- {/each} -
-
- -
- - -
-
-
- - - - Preview JSON - - -
{JSON.stringify(
-								listPreview,
-								null,
-								2
-							)}
-
-
-
-
-
- - - - - {existingGroup ? 'Edit Topping Group' : 'Add Topping Group'} - Manage one group inside ToppingGroup. - - -
- - -
-
- - -
-
- - -
- -
- -
-
- - -
-
- - -
-
- -
- - -
- -
- - -

Comma-separated `ToppingList.id` values.

-
- -
- - -
-
-
- - - - Preview JSON - - -
{JSON.stringify(
-								groupPreview,
-								null,
-								2
-							)}
-
-
-
-
-
- - - - - Delete Topping? - This will remove the selected entry from Android recipe JSON. - - - {#if pendingDelete} -
-
- {pendingDelete.type === 'list' ? 'ToppingList' : 'ToppingGroup'} -
-
- {pendingDelete.type === 'list' - ? (pendingDelete.item as ToppingListItem).id - : (pendingDelete.item as ToppingGroup).groupID} -
-
- {pendingDelete.item.name || pendingDelete.item.otherName || 'Unnamed'} -
-
- {/if} - -
- - -
-
-
-
diff --git a/src/routes/(authed)/sheet/priceslot/[country]/+page.svelte b/src/routes/(authed)/sheet/priceslot/[country]/+page.svelte deleted file mode 100644 index 86a2542..0000000 --- a/src/routes/(authed)/sheet/priceslot/[country]/+page.svelte +++ /dev/null @@ -1,586 +0,0 @@ - - -
-
-
-
-

- PriceSlot [ {selectedCountry.toUpperCase()} ] -

-

- Edit sheet PriceSlot names, descriptions, and product prices. -

-
-
- {#if enabledCountries.length > 0} - { - if (v) { - selectedCountry = v; - goto(`/sheet/priceslot/${v}`); - } - }} - > - - {selectedCountry.toUpperCase()} - - - {#each enabledCountries as country} - - {country.toUpperCase()} - - {/each} - - - {/if} - - -
-
- -
- {#each slots as slot} - - {/each} -
- -
-
-
-
-

PriceSlot{selectedSlot}

- - {hasChanges ? `${changedCount} changes` : 'No changes'} - -
- -
- -
- - updateSlotField('name', event.currentTarget.value)} - /> -
- -
- - updateSlotField('description', event.currentTarget.value)} - /> -
- -
- - - -
-
-
- -
-
-
- -
- - -
-
-

- Showing {filteredProducts.length} of {currentSlot.products.length} products -

-
- -
- - - - ProductCode - ProductName [{selectedCountryLanguage}] - ProductNameEng - Price - - - - {#each filteredProducts as product (product.product_code)} - {@const productNames = getProductNames(product)} - - - {product.product_code} - - {productNames.local} - {productNames.english} - - - updateProductPrice(product.product_code, event.currentTarget.value)} - /> - - - {/each} - {#if filteredProducts.length === 0} - - - No product code found. - - - {/if} - - -
-
-
-
- - - - - Create PriceSlot - - Choose how to adjust base prices before creating a new PriceSlot. - - - -
- - -
-
- - { - if (v) adjustmentMode = v as AdjustmentMode; - applyCreateTemplate(); - }} - > - - {adjustmentModeLabels[adjustmentMode]} - - - Increase by Percentage (%) - Increase by Fixed Amount - Decrease by Percentage (%) - Decrease by Fixed Amount - - -
- -
- - { - adjustmentValue = Number(event.currentTarget.value); - applyCreateTemplate(); - }} - /> -
- -
- - (createName = event.currentTarget.value)} - /> -
- -
- - (createDescription = event.currentTarget.value)} - /> -
-
-
- - - - - -
-
diff --git a/src/routes/(authed)/tools/adv-upload/+page.svelte b/src/routes/(authed)/tools/adv-upload/+page.svelte index 1735f59..ec63447 100644 --- a/src/routes/(authed)/tools/adv-upload/+page.svelte +++ b/src/routes/(authed)/tools/adv-upload/+page.svelte @@ -28,8 +28,8 @@ // pushes the selected .mp4 (from the browser), then // `ls -l > sync_1.file` on the machine, pulls it, uploads it. // ⚠️ FULL REPLACE — requires ADB; select the COMPLETE adv set. - const MANIFEST_MODE: 'ftp_listdir' | 'machine' = 'ftp_listdir'; - //const MANIFEST_MODE: 'ftp_listdir' | 'machine' = 'machine'; + //const MANIFEST_MODE: 'ftp_listdir' | 'machine' = 'ftp_listdir'; + const MANIFEST_MODE: 'ftp_listdir' | 'machine' = 'machine'; // ───────────────────────────────────────────────────────────────────────── // adv folder on the machine. Domestic Thailand uses the flat folder; every diff --git a/src/routes/(authed)/tools/brew/+page.svelte b/src/routes/(authed)/tools/brew/+page.svelte index e5e4c92..eddda99 100644 --- a/src/routes/(authed)/tools/brew/+page.svelte +++ b/src/routes/(authed)/tools/brew/+page.svelte @@ -183,7 +183,6 @@ await startFetchRecipeFromMachine(); await loadEssentialFiles(); await loadStagedMenusFromAndroid(); - await openBrewApp(); } async function tryAutoConnect() { @@ -234,55 +233,6 @@ } } - async function openBrewApp() { - try { - let instance = adb.getAdbInstance(); - if (instance) { - try { - // bypass - await adb.executeCmd('echo -n hurr > /sdcard/coffeevending/ignore_pass'); - } catch (e) {} - - let result = await adb.executeCmd( - 'am start -n com.forthvending.coffeemain/com.forthvending.coffeemain.MainActivity' - ); - // if (result?.output) { - // toast.success('Open app success!'); - // machineStatus = 'open app success, check the screen and put the password'; - // } else if (result?.error) { - // // case usb connection cutoff - // if (result.error === 'ExactReadableEndedError') { - // toast.warning('Connection unstable'); - // machineStatus = 'app maybe opened, check the screen'; - // } else { - // throw new Error(`Exit ${result.exitCode}. ${result.error}`); - // } - // } else { - // throw new Error('Instance not found or error while executing'); - // } - - // hasOpenedBrewOnce = true; - - try { - // bypass - await adb.executeCmd('echo -n hurr > /sdcard/coffeevending/ignore_pass'); - } catch (e) {} - - setTimeout(async () => { - try { - // bypass - await adb.executeCmd('input tap 336 795'); - } catch (e) {} - }, 3000); - } - } catch (e: any) { - // machineStatus = 'Cannot open brew app'; - // toast.error('Error while trying to open brew app, please check the screen. ', { - // description: e.toString() - // }); - } - } - async function ensureAndroidSocket() { if (isAdbWriterAvailable()) return true;