@tallyui/components 3.5.3 → 3.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +5 -1
- package/dist/index.js +11 -3
- package/package.json +9 -9
- package/src/sale/orders-list.tsx +1 -1
- package/src/sale/receipt.tsx +10 -4
package/dist/index.d.ts
CHANGED
|
@@ -1411,7 +1411,7 @@ declare function Catalogue<Doc>({ products, traits, currency, onSelect, statusTe
|
|
|
1411
1411
|
|
|
1412
1412
|
/** `store`/`taxLabel`/`topInset`/`formatDate` replace the app's Medusa settings, hard-coded VAT (default matches
|
|
1413
1413
|
* TV6a's `Cart`), outbox strip and date util, so `Receipt` stays platform-neutral (ADR-052). */
|
|
1414
|
-
declare function Receipt({ order, posOrder, store, cashier, registerId, newSale, taxLabel, topInset, formatDate }: {
|
|
1414
|
+
declare function Receipt({ order, posOrder, store, cashier, registerId, registerName, newSale, taxLabel, topInset, formatDate, footerSlot }: {
|
|
1415
1415
|
order: SentOrder;
|
|
1416
1416
|
store: {
|
|
1417
1417
|
name: string;
|
|
@@ -1420,12 +1420,16 @@ declare function Receipt({ order, posOrder, store, cashier, registerId, newSale,
|
|
|
1420
1420
|
cashier: string;
|
|
1421
1421
|
registerId: string;
|
|
1422
1422
|
newSale: () => void;
|
|
1423
|
+
/** The register's name, printed as `Register: <name>`; the id is never printed. */
|
|
1424
|
+
registerName?: string;
|
|
1423
1425
|
/** The finalized order (useSale's receipt stage has it). With it the receipt prints its reference and time, the
|
|
1424
1426
|
* same as Orders; without it (a preview before finalize) the sale id is marked as a draft. */
|
|
1425
1427
|
posOrder?: PosOrder;
|
|
1426
1428
|
taxLabel?: (ratePpm: number) => string;
|
|
1427
1429
|
topInset?: number;
|
|
1428
1430
|
formatDate?: (iso: string) => string;
|
|
1431
|
+
/** Prints after the Change row and above the on-screen buttons (e.g. an app's register/software block). */
|
|
1432
|
+
footerSlot?: ReactNode;
|
|
1429
1433
|
}): react_jsx_runtime.JSX.Element;
|
|
1430
1434
|
|
|
1431
1435
|
/** The order reference a visitor sees on the receipt and in Orders (front desk ruling, 2026-10-06): the finalized
|
package/dist/index.js
CHANGED
|
@@ -5021,17 +5021,20 @@ function Receipt({
|
|
|
5021
5021
|
store,
|
|
5022
5022
|
cashier,
|
|
5023
5023
|
registerId,
|
|
5024
|
+
registerName,
|
|
5024
5025
|
newSale,
|
|
5025
5026
|
taxLabel = (ratePpm) => `Tax ${ratePpm / 1e4}%`,
|
|
5026
5027
|
topInset = 0,
|
|
5027
|
-
formatDate = defaultFormatDate
|
|
5028
|
+
formatDate = defaultFormatDate,
|
|
5029
|
+
footerSlot
|
|
5028
5030
|
}) {
|
|
5029
5031
|
useEffect6(injectPrintStyle, []);
|
|
5030
5032
|
const receipt = buildReceiptData3(order, {
|
|
5031
5033
|
storeName: store.name,
|
|
5032
5034
|
storeAddress: store.address,
|
|
5033
5035
|
cashier,
|
|
5034
|
-
register: registerId
|
|
5036
|
+
register: registerId,
|
|
5037
|
+
registerName
|
|
5035
5038
|
});
|
|
5036
5039
|
const money = (amount) => formatMoney16({ amount, currency: receipt.currency }) ?? "";
|
|
5037
5040
|
const row = (label, amount, bold = false, key) => /* @__PURE__ */ jsxs56(View63, { accessibilityLabel: `${label}: ${amount}`, className: "flex-row justify-between gap-4", children: [
|
|
@@ -5052,6 +5055,10 @@ function Receipt({
|
|
|
5052
5055
|
"Cashier: ",
|
|
5053
5056
|
receipt.header.cashier
|
|
5054
5057
|
] }),
|
|
5058
|
+
receipt.register.name ? /* @__PURE__ */ jsxs56(Text41, { testID: "receipt-register", className: "text-muted-foreground", children: [
|
|
5059
|
+
"Register: ",
|
|
5060
|
+
receipt.register.name
|
|
5061
|
+
] }) : null,
|
|
5055
5062
|
receipt.header.customer && /* @__PURE__ */ jsxs56(Text41, { className: "text-muted-foreground", children: [
|
|
5056
5063
|
"Customer: ",
|
|
5057
5064
|
receipt.header.customer
|
|
@@ -5078,6 +5085,7 @@ function Receipt({
|
|
|
5078
5085
|
index
|
|
5079
5086
|
)),
|
|
5080
5087
|
row("Change", money(receipt.changeDueMinor)),
|
|
5088
|
+
footerSlot ? /* @__PURE__ */ jsx98(View63, { testID: "receipt-footer", className: "mt-3 items-center border-t border-dashed border-border pt-3", children: footerSlot }) : null,
|
|
5081
5089
|
/* @__PURE__ */ jsxs56(View63, { dataSet: { print: "hide" }, className: "flex-row gap-4", children: [
|
|
5082
5090
|
/* @__PURE__ */ jsx98(Pressable33, { accessibilityRole: "button", onPress: () => {
|
|
5083
5091
|
if (typeof window !== "undefined" && typeof window.print === "function") window.print();
|
|
@@ -5277,7 +5285,7 @@ function OrdersList({ orders, onRetry, formatDate = defaultFormatDate2, footer,
|
|
|
5277
5285
|
setRetryingIds(new Set(retrying.current));
|
|
5278
5286
|
}
|
|
5279
5287
|
}, className: "rounded-md bg-primary px-4 py-2", children: /* @__PURE__ */ jsx100(Text43, { className: "text-center font-semibold text-primary-foreground", children: "Retry" }) }) : null,
|
|
5280
|
-
knownWarnings(order.warnings).map((warning, index) => /* @__PURE__ */ jsx100(View65, { className: "border-l-4 border-warning pl-2", children: /* @__PURE__ */ jsx100(Text43, { className: "text-foreground", children: warning.code === "insufficient_stock" ? `${warning.quantity} sold without stock: ${order.lines.find((line) => line.variantId === warning.variantId)?.name}` : warning.code === "tax_rate_mismatch" ? `Tax at ${(warning.ratePpm / 1e4).toLocaleString(void 0, { maximumFractionDigits: 4 })}%: store ${formatMoney17({ amount: warning.serverMinor, currency: order.currency })} vs POS ${formatMoney17({ amount: warning.expectedMinor, currency: order.currency })}` : warning.code === "customer_ignored" ? `The online store didn't recognise the customer on this sale, so it was saved as a guest sale. Customer id: ${warning.customerId}.` : warning.code === "figures_mismatch" ? `The online store worked out different figures for this sale. ${warning.fields.map(({ field, tillMinor, serverMinor }) => `${FIGURE_LABELS.get(field) ?? field}: till ${formatMoney17({ amount: tillMinor, currency: order.currency })}, store ${formatMoney17({ amount: serverMinor, currency: order.currency })}.`).join(" ")}` : warning.bridgeMinor !== void 0 ? `Store calculated ${formatMoney17({ amount: warning.serverMinor, currency: order.currency })}; a rounding line of ${warning.bridgeMinor > 0 ? "+" : ""}${formatMoney17({ amount: warning.bridgeMinor, currency: order.currency })} brought it to ${formatMoney17({ amount: warning.expectedMinor, currency: order.currency })}` : `Store total ${formatMoney17({ amount: warning.serverMinor, currency: order.currency })} vs POS ${formatMoney17({ amount: warning.expectedMinor, currency: order.currency })}` }) }, index))
|
|
5288
|
+
knownWarnings(order.warnings).filter((warning) => warning.code !== "register_session_unknown").map((warning, index) => /* @__PURE__ */ jsx100(View65, { className: "border-l-4 border-warning pl-2", children: /* @__PURE__ */ jsx100(Text43, { className: "text-foreground", children: warning.code === "insufficient_stock" ? `${warning.quantity} sold without stock: ${order.lines.find((line) => line.variantId === warning.variantId)?.name}` : warning.code === "tax_rate_mismatch" ? `Tax at ${(warning.ratePpm / 1e4).toLocaleString(void 0, { maximumFractionDigits: 4 })}%: store ${formatMoney17({ amount: warning.serverMinor, currency: order.currency })} vs POS ${formatMoney17({ amount: warning.expectedMinor, currency: order.currency })}` : warning.code === "customer_ignored" ? `The online store didn't recognise the customer on this sale, so it was saved as a guest sale. Customer id: ${warning.customerId}.` : warning.code === "figures_mismatch" ? `The online store worked out different figures for this sale. ${warning.fields.map(({ field, tillMinor, serverMinor }) => `${FIGURE_LABELS.get(field) ?? field}: till ${formatMoney17({ amount: tillMinor, currency: order.currency })}, store ${formatMoney17({ amount: serverMinor, currency: order.currency })}.`).join(" ")}` : warning.bridgeMinor !== void 0 ? `Store calculated ${formatMoney17({ amount: warning.serverMinor, currency: order.currency })}; a rounding line of ${warning.bridgeMinor > 0 ? "+" : ""}${formatMoney17({ amount: warning.bridgeMinor, currency: order.currency })} brought it to ${formatMoney17({ amount: warning.expectedMinor, currency: order.currency })}` : `Store total ${formatMoney17({ amount: warning.serverMinor, currency: order.currency })} vs POS ${formatMoney17({ amount: warning.expectedMinor, currency: order.currency })}` }) }, index))
|
|
5281
5289
|
] }, order.id);
|
|
5282
5290
|
})
|
|
5283
5291
|
] }, section.title)),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tallyui/components",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.6.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Universal POS UI components for Tally UI",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -27,22 +27,22 @@
|
|
|
27
27
|
"directory": "packages/components"
|
|
28
28
|
},
|
|
29
29
|
"peerDependencies": {
|
|
30
|
-
"@tallyui/core": "^3.
|
|
31
|
-
"@tallyui/primitives": "^3.
|
|
32
|
-
"@tallyui/theme": "^3.
|
|
30
|
+
"@tallyui/core": "^3.6.0",
|
|
31
|
+
"@tallyui/primitives": "^3.6.0",
|
|
32
|
+
"@tallyui/theme": "^3.6.0",
|
|
33
33
|
"react": ">=18",
|
|
34
34
|
"react-native": ">=0.74",
|
|
35
35
|
"react-native-svg": ">=15"
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
38
|
"class-variance-authority": "^0.7.1",
|
|
39
|
-
"@tallyui/pos": "3.
|
|
39
|
+
"@tallyui/pos": "3.6.0"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
|
-
"@tallyui/connector-medusa": "3.
|
|
43
|
-
"@tallyui/connector-vendure": "3.
|
|
44
|
-
"@tallyui/connector-woocommerce": "3.
|
|
45
|
-
"@tallyui/mock-api": "3.
|
|
42
|
+
"@tallyui/connector-medusa": "3.6.0",
|
|
43
|
+
"@tallyui/connector-vendure": "3.6.0",
|
|
44
|
+
"@tallyui/connector-woocommerce": "3.6.0",
|
|
45
|
+
"@tallyui/mock-api": "3.6.0",
|
|
46
46
|
"@types/react": ">=18",
|
|
47
47
|
"react": "^19.2.4",
|
|
48
48
|
"react-native-svg": "15.12.1",
|
package/src/sale/orders-list.tsx
CHANGED
|
@@ -105,7 +105,7 @@ export function OrdersList({ orders, onRetry, formatDate = defaultFormatDate, fo
|
|
|
105
105
|
}} className="rounded-md bg-primary px-4 py-2">
|
|
106
106
|
<Text className="text-center font-semibold text-primary-foreground">Retry</Text>
|
|
107
107
|
</Pressable> : null}
|
|
108
|
-
{knownWarnings(order.warnings).map((warning, index) => <View key={index} className="border-l-4 border-warning pl-2"><Text className="text-foreground">
|
|
108
|
+
{knownWarnings(order.warnings).filter((warning) => warning.code !== 'register_session_unknown').map((warning, index) => <View key={index} className="border-l-4 border-warning pl-2"><Text className="text-foreground">
|
|
109
109
|
{warning.code === 'insufficient_stock'
|
|
110
110
|
? `${warning.quantity} sold without stock: ${order.lines.find((line) => line.variantId === warning.variantId)?.name}`
|
|
111
111
|
: warning.code === 'tax_rate_mismatch'
|
package/src/sale/receipt.tsx
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useEffect } from 'react';
|
|
1
|
+
import { useEffect, type ReactNode } from 'react';
|
|
2
2
|
import { Pressable, Text, View } from 'react-native';
|
|
3
3
|
import { formatMoney } from '@tallyui/core';
|
|
4
4
|
import { buildReceiptData, type SentOrder } from '@tallyui/pos';
|
|
@@ -11,17 +11,21 @@ const defaultFormatDate = (iso: string) => new Intl.DateTimeFormat(undefined, {
|
|
|
11
11
|
|
|
12
12
|
/** `store`/`taxLabel`/`topInset`/`formatDate` replace the app's Medusa settings, hard-coded VAT (default matches
|
|
13
13
|
* TV6a's `Cart`), outbox strip and date util, so `Receipt` stays platform-neutral (ADR-052). */
|
|
14
|
-
export function Receipt({ order, posOrder, store, cashier, registerId, newSale, taxLabel = (ratePpm: number) => `Tax ${ratePpm / 10000}%`,
|
|
15
|
-
topInset = 0, formatDate = defaultFormatDate }: {
|
|
14
|
+
export function Receipt({ order, posOrder, store, cashier, registerId, registerName, newSale, taxLabel = (ratePpm: number) => `Tax ${ratePpm / 10000}%`,
|
|
15
|
+
topInset = 0, formatDate = defaultFormatDate, footerSlot }: {
|
|
16
16
|
order: SentOrder; store: { name: string; address?: string }; cashier: string; registerId: string; newSale: () => void;
|
|
17
|
+
/** The register's name, printed as `Register: <name>`; the id is never printed. */
|
|
18
|
+
registerName?: string;
|
|
17
19
|
/** The finalized order (useSale's receipt stage has it). With it the receipt prints its reference and time, the
|
|
18
20
|
* same as Orders; without it (a preview before finalize) the sale id is marked as a draft. */
|
|
19
21
|
posOrder?: PosOrder;
|
|
20
22
|
taxLabel?: (ratePpm: number) => string; topInset?: number; formatDate?: (iso: string) => string;
|
|
23
|
+
/** Prints after the Change row and above the on-screen buttons (e.g. an app's register/software block). */
|
|
24
|
+
footerSlot?: ReactNode;
|
|
21
25
|
}) {
|
|
22
26
|
useEffect(injectPrintStyle, []);
|
|
23
27
|
const receipt = buildReceiptData(order, {
|
|
24
|
-
storeName: store.name, storeAddress: store.address, cashier, register: registerId,
|
|
28
|
+
storeName: store.name, storeAddress: store.address, cashier, register: registerId, registerName,
|
|
25
29
|
});
|
|
26
30
|
const money = (amount: number) => formatMoney({ amount, currency: receipt.currency }) ?? '';
|
|
27
31
|
const row = (label: string, amount: string, bold = false, key?: number) => <View key={key} accessibilityLabel={`${label}: ${amount}`} className="flex-row justify-between gap-4">
|
|
@@ -40,6 +44,7 @@ export function Receipt({ order, posOrder, store, cashier, registerId, newSale,
|
|
|
40
44
|
<Text testID="receipt-order" className="text-foreground">{posOrder ? `Order ${orderReference(posOrder)}` : `Order ${receipt.header.orderNumber.slice(-8)} (draft)`}</Text>
|
|
41
45
|
<Text className="text-muted-foreground">{formatDate(posOrder?.createdAt ?? receipt.header.date)}</Text>
|
|
42
46
|
<Text className="text-muted-foreground">Cashier: {receipt.header.cashier}</Text>
|
|
47
|
+
{receipt.register.name ? <Text testID="receipt-register" className="text-muted-foreground">Register: {receipt.register.name}</Text> : null}
|
|
43
48
|
{receipt.header.customer && <Text className="text-muted-foreground">Customer: {receipt.header.customer}</Text>}
|
|
44
49
|
{receipt.lineItems.map((line, index) => <View key={index}>
|
|
45
50
|
<Text className="text-foreground">{line.name}</Text>
|
|
@@ -61,6 +66,7 @@ export function Receipt({ order, posOrder, store, cashier, registerId, newSale,
|
|
|
61
66
|
{receipt.payments.map((payment, index) => row(payment.method === 'cash' ? 'Cash tendered' : 'Card terminal',
|
|
62
67
|
money(payment.amountMinor) + (payment.reference ? ` · ${payment.reference}` : ''), false, index))}
|
|
63
68
|
{row('Change', money(receipt.changeDueMinor))}
|
|
69
|
+
{footerSlot ? <View testID="receipt-footer" className="mt-3 items-center border-t border-dashed border-border pt-3">{footerSlot}</View> : null}
|
|
64
70
|
<View dataSet={{ print: 'hide' }} className="flex-row gap-4">
|
|
65
71
|
<Pressable accessibilityRole="button" onPress={() => { if (typeof window !== 'undefined' && typeof window.print === 'function') window.print(); }} className="rounded-md border border-border bg-card px-4 py-3">
|
|
66
72
|
<Text className="text-center text-foreground">Print receipt</Text>
|