@tallyui/components 3.8.0 → 3.9.1

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 CHANGED
@@ -1456,16 +1456,29 @@ declare function SyncStatus({ state, registerState, pluginName, pullNotice }: {
1456
1456
  pullNotice?: SyncNotice;
1457
1457
  }): react_jsx_runtime.JSX.Element;
1458
1458
 
1459
+ /** One order from the store's own history (ADR-052 amendment 1), mapped by the app from its platform. */
1460
+ type OrderHistoryRow = {
1461
+ id: string;
1462
+ clientOrderId?: string;
1463
+ reference: string;
1464
+ placedAt: string;
1465
+ totalMinor: number;
1466
+ currency: string;
1467
+ itemCount: number;
1468
+ stateLabel: string;
1469
+ };
1459
1470
  /** The "Needs attention" (when not empty) and "Recent" orders, lifted from medusapos/app's orders screen (ADR-052).
1460
1471
  * `onRetry` is the outbox's `requeue`; `formatDate` replaces the app's date util; `footer` is the app's own content
1461
1472
  * (medusapos: the feedback link). The router and session redirect stay in the app. `stuck` is the outbox's
1462
- * `state.stuck` (`useOrderOutbox`): those pending orders need attention too, each with its own entry's reason and since. */
1463
- declare function OrdersList({ orders, onRetry, formatDate, footer, stuck }: {
1473
+ * `state.stuck` (`useOrderOutbox`): those pending orders need attention too, each with its own entry's reason and since.
1474
+ * `history` adds read-only store order rows to Recent (ADR-052 amendment 1). */
1475
+ declare function OrdersList({ orders, onRetry, formatDate, footer, stuck, history }: {
1464
1476
  orders: PosOrder[];
1465
1477
  onRetry(orderIds: string[]): Promise<number>;
1466
1478
  formatDate?: (iso: string) => string;
1467
1479
  footer?: ReactNode;
1468
1480
  stuck?: OutboxState['stuck'];
1481
+ history?: OrderHistoryRow[];
1469
1482
  }): react_jsx_runtime.JSX.Element;
1470
1483
 
1471
1484
  /** Pass `useParkedSales(drafts)`'s `parked` and `discard`, or your own parked store's list and handlers (`onPark`, `onResume`, `onDiscard`) with the same results. */
@@ -1560,4 +1573,4 @@ interface StoreSettingsChoiceScreenProps extends Omit<ViewProps, 'children'> {
1560
1573
  */
1561
1574
  declare function StoreSettingsChoiceScreen({ choices, initial, onSubmit, countryName, locale, title, body, regionLabel, countryLabel, channelLabel, submitLabel, className, ...viewProps }: StoreSettingsChoiceScreenProps): react_jsx_runtime.JSX.Element;
1562
1575
 
1563
- export { APPROVAL_REQUIRED_TEXT, Accordion, AccordionContent, AccordionItem, AccordionTrigger, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, Avatar, type AvatarProps, Badge, type BadgeProps, Button, type ButtonProps, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Cart, type CartAction, CartBar, CartLine, CartLineActions, type CartLineActionsProps, type CartLineProps, CartNoteInput, type CartNoteInputProps, CartPanel, type CartPanelProps, CartTotal, type CartTotalProps, CashCountInput, type CashCountInputProps, CashTendered, type CashTenderedProps, Catalogue, type CategoryItem, CategoryNav, type CategoryNavProps, ChangeDisplay, type ChangeDisplayProps, ChargeForm, type ChargeFormProps, Checkbox, CheckoutLayout, type CheckoutLayoutProps, type ChipItem, ClosureSheet, type ClosureSheetProps, Collapsible, CollapsibleContent, CollapsibleTrigger, Combobox, ComboboxContent, ComboboxEmpty, ComboboxInput, ComboboxItem, ComboboxTrigger, type ConnectionStatus, ConnectorStatus, type ConnectorStatusProps, ContextMenu, ContextMenuCheckboxItem, ContextMenuContent, ContextMenuGroup, ContextMenuItem, ContextMenuLabel, ContextMenuPortal, ContextMenuRadioGroup, ContextMenuRadioItem, ContextMenuSeparator, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuTrigger, CustomerCard, type CustomerCardProps, CustomerForm, type CustomerFormProps, type CustomerFormValues, CustomerOrderHistory, type CustomerOrderHistoryProps, CustomerPicker, type CustomerPickerProps, CustomerSelect, type CustomerSelectProps, type Denomination, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, DiscountBadge, type DiscountBadgeProps, DiscountChips, DiscountForm, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, FilterChip, FilterChipGroup, type FilterChipGroupProps, type FilterChipProps, HStack, type HStackProps, HoverCard, HoverCardContent, HoverCardTrigger, Icon, IconButton, type IconButtonProps, type IconProps, Input, InputField, InputRoot, type InputRootProps, InputSlot, Label, type LabelProps, LiveTabScreen, type LiveTabScreenProps, type LiveTabScreenState, Loader, type LoaderProps, MovementSheet, type MovementSheetProps, OpenRegisterCard, type OpenRegisterCardProps, OrderCard, type OrderCardProps, OrderDetail, type OrderDetailLineItem, type OrderDetailProps, OrderList, type OrderListProps, type OrderStatus, OrderStatusBadge, type OrderStatusBadgeProps, OrderSummary, OrderSummaryLine, type OrderSummaryLineProps, type OrderSummaryPayment, type OrderSummaryProps, OrdersList, POSLayout, type POSLayoutProps, ParkedSales, type ParkedSalesProps, type PaymentMethod, PaymentMethodCard, type PaymentMethodCardProps, PaymentSelector, type PaymentSelectorProps, Popover, PopoverContent, PopoverTrigger, PriceForm, ProductCard, type ProductCardProps, ProductGrid, type ProductGridProps, ProductImage, type ProductImageProps, ProductList, type ProductListProps, ProductPrice, type ProductPriceProps, ProductSku, type ProductSkuProps, ProductStockBadge, type ProductStockBadgeProps, ProductTable, type ProductTableColumn, type ProductTableProps, ProductTitle, type ProductTitleProps, ProductVariantPicker, type ProductVariantPickerProps, Progress, type ProgressProps, QuantityStepper, type QuantityStepperProps, RadioGroup, RadioGroupItem, Receipt, type ReceiptItem, ReceiptPreview, type ReceiptPreviewProps, RegisterBar, type RegisterBarPill, type RegisterBarProps, RegisterColumn, type RegisterColumnProps, RegisterCount, type RegisterCountProps, RegisterOpenClose, type RegisterOpenCloseProps, RegisterPanel, type RegisterPanelProps, RegisterPicker, type RegisterPickerProps, type RegisterPickerRegister, RegisterSummary, type RegisterSummaryProps, SearchIcon, SearchInput, type SearchInputProps, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectSeparator, SelectTrigger, SelectValue, Separator, type SeparatorProps, SettingsGroup, type SettingsGroupProps, SettingsLayout, type SettingsLayoutProps, SettingsRow, type SettingsRowProps, Slider, type SliderProps, SplitTender, StoreSettingsChoiceScreen, type StoreSettingsChoiceScreenProps, type SvgIconProps, Switch, SyncStatus, Table, TableBody, TableCell, TableFooter, TableHead, TableHeader, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, Tender, Text, type TextProps, Textarea, type TextareaProps, Toast, ToastClose, ToastDescription, type ToastProps, ToastTitle, Toggle, ToggleGroup, ToggleGroupItem, type ToggleGroupItemProps, type ToggleGroupProps, type ToggleProps, Tooltip, TooltipContent, TooltipTrigger, type TransactionSummary, VStack, type VStackProps, type VariantOption, ViewToggle, type ViewToggleProps, XIcon, avatarVariants, badgeTextVariants, badgeVariants, buttonTextVariants, buttonVariants, createSvgIcon, defaultProductColumns, describeRegisterBarPill, discountLabel, formatStockSyncTime, hstackVariants, iconButtonVariants, iconVariants, injectPrintStyle, loaderVariants, orderReference, parseDiscount, parsePrice, textVariants, toastVariants, toggleTextVariants, toggleVariants, useDefaultProductColumns, useInputContext, vstackVariants };
1576
+ export { APPROVAL_REQUIRED_TEXT, Accordion, AccordionContent, AccordionItem, AccordionTrigger, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, Avatar, type AvatarProps, Badge, type BadgeProps, Button, type ButtonProps, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Cart, type CartAction, CartBar, CartLine, CartLineActions, type CartLineActionsProps, type CartLineProps, CartNoteInput, type CartNoteInputProps, CartPanel, type CartPanelProps, CartTotal, type CartTotalProps, CashCountInput, type CashCountInputProps, CashTendered, type CashTenderedProps, Catalogue, type CategoryItem, CategoryNav, type CategoryNavProps, ChangeDisplay, type ChangeDisplayProps, ChargeForm, type ChargeFormProps, Checkbox, CheckoutLayout, type CheckoutLayoutProps, type ChipItem, ClosureSheet, type ClosureSheetProps, Collapsible, CollapsibleContent, CollapsibleTrigger, Combobox, ComboboxContent, ComboboxEmpty, ComboboxInput, ComboboxItem, ComboboxTrigger, type ConnectionStatus, ConnectorStatus, type ConnectorStatusProps, ContextMenu, ContextMenuCheckboxItem, ContextMenuContent, ContextMenuGroup, ContextMenuItem, ContextMenuLabel, ContextMenuPortal, ContextMenuRadioGroup, ContextMenuRadioItem, ContextMenuSeparator, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuTrigger, CustomerCard, type CustomerCardProps, CustomerForm, type CustomerFormProps, type CustomerFormValues, CustomerOrderHistory, type CustomerOrderHistoryProps, CustomerPicker, type CustomerPickerProps, CustomerSelect, type CustomerSelectProps, type Denomination, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, DiscountBadge, type DiscountBadgeProps, DiscountChips, DiscountForm, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, FilterChip, FilterChipGroup, type FilterChipGroupProps, type FilterChipProps, HStack, type HStackProps, HoverCard, HoverCardContent, HoverCardTrigger, Icon, IconButton, type IconButtonProps, type IconProps, Input, InputField, InputRoot, type InputRootProps, InputSlot, Label, type LabelProps, LiveTabScreen, type LiveTabScreenProps, type LiveTabScreenState, Loader, type LoaderProps, MovementSheet, type MovementSheetProps, OpenRegisterCard, type OpenRegisterCardProps, OrderCard, type OrderCardProps, OrderDetail, type OrderDetailLineItem, type OrderDetailProps, type OrderHistoryRow, OrderList, type OrderListProps, type OrderStatus, OrderStatusBadge, type OrderStatusBadgeProps, OrderSummary, OrderSummaryLine, type OrderSummaryLineProps, type OrderSummaryPayment, type OrderSummaryProps, OrdersList, POSLayout, type POSLayoutProps, ParkedSales, type ParkedSalesProps, type PaymentMethod, PaymentMethodCard, type PaymentMethodCardProps, PaymentSelector, type PaymentSelectorProps, Popover, PopoverContent, PopoverTrigger, PriceForm, ProductCard, type ProductCardProps, ProductGrid, type ProductGridProps, ProductImage, type ProductImageProps, ProductList, type ProductListProps, ProductPrice, type ProductPriceProps, ProductSku, type ProductSkuProps, ProductStockBadge, type ProductStockBadgeProps, ProductTable, type ProductTableColumn, type ProductTableProps, ProductTitle, type ProductTitleProps, ProductVariantPicker, type ProductVariantPickerProps, Progress, type ProgressProps, QuantityStepper, type QuantityStepperProps, RadioGroup, RadioGroupItem, Receipt, type ReceiptItem, ReceiptPreview, type ReceiptPreviewProps, RegisterBar, type RegisterBarPill, type RegisterBarProps, RegisterColumn, type RegisterColumnProps, RegisterCount, type RegisterCountProps, RegisterOpenClose, type RegisterOpenCloseProps, RegisterPanel, type RegisterPanelProps, RegisterPicker, type RegisterPickerProps, type RegisterPickerRegister, RegisterSummary, type RegisterSummaryProps, SearchIcon, SearchInput, type SearchInputProps, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectSeparator, SelectTrigger, SelectValue, Separator, type SeparatorProps, SettingsGroup, type SettingsGroupProps, SettingsLayout, type SettingsLayoutProps, SettingsRow, type SettingsRowProps, Slider, type SliderProps, SplitTender, StoreSettingsChoiceScreen, type StoreSettingsChoiceScreenProps, type SvgIconProps, Switch, SyncStatus, Table, TableBody, TableCell, TableFooter, TableHead, TableHeader, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, Tender, Text, type TextProps, Textarea, type TextareaProps, Toast, ToastClose, ToastDescription, type ToastProps, ToastTitle, Toggle, ToggleGroup, ToggleGroupItem, type ToggleGroupItemProps, type ToggleGroupProps, type ToggleProps, Tooltip, TooltipContent, TooltipTrigger, type TransactionSummary, VStack, type VStackProps, type VariantOption, ViewToggle, type ViewToggleProps, XIcon, avatarVariants, badgeTextVariants, badgeVariants, buttonTextVariants, buttonVariants, createSvgIcon, defaultProductColumns, describeRegisterBarPill, discountLabel, formatStockSyncTime, hstackVariants, iconButtonVariants, iconVariants, injectPrintStyle, loaderVariants, orderReference, parseDiscount, parsePrice, textVariants, toastVariants, toggleTextVariants, toggleVariants, useDefaultProductColumns, useInputContext, vstackVariants };
package/dist/index.js CHANGED
@@ -5226,7 +5226,7 @@ function defaultFormatDate2(iso) {
5226
5226
  const date = new Date(iso);
5227
5227
  return Number.isNaN(date.getTime()) ? iso : new Intl.DateTimeFormat(void 0, { dateStyle: "medium", timeStyle: "short" }).format(date);
5228
5228
  }
5229
- function OrdersList({ orders, onRetry, formatDate = defaultFormatDate2, footer, stuck }) {
5229
+ function OrdersList({ orders, onRetry, formatDate = defaultFormatDate2, footer, stuck, history }) {
5230
5230
  const retrying = useRef8(/* @__PURE__ */ new Set());
5231
5231
  const [retryingIds, setRetryingIds] = useState24(/* @__PURE__ */ new Set());
5232
5232
  const [expanded, setExpanded] = useState24(/* @__PURE__ */ new Set());
@@ -5236,11 +5236,32 @@ function OrdersList({ orders, onRetry, formatDate = defaultFormatDate2, footer,
5236
5236
  }
5237
5237
  setRetryingIds(new Set(retrying.current));
5238
5238
  }, [orders]);
5239
+ const shown = (history ?? []).filter((row) => row.clientOrderId === void 0 || !orders.some((order) => order.id === row.clientOrderId));
5240
+ const recent = shown.length === 0 ? orders : [...orders, ...shown].sort((a, b) => {
5241
+ const aTime = Date.parse("placedAt" in a ? a.placedAt : a.createdAt);
5242
+ const bTime = Date.parse("placedAt" in b ? b.placedAt : b.createdAt);
5243
+ if (Number.isNaN(aTime)) return Number.isNaN(bTime) ? 0 : 1;
5244
+ if (Number.isNaN(bTime)) return -1;
5245
+ return bTime - aTime;
5246
+ });
5239
5247
  return /* @__PURE__ */ jsxs58(ScrollView13, { className: "flex-1 bg-background p-4", children: [
5240
- [{ title: "Needs attention", orders: needsAttention(orders, { stuckCommandIds: stuck?.commandIds }) }, { title: "Recent", orders }].filter((section) => section.title === "Recent" || section.orders.length > 0).map((section) => /* @__PURE__ */ jsxs58(View65, { className: "mb-6 gap-3", children: [
5248
+ [{ title: "Needs attention", orders: needsAttention(orders, { stuckCommandIds: stuck?.commandIds }) }, { title: "Recent", orders: recent }].filter((section) => section.title === "Recent" || section.orders.length > 0).map((section) => /* @__PURE__ */ jsxs58(View65, { className: "mb-6 gap-3", children: [
5241
5249
  /* @__PURE__ */ jsx100(Text43, { accessibilityRole: "header", className: "text-xl font-semibold text-foreground", children: section.title }),
5242
- section.title === "Recent" && orders.length === 0 ? /* @__PURE__ */ jsx100(Text43, { testID: "orders-empty", className: "text-muted-foreground", children: "No sales yet. Completed sales appear here." }) : null,
5250
+ section.title === "Recent" && orders.length === 0 && shown.length === 0 ? /* @__PURE__ */ jsx100(Text43, { testID: "orders-empty", className: "text-muted-foreground", children: "No sales yet. Completed sales appear here." }) : null,
5243
5251
  section.orders.map((order) => {
5252
+ if ("placedAt" in order) {
5253
+ const row = order;
5254
+ return /* @__PURE__ */ jsxs58(View65, { testID: `history-row-${row.id}`, className: "gap-1 rounded-md border border-border bg-card p-3", children: [
5255
+ /* @__PURE__ */ jsx100(Text43, { className: "text-foreground", children: `Order ${row.reference} \xB7 ${row.itemCount} ${row.itemCount === 1 ? "item" : "items"}` }),
5256
+ /* @__PURE__ */ jsxs58(Text43, { className: "text-muted-foreground", children: [
5257
+ formatDate(row.placedAt),
5258
+ " \xB7 ",
5259
+ formatMoney17({ amount: row.totalMinor, currency: row.currency }),
5260
+ " \xB7 ",
5261
+ row.stateLabel
5262
+ ] })
5263
+ ] }, `history:${row.id}`);
5264
+ }
5244
5265
  const count2 = order.lines.reduce((sum, line) => sum + line.quantity, 0);
5245
5266
  const key = `${section.title}:${order.id}`;
5246
5267
  const isExpanded = expanded.has(key);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tallyui/components",
3
- "version": "3.8.0",
3
+ "version": "3.9.1",
4
4
  "type": "module",
5
5
  "description": "Universal POS UI components for Tally UI",
6
6
  "main": "./dist/index.js",
@@ -10,7 +10,8 @@
10
10
  ".": {
11
11
  "types": "./dist/index.d.ts",
12
12
  "import": "./dist/index.js",
13
- "source": "./src/index.ts"
13
+ "source": "./src/index.ts",
14
+ "default": "./dist/index.js"
14
15
  }
15
16
  },
16
17
  "files": [
@@ -27,22 +28,22 @@
27
28
  "directory": "packages/components"
28
29
  },
29
30
  "peerDependencies": {
30
- "@tallyui/core": "^3.8.0",
31
- "@tallyui/primitives": "^3.8.0",
32
- "@tallyui/theme": "^3.8.0",
31
+ "@tallyui/core": "^3.9.1",
32
+ "@tallyui/primitives": "^3.9.1",
33
+ "@tallyui/theme": "^3.9.1",
33
34
  "react": ">=18",
34
35
  "react-native": ">=0.74",
35
36
  "react-native-svg": ">=15"
36
37
  },
37
38
  "dependencies": {
38
39
  "class-variance-authority": "^0.7.1",
39
- "@tallyui/pos": "3.8.0"
40
+ "@tallyui/pos": "3.9.1"
40
41
  },
41
42
  "devDependencies": {
42
- "@tallyui/connector-medusa": "3.8.0",
43
- "@tallyui/connector-vendure": "3.8.0",
44
- "@tallyui/connector-woocommerce": "3.8.0",
45
- "@tallyui/mock-api": "3.8.0",
43
+ "@tallyui/connector-medusa": "3.9.1",
44
+ "@tallyui/connector-vendure": "3.9.1",
45
+ "@tallyui/connector-woocommerce": "3.9.1",
46
+ "@tallyui/mock-api": "3.9.1",
46
47
  "@types/react": ">=18",
47
48
  "react": "^19.2.4",
48
49
  "react-native-svg": "15.12.1",
package/src/index.ts CHANGED
@@ -164,7 +164,7 @@ export {
164
164
  Cart, CartBar, Tender, SplitTender, DiscountForm, DiscountChips, parseDiscount, discountLabel,
165
165
  PriceForm, parsePrice,
166
166
  ChargeForm, type ChargeFormProps,
167
- Catalogue, formatStockSyncTime, Receipt, injectPrintStyle, SyncStatus, OrdersList, orderReference,
167
+ Catalogue, formatStockSyncTime, Receipt, injectPrintStyle, SyncStatus, OrdersList, type OrderHistoryRow, orderReference,
168
168
  ParkedSales, type ParkedSalesProps,
169
169
  } from './sale';
170
170
 
package/src/sale/index.ts CHANGED
@@ -10,5 +10,5 @@ export { Receipt } from './receipt';
10
10
  export { orderReference } from './order-reference';
11
11
  export { injectPrintStyle } from './print-style';
12
12
  export { SyncStatus } from './sync-status';
13
- export { OrdersList } from './orders-list';
13
+ export { OrdersList, type OrderHistoryRow } from './orders-list';
14
14
  export { ParkedSales, type ParkedSalesProps } from './parked-sales';
@@ -5,6 +5,12 @@ import { needsAttention, type OutboxState, type PosOrder } from '@tallyui/pos';
5
5
  import { orderReference } from './order-reference';
6
6
  import { sinceText } from './since-text';
7
7
 
8
+ /** One order from the store's own history (ADR-052 amendment 1), mapped by the app from its platform. */
9
+ export type OrderHistoryRow = {
10
+ id: string; clientOrderId?: string; reference: string; placedAt: string;
11
+ totalMinor: number; currency: string; itemCount: number; stateLabel: string;
12
+ };
13
+
8
14
  const STATUS_LABEL = { pending: 'Waiting to sync', applied: 'Synced', rejected: 'Not accepted' };
9
15
  /** `figures_mismatch`'s labels; a field a newer store sends that isn't here is shown by its raw name. */
10
16
  const FIGURE_LABELS = new Map([['subtotalMinor', 'Subtotal'], ['taxMinor', 'Tax'], ['discountMinor', 'Discount']]);
@@ -36,10 +42,12 @@ function defaultFormatDate(iso: string) {
36
42
  /** The "Needs attention" (when not empty) and "Recent" orders, lifted from medusapos/app's orders screen (ADR-052).
37
43
  * `onRetry` is the outbox's `requeue`; `formatDate` replaces the app's date util; `footer` is the app's own content
38
44
  * (medusapos: the feedback link). The router and session redirect stay in the app. `stuck` is the outbox's
39
- * `state.stuck` (`useOrderOutbox`): those pending orders need attention too, each with its own entry's reason and since. */
40
- export function OrdersList({ orders, onRetry, formatDate = defaultFormatDate, footer, stuck }: {
45
+ * `state.stuck` (`useOrderOutbox`): those pending orders need attention too, each with its own entry's reason and since.
46
+ * `history` adds read-only store order rows to Recent (ADR-052 amendment 1). */
47
+ export function OrdersList({ orders, onRetry, formatDate = defaultFormatDate, footer, stuck, history }: {
41
48
  orders: PosOrder[]; onRetry(orderIds: string[]): Promise<number>; formatDate?: (iso: string) => string; footer?: ReactNode;
42
49
  stuck?: OutboxState['stuck'];
50
+ history?: OrderHistoryRow[];
43
51
  }) {
44
52
  const retrying = useRef(new Set<string>());
45
53
  const [retryingIds, setRetryingIds] = useState(new Set<string>());
@@ -50,12 +58,27 @@ export function OrdersList({ orders, onRetry, formatDate = defaultFormatDate, fo
50
58
  }
51
59
  setRetryingIds(new Set(retrying.current));
52
60
  }, [orders]);
61
+ const shown = (history ?? []).filter((row) => row.clientOrderId === undefined || !orders.some((order) => order.id === row.clientOrderId));
62
+ const recent = shown.length === 0 ? orders : [...orders, ...shown].sort((a, b) => {
63
+ const aTime = Date.parse('placedAt' in a ? a.placedAt : a.createdAt);
64
+ const bTime = Date.parse('placedAt' in b ? b.placedAt : b.createdAt);
65
+ if (Number.isNaN(aTime)) return Number.isNaN(bTime) ? 0 : 1;
66
+ if (Number.isNaN(bTime)) return -1;
67
+ return bTime - aTime;
68
+ });
53
69
  return <ScrollView className="flex-1 bg-background p-4">
54
- {[{ title: 'Needs attention', orders: needsAttention(orders, { stuckCommandIds: stuck?.commandIds }) }, { title: 'Recent', orders }].filter((section) => section.title === 'Recent' || section.orders.length > 0).map((section) => (
70
+ {[{ title: 'Needs attention', orders: needsAttention(orders, { stuckCommandIds: stuck?.commandIds }) }, { title: 'Recent', orders: recent }].filter((section) => section.title === 'Recent' || section.orders.length > 0).map((section) => (
55
71
  <View key={section.title} className="mb-6 gap-3">
56
72
  <Text accessibilityRole="header" className="text-xl font-semibold text-foreground">{section.title}</Text>
57
- {section.title === 'Recent' && orders.length === 0 ? <Text testID="orders-empty" className="text-muted-foreground">No sales yet. Completed sales appear here.</Text> : null}
73
+ {section.title === 'Recent' && orders.length === 0 && shown.length === 0 ? <Text testID="orders-empty" className="text-muted-foreground">No sales yet. Completed sales appear here.</Text> : null}
58
74
  {section.orders.map((order) => {
75
+ if ('placedAt' in order) {
76
+ const row = order;
77
+ return <View key={`history:${row.id}`} testID={`history-row-${row.id}`} className="gap-1 rounded-md border border-border bg-card p-3">
78
+ <Text className="text-foreground">{`Order ${row.reference} · ${row.itemCount} ${row.itemCount === 1 ? 'item' : 'items'}`}</Text>
79
+ <Text className="text-muted-foreground">{formatDate(row.placedAt)} · {formatMoney({ amount: row.totalMinor, currency: row.currency })} · {row.stateLabel}</Text>
80
+ </View>;
81
+ }
59
82
  const count = order.lines.reduce((sum, line) => sum + line.quantity, 0);
60
83
  const key = `${section.title}:${order.id}`;
61
84
  const isExpanded = expanded.has(key);