Merge branch 'master' into feature/edit-recipe-event-bus

This commit is contained in:
pakintada@gmail.com 2026-07-01 08:53:13 +07:00
commit 3625712678
28 changed files with 6414 additions and 783 deletions

View file

@ -8,10 +8,18 @@ import {
markSheetPriceAsSent,
sheetPriceLoading,
streamingRawData,
setPendingProductCodesCountry
setPendingProductCodesCountry,
setPendingPriceSlotsCountry,
priceSlotsLoading,
resetPriceSlotsCountry
} from '../stores/sheetStore';
import type { PriceSlot } from '../stores/sheetStore';
import { setGenLayoutGenerating } from '../stores/genLayoutStore';
type SheetCellUpdate = { value: string; coord: { row: number; col: number } };
type SheetRowUpdate = { row_index: number; cells: SheetCellUpdate[] };
type SheetRowCreate = { header?: string[]; cells: string[] };
export async function requestCatalogs(country: string): Promise<boolean> {
return await sendCommandRequest('sheet', {
country: country,
@ -19,27 +27,179 @@ export async function requestCatalogs(country: string): Promise<boolean> {
});
}
export async function requestPriceSlots(country: string): Promise<boolean> {
/**
* Register a newly created catalog as a Grist table so it shows in the overview
* and menus can be added to it. `catalog` is the .skt filename produced by
* /api/catalog-create (e.g. "page_catalog_group_pro_summer_splash.skt").
*/
export async function addCatalog(
country: string,
catalogName: string,
catalog: string
): Promise<boolean> {
return await sendCommandRequest('sheet', {
country: country,
param: 'priceslot'
catalog: catalog,
catalog_name: catalogName,
param: 'add/catalog'
});
}
export async function requestPriceSlots(country: string): Promise<boolean> {
setPendingPriceSlotsCountry(country);
resetPriceSlotsCountry(country);
return requestPriceSlotOption(country, 'PriceSlot');
}
export async function requestPriceSlot(country: string, slotNumber: number): Promise<boolean> {
setPendingPriceSlotsCountry(country);
return requestPriceSlotOption(country, `PriceSlot${slotNumber}`);
}
async function requestPriceSlotOption(country: string, option: string): Promise<boolean> {
const request_id = crypto.randomUUID();
streamingRawData.update((data) => ({
...data,
priceslot: {
request_id,
country,
chunks: [],
rawParts: []
}
}));
priceSlotsLoading.set(true);
const values = {
country: country,
param: 'price',
option,
stream: true,
request_id
};
console.log('[sheetService] Sending PriceSlot request:', values);
const sent = await sendCommandRequest('sheet', values);
console.log('[sheetService] PriceSlot request sent:', sent);
if (!sent) {
priceSlotsLoading.set(false);
}
return sent;
}
export async function refreshPriceSlotList(country: string): Promise<boolean> {
return requestPriceSlotOption(country, 'PriceSlot');
}
export async function updatePriceSlot(
country: string,
content: {
slot: number;
name: string;
description: string;
products: { product_code: string; price: number | null; row_index?: number }[];
}
slot: PriceSlot,
content: SheetRowUpdate[]
): Promise<boolean> {
return await sendCommandRequest('sheet', {
// console.log('[sheetService] Sending PriceSlot update:', {
// country,
// slot: slot.slot,
// name: slot.name,
// description: slot.description,
// kind: slot.kind,
// rows: content.length,
// param: 'update/price',
// option: `PriceSlot${slot.slot}`
// });
const sent = await sendCommandRequest('sheet', {
country: country,
content: content,
param: 'update/priceslot'
param: 'update/price',
option: `PriceSlot${slot.slot}`
});
console.log('[sheetService] PriceSlot update sent:', {
country,
slot: slot.slot,
sent
});
return sent;
}
export async function addPriceSlot(
country: string,
slot: PriceSlot,
content: SheetRowCreate[]
): Promise<boolean> {
console.log('[sheetService] Sending PriceSlot create:', {
country,
slot: slot.slot,
name: slot.name,
description: slot.description,
kind: slot.kind,
rows: content.length,
param: 'add/price',
option: `PriceSlot${slot.slot}`
});
const sent = await sendCommandRequest('sheet', {
country: country,
content: content,
param: 'add/price',
option: `PriceSlot${slot.slot}`
});
console.log('[sheetService] PriceSlot create sent:', {
country,
slot: slot.slot,
sent
});
return sent;
}
export async function addPriceSlotRows(
country: string,
slot: PriceSlot,
content: SheetRowCreate[]
): Promise<boolean> {
if (!content || content.length === 0) return true;
const sent = await sendCommandRequest('sheet', {
country: country,
content: content,
param: 'add/price',
option: `PriceSlot${slot.slot}`
});
console.log('[sheetService] PriceSlot rows add sent:', {
country,
slot: slot.slot,
rows: content.length,
sent
});
return sent;
}
export async function deletePriceSlotRows(
country: string,
slot: PriceSlot,
rowIds: number[]
): Promise<boolean> {
if (!rowIds || rowIds.length === 0) return true;
const sent = await sendCommandRequest('sheet', {
country: country,
content: rowIds.map((target_id) => ({ target_id })),
param: 'delete/price',
option: `PriceSlot${slot.slot}`
});
console.log('[sheetService] PriceSlot rows delete sent:', {
country,
slot: slot.slot,
rows: rowIds.length,
sent
});
return sent;
}
export async function enterRoom(country: string, catalog: string): Promise<boolean> {
@ -188,9 +348,13 @@ export async function requestGenLayout(country: string): Promise<boolean> {
* Request price data from sheet for specific product codes
* NOTE: Can only send once per type (price). Use hasSheetPriceBeenSent to check.
*/
export async function requestSheetPrice(country: string, productCodes: string[]): Promise<boolean> {
export async function requestSheetPrice(
country: string,
productCodes: string[],
force = false
): Promise<boolean> {
// Check if already sent
if (hasSheetPriceBeenSent('price')) {
if (!force && hasSheetPriceBeenSent('price')) {
logger.warn('[sheetService] Price request already sent, skipping');
return false;
}
@ -232,6 +396,48 @@ export async function requestSheetPrice(country: string, productCodes: string[])
country: country,
content: content,
param: 'price',
option: 'price',
stream: true,
request_id
});
console.log('[sheetService] Sheet price request sent:', { country, request_id, sent });
if (sent) {
markSheetPriceAsSent('price');
} else {
sheetPriceLoading.set(false);
}
return sent;
}
export async function requestAllSheetPrice(country: string, force = false): Promise<boolean> {
if (!force && hasSheetPriceBeenSent('price')) {
console.warn('[sheetService] Price request already sent, skipping');
return false;
}
const request_id = crypto.randomUUID();
streamingRawData.update((data) => ({
...data,
price: {
request_id,
country,
chunks: [],
rawParts: []
}
}));
sheetPriceLoading.set(true);
console.log('[sheetService] Sending all sheet price request:', { country, request_id });
const sent = await sendCommandRequest('sheet', {
country,
content: [],
param: 'price',
option: 'price',
stream: true,
request_id
});