wip: add more detail in recipe dialog

Signed-off-by: pakintada@gmail.com <Pakin>
This commit is contained in:
pakintada@gmail.com 2026-06-10 15:24:21 +07:00
parent 8b0479bf58
commit be785825fe
4 changed files with 202 additions and 25 deletions

View file

@ -5,8 +5,6 @@ Idea, Issue, Work Tracking
[Pending]
- [] #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
@ -19,5 +17,7 @@ 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]

BIN
bun.lockb

Binary file not shown.

View file

@ -74,7 +74,7 @@
"@yume-chan/scrcpy": "^2.3.0",
"@yume-chan/stream-extra": "^2.5.3",
"animejs": "^4.3.6",
"firebase": "^12.11.0",
"firebase": "^12.14.0",
"idb": "^8.0.3",
"mode-watcher": "^1.1.0",
"usb": "^2.17.0",

View file

@ -16,6 +16,7 @@
import { get, readable, writable } from 'svelte/store';
import {
currentEditingRecipeProductCode,
lastRequestSheetPrice,
latestRecipeToppingData,
materialFromMachineQuery,
materialFromServerQuery,
@ -28,6 +29,8 @@
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';
@ -43,6 +46,10 @@
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();
@ -52,6 +59,8 @@
let toppingSlotState: any = $state([]);
let unsubSheetPrice: (() => void) | null = null;
const recipeDetailDispatch = createEventDispatcher();
function remappingToColumn(data: any[]): RecipelistMaterial[] {
@ -167,6 +176,22 @@
}
}
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) {
@ -182,6 +207,26 @@
}
}
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);
@ -231,8 +276,19 @@
} 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();
});
</script>
@ -265,31 +321,152 @@
<Card.Description>Info about this menu</Card.Description>
</Card.Header>
<Card.Content class="grid gap-6">
<div class="grid grid-cols-2 gap-6">
<div class="grid grid-flow-row gap-3">
<Label for="tabs-menu-name">Name</Label>
<Input id="tabs-menu-name" value={recipeData['name'] ?? ''} />
<!-- Basic Info Card -->
<Card.Root class="mb-4">
<Card.Header>
<Card.Title>Basic Information</Card.Title>
</Card.Header>
<Card.Content class="space-y-4">
<div class="grid grid-cols-2 gap-4">
<div class="space-y-2">
<Label for="tabs-menu-name">Name</Label>
<Input id="tabs-menu-name" value={recipeData['name'] ?? ''} />
</div>
<div class="space-y-2">
<Label for="tabs-menu-other-name">Other Name</Label>
<Input id="tabs-menu-other-name" value={recipeData['otherName'] ?? ''} />
</div>
</div>
</Card.Content>
</Card.Root>
<div class="grid grid-flow-row gap-3">
<Label for="tabs-menu-other-name">Other Name</Label>
<Input id="tabs-menu-other-name" value={recipeData['otherName'] ?? ''} />
<!-- Price Information Card -->
<Card.Root class="mb-4">
<Card.Header>
<Card.Title>Price Information</Card.Title>
</Card.Header>
<Card.Content class="space-y-4">
<div class="space-y-4">
<!-- Current Price -->
<div class="space-y-2">
<Label for="tabs-menu-price">Price</Label>
<Input id="tabs-menu-price" value={menuCurrentPrice} />
</div>
{#if showSheetPrice}
<!-- Sheet Price (when different) -->
<div class="space-y-2">
<Label for="tabs-menu-sheet-price">Price from Sheet</Label>
<div class="flex flex-row gap-2">
<Input
id="tabs-menu-sheet-price"
bind:value={sheetPriceValue}
disabled={!canEditSheetPrice}
/>
{#if canEditSheetPrice}
<Button onclick={saveSheetPrice} class="btn-sm">
Save
</Button>
{/if}
</div>
</div>
{/if}
<!-- Disabled by Price -->
<div class="space-y-2">
<div class="flex flex-row items-center gap-2">
<Checkbox
id="disable-menu-by-price"
checked={isMenuHideByPrice}
/>
<span>Disabled by Price</span>
</div>
</div>
</div>
</div>
</Card.Content>
</Card.Root>
<div class="grid grid-cols-2 gap-3">
<!-- price -->
<div>
<Label for="tabs-menu-price">Price</Label>
<Input id="tabs-menu-price" value={menuCurrentPrice} />
</div>
<b> Disabled </b>
<Checkbox id="disable-menu-by-price" checked={isMenuHideByPrice} />
</div>
</Card.Content>
<!-- Additional Recipe Data Card -->
<Card.Root>
<Card.Header>
<Card.Title>Additional Recipe Data</Card.Title>
</Card.Header>
<Card.Content class="space-y-4">
{#if recipeData}
<div class="space-y-3">
<div class="space-y-2">
<Label for="tabs-last-change">Last Change</Label>
<span id="tabs-last-change" class="text-sm text-muted-foreground block">
{recipeData.LastChange ?? 'N/A'}
</span>
</div>
<div class="space-y-2">
<Label for="tabs-total-time">Total Time (seconds)</Label>
<Input
id="tabs-total-time"
type="number"
value={String(recipeData.total_time ?? '')}
oninput={(e) => {
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 }
});
}
}
}}
/>
</div>
<div class="space-y-2">
<Label class="flex flex-row items-center gap-2">
<Checkbox
id="tabs-use-gram"
checked={recipeData.useGram ?? false}
onchange={(e) => {
const checkbox = e.target as HTMLInputElement | null;
if (checkbox) {
recipeData.useGram = checkbox.checked;
onPendingChange({
target: 'recipeData',
ref_pd: productCode,
value: { ...recipeData, useGram: checkbox.checked }
});
}
}}
/>
<span>Use Gram for Measurement</span>
</Label>
</div>
<div class="space-y-2">
<Label for="tabs-uri-data">URI Data</Label>
<Input
id="tabs-uri-data"
value={recipeData.uriData ?? ''}
oninput={(e) => {
const input = e.target as HTMLInputElement | null;
if (input) {
recipeData.uriData = input.value;
onPendingChange({
target: 'recipeData',
ref_pd: productCode,
value: { ...recipeData, uriData: input.value }
});
}
}}
/>
</div>
</div>
{:else}
<p class="text-muted-foreground">No recipe data available</p>
{/if}
</Card.Content>
</Card.Root>
</Card.Root>
</Tabs.Content>