enh
This commit is contained in:
parent
c4a33b91da
commit
1e7db8f016
12 changed files with 12724 additions and 7674 deletions
|
|
@ -79,7 +79,9 @@
|
|||
"Shell(cd /Users/mohammedshafiuddin/WebDev/freshyo && grep -c \"add-slot-fab\" \"test-results/specs-product-lifecycle-pr-e8d1e-e-→-update-→-slot-→-suspend-chromium/error-context.md\"; grep -ao \"add-slot-fab\" \"test-results/specs-product-lifecycle-pr-e8d1e-e-→-update-→-slot-→-suspend-chromium/error-context.md\" | head; echo \"--- tail of snapshot:\"; sed -n '/```yaml/,/```/p' \"test-results/specs-product-lifecycle-pr-e8d1e-e-→-update-→-slot-→-suspend-chromium/error-context.md\" | tail -25)",
|
||||
"Shell(cd /Users/mohammedshafiuddin/WebDev/freshyo && npx tsc --noEmit -p tests 2>&1 | tail -5; echo \"tsc_exit=$?\"; bun run test:e2e > /tmp/e2e_run8.log 2>&1; echo \"exit=$?\" >> /tmp/e2e_run8.log)",
|
||||
"Shell(cd /Users/mohammedshafiuddin/WebDev/freshyo && npx tsc --noEmit -p tests 2>&1 | tail -5; echo \"tsc_exit=$?\"; bun run test:e2e > /tmp/e2e_run9.log 2>&1; echo \"exit=$?\" >> /tmp/e2e_run9.log)",
|
||||
"Shell(DEBUG=pw:browser npx playwright test tests/specs/smoke.spec.ts 2 >& 1)"
|
||||
"Shell(DEBUG=pw:browser npx playwright test tests/specs/smoke.spec.ts 2 >& 1)",
|
||||
"Shell(cd /Users/mohammedshafiuddin/WebDev/freshyo && git diff product_to_sku_c1 -- apps/user-ui/hooks/cart-query-hooks.tsx apps/user-ui/hooks/useUploadToObjectStore.ts apps/user-ui/eas.json apps/user-ui/'(drawer)' 2>/dev/null; git diff product_to_sku_c1 -- \"apps/user-ui/app/(drawer)/(tabs)/me/addresses/index.tsx\" \"apps/user-ui/app/(drawer)/(tabs)/me/my-orders/index.tsx\" | head -160)",
|
||||
"Shell(cd /Users/mohammedshafiuddin/WebDev/freshyo/packages/db_helper_sqlite && npx tsc --noEmit 2>&1 | tail -8; echo \"sqlite_exit=$?\"; echo \"=== user-ui ===\"; cd /Users/mohammedshafiuddin/WebDev/freshyo/apps/user-ui && npx tsc --noEmit 2>&1 | tee /tmp/uui_tsc.txt | tail -5; echo \"userui_errors=$(grep -cE 'error TS' /tmp/uui_tsc.txt)\")"
|
||||
],
|
||||
"deny": [],
|
||||
"defaultMode": "default"
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
# Taste
|
||||
- Defines tunable/magic numbers as named module-level constants in the SAME file where they are used (e.g., `const TOKENS_PER_QUEUE_MESSAGE = 5` next to the code it configures, with a short explanatory comment) instead of inline literals or a shared/global config — explicitly stated: "Define 5 as a constant in the same file." Confidence: 0.7
|
||||
- Prefers that the agent not run typechecks; instead, read the project's AGENTS.md for instructions on what to do/not do before finalizing work. Confidence: 0.9
|
||||
- Judges completion by seeing the feature live in the running app ("I still don't see it on the /home route page"), so for data-driven features the agent must verify the app's actual runtime data source (API base URL, cache/backend) has the required data — not just that code builds and typechecks. Confirmed when the user signaled success only after the fix (pointing web-ui at the local backend with the tags data) made the section visible in the running app, and reconfirmed with the admin-ui product selector showing no products because it points at the production worker. Confidence: 0.9
|
||||
- Prefers detailed analysis and explicit error/mistake checking before executing destructive operations, rather than just performing the action — e.g., before a git merge, or before deleting a row directly from the DB (asked "Can I simply delete the row from db. Will it cause any problems" about an unclaimed reserved coupon, expecting the agent to trace all referencing tables/FKs — couponUsages, couponApplicableUsers/Products — before answering). Confidence: 0.7
|
||||
|
|
@ -104,6 +105,7 @@ er-ui/app/(drawer)/(tabs)/home/index.tsx, I want similar here") and expects the
|
|||
- The dedup directive is general, not limited to DB helpers: for types that are "exactly same but repeated" anywhere in the monorepo, move them into a shared package (@packages/shared), organize them there with proper comments, and export/reuse them from that one source — "Do this for all the types which are same and repeated" (stated when asking to address the duplicate-type spread repo-wide). Confidence: 0.9
|
||||
|
||||
- When organizing a shared type package, prefers to keep similar types together — all types that have identical properties should stay grouped/collocated so exact duplicates live side by side (e.g., clustering same-shaped types together in the shared files rather than scattering them). Confidence: 0.75
|
||||
- When he introduces a processing/batching parameter (e.g., a batch size such as "5 tokens per queue message"), expects it enforced end-to-end on BOTH sides of the pipeline — the write/enqueue producer AND the read/consumer/processing path — and follows up to confirm the read side honors the same limit ("we've also changed the code to read and process 5 tokens at a time right?"); a limit applied on only one side is treated as an incomplete change. Confidence: 0.6
|
||||
- Scrollable content (e.g., a product grid) must never be buried beneath a persistent floating UI element like the floating cart bar: pages that scroll above such a bar need sufficient bottom padding on the content container so the last row of items can scroll fully clear of the bar ("There should be enough padding in bottom. I see the last row of products buried beneath the floating cart bar. They should be scrollable"). Errs toward GENEROUS bottom spacing and iterates for more if it still feels tight — after the initial fix (matching siblings' mobile `pb-24`) he asked to bump it again ("it's improved but add some more padding"), landing at mobile `pb-32` / desktop `md:pb-16`. Expects the fix to follow the sibling pages' bottom-padding pattern but lean roomier rather than matching the minimum. Confidence: 0.85
|
||||
- Prefers an incremental "load more"/"Show More" reveal model over rendering the entire product list at once on listing/dashboard pages: show a fixed batch at a time (the user-ui dashboard's All Products list shows 21 items and adds another 21 per click, hiding the button once all are visible) and expects the same model replicated in the sibling web-ui app ("we aren't showing all the items at once. We have a load more model. Implement the same on the @apps/web-ui too"), matching the reference's batch size and button behavior. Confidence: 0.8
|
||||
- For browser/E2E test automation, prefers Playwright and wants the suite placed in a `tests/` folder at the project ROOT (not inside the app it targets) — "At the project root add a folder tests. I want playwright based tests". Confidence: 0.85
|
||||
|
|
@ -115,7 +117,11 @@ er-ui/app/(drawer)/(tabs)/home/index.tsx, I want similar here") and expects the
|
|||
- Uses Bun as his package manager / package runner ("I use bun"), so whenever giving or documenting commands he expects `bun run <script>` / `bunx <tool>` rather than `npm run` / `npx` (including inside subfolders, e.g. `bun run --cwd .. <script>`). Confidence: 0.9
|
||||
- Expects generated test automation to be actually EXECUTED and passing, not just written/typechecking — he asks the agent to run the suite and report how many tests succeed ("try to run the script and see how many tests succeed"), treating a suite that was never run against a live app as unverified. Confidence: 0.65
|
||||
- Treats reports/audits (e.g., DEAD_CODE_REPORT.md) as claims to be independently verified against actual code usage, not trusted at face value: he asks the agent to read a report and confirm "if the pointed code is actually dead", expecting per-claim caller searches and explicit flags of false positives. Confidence: 0.75
|
||||
- Before shipping/publishing a branch, wants a pre-flight risk assessment rather than just execution: he names the last published reference branch and asks "Tell me if I'm going to face any problems" — expecting the agent to verify the current branch is a superset of what was published (no feature/migration/commit lost), that removed files and assets have no dangling references or build-config dependencies, and that build/typecheck integrity holds, then present blockers vs. non-blocking caveats (e.g., committed secrets) before he deploys. Confidence: 0.7
|
||||
- After performing removals himself, expects the agent to re-scan the codebase and independently confirm each item is actually gone (and that the removals didn't break anything) — "I've removed them. Check and tell me if all are gone" — treating his own "done" statement as a claim to verify rather than assuming completion. Confidence: 0.6
|
||||
- When asking to compare branches/versions (e.g., "compare the current branch's @apps/user-ui with the product_to_sku_c1 branch"), wants the answer framed "functionality wise" — a semantic/behavioral summary of what actually changed for the app and its users (new logic, changed API calls, changed UI, removed screens), explicitly distinguishing real functional changes from no-op churn (pure type imports, dead-code deletions, config tweaks which he should be told are non-functional), rather than a raw file/line diff dump. Confidence: 0.6
|
||||
- Wants order-item rows to display the pack size / unit notation (e.g., `2 × 500g · ₹250`) alongside quantity and unit price, not quantity alone — composed via the existing shared `composeUnitNotation` helper and surfaced through the shared item type to both user-ui and web-ui. Confidence: 0.6
|
||||
- Uses "quantity" loosely to refer to the pack size / unit notation on order items: he reported "we aren't showing quantity" about a row that already rendered the numeric count, then clarified "yeah, show the pack size" — so when he says a quantity isn't shown, check whether he actually means the unit/pack-size notation is missing. Confidence: 0.55
|
||||
e changes. Confidence: 0.95
|
||||
er-ui/app/(drawer)/(tabs)/home/index.tsx, I want similar here") and expects the agent to mirror that pattern exactly, including details like item counts and container styling. Confidence: 0.9
|
||||
als) rather than introducing new brand palettes; approval of a redesign's layout/composition does not imply approval of color or theme changes. Confidence: 0.95
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -38,28 +38,35 @@ export const notificationWorker:any = {};
|
|||
// });
|
||||
|
||||
export async function sendAdminNotification(data: {
|
||||
token: string;
|
||||
tokens: string[];
|
||||
title: string;
|
||||
body: string;
|
||||
imageUrl: string | null;
|
||||
}) {
|
||||
const { token, title, body, imageUrl } = data;
|
||||
const { tokens, title, body, imageUrl } = data;
|
||||
const { Expo } = await import('expo-server-sdk')
|
||||
|
||||
// Validate Expo push token
|
||||
if (!Expo.isExpoPushToken(token)) {
|
||||
console.error(`Invalid Expo push token: ${token}`);
|
||||
// Validate Expo push tokens (drop invalid ones)
|
||||
const validTokens = tokens.filter((token) => {
|
||||
if (!Expo.isExpoPushToken(token)) {
|
||||
console.error(`Invalid Expo push token: ${token}`);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
if (validTokens.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Generate signed URL for image if provided
|
||||
const signedImageUrl = imageUrl ? scaffoldAssetUrl(imageUrl) : null;
|
||||
|
||||
|
||||
// Send notification
|
||||
const expo = new Expo();
|
||||
const message = {
|
||||
const messages = validTokens.map((token) => ({
|
||||
to: token,
|
||||
sound: 'default',
|
||||
sound: 'default' as const,
|
||||
title,
|
||||
body,
|
||||
data: { imageUrl },
|
||||
|
|
@ -71,12 +78,12 @@ export async function sendAdminNotification(data: {
|
|||
}
|
||||
]
|
||||
} : {}),
|
||||
};
|
||||
|
||||
}));
|
||||
|
||||
try {
|
||||
const [ticket] = await expo.sendPushNotificationsAsync([message]);
|
||||
await expo.sendPushNotificationsAsync(messages);
|
||||
} catch (error) {
|
||||
console.log(`Failed to send notification:`, error);
|
||||
console.log(`Failed to send notifications:`, error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,9 +10,13 @@ export const handleNotifQueue =async (batch: any) => {
|
|||
continue
|
||||
}
|
||||
|
||||
if (body.name === 'send-admin-notification' && body.jobData?.token) {
|
||||
if (
|
||||
body.name === 'send-admin-notification' &&
|
||||
Array.isArray(body.jobData?.tokens) &&
|
||||
body.jobData.tokens.length > 0
|
||||
) {
|
||||
await sendAdminNotification({
|
||||
token: body.jobData.token,
|
||||
tokens: body.jobData.tokens,
|
||||
title: body.jobData.title,
|
||||
body: body.jobData.body,
|
||||
imageUrl: body.jobData.imageUrl ?? null,
|
||||
|
|
|
|||
|
|
@ -23,6 +23,9 @@ import {
|
|||
} from '@/src/dbService';
|
||||
import { queueDataPusher } from '@/src/lib/queue-data-pusher'
|
||||
|
||||
// Number of push tokens batched into a single queue message.
|
||||
const TOKENS_PER_QUEUE_MESSAGE = 5
|
||||
|
||||
export const userRouter = {
|
||||
getEssentials: protectedProcedure
|
||||
.query(async () => {
|
||||
|
|
@ -205,14 +208,15 @@ export const userRouter = {
|
|||
|
||||
// tokens = ['ExponentPushToken[w4KTsLKnnp8SbURdl5-Q6x]', 'ExponentPushToken[81Io9TG3Qg0s3N0V8L86T-]', 'ExponentPushToken[YJRSQmMUEUbaI2VCZLaoN_]', 'ExponentPushToken[LQZgYkFG_3CweaUbv0fBKJ]']
|
||||
|
||||
// Queue one job per token
|
||||
// Queue one job per batch of tokens
|
||||
let queuedCount = 0;
|
||||
for (const token of tokens) {
|
||||
for (let i = 0; i < tokens.length; i += TOKENS_PER_QUEUE_MESSAGE) {
|
||||
const tokenChunk = tokens.slice(i, i + TOKENS_PER_QUEUE_MESSAGE)
|
||||
try {
|
||||
await queueDataPusher.pushNotifQueue({
|
||||
name: 'send-admin-notification',
|
||||
jobData: {
|
||||
token,
|
||||
tokens: tokenChunk,
|
||||
title,
|
||||
body: text,
|
||||
imageUrl: imageUrl || null,
|
||||
|
|
@ -225,17 +229,9 @@ export const userRouter = {
|
|||
},
|
||||
},
|
||||
})
|
||||
// await queueDataPusher.pushNotifQueue({
|
||||
// jobData: {
|
||||
// token,
|
||||
// title,
|
||||
// body: text,
|
||||
// imageUrl: imageUrl || null,
|
||||
// }
|
||||
// })
|
||||
queuedCount++;
|
||||
queuedCount += tokenChunk.length;
|
||||
} catch (error) {
|
||||
console.error(`Failed to queue notification for token:`, error);
|
||||
console.error(`Failed to queue notification for tokens:`, error);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import {
|
|||
applyDiscountToUserOrder,
|
||||
cancelUserOrderTransaction,
|
||||
checkUserSuspended,
|
||||
composeUnitNotation,
|
||||
db,
|
||||
deleteUserCartItemsForOrder,
|
||||
getOrderProductById,
|
||||
|
|
@ -366,6 +367,7 @@ export const orderRouter = router({
|
|||
productName: item.sku?.product?.name || 'Unknown',
|
||||
skuName: item.sku?.name || null,
|
||||
quantity: parseFloat(item.quantity),
|
||||
unitNotation: composeUnitNotation(item.sku?.features || []),
|
||||
price: parseFloat(item.price.toString()),
|
||||
discountedPrice: parseFloat(
|
||||
item.discountedPrice?.toString() || item.price.toString()
|
||||
|
|
@ -503,6 +505,7 @@ export const orderRouter = router({
|
|||
productName: item.sku?.product?.name || 'Unknown',
|
||||
skuName: item.sku?.name || null,
|
||||
quantity: parseFloat(item.quantity),
|
||||
unitNotation: composeUnitNotation(item.sku?.features || []),
|
||||
price: parseFloat(item.price.toString()),
|
||||
discountedPrice: parseFloat(
|
||||
item.discountedPrice?.toString() || item.price.toString()
|
||||
|
|
|
|||
|
|
@ -310,7 +310,7 @@ export default function OrderDetails() {
|
|||
</View>
|
||||
<View style={tw`flex-1`}>
|
||||
<MyText style={tw`text-slate-900 font-bold text-sm`} numberOfLines={1}>{item.productName}</MyText>
|
||||
<MyText style={tw`text-slate-400 text-xs mt-1`}>{item.quantity} × ₹{item.price}</MyText>
|
||||
<MyText style={tw`text-slate-400 text-xs mt-1`}>{item.quantity}{item.unitNotation ? ` × ${item.unitNotation}` : ''} · ₹{item.price}</MyText>
|
||||
</View>
|
||||
<MyText style={tw`text-slate-900 font-bold text-base ml-2`}>₹{item.amount}</MyText>
|
||||
</View>
|
||||
|
|
|
|||
|
|
@ -316,7 +316,7 @@ function OrderDetailPage() {
|
|||
</div>
|
||||
<div className="flex-1">
|
||||
<p className="line-clamp-1 text-sm font-bold text-slate-900">{item.productName}</p>
|
||||
<p className="mt-1 text-xs text-slate-400">{item.quantity} × ₹{item.price}</p>
|
||||
<p className="mt-1 text-xs text-slate-400">{item.quantity}{item.unitNotation ? ` × ${item.unitNotation}` : ''} · ₹{item.price}</p>
|
||||
</div>
|
||||
<p className="ml-2 text-base font-bold text-slate-900">₹{item.amount}</p>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1585,3 +1585,78 @@ FIX (match user-ui): drop `formatQuantity` helpers + `productQuantity` prefixes;
|
|||
- apps/admin-ui .../products/index.tsx + apps/admin-web .../dashboard.products.tsx: third card button (green "Stock" when out, orange "Out" when live), mutation + refetch + toast.
|
||||
|
||||
[2026-09-06 05:10:00] VERIFIED out-of-stock toggle: packages/db_helper_sqlite index.ts needed explicit export of toggleProductOutOfStock (added). tsc clean: sqlite 0, backend 0, admin-ui 0, admin-web 0; admin-web vite build clean. Note: admin-ui-only toaster + backend sqlite-only DB helper (used by running backend); postgres parity not added.
|
||||
|
||||
[2026-09-14 09:21:37] BATCH push notifications: 5 tokens per queue message (was 1 per token).
|
||||
|
||||
=== apps/backend/src/trpc/apis/admin-apis/apis/user.ts ===
|
||||
- add module constant near the top:
|
||||
const TOKENS_PER_QUEUE_MESSAGE = 5
|
||||
- sendNotification: replace the per-token enqueue loop with chunked enqueue:
|
||||
before:
|
||||
// Queue one job per token
|
||||
let queuedCount = 0
|
||||
for (const token of tokens) {
|
||||
await queueDataPusher.pushNotifQueue({
|
||||
name: 'send-admin-notification',
|
||||
jobData: { token, title, body: text, imageUrl: imageUrl || null },
|
||||
options: { attempts: 3, backoff: { type: 'exponential', delay: 2000 } },
|
||||
})
|
||||
queuedCount++
|
||||
}
|
||||
after:
|
||||
let queuedCount = 0
|
||||
for (let i = 0; i < tokens.length; i += TOKENS_PER_QUEUE_MESSAGE) {
|
||||
const tokenChunk = tokens.slice(i, i + TOKENS_PER_QUEUE_MESSAGE)
|
||||
await queueDataPusher.pushNotifQueue({
|
||||
name: 'send-admin-notification',
|
||||
jobData: { tokens: tokenChunk, title, body: text, imageUrl: imageUrl || null },
|
||||
options: { attempts: 3, backoff: { type: 'exponential', delay: 2000 } },
|
||||
})
|
||||
queuedCount += tokenChunk.length
|
||||
}
|
||||
(jobData.token -> jobData.tokens; message payload otherwise unchanged)
|
||||
|
||||
=== apps/backend/src/lib/queue-consumer.ts (handleNotifQueue) ===
|
||||
- before: if (body.name === 'send-admin-notification' && body.jobData?.token) {
|
||||
await sendAdminNotification({ token: body.jobData.token, title, body, imageUrl: body.jobData.imageUrl ?? null })
|
||||
}
|
||||
- after: if (body.name === 'send-admin-notification' && Array.isArray(body.jobData?.tokens) && body.jobData.tokens.length > 0) {
|
||||
await sendAdminNotification({ tokens: body.jobData.tokens, title: body.jobData.title, body: body.jobData.body, imageUrl: body.jobData.imageUrl ?? null })
|
||||
}
|
||||
|
||||
=== apps/backend/src/lib/notif-job.ts (sendAdminNotification) ===
|
||||
- signature: data.token: string -> data.tokens: string[]
|
||||
- body: filter invalid tokens once, map all valid ones to Expo messages, single
|
||||
expo.sendPushNotificationsAsync(messages) call per batch (was one call per token);
|
||||
drop the unused `const [ticket] =` binding. Signed imageUrl / attachments logic unchanged.
|
||||
|
||||
NOTE: 'send-notification' messages (order packaged/delivered via scheduleNotification) remain
|
||||
unhandled by the consumer — unchanged by this edit.
|
||||
|
||||
[2026-09-14 09:28:38] Show pack size (unitNotation) on order items.
|
||||
|
||||
=== packages/shared/types/user.ts ===
|
||||
- UserOrderItemSummary: add unitNotation: string;
|
||||
|
||||
=== packages/db_helper_sqlite/src/user-apis/order.ts ===
|
||||
- OrderWithRelations.orderItems[].sku: add features: Array<{ featureName: string | null; featureValue: string }>
|
||||
(OrderDetailWithRelations = OrderWithRelations, so one type only)
|
||||
- getOrdersWithRelations (sku.with): + features: { columns: { featureName: true, featureValue: true } }
|
||||
- getOrderByIdWithRelations (sku.with): + features: { columns: { featureName: true, featureValue: true } }
|
||||
|
||||
=== apps/backend/src/trpc/apis/user-apis/apis/order.ts ===
|
||||
- import: + composeUnitNotation from '@/src/dbService'
|
||||
- getOrders item mapping: + unitNotation: composeUnitNotation(item.sku?.features || [])
|
||||
- getOrderById item mapping: + unitNotation: composeUnitNotation(item.sku?.features || [])
|
||||
|
||||
=== apps/user-ui/app/(drawer)/(tabs)/me/my-orders/[id].tsx (order item row) ===
|
||||
- before: <MyText ...>{item.quantity} × ₹{item.price}</MyText>
|
||||
- after: <MyText ...>{item.quantity}{item.unitNotation ? ` × ${item.unitNotation}` : ''} · ₹{item.price}</MyText>
|
||||
|
||||
=== apps/web-ui/src/routes/me.orders.$id.tsx (order item row) ===
|
||||
- before: <p className="mt-1 text-xs text-slate-400">{item.quantity} × ₹{item.price}</p>
|
||||
- after: <p className="mt-1 text-xs text-slate-400">{item.quantity}{item.unitNotation ? ` × ${item.unitNotation}` : ''} · ₹{item.price}</p>
|
||||
|
||||
NOTE: db_helper_postgres order helpers left untouched (dormant package, pre-existing drift).
|
||||
Order list screens (my-orders/index.tsx, web-ui me.orders.tsx) unchanged — they render item rows too
|
||||
but were not in scope for this request.
|
||||
|
|
|
|||
|
|
@ -49,6 +49,10 @@ export interface OrderWithRelations {
|
|||
id: number
|
||||
name: string | null
|
||||
images: unknown
|
||||
features: Array<{
|
||||
featureName: string | null
|
||||
featureValue: string
|
||||
}>
|
||||
product: {
|
||||
name: string
|
||||
} | null
|
||||
|
|
@ -317,6 +321,12 @@ export async function getOrdersWithRelations(
|
|||
name: true,
|
||||
},
|
||||
},
|
||||
features: {
|
||||
columns: {
|
||||
featureName: true,
|
||||
featureValue: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
columns: {
|
||||
id: true,
|
||||
|
|
@ -400,6 +410,12 @@ export async function getOrderByIdWithRelations(
|
|||
name: true,
|
||||
},
|
||||
},
|
||||
features: {
|
||||
columns: {
|
||||
featureName: true,
|
||||
featureValue: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
columns: {
|
||||
id: true,
|
||||
|
|
|
|||
|
|
@ -500,6 +500,7 @@ export type UserSavePushTokenResponse = BasicSuccessResponse
|
|||
export interface UserOrderItemSummary {
|
||||
productName: string;
|
||||
quantity: number;
|
||||
unitNotation: string;
|
||||
price: number;
|
||||
discountedPrice: number;
|
||||
amount: number;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue