@retalia/pos-components 0.0.4 → 0.0.5

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.
Files changed (45) hide show
  1. package/fesm2022/retalia-pos-components.mjs +1089 -0
  2. package/fesm2022/retalia-pos-components.mjs.map +1 -0
  3. package/package.json +39 -17
  4. package/types/retalia-pos-components.d.ts +300 -0
  5. package/eslint.config.js +0 -32
  6. package/ng-package.json +0 -14
  7. package/src/lib/basket/pos-basket.html +0 -124
  8. package/src/lib/basket/pos-basket.scss +0 -285
  9. package/src/lib/basket/pos-basket.spec.ts +0 -198
  10. package/src/lib/basket/pos-basket.stories.ts +0 -114
  11. package/src/lib/basket/pos-basket.ts +0 -142
  12. package/src/lib/item-entry/pos-item-entry.html +0 -41
  13. package/src/lib/item-entry/pos-item-entry.scss +0 -145
  14. package/src/lib/item-entry/pos-item-entry.spec.ts +0 -123
  15. package/src/lib/item-entry/pos-item-entry.stories.ts +0 -31
  16. package/src/lib/item-entry/pos-item-entry.ts +0 -81
  17. package/src/lib/login/pos-login.html +0 -82
  18. package/src/lib/login/pos-login.scss +0 -238
  19. package/src/lib/login/pos-login.spec.ts +0 -89
  20. package/src/lib/login/pos-login.stories.ts +0 -36
  21. package/src/lib/login/pos-login.ts +0 -150
  22. package/src/lib/receipt/pos-receipt.html +0 -116
  23. package/src/lib/receipt/pos-receipt.scss +0 -367
  24. package/src/lib/receipt/pos-receipt.spec.ts +0 -188
  25. package/src/lib/receipt/pos-receipt.stories.ts +0 -163
  26. package/src/lib/receipt/pos-receipt.ts +0 -129
  27. package/src/lib/tender/pos-tender.html +0 -79
  28. package/src/lib/tender/pos-tender.scss +0 -318
  29. package/src/lib/tender/pos-tender.spec.ts +0 -150
  30. package/src/lib/tender/pos-tender.stories.ts +0 -47
  31. package/src/lib/tender/pos-tender.ts +0 -154
  32. package/src/lib/tokens/pos-theme-css.spec.ts +0 -75
  33. package/src/lib/tokens/pos-theme-css.ts +0 -123
  34. package/src/lib/tokens/pos-token-catalog.ts +0 -514
  35. package/src/lib/tokens/pos-tokens.html +0 -351
  36. package/src/lib/tokens/pos-tokens.scss +0 -437
  37. package/src/lib/tokens/pos-tokens.spec.ts +0 -164
  38. package/src/lib/tokens/pos-tokens.stories.ts +0 -22
  39. package/src/lib/tokens/pos-tokens.ts +0 -208
  40. package/src/public-api.ts +0 -37
  41. package/tsconfig.lib.json +0 -14
  42. package/tsconfig.lib.prod.json +0 -11
  43. package/tsconfig.spec.json +0 -11
  44. /package/{src/styles → styles}/styles.css +0 -0
  45. /package/{src/styles → styles}/tokens.css +0 -0
