@tallyui/components 2.0.0 → 3.0.0-next.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 +50 -20
- package/dist/index.js +914 -638
- package/package.json +10 -10
- package/src/customer/customer-card.tsx +10 -5
- package/src/customer/customer-form.tsx +3 -1
- package/src/customer/customer-picker.tsx +124 -0
- package/src/customer/customer-select.tsx +24 -14
- package/src/customer/index.ts +1 -0
- package/src/index.ts +2 -0
- package/src/product/product-grid.tsx +23 -9
- package/src/register/closure-sheet.tsx +7 -1
- package/src/sale/catalogue.tsx +13 -5
- package/src/sale/orders-list.tsx +52 -10
- package/src/sale/receipt.tsx +3 -2
- package/src/sale/sync-status.tsx +133 -12
- package/src/sale/tender.tsx +4 -1
package/dist/index.js
CHANGED
|
@@ -1694,9 +1694,9 @@ import { cn as cn39 } from "@tallyui/theme";
|
|
|
1694
1694
|
import { jsx as jsx41 } from "react/jsx-runtime";
|
|
1695
1695
|
function ProductSku({ doc, fallback = "\u2014", className, ...textProps }) {
|
|
1696
1696
|
const { getSku, getVariantCount } = useProductTraits4();
|
|
1697
|
-
const
|
|
1697
|
+
const count2 = getVariantCount(doc);
|
|
1698
1698
|
const sku = getSku(doc);
|
|
1699
|
-
return /* @__PURE__ */ jsx41(Text, { className: cn39("text-xs text-muted-foreground", className), ...textProps, children:
|
|
1699
|
+
return /* @__PURE__ */ jsx41(Text, { className: cn39("text-xs text-muted-foreground", className), ...textProps, children: count2 > 1 ? `${count2} variants` : sku ?? fallback });
|
|
1700
1700
|
}
|
|
1701
1701
|
|
|
1702
1702
|
// src/product/product-stock-badge.tsx
|
|
@@ -1794,10 +1794,13 @@ function ProductCard({ doc, onPress, imageSize = 80, currencySymbol: currencySym
|
|
|
1794
1794
|
}
|
|
1795
1795
|
|
|
1796
1796
|
// src/product/product-grid.tsx
|
|
1797
|
-
import {
|
|
1797
|
+
import { FlatList, View as View19 } from "react-native";
|
|
1798
1798
|
import { cn as cn42 } from "@tallyui/theme";
|
|
1799
1799
|
import { useProductTraits as useProductTraits6 } from "@tallyui/core";
|
|
1800
1800
|
import { jsx as jsx44, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
1801
|
+
var INITIAL_ROWS = 8;
|
|
1802
|
+
var BATCH_ROWS = 8;
|
|
1803
|
+
var WINDOW_SIZE = 5;
|
|
1801
1804
|
function ProductGrid({
|
|
1802
1805
|
items,
|
|
1803
1806
|
renderItem,
|
|
@@ -1820,12 +1823,25 @@ function ProductGrid({
|
|
|
1820
1823
|
return /* @__PURE__ */ jsxs8(VStack, { space: "none", className: cn42("flex-1", className), ...viewProps, children: [
|
|
1821
1824
|
searchSlot && /* @__PURE__ */ jsx44(View19, { className: "px-3 py-2", children: searchSlot }),
|
|
1822
1825
|
filterSlot && /* @__PURE__ */ jsx44(View19, { className: "px-3 pb-2", children: filterSlot }),
|
|
1823
|
-
hasItems ? /* @__PURE__ */ jsx44(
|
|
1826
|
+
hasItems ? /* @__PURE__ */ jsx44(
|
|
1827
|
+
FlatList,
|
|
1828
|
+
{
|
|
1829
|
+
data: visibleItems,
|
|
1830
|
+
numColumns,
|
|
1831
|
+
keyExtractor: (item, index) => String(item.id ?? index),
|
|
1832
|
+
contentContainerClassName: "p-1",
|
|
1833
|
+
initialNumToRender: INITIAL_ROWS,
|
|
1834
|
+
maxToRenderPerBatch: BATCH_ROWS,
|
|
1835
|
+
windowSize: WINDOW_SIZE,
|
|
1836
|
+
renderItem: ({ item, index }) => /* @__PURE__ */ jsx44(View19, { style: { width: `${100 / numColumns}%` }, className: "p-1", children: renderItem(item, index) })
|
|
1837
|
+
},
|
|
1838
|
+
numColumns
|
|
1839
|
+
) : emptyState ?? null
|
|
1824
1840
|
] });
|
|
1825
1841
|
}
|
|
1826
1842
|
|
|
1827
1843
|
// src/product/product-list.tsx
|
|
1828
|
-
import { ScrollView as
|
|
1844
|
+
import { ScrollView as ScrollView2, View as View20 } from "react-native";
|
|
1829
1845
|
import { cn as cn43 } from "@tallyui/theme";
|
|
1830
1846
|
import { jsx as jsx45, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
1831
1847
|
function ProductList({
|
|
@@ -1841,12 +1857,12 @@ function ProductList({
|
|
|
1841
1857
|
return /* @__PURE__ */ jsxs9(View20, { className: cn43("flex-1", className), ...viewProps, children: [
|
|
1842
1858
|
searchSlot && /* @__PURE__ */ jsx45(View20, { className: "px-3 py-2", children: searchSlot }),
|
|
1843
1859
|
filterSlot && /* @__PURE__ */ jsx45(View20, { className: "px-3 pb-2", children: filterSlot }),
|
|
1844
|
-
hasItems ? /* @__PURE__ */ jsx45(
|
|
1860
|
+
hasItems ? /* @__PURE__ */ jsx45(ScrollView2, { className: "flex-1", children: items.map((item, index) => /* @__PURE__ */ jsx45(View20, { className: "border-b border-border", children: renderItem(item, index) }, item.id ?? index)) }) : emptyState ?? null
|
|
1845
1861
|
] });
|
|
1846
1862
|
}
|
|
1847
1863
|
|
|
1848
1864
|
// src/product/category-nav.tsx
|
|
1849
|
-
import { Pressable as Pressable8, ScrollView as
|
|
1865
|
+
import { Pressable as Pressable8, ScrollView as ScrollView3, Text as Text11, View as View21 } from "react-native";
|
|
1850
1866
|
import { cn as cn44 } from "@tallyui/theme";
|
|
1851
1867
|
import { jsx as jsx46 } from "react/jsx-runtime";
|
|
1852
1868
|
function CategoryNav({
|
|
@@ -1884,7 +1900,7 @@ function CategoryNav({
|
|
|
1884
1900
|
});
|
|
1885
1901
|
if (isHorizontal) {
|
|
1886
1902
|
return /* @__PURE__ */ jsx46(
|
|
1887
|
-
|
|
1903
|
+
ScrollView3,
|
|
1888
1904
|
{
|
|
1889
1905
|
horizontal: true,
|
|
1890
1906
|
showsHorizontalScrollIndicator: false,
|
|
@@ -1993,7 +2009,7 @@ function CartTotal({
|
|
|
1993
2009
|
}
|
|
1994
2010
|
|
|
1995
2011
|
// src/cart/cart-panel.tsx
|
|
1996
|
-
import { ScrollView as
|
|
2012
|
+
import { ScrollView as ScrollView4, View as View23 } from "react-native";
|
|
1997
2013
|
import { cn as cn48 } from "@tallyui/theme";
|
|
1998
2014
|
import { jsx as jsx50, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
1999
2015
|
function defaultKey(item, index) {
|
|
@@ -2014,7 +2030,7 @@ function CartPanel({
|
|
|
2014
2030
|
const hasItems = items.length > 0;
|
|
2015
2031
|
return /* @__PURE__ */ jsxs13(VStack, { space: "none", className: cn48("flex-1 min-h-0", className), ...props, children: [
|
|
2016
2032
|
header && /* @__PURE__ */ jsx50(View23, { className: "border-b border-border px-3 py-2", children: header }),
|
|
2017
|
-
/* @__PURE__ */ jsxs13(
|
|
2033
|
+
/* @__PURE__ */ jsxs13(ScrollView4, { className: "flex-1 min-h-0", contentContainerClassName: "flex-grow", children: [
|
|
2018
2034
|
hasItems ? items.map((item, index) => /* @__PURE__ */ jsx50(View23, { children: renderItem(item, index) }, keyExtractor ? keyExtractor(item, index) : defaultKey(item, index))) : emptyState ?? null,
|
|
2019
2035
|
afterItems
|
|
2020
2036
|
] }),
|
|
@@ -2138,7 +2154,7 @@ function SearchInput({ value, onChangeText, className, placeholder = "Search..."
|
|
|
2138
2154
|
|
|
2139
2155
|
// src/input/filter-chip.tsx
|
|
2140
2156
|
import { useMemo } from "react";
|
|
2141
|
-
import { Pressable as Pressable12, ScrollView as
|
|
2157
|
+
import { Pressable as Pressable12, ScrollView as ScrollView5 } from "react-native";
|
|
2142
2158
|
import { ToggleGroup as ToggleGroup3 } from "@tallyui/primitives";
|
|
2143
2159
|
import { cn as cn53 } from "@tallyui/theme";
|
|
2144
2160
|
import { jsx as jsx55 } from "react/jsx-runtime";
|
|
@@ -2191,7 +2207,7 @@ function FilterChipGroup({ chips, onChipPress, className, ...viewProps }) {
|
|
|
2191
2207
|
onValueChange: handleValueChange,
|
|
2192
2208
|
asChild: true,
|
|
2193
2209
|
children: /* @__PURE__ */ jsx55(
|
|
2194
|
-
|
|
2210
|
+
ScrollView5,
|
|
2195
2211
|
{
|
|
2196
2212
|
horizontal: true,
|
|
2197
2213
|
showsHorizontalScrollIndicator: false,
|
|
@@ -2267,9 +2283,12 @@ function QuantityStepper({
|
|
|
2267
2283
|
import { useCustomerTraits } from "@tallyui/core";
|
|
2268
2284
|
import { cn as cn55 } from "@tallyui/theme";
|
|
2269
2285
|
import { jsx as jsx57, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
2270
|
-
function
|
|
2286
|
+
function CustomerCardFromContext(props) {
|
|
2271
2287
|
const traits = useCustomerTraits();
|
|
2272
|
-
|
|
2288
|
+
return traits ? /* @__PURE__ */ jsx57(CustomerCard, { ...props, traits }) : null;
|
|
2289
|
+
}
|
|
2290
|
+
function CustomerCard({ doc, traits, className, ...props }) {
|
|
2291
|
+
if (!traits) return /* @__PURE__ */ jsx57(CustomerCardFromContext, { doc, className, ...props });
|
|
2273
2292
|
const name = traits.getName(doc);
|
|
2274
2293
|
const email = traits.getEmail(doc);
|
|
2275
2294
|
const address = traits.getAddressSummary(doc);
|
|
@@ -2281,21 +2300,27 @@ function CustomerCard({ doc, className, ...props }) {
|
|
|
2281
2300
|
}
|
|
2282
2301
|
|
|
2283
2302
|
// src/customer/customer-select.tsx
|
|
2284
|
-
import { ScrollView as
|
|
2303
|
+
import { Pressable as Pressable14, ScrollView as ScrollView6, View as View29 } from "react-native";
|
|
2285
2304
|
import { Select as Select2 } from "@tallyui/primitives";
|
|
2286
2305
|
import { useCustomerTraits as useCustomerTraits2 } from "@tallyui/core";
|
|
2287
2306
|
import { cn as cn56 } from "@tallyui/theme";
|
|
2288
2307
|
import { jsx as jsx58, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
2289
|
-
function CustomerSelect({
|
|
2308
|
+
function CustomerSelect(props) {
|
|
2309
|
+
return props.traits ? /* @__PURE__ */ jsx58(CustomerSelectView, { ...props }) : /* @__PURE__ */ jsx58(CustomerSelectFromContext, { ...props });
|
|
2310
|
+
}
|
|
2311
|
+
function CustomerSelectFromContext(props) {
|
|
2312
|
+
return /* @__PURE__ */ jsx58(CustomerSelectView, { ...props, traits: useCustomerTraits2() });
|
|
2313
|
+
}
|
|
2314
|
+
function CustomerSelectView({
|
|
2290
2315
|
customers,
|
|
2291
2316
|
selected,
|
|
2292
2317
|
onSelect,
|
|
2293
2318
|
onSearch,
|
|
2294
2319
|
placeholder = "Search customers...",
|
|
2295
2320
|
className,
|
|
2321
|
+
traits,
|
|
2296
2322
|
...props
|
|
2297
2323
|
}) {
|
|
2298
|
-
const traits = useCustomerTraits2();
|
|
2299
2324
|
const selectedOption = selected && traits ? { value: traits.getId(selected), label: traits.getName(selected) } : void 0;
|
|
2300
2325
|
const customerById = /* @__PURE__ */ new Map();
|
|
2301
2326
|
if (traits) {
|
|
@@ -2314,17 +2339,18 @@ function CustomerSelect({
|
|
|
2314
2339
|
onValueChange: handleValueChange,
|
|
2315
2340
|
defaultOpen: true,
|
|
2316
2341
|
children: /* @__PURE__ */ jsxs18(VStack, { space: "sm", className: cn56(className), ...props, children: [
|
|
2317
|
-
selected && traits && /* @__PURE__ */ jsx58(Select2.Trigger, { asChild: true, children: /* @__PURE__ */ jsx58(View29, { className: "rounded-lg border border-primary bg-primary/5 px-3 py-2", children: /* @__PURE__ */ jsx58(CustomerCard, { doc: selected }) }) }),
|
|
2318
|
-
customers.length > 0 && /* @__PURE__ */ jsx58(Select2.Content, { asChild: true, forceMount: true, disablePositioningStyle: true, children: /* @__PURE__ */ jsx58(
|
|
2342
|
+
selected && traits && /* @__PURE__ */ jsx58(Select2.Trigger, { asChild: true, children: /* @__PURE__ */ jsx58(View29, { className: "rounded-lg border border-primary bg-primary/5 px-3 py-2", children: /* @__PURE__ */ jsx58(CustomerCard, { doc: selected, traits }) }) }),
|
|
2343
|
+
customers.length > 0 && /* @__PURE__ */ jsx58(Select2.Content, { asChild: true, forceMount: true, disablePositioningStyle: true, children: /* @__PURE__ */ jsx58(ScrollView6, { className: "max-h-60", children: customers.map((customer, index) => {
|
|
2319
2344
|
const id = traits?.getId(customer) ?? String(index);
|
|
2320
2345
|
const label = traits?.getName(customer) ?? "";
|
|
2346
|
+
const email = traits?.getEmail(customer);
|
|
2321
2347
|
return /* @__PURE__ */ jsx58(
|
|
2322
2348
|
Select2.Item,
|
|
2323
2349
|
{
|
|
2324
2350
|
value: id,
|
|
2325
2351
|
label,
|
|
2326
2352
|
asChild: true,
|
|
2327
|
-
children: /* @__PURE__ */ jsx58(
|
|
2353
|
+
children: /* @__PURE__ */ jsx58(Pressable14, { accessibilityLabel: email ? `${label}, ${email}` : label, className: "border-b border-border px-3 py-2", children: /* @__PURE__ */ jsx58(CustomerCard, { doc: customer, traits }) })
|
|
2328
2354
|
},
|
|
2329
2355
|
id
|
|
2330
2356
|
);
|
|
@@ -2335,7 +2361,7 @@ function CustomerSelect({
|
|
|
2335
2361
|
}
|
|
2336
2362
|
|
|
2337
2363
|
// src/customer/customer-form.tsx
|
|
2338
|
-
import { Pressable as
|
|
2364
|
+
import { Pressable as Pressable15, Text as Text17, TextInput as TextInput6, View as View30 } from "react-native";
|
|
2339
2365
|
import { cn as cn57 } from "@tallyui/theme";
|
|
2340
2366
|
import { jsx as jsx59, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
2341
2367
|
function FormField({
|
|
@@ -2363,6 +2389,7 @@ function CustomerForm({
|
|
|
2363
2389
|
onChangeField,
|
|
2364
2390
|
onSubmit,
|
|
2365
2391
|
submitLabel = "Save Customer",
|
|
2392
|
+
showAddress = true,
|
|
2366
2393
|
className,
|
|
2367
2394
|
...viewProps
|
|
2368
2395
|
}) {
|
|
@@ -2373,13 +2400,13 @@ function CustomerForm({
|
|
|
2373
2400
|
] }),
|
|
2374
2401
|
/* @__PURE__ */ jsx59(FormField, { label: "Email", value: values.email, onChangeText: (v) => onChangeField("email", v), placeholder: "email@example.com", keyboardType: "email-address" }),
|
|
2375
2402
|
/* @__PURE__ */ jsx59(FormField, { label: "Phone", value: values.phone, onChangeText: (v) => onChangeField("phone", v), placeholder: "Phone number", keyboardType: "phone-pad" }),
|
|
2376
|
-
/* @__PURE__ */ jsx59(FormField, { label: "Address", value: values.address, onChangeText: (v) => onChangeField("address", v), placeholder: "Street address", multiline: true }),
|
|
2377
|
-
onSubmit && /* @__PURE__ */ jsx59(
|
|
2403
|
+
showAddress && /* @__PURE__ */ jsx59(FormField, { label: "Address", value: values.address, onChangeText: (v) => onChangeField("address", v), placeholder: "Street address", multiline: true }),
|
|
2404
|
+
onSubmit && /* @__PURE__ */ jsx59(Pressable15, { onPress: onSubmit, className: "items-center rounded-lg bg-primary px-4 py-3", children: /* @__PURE__ */ jsx59(Text17, { className: "text-sm font-semibold text-primary-foreground", children: submitLabel }) })
|
|
2378
2405
|
] });
|
|
2379
2406
|
}
|
|
2380
2407
|
|
|
2381
2408
|
// src/customer/customer-order-history.tsx
|
|
2382
|
-
import { ScrollView as
|
|
2409
|
+
import { ScrollView as ScrollView7, Text as Text18, View as View31 } from "react-native";
|
|
2383
2410
|
import { cn as cn58 } from "@tallyui/theme";
|
|
2384
2411
|
import { jsx as jsx60, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
2385
2412
|
function CustomerOrderHistory({
|
|
@@ -2391,45 +2418,198 @@ function CustomerOrderHistory({
|
|
|
2391
2418
|
}) {
|
|
2392
2419
|
return /* @__PURE__ */ jsxs20(View31, { className: cn58("flex-1", className), ...viewProps, children: [
|
|
2393
2420
|
/* @__PURE__ */ jsx60(Text18, { className: "px-3 py-2 text-xs font-semibold text-muted-foreground", children: "Order History" }),
|
|
2394
|
-
orders.length > 0 ? /* @__PURE__ */ jsx60(
|
|
2421
|
+
orders.length > 0 ? /* @__PURE__ */ jsx60(ScrollView7, { contentContainerClassName: "gap-2 px-3 pb-3", children: orders.map((order, index) => /* @__PURE__ */ jsx60(View31, { children: renderItem(order, index) }, order.id ?? index)) }) : emptyState ?? null
|
|
2395
2422
|
] });
|
|
2396
2423
|
}
|
|
2397
2424
|
|
|
2398
|
-
// src/
|
|
2399
|
-
import {
|
|
2425
|
+
// src/customer/customer-picker.tsx
|
|
2426
|
+
import { useEffect, useRef, useState as useState6 } from "react";
|
|
2427
|
+
import { Pressable as Pressable16, Text as Text19, TextInput as TextInput7, View as View32 } from "react-native";
|
|
2428
|
+
import { customerTraits, CustomerServiceError, ConnectorUnauthorizedError } from "@tallyui/core";
|
|
2400
2429
|
import { cn as cn59 } from "@tallyui/theme";
|
|
2401
2430
|
import { jsx as jsx61, jsxs as jsxs21 } from "react/jsx-runtime";
|
|
2431
|
+
var EMAIL_MAX = 254;
|
|
2432
|
+
var EMAIL_SHAPE = /^[^\s@\u0000]+@[^\s@\u0000]+\.[^\s@\u0000]+$/u;
|
|
2433
|
+
function CustomerPicker({ search, create, selected, onSelect, onError, online, debounceMs = 250, className }) {
|
|
2434
|
+
const [query, setQuery] = useState6("");
|
|
2435
|
+
const [customers, setCustomers] = useState6([]);
|
|
2436
|
+
const [error, setError] = useState6(null);
|
|
2437
|
+
const [showForm, setShowForm] = useState6(false);
|
|
2438
|
+
const [creating, setCreating] = useState6(false);
|
|
2439
|
+
const [values, setValues] = useState6({ firstName: "", lastName: "", email: "", phone: "", address: "" });
|
|
2440
|
+
const sequence = useRef(0);
|
|
2441
|
+
const searchRef = useRef(search);
|
|
2442
|
+
searchRef.current = search;
|
|
2443
|
+
const [noResults, setNoResults] = useState6(false);
|
|
2444
|
+
function handleError(error2) {
|
|
2445
|
+
if (error2 instanceof CustomerServiceError) {
|
|
2446
|
+
setError(error2.code === "network" ? "Couldn't reach the store. Try again." : error2.code === "server" ? "The store couldn't do that. Try again." : error2.message);
|
|
2447
|
+
} else {
|
|
2448
|
+
setError(error2 instanceof ConnectorUnauthorizedError ? "Sign in again to continue." : "Something went wrong. Try again.");
|
|
2449
|
+
onError?.(error2);
|
|
2450
|
+
}
|
|
2451
|
+
}
|
|
2452
|
+
useEffect(() => {
|
|
2453
|
+
const current = ++sequence.current;
|
|
2454
|
+
setNoResults(false);
|
|
2455
|
+
setError(null);
|
|
2456
|
+
if (!online || !query.trim()) {
|
|
2457
|
+
setCustomers([]);
|
|
2458
|
+
return;
|
|
2459
|
+
}
|
|
2460
|
+
const timer = setTimeout(async () => {
|
|
2461
|
+
try {
|
|
2462
|
+
const results = await searchRef.current(query);
|
|
2463
|
+
if (current === sequence.current) {
|
|
2464
|
+
setCustomers(results);
|
|
2465
|
+
setNoResults(results.length === 0);
|
|
2466
|
+
}
|
|
2467
|
+
} catch (error2) {
|
|
2468
|
+
if (current === sequence.current) handleError(error2);
|
|
2469
|
+
}
|
|
2470
|
+
}, debounceMs);
|
|
2471
|
+
return () => {
|
|
2472
|
+
clearTimeout(timer);
|
|
2473
|
+
sequence.current++;
|
|
2474
|
+
};
|
|
2475
|
+
}, [query, online, debounceMs]);
|
|
2476
|
+
async function submit() {
|
|
2477
|
+
const email = values.email.trim();
|
|
2478
|
+
if (!online || !create || creating || !email) return;
|
|
2479
|
+
if (email.length > EMAIL_MAX || !EMAIL_SHAPE.test(email)) return setError(`Enter a valid email address (up to ${EMAIL_MAX} characters)`);
|
|
2480
|
+
setCreating(true);
|
|
2481
|
+
setError(null);
|
|
2482
|
+
try {
|
|
2483
|
+
const created = await create({
|
|
2484
|
+
email,
|
|
2485
|
+
...values.firstName.trim() ? { firstName: values.firstName.trim() } : {},
|
|
2486
|
+
...values.lastName.trim() ? { lastName: values.lastName.trim() } : {},
|
|
2487
|
+
...values.phone.trim() ? { phone: values.phone.trim() } : {}
|
|
2488
|
+
});
|
|
2489
|
+
onSelect(created);
|
|
2490
|
+
setValues({ firstName: "", lastName: "", email: "", phone: "", address: "" });
|
|
2491
|
+
setShowForm(false);
|
|
2492
|
+
} catch (error2) {
|
|
2493
|
+
handleError(error2);
|
|
2494
|
+
} finally {
|
|
2495
|
+
setCreating(false);
|
|
2496
|
+
}
|
|
2497
|
+
}
|
|
2498
|
+
return /* @__PURE__ */ jsxs21(View32, { className: cn59("gap-3", className), children: [
|
|
2499
|
+
selected && /* @__PURE__ */ jsxs21(View32, { children: [
|
|
2500
|
+
/* @__PURE__ */ jsx61(CustomerCard, { doc: selected, traits: customerTraits }),
|
|
2501
|
+
/* @__PURE__ */ jsx61(Pressable16, { accessibilityRole: "button", className: "items-center rounded-lg border border-border px-4 py-3", onPress: () => onSelect(null), children: /* @__PURE__ */ jsx61(Text19, { className: "text-sm font-semibold text-foreground", children: "Remove customer" }) })
|
|
2502
|
+
] }),
|
|
2503
|
+
/* @__PURE__ */ jsx61(Text19, { className: "text-xs font-medium text-muted-foreground", children: "Search customers" }),
|
|
2504
|
+
/* @__PURE__ */ jsx61(
|
|
2505
|
+
TextInput7,
|
|
2506
|
+
{
|
|
2507
|
+
accessibilityLabel: "Search customers",
|
|
2508
|
+
value: query,
|
|
2509
|
+
onChangeText: setQuery,
|
|
2510
|
+
editable: online,
|
|
2511
|
+
className: "rounded-lg border border-border bg-card px-3 py-2 text-sm text-foreground",
|
|
2512
|
+
placeholderTextColorClassName: "accent-muted-foreground",
|
|
2513
|
+
placeholder: "Name or email"
|
|
2514
|
+
}
|
|
2515
|
+
),
|
|
2516
|
+
!online && /* @__PURE__ */ jsx61(Text19, { className: "text-sm text-muted-foreground", children: "Connect to search or add customers." }),
|
|
2517
|
+
noResults && /* @__PURE__ */ jsx61(Text19, { className: "text-sm text-muted-foreground", children: "No customers found." }),
|
|
2518
|
+
error && /* @__PURE__ */ jsx61(Text19, { accessibilityRole: "alert", className: "text-sm text-destructive", children: error }),
|
|
2519
|
+
/* @__PURE__ */ jsx61(
|
|
2520
|
+
CustomerSelect,
|
|
2521
|
+
{
|
|
2522
|
+
customers,
|
|
2523
|
+
traits: customerTraits,
|
|
2524
|
+
onSearch: setQuery,
|
|
2525
|
+
onSelect: (customer) => {
|
|
2526
|
+
onSelect(customer);
|
|
2527
|
+
setQuery("");
|
|
2528
|
+
}
|
|
2529
|
+
}
|
|
2530
|
+
),
|
|
2531
|
+
create && /* @__PURE__ */ jsx61(
|
|
2532
|
+
Pressable16,
|
|
2533
|
+
{
|
|
2534
|
+
accessibilityRole: "button",
|
|
2535
|
+
disabled: !online || creating,
|
|
2536
|
+
onPress: () => setShowForm(true),
|
|
2537
|
+
className: cn59("items-center rounded-lg border border-border px-4 py-3", (!online || creating) && "opacity-50"),
|
|
2538
|
+
children: /* @__PURE__ */ jsx61(Text19, { className: "text-sm font-semibold text-foreground", children: "New customer" })
|
|
2539
|
+
}
|
|
2540
|
+
),
|
|
2541
|
+
showForm && /* @__PURE__ */ jsxs21(View32, { children: [
|
|
2542
|
+
/* @__PURE__ */ jsx61(
|
|
2543
|
+
CustomerForm,
|
|
2544
|
+
{
|
|
2545
|
+
values,
|
|
2546
|
+
showAddress: false,
|
|
2547
|
+
onChangeField: (field, value) => setValues((current) => ({ ...current, [field]: value }))
|
|
2548
|
+
}
|
|
2549
|
+
),
|
|
2550
|
+
/* @__PURE__ */ jsxs21(View32, { className: "flex-row gap-3", children: [
|
|
2551
|
+
/* @__PURE__ */ jsx61(
|
|
2552
|
+
Pressable16,
|
|
2553
|
+
{
|
|
2554
|
+
accessibilityRole: "button",
|
|
2555
|
+
disabled: !online || creating || !values.email.trim(),
|
|
2556
|
+
onPress: submit,
|
|
2557
|
+
className: cn59("items-center rounded-lg bg-primary px-4 py-3", (!online || creating || !values.email.trim()) && "opacity-50"),
|
|
2558
|
+
children: /* @__PURE__ */ jsx61(Text19, { className: "text-sm font-semibold text-primary-foreground", children: "Save Customer" })
|
|
2559
|
+
}
|
|
2560
|
+
),
|
|
2561
|
+
/* @__PURE__ */ jsx61(
|
|
2562
|
+
Pressable16,
|
|
2563
|
+
{
|
|
2564
|
+
accessibilityRole: "button",
|
|
2565
|
+
className: "items-center rounded-lg border border-border px-4 py-3",
|
|
2566
|
+
onPress: () => {
|
|
2567
|
+
setShowForm(false);
|
|
2568
|
+
setValues({ firstName: "", lastName: "", email: "", phone: "", address: "" });
|
|
2569
|
+
},
|
|
2570
|
+
children: /* @__PURE__ */ jsx61(Text19, { className: "text-sm font-semibold text-foreground", children: "Cancel" })
|
|
2571
|
+
}
|
|
2572
|
+
)
|
|
2573
|
+
] })
|
|
2574
|
+
] })
|
|
2575
|
+
] });
|
|
2576
|
+
}
|
|
2577
|
+
|
|
2578
|
+
// src/checkout/payment-method-card.tsx
|
|
2579
|
+
import { Pressable as Pressable17, View as View33 } from "react-native";
|
|
2580
|
+
import { cn as cn60 } from "@tallyui/theme";
|
|
2581
|
+
import { jsx as jsx62, jsxs as jsxs22 } from "react/jsx-runtime";
|
|
2402
2582
|
function PaymentMethodCard({ label, selected, onPress, icon, className, ...props }) {
|
|
2403
|
-
return /* @__PURE__ */
|
|
2583
|
+
return /* @__PURE__ */ jsx62(Pressable17, { onPress, ...props, children: /* @__PURE__ */ jsxs22(
|
|
2404
2584
|
HStack,
|
|
2405
2585
|
{
|
|
2406
|
-
className:
|
|
2586
|
+
className: cn60(
|
|
2407
2587
|
"rounded-lg border px-4 py-3",
|
|
2408
2588
|
selected ? "border-primary bg-primary/5" : "border-border bg-card",
|
|
2409
2589
|
className
|
|
2410
2590
|
),
|
|
2411
2591
|
children: [
|
|
2412
|
-
icon && /* @__PURE__ */
|
|
2413
|
-
/* @__PURE__ */
|
|
2414
|
-
selected && /* @__PURE__ */
|
|
2592
|
+
icon && /* @__PURE__ */ jsx62(View33, { children: icon }),
|
|
2593
|
+
/* @__PURE__ */ jsx62(Text, { className: cn60("flex-1 text-sm font-medium", selected ? "text-primary" : ""), children: label }),
|
|
2594
|
+
selected && /* @__PURE__ */ jsx62(View33, { className: "h-5 w-5 items-center justify-center rounded-full bg-primary", children: /* @__PURE__ */ jsx62(Text, { className: "text-xs text-primary-foreground", children: "\u2713" }) })
|
|
2415
2595
|
]
|
|
2416
2596
|
}
|
|
2417
2597
|
) });
|
|
2418
2598
|
}
|
|
2419
2599
|
|
|
2420
2600
|
// src/checkout/order-summary-line.tsx
|
|
2421
|
-
import { cn as
|
|
2422
|
-
import { jsx as
|
|
2601
|
+
import { cn as cn61 } from "@tallyui/theme";
|
|
2602
|
+
import { jsx as jsx63, jsxs as jsxs23 } from "react/jsx-runtime";
|
|
2423
2603
|
function OrderSummaryLine({ label, amount, bold = false, className, ...props }) {
|
|
2424
|
-
return /* @__PURE__ */
|
|
2425
|
-
/* @__PURE__ */
|
|
2426
|
-
/* @__PURE__ */
|
|
2604
|
+
return /* @__PURE__ */ jsxs23(HStack, { space: "none", className: cn61("justify-between", className), ...props, children: [
|
|
2605
|
+
/* @__PURE__ */ jsx63(Text, { className: cn61("text-sm", bold ? "font-bold" : "text-muted-foreground"), children: label }),
|
|
2606
|
+
/* @__PURE__ */ jsx63(Text, { className: cn61("text-sm", bold && "font-bold"), children: amount })
|
|
2427
2607
|
] });
|
|
2428
2608
|
}
|
|
2429
2609
|
|
|
2430
2610
|
// src/checkout/payment-selector.tsx
|
|
2431
|
-
import { cn as
|
|
2432
|
-
import { jsx as
|
|
2611
|
+
import { cn as cn62 } from "@tallyui/theme";
|
|
2612
|
+
import { jsx as jsx64 } from "react/jsx-runtime";
|
|
2433
2613
|
function PaymentSelector({
|
|
2434
2614
|
methods,
|
|
2435
2615
|
selected,
|
|
@@ -2437,7 +2617,7 @@ function PaymentSelector({
|
|
|
2437
2617
|
className,
|
|
2438
2618
|
...props
|
|
2439
2619
|
}) {
|
|
2440
|
-
return /* @__PURE__ */
|
|
2620
|
+
return /* @__PURE__ */ jsx64(VStack, { space: "sm", className: cn62(className), ...props, children: methods.map((method) => /* @__PURE__ */ jsx64(
|
|
2441
2621
|
PaymentMethodCard,
|
|
2442
2622
|
{
|
|
2443
2623
|
label: method.label,
|
|
@@ -2450,9 +2630,9 @@ function PaymentSelector({
|
|
|
2450
2630
|
}
|
|
2451
2631
|
|
|
2452
2632
|
// src/checkout/order-summary.tsx
|
|
2453
|
-
import { View as
|
|
2454
|
-
import { cn as
|
|
2455
|
-
import { jsx as
|
|
2633
|
+
import { View as View34 } from "react-native";
|
|
2634
|
+
import { cn as cn63 } from "@tallyui/theme";
|
|
2635
|
+
import { jsx as jsx65, jsxs as jsxs24 } from "react/jsx-runtime";
|
|
2456
2636
|
function OrderSummary({
|
|
2457
2637
|
subtotal,
|
|
2458
2638
|
tax,
|
|
@@ -2464,34 +2644,34 @@ function OrderSummary({
|
|
|
2464
2644
|
className,
|
|
2465
2645
|
...props
|
|
2466
2646
|
}) {
|
|
2467
|
-
return /* @__PURE__ */
|
|
2468
|
-
header && /* @__PURE__ */
|
|
2469
|
-
/* @__PURE__ */
|
|
2470
|
-
tax && /* @__PURE__ */
|
|
2471
|
-
/* @__PURE__ */
|
|
2472
|
-
payments && payments.length > 0 && /* @__PURE__ */
|
|
2473
|
-
footer && /* @__PURE__ */
|
|
2647
|
+
return /* @__PURE__ */ jsxs24(VStack, { space: "none", className: cn63("gap-1.5 px-3 py-3", className), ...props, children: [
|
|
2648
|
+
header && /* @__PURE__ */ jsx65(View34, { className: "mb-2", children: header }),
|
|
2649
|
+
/* @__PURE__ */ jsx65(OrderSummaryLine, { label: "Subtotal", amount: subtotal }),
|
|
2650
|
+
tax && /* @__PURE__ */ jsx65(OrderSummaryLine, { label: taxLabel, amount: tax }),
|
|
2651
|
+
/* @__PURE__ */ jsx65(OrderSummaryLine, { label: "Total", amount: total, bold: true }),
|
|
2652
|
+
payments && payments.length > 0 && /* @__PURE__ */ jsx65(VStack, { space: "none", className: "mt-2 gap-1.5 border-t border-border pt-2", children: payments.map((payment) => /* @__PURE__ */ jsx65(OrderSummaryLine, { label: payment.label, amount: payment.amount }, payment.label)) }),
|
|
2653
|
+
footer && /* @__PURE__ */ jsx65(View34, { className: "mt-2", children: footer })
|
|
2474
2654
|
] });
|
|
2475
2655
|
}
|
|
2476
2656
|
|
|
2477
2657
|
// src/checkout/change-display.tsx
|
|
2478
|
-
import { Text as
|
|
2658
|
+
import { Text as Text20, View as View35 } from "react-native";
|
|
2479
2659
|
import { formatMoney as formatMoney4 } from "@tallyui/core";
|
|
2480
|
-
import { cn as
|
|
2481
|
-
import { jsx as
|
|
2660
|
+
import { cn as cn64 } from "@tallyui/theme";
|
|
2661
|
+
import { jsx as jsx66, jsxs as jsxs25 } from "react/jsx-runtime";
|
|
2482
2662
|
function ChangeDisplay({ change, locale, className, ...viewProps }) {
|
|
2483
|
-
return /* @__PURE__ */
|
|
2484
|
-
/* @__PURE__ */
|
|
2485
|
-
/* @__PURE__ */
|
|
2663
|
+
return /* @__PURE__ */ jsxs25(View35, { className: cn64("items-center gap-1 rounded-xl bg-muted p-4", className), ...viewProps, children: [
|
|
2664
|
+
/* @__PURE__ */ jsx66(Text20, { className: "text-sm text-muted-foreground", children: "Change Due" }),
|
|
2665
|
+
/* @__PURE__ */ jsx66(Text20, { className: "text-3xl font-bold text-success", children: formatMoney4(change, locale) ?? "\u2014" })
|
|
2486
2666
|
] });
|
|
2487
2667
|
}
|
|
2488
2668
|
|
|
2489
2669
|
// src/checkout/cash-tendered.tsx
|
|
2490
|
-
import { useEffect, useRef, useState as
|
|
2491
|
-
import { Pressable as
|
|
2670
|
+
import { useEffect as useEffect2, useRef as useRef2, useState as useState7 } from "react";
|
|
2671
|
+
import { Pressable as Pressable18, Text as Text21, TextInput as TextInput8, View as View36 } from "react-native";
|
|
2492
2672
|
import { formatMoney as formatMoney5, minorUnitDigits as minorUnitDigits2, moneyFromDecimalString } from "@tallyui/core";
|
|
2493
|
-
import { cn as
|
|
2494
|
-
import { jsx as
|
|
2673
|
+
import { cn as cn65 } from "@tallyui/theme";
|
|
2674
|
+
import { jsx as jsx67, jsxs as jsxs26 } from "react/jsx-runtime";
|
|
2495
2675
|
function defaultQuickAmounts(total) {
|
|
2496
2676
|
const unit = 10 ** minorUnitDigits2(total.currency);
|
|
2497
2677
|
const amounts = [
|
|
@@ -2512,15 +2692,15 @@ function CashTendered({
|
|
|
2512
2692
|
className,
|
|
2513
2693
|
...viewProps
|
|
2514
2694
|
}) {
|
|
2515
|
-
const [internalAmount, setInternalAmount] =
|
|
2695
|
+
const [internalAmount, setInternalAmount] = useState7(defaultAmount ?? total);
|
|
2516
2696
|
const amount = controlledAmount ?? internalAmount;
|
|
2517
2697
|
const buttons = quickAmounts ?? defaultQuickAmounts(total);
|
|
2518
2698
|
const digits = minorUnitDigits2(amount.currency);
|
|
2519
2699
|
const amountText = String(Math.abs(amount.amount)).padStart(digits + 1, "0");
|
|
2520
2700
|
const decimal2 = (amount.amount < 0 ? "-" : "") + (digits ? `${amountText.slice(0, -digits)}.${amountText.slice(-digits)}` : amountText);
|
|
2521
|
-
const [text, setText] =
|
|
2522
|
-
const lastTextAmount =
|
|
2523
|
-
|
|
2701
|
+
const [text, setText] = useState7(decimal2);
|
|
2702
|
+
const lastTextAmount = useRef2(amount);
|
|
2703
|
+
useEffect2(() => {
|
|
2524
2704
|
if (amount.amount !== lastTextAmount.current.amount || amount.currency !== lastTextAmount.current.currency) {
|
|
2525
2705
|
setText(decimal2);
|
|
2526
2706
|
lastTextAmount.current = amount;
|
|
@@ -2530,20 +2710,20 @@ function CashTendered({
|
|
|
2530
2710
|
if (controlledAmount === void 0) setInternalAmount(value);
|
|
2531
2711
|
onChangeAmount?.(value);
|
|
2532
2712
|
};
|
|
2533
|
-
return /* @__PURE__ */
|
|
2534
|
-
/* @__PURE__ */
|
|
2535
|
-
/* @__PURE__ */
|
|
2536
|
-
|
|
2713
|
+
return /* @__PURE__ */ jsxs26(View36, { className: cn65("gap-3", className), ...viewProps, children: [
|
|
2714
|
+
/* @__PURE__ */ jsx67(Text21, { className: "text-sm font-semibold text-foreground", children: "Cash Tendered" }),
|
|
2715
|
+
/* @__PURE__ */ jsx67(View36, { className: "flex-row flex-wrap gap-2", children: buttons.map((val) => /* @__PURE__ */ jsx67(
|
|
2716
|
+
Pressable18,
|
|
2537
2717
|
{
|
|
2538
2718
|
onPress: () => handleChange(val),
|
|
2539
|
-
className:
|
|
2719
|
+
className: cn65(
|
|
2540
2720
|
"rounded-lg border px-4 py-2",
|
|
2541
2721
|
amount.amount === val.amount && amount.currency === val.currency ? "border-primary bg-primary" : "border-input bg-card"
|
|
2542
2722
|
),
|
|
2543
|
-
children: /* @__PURE__ */
|
|
2544
|
-
|
|
2723
|
+
children: /* @__PURE__ */ jsx67(
|
|
2724
|
+
Text21,
|
|
2545
2725
|
{
|
|
2546
|
-
className:
|
|
2726
|
+
className: cn65(
|
|
2547
2727
|
"text-sm font-semibold",
|
|
2548
2728
|
amount.amount === val.amount && amount.currency === val.currency ? "text-primary-foreground" : "text-foreground"
|
|
2549
2729
|
),
|
|
@@ -2553,8 +2733,8 @@ function CashTendered({
|
|
|
2553
2733
|
},
|
|
2554
2734
|
`${val.currency}:${val.amount}`
|
|
2555
2735
|
)) }),
|
|
2556
|
-
/* @__PURE__ */
|
|
2557
|
-
|
|
2736
|
+
/* @__PURE__ */ jsx67(
|
|
2737
|
+
TextInput8,
|
|
2558
2738
|
{
|
|
2559
2739
|
value: text,
|
|
2560
2740
|
onChangeText: (text2) => {
|
|
@@ -2575,9 +2755,9 @@ function CashTendered({
|
|
|
2575
2755
|
}
|
|
2576
2756
|
|
|
2577
2757
|
// src/checkout/receipt-preview.tsx
|
|
2578
|
-
import { Text as
|
|
2579
|
-
import { cn as
|
|
2580
|
-
import { jsx as
|
|
2758
|
+
import { Text as Text22, View as View37 } from "react-native";
|
|
2759
|
+
import { cn as cn66 } from "@tallyui/theme";
|
|
2760
|
+
import { jsx as jsx68, jsxs as jsxs27 } from "react/jsx-runtime";
|
|
2581
2761
|
function ReceiptPreview({
|
|
2582
2762
|
items,
|
|
2583
2763
|
subtotal,
|
|
@@ -2589,42 +2769,42 @@ function ReceiptPreview({
|
|
|
2589
2769
|
className,
|
|
2590
2770
|
...viewProps
|
|
2591
2771
|
}) {
|
|
2592
|
-
return /* @__PURE__ */
|
|
2593
|
-
headerSlot && /* @__PURE__ */
|
|
2594
|
-
/* @__PURE__ */
|
|
2595
|
-
/* @__PURE__ */
|
|
2772
|
+
return /* @__PURE__ */ jsxs27(View37, { className: cn66("rounded-lg border border-border bg-card p-4", className), ...viewProps, children: [
|
|
2773
|
+
headerSlot && /* @__PURE__ */ jsx68(View37, { className: "mb-3 items-center border-b border-dashed border-border pb-3", children: headerSlot }),
|
|
2774
|
+
/* @__PURE__ */ jsx68(View37, { className: "gap-1", children: items.map((item, i) => /* @__PURE__ */ jsxs27(View37, { className: "flex-row justify-between", children: [
|
|
2775
|
+
/* @__PURE__ */ jsxs27(Text22, { className: "flex-1 text-sm text-foreground", children: [
|
|
2596
2776
|
item.name,
|
|
2597
2777
|
" x",
|
|
2598
2778
|
item.quantity
|
|
2599
2779
|
] }),
|
|
2600
|
-
/* @__PURE__ */
|
|
2780
|
+
/* @__PURE__ */ jsx68(Text22, { className: "text-sm text-foreground", children: item.total })
|
|
2601
2781
|
] }, i)) }),
|
|
2602
|
-
/* @__PURE__ */
|
|
2603
|
-
/* @__PURE__ */
|
|
2604
|
-
/* @__PURE__ */
|
|
2605
|
-
/* @__PURE__ */
|
|
2782
|
+
/* @__PURE__ */ jsxs27(View37, { className: "mt-3 gap-1 border-t border-dashed border-border pt-3", children: [
|
|
2783
|
+
/* @__PURE__ */ jsxs27(View37, { className: "flex-row justify-between", children: [
|
|
2784
|
+
/* @__PURE__ */ jsx68(Text22, { className: "text-sm text-muted-foreground", children: "Subtotal" }),
|
|
2785
|
+
/* @__PURE__ */ jsx68(Text22, { className: "text-sm text-foreground", children: subtotal })
|
|
2606
2786
|
] }),
|
|
2607
|
-
/* @__PURE__ */
|
|
2608
|
-
/* @__PURE__ */
|
|
2609
|
-
/* @__PURE__ */
|
|
2787
|
+
/* @__PURE__ */ jsxs27(View37, { className: "flex-row justify-between", children: [
|
|
2788
|
+
/* @__PURE__ */ jsx68(Text22, { className: "text-sm text-muted-foreground", children: "Tax" }),
|
|
2789
|
+
/* @__PURE__ */ jsx68(Text22, { className: "text-sm text-foreground", children: tax })
|
|
2610
2790
|
] }),
|
|
2611
|
-
/* @__PURE__ */
|
|
2612
|
-
/* @__PURE__ */
|
|
2613
|
-
/* @__PURE__ */
|
|
2791
|
+
/* @__PURE__ */ jsxs27(View37, { className: "flex-row justify-between border-t border-border pt-1", children: [
|
|
2792
|
+
/* @__PURE__ */ jsx68(Text22, { className: "text-sm font-bold text-foreground", children: "Total" }),
|
|
2793
|
+
/* @__PURE__ */ jsx68(Text22, { className: "text-sm font-bold text-foreground", children: total })
|
|
2614
2794
|
] })
|
|
2615
2795
|
] }),
|
|
2616
|
-
payments && payments.length > 0 && /* @__PURE__ */
|
|
2617
|
-
/* @__PURE__ */
|
|
2618
|
-
/* @__PURE__ */
|
|
2796
|
+
payments && payments.length > 0 && /* @__PURE__ */ jsx68(View37, { className: "mt-3 gap-1 border-t border-dashed border-border pt-3", children: payments.map((p, i) => /* @__PURE__ */ jsxs27(View37, { className: "flex-row justify-between", children: [
|
|
2797
|
+
/* @__PURE__ */ jsx68(Text22, { className: "text-sm text-muted-foreground", children: p.method }),
|
|
2798
|
+
/* @__PURE__ */ jsx68(Text22, { className: "text-sm text-foreground", children: p.amount })
|
|
2619
2799
|
] }, i)) }),
|
|
2620
|
-
footerSlot && /* @__PURE__ */
|
|
2800
|
+
footerSlot && /* @__PURE__ */ jsx68(View37, { className: "mt-3 items-center border-t border-dashed border-border pt-3", children: footerSlot })
|
|
2621
2801
|
] });
|
|
2622
2802
|
}
|
|
2623
2803
|
|
|
2624
2804
|
// src/order/order-status-badge.tsx
|
|
2625
|
-
import { Text as
|
|
2626
|
-
import { cn as
|
|
2627
|
-
import { jsx as
|
|
2805
|
+
import { Text as Text23, View as View38 } from "react-native";
|
|
2806
|
+
import { cn as cn67 } from "@tallyui/theme";
|
|
2807
|
+
import { jsx as jsx69, jsxs as jsxs28 } from "react/jsx-runtime";
|
|
2628
2808
|
var STATUS_CONFIG = {
|
|
2629
2809
|
pending: { label: "Pending", badge: "bg-warning/15", dot: "bg-warning", text: "text-foreground" },
|
|
2630
2810
|
processing: { label: "Processing", badge: "bg-info/15", dot: "bg-info", text: "text-foreground" },
|
|
@@ -2634,23 +2814,23 @@ var STATUS_CONFIG = {
|
|
|
2634
2814
|
};
|
|
2635
2815
|
function OrderStatusBadge({ status, className, ...viewProps }) {
|
|
2636
2816
|
const config = STATUS_CONFIG[status] ?? STATUS_CONFIG.pending;
|
|
2637
|
-
return /* @__PURE__ */
|
|
2638
|
-
|
|
2817
|
+
return /* @__PURE__ */ jsxs28(
|
|
2818
|
+
View38,
|
|
2639
2819
|
{
|
|
2640
|
-
className:
|
|
2820
|
+
className: cn67("flex-row items-center self-start gap-1.5 rounded-xl px-2 py-1", config.badge, className),
|
|
2641
2821
|
...viewProps,
|
|
2642
2822
|
children: [
|
|
2643
|
-
/* @__PURE__ */
|
|
2644
|
-
/* @__PURE__ */
|
|
2823
|
+
/* @__PURE__ */ jsx69(View38, { className: cn67("h-1.5 w-1.5 rounded-full", config.dot) }),
|
|
2824
|
+
/* @__PURE__ */ jsx69(Text23, { className: cn67("text-xs font-semibold", config.text), children: config.label })
|
|
2645
2825
|
]
|
|
2646
2826
|
}
|
|
2647
2827
|
);
|
|
2648
2828
|
}
|
|
2649
2829
|
|
|
2650
2830
|
// src/order/order-card.tsx
|
|
2651
|
-
import { Pressable as
|
|
2652
|
-
import { cn as
|
|
2653
|
-
import { jsx as
|
|
2831
|
+
import { Pressable as Pressable19, Text as Text24, View as View39 } from "react-native";
|
|
2832
|
+
import { cn as cn68 } from "@tallyui/theme";
|
|
2833
|
+
import { jsx as jsx70, jsxs as jsxs29 } from "react/jsx-runtime";
|
|
2654
2834
|
function OrderCard({
|
|
2655
2835
|
orderNumber,
|
|
2656
2836
|
date,
|
|
@@ -2661,24 +2841,24 @@ function OrderCard({
|
|
|
2661
2841
|
className,
|
|
2662
2842
|
...viewProps
|
|
2663
2843
|
}) {
|
|
2664
|
-
const Wrapper = onPress ?
|
|
2665
|
-
return /* @__PURE__ */
|
|
2844
|
+
const Wrapper = onPress ? Pressable19 : View39;
|
|
2845
|
+
return /* @__PURE__ */ jsxs29(
|
|
2666
2846
|
Wrapper,
|
|
2667
2847
|
{
|
|
2668
2848
|
onPress,
|
|
2669
|
-
className:
|
|
2849
|
+
className: cn68("gap-2 rounded-lg border border-border bg-card p-3", className),
|
|
2670
2850
|
...viewProps,
|
|
2671
2851
|
children: [
|
|
2672
|
-
/* @__PURE__ */
|
|
2673
|
-
/* @__PURE__ */
|
|
2674
|
-
/* @__PURE__ */
|
|
2852
|
+
/* @__PURE__ */ jsxs29(View39, { className: "flex-row items-center justify-between", children: [
|
|
2853
|
+
/* @__PURE__ */ jsx70(Text24, { className: "text-sm font-semibold text-foreground", children: orderNumber }),
|
|
2854
|
+
/* @__PURE__ */ jsx70(OrderStatusBadge, { status })
|
|
2675
2855
|
] }),
|
|
2676
|
-
/* @__PURE__ */
|
|
2677
|
-
/* @__PURE__ */
|
|
2678
|
-
/* @__PURE__ */
|
|
2679
|
-
customerName && /* @__PURE__ */
|
|
2856
|
+
/* @__PURE__ */ jsxs29(View39, { className: "flex-row items-center justify-between", children: [
|
|
2857
|
+
/* @__PURE__ */ jsxs29(View39, { className: "gap-0.5", children: [
|
|
2858
|
+
/* @__PURE__ */ jsx70(Text24, { className: "text-xs text-muted-foreground", children: date }),
|
|
2859
|
+
customerName && /* @__PURE__ */ jsx70(Text24, { className: "text-xs text-muted-foreground", children: customerName })
|
|
2680
2860
|
] }),
|
|
2681
|
-
/* @__PURE__ */
|
|
2861
|
+
/* @__PURE__ */ jsx70(Text24, { className: "text-sm font-semibold text-foreground", children: total })
|
|
2682
2862
|
] })
|
|
2683
2863
|
]
|
|
2684
2864
|
}
|
|
@@ -2686,9 +2866,9 @@ function OrderCard({
|
|
|
2686
2866
|
}
|
|
2687
2867
|
|
|
2688
2868
|
// src/order/order-list.tsx
|
|
2689
|
-
import { ScrollView as
|
|
2690
|
-
import { cn as
|
|
2691
|
-
import { jsx as
|
|
2869
|
+
import { ScrollView as ScrollView8, View as View40 } from "react-native";
|
|
2870
|
+
import { cn as cn69 } from "@tallyui/theme";
|
|
2871
|
+
import { jsx as jsx71, jsxs as jsxs30 } from "react/jsx-runtime";
|
|
2692
2872
|
function OrderList({
|
|
2693
2873
|
items,
|
|
2694
2874
|
renderItem,
|
|
@@ -2698,16 +2878,16 @@ function OrderList({
|
|
|
2698
2878
|
...viewProps
|
|
2699
2879
|
}) {
|
|
2700
2880
|
const hasItems = items.length > 0;
|
|
2701
|
-
return /* @__PURE__ */
|
|
2702
|
-
headerSlot && /* @__PURE__ */
|
|
2703
|
-
hasItems ? /* @__PURE__ */
|
|
2881
|
+
return /* @__PURE__ */ jsxs30(View40, { className: cn69("flex-1", className), ...viewProps, children: [
|
|
2882
|
+
headerSlot && /* @__PURE__ */ jsx71(View40, { className: "px-3 py-2", children: headerSlot }),
|
|
2883
|
+
hasItems ? /* @__PURE__ */ jsx71(ScrollView8, { contentContainerClassName: "gap-2 p-3", children: items.map((item, index) => /* @__PURE__ */ jsx71(View40, { children: renderItem(item, index) }, item.id ?? index)) }) : emptyState ?? null
|
|
2704
2884
|
] });
|
|
2705
2885
|
}
|
|
2706
2886
|
|
|
2707
2887
|
// src/order/order-detail.tsx
|
|
2708
|
-
import { ScrollView as
|
|
2709
|
-
import { cn as
|
|
2710
|
-
import { jsx as
|
|
2888
|
+
import { ScrollView as ScrollView9, Text as Text25, View as View41 } from "react-native";
|
|
2889
|
+
import { cn as cn70 } from "@tallyui/theme";
|
|
2890
|
+
import { jsx as jsx72, jsxs as jsxs31 } from "react/jsx-runtime";
|
|
2711
2891
|
function OrderDetail({
|
|
2712
2892
|
orderNumber,
|
|
2713
2893
|
status,
|
|
@@ -2721,47 +2901,47 @@ function OrderDetail({
|
|
|
2721
2901
|
className,
|
|
2722
2902
|
...viewProps
|
|
2723
2903
|
}) {
|
|
2724
|
-
return /* @__PURE__ */
|
|
2725
|
-
/* @__PURE__ */
|
|
2726
|
-
/* @__PURE__ */
|
|
2727
|
-
/* @__PURE__ */
|
|
2904
|
+
return /* @__PURE__ */ jsx72(ScrollView9, { className: cn70("flex-1", className), ...viewProps, children: /* @__PURE__ */ jsxs31(View41, { className: "gap-4 p-4", children: [
|
|
2905
|
+
/* @__PURE__ */ jsxs31(View41, { className: "flex-row items-center justify-between", children: [
|
|
2906
|
+
/* @__PURE__ */ jsx72(Text25, { className: "text-lg font-bold text-foreground", children: orderNumber }),
|
|
2907
|
+
/* @__PURE__ */ jsx72(OrderStatusBadge, { status })
|
|
2728
2908
|
] }),
|
|
2729
|
-
customerSlot && /* @__PURE__ */
|
|
2730
|
-
/* @__PURE__ */
|
|
2731
|
-
/* @__PURE__ */
|
|
2732
|
-
lineItems.map((item, i) => /* @__PURE__ */
|
|
2733
|
-
/* @__PURE__ */
|
|
2909
|
+
customerSlot && /* @__PURE__ */ jsx72(View41, { className: "border-b border-border pb-3", children: customerSlot }),
|
|
2910
|
+
/* @__PURE__ */ jsxs31(View41, { className: "gap-1", children: [
|
|
2911
|
+
/* @__PURE__ */ jsx72(Text25, { className: "text-xs font-semibold text-muted-foreground", children: "Items" }),
|
|
2912
|
+
lineItems.map((item, i) => /* @__PURE__ */ jsxs31(View41, { className: "flex-row items-center justify-between py-1", children: [
|
|
2913
|
+
/* @__PURE__ */ jsxs31(Text25, { className: "flex-1 text-sm text-foreground", children: [
|
|
2734
2914
|
item.name,
|
|
2735
2915
|
" x",
|
|
2736
2916
|
item.quantity
|
|
2737
2917
|
] }),
|
|
2738
|
-
/* @__PURE__ */
|
|
2918
|
+
/* @__PURE__ */ jsx72(Text25, { className: "text-sm text-foreground", children: item.total })
|
|
2739
2919
|
] }, i))
|
|
2740
2920
|
] }),
|
|
2741
|
-
/* @__PURE__ */
|
|
2742
|
-
/* @__PURE__ */
|
|
2743
|
-
/* @__PURE__ */
|
|
2744
|
-
/* @__PURE__ */
|
|
2921
|
+
/* @__PURE__ */ jsxs31(View41, { className: "gap-1 border-t border-border pt-3", children: [
|
|
2922
|
+
/* @__PURE__ */ jsxs31(View41, { className: "flex-row justify-between", children: [
|
|
2923
|
+
/* @__PURE__ */ jsx72(Text25, { className: "text-sm text-muted-foreground", children: "Subtotal" }),
|
|
2924
|
+
/* @__PURE__ */ jsx72(Text25, { className: "text-sm text-foreground", children: subtotal })
|
|
2745
2925
|
] }),
|
|
2746
|
-
/* @__PURE__ */
|
|
2747
|
-
/* @__PURE__ */
|
|
2748
|
-
/* @__PURE__ */
|
|
2926
|
+
/* @__PURE__ */ jsxs31(View41, { className: "flex-row justify-between", children: [
|
|
2927
|
+
/* @__PURE__ */ jsx72(Text25, { className: "text-sm text-muted-foreground", children: "Tax" }),
|
|
2928
|
+
/* @__PURE__ */ jsx72(Text25, { className: "text-sm text-foreground", children: tax })
|
|
2749
2929
|
] }),
|
|
2750
|
-
/* @__PURE__ */
|
|
2751
|
-
/* @__PURE__ */
|
|
2752
|
-
/* @__PURE__ */
|
|
2930
|
+
/* @__PURE__ */ jsxs31(View41, { className: "flex-row justify-between pt-1", children: [
|
|
2931
|
+
/* @__PURE__ */ jsx72(Text25, { className: "text-sm font-bold text-foreground", children: "Total" }),
|
|
2932
|
+
/* @__PURE__ */ jsx72(Text25, { className: "text-sm font-bold text-foreground", children: total })
|
|
2753
2933
|
] })
|
|
2754
2934
|
] }),
|
|
2755
|
-
paymentSlot && /* @__PURE__ */
|
|
2756
|
-
footerSlot && /* @__PURE__ */
|
|
2935
|
+
paymentSlot && /* @__PURE__ */ jsx72(View41, { className: "border-t border-border pt-3", children: paymentSlot }),
|
|
2936
|
+
footerSlot && /* @__PURE__ */ jsx72(View41, { className: "border-t border-border pt-3", children: footerSlot })
|
|
2757
2937
|
] }) });
|
|
2758
2938
|
}
|
|
2759
2939
|
|
|
2760
2940
|
// src/register/cash-count-input.tsx
|
|
2761
|
-
import { useState as
|
|
2762
|
-
import { Text as
|
|
2763
|
-
import { cn as
|
|
2764
|
-
import { jsx as
|
|
2941
|
+
import { useState as useState8 } from "react";
|
|
2942
|
+
import { Text as Text26, View as View42 } from "react-native";
|
|
2943
|
+
import { cn as cn71 } from "@tallyui/theme";
|
|
2944
|
+
import { jsx as jsx73, jsxs as jsxs32 } from "react/jsx-runtime";
|
|
2765
2945
|
var DEFAULT_DENOMINATIONS = [
|
|
2766
2946
|
{ label: "$100", value: 100 },
|
|
2767
2947
|
{ label: "$50", value: 50 },
|
|
@@ -2783,7 +2963,7 @@ function CashCountInput({
|
|
|
2783
2963
|
className,
|
|
2784
2964
|
...viewProps
|
|
2785
2965
|
}) {
|
|
2786
|
-
const [internalCounts, setInternalCounts] =
|
|
2966
|
+
const [internalCounts, setInternalCounts] = useState8(defaultCounts ?? {});
|
|
2787
2967
|
const counts = controlledCounts ?? internalCounts;
|
|
2788
2968
|
const total = denominations2.reduce(
|
|
2789
2969
|
(sum, d) => sum + d.value * (counts[d.value] ?? 0),
|
|
@@ -2799,10 +2979,10 @@ function CashCountInput({
|
|
|
2799
2979
|
);
|
|
2800
2980
|
onChangeTotal?.(newTotal);
|
|
2801
2981
|
};
|
|
2802
|
-
return /* @__PURE__ */
|
|
2803
|
-
denominations2.map((d) => /* @__PURE__ */
|
|
2804
|
-
/* @__PURE__ */
|
|
2805
|
-
/* @__PURE__ */
|
|
2982
|
+
return /* @__PURE__ */ jsxs32(View42, { className: cn71("gap-2", className), ...viewProps, children: [
|
|
2983
|
+
denominations2.map((d) => /* @__PURE__ */ jsxs32(View42, { className: "flex-row items-center justify-between px-3 py-1", children: [
|
|
2984
|
+
/* @__PURE__ */ jsx73(Text26, { className: "w-16 text-sm font-medium text-foreground", children: d.label }),
|
|
2985
|
+
/* @__PURE__ */ jsx73(
|
|
2806
2986
|
QuantityStepper,
|
|
2807
2987
|
{
|
|
2808
2988
|
quantity: counts[d.value] ?? 0,
|
|
@@ -2810,9 +2990,9 @@ function CashCountInput({
|
|
|
2810
2990
|
onChangeQuantity: (qty) => handleCountChange(d.value, qty)
|
|
2811
2991
|
}
|
|
2812
2992
|
),
|
|
2813
|
-
/* @__PURE__ */
|
|
2993
|
+
/* @__PURE__ */ jsx73(Text26, { className: "w-20 text-right text-sm text-muted-foreground", children: (d.value * (counts[d.value] ?? 0)).toFixed(2) })
|
|
2814
2994
|
] }, d.value)),
|
|
2815
|
-
/* @__PURE__ */
|
|
2995
|
+
/* @__PURE__ */ jsx73(View42, { className: "border-t border-border px-3 pt-2", children: /* @__PURE__ */ jsxs32(Text26, { className: "text-right text-base font-bold text-foreground", children: [
|
|
2816
2996
|
"Total: ",
|
|
2817
2997
|
total.toFixed(2)
|
|
2818
2998
|
] }) })
|
|
@@ -2820,9 +3000,9 @@ function CashCountInput({
|
|
|
2820
3000
|
}
|
|
2821
3001
|
|
|
2822
3002
|
// src/register/register-summary.tsx
|
|
2823
|
-
import { Text as
|
|
2824
|
-
import { cn as
|
|
2825
|
-
import { jsx as
|
|
3003
|
+
import { Text as Text27, View as View43 } from "react-native";
|
|
3004
|
+
import { cn as cn72 } from "@tallyui/theme";
|
|
3005
|
+
import { jsx as jsx74, jsxs as jsxs33 } from "react/jsx-runtime";
|
|
2826
3006
|
function RegisterSummary({
|
|
2827
3007
|
expectedCash,
|
|
2828
3008
|
actualCash,
|
|
@@ -2833,37 +3013,37 @@ function RegisterSummary({
|
|
|
2833
3013
|
...viewProps
|
|
2834
3014
|
}) {
|
|
2835
3015
|
const discrepancy = actualCash - expectedCash;
|
|
2836
|
-
return /* @__PURE__ */
|
|
3016
|
+
return /* @__PURE__ */ jsxs33(View43, { className: cn72("gap-4 rounded-lg border border-border bg-card p-4", className), ...viewProps, children: [
|
|
2837
3017
|
headerSlot,
|
|
2838
|
-
/* @__PURE__ */
|
|
2839
|
-
/* @__PURE__ */
|
|
2840
|
-
/* @__PURE__ */
|
|
2841
|
-
/* @__PURE__ */
|
|
2842
|
-
/* @__PURE__ */
|
|
3018
|
+
/* @__PURE__ */ jsxs33(View43, { className: "gap-2", children: [
|
|
3019
|
+
/* @__PURE__ */ jsx74(Text27, { className: "text-xs font-semibold text-muted-foreground", children: "Cash Drawer" }),
|
|
3020
|
+
/* @__PURE__ */ jsxs33(View43, { className: "flex-row justify-between", children: [
|
|
3021
|
+
/* @__PURE__ */ jsx74(Text27, { className: "text-sm text-foreground", children: "Expected" }),
|
|
3022
|
+
/* @__PURE__ */ jsx74(Text27, { className: "text-sm text-foreground", children: expectedCash.toFixed(2) })
|
|
2843
3023
|
] }),
|
|
2844
|
-
/* @__PURE__ */
|
|
2845
|
-
/* @__PURE__ */
|
|
2846
|
-
/* @__PURE__ */
|
|
3024
|
+
/* @__PURE__ */ jsxs33(View43, { className: "flex-row justify-between", children: [
|
|
3025
|
+
/* @__PURE__ */ jsx74(Text27, { className: "text-sm text-foreground", children: "Actual" }),
|
|
3026
|
+
/* @__PURE__ */ jsx74(Text27, { className: "text-sm text-foreground", children: actualCash.toFixed(2) })
|
|
2847
3027
|
] }),
|
|
2848
|
-
/* @__PURE__ */
|
|
2849
|
-
/* @__PURE__ */
|
|
2850
|
-
/* @__PURE__ */
|
|
3028
|
+
/* @__PURE__ */ jsxs33(View43, { className: "flex-row justify-between border-t border-border pt-1", children: [
|
|
3029
|
+
/* @__PURE__ */ jsx74(Text27, { className: "text-sm font-semibold text-foreground", children: "Discrepancy" }),
|
|
3030
|
+
/* @__PURE__ */ jsxs33(Text27, { className: cn72("text-sm font-semibold", discrepancy === 0 ? "text-success" : "text-destructive"), children: [
|
|
2851
3031
|
discrepancy >= 0 ? "" : "-",
|
|
2852
3032
|
Math.abs(discrepancy).toFixed(2)
|
|
2853
3033
|
] })
|
|
2854
3034
|
] })
|
|
2855
3035
|
] }),
|
|
2856
|
-
transactions.length > 0 && /* @__PURE__ */
|
|
2857
|
-
/* @__PURE__ */
|
|
2858
|
-
transactions.map((t) => /* @__PURE__ */
|
|
2859
|
-
/* @__PURE__ */
|
|
2860
|
-
/* @__PURE__ */
|
|
2861
|
-
/* @__PURE__ */
|
|
3036
|
+
transactions.length > 0 && /* @__PURE__ */ jsxs33(View43, { className: "gap-2", children: [
|
|
3037
|
+
/* @__PURE__ */ jsx74(Text27, { className: "text-xs font-semibold text-muted-foreground", children: "Transactions" }),
|
|
3038
|
+
transactions.map((t) => /* @__PURE__ */ jsxs33(View43, { className: "flex-row items-center justify-between", children: [
|
|
3039
|
+
/* @__PURE__ */ jsxs33(View43, { className: "gap-0.5", children: [
|
|
3040
|
+
/* @__PURE__ */ jsx74(Text27, { className: "text-sm text-foreground", children: t.method }),
|
|
3041
|
+
/* @__PURE__ */ jsxs33(Text27, { className: "text-xs text-muted-foreground", children: [
|
|
2862
3042
|
t.count,
|
|
2863
3043
|
" transactions"
|
|
2864
3044
|
] })
|
|
2865
3045
|
] }),
|
|
2866
|
-
/* @__PURE__ */
|
|
3046
|
+
/* @__PURE__ */ jsx74(Text27, { className: "text-sm font-semibold text-foreground", children: t.total.toFixed(2) })
|
|
2867
3047
|
] }, t.method))
|
|
2868
3048
|
] }),
|
|
2869
3049
|
footerSlot
|
|
@@ -2871,9 +3051,9 @@ function RegisterSummary({
|
|
|
2871
3051
|
}
|
|
2872
3052
|
|
|
2873
3053
|
// src/register/register-open-close.tsx
|
|
2874
|
-
import { Pressable as
|
|
2875
|
-
import { cn as
|
|
2876
|
-
import { jsx as
|
|
3054
|
+
import { Pressable as Pressable20, Text as Text28, View as View44 } from "react-native";
|
|
3055
|
+
import { cn as cn73 } from "@tallyui/theme";
|
|
3056
|
+
import { jsx as jsx75, jsxs as jsxs34 } from "react/jsx-runtime";
|
|
2877
3057
|
function RegisterOpenClose({
|
|
2878
3058
|
isOpen,
|
|
2879
3059
|
onOpen,
|
|
@@ -2884,67 +3064,67 @@ function RegisterOpenClose({
|
|
|
2884
3064
|
className,
|
|
2885
3065
|
...viewProps
|
|
2886
3066
|
}) {
|
|
2887
|
-
return /* @__PURE__ */
|
|
2888
|
-
/* @__PURE__ */
|
|
2889
|
-
isOpen && expectedBalance != null && /* @__PURE__ */
|
|
2890
|
-
/* @__PURE__ */
|
|
2891
|
-
/* @__PURE__ */
|
|
3067
|
+
return /* @__PURE__ */ jsxs34(View44, { className: cn73("gap-4 p-4", className), ...viewProps, children: [
|
|
3068
|
+
/* @__PURE__ */ jsx75(Text28, { className: "text-lg font-bold text-foreground", children: isOpen ? "Close Register" : "Open Register" }),
|
|
3069
|
+
isOpen && expectedBalance != null && /* @__PURE__ */ jsxs34(View44, { className: "flex-row justify-between rounded-lg bg-muted px-3 py-2", children: [
|
|
3070
|
+
/* @__PURE__ */ jsx75(Text28, { className: "text-sm text-muted-foreground", children: "Expected Balance" }),
|
|
3071
|
+
/* @__PURE__ */ jsx75(Text28, { className: "text-sm font-semibold text-foreground", children: expectedBalance.toFixed(2) })
|
|
2892
3072
|
] }),
|
|
2893
|
-
cashCountSlot && /* @__PURE__ */
|
|
2894
|
-
notesSlot && /* @__PURE__ */
|
|
2895
|
-
/* @__PURE__ */
|
|
2896
|
-
|
|
3073
|
+
cashCountSlot && /* @__PURE__ */ jsx75(View44, { children: cashCountSlot }),
|
|
3074
|
+
notesSlot && /* @__PURE__ */ jsx75(View44, { children: notesSlot }),
|
|
3075
|
+
/* @__PURE__ */ jsx75(
|
|
3076
|
+
Pressable20,
|
|
2897
3077
|
{
|
|
2898
3078
|
onPress: isOpen ? onClose : onOpen,
|
|
2899
3079
|
className: "items-center rounded-lg bg-primary px-4 py-3",
|
|
2900
|
-
children: /* @__PURE__ */
|
|
3080
|
+
children: /* @__PURE__ */ jsx75(Text28, { className: "text-sm font-semibold text-primary-foreground", children: isOpen ? "Close Register" : "Open Register" })
|
|
2901
3081
|
}
|
|
2902
3082
|
)
|
|
2903
3083
|
] });
|
|
2904
3084
|
}
|
|
2905
3085
|
|
|
2906
3086
|
// src/register/register-picker.tsx
|
|
2907
|
-
import { ScrollView as
|
|
2908
|
-
import { jsx as
|
|
3087
|
+
import { ScrollView as ScrollView10 } from "react-native";
|
|
3088
|
+
import { jsx as jsx76, jsxs as jsxs35 } from "react/jsx-runtime";
|
|
2909
3089
|
function RegisterPicker({ registers, onPick, className }) {
|
|
2910
|
-
return /* @__PURE__ */
|
|
2911
|
-
/* @__PURE__ */
|
|
2912
|
-
/* @__PURE__ */
|
|
2913
|
-
registers.map((register) => /* @__PURE__ */
|
|
3090
|
+
return /* @__PURE__ */ jsxs35(Card, { testID: "register-picker", className, children: [
|
|
3091
|
+
/* @__PURE__ */ jsx76(CardHeader, { children: /* @__PURE__ */ jsx76(CardTitle, { children: "Choose a register" }) }),
|
|
3092
|
+
/* @__PURE__ */ jsx76(CardContent, { children: /* @__PURE__ */ jsxs35(ScrollView10, { children: [
|
|
3093
|
+
registers.map((register) => /* @__PURE__ */ jsx76(
|
|
2914
3094
|
Button,
|
|
2915
3095
|
{
|
|
2916
3096
|
testID: `register-picker-row-${register.id}`,
|
|
2917
3097
|
variant: "ghost",
|
|
2918
3098
|
className: "h-auto min-h-11 items-start justify-start py-2",
|
|
2919
3099
|
onPress: () => onPick(register.id),
|
|
2920
|
-
children: /* @__PURE__ */
|
|
2921
|
-
/* @__PURE__ */
|
|
2922
|
-
/* @__PURE__ */
|
|
3100
|
+
children: /* @__PURE__ */ jsxs35(VStack, { space: "none", children: [
|
|
3101
|
+
/* @__PURE__ */ jsx76(Text, { numberOfLines: 1, children: register.name }),
|
|
3102
|
+
/* @__PURE__ */ jsx76(Text, { testID: `register-picker-row-${register.id}-status`, className: "text-muted-foreground text-sm", children: "Not opened" })
|
|
2923
3103
|
] })
|
|
2924
3104
|
},
|
|
2925
3105
|
register.id
|
|
2926
3106
|
)),
|
|
2927
|
-
registers.length === 0 && /* @__PURE__ */
|
|
3107
|
+
registers.length === 0 && /* @__PURE__ */ jsx76(Text, { testID: "register-picker-empty", className: "text-muted-foreground p-4", children: "No registers are set up for this store yet." })
|
|
2928
3108
|
] }) })
|
|
2929
3109
|
] });
|
|
2930
3110
|
}
|
|
2931
3111
|
|
|
2932
3112
|
// src/register/open-register-card.tsx
|
|
2933
|
-
import { useState as
|
|
2934
|
-
import { View as
|
|
3113
|
+
import { useState as useState9 } from "react";
|
|
3114
|
+
import { View as View45 } from "react-native";
|
|
2935
3115
|
import { parseMinor, validAmount } from "@tallyui/pos";
|
|
2936
3116
|
import { currencySymbol, formatMoney as formatMoney6, minorUnitDigits as minorUnitDigits3 } from "@tallyui/core";
|
|
2937
|
-
import { cn as
|
|
2938
|
-
import { jsx as
|
|
3117
|
+
import { cn as cn74 } from "@tallyui/theme";
|
|
3118
|
+
import { jsx as jsx77, jsxs as jsxs36 } from "react/jsx-runtime";
|
|
2939
3119
|
var AMOUNT_LABEL_ID = "open-register-amount-label";
|
|
2940
3120
|
function OpenRegisterCard({ register, currency, configuredFloatMinor, className }) {
|
|
2941
3121
|
const digits = minorUnitDigits3(currency);
|
|
2942
3122
|
const lastCountedMinor = register.lastClosure?.counted?.cash ?? null;
|
|
2943
3123
|
const expectedFloatMinor = configuredFloatMinor ?? lastCountedMinor ?? null;
|
|
2944
|
-
const [enteredAmount, setEnteredAmount] =
|
|
3124
|
+
const [enteredAmount, setEnteredAmount] = useState9(null);
|
|
2945
3125
|
const amount = enteredAmount ?? (expectedFloatMinor != null ? decimal(expectedFloatMinor, digits) : "");
|
|
2946
|
-
const [busy, setBusy] =
|
|
2947
|
-
const [error, setError] =
|
|
3126
|
+
const [busy, setBusy] = useState9(false);
|
|
3127
|
+
const [error, setError] = useState9("");
|
|
2948
3128
|
const valid = validAmount(amount, digits);
|
|
2949
3129
|
const countedMinor = valid ? parseMinor(amount, digits) : NaN;
|
|
2950
3130
|
const open = async () => {
|
|
@@ -2960,10 +3140,10 @@ function OpenRegisterCard({ register, currency, configuredFloatMinor, className
|
|
|
2960
3140
|
}
|
|
2961
3141
|
};
|
|
2962
3142
|
const amountLabel = `Cash in the drawer to start (${currencySymbol(currency)})`;
|
|
2963
|
-
return /* @__PURE__ */
|
|
2964
|
-
/* @__PURE__ */
|
|
2965
|
-
/* @__PURE__ */
|
|
2966
|
-
/* @__PURE__ */
|
|
3143
|
+
return /* @__PURE__ */ jsxs36(View45, { testID: "open-register-card", className: cn74("bg-card gap-3 rounded-md p-4", className), children: [
|
|
3144
|
+
/* @__PURE__ */ jsx77(Text, { className: "text-lg font-semibold", children: "Open register" }),
|
|
3145
|
+
/* @__PURE__ */ jsx77(Label, { testID: "open-register-amount-label", nativeID: AMOUNT_LABEL_ID, children: amountLabel }),
|
|
3146
|
+
/* @__PURE__ */ jsx77(Input, { children: /* @__PURE__ */ jsx77(
|
|
2967
3147
|
Input.Field,
|
|
2968
3148
|
{
|
|
2969
3149
|
testID: "open-register-amount",
|
|
@@ -2974,40 +3154,40 @@ function OpenRegisterCard({ register, currency, configuredFloatMinor, className
|
|
|
2974
3154
|
accessibilityLabelledBy: AMOUNT_LABEL_ID
|
|
2975
3155
|
}
|
|
2976
3156
|
) }),
|
|
2977
|
-
configuredFloatMinor != null && /* @__PURE__ */
|
|
3157
|
+
configuredFloatMinor != null && /* @__PURE__ */ jsx77(
|
|
2978
3158
|
Button,
|
|
2979
3159
|
{
|
|
2980
3160
|
testID: "open-register-chip-configured",
|
|
2981
3161
|
variant: "outline",
|
|
2982
3162
|
className: "min-h-11",
|
|
2983
3163
|
onPress: () => setEnteredAmount(decimal(configuredFloatMinor, digits)),
|
|
2984
|
-
children: /* @__PURE__ */
|
|
3164
|
+
children: /* @__PURE__ */ jsxs36(Text, { children: [
|
|
2985
3165
|
"Use the configured float (",
|
|
2986
3166
|
formatMoney6({ amount: configuredFloatMinor, currency }),
|
|
2987
3167
|
")"
|
|
2988
3168
|
] })
|
|
2989
3169
|
}
|
|
2990
3170
|
),
|
|
2991
|
-
lastCountedMinor != null && /* @__PURE__ */
|
|
3171
|
+
lastCountedMinor != null && /* @__PURE__ */ jsx77(
|
|
2992
3172
|
Button,
|
|
2993
3173
|
{
|
|
2994
3174
|
testID: "open-register-chip-last",
|
|
2995
3175
|
variant: "outline",
|
|
2996
3176
|
className: "min-h-11",
|
|
2997
3177
|
onPress: () => setEnteredAmount(decimal(lastCountedMinor, digits)),
|
|
2998
|
-
children: /* @__PURE__ */
|
|
3178
|
+
children: /* @__PURE__ */ jsxs36(Text, { children: [
|
|
2999
3179
|
"Use the last counted cash (",
|
|
3000
3180
|
formatMoney6({ amount: lastCountedMinor, currency }),
|
|
3001
3181
|
")"
|
|
3002
3182
|
] })
|
|
3003
3183
|
}
|
|
3004
3184
|
),
|
|
3005
|
-
expectedFloatMinor !== null && valid && countedMinor !== expectedFloatMinor && /* @__PURE__ */
|
|
3185
|
+
expectedFloatMinor !== null && valid && countedMinor !== expectedFloatMinor && /* @__PURE__ */ jsxs36(Text, { testID: "opening-variance", children: [
|
|
3006
3186
|
formatMoney6({ amount: countedMinor - expectedFloatMinor, currency }),
|
|
3007
3187
|
" vs the expected float"
|
|
3008
3188
|
] }),
|
|
3009
|
-
!!error && /* @__PURE__ */
|
|
3010
|
-
/* @__PURE__ */
|
|
3189
|
+
!!error && /* @__PURE__ */ jsx77(Text, { className: "text-destructive", children: error }),
|
|
3190
|
+
/* @__PURE__ */ jsx77(Button, { testID: "open-register-button", className: "min-h-14", disabled: busy || !valid, onPress: open, children: /* @__PURE__ */ jsx77(Text, { children: busy ? "Opening\u2026" : "Open register" }) })
|
|
3011
3191
|
] });
|
|
3012
3192
|
}
|
|
3013
3193
|
function decimal(minor, digits) {
|
|
@@ -3016,8 +3196,8 @@ function decimal(minor, digits) {
|
|
|
3016
3196
|
}
|
|
3017
3197
|
|
|
3018
3198
|
// src/register/register-bar.tsx
|
|
3019
|
-
import { Pressable as
|
|
3020
|
-
import { cn as
|
|
3199
|
+
import { Pressable as Pressable21, View as View46 } from "react-native";
|
|
3200
|
+
import { cn as cn75 } from "@tallyui/theme";
|
|
3021
3201
|
|
|
3022
3202
|
// src/register/register-bar.helpers.ts
|
|
3023
3203
|
function describeRegisterBarPill({
|
|
@@ -3040,7 +3220,7 @@ function describeRegisterBarPill({
|
|
|
3040
3220
|
}
|
|
3041
3221
|
|
|
3042
3222
|
// src/register/register-bar.tsx
|
|
3043
|
-
import { jsx as
|
|
3223
|
+
import { jsx as jsx78, jsxs as jsxs37 } from "react/jsx-runtime";
|
|
3044
3224
|
function RegisterBar({
|
|
3045
3225
|
register,
|
|
3046
3226
|
registerId,
|
|
@@ -3061,10 +3241,10 @@ function RegisterBar({
|
|
|
3061
3241
|
sessionsOn: enabled,
|
|
3062
3242
|
closing
|
|
3063
3243
|
});
|
|
3064
|
-
return /* @__PURE__ */
|
|
3065
|
-
/* @__PURE__ */
|
|
3066
|
-
pill && (onPressPill ? /* @__PURE__ */
|
|
3067
|
-
(session || lastClosure) && /* @__PURE__ */
|
|
3244
|
+
return /* @__PURE__ */ jsxs37(HStack, { testID: "register-bar", className: cn75("bg-card border-border h-12 border-b px-3", className), children: [
|
|
3245
|
+
/* @__PURE__ */ jsx78(View46, { className: "min-w-0 flex-1 shrink", children: multiRegister && registerId !== null && /* @__PURE__ */ jsx78(Text, { testID: "register-bar-name", numberOfLines: 1, children: registerName }) }),
|
|
3246
|
+
pill && (onPressPill ? /* @__PURE__ */ jsx78(Pressable21, { testID: "register-bar-pill", accessibilityRole: "button", accessibilityLabel: pill, onPress: onPressPill, children: /* @__PURE__ */ jsx78(Badge, { label: pill, variant: "warning" }) }) : /* @__PURE__ */ jsx78(Badge, { testID: "register-bar-pill", label: pill, variant: "warning" })),
|
|
3247
|
+
(session || lastClosure) && /* @__PURE__ */ jsx78(
|
|
3068
3248
|
Button,
|
|
3069
3249
|
{
|
|
3070
3250
|
variant: "ghost",
|
|
@@ -3072,17 +3252,17 @@ function RegisterBar({
|
|
|
3072
3252
|
testID: "register-bar-open-panel",
|
|
3073
3253
|
accessibilityLabel: "Open register panel",
|
|
3074
3254
|
onPress: onOpenPanel,
|
|
3075
|
-
children: /* @__PURE__ */
|
|
3255
|
+
children: /* @__PURE__ */ jsx78(Text, { className: overdue ? "text-warning" : void 0, children: "Register \u203A" })
|
|
3076
3256
|
}
|
|
3077
3257
|
)
|
|
3078
3258
|
] });
|
|
3079
3259
|
}
|
|
3080
3260
|
|
|
3081
3261
|
// src/register/movement-sheet.tsx
|
|
3082
|
-
import { useRef as
|
|
3262
|
+
import { useRef as useRef3, useState as useState10 } from "react";
|
|
3083
3263
|
import { movementFieldError, normalizeAmount, parseMinor as parseMinor2 } from "@tallyui/pos";
|
|
3084
3264
|
import { currencySymbol as currencySymbol2, minorUnitDigits as minorUnitDigits4 } from "@tallyui/core";
|
|
3085
|
-
import { Fragment as Fragment2, jsx as
|
|
3265
|
+
import { Fragment as Fragment2, jsx as jsx79, jsxs as jsxs38 } from "react/jsx-runtime";
|
|
3086
3266
|
var LABELS = {
|
|
3087
3267
|
paid_in: "Paid in",
|
|
3088
3268
|
paid_out: "Paid out",
|
|
@@ -3092,11 +3272,11 @@ var AMOUNT_LABEL_ID2 = "movement-amount-label";
|
|
|
3092
3272
|
var REASON_LABEL_ID = "movement-reason-label";
|
|
3093
3273
|
function MovementSheet({ register, type, currency, onDone, onOpenChange, onOpenDrawer }) {
|
|
3094
3274
|
const digits = minorUnitDigits4(currency);
|
|
3095
|
-
const [amount, setAmount] =
|
|
3096
|
-
const [reason, setReason] =
|
|
3097
|
-
const [busy, setBusy] =
|
|
3098
|
-
const busyRef =
|
|
3099
|
-
const [error, setError] =
|
|
3275
|
+
const [amount, setAmount] = useState10("");
|
|
3276
|
+
const [reason, setReason] = useState10("");
|
|
3277
|
+
const [busy, setBusy] = useState10(false);
|
|
3278
|
+
const busyRef = useRef3(false);
|
|
3279
|
+
const [error, setError] = useState10("");
|
|
3100
3280
|
const invalid = movementFieldError({ type, amount, reason });
|
|
3101
3281
|
const confirm = async () => {
|
|
3102
3282
|
if (invalid || busyRef.current) return;
|
|
@@ -3118,11 +3298,11 @@ function MovementSheet({ register, type, currency, onDone, onOpenChange, onOpenD
|
|
|
3118
3298
|
setBusy(false);
|
|
3119
3299
|
}
|
|
3120
3300
|
};
|
|
3121
|
-
return /* @__PURE__ */
|
|
3122
|
-
/* @__PURE__ */
|
|
3123
|
-
type !== "no_sale" && /* @__PURE__ */
|
|
3124
|
-
/* @__PURE__ */
|
|
3125
|
-
/* @__PURE__ */
|
|
3301
|
+
return /* @__PURE__ */ jsx79(Dialog, { open: true, onOpenChange, children: /* @__PURE__ */ jsxs38(DialogContent, { testID: "movement-sheet", children: [
|
|
3302
|
+
/* @__PURE__ */ jsx79(DialogTitle, { children: LABELS[type] }),
|
|
3303
|
+
type !== "no_sale" && /* @__PURE__ */ jsxs38(Fragment2, { children: [
|
|
3304
|
+
/* @__PURE__ */ jsx79(Label, { testID: "movement-amount-label", nativeID: AMOUNT_LABEL_ID2, children: `Amount (${currencySymbol2(currency)})` }),
|
|
3305
|
+
/* @__PURE__ */ jsx79(Input, { children: /* @__PURE__ */ jsx79(
|
|
3126
3306
|
Input.Field,
|
|
3127
3307
|
{
|
|
3128
3308
|
testID: "movement-amount",
|
|
@@ -3134,8 +3314,8 @@ function MovementSheet({ register, type, currency, onDone, onOpenChange, onOpenD
|
|
|
3134
3314
|
}
|
|
3135
3315
|
) })
|
|
3136
3316
|
] }),
|
|
3137
|
-
/* @__PURE__ */
|
|
3138
|
-
/* @__PURE__ */
|
|
3317
|
+
/* @__PURE__ */ jsx79(Label, { testID: "movement-reason-label", nativeID: REASON_LABEL_ID, children: "Reason" }),
|
|
3318
|
+
/* @__PURE__ */ jsx79(Input, { children: /* @__PURE__ */ jsx79(
|
|
3139
3319
|
Input.Field,
|
|
3140
3320
|
{
|
|
3141
3321
|
testID: "movement-reason",
|
|
@@ -3146,25 +3326,25 @@ function MovementSheet({ register, type, currency, onDone, onOpenChange, onOpenD
|
|
|
3146
3326
|
accessibilityLabelledBy: REASON_LABEL_ID
|
|
3147
3327
|
}
|
|
3148
3328
|
) }),
|
|
3149
|
-
!!error && /* @__PURE__ */
|
|
3150
|
-
!!invalid && /* @__PURE__ */
|
|
3151
|
-
/* @__PURE__ */
|
|
3329
|
+
!!error && /* @__PURE__ */ jsx79(Text, { className: "text-destructive", children: error }),
|
|
3330
|
+
!!invalid && /* @__PURE__ */ jsx79(Text, { testID: "movement-invalid", className: "text-muted-foreground", children: invalid === "amount" ? "Enter a valid amount." : "Enter a reason." }),
|
|
3331
|
+
/* @__PURE__ */ jsx79(Button, { testID: "movement-confirm", disabled: !!invalid || busy, onPress: confirm, children: /* @__PURE__ */ jsx79(Text, { children: busy ? "Recording\u2026" : "Record" }) })
|
|
3152
3332
|
] }) });
|
|
3153
3333
|
}
|
|
3154
3334
|
|
|
3155
3335
|
// src/register/register-panel.tsx
|
|
3156
|
-
import { useState as
|
|
3157
|
-
import { ScrollView as
|
|
3336
|
+
import { useState as useState11 } from "react";
|
|
3337
|
+
import { ScrollView as ScrollView11, useWindowDimensions, View as View47 } from "react-native";
|
|
3158
3338
|
import { formatMoney as formatMoney7 } from "@tallyui/core";
|
|
3159
|
-
import { jsx as
|
|
3339
|
+
import { jsx as jsx80, jsxs as jsxs39 } from "react/jsx-runtime";
|
|
3160
3340
|
var DIALOG_VERTICAL_MARGIN = 64;
|
|
3161
3341
|
function RegisterPanel({ register, currency, registerName, open, onOpenChange, className }) {
|
|
3162
3342
|
const { session, expected, salesCount, blind, movements, lastClosure, actions } = register;
|
|
3163
3343
|
const { height: windowHeight } = useWindowDimensions();
|
|
3164
3344
|
const maxHeight = Math.max(280, windowHeight - DIALOG_VERTICAL_MARGIN);
|
|
3165
|
-
const [movementType, setMovementType] =
|
|
3166
|
-
const [expanded, setExpanded] =
|
|
3167
|
-
const [error, setError] =
|
|
3345
|
+
const [movementType, setMovementType] = useState11(null);
|
|
3346
|
+
const [expanded, setExpanded] = useState11(false);
|
|
3347
|
+
const [error, setError] = useState11("");
|
|
3168
3348
|
const attempt = async (action) => {
|
|
3169
3349
|
try {
|
|
3170
3350
|
await action();
|
|
@@ -3176,22 +3356,22 @@ function RegisterPanel({ register, currency, registerName, open, onOpenChange, c
|
|
|
3176
3356
|
const activeMovements = movements.filter(
|
|
3177
3357
|
(row) => row.type !== "void" && !row.voided_by && !movements.some((entry) => entry.voids === row.id)
|
|
3178
3358
|
);
|
|
3179
|
-
return /* @__PURE__ */
|
|
3359
|
+
return /* @__PURE__ */ jsx80(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsxs39(
|
|
3180
3360
|
DialogContent,
|
|
3181
3361
|
{
|
|
3182
3362
|
testID: "register-panel",
|
|
3183
3363
|
className: `flex-col overflow-hidden ${className ?? ""}`,
|
|
3184
3364
|
style: { maxHeight },
|
|
3185
3365
|
children: [
|
|
3186
|
-
/* @__PURE__ */
|
|
3187
|
-
/* @__PURE__ */
|
|
3366
|
+
/* @__PURE__ */ jsx80(DialogTitle, { testID: "register-panel-amount", children: registerName ?? "Register" }),
|
|
3367
|
+
/* @__PURE__ */ jsxs39(Text, { testID: "register-panel-sales-count", children: [
|
|
3188
3368
|
salesCount,
|
|
3189
3369
|
" sale",
|
|
3190
3370
|
salesCount === 1 ? "" : "s",
|
|
3191
3371
|
" this session"
|
|
3192
3372
|
] }),
|
|
3193
|
-
/* @__PURE__ */
|
|
3194
|
-
/* @__PURE__ */
|
|
3373
|
+
/* @__PURE__ */ jsxs39(ScrollView11, { testID: "register-panel-body", className: "flex-1", contentContainerClassName: "gap-3", children: [
|
|
3374
|
+
/* @__PURE__ */ jsx80(View47, { className: "flex-row gap-2", children: ["paid_in", "paid_out", "no_sale"].map((type) => /* @__PURE__ */ jsx80(
|
|
3195
3375
|
Button,
|
|
3196
3376
|
{
|
|
3197
3377
|
testID: `register-panel-${type.replace("_", "-")}`,
|
|
@@ -3199,33 +3379,33 @@ function RegisterPanel({ register, currency, registerName, open, onOpenChange, c
|
|
|
3199
3379
|
variant: "outline",
|
|
3200
3380
|
disabled: session?.status !== "open",
|
|
3201
3381
|
onPress: () => setMovementType(type),
|
|
3202
|
-
children: /* @__PURE__ */
|
|
3382
|
+
children: /* @__PURE__ */ jsx80(Text, { children: type === "paid_in" ? "Paid in" : type === "paid_out" ? "Paid out" : "No sale" })
|
|
3203
3383
|
},
|
|
3204
3384
|
type
|
|
3205
3385
|
)) }),
|
|
3206
|
-
!blind && /* @__PURE__ */
|
|
3207
|
-
/* @__PURE__ */
|
|
3208
|
-
Object.entries(expected).map(([method, amount]) => /* @__PURE__ */
|
|
3209
|
-
/* @__PURE__ */
|
|
3210
|
-
/* @__PURE__ */
|
|
3386
|
+
!blind && /* @__PURE__ */ jsxs39(View47, { testID: "register-panel-expected", className: "gap-1", children: [
|
|
3387
|
+
/* @__PURE__ */ jsx80(Text, { className: "text-muted-foreground text-sm font-semibold", children: "Expected in the drawer" }),
|
|
3388
|
+
Object.entries(expected).map(([method, amount]) => /* @__PURE__ */ jsxs39(View47, { className: "min-h-11 flex-row items-center justify-between", children: [
|
|
3389
|
+
/* @__PURE__ */ jsx80(Text, { className: "capitalize", children: method === "cash" ? "Cash" : method }),
|
|
3390
|
+
/* @__PURE__ */ jsx80(Text, { className: "tabular-nums", children: formatMoney7({ amount, currency }) })
|
|
3211
3391
|
] }, method))
|
|
3212
3392
|
] }),
|
|
3213
|
-
/* @__PURE__ */
|
|
3393
|
+
/* @__PURE__ */ jsx80(
|
|
3214
3394
|
Button,
|
|
3215
3395
|
{
|
|
3216
3396
|
testID: "register-panel-movements",
|
|
3217
3397
|
variant: "ghost",
|
|
3218
3398
|
className: "min-h-11",
|
|
3219
3399
|
onPress: () => setExpanded(!expanded),
|
|
3220
|
-
children: /* @__PURE__ */
|
|
3400
|
+
children: /* @__PURE__ */ jsx80(Text, { children: "Paid in / out" })
|
|
3221
3401
|
}
|
|
3222
3402
|
),
|
|
3223
|
-
expanded && activeMovements.map((row) => /* @__PURE__ */
|
|
3224
|
-
/* @__PURE__ */
|
|
3403
|
+
expanded && activeMovements.map((row) => /* @__PURE__ */ jsxs39(View47, { className: "min-h-11 flex-row items-center gap-2", children: [
|
|
3404
|
+
/* @__PURE__ */ jsxs39(Text, { testID: `movement-row-${row.id}`, className: "flex-1", children: [
|
|
3225
3405
|
row.type === "paid_in" ? "Paid in" : row.type === "paid_out" ? "Paid out" : "No sale",
|
|
3226
3406
|
!blind ? ` \xB7 ${formatMoney7({ amount: row.amountMinor, currency })} \xB7 ${row.reason}` : ""
|
|
3227
3407
|
] }),
|
|
3228
|
-
/* @__PURE__ */
|
|
3408
|
+
/* @__PURE__ */ jsx80(
|
|
3229
3409
|
Button,
|
|
3230
3410
|
{
|
|
3231
3411
|
variant: "ghost",
|
|
@@ -3233,12 +3413,12 @@ function RegisterPanel({ register, currency, registerName, open, onOpenChange, c
|
|
|
3233
3413
|
testID: `movement-void-${row.id}`,
|
|
3234
3414
|
disabled: session?.status !== "open",
|
|
3235
3415
|
onPress: () => attempt(() => actions.voidMovement(row.id)),
|
|
3236
|
-
children: /* @__PURE__ */
|
|
3416
|
+
children: /* @__PURE__ */ jsx80(Text, { children: "Undo" })
|
|
3237
3417
|
}
|
|
3238
3418
|
)
|
|
3239
3419
|
] }, row.id)),
|
|
3240
|
-
!!error && /* @__PURE__ */
|
|
3241
|
-
/* @__PURE__ */
|
|
3420
|
+
!!error && /* @__PURE__ */ jsx80(Text, { className: "text-destructive", children: error }),
|
|
3421
|
+
/* @__PURE__ */ jsx80(
|
|
3242
3422
|
Button,
|
|
3243
3423
|
{
|
|
3244
3424
|
testID: "register-panel-close",
|
|
@@ -3249,11 +3429,11 @@ function RegisterPanel({ register, currency, registerName, open, onOpenChange, c
|
|
|
3249
3429
|
await actions.startCounting();
|
|
3250
3430
|
onOpenChange(false);
|
|
3251
3431
|
}),
|
|
3252
|
-
children: /* @__PURE__ */
|
|
3432
|
+
children: /* @__PURE__ */ jsx80(Text, { children: "Close register" })
|
|
3253
3433
|
}
|
|
3254
3434
|
)
|
|
3255
3435
|
] }),
|
|
3256
|
-
movementType && /* @__PURE__ */
|
|
3436
|
+
movementType && /* @__PURE__ */ jsx80(
|
|
3257
3437
|
MovementSheet,
|
|
3258
3438
|
{
|
|
3259
3439
|
register,
|
|
@@ -3271,9 +3451,9 @@ function RegisterPanel({ register, currency, registerName, open, onOpenChange, c
|
|
|
3271
3451
|
}
|
|
3272
3452
|
|
|
3273
3453
|
// src/register/register-column.tsx
|
|
3274
|
-
import { useState as
|
|
3275
|
-
import { View as
|
|
3276
|
-
import { Fragment as Fragment3, jsx as
|
|
3454
|
+
import { useState as useState12 } from "react";
|
|
3455
|
+
import { View as View48 } from "react-native";
|
|
3456
|
+
import { Fragment as Fragment3, jsx as jsx81, jsxs as jsxs40 } from "react/jsx-runtime";
|
|
3277
3457
|
function RegisterColumn({
|
|
3278
3458
|
register,
|
|
3279
3459
|
registerId,
|
|
@@ -3285,30 +3465,30 @@ function RegisterColumn({
|
|
|
3285
3465
|
cartEmpty,
|
|
3286
3466
|
children
|
|
3287
3467
|
}) {
|
|
3288
|
-
const [finishing, setFinishing] =
|
|
3468
|
+
const [finishing, setFinishing] = useState12(false);
|
|
3289
3469
|
if (registerId === null) {
|
|
3290
|
-
return /* @__PURE__ */
|
|
3470
|
+
return /* @__PURE__ */ jsx81(RegisterPicker, { registers, onPick, className: "flex-1" });
|
|
3291
3471
|
}
|
|
3292
3472
|
if (register.session?.status === "closed") {
|
|
3293
|
-
return register.closing && !finishing ? /* @__PURE__ */
|
|
3473
|
+
return register.closing && !finishing ? /* @__PURE__ */ jsx81(Fragment3, { children: countSlot }) : /* @__PURE__ */ jsx81(FinishClose, { register, busy: finishing, setBusy: setFinishing });
|
|
3294
3474
|
}
|
|
3295
3475
|
if (!register.session) {
|
|
3296
|
-
return /* @__PURE__ */
|
|
3476
|
+
return /* @__PURE__ */ jsx81(OpenRegisterCard, { register, currency, configuredFloatMinor, className: "flex-1" });
|
|
3297
3477
|
}
|
|
3298
3478
|
if (register.session.status === "counting") {
|
|
3299
|
-
return /* @__PURE__ */
|
|
3479
|
+
return /* @__PURE__ */ jsx81(Fragment3, { children: countSlot });
|
|
3300
3480
|
}
|
|
3301
|
-
return /* @__PURE__ */
|
|
3302
|
-
register.overdue && cartEmpty && /* @__PURE__ */
|
|
3303
|
-
/* @__PURE__ */
|
|
3304
|
-
/* @__PURE__ */
|
|
3481
|
+
return /* @__PURE__ */ jsxs40(View48, { testID: "register-column", className: "flex-1", children: [
|
|
3482
|
+
register.overdue && cartEmpty && /* @__PURE__ */ jsxs40(View48, { testID: "register-column-overdue", className: "bg-warning/10 flex-row items-center justify-between gap-2 px-3 py-2", children: [
|
|
3483
|
+
/* @__PURE__ */ jsx81(Text, { className: "flex-1", children: "This register is overdue for closing." }),
|
|
3484
|
+
/* @__PURE__ */ jsx81(
|
|
3305
3485
|
Button,
|
|
3306
3486
|
{
|
|
3307
3487
|
testID: "register-column-close-overdue",
|
|
3308
3488
|
variant: "outline",
|
|
3309
3489
|
className: "min-h-11",
|
|
3310
3490
|
onPress: () => register.actions.startCounting(),
|
|
3311
|
-
children: /* @__PURE__ */
|
|
3491
|
+
children: /* @__PURE__ */ jsx81(Text, { children: "Close register" })
|
|
3312
3492
|
}
|
|
3313
3493
|
)
|
|
3314
3494
|
] }),
|
|
@@ -3316,7 +3496,7 @@ function RegisterColumn({
|
|
|
3316
3496
|
] });
|
|
3317
3497
|
}
|
|
3318
3498
|
function FinishClose({ register, busy, setBusy }) {
|
|
3319
|
-
const [error, setError] =
|
|
3499
|
+
const [error, setError] = useState12("");
|
|
3320
3500
|
const finish = async () => {
|
|
3321
3501
|
setBusy(true);
|
|
3322
3502
|
setError("");
|
|
@@ -3328,16 +3508,16 @@ function FinishClose({ register, busy, setBusy }) {
|
|
|
3328
3508
|
setBusy(false);
|
|
3329
3509
|
}
|
|
3330
3510
|
};
|
|
3331
|
-
return /* @__PURE__ */
|
|
3332
|
-
/* @__PURE__ */
|
|
3333
|
-
/* @__PURE__ */
|
|
3334
|
-
!!error && /* @__PURE__ */
|
|
3511
|
+
return /* @__PURE__ */ jsxs40(View48, { testID: "register-column-finish-close", className: "flex-1 gap-3 p-4", children: [
|
|
3512
|
+
/* @__PURE__ */ jsx81(Text, { children: "The last close didn't finish." }),
|
|
3513
|
+
/* @__PURE__ */ jsx81(Button, { testID: "register-column-finish-close-button", nativeID: "register-column-finish-close-button", disabled: busy, onPress: finish, children: /* @__PURE__ */ jsx81(Text, { children: "Finish closing" }) }),
|
|
3514
|
+
!!error && /* @__PURE__ */ jsx81(Text, { testID: "register-column-finish-close-error", className: "text-destructive", children: error })
|
|
3335
3515
|
] });
|
|
3336
3516
|
}
|
|
3337
3517
|
|
|
3338
3518
|
// src/register/register-count.tsx
|
|
3339
|
-
import { useEffect as
|
|
3340
|
-
import { Platform, Pressable as
|
|
3519
|
+
import { useEffect as useEffect3, useRef as useRef4, useState as useState13 } from "react";
|
|
3520
|
+
import { Platform, Pressable as Pressable22, ScrollView as ScrollView12, useWindowDimensions as useWindowDimensions2, View as View49 } from "react-native";
|
|
3341
3521
|
import {
|
|
3342
3522
|
closeNeedsApproval,
|
|
3343
3523
|
countVariance,
|
|
@@ -3349,8 +3529,8 @@ import {
|
|
|
3349
3529
|
varianceText
|
|
3350
3530
|
} from "@tallyui/pos";
|
|
3351
3531
|
import { currencySymbol as currencySymbol3, formatMoney as formatMoney8, minorUnitDigits as minorUnitDigits5 } from "@tallyui/core";
|
|
3352
|
-
import { cn as
|
|
3353
|
-
import { jsx as
|
|
3532
|
+
import { cn as cn76 } from "@tallyui/theme";
|
|
3533
|
+
import { jsx as jsx82, jsxs as jsxs41 } from "react/jsx-runtime";
|
|
3354
3534
|
var AMOUNT_LABEL_ID3 = "count-amount-label";
|
|
3355
3535
|
var APPROVAL_REQUIRED_TEXT = "Manager approval needed. Ask a manager to approve, or count again.";
|
|
3356
3536
|
function varianceWord(key) {
|
|
@@ -3372,17 +3552,17 @@ function tileLabel(value, currency) {
|
|
|
3372
3552
|
return formatter.format(value / 10 ** minorUnitDigits5(currency));
|
|
3373
3553
|
}
|
|
3374
3554
|
var tenderLabel = (method) => method.charAt(0).toUpperCase() + method.slice(1);
|
|
3375
|
-
function DenominationTile({ value, count, currency, onAdd }) {
|
|
3555
|
+
function DenominationTile({ value, count: count2, currency, onAdd }) {
|
|
3376
3556
|
const label = tileLabel(value, currency);
|
|
3377
|
-
const held =
|
|
3378
|
-
const timer =
|
|
3557
|
+
const held = useRef4(false);
|
|
3558
|
+
const timer = useRef4(void 0);
|
|
3379
3559
|
const stop = () => {
|
|
3380
3560
|
if (timer.current !== void 0) clearInterval(timer.current);
|
|
3381
3561
|
timer.current = void 0;
|
|
3382
3562
|
};
|
|
3383
|
-
|
|
3384
|
-
return /* @__PURE__ */
|
|
3385
|
-
|
|
3563
|
+
useEffect3(() => stop, []);
|
|
3564
|
+
return /* @__PURE__ */ jsxs41(
|
|
3565
|
+
Pressable22,
|
|
3386
3566
|
{
|
|
3387
3567
|
testID: `den-tile-${value}`,
|
|
3388
3568
|
accessibilityRole: "button",
|
|
@@ -3403,8 +3583,8 @@ function DenominationTile({ value, count, currency, onAdd }) {
|
|
|
3403
3583
|
if (!held.current) onAdd(1);
|
|
3404
3584
|
},
|
|
3405
3585
|
children: [
|
|
3406
|
-
/* @__PURE__ */
|
|
3407
|
-
/* @__PURE__ */
|
|
3586
|
+
/* @__PURE__ */ jsx82(Text, { className: "text-sm tabular-nums", numberOfLines: 1, children: label }),
|
|
3587
|
+
/* @__PURE__ */ jsx82(Text, { testID: `den-count-${value}`, className: "bg-background min-w-6 rounded-full px-1.5 text-center text-xs tabular-nums", children: count2 })
|
|
3408
3588
|
]
|
|
3409
3589
|
}
|
|
3410
3590
|
);
|
|
@@ -3415,18 +3595,18 @@ function RegisterCount({ register, currency, approve, className }) {
|
|
|
3415
3595
|
const faces = denominations[currency] ?? denominations.default;
|
|
3416
3596
|
const { width } = useWindowDimensions2();
|
|
3417
3597
|
const columns = width < 480 ? 3 : 4;
|
|
3418
|
-
const [pieces, setPieces] =
|
|
3419
|
-
const [cashText, setCashText] =
|
|
3598
|
+
const [pieces, setPieces] = useState13({});
|
|
3599
|
+
const [cashText, setCashText] = useState13(
|
|
3420
3600
|
() => session?.counted?.cash != null ? minorToDecimal(session.counted.cash, digits) : ""
|
|
3421
3601
|
);
|
|
3422
|
-
const [others, setOthers] =
|
|
3602
|
+
const [others, setOthers] = useState13(
|
|
3423
3603
|
() => Object.fromEntries(
|
|
3424
3604
|
Object.entries(session?.counted ?? {}).filter(([method]) => method !== "cash").map(([method, minor]) => [method, minorToDecimal(minor, digits)])
|
|
3425
3605
|
)
|
|
3426
3606
|
);
|
|
3427
|
-
const [busy, setBusy] =
|
|
3428
|
-
const [error, setError] =
|
|
3429
|
-
const [refusal, setRefusal] =
|
|
3607
|
+
const [busy, setBusy] = useState13(false);
|
|
3608
|
+
const [error, setError] = useState13("");
|
|
3609
|
+
const [refusal, setRefusal] = useState13("");
|
|
3430
3610
|
const usingTiles = Object.keys(pieces).length > 0;
|
|
3431
3611
|
const tilesTotal = denominationTotal(pieces);
|
|
3432
3612
|
const displayAmount = usingTiles ? minorToDecimal(tilesTotal, digits) : cashText;
|
|
@@ -3474,11 +3654,11 @@ function RegisterCount({ register, currency, approve, className }) {
|
|
|
3474
3654
|
void attempt(() => actions.closeSession({ counted }));
|
|
3475
3655
|
};
|
|
3476
3656
|
if (!session) return null;
|
|
3477
|
-
return /* @__PURE__ */
|
|
3478
|
-
/* @__PURE__ */
|
|
3479
|
-
/* @__PURE__ */
|
|
3480
|
-
/* @__PURE__ */
|
|
3481
|
-
/* @__PURE__ */
|
|
3657
|
+
return /* @__PURE__ */ jsxs41(View49, { testID: "register-count", className: cn76("bg-card flex-1 rounded-md", className), children: [
|
|
3658
|
+
/* @__PURE__ */ jsxs41(ScrollView12, { className: "flex-1", contentContainerClassName: "gap-3 p-4", children: [
|
|
3659
|
+
/* @__PURE__ */ jsx82(Text, { className: "min-h-11 text-lg font-semibold", children: "Count the drawer" }),
|
|
3660
|
+
/* @__PURE__ */ jsx82(Label, { testID: "count-amount-label", nativeID: AMOUNT_LABEL_ID3, children: `Cash counted (${currencySymbol3(currency)})` }),
|
|
3661
|
+
/* @__PURE__ */ jsx82(Input, { children: /* @__PURE__ */ jsx82(
|
|
3482
3662
|
Input.Field,
|
|
3483
3663
|
{
|
|
3484
3664
|
testID: "count-amount",
|
|
@@ -3492,16 +3672,16 @@ function RegisterCount({ register, currency, approve, className }) {
|
|
|
3492
3672
|
accessibilityLabelledBy: AMOUNT_LABEL_ID3
|
|
3493
3673
|
}
|
|
3494
3674
|
) }),
|
|
3495
|
-
!blind && valid && /* @__PURE__ */
|
|
3675
|
+
!blind && valid && /* @__PURE__ */ jsx82(Text, { testID: "count-variance", className: "min-h-11 tabular-nums", children: `Expected ${formatMoney8({ amount: expected.cash ?? 0, currency })} \xB7 ${varianceText(
|
|
3496
3676
|
variance,
|
|
3497
3677
|
digits,
|
|
3498
3678
|
(major) => formatMoney8({ amount: Math.round(major * 10 ** digits), currency }) ?? "",
|
|
3499
3679
|
varianceWord
|
|
3500
3680
|
)}` }),
|
|
3501
|
-
/* @__PURE__ */
|
|
3502
|
-
Array.from({ length: Math.ceil(faces.length / columns) }, (_, row) => /* @__PURE__ */
|
|
3681
|
+
/* @__PURE__ */ jsxs41(View49, { testID: "count-denominations", className: "gap-2", children: [
|
|
3682
|
+
Array.from({ length: Math.ceil(faces.length / columns) }, (_, row) => /* @__PURE__ */ jsx82(View49, { className: "flex-row gap-2", children: Array.from({ length: columns }, (_2, column) => {
|
|
3503
3683
|
const value = faces[row * columns + column];
|
|
3504
|
-
return value ? /* @__PURE__ */
|
|
3684
|
+
return value ? /* @__PURE__ */ jsx82(
|
|
3505
3685
|
DenominationTile,
|
|
3506
3686
|
{
|
|
3507
3687
|
value,
|
|
@@ -3510,9 +3690,9 @@ function RegisterCount({ register, currency, approve, className }) {
|
|
|
3510
3690
|
onAdd: (n) => addPieces(value, n)
|
|
3511
3691
|
},
|
|
3512
3692
|
value
|
|
3513
|
-
) : /* @__PURE__ */
|
|
3693
|
+
) : /* @__PURE__ */ jsx82(View49, { className: "flex-1" }, column);
|
|
3514
3694
|
}) }, row)),
|
|
3515
|
-
/* @__PURE__ */
|
|
3695
|
+
/* @__PURE__ */ jsx82(
|
|
3516
3696
|
Button,
|
|
3517
3697
|
{
|
|
3518
3698
|
testID: "count-clear",
|
|
@@ -3522,16 +3702,16 @@ function RegisterCount({ register, currency, approve, className }) {
|
|
|
3522
3702
|
setPieces({});
|
|
3523
3703
|
setCashText(minorToDecimal(0, digits));
|
|
3524
3704
|
},
|
|
3525
|
-
children: /* @__PURE__ */
|
|
3705
|
+
children: /* @__PURE__ */ jsx82(Text, { children: "Clear" })
|
|
3526
3706
|
}
|
|
3527
3707
|
)
|
|
3528
3708
|
] }),
|
|
3529
3709
|
otherMethods.map((method) => {
|
|
3530
3710
|
const labelId = `count-tender-${method}-label`;
|
|
3531
3711
|
const label = `${tenderLabel(method)} counted (${currencySymbol3(currency)})`;
|
|
3532
|
-
return /* @__PURE__ */
|
|
3533
|
-
/* @__PURE__ */
|
|
3534
|
-
/* @__PURE__ */
|
|
3712
|
+
return /* @__PURE__ */ jsxs41(View49, { className: "gap-2", children: [
|
|
3713
|
+
/* @__PURE__ */ jsx82(Label, { testID: labelId, nativeID: labelId, children: label }),
|
|
3714
|
+
/* @__PURE__ */ jsx82(Input, { children: /* @__PURE__ */ jsx82(
|
|
3535
3715
|
Input.Field,
|
|
3536
3716
|
{
|
|
3537
3717
|
testID: `count-tender-${method}`,
|
|
@@ -3544,11 +3724,11 @@ function RegisterCount({ register, currency, approve, className }) {
|
|
|
3544
3724
|
) })
|
|
3545
3725
|
] }, method);
|
|
3546
3726
|
}),
|
|
3547
|
-
!!refusal && /* @__PURE__ */
|
|
3548
|
-
!!error && /* @__PURE__ */
|
|
3727
|
+
!!refusal && /* @__PURE__ */ jsx82(Text, { testID: "count-manager-line", className: "text-warning min-h-11", children: refusal }),
|
|
3728
|
+
!!error && /* @__PURE__ */ jsx82(Text, { testID: "count-error", className: "text-destructive min-h-11", children: error })
|
|
3549
3729
|
] }),
|
|
3550
|
-
/* @__PURE__ */
|
|
3551
|
-
/* @__PURE__ */
|
|
3730
|
+
/* @__PURE__ */ jsxs41(View49, { className: "gap-2 border-t border-border p-4", children: [
|
|
3731
|
+
/* @__PURE__ */ jsx82(
|
|
3552
3732
|
Button,
|
|
3553
3733
|
{
|
|
3554
3734
|
testID: "count-back",
|
|
@@ -3556,17 +3736,17 @@ function RegisterCount({ register, currency, approve, className }) {
|
|
|
3556
3736
|
className: "min-h-11",
|
|
3557
3737
|
disabled: busy,
|
|
3558
3738
|
onPress: () => attempt(actions.backToSelling),
|
|
3559
|
-
children: /* @__PURE__ */
|
|
3739
|
+
children: /* @__PURE__ */ jsx82(Text, { children: "Back to selling" })
|
|
3560
3740
|
}
|
|
3561
3741
|
),
|
|
3562
|
-
/* @__PURE__ */
|
|
3742
|
+
/* @__PURE__ */ jsx82(
|
|
3563
3743
|
Button,
|
|
3564
3744
|
{
|
|
3565
3745
|
testID: "count-close",
|
|
3566
3746
|
className: "min-h-14",
|
|
3567
3747
|
disabled: !valid || otherTendersInvalid || busy,
|
|
3568
3748
|
onPress: onClose,
|
|
3569
|
-
children: /* @__PURE__ */
|
|
3749
|
+
children: /* @__PURE__ */ jsx82(Text, { children: busy ? "Closing\u2026" : "Close register" })
|
|
3570
3750
|
}
|
|
3571
3751
|
)
|
|
3572
3752
|
] })
|
|
@@ -3574,15 +3754,15 @@ function RegisterCount({ register, currency, approve, className }) {
|
|
|
3574
3754
|
}
|
|
3575
3755
|
|
|
3576
3756
|
// src/register/closure-sheet.tsx
|
|
3577
|
-
import { useEffect as
|
|
3578
|
-
import { AccessibilityInfo, Animated, View as
|
|
3579
|
-
import { countVariance as countVariance2, varianceText as varianceText2 } from "@tallyui/pos";
|
|
3757
|
+
import { useEffect as useEffect4, useRef as useRef5, useState as useState14 } from "react";
|
|
3758
|
+
import { AccessibilityInfo, Animated, View as View50 } from "react-native";
|
|
3759
|
+
import { countVariance as countVariance2, TAX_ROUNDING_MIXED_NOTE, varianceText as varianceText2 } from "@tallyui/pos";
|
|
3580
3760
|
import { formatMoney as formatMoney9, minorUnitDigits as minorUnitDigits6 } from "@tallyui/core";
|
|
3581
|
-
import { jsx as
|
|
3761
|
+
import { jsx as jsx83, jsxs as jsxs42 } from "react/jsx-runtime";
|
|
3582
3762
|
function useCompletionMotion() {
|
|
3583
|
-
const opacity =
|
|
3584
|
-
const scale =
|
|
3585
|
-
|
|
3763
|
+
const opacity = useRef5(new Animated.Value(0)).current;
|
|
3764
|
+
const scale = useRef5(new Animated.Value(0.6)).current;
|
|
3765
|
+
useEffect4(() => {
|
|
3586
3766
|
let cancelled = false;
|
|
3587
3767
|
AccessibilityInfo.isReduceMotionEnabled().then((reduced) => {
|
|
3588
3768
|
if (cancelled) return;
|
|
@@ -3606,8 +3786,8 @@ function ClosureSheet({ register, currency, onPrint, onDone }) {
|
|
|
3606
3786
|
const { lastClosure: closure, blind } = register;
|
|
3607
3787
|
const digits = minorUnitDigits6(currency);
|
|
3608
3788
|
const { opacity, scale } = useCompletionMotion();
|
|
3609
|
-
const [busy, setBusy] =
|
|
3610
|
-
const [error, setError] =
|
|
3789
|
+
const [busy, setBusy] = useState14(false);
|
|
3790
|
+
const [error, setError] = useState14("");
|
|
3611
3791
|
if (!closure) return null;
|
|
3612
3792
|
const methods = Object.keys(closure.counted);
|
|
3613
3793
|
const approvedByName = closure.breakdowns.approved_by_name;
|
|
@@ -3625,34 +3805,34 @@ function ClosureSheet({ register, currency, onPrint, onDone }) {
|
|
|
3625
3805
|
setBusy(false);
|
|
3626
3806
|
}
|
|
3627
3807
|
};
|
|
3628
|
-
return /* @__PURE__ */
|
|
3808
|
+
return /* @__PURE__ */ jsx83(
|
|
3629
3809
|
Dialog,
|
|
3630
3810
|
{
|
|
3631
3811
|
open: true,
|
|
3632
3812
|
onOpenChange: (open) => {
|
|
3633
3813
|
if (!open) onDone();
|
|
3634
3814
|
},
|
|
3635
|
-
children: /* @__PURE__ */
|
|
3636
|
-
/* @__PURE__ */
|
|
3815
|
+
children: /* @__PURE__ */ jsxs42(DialogContent, { testID: "closure-sheet", children: [
|
|
3816
|
+
/* @__PURE__ */ jsx83(
|
|
3637
3817
|
Animated.View,
|
|
3638
3818
|
{
|
|
3639
3819
|
testID: "closure-check",
|
|
3640
3820
|
style: { opacity, transform: [{ scale }] },
|
|
3641
3821
|
className: "bg-success/10 h-10 w-10 items-center justify-center rounded-full",
|
|
3642
|
-
children: /* @__PURE__ */
|
|
3822
|
+
children: /* @__PURE__ */ jsx83(Text, { className: "text-success text-lg font-bold", accessibilityElementsHidden: true, importantForAccessibility: "no-hide-descendants", children: "\u2713" })
|
|
3643
3823
|
}
|
|
3644
3824
|
),
|
|
3645
|
-
/* @__PURE__ */
|
|
3646
|
-
/* @__PURE__ */
|
|
3647
|
-
!blind && /* @__PURE__ */
|
|
3825
|
+
/* @__PURE__ */ jsx83(DialogTitle, { testID: "closure-title", children: "Register closed" }),
|
|
3826
|
+
/* @__PURE__ */ jsx83(Text, { testID: "closure-number", className: "text-muted-foreground min-h-11", children: `Closure #${closure.number}` }),
|
|
3827
|
+
!blind && /* @__PURE__ */ jsx83(View50, { testID: "closure-figures", className: "gap-3", children: methods.map((method) => {
|
|
3648
3828
|
const countedMinor = closure.counted[method] ?? 0;
|
|
3649
3829
|
const expectedMinor = closure.expected[method] ?? 0;
|
|
3650
3830
|
const varianceMinor = closure.variance[method] ?? countVariance2(countedMinor, expectedMinor);
|
|
3651
|
-
return /* @__PURE__ */
|
|
3652
|
-
/* @__PURE__ */
|
|
3653
|
-
/* @__PURE__ */
|
|
3654
|
-
/* @__PURE__ */
|
|
3655
|
-
/* @__PURE__ */
|
|
3831
|
+
return /* @__PURE__ */ jsxs42(View50, { className: "gap-1", children: [
|
|
3832
|
+
/* @__PURE__ */ jsx83(Text, { className: "text-muted-foreground text-xs font-semibold", children: tenderLabel(method) }),
|
|
3833
|
+
/* @__PURE__ */ jsx83(Text, { testID: `closure-counted-${method}`, className: "min-h-11 tabular-nums", children: `Counted ${formatMoney9({ amount: countedMinor, currency })}` }),
|
|
3834
|
+
/* @__PURE__ */ jsx83(Text, { testID: `closure-expected-${method}`, className: "min-h-11 tabular-nums", children: `Expected ${formatMoney9({ amount: expectedMinor, currency })}` }),
|
|
3835
|
+
/* @__PURE__ */ jsx83(Text, { testID: `closure-variance-${method}`, className: "min-h-11 tabular-nums", children: varianceText2(
|
|
3656
3836
|
varianceMinor,
|
|
3657
3837
|
digits,
|
|
3658
3838
|
(major) => formatMoney9({ amount: Math.round(major * 10 ** digits), currency }) ?? "",
|
|
@@ -3660,52 +3840,53 @@ function ClosureSheet({ register, currency, onPrint, onDone }) {
|
|
|
3660
3840
|
) })
|
|
3661
3841
|
] }, method);
|
|
3662
3842
|
}) }),
|
|
3663
|
-
!!approvedBy && /* @__PURE__ */
|
|
3843
|
+
!!approvedBy && /* @__PURE__ */ jsxs42(Text, { testID: "closure-approved-by", children: [
|
|
3664
3844
|
"Approved by ",
|
|
3665
3845
|
approvedBy
|
|
3666
3846
|
] }),
|
|
3667
|
-
|
|
3668
|
-
|
|
3669
|
-
/* @__PURE__ */
|
|
3847
|
+
closure.breakdowns.tax_rounding_mixed === true && /* @__PURE__ */ jsx83(Text, { testID: "closure-tax-rounding-mixed", className: "text-muted-foreground", children: TAX_ROUNDING_MIXED_NOTE }),
|
|
3848
|
+
!!error && /* @__PURE__ */ jsx83(Text, { testID: "closure-print-error", className: "text-destructive", children: error }),
|
|
3849
|
+
!blind && !!onPrint && /* @__PURE__ */ jsx83(Button, { testID: "closure-print", className: "min-h-14", disabled: busy, onPress: print, children: /* @__PURE__ */ jsx83(Text, { children: busy ? "Printing\u2026" : "Print the Z report" }) }),
|
|
3850
|
+
/* @__PURE__ */ jsx83(Button, { testID: "closure-done", variant: "outline", className: "min-h-14", onPress: onDone, children: /* @__PURE__ */ jsx83(Text, { children: "Done" }) })
|
|
3670
3851
|
] })
|
|
3671
3852
|
}
|
|
3672
3853
|
);
|
|
3673
3854
|
}
|
|
3674
3855
|
|
|
3675
3856
|
// src/settings/settings-row.tsx
|
|
3676
|
-
import { Text as
|
|
3677
|
-
import { cn as
|
|
3678
|
-
import { jsx as
|
|
3857
|
+
import { Text as Text29, View as View51 } from "react-native";
|
|
3858
|
+
import { cn as cn77 } from "@tallyui/theme";
|
|
3859
|
+
import { jsx as jsx84, jsxs as jsxs43 } from "react/jsx-runtime";
|
|
3679
3860
|
function SettingsRow({ label, description, action, className, ...viewProps }) {
|
|
3680
|
-
return /* @__PURE__ */
|
|
3681
|
-
/* @__PURE__ */
|
|
3682
|
-
/* @__PURE__ */
|
|
3683
|
-
description && /* @__PURE__ */
|
|
3861
|
+
return /* @__PURE__ */ jsxs43(View51, { className: cn77("flex-row items-center gap-3 px-4 py-3", className), ...viewProps, children: [
|
|
3862
|
+
/* @__PURE__ */ jsxs43(View51, { className: "flex-1 gap-0.5", children: [
|
|
3863
|
+
/* @__PURE__ */ jsx84(Text29, { className: "text-sm font-medium text-foreground", children: label }),
|
|
3864
|
+
description && /* @__PURE__ */ jsx84(Text29, { className: "text-xs text-muted-foreground", children: description })
|
|
3684
3865
|
] }),
|
|
3685
|
-
action && /* @__PURE__ */
|
|
3866
|
+
action && /* @__PURE__ */ jsx84(View51, { children: action })
|
|
3686
3867
|
] });
|
|
3687
3868
|
}
|
|
3688
3869
|
|
|
3689
3870
|
// src/settings/settings-group.tsx
|
|
3690
|
-
import { Text as
|
|
3691
|
-
import { cn as
|
|
3692
|
-
import { jsx as
|
|
3871
|
+
import { Text as Text30, View as View52 } from "react-native";
|
|
3872
|
+
import { cn as cn78 } from "@tallyui/theme";
|
|
3873
|
+
import { jsx as jsx85, jsxs as jsxs44 } from "react/jsx-runtime";
|
|
3693
3874
|
function SettingsGroup({ title, description, children, className, ...viewProps }) {
|
|
3694
|
-
return /* @__PURE__ */
|
|
3695
|
-
/* @__PURE__ */
|
|
3696
|
-
/* @__PURE__ */
|
|
3697
|
-
description && /* @__PURE__ */
|
|
3875
|
+
return /* @__PURE__ */ jsxs44(View52, { className: cn78("gap-1", className), ...viewProps, children: [
|
|
3876
|
+
/* @__PURE__ */ jsxs44(View52, { className: "px-4 py-2", children: [
|
|
3877
|
+
/* @__PURE__ */ jsx85(Text30, { className: "text-sm font-semibold text-foreground", children: title }),
|
|
3878
|
+
description && /* @__PURE__ */ jsx85(Text30, { className: "text-xs text-muted-foreground", children: description })
|
|
3698
3879
|
] }),
|
|
3699
|
-
/* @__PURE__ */
|
|
3880
|
+
/* @__PURE__ */ jsx85(View52, { className: "rounded-lg border border-border bg-card", children })
|
|
3700
3881
|
] });
|
|
3701
3882
|
}
|
|
3702
3883
|
|
|
3703
3884
|
// src/settings/connector-status.tsx
|
|
3704
|
-
import { Text as
|
|
3705
|
-
import { cn as
|
|
3706
|
-
import { jsx as
|
|
3707
|
-
function defaultFormatUnsold(
|
|
3708
|
-
return `${
|
|
3885
|
+
import { Text as Text31, View as View53 } from "react-native";
|
|
3886
|
+
import { cn as cn79 } from "@tallyui/theme";
|
|
3887
|
+
import { jsx as jsx86, jsxs as jsxs45 } from "react/jsx-runtime";
|
|
3888
|
+
function defaultFormatUnsold(count2, stale) {
|
|
3889
|
+
return `${count2} ${count2 === 1 ? "product" : "products"} not sold in this channel${stale ? " (last check failed)" : ""}`;
|
|
3709
3890
|
}
|
|
3710
3891
|
var STATUS_CONFIG2 = {
|
|
3711
3892
|
connected: { label: "Connected", dot: "bg-success", text: "text-success" },
|
|
@@ -3725,33 +3906,33 @@ function ConnectorStatus({
|
|
|
3725
3906
|
...viewProps
|
|
3726
3907
|
}) {
|
|
3727
3908
|
const config = STATUS_CONFIG2[status];
|
|
3728
|
-
return /* @__PURE__ */
|
|
3729
|
-
/* @__PURE__ */
|
|
3730
|
-
/* @__PURE__ */
|
|
3731
|
-
/* @__PURE__ */
|
|
3732
|
-
/* @__PURE__ */
|
|
3733
|
-
/* @__PURE__ */
|
|
3909
|
+
return /* @__PURE__ */ jsxs45(View53, { className: cn79("gap-2 rounded-lg border border-border bg-card p-3", className), ...viewProps, children: [
|
|
3910
|
+
/* @__PURE__ */ jsxs45(View53, { className: "flex-row items-center justify-between", children: [
|
|
3911
|
+
/* @__PURE__ */ jsx86(Text31, { className: "text-sm font-semibold text-foreground", children: name }),
|
|
3912
|
+
/* @__PURE__ */ jsxs45(View53, { className: "flex-row items-center gap-1.5", children: [
|
|
3913
|
+
/* @__PURE__ */ jsx86(View53, { className: cn79("h-2 w-2 rounded-full", config.dot) }),
|
|
3914
|
+
/* @__PURE__ */ jsx86(Text31, { className: cn79("text-xs font-medium", config.text), children: config.label })
|
|
3734
3915
|
] })
|
|
3735
3916
|
] }),
|
|
3736
|
-
lastSync && /* @__PURE__ */
|
|
3917
|
+
lastSync && /* @__PURE__ */ jsxs45(Text31, { className: "text-xs text-muted-foreground", children: [
|
|
3737
3918
|
"Last sync: ",
|
|
3738
3919
|
lastSync
|
|
3739
3920
|
] }),
|
|
3740
|
-
error && /* @__PURE__ */
|
|
3741
|
-
!!unsoldCount && /* @__PURE__ */
|
|
3921
|
+
error && /* @__PURE__ */ jsx86(Text31, { className: "text-xs text-destructive", children: error }),
|
|
3922
|
+
!!unsoldCount && /* @__PURE__ */ jsx86(Text31, { className: cn79("text-xs", unsoldStale ? "text-muted-foreground" : "text-warning"), children: formatUnsold(unsoldCount, !!unsoldStale) })
|
|
3742
3923
|
] });
|
|
3743
3924
|
}
|
|
3744
3925
|
|
|
3745
3926
|
// src/sale/cart.tsx
|
|
3746
|
-
import { useState as
|
|
3747
|
-
import { Pressable as
|
|
3927
|
+
import { useState as useState16 } from "react";
|
|
3928
|
+
import { Pressable as Pressable24, Text as Text33, View as View55 } from "react-native";
|
|
3748
3929
|
import { buildReceiptData } from "@tallyui/pos";
|
|
3749
3930
|
|
|
3750
3931
|
// src/sale/discount-form.tsx
|
|
3751
|
-
import { useState as
|
|
3752
|
-
import { Pressable as
|
|
3932
|
+
import { useState as useState15 } from "react";
|
|
3933
|
+
import { Pressable as Pressable23, Text as Text32, TextInput as TextInput9, View as View54 } from "react-native";
|
|
3753
3934
|
import { formatMoney as formatMoney10, minorUnitDigits as minorUnitDigits7, moneyFromDecimalString as moneyFromDecimalString2 } from "@tallyui/core";
|
|
3754
|
-
import { jsx as
|
|
3935
|
+
import { jsx as jsx87, jsxs as jsxs46 } from "react/jsx-runtime";
|
|
3755
3936
|
function parseDiscount(type, text, currency) {
|
|
3756
3937
|
const raw = text.trim();
|
|
3757
3938
|
const trimmed = raw.split(",").length === 2 ? raw.replace(",", ".") : raw;
|
|
@@ -3768,31 +3949,31 @@ function parseDiscount(type, text, currency) {
|
|
|
3768
3949
|
var discountLabel = (discount, currency) => discount.type === "percentage" ? `${discount.value}%` : formatMoney10({ amount: discount.amountMinor, currency }) ?? String(discount.amountMinor);
|
|
3769
3950
|
var button = "rounded-md border border-border px-3 py-2 min-h-11 items-center justify-center";
|
|
3770
3951
|
function DiscountForm({ title, currency, onApply, onClose }) {
|
|
3771
|
-
const [type, setType] =
|
|
3772
|
-
const [text, setText] =
|
|
3773
|
-
const [error, setError] =
|
|
3952
|
+
const [type, setType] = useState15("percentage");
|
|
3953
|
+
const [text, setText] = useState15("");
|
|
3954
|
+
const [error, setError] = useState15(null);
|
|
3774
3955
|
function apply() {
|
|
3775
3956
|
const parsed = parseDiscount(type, text, currency);
|
|
3776
3957
|
const refused = typeof parsed === "string" ? parsed : onApply(parsed);
|
|
3777
3958
|
setError(refused);
|
|
3778
3959
|
if (refused === null) onClose();
|
|
3779
3960
|
}
|
|
3780
|
-
return /* @__PURE__ */
|
|
3781
|
-
/* @__PURE__ */
|
|
3782
|
-
/* @__PURE__ */
|
|
3783
|
-
["percentage", "fixed"].map((option) => /* @__PURE__ */
|
|
3784
|
-
|
|
3961
|
+
return /* @__PURE__ */ jsxs46(View54, { role: "group", accessibilityLabel: title, className: "gap-2 px-3 py-2", children: [
|
|
3962
|
+
/* @__PURE__ */ jsx87(Text32, { className: "font-semibold text-foreground", children: title }),
|
|
3963
|
+
/* @__PURE__ */ jsxs46(View54, { className: "flex-row gap-2", children: [
|
|
3964
|
+
["percentage", "fixed"].map((option) => /* @__PURE__ */ jsx87(
|
|
3965
|
+
Pressable23,
|
|
3785
3966
|
{
|
|
3786
3967
|
accessibilityRole: "button",
|
|
3787
3968
|
accessibilityState: { selected: type === option },
|
|
3788
3969
|
onPress: () => setType(option),
|
|
3789
3970
|
className: `${button} ${type === option ? "bg-primary" : "bg-card"}`,
|
|
3790
|
-
children: /* @__PURE__ */
|
|
3971
|
+
children: /* @__PURE__ */ jsx87(Text32, { className: type === option ? "text-primary-foreground" : "text-foreground", children: option === "percentage" ? "Percent" : "Amount" })
|
|
3791
3972
|
},
|
|
3792
3973
|
option
|
|
3793
3974
|
)),
|
|
3794
|
-
/* @__PURE__ */
|
|
3795
|
-
|
|
3975
|
+
/* @__PURE__ */ jsx87(
|
|
3976
|
+
TextInput9,
|
|
3796
3977
|
{
|
|
3797
3978
|
accessibilityLabel: "Discount value",
|
|
3798
3979
|
value: text,
|
|
@@ -3804,16 +3985,16 @@ function DiscountForm({ title, currency, onApply, onClose }) {
|
|
|
3804
3985
|
}
|
|
3805
3986
|
)
|
|
3806
3987
|
] }),
|
|
3807
|
-
error ? /* @__PURE__ */
|
|
3808
|
-
/* @__PURE__ */
|
|
3809
|
-
/* @__PURE__ */
|
|
3810
|
-
/* @__PURE__ */
|
|
3988
|
+
error ? /* @__PURE__ */ jsx87(Text32, { accessibilityRole: "alert", className: "text-destructive", children: error }) : null,
|
|
3989
|
+
/* @__PURE__ */ jsxs46(View54, { className: "flex-row gap-2", children: [
|
|
3990
|
+
/* @__PURE__ */ jsx87(Pressable23, { accessibilityRole: "button", onPress: apply, className: `${button} bg-primary`, children: /* @__PURE__ */ jsx87(Text32, { className: "font-semibold text-primary-foreground", children: "Apply" }) }),
|
|
3991
|
+
/* @__PURE__ */ jsx87(Pressable23, { accessibilityRole: "button", onPress: onClose, className: `${button} bg-card`, children: /* @__PURE__ */ jsx87(Text32, { className: "text-foreground", children: "Cancel" }) })
|
|
3811
3992
|
] })
|
|
3812
3993
|
] });
|
|
3813
3994
|
}
|
|
3814
3995
|
function DiscountChips({ discounts, currency, onRemove, prefix, amounts = [] }) {
|
|
3815
3996
|
if (!discounts.length) return null;
|
|
3816
|
-
return /* @__PURE__ */
|
|
3997
|
+
return /* @__PURE__ */ jsx87(View54, { className: "flex-row flex-wrap gap-2 px-3", children: discounts.map((discount) => {
|
|
3817
3998
|
const amount = amounts.find((row) => row.discountId === discount.id)?.amountMinor;
|
|
3818
3999
|
const own = discountLabel(discount, currency);
|
|
3819
4000
|
const label = [
|
|
@@ -3821,16 +4002,16 @@ function DiscountChips({ discounts, currency, onRemove, prefix, amounts = [] })
|
|
|
3821
4002
|
amount === void 0 ? prefix ? `\u2212${own}` : own : discount.type === "percentage" ? own : null,
|
|
3822
4003
|
amount === void 0 ? null : `\u2212${formatMoney10({ amount, currency })}`
|
|
3823
4004
|
].filter(Boolean).join(" ");
|
|
3824
|
-
return /* @__PURE__ */
|
|
3825
|
-
|
|
4005
|
+
return /* @__PURE__ */ jsxs46(
|
|
4006
|
+
Pressable23,
|
|
3826
4007
|
{
|
|
3827
4008
|
accessibilityRole: "button",
|
|
3828
4009
|
accessibilityLabel: `Remove discount ${label}`,
|
|
3829
4010
|
onPress: () => onRemove(discount.id),
|
|
3830
4011
|
className: "min-h-11 flex-row items-center gap-1",
|
|
3831
4012
|
children: [
|
|
3832
|
-
/* @__PURE__ */
|
|
3833
|
-
/* @__PURE__ */
|
|
4013
|
+
/* @__PURE__ */ jsx87(DiscountBadge, { label, className: "self-center" }),
|
|
4014
|
+
/* @__PURE__ */ jsx87(Text32, { className: "text-muted-foreground", children: "\u2715" })
|
|
3834
4015
|
]
|
|
3835
4016
|
},
|
|
3836
4017
|
discount.id
|
|
@@ -3839,7 +4020,7 @@ function DiscountChips({ discounts, currency, onRemove, prefix, amounts = [] })
|
|
|
3839
4020
|
}
|
|
3840
4021
|
|
|
3841
4022
|
// src/sale/cart.tsx
|
|
3842
|
-
import { Fragment as Fragment4, jsx as
|
|
4023
|
+
import { Fragment as Fragment4, jsx as jsx88, jsxs as jsxs47 } from "react/jsx-runtime";
|
|
3843
4024
|
function Cart({ sale, taxLabel = (ratePpm) => `Tax ${ratePpm / 1e4}%` }) {
|
|
3844
4025
|
const { order } = sale;
|
|
3845
4026
|
const money = (amount) => ({ amount, currency: order.currency });
|
|
@@ -3847,8 +4028,8 @@ function Cart({ sale, taxLabel = (ratePpm) => `Tax ${ratePpm / 1e4}%` }) {
|
|
|
3847
4028
|
const taxRows = totals.taxLines.map((line) => ({ label: taxLabel(line.ratePpm), amount: money(line.amountMinor) }));
|
|
3848
4029
|
const display = (lineId) => order.display.lines.find((line) => line.lineId === lineId);
|
|
3849
4030
|
const orderAmounts = order.discounts.length === 1 ? [{ discountId: order.discounts[0].id, amountMinor: order.display.orderDiscountMinor }] : [];
|
|
3850
|
-
const [form, setForm] =
|
|
3851
|
-
const discountForm = (lineId, title) => form?.lineId === lineId ? /* @__PURE__ */
|
|
4031
|
+
const [form, setForm] = useState16(null);
|
|
4032
|
+
const discountForm = (lineId, title) => form?.lineId === lineId ? /* @__PURE__ */ jsx88(
|
|
3852
4033
|
DiscountForm,
|
|
3853
4034
|
{
|
|
3854
4035
|
title,
|
|
@@ -3859,8 +4040,8 @@ function Cart({ sale, taxLabel = (ratePpm) => `Tax ${ratePpm / 1e4}%` }) {
|
|
|
3859
4040
|
lineId ?? "order"
|
|
3860
4041
|
) : null;
|
|
3861
4042
|
const pay = `min-h-12 flex-1 justify-center rounded-md bg-primary px-4 py-3 ${!order.lineItems.length ? "opacity-50" : ""}`;
|
|
3862
|
-
const renderItem = (line) => /* @__PURE__ */
|
|
3863
|
-
/* @__PURE__ */
|
|
4043
|
+
const renderItem = (line) => /* @__PURE__ */ jsxs47(Fragment4, { children: [
|
|
4044
|
+
/* @__PURE__ */ jsx88(CartLineActions, { actions: [{ id: "discount", label: "Discount", color: "text-primary", onPress: () => setForm({ lineId: line.id }) }], children: /* @__PURE__ */ jsx88(
|
|
3864
4045
|
CartLine,
|
|
3865
4046
|
{
|
|
3866
4047
|
name: line.name,
|
|
@@ -3869,50 +4050,50 @@ function Cart({ sale, taxLabel = (ratePpm) => `Tax ${ratePpm / 1e4}%` }) {
|
|
|
3869
4050
|
lineTotal: money(display(line.id).amountMinor)
|
|
3870
4051
|
}
|
|
3871
4052
|
) }),
|
|
3872
|
-
/* @__PURE__ */
|
|
3873
|
-
/* @__PURE__ */
|
|
3874
|
-
/* @__PURE__ */
|
|
3875
|
-
|
|
4053
|
+
/* @__PURE__ */ jsx88(DiscountChips, { discounts: line.discounts, amounts: display(line.id).discounts, currency: order.currency, onRemove: sale.removeDiscount }),
|
|
4054
|
+
/* @__PURE__ */ jsxs47(View55, { className: "flex-row gap-4 px-3 py-2", children: [
|
|
4055
|
+
/* @__PURE__ */ jsx88(
|
|
4056
|
+
Pressable24,
|
|
3876
4057
|
{
|
|
3877
4058
|
accessibilityRole: "button",
|
|
3878
4059
|
accessibilityLabel: `Decrease ${line.name}`,
|
|
3879
4060
|
onPress: () => sale.setQuantity(line.id, line.quantity - 1),
|
|
3880
4061
|
className: "rounded-md border border-border bg-card px-3 py-2 min-h-11 min-w-11 items-center justify-center",
|
|
3881
|
-
children: /* @__PURE__ */
|
|
4062
|
+
children: /* @__PURE__ */ jsx88(Text33, { className: "text-center text-foreground", children: "\u2212" })
|
|
3882
4063
|
}
|
|
3883
4064
|
),
|
|
3884
|
-
/* @__PURE__ */
|
|
3885
|
-
|
|
4065
|
+
/* @__PURE__ */ jsx88(
|
|
4066
|
+
Pressable24,
|
|
3886
4067
|
{
|
|
3887
4068
|
accessibilityRole: "button",
|
|
3888
4069
|
accessibilityLabel: `Increase ${line.name}`,
|
|
3889
4070
|
onPress: () => sale.setQuantity(line.id, line.quantity + 1),
|
|
3890
4071
|
className: "rounded-md border border-border bg-card px-3 py-2 min-h-11 min-w-11 items-center justify-center",
|
|
3891
|
-
children: /* @__PURE__ */
|
|
4072
|
+
children: /* @__PURE__ */ jsx88(Text33, { className: "text-center text-foreground", children: "+" })
|
|
3892
4073
|
}
|
|
3893
4074
|
),
|
|
3894
|
-
/* @__PURE__ */
|
|
3895
|
-
|
|
4075
|
+
/* @__PURE__ */ jsx88(
|
|
4076
|
+
Pressable24,
|
|
3896
4077
|
{
|
|
3897
4078
|
accessibilityRole: "button",
|
|
3898
4079
|
accessibilityLabel: `Remove ${line.name}`,
|
|
3899
4080
|
onPress: () => sale.remove(line.id),
|
|
3900
4081
|
className: "rounded-md border border-border bg-card px-3 py-2 min-h-11 min-w-11 items-center justify-center",
|
|
3901
|
-
children: /* @__PURE__ */
|
|
4082
|
+
children: /* @__PURE__ */ jsx88(Text33, { className: "text-center text-foreground", children: "Remove" })
|
|
3902
4083
|
}
|
|
3903
4084
|
)
|
|
3904
4085
|
] }),
|
|
3905
4086
|
discountForm(line.id, `Discount on ${line.name}`)
|
|
3906
4087
|
] });
|
|
3907
|
-
return /* @__PURE__ */
|
|
4088
|
+
return /* @__PURE__ */ jsx88(
|
|
3908
4089
|
CartPanel,
|
|
3909
4090
|
{
|
|
3910
4091
|
dataSet: { print: "hide" },
|
|
3911
4092
|
items: order.lineItems,
|
|
3912
4093
|
renderItem,
|
|
3913
|
-
emptyState: /* @__PURE__ */
|
|
3914
|
-
afterItems: order.lineItems.length ? /* @__PURE__ */
|
|
3915
|
-
/* @__PURE__ */
|
|
4094
|
+
emptyState: /* @__PURE__ */ jsx88(Text33, { className: "text-muted-foreground", children: "Scan or tap a product to start a sale." }),
|
|
4095
|
+
afterItems: order.lineItems.length ? /* @__PURE__ */ jsxs47(View55, { className: "gap-3 px-3 py-2", children: [
|
|
4096
|
+
/* @__PURE__ */ jsx88(
|
|
3916
4097
|
DiscountChips,
|
|
3917
4098
|
{
|
|
3918
4099
|
discounts: order.discounts,
|
|
@@ -3922,18 +4103,18 @@ function Cart({ sale, taxLabel = (ratePpm) => `Tax ${ratePpm / 1e4}%` }) {
|
|
|
3922
4103
|
prefix: "Order discount"
|
|
3923
4104
|
}
|
|
3924
4105
|
),
|
|
3925
|
-
form?.lineId === null ? discountForm(null, "Order discount") : /* @__PURE__ */
|
|
3926
|
-
|
|
4106
|
+
form?.lineId === null ? discountForm(null, "Order discount") : /* @__PURE__ */ jsx88(
|
|
4107
|
+
Pressable24,
|
|
3927
4108
|
{
|
|
3928
4109
|
accessibilityRole: "button",
|
|
3929
4110
|
onPress: () => setForm({ lineId: null }),
|
|
3930
4111
|
className: "self-start rounded-md border border-border bg-card px-4 py-2 min-h-11 justify-center",
|
|
3931
|
-
children: /* @__PURE__ */
|
|
4112
|
+
children: /* @__PURE__ */ jsx88(Text33, { className: "text-foreground", children: "Order discount" })
|
|
3932
4113
|
}
|
|
3933
4114
|
)
|
|
3934
4115
|
] }) : void 0,
|
|
3935
|
-
footer: /* @__PURE__ */
|
|
3936
|
-
/* @__PURE__ */
|
|
4116
|
+
footer: /* @__PURE__ */ jsxs47(View55, { testID: "cart-footer", className: "gap-3 pb-4", children: [
|
|
4117
|
+
/* @__PURE__ */ jsx88(
|
|
3937
4118
|
CartTotal,
|
|
3938
4119
|
{
|
|
3939
4120
|
subtotal: money(totals.subtotalMinor),
|
|
@@ -3943,10 +4124,10 @@ function Cart({ sale, taxLabel = (ratePpm) => `Tax ${ratePpm / 1e4}%` }) {
|
|
|
3943
4124
|
taxInclusive: totals.taxInclusive
|
|
3944
4125
|
}
|
|
3945
4126
|
),
|
|
3946
|
-
sale.error ? /* @__PURE__ */
|
|
3947
|
-
/* @__PURE__ */
|
|
3948
|
-
/* @__PURE__ */
|
|
3949
|
-
/* @__PURE__ */
|
|
4127
|
+
sale.error ? /* @__PURE__ */ jsx88(Text33, { accessibilityRole: "alert", className: "text-destructive", children: sale.error }) : null,
|
|
4128
|
+
/* @__PURE__ */ jsxs47(View55, { className: "flex-row gap-3", children: [
|
|
4129
|
+
/* @__PURE__ */ jsx88(Pressable24, { accessibilityRole: "button", disabled: !order.lineItems.length, onPress: () => sale.startTender("cash"), className: pay, children: /* @__PURE__ */ jsx88(Text33, { className: "text-center font-semibold text-primary-foreground", children: "Cash" }) }),
|
|
4130
|
+
/* @__PURE__ */ jsx88(Pressable24, { accessibilityRole: "button", disabled: !order.lineItems.length, onPress: () => sale.startTender("external"), className: pay, children: /* @__PURE__ */ jsx88(Text33, { className: "text-center font-semibold text-primary-foreground", children: "Card terminal" }) })
|
|
3950
4131
|
] })
|
|
3951
4132
|
] })
|
|
3952
4133
|
}
|
|
@@ -3954,26 +4135,26 @@ function Cart({ sale, taxLabel = (ratePpm) => `Tax ${ratePpm / 1e4}%` }) {
|
|
|
3954
4135
|
}
|
|
3955
4136
|
|
|
3956
4137
|
// src/sale/cart-bar.tsx
|
|
3957
|
-
import { Pressable as
|
|
4138
|
+
import { Pressable as Pressable25, Text as Text34 } from "react-native";
|
|
3958
4139
|
import { formatMoney as formatMoney11 } from "@tallyui/core";
|
|
3959
4140
|
import { buildReceiptData as buildReceiptData2 } from "@tallyui/pos";
|
|
3960
|
-
import { jsx as
|
|
4141
|
+
import { jsx as jsx89, jsxs as jsxs48 } from "react/jsx-runtime";
|
|
3961
4142
|
function CartBar({ sale, onOpen }) {
|
|
3962
4143
|
const { order } = sale;
|
|
3963
|
-
const
|
|
4144
|
+
const count2 = order.lineItems.reduce((sum, line) => sum + line.quantity, 0);
|
|
3964
4145
|
const total = formatMoney11({ amount: buildReceiptData2(order, { storeName: "" }).totals.totalMinor, currency: order.currency });
|
|
3965
|
-
const items = `${
|
|
3966
|
-
return /* @__PURE__ */
|
|
3967
|
-
|
|
4146
|
+
const items = `${count2} ${count2 === 1 ? "item" : "items"}`;
|
|
4147
|
+
return /* @__PURE__ */ jsxs48(
|
|
4148
|
+
Pressable25,
|
|
3968
4149
|
{
|
|
3969
4150
|
accessibilityRole: "button",
|
|
3970
|
-
accessibilityLabel:
|
|
3971
|
-
disabled: !
|
|
4151
|
+
accessibilityLabel: count2 ? `Open cart, ${items}, ${total}` : "Cart is empty",
|
|
4152
|
+
disabled: !count2,
|
|
3972
4153
|
onPress: onOpen,
|
|
3973
|
-
className: `min-h-14 mx-3 mb-3 flex-row items-center justify-between rounded-md bg-primary px-4 py-3 ${
|
|
4154
|
+
className: `min-h-14 mx-3 mb-3 flex-row items-center justify-between rounded-md bg-primary px-4 py-3 ${count2 ? "" : "opacity-50"}`,
|
|
3974
4155
|
children: [
|
|
3975
|
-
/* @__PURE__ */
|
|
3976
|
-
|
|
4156
|
+
/* @__PURE__ */ jsx89(Text34, { className: "font-bold text-primary-foreground", children: count2 ? `Cart \xB7 ${items}` : "Cart is empty" }),
|
|
4157
|
+
count2 ? /* @__PURE__ */ jsxs48(Text34, { className: "font-bold text-primary-foreground", children: [
|
|
3977
4158
|
total,
|
|
3978
4159
|
" \u203A"
|
|
3979
4160
|
] }) : null
|
|
@@ -3983,16 +4164,17 @@ function CartBar({ sale, onOpen }) {
|
|
|
3983
4164
|
}
|
|
3984
4165
|
|
|
3985
4166
|
// src/sale/tender.tsx
|
|
3986
|
-
import { Pressable as
|
|
4167
|
+
import { Pressable as Pressable26, Text as Text35, TextInput as TextInput10, View as View56 } from "react-native";
|
|
3987
4168
|
import { formatMoney as formatMoney12 } from "@tallyui/core";
|
|
3988
|
-
import { Fragment as Fragment5, jsx as
|
|
4169
|
+
import { Fragment as Fragment5, jsx as jsx90, jsxs as jsxs49 } from "react/jsx-runtime";
|
|
4170
|
+
var REFERENCE_MAX = 255;
|
|
3989
4171
|
function Tender({ sale }) {
|
|
3990
4172
|
const { order, stage } = sale;
|
|
3991
4173
|
if (stage.kind !== "tender") return null;
|
|
3992
4174
|
const money = (amount) => ({ amount, currency: order.currency });
|
|
3993
|
-
return /* @__PURE__ */
|
|
3994
|
-
stage.method === "cash" ? /* @__PURE__ */
|
|
3995
|
-
/* @__PURE__ */
|
|
4175
|
+
return /* @__PURE__ */ jsxs49(View56, { dataSet: { print: "hide" }, className: "gap-4 p-4", children: [
|
|
4176
|
+
stage.method === "cash" ? /* @__PURE__ */ jsxs49(Fragment5, { children: [
|
|
4177
|
+
/* @__PURE__ */ jsx90(
|
|
3996
4178
|
CashTendered,
|
|
3997
4179
|
{
|
|
3998
4180
|
total: money(order.totalMinor),
|
|
@@ -4000,43 +4182,45 @@ function Tender({ sale }) {
|
|
|
4000
4182
|
onChangeAmount: (amount) => sale.setTender({ method: "cash", amountMinor: amount.amount })
|
|
4001
4183
|
}
|
|
4002
4184
|
),
|
|
4003
|
-
/* @__PURE__ */
|
|
4004
|
-
order.balanceDueMinor > 0 ? /* @__PURE__ */
|
|
4185
|
+
/* @__PURE__ */ jsx90(ChangeDisplay, { change: money(order.changeDueMinor) }),
|
|
4186
|
+
order.balanceDueMinor > 0 ? /* @__PURE__ */ jsxs49(Text35, { className: "text-foreground", children: [
|
|
4005
4187
|
"Balance due: ",
|
|
4006
4188
|
formatMoney12(money(order.balanceDueMinor))
|
|
4007
4189
|
] }) : null,
|
|
4008
|
-
/* @__PURE__ */
|
|
4009
|
-
] }) : /* @__PURE__ */
|
|
4010
|
-
/* @__PURE__ */
|
|
4190
|
+
/* @__PURE__ */ jsx90(Pressable26, { accessibilityRole: "button", disabled: order.balanceDueMinor > 0, onPress: sale.complete, className: `rounded-md bg-primary px-4 py-3 ${order.balanceDueMinor > 0 ? "opacity-50" : ""}`, children: /* @__PURE__ */ jsx90(Text35, { className: "text-center font-semibold text-primary-foreground", children: "Complete sale" }) })
|
|
4191
|
+
] }) : /* @__PURE__ */ jsxs49(Fragment5, { children: [
|
|
4192
|
+
/* @__PURE__ */ jsxs49(Text35, { className: "text-foreground", children: [
|
|
4011
4193
|
"Card terminal: ",
|
|
4012
4194
|
formatMoney12(money(order.totalMinor))
|
|
4013
4195
|
] }),
|
|
4014
|
-
/* @__PURE__ */
|
|
4015
|
-
|
|
4196
|
+
/* @__PURE__ */ jsx90(
|
|
4197
|
+
TextInput10,
|
|
4016
4198
|
{
|
|
4017
4199
|
accessibilityLabel: "Terminal reference",
|
|
4018
4200
|
placeholder: "Terminal reference",
|
|
4201
|
+
maxLength: REFERENCE_MAX,
|
|
4019
4202
|
value: order.payments[0]?.reference ?? "",
|
|
4020
4203
|
onChangeText: (reference) => sale.setTender({ method: "external", amountMinor: order.totalMinor, reference }),
|
|
4021
4204
|
className: "rounded-md border border-border px-3 py-2 text-foreground"
|
|
4022
4205
|
}
|
|
4023
4206
|
),
|
|
4024
|
-
/* @__PURE__ */
|
|
4207
|
+
/* @__PURE__ */ jsx90(Pressable26, { accessibilityRole: "button", onPress: sale.complete, className: "rounded-md bg-primary px-4 py-3", children: /* @__PURE__ */ jsx90(Text35, { className: "text-center font-semibold text-primary-foreground", children: "Payment approved on terminal" }) })
|
|
4025
4208
|
] }),
|
|
4026
|
-
sale.error ? /* @__PURE__ */
|
|
4027
|
-
sale.canContinue ? /* @__PURE__ */
|
|
4028
|
-
/* @__PURE__ */
|
|
4029
|
-
/* @__PURE__ */
|
|
4209
|
+
sale.error ? /* @__PURE__ */ jsx90(Text35, { accessibilityRole: "alert", className: "text-destructive", children: sale.error }) : null,
|
|
4210
|
+
sale.canContinue ? /* @__PURE__ */ jsxs49(Fragment5, { children: [
|
|
4211
|
+
/* @__PURE__ */ jsx90(Text35, { className: "text-foreground", children: "This sale is stored and will be sent. Continue to the next sale." }),
|
|
4212
|
+
/* @__PURE__ */ jsx90(Pressable26, { accessibilityRole: "button", onPress: () => sale.continueSale(), className: "rounded-md bg-primary px-4 py-3", children: /* @__PURE__ */ jsx90(Text35, { className: "text-center font-semibold text-primary-foreground", children: "Continue" }) })
|
|
4030
4213
|
] }) : null,
|
|
4031
|
-
/* @__PURE__ */
|
|
4214
|
+
/* @__PURE__ */ jsx90(Pressable26, { accessibilityRole: "button", onPress: sale.cancelTender, className: "rounded-md border border-border bg-card px-4 py-3", children: /* @__PURE__ */ jsx90(Text35, { className: "text-center text-foreground", children: "Back" }) })
|
|
4032
4215
|
] });
|
|
4033
4216
|
}
|
|
4034
4217
|
|
|
4035
4218
|
// src/sale/catalogue.tsx
|
|
4036
|
-
import { useEffect as
|
|
4037
|
-
import { Pressable as
|
|
4219
|
+
import { useEffect as useEffect5, useMemo as useMemo2, useState as useState17 } from "react";
|
|
4220
|
+
import { Pressable as Pressable27, Text as Text36, View as View57 } from "react-native";
|
|
4221
|
+
import { useStockOverlaid, useStockOverlayAsOf } from "@tallyui/core";
|
|
4038
4222
|
import { catalogueEntries, findEntryByCode, searchProducts, variantPriceLabel } from "@tallyui/pos";
|
|
4039
|
-
import { jsx as
|
|
4223
|
+
import { jsx as jsx91, jsxs as jsxs50 } from "react/jsx-runtime";
|
|
4040
4224
|
var MIN_TILE_WIDTH = 160;
|
|
4041
4225
|
var STOCK_LABEL = {
|
|
4042
4226
|
in_stock: "In Stock",
|
|
@@ -4056,24 +4240,28 @@ function laterOf(a, b) {
|
|
|
4056
4240
|
return a.getTime() >= b.getTime() ? a : b;
|
|
4057
4241
|
}
|
|
4058
4242
|
function Catalogue({ products, traits, currency, onSelect, statusText, statusAccessory, lastSyncedAt, lastStockCheckAt, hour12, minCodeLength }) {
|
|
4059
|
-
const
|
|
4060
|
-
const
|
|
4061
|
-
const
|
|
4062
|
-
const
|
|
4243
|
+
const shown = useStockOverlaid(products);
|
|
4244
|
+
const overlayAsOf = useStockOverlayAsOf();
|
|
4245
|
+
const parsedOverlayAsOf = overlayAsOf ? new Date(overlayAsOf) : void 0;
|
|
4246
|
+
const validOverlayAsOf = parsedOverlayAsOf && !isNaN(parsedOverlayAsOf.getTime()) ? parsedOverlayAsOf : void 0;
|
|
4247
|
+
const stockAsOf = laterOf(laterOf(lastStockCheckAt, validOverlayAsOf), lastSyncedAt);
|
|
4248
|
+
const [query, setQuery] = useState17("");
|
|
4249
|
+
const [chooserId, setChooserId] = useState17(null);
|
|
4250
|
+
const [width, setWidth] = useState17(0);
|
|
4063
4251
|
const columns = Math.max(2, Math.min(6, Math.floor((width - 8) / (MIN_TILE_WIDTH + 8))));
|
|
4064
|
-
const entries = useMemo2(() => catalogueEntries(
|
|
4065
|
-
const results = useMemo2(() => searchProducts(
|
|
4252
|
+
const entries = useMemo2(() => catalogueEntries(shown, traits), [shown, traits]);
|
|
4253
|
+
const results = useMemo2(() => searchProducts(shown, query, traits), [shown, query, traits]);
|
|
4066
4254
|
const choices = useMemo2(() => chooserId === null ? [] : entries.filter((entry) => traits.getId(entry.product) === chooserId), [entries, chooserId, traits]);
|
|
4067
|
-
|
|
4255
|
+
useEffect5(() => {
|
|
4068
4256
|
if (chooserId !== null && choices.length === 0) setChooserId(null);
|
|
4069
4257
|
}, [chooserId, choices]);
|
|
4070
4258
|
function select(entry) {
|
|
4071
4259
|
onSelect(entry);
|
|
4072
4260
|
setChooserId(null);
|
|
4073
4261
|
}
|
|
4074
|
-
return /* @__PURE__ */
|
|
4075
|
-
/* @__PURE__ */
|
|
4076
|
-
/* @__PURE__ */
|
|
4262
|
+
return /* @__PURE__ */ jsxs50(View57, { className: "flex-1", onLayout: (event) => setWidth(event.nativeEvent.layout.width), children: [
|
|
4263
|
+
/* @__PURE__ */ jsxs50(View57, { className: "gap-2 border-b border-border bg-card px-4 pb-3 pt-3", children: [
|
|
4264
|
+
/* @__PURE__ */ jsx91(
|
|
4077
4265
|
SearchInput,
|
|
4078
4266
|
{
|
|
4079
4267
|
value: query,
|
|
@@ -4090,25 +4278,25 @@ function Catalogue({ products, traits, currency, onSelect, statusText, statusAcc
|
|
|
4090
4278
|
}
|
|
4091
4279
|
}
|
|
4092
4280
|
),
|
|
4093
|
-
statusText || statusAccessory ? /* @__PURE__ */
|
|
4094
|
-
statusText ? /* @__PURE__ */
|
|
4281
|
+
statusText || statusAccessory ? /* @__PURE__ */ jsxs50(View57, { testID: "catalogue-status-row", className: "flex-row items-center gap-2", children: [
|
|
4282
|
+
statusText ? /* @__PURE__ */ jsxs50(Text36, { className: "flex-1 text-xs text-muted-foreground", numberOfLines: statusAccessory ? 1 : void 0, children: [
|
|
4095
4283
|
statusText,
|
|
4096
4284
|
query.trim() ? ` \xB7 ${results.length.toLocaleString()} matching` : ""
|
|
4097
4285
|
] }) : null,
|
|
4098
4286
|
statusAccessory
|
|
4099
4287
|
] }) : null,
|
|
4100
|
-
choices.length > 0 ? /* @__PURE__ */
|
|
4101
|
-
choices.map((entry) => /* @__PURE__ */
|
|
4102
|
-
|
|
4288
|
+
choices.length > 0 ? /* @__PURE__ */ jsxs50(View57, { accessibilityLabel: "Choose variant", className: "gap-2", children: [
|
|
4289
|
+
choices.map((entry) => /* @__PURE__ */ jsxs50(
|
|
4290
|
+
Pressable27,
|
|
4103
4291
|
{
|
|
4104
4292
|
accessibilityRole: "button",
|
|
4105
4293
|
onPress: () => select(entry),
|
|
4106
4294
|
className: "gap-1 rounded-md border border-border p-3",
|
|
4107
4295
|
children: [
|
|
4108
|
-
/* @__PURE__ */
|
|
4109
|
-
/* @__PURE__ */
|
|
4110
|
-
/* @__PURE__ */
|
|
4111
|
-
/* @__PURE__ */
|
|
4296
|
+
/* @__PURE__ */ jsx91(Text36, { className: "font-semibold text-foreground", children: entry.variant.title }),
|
|
4297
|
+
/* @__PURE__ */ jsx91(Text36, { className: "text-muted-foreground", children: entry.variant.sku }),
|
|
4298
|
+
/* @__PURE__ */ jsx91(Text36, { className: "text-foreground", children: variantPriceLabel(entry.variant, currency) }),
|
|
4299
|
+
/* @__PURE__ */ jsxs50(Text36, { className: "text-muted-foreground", children: [
|
|
4112
4300
|
STOCK_LABEL[entry.variant.stock.status],
|
|
4113
4301
|
" \xB7 ",
|
|
4114
4302
|
stockAsOf ? `as of ${formatStockSyncTime(stockAsOf, void 0, hour12)}` : "not yet synced"
|
|
@@ -4117,10 +4305,10 @@ function Catalogue({ products, traits, currency, onSelect, statusText, statusAcc
|
|
|
4117
4305
|
},
|
|
4118
4306
|
entry.variant.id
|
|
4119
4307
|
)),
|
|
4120
|
-
/* @__PURE__ */
|
|
4308
|
+
/* @__PURE__ */ jsx91(Pressable27, { accessibilityRole: "button", onPress: () => setChooserId(null), className: "rounded-md border border-border bg-card px-4 py-3", children: /* @__PURE__ */ jsx91(Text36, { className: "text-center text-foreground", children: "Cancel" }) })
|
|
4121
4309
|
] }) : null
|
|
4122
4310
|
] }),
|
|
4123
|
-
/* @__PURE__ */
|
|
4311
|
+
/* @__PURE__ */ jsx91(
|
|
4124
4312
|
ProductGrid,
|
|
4125
4313
|
{
|
|
4126
4314
|
items: results,
|
|
@@ -4129,26 +4317,26 @@ function Catalogue({ products, traits, currency, onSelect, statusText, statusAcc
|
|
|
4129
4317
|
// TallyUI's ProductCard has no children slot, so the tile is composed directly here
|
|
4130
4318
|
// (same structure/classes as ProductCard) to add the stock badge as a fourth child,
|
|
4131
4319
|
// inside the card and centred with the rest, rather than adding a slot to ProductCard (out of scope for TV6b).
|
|
4132
|
-
/* @__PURE__ */
|
|
4320
|
+
/* @__PURE__ */ jsx91(Pressable27, { accessibilityRole: "button", testID: `product-tile-${traits.getName(product)}`, onPress: () => {
|
|
4133
4321
|
const variants = entries.filter((entry) => entry.product === product);
|
|
4134
4322
|
if (variants.length === 1) select(variants[0]);
|
|
4135
4323
|
else setChooserId(traits.getId(product));
|
|
4136
|
-
}, children: /* @__PURE__ */
|
|
4137
|
-
/* @__PURE__ */
|
|
4138
|
-
/* @__PURE__ */
|
|
4139
|
-
/* @__PURE__ */
|
|
4140
|
-
/* @__PURE__ */
|
|
4324
|
+
}, children: /* @__PURE__ */ jsxs50(VStack, { space: "sm", className: "items-center rounded-lg border border-border bg-card p-3", children: [
|
|
4325
|
+
/* @__PURE__ */ jsx91(ProductImage, { doc: product, size: 80, className: "rounded-md" }),
|
|
4326
|
+
/* @__PURE__ */ jsx91(ProductTitle, { doc: product, className: "text-sm", numberOfLines: 2 }),
|
|
4327
|
+
/* @__PURE__ */ jsx91(ProductPrice, { doc: product }),
|
|
4328
|
+
/* @__PURE__ */ jsx91(ProductStockBadge, { doc: product, showAsOf: false, className: "self-center" })
|
|
4141
4329
|
] }) })
|
|
4142
4330
|
),
|
|
4143
|
-
emptyState: /* @__PURE__ */
|
|
4331
|
+
emptyState: /* @__PURE__ */ jsx91(Text36, { className: "mt-10 text-center text-sm text-muted-foreground", children: query.trim() ? `No products match "${query.trim()}".` : "No products yet." })
|
|
4144
4332
|
}
|
|
4145
4333
|
)
|
|
4146
4334
|
] });
|
|
4147
4335
|
}
|
|
4148
4336
|
|
|
4149
4337
|
// src/sale/receipt.tsx
|
|
4150
|
-
import { useEffect as
|
|
4151
|
-
import { Pressable as
|
|
4338
|
+
import { useEffect as useEffect6 } from "react";
|
|
4339
|
+
import { Pressable as Pressable28, Text as Text37, View as View58 } from "react-native";
|
|
4152
4340
|
import { formatMoney as formatMoney13 } from "@tallyui/core";
|
|
4153
4341
|
import { buildReceiptData as buildReceiptData3 } from "@tallyui/pos";
|
|
4154
4342
|
|
|
@@ -4163,7 +4351,7 @@ function injectPrintStyle() {
|
|
|
4163
4351
|
}
|
|
4164
4352
|
|
|
4165
4353
|
// src/sale/receipt.tsx
|
|
4166
|
-
import { Fragment as Fragment6, jsx as
|
|
4354
|
+
import { Fragment as Fragment6, jsx as jsx92, jsxs as jsxs51 } from "react/jsx-runtime";
|
|
4167
4355
|
var defaultFormatDate = (iso) => new Intl.DateTimeFormat(void 0, { dateStyle: "medium", timeStyle: "short" }).format(new Date(iso));
|
|
4168
4356
|
function Receipt({
|
|
4169
4357
|
order,
|
|
@@ -4175,7 +4363,7 @@ function Receipt({
|
|
|
4175
4363
|
topInset = 0,
|
|
4176
4364
|
formatDate = defaultFormatDate
|
|
4177
4365
|
}) {
|
|
4178
|
-
|
|
4366
|
+
useEffect6(injectPrintStyle, []);
|
|
4179
4367
|
const receipt = buildReceiptData3(order, {
|
|
4180
4368
|
storeName: store.name,
|
|
4181
4369
|
storeAddress: store.address,
|
|
@@ -4183,30 +4371,34 @@ function Receipt({
|
|
|
4183
4371
|
register: registerId
|
|
4184
4372
|
});
|
|
4185
4373
|
const money = (amount) => formatMoney13({ amount, currency: receipt.currency }) ?? "";
|
|
4186
|
-
const row = (label, amount, bold = false, key) => /* @__PURE__ */
|
|
4187
|
-
/* @__PURE__ */
|
|
4188
|
-
/* @__PURE__ */
|
|
4374
|
+
const row = (label, amount, bold = false, key) => /* @__PURE__ */ jsxs51(View58, { accessibilityLabel: `${label}: ${amount}`, className: "flex-row justify-between gap-4", children: [
|
|
4375
|
+
/* @__PURE__ */ jsx92(Text37, { className: `text-foreground ${bold ? "font-semibold" : ""}`, children: label }),
|
|
4376
|
+
/* @__PURE__ */ jsx92(Text37, { className: `text-right text-foreground ${bold ? "font-semibold" : ""}`, children: amount })
|
|
4189
4377
|
] }, key);
|
|
4190
4378
|
const { totals } = receipt;
|
|
4191
4379
|
const taxRows = totals.taxLines.map((line, index) => row(`${totals.taxInclusive ? "incl. " : ""}${taxLabel(line.ratePpm)}`, money(line.amountMinor), false, index));
|
|
4192
|
-
return /* @__PURE__ */
|
|
4193
|
-
topInset > 0 ? /* @__PURE__ */
|
|
4194
|
-
/* @__PURE__ */
|
|
4195
|
-
/* @__PURE__ */
|
|
4196
|
-
receipt.header.storeAddress ? /* @__PURE__ */
|
|
4197
|
-
/* @__PURE__ */
|
|
4380
|
+
return /* @__PURE__ */ jsxs51(Fragment6, { children: [
|
|
4381
|
+
topInset > 0 ? /* @__PURE__ */ jsx92(View58, { dataSet: { print: "hide" }, style: { height: topInset, flexShrink: 0 } }) : null,
|
|
4382
|
+
/* @__PURE__ */ jsxs51(View58, { className: "w-full max-w-md self-center gap-3 p-4 bg-card", children: [
|
|
4383
|
+
/* @__PURE__ */ jsx92(Text37, { className: "text-lg font-semibold text-foreground", children: receipt.header.storeName }),
|
|
4384
|
+
receipt.header.storeAddress ? /* @__PURE__ */ jsx92(Text37, { className: "text-muted-foreground", children: receipt.header.storeAddress }) : null,
|
|
4385
|
+
/* @__PURE__ */ jsxs51(Text37, { className: "text-foreground", children: [
|
|
4198
4386
|
"Order ",
|
|
4199
4387
|
receipt.header.orderNumber.slice(-8)
|
|
4200
4388
|
] }),
|
|
4201
|
-
/* @__PURE__ */
|
|
4202
|
-
/* @__PURE__ */
|
|
4389
|
+
/* @__PURE__ */ jsx92(Text37, { className: "text-muted-foreground", children: formatDate(receipt.header.date) }),
|
|
4390
|
+
/* @__PURE__ */ jsxs51(Text37, { className: "text-muted-foreground", children: [
|
|
4203
4391
|
"Cashier: ",
|
|
4204
4392
|
receipt.header.cashier
|
|
4205
4393
|
] }),
|
|
4206
|
-
receipt.
|
|
4207
|
-
|
|
4394
|
+
receipt.header.customer && /* @__PURE__ */ jsxs51(Text37, { className: "text-muted-foreground", children: [
|
|
4395
|
+
"Customer: ",
|
|
4396
|
+
receipt.header.customer
|
|
4397
|
+
] }),
|
|
4398
|
+
receipt.lineItems.map((line, index) => /* @__PURE__ */ jsxs51(View58, { children: [
|
|
4399
|
+
/* @__PURE__ */ jsx92(Text37, { className: "text-foreground", children: line.name }),
|
|
4208
4400
|
row(`${line.quantity} \xD7 ${money(line.unitPriceMinor)}`, money(line.displayAmountMinor)),
|
|
4209
|
-
line.displayDiscounts.map((discount, i) => /* @__PURE__ */
|
|
4401
|
+
line.displayDiscounts.map((discount, i) => /* @__PURE__ */ jsx92(View58, { className: "pl-4", children: row(`${discountLabel(
|
|
4210
4402
|
order.lineItems[index].discounts[i],
|
|
4211
4403
|
receipt.currency
|
|
4212
4404
|
)} off`, `\u2212${money(discount.amountMinor)}`) }, i))
|
|
@@ -4223,82 +4415,165 @@ function Receipt({
|
|
|
4223
4415
|
index
|
|
4224
4416
|
)),
|
|
4225
4417
|
row("Change", money(receipt.changeDueMinor)),
|
|
4226
|
-
/* @__PURE__ */
|
|
4227
|
-
/* @__PURE__ */
|
|
4418
|
+
/* @__PURE__ */ jsxs51(View58, { dataSet: { print: "hide" }, className: "flex-row gap-4", children: [
|
|
4419
|
+
/* @__PURE__ */ jsx92(Pressable28, { accessibilityRole: "button", onPress: () => {
|
|
4228
4420
|
if (typeof window !== "undefined" && typeof window.print === "function") window.print();
|
|
4229
|
-
}, className: "rounded-md border border-border bg-card px-4 py-3", children: /* @__PURE__ */
|
|
4230
|
-
/* @__PURE__ */
|
|
4421
|
+
}, className: "rounded-md border border-border bg-card px-4 py-3", children: /* @__PURE__ */ jsx92(Text37, { className: "text-center text-foreground", children: "Print receipt" }) }),
|
|
4422
|
+
/* @__PURE__ */ jsx92(Pressable28, { accessibilityRole: "button", onPress: newSale, className: "rounded-md bg-primary px-4 py-3", children: /* @__PURE__ */ jsx92(Text37, { className: "text-center font-semibold text-primary-foreground", children: "New sale" }) })
|
|
4231
4423
|
] })
|
|
4232
4424
|
] })
|
|
4233
4425
|
] });
|
|
4234
4426
|
}
|
|
4235
4427
|
|
|
4236
4428
|
// src/sale/sync-status.tsx
|
|
4237
|
-
import { useEffect as
|
|
4238
|
-
import { Text as
|
|
4239
|
-
import { jsxs as
|
|
4240
|
-
|
|
4241
|
-
|
|
4242
|
-
|
|
4429
|
+
import { useEffect as useEffect7, useRef as useRef6, useState as useState18 } from "react";
|
|
4430
|
+
import { AccessibilityInfo as AccessibilityInfo2, Platform as Platform3, Text as Text38, View as View59 } from "react-native";
|
|
4431
|
+
import { Fragment as Fragment7, jsx as jsx93, jsxs as jsxs52 } from "react/jsx-runtime";
|
|
4432
|
+
var PULL_NOTICE_TEXT = {
|
|
4433
|
+
unauthorized: {
|
|
4434
|
+
line: () => "Products aren't updating: this till needs to sign in to the online store again.",
|
|
4435
|
+
detail: () => "You can keep selling. Products, prices and stock stay as they were until someone signs in again."
|
|
4436
|
+
},
|
|
4437
|
+
till_update_required: {
|
|
4438
|
+
line: () => "Products aren't updating: this till needs updating.",
|
|
4439
|
+
detail: () => "You can keep selling. Products, prices and stock stay as they were until this till is updated."
|
|
4440
|
+
},
|
|
4441
|
+
unsupported_store: {
|
|
4442
|
+
line: () => "Products aren't updating: the online store needs a software update.",
|
|
4443
|
+
detail: ({ software, minVersion }) => software && minVersion ? `You can keep selling. Ask the store owner to update ${software} to version ${minVersion} or later.` : "You can keep selling. Ask the store owner to update the store's software."
|
|
4444
|
+
},
|
|
4445
|
+
missing_plugin: {
|
|
4446
|
+
line: (pluginName) => `Products aren't updating: the online store is missing ${pluginName}.`,
|
|
4447
|
+
detail: (_notice, pluginName) => `You can keep selling. This till couldn't find ${pluginName} on the online store. Ask the store owner to check that it is installed and switched on, and that the store address in this till's settings is right.`
|
|
4448
|
+
},
|
|
4449
|
+
store_misconfigured: {
|
|
4450
|
+
line: () => "Products aren't updating: a setting on the online store needs changing.",
|
|
4451
|
+
detail: ({ fix }) => fix ? `You can keep selling. Ask the store owner to ${fix}.` : "You can keep selling. Ask the store owner to check the store's settings."
|
|
4452
|
+
}
|
|
4453
|
+
};
|
|
4454
|
+
var PULL_NOTICE_FALLBACK = {
|
|
4455
|
+
line: () => "Products aren't updating.",
|
|
4456
|
+
detail: () => "You can keep selling. Products, prices and stock stay as they were. Restart the app; if it keeps happening, tell the store owner."
|
|
4457
|
+
};
|
|
4458
|
+
var BACKEND_MISSING = "Sales aren't reaching the online store. Keep selling: they're saved on this till and will send by themselves.";
|
|
4459
|
+
var BACKEND_MISSING_SINCE = "Sales haven't reached the online store since {time}. Keep selling: they're saved on this till and will send by themselves.";
|
|
4460
|
+
var TILL_UPDATES_MISSING = "Till updates aren't reaching the online store. Keep selling: they're saved on this till and will send by themselves.";
|
|
4461
|
+
var TILL_UPDATES_MISSING_SINCE = "Till updates haven't reached the online store since {time}. Keep selling: they're saved on this till and will send by themselves.";
|
|
4462
|
+
var BACKEND_MISSING_DETAIL = "This till couldn't find {pluginName} on the online store{lastTime}. Ask the store owner to check that it is installed and switched on, and that the store address in this till's settings is right.";
|
|
4463
|
+
var REFUSED = (n, waiting) => n === 1 ? `1 sale needs attention${waiting} \xB7 The online store refused it. Ask the store owner to look at the till's sync log.` : `${n} sales need attention${waiting} \xB7 The online store refused them. Ask the store owner to look at the till's sync log.`;
|
|
4464
|
+
var REFUSED_DETAIL = "Refused sales stay on this till under Needs attention, each with what to do next.";
|
|
4465
|
+
var SALES_REFUSED = "The online store refused the last send. This till will try again with the next sale, or when the app is reopened.";
|
|
4466
|
+
var TILL_UPDATES_REFUSED = "The online store refused the last send. This till will try again with the next till update.";
|
|
4467
|
+
var count = (n, noun) => `${n} ${noun}${n === 1 ? "" : "s"}`;
|
|
4468
|
+
function useAnnounceOnIos(...texts) {
|
|
4469
|
+
const announced = useRef6(texts);
|
|
4470
|
+
useEffect7(() => {
|
|
4471
|
+
const changed = texts.filter((text, index) => text && text !== announced.current[index]);
|
|
4472
|
+
announced.current = texts;
|
|
4473
|
+
if (changed.length > 0 && Platform3.OS === "ios") AccessibilityInfo2.announceForAccessibility(changed.join(" "));
|
|
4474
|
+
}, texts);
|
|
4475
|
+
}
|
|
4476
|
+
function SyncStatus({ state, registerState, pluginName = "the POS plugin", pullNotice }) {
|
|
4477
|
+
const updates = registerState?.pending ?? 0;
|
|
4478
|
+
const outbox = state.pending === 0 && registerState?.pending ? registerState : state;
|
|
4479
|
+
const [now, setNow] = useState18(Date.now);
|
|
4480
|
+
useEffect7(() => {
|
|
4243
4481
|
setNow(Date.now());
|
|
4244
|
-
if (!
|
|
4482
|
+
if (!outbox.nextAttemptAt) return;
|
|
4245
4483
|
const timer = setInterval(() => setNow(Date.now()), 1e3);
|
|
4246
4484
|
return () => clearInterval(timer);
|
|
4247
|
-
}, [
|
|
4248
|
-
const seconds = Math.max(0, Math.ceil(((
|
|
4249
|
-
const label =
|
|
4250
|
-
|
|
4251
|
-
|
|
4252
|
-
|
|
4485
|
+
}, [outbox.nextAttemptAt]);
|
|
4486
|
+
const seconds = Math.max(0, Math.ceil(((outbox.nextAttemptAt ?? now) - now) / 1e3));
|
|
4487
|
+
const label = [
|
|
4488
|
+
state.pending && count(state.pending, "sale"),
|
|
4489
|
+
updates && count(updates, "till update")
|
|
4490
|
+
].filter(Boolean).join(" and ") + " waiting to sync";
|
|
4491
|
+
const { stuck } = state;
|
|
4492
|
+
const backendMissing = state.backendMissing ?? registerState?.backendMissing;
|
|
4493
|
+
const at = (time) => new Date(time).toLocaleTimeString(void 0, { hour: "numeric", minute: "2-digit" });
|
|
4494
|
+
const backendMissingText = state.pending === 0 && updates > 0 ? registerState?.stuck ? TILL_UPDATES_MISSING_SINCE.replace("{time}", () => at(registerState.stuck.since)) : TILL_UPDATES_MISSING : stuck ? BACKEND_MISSING_SINCE.replace("{time}", () => at(stuck.since)) : BACKEND_MISSING;
|
|
4495
|
+
const upToDate = state.pending === 0 && updates === 0;
|
|
4496
|
+
const sentence = outbox.refused ? ` \xB7 ${outbox === state ? SALES_REFUSED : TILL_UPDATES_REFUSED}` : backendMissing || (state.pending === 0 && updates > 0 ? registerState?.stuck : stuck) ? ` \xB7 ${backendMissingText}` : "";
|
|
4497
|
+
const refused = state.rejected ? REFUSED(state.rejected, upToDate ? "" : `, ${updates ? label : `${state.pending} waiting to sync`}`) : "";
|
|
4498
|
+
const spoken = refused || (upToDate ? "Sales are up to date." : label + sentence);
|
|
4499
|
+
const doing = refused || upToDate || backendMissing || outbox.refused ? "" : outbox.sending ? "Sending\u2026" : outbox.lastRetryReason ? `Retrying in ${seconds} s.` : "";
|
|
4500
|
+
const text = pullNotice && (Object.hasOwn(PULL_NOTICE_TEXT, pullNotice.code) ? PULL_NOTICE_TEXT[pullNotice.code] : PULL_NOTICE_FALLBACK);
|
|
4501
|
+
const notice = pullNotice && text && { line: text.line(pluginName), detail: text.detail(pullNotice, pluginName) };
|
|
4502
|
+
useAnnounceOnIos(notice?.line, spoken);
|
|
4503
|
+
const oneDetail = pullNotice?.code === "missing_plugin" && !!backendMissing;
|
|
4504
|
+
return /* @__PURE__ */ jsxs52(View59, { children: [
|
|
4505
|
+
notice ? /* @__PURE__ */ jsxs52(Fragment7, { children: [
|
|
4506
|
+
/* @__PURE__ */ jsx93(Text38, { accessibilityLiveRegion: "polite", className: "px-4 py-2 text-xs text-muted-foreground", children: notice.line }),
|
|
4507
|
+
oneDetail ? null : /* @__PURE__ */ jsx93(Text38, { className: "px-4 pb-2 text-xs text-muted-foreground", children: notice.detail })
|
|
4508
|
+
] }) : null,
|
|
4509
|
+
/* @__PURE__ */ jsx93(Text38, { accessibilityLabel: spoken, accessibilityLiveRegion: "polite", className: "px-4 py-2 text-xs text-muted-foreground", children: spoken }),
|
|
4510
|
+
doing ? /* @__PURE__ */ jsx93(Text38, { className: "px-4 pb-2 text-xs text-muted-foreground", children: doing }) : null,
|
|
4511
|
+
refused ? /* @__PURE__ */ jsx93(Text38, { className: "px-4 pb-2 text-xs text-muted-foreground", children: REFUSED_DETAIL }) : null,
|
|
4512
|
+
oneDetail && notice ? /* @__PURE__ */ jsx93(Text38, { className: "px-4 pb-2 text-xs text-muted-foreground", children: notice.detail }) : backendMissing ? /* @__PURE__ */ jsx93(Text38, { className: "px-4 pb-2 text-xs text-muted-foreground", children: BACKEND_MISSING_DETAIL.replace("{pluginName}", () => pluginName).replace("{lastTime}", () => upToDate ? " the last time it checked" : "") }) : null
|
|
4253
4513
|
] });
|
|
4254
4514
|
}
|
|
4255
4515
|
|
|
4256
4516
|
// src/sale/orders-list.tsx
|
|
4257
|
-
import { useEffect as
|
|
4258
|
-
import { Pressable as
|
|
4259
|
-
import { formatMoney as formatMoney14 } from "@tallyui/core";
|
|
4517
|
+
import { useEffect as useEffect8, useRef as useRef7, useState as useState19 } from "react";
|
|
4518
|
+
import { Pressable as Pressable29, ScrollView as ScrollView13, Text as Text39, View as View60 } from "react-native";
|
|
4519
|
+
import { formatMoney as formatMoney14, knownWarnings } from "@tallyui/core";
|
|
4260
4520
|
import { needsAttention } from "@tallyui/pos";
|
|
4261
|
-
import { jsx as
|
|
4521
|
+
import { jsx as jsx94, jsxs as jsxs53 } from "react/jsx-runtime";
|
|
4262
4522
|
var STATUS_LABEL = { pending: "Waiting to sync", applied: "Synced", rejected: "Not accepted" };
|
|
4523
|
+
var FIGURE_LABELS = /* @__PURE__ */ new Map([["subtotalMinor", "Subtotal"], ["taxMinor", "Tax"], ["discountMinor", "Discount"]]);
|
|
4524
|
+
var REFUSAL_SENTENCES = /* @__PURE__ */ new Map([
|
|
4525
|
+
["invalid_payload", "The online store refused this sale: this till sent it in a form the store can't read. Ask the store owner to look at the till's sync log."],
|
|
4526
|
+
["unsupported_version", "The online store refused this sale: the store's software is older than this till's. Ask the store owner to update the POS plugin."],
|
|
4527
|
+
["idempotency_mismatch", "The online store has a different sale under this sale's number. Don't send it again; ask the store owner to compare the two."],
|
|
4528
|
+
["store_configuration", "The online store refused this sale: a setting on the store needs changing. Once the store owner fixes it, press Retry."],
|
|
4529
|
+
["platform_error", "The online store refused this sale. Ask the store owner to look at the till's sync log."],
|
|
4530
|
+
["internal_error", "The online store hit a fault in its POS plugin and refused this sale. Ask the store owner to look at the till's sync log."],
|
|
4531
|
+
["insufficient_stock", "The online store refused this sale: it doesn't have enough stock of one of the items."],
|
|
4532
|
+
["unsupported_tax_mode", "The online store refused this sale: its tax settings can't take a sale like this one. Ask the store owner to check them."],
|
|
4533
|
+
["unknown_variant", "The online store refused this sale: that product variation no longer exists."],
|
|
4534
|
+
["invalid_quantity", "The online store refused this sale: a quantity or a discount on it isn't allowed."],
|
|
4535
|
+
["underpaid", "The online store refused this sale: the payments add up to less than the total."],
|
|
4536
|
+
["unsupported_currency", "The online store refused this sale: the store doesn't take this currency."]
|
|
4537
|
+
]);
|
|
4538
|
+
var refusalSentence = (code) => REFUSAL_SENTENCES.get(code ?? "") ?? REFUSAL_SENTENCES.get("platform_error");
|
|
4263
4539
|
function defaultFormatDate2(iso) {
|
|
4264
4540
|
const date = new Date(iso);
|
|
4265
4541
|
return Number.isNaN(date.getTime()) ? iso : new Intl.DateTimeFormat(void 0, { dateStyle: "medium", timeStyle: "short" }).format(date);
|
|
4266
4542
|
}
|
|
4267
|
-
function OrdersList({ orders, onRetry, formatDate = defaultFormatDate2, footer }) {
|
|
4268
|
-
const retrying =
|
|
4269
|
-
const [retryingIds, setRetryingIds] =
|
|
4270
|
-
|
|
4543
|
+
function OrdersList({ orders, onRetry, formatDate = defaultFormatDate2, footer, stuck }) {
|
|
4544
|
+
const retrying = useRef7(/* @__PURE__ */ new Set());
|
|
4545
|
+
const [retryingIds, setRetryingIds] = useState19(/* @__PURE__ */ new Set());
|
|
4546
|
+
useEffect8(() => {
|
|
4271
4547
|
for (const id of retrying.current) {
|
|
4272
4548
|
if (!orders.some((order) => order.id === id && order.syncStatus === "rejected")) retrying.current.delete(id);
|
|
4273
4549
|
}
|
|
4274
4550
|
setRetryingIds(new Set(retrying.current));
|
|
4275
4551
|
}, [orders]);
|
|
4276
|
-
return /* @__PURE__ */
|
|
4277
|
-
[{ title: "Needs attention", orders: needsAttention(orders) }, { title: "Recent", orders }].filter((section) => section.title === "Recent" || section.orders.length > 0).map((section) => /* @__PURE__ */
|
|
4278
|
-
/* @__PURE__ */
|
|
4552
|
+
return /* @__PURE__ */ jsxs53(ScrollView13, { className: "flex-1 bg-background p-4", children: [
|
|
4553
|
+
[{ title: "Needs attention", orders: needsAttention(orders, { stuckCommandIds: stuck?.commandIds }) }, { title: "Recent", orders }].filter((section) => section.title === "Recent" || section.orders.length > 0).map((section) => /* @__PURE__ */ jsxs53(View60, { className: "mb-6 gap-3", children: [
|
|
4554
|
+
/* @__PURE__ */ jsx94(Text39, { accessibilityRole: "header", className: "text-xl font-semibold text-foreground", children: section.title }),
|
|
4279
4555
|
section.orders.map((order) => {
|
|
4280
|
-
const
|
|
4281
|
-
|
|
4282
|
-
|
|
4556
|
+
const count2 = order.lines.reduce((sum, line) => sum + line.quantity, 0);
|
|
4557
|
+
const stuckEntry = order.syncStatus === "pending" ? stuck?.orders.find((entry) => entry.commandId === order.commandId) : void 0;
|
|
4558
|
+
return /* @__PURE__ */ jsxs53(View60, { className: "gap-1 rounded-md border border-border bg-card p-3", children: [
|
|
4559
|
+
/* @__PURE__ */ jsxs53(Text39, { className: "text-foreground", children: [
|
|
4283
4560
|
order.serverRefs?.displayId ? `Order #${order.serverRefs.displayId} \xB7 ` : "",
|
|
4284
|
-
|
|
4561
|
+
count2,
|
|
4285
4562
|
" ",
|
|
4286
|
-
|
|
4563
|
+
count2 === 1 ? "item" : "items"
|
|
4287
4564
|
] }),
|
|
4288
|
-
/* @__PURE__ */
|
|
4565
|
+
/* @__PURE__ */ jsxs53(Text39, { className: "text-muted-foreground", children: [
|
|
4289
4566
|
formatDate(order.createdAt),
|
|
4290
4567
|
" \xB7 ",
|
|
4291
4568
|
formatMoney14({ amount: order.totalMinor, currency: order.currency }),
|
|
4292
4569
|
" \xB7 ",
|
|
4293
4570
|
STATUS_LABEL[order.syncStatus]
|
|
4294
4571
|
] }),
|
|
4295
|
-
|
|
4296
|
-
|
|
4297
|
-
|
|
4298
|
-
|
|
4299
|
-
|
|
4300
|
-
order.lateSessionId !== void 0 ? /* @__PURE__ */ jsx92(Text38, { className: "text-foreground", children: "Taken after the register closed. It is not in that register's closure." }) : null,
|
|
4301
|
-
section.title === "Needs attention" && order.syncStatus === "rejected" ? order.error?.code === "idempotency_mismatch" ? /* @__PURE__ */ jsx92(Text38, { className: "text-foreground", children: "This sale needs checking against the store before it can be sent again." }) : /* @__PURE__ */ jsx92(Pressable27, { accessibilityRole: "button", disabled: retryingIds.has(order.id), onPress: async () => {
|
|
4572
|
+
stuckEntry ? /* @__PURE__ */ jsx94(Text39, { className: "text-destructive", children: `Hasn't reached the online store since ${new Date(stuckEntry.since).toLocaleTimeString(void 0, { hour: "numeric", minute: "2-digit" })}.` }) : null,
|
|
4573
|
+
order.syncStatus === "rejected" ? /* @__PURE__ */ jsx94(Text39, { className: "text-destructive", children: refusalSentence(order.error?.code) }) : null,
|
|
4574
|
+
order.lateSessionId !== void 0 ? /* @__PURE__ */ jsx94(Text39, { className: "text-foreground", children: "Taken after the register closed. It is not in that register's closure." }) : null,
|
|
4575
|
+
order.localWarnings?.map((warning, index) => /* @__PURE__ */ jsx94(Text39, { className: "text-foreground", children: warning.code === "customer_omitted" ? `The customer's ${warning.field} couldn't be sent to the store, so the order isn't linked to them.` : "The terminal's payment reference couldn't be kept; the payment is recorded without it." }, index)),
|
|
4576
|
+
section.title === "Needs attention" && order.syncStatus === "rejected" && order.error?.code !== "idempotency_mismatch" ? /* @__PURE__ */ jsx94(Pressable29, { accessibilityRole: "button", disabled: retryingIds.has(order.id), onPress: async () => {
|
|
4302
4577
|
if (retrying.current.has(order.id)) return;
|
|
4303
4578
|
retrying.current.add(order.id);
|
|
4304
4579
|
setRetryingIds(new Set(retrying.current));
|
|
@@ -4306,8 +4581,8 @@ function OrdersList({ orders, onRetry, formatDate = defaultFormatDate2, footer }
|
|
|
4306
4581
|
retrying.current.delete(order.id);
|
|
4307
4582
|
setRetryingIds(new Set(retrying.current));
|
|
4308
4583
|
}
|
|
4309
|
-
}, className: "rounded-md bg-primary px-4 py-2", children: /* @__PURE__ */
|
|
4310
|
-
order.warnings
|
|
4584
|
+
}, className: "rounded-md bg-primary px-4 py-2", children: /* @__PURE__ */ jsx94(Text39, { className: "text-center font-semibold text-primary-foreground", children: "Retry" }) }) : null,
|
|
4585
|
+
knownWarnings(order.warnings).map((warning, index) => /* @__PURE__ */ jsx94(View60, { className: "border-l-4 border-warning pl-2", children: /* @__PURE__ */ jsx94(Text39, { className: "text-foreground", children: warning.code === "insufficient_stock" ? `Stock short by ${warning.quantity} for ${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 ${formatMoney14({ amount: warning.serverMinor, currency: order.currency })} vs POS ${formatMoney14({ 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 ${formatMoney14({ amount: tillMinor, currency: order.currency })}, store ${formatMoney14({ amount: serverMinor, currency: order.currency })}.`).join(" ")}` : warning.bridgeMinor !== void 0 ? `Store calculated ${formatMoney14({ amount: warning.serverMinor, currency: order.currency })}; a rounding line of ${warning.bridgeMinor > 0 ? "+" : ""}${formatMoney14({ amount: warning.bridgeMinor, currency: order.currency })} brought it to ${formatMoney14({ amount: warning.expectedMinor, currency: order.currency })}` : `Store total ${formatMoney14({ amount: warning.serverMinor, currency: order.currency })} vs POS ${formatMoney14({ amount: warning.expectedMinor, currency: order.currency })}` }) }, index))
|
|
4311
4586
|
] }, order.id);
|
|
4312
4587
|
})
|
|
4313
4588
|
] }, section.title)),
|
|
@@ -4316,10 +4591,10 @@ function OrdersList({ orders, onRetry, formatDate = defaultFormatDate2, footer }
|
|
|
4316
4591
|
}
|
|
4317
4592
|
|
|
4318
4593
|
// src/layout/pos-layout.tsx
|
|
4319
|
-
import { useState as
|
|
4320
|
-
import { Pressable as
|
|
4321
|
-
import { cn as
|
|
4322
|
-
import { Fragment as
|
|
4594
|
+
import { useState as useState20 } from "react";
|
|
4595
|
+
import { Pressable as Pressable30, Text as Text40, View as View61, useWindowDimensions as useWindowDimensions3 } from "react-native";
|
|
4596
|
+
import { cn as cn80 } from "@tallyui/theme";
|
|
4597
|
+
import { Fragment as Fragment8, jsx as jsx95, jsxs as jsxs54 } from "react/jsx-runtime";
|
|
4323
4598
|
function POSLayout({
|
|
4324
4599
|
browseSlot,
|
|
4325
4600
|
cartSlot,
|
|
@@ -4331,40 +4606,40 @@ function POSLayout({
|
|
|
4331
4606
|
}) {
|
|
4332
4607
|
const { width } = useWindowDimensions3();
|
|
4333
4608
|
const layout = layoutProp ?? (width >= breakpoint ? "split" : "stacked");
|
|
4334
|
-
const [activeTab, setActiveTab] =
|
|
4335
|
-
return /* @__PURE__ */
|
|
4336
|
-
headerSlot && /* @__PURE__ */
|
|
4337
|
-
layout === "split" ? /* @__PURE__ */
|
|
4338
|
-
/* @__PURE__ */
|
|
4339
|
-
/* @__PURE__ */
|
|
4340
|
-
] }) : /* @__PURE__ */
|
|
4341
|
-
/* @__PURE__ */
|
|
4342
|
-
/* @__PURE__ */
|
|
4343
|
-
|
|
4609
|
+
const [activeTab, setActiveTab] = useState20("browse");
|
|
4610
|
+
return /* @__PURE__ */ jsxs54(View61, { className: cn80("flex-1 bg-bg", className), ...viewProps, children: [
|
|
4611
|
+
headerSlot && /* @__PURE__ */ jsx95(View61, { className: "border-b border-border", children: headerSlot }),
|
|
4612
|
+
layout === "split" ? /* @__PURE__ */ jsxs54(View61, { className: "flex-1 flex-row", children: [
|
|
4613
|
+
/* @__PURE__ */ jsx95(View61, { className: "flex-[3]", children: browseSlot }),
|
|
4614
|
+
/* @__PURE__ */ jsx95(View61, { className: "flex-[2] border-l border-border", children: cartSlot })
|
|
4615
|
+
] }) : /* @__PURE__ */ jsxs54(Fragment8, { children: [
|
|
4616
|
+
/* @__PURE__ */ jsxs54(View61, { className: "flex-row border-b border-border", children: [
|
|
4617
|
+
/* @__PURE__ */ jsx95(
|
|
4618
|
+
Pressable30,
|
|
4344
4619
|
{
|
|
4345
4620
|
onPress: () => setActiveTab("browse"),
|
|
4346
|
-
className:
|
|
4347
|
-
children: /* @__PURE__ */
|
|
4621
|
+
className: cn80("flex-1 py-3", activeTab === "browse" && "border-b-2 border-primary"),
|
|
4622
|
+
children: /* @__PURE__ */ jsx95(Text40, { className: cn80("text-center text-sm font-semibold", activeTab === "browse" ? "text-primary" : "text-muted-foreground"), children: "Browse" })
|
|
4348
4623
|
}
|
|
4349
4624
|
),
|
|
4350
|
-
/* @__PURE__ */
|
|
4351
|
-
|
|
4625
|
+
/* @__PURE__ */ jsx95(
|
|
4626
|
+
Pressable30,
|
|
4352
4627
|
{
|
|
4353
4628
|
onPress: () => setActiveTab("cart"),
|
|
4354
|
-
className:
|
|
4355
|
-
children: /* @__PURE__ */
|
|
4629
|
+
className: cn80("flex-1 py-3", activeTab === "cart" && "border-b-2 border-primary"),
|
|
4630
|
+
children: /* @__PURE__ */ jsx95(Text40, { className: cn80("text-center text-sm font-semibold", activeTab === "cart" ? "text-primary" : "text-muted-foreground"), children: "Cart" })
|
|
4356
4631
|
}
|
|
4357
4632
|
)
|
|
4358
4633
|
] }),
|
|
4359
|
-
/* @__PURE__ */
|
|
4634
|
+
/* @__PURE__ */ jsx95(View61, { className: "flex-1", children: activeTab === "browse" ? browseSlot : cartSlot })
|
|
4360
4635
|
] })
|
|
4361
4636
|
] });
|
|
4362
4637
|
}
|
|
4363
4638
|
|
|
4364
4639
|
// src/layout/checkout-layout.tsx
|
|
4365
|
-
import { ScrollView as
|
|
4366
|
-
import { cn as
|
|
4367
|
-
import { jsx as
|
|
4640
|
+
import { ScrollView as ScrollView14, View as View62, useWindowDimensions as useWindowDimensions4 } from "react-native";
|
|
4641
|
+
import { cn as cn81 } from "@tallyui/theme";
|
|
4642
|
+
import { jsx as jsx96, jsxs as jsxs55 } from "react/jsx-runtime";
|
|
4368
4643
|
function CheckoutLayout({
|
|
4369
4644
|
summarySlot,
|
|
4370
4645
|
paymentSlot,
|
|
@@ -4376,12 +4651,12 @@ function CheckoutLayout({
|
|
|
4376
4651
|
}) {
|
|
4377
4652
|
const { width } = useWindowDimensions4();
|
|
4378
4653
|
const layout = layoutProp ?? (width >= breakpoint ? "split" : "stacked");
|
|
4379
|
-
return /* @__PURE__ */
|
|
4380
|
-
headerSlot && /* @__PURE__ */
|
|
4381
|
-
layout === "split" ? /* @__PURE__ */
|
|
4382
|
-
/* @__PURE__ */
|
|
4383
|
-
/* @__PURE__ */
|
|
4384
|
-
] }) : /* @__PURE__ */
|
|
4654
|
+
return /* @__PURE__ */ jsxs55(View62, { className: cn81("flex-1 bg-bg", className), ...viewProps, children: [
|
|
4655
|
+
headerSlot && /* @__PURE__ */ jsx96(View62, { className: "border-b border-border", children: headerSlot }),
|
|
4656
|
+
layout === "split" ? /* @__PURE__ */ jsxs55(View62, { className: "flex-1 flex-row", children: [
|
|
4657
|
+
/* @__PURE__ */ jsx96(View62, { className: "flex-1 border-r border-border", children: summarySlot }),
|
|
4658
|
+
/* @__PURE__ */ jsx96(View62, { className: "flex-1", children: paymentSlot })
|
|
4659
|
+
] }) : /* @__PURE__ */ jsx96(ScrollView14, { className: "flex-1", children: /* @__PURE__ */ jsxs55(View62, { className: "gap-4 p-4", children: [
|
|
4385
4660
|
summarySlot,
|
|
4386
4661
|
paymentSlot
|
|
4387
4662
|
] }) })
|
|
@@ -4389,10 +4664,10 @@ function CheckoutLayout({
|
|
|
4389
4664
|
}
|
|
4390
4665
|
|
|
4391
4666
|
// src/layout/settings-layout.tsx
|
|
4392
|
-
import { useState as
|
|
4393
|
-
import { Pressable as
|
|
4394
|
-
import { cn as
|
|
4395
|
-
import { jsx as
|
|
4667
|
+
import { useState as useState21 } from "react";
|
|
4668
|
+
import { Pressable as Pressable31, Text as Text41, View as View63, useWindowDimensions as useWindowDimensions5 } from "react-native";
|
|
4669
|
+
import { cn as cn82 } from "@tallyui/theme";
|
|
4670
|
+
import { jsx as jsx97, jsxs as jsxs56 } from "react/jsx-runtime";
|
|
4396
4671
|
function SettingsLayout({
|
|
4397
4672
|
navSlot,
|
|
4398
4673
|
contentSlot,
|
|
@@ -4404,26 +4679,26 @@ function SettingsLayout({
|
|
|
4404
4679
|
}) {
|
|
4405
4680
|
const { width } = useWindowDimensions5();
|
|
4406
4681
|
const layout = layoutProp ?? (width >= breakpoint ? "split" : "stacked");
|
|
4407
|
-
const [showNav, setShowNav] =
|
|
4408
|
-
return /* @__PURE__ */
|
|
4409
|
-
headerSlot && /* @__PURE__ */
|
|
4410
|
-
layout === "split" ? /* @__PURE__ */
|
|
4411
|
-
/* @__PURE__ */
|
|
4412
|
-
/* @__PURE__ */
|
|
4413
|
-
] }) : /* @__PURE__ */
|
|
4682
|
+
const [showNav, setShowNav] = useState21(false);
|
|
4683
|
+
return /* @__PURE__ */ jsxs56(View63, { className: cn82("flex-1 bg-bg", className), ...viewProps, children: [
|
|
4684
|
+
headerSlot && /* @__PURE__ */ jsx97(View63, { className: "border-b border-border", children: headerSlot }),
|
|
4685
|
+
layout === "split" ? /* @__PURE__ */ jsxs56(View63, { className: "flex-1 flex-row", children: [
|
|
4686
|
+
/* @__PURE__ */ jsx97(View63, { className: "w-64 border-r border-border", children: navSlot }),
|
|
4687
|
+
/* @__PURE__ */ jsx97(View63, { className: "flex-1", children: contentSlot })
|
|
4688
|
+
] }) : /* @__PURE__ */ jsx97(View63, { className: "flex-1", children: showNav ? /* @__PURE__ */ jsxs56(View63, { className: "flex-1", children: [
|
|
4414
4689
|
navSlot,
|
|
4415
|
-
/* @__PURE__ */
|
|
4416
|
-
] }) : /* @__PURE__ */
|
|
4417
|
-
/* @__PURE__ */
|
|
4690
|
+
/* @__PURE__ */ jsx97(Pressable31, { onPress: () => setShowNav(false), className: "border-t border-border p-3", children: /* @__PURE__ */ jsx97(Text41, { className: "text-center text-sm font-medium text-primary", children: "Done" }) })
|
|
4691
|
+
] }) : /* @__PURE__ */ jsxs56(View63, { className: "flex-1", children: [
|
|
4692
|
+
/* @__PURE__ */ jsx97(Pressable31, { onPress: () => setShowNav(true), className: "border-b border-border px-4 py-2", children: /* @__PURE__ */ jsx97(Text41, { className: "text-sm font-medium text-primary", children: "Menu" }) }),
|
|
4418
4693
|
contentSlot
|
|
4419
4694
|
] }) })
|
|
4420
4695
|
] });
|
|
4421
4696
|
}
|
|
4422
4697
|
|
|
4423
4698
|
// src/layout/live-tab-screen.tsx
|
|
4424
|
-
import { Pressable as
|
|
4425
|
-
import { cn as
|
|
4426
|
-
import { jsx as
|
|
4699
|
+
import { Pressable as Pressable32, Text as Text42, View as View64 } from "react-native";
|
|
4700
|
+
import { cn as cn83 } from "@tallyui/theme";
|
|
4701
|
+
import { jsx as jsx98, jsxs as jsxs57 } from "react/jsx-runtime";
|
|
4427
4702
|
function LiveTabScreen({
|
|
4428
4703
|
state,
|
|
4429
4704
|
onUseHere,
|
|
@@ -4440,21 +4715,21 @@ function LiveTabScreen({
|
|
|
4440
4715
|
const body = state === "parked" ? parkedBody : blockedBody;
|
|
4441
4716
|
const buttonLabel = state === "parked" ? useHereLabel : reloadLabel;
|
|
4442
4717
|
const onPress = state === "parked" ? onUseHere : onReload;
|
|
4443
|
-
return /* @__PURE__ */
|
|
4444
|
-
/* @__PURE__ */
|
|
4445
|
-
/* @__PURE__ */
|
|
4446
|
-
/* @__PURE__ */
|
|
4718
|
+
return /* @__PURE__ */ jsxs57(View64, { className: cn83("flex-1 items-center justify-center gap-4 bg-bg p-6", className), ...viewProps, children: [
|
|
4719
|
+
/* @__PURE__ */ jsx98(Text42, { className: "text-center text-lg font-bold text-foreground", children: parkedTitle }),
|
|
4720
|
+
/* @__PURE__ */ jsx98(Text42, { className: "text-center text-sm text-muted-foreground", children: body }),
|
|
4721
|
+
/* @__PURE__ */ jsx98(Pressable32, { onPress, className: "items-center rounded-lg bg-primary px-4 py-3", children: /* @__PURE__ */ jsx98(Text42, { className: "text-sm font-semibold text-primary-foreground", children: buttonLabel }) })
|
|
4447
4722
|
] });
|
|
4448
4723
|
}
|
|
4449
4724
|
|
|
4450
4725
|
// src/layout/store-settings-choice-screen.tsx
|
|
4451
|
-
import { useState as
|
|
4452
|
-
import { Pressable as
|
|
4453
|
-
import { cn as
|
|
4454
|
-
import { jsx as
|
|
4726
|
+
import { useState as useState22 } from "react";
|
|
4727
|
+
import { Pressable as Pressable33, Text as Text43, View as View65 } from "react-native";
|
|
4728
|
+
import { cn as cn84 } from "@tallyui/theme";
|
|
4729
|
+
import { jsx as jsx99, jsxs as jsxs58 } from "react/jsx-runtime";
|
|
4455
4730
|
function useSectionSelection(options, initialValue) {
|
|
4456
4731
|
const preset = options.length === 1 ? options[0].value : options.find((o) => o.value === initialValue)?.value;
|
|
4457
|
-
return
|
|
4732
|
+
return useState22(preset);
|
|
4458
4733
|
}
|
|
4459
4734
|
function defaultCountryName(code, locale) {
|
|
4460
4735
|
try {
|
|
@@ -4500,41 +4775,41 @@ function StoreSettingsChoiceScreen({
|
|
|
4500
4775
|
else if (initial?.channel !== void 0) choice.channel = initial.channel;
|
|
4501
4776
|
onSubmit(choice);
|
|
4502
4777
|
};
|
|
4503
|
-
return /* @__PURE__ */
|
|
4504
|
-
/* @__PURE__ */
|
|
4505
|
-
/* @__PURE__ */
|
|
4506
|
-
/* @__PURE__ */
|
|
4778
|
+
return /* @__PURE__ */ jsxs58(View65, { className: cn84("w-full max-w-[560px] flex-1 self-center gap-6 bg-bg p-6", className), ...viewProps, children: [
|
|
4779
|
+
/* @__PURE__ */ jsxs58(View65, { className: "gap-2", children: [
|
|
4780
|
+
/* @__PURE__ */ jsx99(Text43, { className: "text-lg font-bold text-foreground", children: title }),
|
|
4781
|
+
/* @__PURE__ */ jsx99(Text43, { className: "text-sm text-muted-foreground", children: body })
|
|
4507
4782
|
] }),
|
|
4508
|
-
showRegions && /* @__PURE__ */
|
|
4509
|
-
showCountries && /* @__PURE__ */
|
|
4510
|
-
showChannels && /* @__PURE__ */
|
|
4511
|
-
/* @__PURE__ */
|
|
4512
|
-
|
|
4783
|
+
showRegions && /* @__PURE__ */ jsx99(ChoiceSection, { label: regionLabel, options: regionOptions, selected: region, onSelect: setRegion }),
|
|
4784
|
+
showCountries && /* @__PURE__ */ jsx99(ChoiceSection, { label: countryLabel, options: countryOptions, selected: country, onSelect: setCountry }),
|
|
4785
|
+
showChannels && /* @__PURE__ */ jsx99(ChoiceSection, { label: channelLabel, options: channelOptions, selected: channel, onSelect: setChannel }),
|
|
4786
|
+
/* @__PURE__ */ jsx99(
|
|
4787
|
+
Pressable33,
|
|
4513
4788
|
{
|
|
4514
4789
|
onPress: handleSubmit,
|
|
4515
4790
|
disabled: !complete,
|
|
4516
|
-
className:
|
|
4517
|
-
children: /* @__PURE__ */
|
|
4791
|
+
className: cn84("items-center rounded-lg bg-primary px-4 py-3", !complete && "opacity-50"),
|
|
4792
|
+
children: /* @__PURE__ */ jsx99(Text43, { className: "text-sm font-semibold text-primary-foreground", children: submitLabel })
|
|
4518
4793
|
}
|
|
4519
4794
|
)
|
|
4520
4795
|
] });
|
|
4521
4796
|
}
|
|
4522
4797
|
function ChoiceSection({ label, options, selected, onSelect }) {
|
|
4523
|
-
return /* @__PURE__ */
|
|
4524
|
-
/* @__PURE__ */
|
|
4525
|
-
/* @__PURE__ */
|
|
4798
|
+
return /* @__PURE__ */ jsxs58(View65, { className: "gap-1.5", children: [
|
|
4799
|
+
/* @__PURE__ */ jsx99(Text43, { className: "text-xs font-semibold text-muted-foreground", children: label }),
|
|
4800
|
+
/* @__PURE__ */ jsx99(View65, { className: "rounded-lg border border-border", children: options.map((option, index) => {
|
|
4526
4801
|
const checked = option.value === selected;
|
|
4527
|
-
return /* @__PURE__ */
|
|
4528
|
-
|
|
4802
|
+
return /* @__PURE__ */ jsxs58(
|
|
4803
|
+
Pressable33,
|
|
4529
4804
|
{
|
|
4530
4805
|
onPress: () => onSelect(option.value),
|
|
4531
4806
|
accessibilityRole: "radio",
|
|
4532
4807
|
"aria-checked": checked,
|
|
4533
4808
|
testID: `choice-option-${option.value}`,
|
|
4534
|
-
className:
|
|
4809
|
+
className: cn84("flex-row items-center gap-3 px-4 py-3", index > 0 && "border-t border-border", checked && "bg-primary/10"),
|
|
4535
4810
|
children: [
|
|
4536
|
-
/* @__PURE__ */
|
|
4537
|
-
/* @__PURE__ */
|
|
4811
|
+
/* @__PURE__ */ jsx99(View65, { className: "h-4 w-4 items-center justify-center rounded-full border border-primary", children: checked && /* @__PURE__ */ jsx99(View65, { testID: `choice-option-${option.value}-dot`, className: "h-2.5 w-2.5 rounded-full bg-primary" }) }),
|
|
4812
|
+
/* @__PURE__ */ jsx99(Text43, { className: cn84("text-sm", checked ? "font-semibold text-primary" : "text-foreground"), children: option.label })
|
|
4538
4813
|
]
|
|
4539
4814
|
},
|
|
4540
4815
|
option.value
|
|
@@ -4610,6 +4885,7 @@ export {
|
|
|
4610
4885
|
CustomerCard,
|
|
4611
4886
|
CustomerForm,
|
|
4612
4887
|
CustomerOrderHistory,
|
|
4888
|
+
CustomerPicker,
|
|
4613
4889
|
CustomerSelect,
|
|
4614
4890
|
Dialog,
|
|
4615
4891
|
DialogClose,
|