@@ -0,0 +1,300 @@
1
+ import * as _angular_core from '@angular/core';
2
+
3
+ type PosLoginIntent = {
4
+ readonly type: 'login.key';
5
+ readonly key: string;
6
+ } | {
7
+ readonly type: 'login.backspace';
8
+ } | {
9
+ readonly type: 'login.next';
10
+ readonly clerkNumber: string;
11
+ } | {
12
+ readonly type: 'login.submit';
13
+ readonly clerkNumber: string;
14
+ readonly password: string;
15
+ } | {
16
+ readonly type: 'login.back';
17
+ };
18
+ /** Display-only login/session state from the host envelope — not an API DTO. */
19
+ type PosLoginSessionStatus = 'signedOut' | 'busy' | 'signedIn';
20
+ interface PosLoginSessionState {
21
+ readonly status: PosLoginSessionStatus;
22
+ readonly displayName?: string;
23
+ }
24
+ type LoginStage = 'clerkNumber' | 'password';
25
+ declare class PosLogin {
26
+ readonly errorMessage: _angular_core.InputSignal<string>;
27
+ readonly session: _angular_core.InputSignal<PosLoginSessionState>;
28
+ readonly titleClerkNumber: _angular_core.InputSignal<string>;
29
+ readonly titleClerkPassword: _angular_core.InputSignal<string>;
30
+ readonly nextLabel: _angular_core.InputSignal<string>;
31
+ readonly loginLabel: _angular_core.InputSignal<string>;
32
+ readonly action: _angular_core.OutputEmitterRef<PosLoginIntent>;
33
+ protected readonly keypadRows: readonly (readonly string[])[];
34
+ protected readonly inputValue: _angular_core.WritableSignal<string>;
35
+ protected readonly stage: _angular_core.WritableSignal<LoginStage>;
36
+ private readonly clerkNumber;
37
+ protected readonly title: _angular_core.Signal<string>;
38
+ protected readonly maskInput: _angular_core.Signal<boolean>;
39
+ protected readonly showBack: _angular_core.Signal<boolean>;
40
+ protected readonly primaryLabel: _angular_core.Signal<string>;
41
+ protected readonly primaryEnabled: _angular_core.Signal<boolean>;
42
+ protected readonly interactionLocked: _angular_core.Signal<boolean>;
43
+ protected readonly sessionStatusText: _angular_core.Signal<string>;
44
+ protected onKeypad(key: string): void;
45
+ protected onPrimary(): void;
46
+ protected onBack(): void;
47
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<PosLogin, never>;
48
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<PosLogin, "pos-login", never, { "errorMessage": { "alias": "errorMessage"; "required": false; "isSignal": true; }; "session": { "alias": "session"; "required": false; "isSignal": true; }; "titleClerkNumber": { "alias": "titleClerkNumber"; "required": false; "isSignal": true; }; "titleClerkPassword": { "alias": "titleClerkPassword"; "required": false; "isSignal": true; }; "nextLabel": { "alias": "nextLabel"; "required": false; "isSignal": true; }; "loginLabel": { "alias": "loginLabel"; "required": false; "isSignal": true; }; }, { "action": "action"; }, never, never, true, never>;
49
+ }
50
+
51
+ type PosBasketIntent = {
52
+ readonly type: 'basket.changeQuantity';
53
+ readonly lineId: number;
54
+ readonly qty: number;
55
+ } | {
56
+ readonly type: 'basket.voidLine';
57
+ readonly lineId: number;
58
+ } | {
59
+ readonly type: 'basket.clear';
60
+ };
61
+ /** Display-only VAT from the host envelope — not calculated here. */
62
+ interface PosBasketVat {
63
+ readonly rate: number;
64
+ readonly amount: number;
65
+ readonly included: boolean;
66
+ }
67
+ /** Display-only basket line from the host envelope — not an API DTO. */
68
+ interface PosBasketLine {
69
+ readonly lineId: number;
70
+ readonly sku: string;
71
+ readonly name: string;
72
+ readonly qty: number;
73
+ readonly unitPrice: number;
74
+ readonly lineTotal: number;
75
+ readonly vat: PosBasketVat;
76
+ readonly struckThrough: boolean;
77
+ }
78
+ /** Display-only totals from the host envelope — not calculated here. */
79
+ interface PosBasketTotals {
80
+ readonly gross: number;
81
+ readonly net: number;
82
+ readonly vat: number;
83
+ readonly discount: number;
84
+ readonly due: number;
85
+ readonly currency: string;
86
+ }
87
+ declare class PosBasket {
88
+ readonly lines: _angular_core.InputSignal<readonly PosBasketLine[]>;
89
+ readonly totals: _angular_core.InputSignal<PosBasketTotals>;
90
+ readonly disabled: _angular_core.InputSignal<boolean>;
91
+ readonly title: _angular_core.InputSignal<string>;
92
+ readonly emptyMessage: _angular_core.InputSignal<string>;
93
+ readonly clearLabel: _angular_core.InputSignal<string>;
94
+ readonly action: _angular_core.OutputEmitterRef<PosBasketIntent>;
95
+ protected readonly hasLines: _angular_core.Signal<boolean>;
96
+ protected readonly canClear: _angular_core.Signal<boolean>;
97
+ protected formatMoney(amount: number): string;
98
+ protected canChangeQuantity(line: PosBasketLine): boolean;
99
+ protected canDecrement(line: PosBasketLine): boolean;
100
+ protected canVoid(line: PosBasketLine): boolean;
101
+ protected onIncrement(line: PosBasketLine): void;
102
+ protected onDecrement(line: PosBasketLine): void;
103
+ protected onVoid(line: PosBasketLine): void;
104
+ protected onClear(): void;
105
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<PosBasket, never>;
106
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<PosBasket, "pos-basket", never, { "lines": { "alias": "lines"; "required": false; "isSignal": true; }; "totals": { "alias": "totals"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "title": { "alias": "title"; "required": false; "isSignal": true; }; "emptyMessage": { "alias": "emptyMessage"; "required": false; "isSignal": true; }; "clearLabel": { "alias": "clearLabel"; "required": false; "isSignal": true; }; }, { "action": "action"; }, never, never, true, never>;
107
+ }
108
+
109
+ type PosItemEntryIntent = {
110
+ readonly type: 'itemEntry.submit';
111
+ readonly reference: string;
112
+ };
113
+ declare class PosItemEntry {
114
+ readonly disabled: _angular_core.InputSignal<boolean>;
115
+ readonly errorMessage: _angular_core.InputSignal<string>;
116
+ readonly autofocus: _angular_core.InputSignal<boolean>;
117
+ readonly label: _angular_core.InputSignal<string>;
118
+ readonly placeholder: _angular_core.InputSignal<string>;
119
+ readonly addLabel: _angular_core.InputSignal<string>;
120
+ readonly action: _angular_core.OutputEmitterRef<{
121
+ readonly type: "itemEntry.submit";
122
+ readonly reference: string;
123
+ }>;
124
+ private readonly itemInput;
125
+ protected readonly reference: _angular_core.WritableSignal<string>;
126
+ protected readonly canSubmit: _angular_core.Signal<boolean>;
127
+ constructor();
128
+ protected onInput(event: Event): void;
129
+ protected onSubmit(event: Event): void;
130
+ private focusInput;
131
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<PosItemEntry, never>;
132
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<PosItemEntry, "pos-item-entry", never, { "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "errorMessage": { "alias": "errorMessage"; "required": false; "isSignal": true; }; "autofocus": { "alias": "autofocus"; "required": false; "isSignal": true; }; "label": { "alias": "label"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "addLabel": { "alias": "addLabel"; "required": false; "isSignal": true; }; }, { "action": "action"; }, never, never, true, never>;
133
+ }
134
+
135
+ type PosTenderIntent = {
136
+ readonly type: 'tender.cash';
137
+ readonly amount: number;
138
+ };
139
+ declare class PosTender {
140
+ /** Display-only amount due from the host envelope — not calculated here. */
141
+ readonly amountDue: _angular_core.InputSignal<number>;
142
+ /** Display-only change due from the host envelope — not calculated here. */
143
+ readonly changeDue: _angular_core.InputSignal<number | null>;
144
+ readonly currency: _angular_core.InputSignal<string>;
145
+ readonly disabled: _angular_core.InputSignal<boolean>;
146
+ readonly errorMessage: _angular_core.InputSignal<string>;
147
+ readonly title: _angular_core.InputSignal<string>;
148
+ readonly amountDueLabel: _angular_core.InputSignal<string>;
149
+ readonly tenderedLabel: _angular_core.InputSignal<string>;
150
+ readonly changeDueLabel: _angular_core.InputSignal<string>;
151
+ readonly tenderLabel: _angular_core.InputSignal<string>;
152
+ readonly processingLabel: _angular_core.InputSignal<string>;
153
+ readonly action: _angular_core.OutputEmitterRef<{
154
+ readonly type: "tender.cash";
155
+ readonly amount: number;
156
+ }>;
157
+ protected readonly keypadRows: readonly (readonly string[])[];
158
+ protected readonly amountInput: _angular_core.WritableSignal<string>;
159
+ protected readonly parsedAmount: _angular_core.Signal<number | null>;
160
+ protected readonly canTender: _angular_core.Signal<boolean>;
161
+ protected readonly hasChangeDue: _angular_core.Signal<boolean>;
162
+ protected readonly displayTendered: _angular_core.Signal<string>;
163
+ protected readonly statusText: _angular_core.Signal<string>;
164
+ protected formatMoney(amount: number): string;
165
+ protected onKeypad(key: string): void;
166
+ protected onTender(): void;
167
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<PosTender, never>;
168
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<PosTender, "pos-tender", never, { "amountDue": { "alias": "amountDue"; "required": false; "isSignal": true; }; "changeDue": { "alias": "changeDue"; "required": false; "isSignal": true; }; "currency": { "alias": "currency"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "errorMessage": { "alias": "errorMessage"; "required": false; "isSignal": true; }; "title": { "alias": "title"; "required": false; "isSignal": true; }; "amountDueLabel": { "alias": "amountDueLabel"; "required": false; "isSignal": true; }; "tenderedLabel": { "alias": "tenderedLabel"; "required": false; "isSignal": true; }; "changeDueLabel": { "alias": "changeDueLabel"; "required": false; "isSignal": true; }; "tenderLabel": { "alias": "tenderLabel"; "required": false; "isSignal": true; }; "processingLabel": { "alias": "processingLabel"; "required": false; "isSignal": true; }; }, { "action": "action"; }, never, never, true, never>;
169
+ }
170
+
171
+ interface PosReceiptIntent {
172
+ readonly type: 'receipt.newSale';
173
+ }
174
+ /** Display-only VAT from the host envelope — not calculated here. */
175
+ interface PosReceiptVat {
176
+ readonly rate: number;
177
+ readonly amount: number;
178
+ readonly included: boolean;
179
+ }
180
+ /** Display-only receipt line from the host envelope — not an API DTO. */
181
+ interface PosReceiptLine {
182
+ readonly lineId: number;
183
+ readonly sku: string;
184
+ readonly name: string;
185
+ readonly qty: number;
186
+ readonly unitPrice: number;
187
+ readonly lineTotal: number;
188
+ readonly vat: PosReceiptVat;
189
+ readonly struckThrough: boolean;
190
+ }
191
+ /** Display-only totals from the host envelope — not calculated here. */
192
+ interface PosReceiptTotals {
193
+ readonly gross: number;
194
+ readonly net: number;
195
+ readonly vat: number;
196
+ readonly discount: number;
197
+ readonly due: number;
198
+ readonly currency: string;
199
+ }
200
+ /** Display-only tender from the host envelope — not calculated here. */
201
+ interface PosReceiptPayment {
202
+ readonly tender: string;
203
+ readonly amount: number;
204
+ readonly tendered: number;
205
+ readonly change: number;
206
+ readonly state: string;
207
+ }
208
+ /** Display-only document metadata from the host envelope. */
209
+ interface PosReceiptDocument {
210
+ readonly number: string;
211
+ readonly receiptReady: boolean;
212
+ }
213
+ declare class PosReceipt {
214
+ readonly lines: _angular_core.InputSignal<readonly PosReceiptLine[]>;
215
+ readonly totals: _angular_core.InputSignal<PosReceiptTotals>;
216
+ readonly payments: _angular_core.InputSignal<readonly PosReceiptPayment[]>;
217
+ readonly document: _angular_core.InputSignal<PosReceiptDocument>;
218
+ readonly disabled: _angular_core.InputSignal<boolean>;
219
+ readonly title: _angular_core.InputSignal<string>;
220
+ readonly emptyMessage: _angular_core.InputSignal<string>;
221
+ readonly preparingLabel: _angular_core.InputSignal<string>;
222
+ readonly readyLabel: _angular_core.InputSignal<string>;
223
+ readonly newSaleLabel: _angular_core.InputSignal<string>;
224
+ readonly tenderLabel: _angular_core.InputSignal<string>;
225
+ readonly amountLabel: _angular_core.InputSignal<string>;
226
+ readonly tenderedLabel: _angular_core.InputSignal<string>;
227
+ readonly changeLabel: _angular_core.InputSignal<string>;
228
+ readonly action: _angular_core.OutputEmitterRef<PosReceiptIntent>;
229
+ protected readonly hasLines: _angular_core.Signal<boolean>;
230
+ protected readonly hasPayments: _angular_core.Signal<boolean>;
231
+ protected readonly hasDocumentNumber: _angular_core.Signal<boolean>;
232
+ protected readonly statusText: _angular_core.Signal<string>;
233
+ protected readonly canStartNewSale: _angular_core.Signal<boolean>;
234
+ protected formatMoney(amount: number): string;
235
+ protected onNewSale(): void;
236
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<PosReceipt, never>;
237
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<PosReceipt, "pos-receipt", never, { "lines": { "alias": "lines"; "required": false; "isSignal": true; }; "totals": { "alias": "totals"; "required": false; "isSignal": true; }; "payments": { "alias": "payments"; "required": false; "isSignal": true; }; "document": { "alias": "document"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "title": { "alias": "title"; "required": false; "isSignal": true; }; "emptyMessage": { "alias": "emptyMessage"; "required": false; "isSignal": true; }; "preparingLabel": { "alias": "preparingLabel"; "required": false; "isSignal": true; }; "readyLabel": { "alias": "readyLabel"; "required": false; "isSignal": true; }; "newSaleLabel": { "alias": "newSaleLabel"; "required": false; "isSignal": true; }; "tenderLabel": { "alias": "tenderLabel"; "required": false; "isSignal": true; }; "amountLabel": { "alias": "amountLabel"; "required": false; "isSignal": true; }; "tenderedLabel": { "alias": "tenderedLabel"; "required": false; "isSignal": true; }; "changeLabel": { "alias": "changeLabel"; "required": false; "isSignal": true; }; }, { "action": "action"; }, never, never, true, never>;
238
+ }
239
+
240
+ /**
241
+ * Theme-lab catalog. Default values must stay in sync with `styles/tokens.css`.
242
+ * The lab never writes that file; edits are live overrides only.
243
+ */
244
+ type PosTokenKind = 'color' | 'length' | 'font-family' | 'font-weight' | 'other';
245
+ type PosTokenGroup = 'color' | 'radius' | 'space' | 'type' | 'control';
246
+ type PosTokenPreview = 'color' | 'radius' | 'space' | 'font-size' | 'font-family' | 'font-weight' | 'letter-spacing' | 'size';
247
+ interface PosTokenSwatch {
248
+ readonly name: string;
249
+ readonly variable: string;
250
+ }
251
+ interface PosTokenDefinition extends PosTokenSwatch {
252
+ readonly kind: PosTokenKind;
253
+ readonly group: PosTokenGroup;
254
+ readonly preview: PosTokenPreview;
255
+ readonly defaultValue: string;
256
+ }
257
+
258
+ interface PosTokenSelection {
259
+ readonly id: string;
260
+ readonly title: string;
261
+ readonly variables: readonly string[];
262
+ }
263
+ declare class PosTokens {
264
+ protected readonly colorTokens: readonly PosTokenDefinition[];
265
+ protected readonly radiusTokens: readonly PosTokenDefinition[];
266
+ protected readonly spaceTokens: readonly PosTokenDefinition[];
267
+ protected readonly typeTokens: readonly PosTokenDefinition[];
268
+ protected readonly controlTokens: readonly PosTokenDefinition[];
269
+ private readonly overrides;
270
+ protected readonly selection: _angular_core.WritableSignal<PosTokenSelection | null>;
271
+ protected readonly statusMessage: _angular_core.WritableSignal<string>;
272
+ protected readonly selectedTokens: _angular_core.Signal<readonly PosTokenDefinition[]>;
273
+ protected readonly hasOverrides: _angular_core.Signal<boolean>;
274
+ protected readonly themeStyle: _angular_core.Signal<string>;
275
+ /** Complete :root CSS for the consuming POS. Package defaults are not written. */
276
+ themeCss(): string;
277
+ /** Load a previously exported theme as live overrides. Does not mutate defaults. */
278
+ loadThemeCss(css: string): void;
279
+ resetTheme(): void;
280
+ protected exportThemeFile(): void;
281
+ protected onImportFile(event: Event): Promise<void>;
282
+ protected selectToken(token: PosTokenDefinition): void;
283
+ protected selectSample(sampleId: string): void;
284
+ protected clearSelection(): void;
285
+ protected isTokenSelected(variable: string): boolean;
286
+ protected isSampleSelected(sampleId: string): boolean;
287
+ protected isModified(variable: string): boolean;
288
+ protected currentValue(variable: string): string;
289
+ protected defaultValue(variable: string): string;
290
+ protected colorInputValue(variable: string): string | null;
291
+ protected tokenFieldId(variable: string): string;
292
+ protected onTokenInput(variable: string, event: Event): void;
293
+ protected resetToken(variable: string): void;
294
+ private setTokenValue;
295
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<PosTokens, never>;
296
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<PosTokens, "pos-tokens", never, {}, {}, never, never, true, never>;
297
+ }
298
+
299
+ export { PosBasket, PosItemEntry, PosLogin, PosReceipt, PosTender, PosTokens };
300
+ export type { PosBasketIntent, PosBasketLine, PosBasketTotals, PosBasketVat, PosItemEntryIntent, PosLoginIntent, PosLoginSessionState, PosLoginSessionStatus, PosReceiptDocument, PosReceiptIntent, PosReceiptLine, PosReceiptPayment, PosReceiptTotals, PosReceiptVat, PosTenderIntent, PosTokenSwatch };
package/eslint.config.js DELETED
@@ -1,32 +0,0 @@
1
- // @ts-check
2
- const { defineConfig } = require('eslint/config');
3
- const rootConfig = require('../../eslint.config.js');
4
-
5
- module.exports = defineConfig([
6
- ...rootConfig,
7
- {
8
- files: ['**/*.ts'],
9
- rules: {
10
- '@angular-eslint/directive-selector': [
11
- 'error',
12
- {
13
- type: 'attribute',
14
- prefix: 'pos',
15
- style: 'camelCase',
16
- },
17
- ],
18
- '@angular-eslint/component-selector': [
19
- 'error',
20
- {
21
- type: 'element',
22
- prefix: 'pos',
23
- style: 'kebab-case',
24
- },
25
- ],
26
- },
27
- },
28
- {
29
- files: ['**/*.html'],
30
- rules: {},
31
- },
32
- ]);
package/ng-package.json DELETED
@@ -1,14 +0,0 @@
1
- {
2
- "$schema": "../../node_modules/ng-packagr/ng-package.schema.json",
3
- "dest": "../../dist/pos-components",
4
- "lib": {
5
- "entryFile": "src/public-api.ts"
6
- },
7
- "assets": [
8
- {
9
- "glob": "**/*",
10
- "input": "src/styles",
11
- "output": "styles"
12
- }
13
- ]
14
- }
@@ -1,124 +0,0 @@
1
- <section
2
- class="pos-basket__panel"
3
- [attr.aria-busy]="disabled() ? true : null"
4
- >
5
- <header class="pos-basket__header">
6
- <h2 class="pos-basket__title">{{ title() }}</h2>
7
- <p class="pos-basket__count">
8
- {{ lines().length }}
9
- {{ lines().length === 1 ? 'line' : 'lines' }}
10
- </p>
11
- </header>
12
-
13
- <ul class="pos-basket__lines" aria-label="Basket lines">
14
- @if (!hasLines()) {
15
- <li class="pos-basket__empty">{{ emptyMessage() }}</li>
16
- } @else {
17
- @for (line of lines(); track line.lineId) {
18
- <li>
19
- <article
20
- class="pos-basket__line"
21
- [class.pos-basket__line--voided]="line.struckThrough"
22
- >
23
- <div class="pos-basket__line-info">
24
- <h3 class="pos-basket__line-name">{{ line.name }}</h3>
25
- <p class="pos-basket__line-sku">{{ line.sku }}</p>
26
- @if (line.struckThrough) {
27
- <p class="pos-basket__line-voided">Voided</p>
28
- }
29
- </div>
30
-
31
- <div
32
- class="pos-basket__stepper"
33
- role="group"
34
- [attr.aria-label]="'Quantity for ' + line.name"
35
- >
36
- <button
37
- type="button"
38
- class="pos-basket__qty-btn"
39
- aria-label="Decrease quantity"
40
- [disabled]="!canDecrement(line)"
41
- (click)="onDecrement(line)"
42
- >
43
-
44
- </button>
45
- <span class="pos-basket__qty" aria-live="polite">{{ line.qty }}</span>
46
- <button
47
- type="button"
48
- class="pos-basket__qty-btn"
49
- aria-label="Increase quantity"
50
- [disabled]="!canChangeQuantity(line)"
51
- (click)="onIncrement(line)"
52
- >
53
- +
54
- </button>
55
- </div>
56
-
57
- <div class="pos-basket__line-prices">
58
- <p class="pos-basket__unit-price">{{ formatMoney(line.unitPrice) }}</p>
59
- <p class="pos-basket__line-total">{{ formatMoney(line.lineTotal) }}</p>
60
- </div>
61
-
62
- <button
63
- type="button"
64
- class="pos-basket__void"
65
- [attr.aria-label]="'Void ' + line.name"
66
- [disabled]="!canVoid(line)"
67
- (click)="onVoid(line)"
68
- >
69
- <svg
70
- xmlns="http://www.w3.org/2000/svg"
71
- width="18"
72
- height="18"
73
- viewBox="0 0 24 24"
74
- fill="none"
75
- aria-hidden="true"
76
- >
77
- <path
78
- d="M6 6l12 12M18 6 6 18"
79
- stroke="currentColor"
80
- stroke-width="2"
81
- stroke-linecap="round"
82
- />
83
- </svg>
84
- </button>
85
- </article>
86
- </li>
87
- }
88
- }
89
- </ul>
90
-
91
- <footer class="pos-basket__footer">
92
- <dl class="pos-basket__totals" aria-live="polite">
93
- <div class="pos-basket__total-row">
94
- <dt>Gross</dt>
95
- <dd>{{ formatMoney(totals().gross) }}</dd>
96
- </div>
97
- <div class="pos-basket__total-row">
98
- <dt>Net</dt>
99
- <dd>{{ formatMoney(totals().net) }}</dd>
100
- </div>
101
- <div class="pos-basket__total-row">
102
- <dt>VAT</dt>
103
- <dd>{{ formatMoney(totals().vat) }}</dd>
104
- </div>
105
- <div class="pos-basket__total-row">
106
- <dt>Discount</dt>
107
- <dd>{{ formatMoney(totals().discount) }}</dd>
108
- </div>
109
- <div class="pos-basket__total-row pos-basket__total-row--due">
110
- <dt>Due</dt>
111
- <dd>{{ formatMoney(totals().due) }}</dd>
112
- </div>
113
- </dl>
114
-
115
- <button
116
- type="button"
117
- class="pos-basket__clear"
118
- [disabled]="!canClear()"
119
- (click)="onClear()"
120
- >
121
- {{ clearLabel() }}
122
- </button>
123
- </footer>
124
- </section>