@marianmeres/stuic 3.9.1 → 3.10.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/components/Checkout/CheckoutAddressForm.svelte +227 -0
- package/dist/components/Checkout/CheckoutAddressForm.svelte.d.ts +56 -0
- package/dist/components/Checkout/CheckoutCartReview.svelte +132 -0
- package/dist/components/Checkout/CheckoutCartReview.svelte.d.ts +47 -0
- package/dist/components/Checkout/CheckoutCompleteStep.svelte +152 -0
- package/dist/components/Checkout/CheckoutCompleteStep.svelte.d.ts +46 -0
- package/dist/components/Checkout/CheckoutConfirmStep.svelte +238 -0
- package/dist/components/Checkout/CheckoutConfirmStep.svelte.d.ts +46 -0
- package/dist/components/Checkout/CheckoutDeliveryOptions.svelte +192 -0
- package/dist/components/Checkout/CheckoutDeliveryOptions.svelte.d.ts +53 -0
- package/dist/components/Checkout/CheckoutGuestForm.svelte +239 -0
- package/dist/components/Checkout/CheckoutGuestForm.svelte.d.ts +51 -0
- package/dist/components/Checkout/CheckoutLoginForm.svelte +193 -0
- package/dist/components/Checkout/CheckoutLoginForm.svelte.d.ts +46 -0
- package/dist/components/Checkout/CheckoutOrderConfirmation.svelte +250 -0
- package/dist/components/Checkout/CheckoutOrderConfirmation.svelte.d.ts +47 -0
- package/dist/components/Checkout/CheckoutOrderReview.svelte +262 -0
- package/dist/components/Checkout/CheckoutOrderReview.svelte.d.ts +65 -0
- package/dist/components/Checkout/CheckoutOrderSummary.svelte +170 -0
- package/dist/components/Checkout/CheckoutOrderSummary.svelte.d.ts +46 -0
- package/dist/components/Checkout/CheckoutProgress.svelte +145 -0
- package/dist/components/Checkout/CheckoutProgress.svelte.d.ts +45 -0
- package/dist/components/Checkout/CheckoutReviewStep.svelte +248 -0
- package/dist/components/Checkout/CheckoutReviewStep.svelte.d.ts +69 -0
- package/dist/components/Checkout/CheckoutShippingStep.svelte +309 -0
- package/dist/components/Checkout/CheckoutShippingStep.svelte.d.ts +61 -0
- package/dist/components/Checkout/_internal/checkout-i18n-defaults.d.ts +5 -0
- package/dist/components/Checkout/_internal/checkout-i18n-defaults.js +129 -0
- package/dist/components/Checkout/_internal/checkout-types.d.ts +87 -0
- package/dist/components/Checkout/_internal/checkout-types.js +4 -0
- package/dist/components/Checkout/_internal/checkout-utils.d.ts +14 -0
- package/dist/components/Checkout/_internal/checkout-utils.js +87 -0
- package/dist/components/Checkout/index.css +1059 -0
- package/dist/components/Checkout/index.d.ts +15 -0
- package/dist/components/Checkout/index.js +16 -0
- package/dist/index.css +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/themes/css/zinc.css +217 -0
- package/dist/themes/zinc.d.ts +6 -0
- package/dist/themes/zinc.js +115 -0
- package/package.json +1 -1
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
<script lang="ts" module>
|
|
2
|
+
import type { Snippet } from "svelte";
|
|
3
|
+
import type { HTMLAttributes } from "svelte/elements";
|
|
4
|
+
import type { TranslateFn } from "../../types.js";
|
|
5
|
+
import type {
|
|
6
|
+
CheckoutAddressData,
|
|
7
|
+
CheckoutValidationError,
|
|
8
|
+
} from "./_internal/checkout-types.js";
|
|
9
|
+
|
|
10
|
+
export interface Props extends Omit<HTMLAttributes<HTMLFieldSetElement>, "children"> {
|
|
11
|
+
/** Bindable address data. Default: createEmptyAddress() */
|
|
12
|
+
address?: CheckoutAddressData;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Label prefix used for:
|
|
16
|
+
* - Accessible field IDs (e.g., "shipping-name", "billing-street")
|
|
17
|
+
* - Error field matching (errors with field "shipping.name" match when label="shipping")
|
|
18
|
+
* Default: "address"
|
|
19
|
+
*/
|
|
20
|
+
label?: string;
|
|
21
|
+
|
|
22
|
+
/** External validation errors */
|
|
23
|
+
errors?: CheckoutValidationError[];
|
|
24
|
+
|
|
25
|
+
/** Which fields to display. All default to true. */
|
|
26
|
+
fields?: {
|
|
27
|
+
name?: boolean;
|
|
28
|
+
street?: boolean;
|
|
29
|
+
city?: boolean;
|
|
30
|
+
postal_code?: boolean;
|
|
31
|
+
country?: boolean;
|
|
32
|
+
phone?: boolean;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Which fields are required (shown with * marker, included in built-in validation).
|
|
37
|
+
* Default: ["name", "street", "city", "postal_code", "country"]
|
|
38
|
+
*/
|
|
39
|
+
requiredFields?: string[];
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Override the country field with a custom selector.
|
|
43
|
+
* When provided, replaces the default text input for country.
|
|
44
|
+
*/
|
|
45
|
+
countryField?: Snippet<
|
|
46
|
+
[
|
|
47
|
+
{
|
|
48
|
+
/** Current country value */
|
|
49
|
+
value: string;
|
|
50
|
+
/** Called when country changes */
|
|
51
|
+
onchange: (value: string) => void;
|
|
52
|
+
/** Error message for this field (if any) */
|
|
53
|
+
error?: string;
|
|
54
|
+
/** Field label text */
|
|
55
|
+
label: string;
|
|
56
|
+
/** HTML id attribute for the input */
|
|
57
|
+
id: string;
|
|
58
|
+
},
|
|
59
|
+
]
|
|
60
|
+
>;
|
|
61
|
+
|
|
62
|
+
t?: TranslateFn;
|
|
63
|
+
unstyled?: boolean;
|
|
64
|
+
class?: string;
|
|
65
|
+
el?: HTMLFieldSetElement;
|
|
66
|
+
}
|
|
67
|
+
</script>
|
|
68
|
+
|
|
69
|
+
<script lang="ts">
|
|
70
|
+
import { twMerge } from "../../utils/tw-merge.js";
|
|
71
|
+
import { t_default } from "./_internal/checkout-i18n-defaults.js";
|
|
72
|
+
import { createEmptyAddress } from "./_internal/checkout-utils.js";
|
|
73
|
+
import FieldInput from "../Input/FieldInput.svelte";
|
|
74
|
+
|
|
75
|
+
const DEFAULT_REQUIRED = ["name", "street", "city", "postal_code", "country"];
|
|
76
|
+
|
|
77
|
+
let {
|
|
78
|
+
address = $bindable(createEmptyAddress()),
|
|
79
|
+
label = "address",
|
|
80
|
+
errors: externalErrors = [],
|
|
81
|
+
fields,
|
|
82
|
+
requiredFields = DEFAULT_REQUIRED,
|
|
83
|
+
countryField,
|
|
84
|
+
t: tProp,
|
|
85
|
+
unstyled = false,
|
|
86
|
+
class: classProp,
|
|
87
|
+
el = $bindable(),
|
|
88
|
+
...rest
|
|
89
|
+
}: Props = $props();
|
|
90
|
+
|
|
91
|
+
let t = $derived(tProp ?? t_default);
|
|
92
|
+
|
|
93
|
+
function fieldError(field: string): string | undefined {
|
|
94
|
+
return externalErrors.find((e) => e.field.endsWith(`.${field}`))?.message;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function isRequired(field: string): boolean {
|
|
98
|
+
return requiredFields.includes(field);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
let _class = $derived(
|
|
102
|
+
unstyled ? classProp : twMerge("stuic-checkout-address", classProp)
|
|
103
|
+
);
|
|
104
|
+
</script>
|
|
105
|
+
|
|
106
|
+
<fieldset bind:this={el} class={_class} {...rest}>
|
|
107
|
+
<!-- Name (full width, block label) -->
|
|
108
|
+
{#if fields?.name !== false}
|
|
109
|
+
<FieldInput
|
|
110
|
+
bind:value={address.name}
|
|
111
|
+
label={t("checkout.address.name_label")}
|
|
112
|
+
placeholder={t("checkout.address.name_placeholder")}
|
|
113
|
+
required={isRequired("name")}
|
|
114
|
+
name="{label}-name"
|
|
115
|
+
id="{label}-name"
|
|
116
|
+
labelLeftBreakpoint={0}
|
|
117
|
+
validate={{
|
|
118
|
+
customValidator(val) {
|
|
119
|
+
return fieldError("name") || "";
|
|
120
|
+
},
|
|
121
|
+
}}
|
|
122
|
+
/>
|
|
123
|
+
{/if}
|
|
124
|
+
|
|
125
|
+
<!-- Street (full width, block label) -->
|
|
126
|
+
{#if fields?.street !== false}
|
|
127
|
+
<FieldInput
|
|
128
|
+
bind:value={address.street}
|
|
129
|
+
label={t("checkout.address.street_label")}
|
|
130
|
+
placeholder={t("checkout.address.street_placeholder")}
|
|
131
|
+
required={isRequired("street")}
|
|
132
|
+
name="{label}-street"
|
|
133
|
+
id="{label}-street"
|
|
134
|
+
labelLeftBreakpoint={0}
|
|
135
|
+
validate={{
|
|
136
|
+
customValidator(val) {
|
|
137
|
+
return fieldError("street") || "";
|
|
138
|
+
},
|
|
139
|
+
}}
|
|
140
|
+
/>
|
|
141
|
+
{/if}
|
|
142
|
+
|
|
143
|
+
<!-- City + Postal Code (2-column grid) -->
|
|
144
|
+
{#if fields?.city !== false || fields?.postal_code !== false}
|
|
145
|
+
<div class={unstyled ? undefined : "stuic-checkout-address-row"}>
|
|
146
|
+
{#if fields?.city !== false}
|
|
147
|
+
<FieldInput
|
|
148
|
+
bind:value={address.city}
|
|
149
|
+
label={t("checkout.address.city_label")}
|
|
150
|
+
placeholder={t("checkout.address.city_placeholder")}
|
|
151
|
+
required={isRequired("city")}
|
|
152
|
+
name="{label}-city"
|
|
153
|
+
id="{label}-city"
|
|
154
|
+
validate={{
|
|
155
|
+
customValidator(val) {
|
|
156
|
+
return fieldError("city") || "";
|
|
157
|
+
},
|
|
158
|
+
}}
|
|
159
|
+
/>
|
|
160
|
+
{/if}
|
|
161
|
+
{#if fields?.postal_code !== false}
|
|
162
|
+
<FieldInput
|
|
163
|
+
bind:value={address.postal_code}
|
|
164
|
+
label={t("checkout.address.postal_code_label")}
|
|
165
|
+
placeholder={t("checkout.address.postal_code_placeholder")}
|
|
166
|
+
required={isRequired("postal_code")}
|
|
167
|
+
name="{label}-postal_code"
|
|
168
|
+
id="{label}-postal_code"
|
|
169
|
+
validate={{
|
|
170
|
+
customValidator(val) {
|
|
171
|
+
return fieldError("postal_code") || "";
|
|
172
|
+
},
|
|
173
|
+
}}
|
|
174
|
+
/>
|
|
175
|
+
{/if}
|
|
176
|
+
</div>
|
|
177
|
+
{/if}
|
|
178
|
+
|
|
179
|
+
<!-- Country (full width, block label) -->
|
|
180
|
+
{#if fields?.country !== false}
|
|
181
|
+
{#if countryField}
|
|
182
|
+
{@render countryField({
|
|
183
|
+
value: address.country,
|
|
184
|
+
onchange: (v) => {
|
|
185
|
+
address.country = v;
|
|
186
|
+
},
|
|
187
|
+
error: fieldError("country"),
|
|
188
|
+
label: t("checkout.address.country_label"),
|
|
189
|
+
id: `${label}-country`,
|
|
190
|
+
})}
|
|
191
|
+
{:else}
|
|
192
|
+
<FieldInput
|
|
193
|
+
bind:value={address.country}
|
|
194
|
+
label={t("checkout.address.country_label")}
|
|
195
|
+
placeholder={t("checkout.address.country_placeholder")}
|
|
196
|
+
required={isRequired("country")}
|
|
197
|
+
name="{label}-country"
|
|
198
|
+
id="{label}-country"
|
|
199
|
+
labelLeftBreakpoint={0}
|
|
200
|
+
validate={{
|
|
201
|
+
customValidator(val) {
|
|
202
|
+
return fieldError("country") || "";
|
|
203
|
+
},
|
|
204
|
+
}}
|
|
205
|
+
/>
|
|
206
|
+
{/if}
|
|
207
|
+
{/if}
|
|
208
|
+
|
|
209
|
+
<!-- Phone (full width, block label) -->
|
|
210
|
+
{#if fields?.phone !== false}
|
|
211
|
+
<FieldInput
|
|
212
|
+
bind:value={address.phone}
|
|
213
|
+
label={t("checkout.address.phone_label")}
|
|
214
|
+
type="tel"
|
|
215
|
+
placeholder={t("checkout.address.phone_placeholder")}
|
|
216
|
+
required={isRequired("phone")}
|
|
217
|
+
name="{label}-phone"
|
|
218
|
+
id="{label}-phone"
|
|
219
|
+
labelLeftBreakpoint={0}
|
|
220
|
+
validate={{
|
|
221
|
+
customValidator(val) {
|
|
222
|
+
return fieldError("phone") || "";
|
|
223
|
+
},
|
|
224
|
+
}}
|
|
225
|
+
/>
|
|
226
|
+
{/if}
|
|
227
|
+
</fieldset>
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { Snippet } from "svelte";
|
|
2
|
+
import type { HTMLAttributes } from "svelte/elements";
|
|
3
|
+
import type { TranslateFn } from "../../types.js";
|
|
4
|
+
import type { CheckoutAddressData, CheckoutValidationError } from "./_internal/checkout-types.js";
|
|
5
|
+
export interface Props extends Omit<HTMLAttributes<HTMLFieldSetElement>, "children"> {
|
|
6
|
+
/** Bindable address data. Default: createEmptyAddress() */
|
|
7
|
+
address?: CheckoutAddressData;
|
|
8
|
+
/**
|
|
9
|
+
* Label prefix used for:
|
|
10
|
+
* - Accessible field IDs (e.g., "shipping-name", "billing-street")
|
|
11
|
+
* - Error field matching (errors with field "shipping.name" match when label="shipping")
|
|
12
|
+
* Default: "address"
|
|
13
|
+
*/
|
|
14
|
+
label?: string;
|
|
15
|
+
/** External validation errors */
|
|
16
|
+
errors?: CheckoutValidationError[];
|
|
17
|
+
/** Which fields to display. All default to true. */
|
|
18
|
+
fields?: {
|
|
19
|
+
name?: boolean;
|
|
20
|
+
street?: boolean;
|
|
21
|
+
city?: boolean;
|
|
22
|
+
postal_code?: boolean;
|
|
23
|
+
country?: boolean;
|
|
24
|
+
phone?: boolean;
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* Which fields are required (shown with * marker, included in built-in validation).
|
|
28
|
+
* Default: ["name", "street", "city", "postal_code", "country"]
|
|
29
|
+
*/
|
|
30
|
+
requiredFields?: string[];
|
|
31
|
+
/**
|
|
32
|
+
* Override the country field with a custom selector.
|
|
33
|
+
* When provided, replaces the default text input for country.
|
|
34
|
+
*/
|
|
35
|
+
countryField?: Snippet<[
|
|
36
|
+
{
|
|
37
|
+
/** Current country value */
|
|
38
|
+
value: string;
|
|
39
|
+
/** Called when country changes */
|
|
40
|
+
onchange: (value: string) => void;
|
|
41
|
+
/** Error message for this field (if any) */
|
|
42
|
+
error?: string;
|
|
43
|
+
/** Field label text */
|
|
44
|
+
label: string;
|
|
45
|
+
/** HTML id attribute for the input */
|
|
46
|
+
id: string;
|
|
47
|
+
}
|
|
48
|
+
]>;
|
|
49
|
+
t?: TranslateFn;
|
|
50
|
+
unstyled?: boolean;
|
|
51
|
+
class?: string;
|
|
52
|
+
el?: HTMLFieldSetElement;
|
|
53
|
+
}
|
|
54
|
+
declare const CheckoutAddressForm: import("svelte").Component<Props, {}, "address" | "el">;
|
|
55
|
+
type CheckoutAddressForm = ReturnType<typeof CheckoutAddressForm>;
|
|
56
|
+
export default CheckoutAddressForm;
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
<script lang="ts" module>
|
|
2
|
+
import type { Snippet } from "svelte";
|
|
3
|
+
import type { HTMLAttributes } from "svelte/elements";
|
|
4
|
+
import type { TranslateFn } from "../../types.js";
|
|
5
|
+
import type { CartComponentItem } from "../Cart/Cart.svelte";
|
|
6
|
+
|
|
7
|
+
export interface Props extends Omit<HTMLAttributes<HTMLDivElement>, "children" | "title"> {
|
|
8
|
+
/** Cart items in stuic CartComponentItem format */
|
|
9
|
+
items: CartComponentItem[];
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Format a number (in cents) to a display string.
|
|
13
|
+
* Default: defaultFormatPrice (cents / 100, 2 decimal places)
|
|
14
|
+
*/
|
|
15
|
+
formatPrice?: (value: number) => string;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Called when "Edit Cart" is clicked.
|
|
19
|
+
* If undefined, the edit action is not rendered.
|
|
20
|
+
*/
|
|
21
|
+
onEditCart?: () => void;
|
|
22
|
+
|
|
23
|
+
/** Override thumbnail rendering (passed through to Cart) */
|
|
24
|
+
thumbnail?: Snippet<[{ item: CartComponentItem }]>;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Override the Cart's summary section.
|
|
28
|
+
* Passed through to Cart's `summary` snippet.
|
|
29
|
+
*/
|
|
30
|
+
summary?: Snippet<
|
|
31
|
+
[{
|
|
32
|
+
items: CartComponentItem[];
|
|
33
|
+
total: number;
|
|
34
|
+
itemCount: number;
|
|
35
|
+
formatPrice: (v: number) => string;
|
|
36
|
+
}]
|
|
37
|
+
>;
|
|
38
|
+
|
|
39
|
+
/** Override the title (default: "Order Summary") */
|
|
40
|
+
title?: Snippet | string;
|
|
41
|
+
|
|
42
|
+
/** Override the edit action */
|
|
43
|
+
editAction?: Snippet<[{ onEditCart?: () => void }]>;
|
|
44
|
+
|
|
45
|
+
t?: TranslateFn;
|
|
46
|
+
unstyled?: boolean;
|
|
47
|
+
class?: string;
|
|
48
|
+
el?: HTMLDivElement;
|
|
49
|
+
}
|
|
50
|
+
</script>
|
|
51
|
+
|
|
52
|
+
<script lang="ts">
|
|
53
|
+
import { twMerge } from "../../utils/tw-merge.js";
|
|
54
|
+
import { t_default } from "./_internal/checkout-i18n-defaults.js";
|
|
55
|
+
import { defaultFormatPrice } from "./_internal/checkout-utils.js";
|
|
56
|
+
import Cart from "../Cart/Cart.svelte";
|
|
57
|
+
import Button from "../Button/Button.svelte";
|
|
58
|
+
|
|
59
|
+
let {
|
|
60
|
+
items,
|
|
61
|
+
formatPrice: formatPriceProp,
|
|
62
|
+
onEditCart,
|
|
63
|
+
thumbnail,
|
|
64
|
+
summary: summaryProp,
|
|
65
|
+
title: titleProp,
|
|
66
|
+
editAction,
|
|
67
|
+
t: tProp,
|
|
68
|
+
unstyled = false,
|
|
69
|
+
class: classProp,
|
|
70
|
+
el = $bindable(),
|
|
71
|
+
...rest
|
|
72
|
+
}: Props = $props();
|
|
73
|
+
|
|
74
|
+
let t = $derived(tProp ?? t_default);
|
|
75
|
+
let fp = $derived(formatPriceProp ?? defaultFormatPrice);
|
|
76
|
+
|
|
77
|
+
let total = $derived(items.reduce((sum, item) => sum + item.lineTotal, 0));
|
|
78
|
+
let itemCount = $derived(items.reduce((sum, item) => sum + item.quantity, 0));
|
|
79
|
+
|
|
80
|
+
let _class = $derived(
|
|
81
|
+
unstyled ? classProp : twMerge("stuic-checkout-cart-review", classProp)
|
|
82
|
+
);
|
|
83
|
+
</script>
|
|
84
|
+
|
|
85
|
+
<div bind:this={el} class={_class} {...rest}>
|
|
86
|
+
<!-- Header bar -->
|
|
87
|
+
<div class={unstyled ? undefined : "stuic-checkout-cart-review-header"}>
|
|
88
|
+
{#if typeof titleProp === "function"}
|
|
89
|
+
{@render titleProp()}
|
|
90
|
+
{:else}
|
|
91
|
+
<h3 class={unstyled ? undefined : "stuic-checkout-cart-review-title"}>
|
|
92
|
+
{typeof titleProp === "string" ? titleProp : t("checkout.cart.title")}
|
|
93
|
+
</h3>
|
|
94
|
+
{/if}
|
|
95
|
+
|
|
96
|
+
{#if editAction}
|
|
97
|
+
{@render editAction({ onEditCart })}
|
|
98
|
+
{:else if onEditCart}
|
|
99
|
+
<Button variant="outline" size="sm" onclick={onEditCart}>
|
|
100
|
+
{t("checkout.cart.edit")}
|
|
101
|
+
</Button>
|
|
102
|
+
{/if}
|
|
103
|
+
</div>
|
|
104
|
+
|
|
105
|
+
<!-- Cart (readonly) -->
|
|
106
|
+
<Cart
|
|
107
|
+
{items}
|
|
108
|
+
readonly
|
|
109
|
+
formatPrice={fp}
|
|
110
|
+
{thumbnail}
|
|
111
|
+
t={tProp}
|
|
112
|
+
{unstyled}
|
|
113
|
+
>
|
|
114
|
+
{#snippet summary({ items: _items, total: _total, itemCount: _itemCount, formatPrice: _fp })}
|
|
115
|
+
{#if summaryProp}
|
|
116
|
+
{@render summaryProp({ items: _items, total: _total, itemCount: _itemCount, formatPrice: _fp })}
|
|
117
|
+
{:else}
|
|
118
|
+
<div class={unstyled ? undefined : "stuic-checkout-cart-review-summary"}>
|
|
119
|
+
<span>
|
|
120
|
+
{t("checkout.cart.subtotal")}
|
|
121
|
+
({_itemCount === 1
|
|
122
|
+
? t("checkout.cart.item_count_1")
|
|
123
|
+
: t("checkout.cart.item_count_n", { count: _itemCount })})
|
|
124
|
+
</span>
|
|
125
|
+
<span class={unstyled ? undefined : "stuic-checkout-cart-review-summary-total"}>
|
|
126
|
+
{_fp(_total)}
|
|
127
|
+
</span>
|
|
128
|
+
</div>
|
|
129
|
+
{/if}
|
|
130
|
+
{/snippet}
|
|
131
|
+
</Cart>
|
|
132
|
+
</div>
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { Snippet } from "svelte";
|
|
2
|
+
import type { HTMLAttributes } from "svelte/elements";
|
|
3
|
+
import type { TranslateFn } from "../../types.js";
|
|
4
|
+
import type { CartComponentItem } from "../Cart/Cart.svelte";
|
|
5
|
+
export interface Props extends Omit<HTMLAttributes<HTMLDivElement>, "children" | "title"> {
|
|
6
|
+
/** Cart items in stuic CartComponentItem format */
|
|
7
|
+
items: CartComponentItem[];
|
|
8
|
+
/**
|
|
9
|
+
* Format a number (in cents) to a display string.
|
|
10
|
+
* Default: defaultFormatPrice (cents / 100, 2 decimal places)
|
|
11
|
+
*/
|
|
12
|
+
formatPrice?: (value: number) => string;
|
|
13
|
+
/**
|
|
14
|
+
* Called when "Edit Cart" is clicked.
|
|
15
|
+
* If undefined, the edit action is not rendered.
|
|
16
|
+
*/
|
|
17
|
+
onEditCart?: () => void;
|
|
18
|
+
/** Override thumbnail rendering (passed through to Cart) */
|
|
19
|
+
thumbnail?: Snippet<[{
|
|
20
|
+
item: CartComponentItem;
|
|
21
|
+
}]>;
|
|
22
|
+
/**
|
|
23
|
+
* Override the Cart's summary section.
|
|
24
|
+
* Passed through to Cart's `summary` snippet.
|
|
25
|
+
*/
|
|
26
|
+
summary?: Snippet<[
|
|
27
|
+
{
|
|
28
|
+
items: CartComponentItem[];
|
|
29
|
+
total: number;
|
|
30
|
+
itemCount: number;
|
|
31
|
+
formatPrice: (v: number) => string;
|
|
32
|
+
}
|
|
33
|
+
]>;
|
|
34
|
+
/** Override the title (default: "Order Summary") */
|
|
35
|
+
title?: Snippet | string;
|
|
36
|
+
/** Override the edit action */
|
|
37
|
+
editAction?: Snippet<[{
|
|
38
|
+
onEditCart?: () => void;
|
|
39
|
+
}]>;
|
|
40
|
+
t?: TranslateFn;
|
|
41
|
+
unstyled?: boolean;
|
|
42
|
+
class?: string;
|
|
43
|
+
el?: HTMLDivElement;
|
|
44
|
+
}
|
|
45
|
+
declare const CheckoutCartReview: import("svelte").Component<Props, {}, "el">;
|
|
46
|
+
type CheckoutCartReview = ReturnType<typeof CheckoutCartReview>;
|
|
47
|
+
export default CheckoutCartReview;
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
<script lang="ts" module>
|
|
2
|
+
import type { Snippet } from "svelte";
|
|
3
|
+
import type { HTMLAttributes } from "svelte/elements";
|
|
4
|
+
import type { TranslateFn } from "../../types.js";
|
|
5
|
+
import type { CheckoutOrderData, CheckoutStep } from "./_internal/checkout-types.js";
|
|
6
|
+
|
|
7
|
+
export interface Props extends Omit<HTMLAttributes<HTMLDivElement>, "children"> {
|
|
8
|
+
/** Completed order data */
|
|
9
|
+
order: CheckoutOrderData;
|
|
10
|
+
|
|
11
|
+
/** Order ID */
|
|
12
|
+
orderId: string;
|
|
13
|
+
|
|
14
|
+
/** Whether confirmation email was sent */
|
|
15
|
+
emailSent?: boolean;
|
|
16
|
+
|
|
17
|
+
// -- State --
|
|
18
|
+
|
|
19
|
+
/** Whether the step is loading (e.g., completing payment in background) */
|
|
20
|
+
isLoading?: boolean;
|
|
21
|
+
|
|
22
|
+
/** Error message */
|
|
23
|
+
error?: string | null;
|
|
24
|
+
|
|
25
|
+
// -- Progress --
|
|
26
|
+
|
|
27
|
+
currentStep?: string;
|
|
28
|
+
steps?: CheckoutStep[];
|
|
29
|
+
onStepNavigate?: (step: CheckoutStep) => void;
|
|
30
|
+
|
|
31
|
+
// -- Actions --
|
|
32
|
+
|
|
33
|
+
/** Called when "Continue Shopping" is clicked */
|
|
34
|
+
onContinueShopping?: () => void;
|
|
35
|
+
|
|
36
|
+
/** Called when "Return to Checkout" is clicked (from error state) */
|
|
37
|
+
onReturnToCheckout?: () => void;
|
|
38
|
+
|
|
39
|
+
// -- Formatting --
|
|
40
|
+
|
|
41
|
+
formatPrice?: (v: number) => string;
|
|
42
|
+
|
|
43
|
+
// -- Pass-through to CheckoutOrderConfirmation --
|
|
44
|
+
|
|
45
|
+
/** Success icon HTML override */
|
|
46
|
+
successIcon?: string;
|
|
47
|
+
|
|
48
|
+
/** Override the confirmation header */
|
|
49
|
+
header?: Snippet<[{ orderId: string }]>;
|
|
50
|
+
|
|
51
|
+
/** Override order number display */
|
|
52
|
+
orderNumber?: Snippet<[{ orderId: string }]>;
|
|
53
|
+
|
|
54
|
+
/** Additional content after the confirmation */
|
|
55
|
+
confirmationFooter?: Snippet<[{ orderId: string; order: CheckoutOrderData }]>;
|
|
56
|
+
|
|
57
|
+
t?: TranslateFn;
|
|
58
|
+
unstyled?: boolean;
|
|
59
|
+
class?: string;
|
|
60
|
+
el?: HTMLDivElement;
|
|
61
|
+
}
|
|
62
|
+
</script>
|
|
63
|
+
|
|
64
|
+
<script lang="ts">
|
|
65
|
+
import { twMerge } from "../../utils/tw-merge.js";
|
|
66
|
+
import Button from "../Button/Button.svelte";
|
|
67
|
+
import Skeleton from "../Skeleton/Skeleton.svelte";
|
|
68
|
+
import CheckoutOrderConfirmation from "./CheckoutOrderConfirmation.svelte";
|
|
69
|
+
import CheckoutProgress from "./CheckoutProgress.svelte";
|
|
70
|
+
import { t_default } from "./_internal/checkout-i18n-defaults.js";
|
|
71
|
+
|
|
72
|
+
let {
|
|
73
|
+
order,
|
|
74
|
+
orderId,
|
|
75
|
+
emailSent,
|
|
76
|
+
isLoading = false,
|
|
77
|
+
error,
|
|
78
|
+
currentStep = "complete",
|
|
79
|
+
steps,
|
|
80
|
+
onStepNavigate,
|
|
81
|
+
onContinueShopping,
|
|
82
|
+
onReturnToCheckout,
|
|
83
|
+
formatPrice,
|
|
84
|
+
successIcon,
|
|
85
|
+
header,
|
|
86
|
+
orderNumber,
|
|
87
|
+
confirmationFooter,
|
|
88
|
+
t: tProp,
|
|
89
|
+
unstyled = false,
|
|
90
|
+
class: classProp,
|
|
91
|
+
el = $bindable(),
|
|
92
|
+
...rest
|
|
93
|
+
}: Props = $props();
|
|
94
|
+
|
|
95
|
+
let t = $derived(tProp ?? t_default);
|
|
96
|
+
|
|
97
|
+
let _class = $derived(
|
|
98
|
+
unstyled ? classProp : twMerge("stuic-checkout-complete-step", classProp)
|
|
99
|
+
);
|
|
100
|
+
</script>
|
|
101
|
+
|
|
102
|
+
<div bind:this={el} class={_class} {...rest}>
|
|
103
|
+
<!-- Progress -->
|
|
104
|
+
<CheckoutProgress
|
|
105
|
+
{steps}
|
|
106
|
+
{currentStep}
|
|
107
|
+
onNavigate={onStepNavigate}
|
|
108
|
+
t={tProp}
|
|
109
|
+
{unstyled}
|
|
110
|
+
/>
|
|
111
|
+
|
|
112
|
+
{#if isLoading}
|
|
113
|
+
<div class={unstyled ? undefined : "stuic-checkout-complete-step-loading"}>
|
|
114
|
+
<Skeleton variant="circle" height="4rem" width="4rem" />
|
|
115
|
+
<Skeleton height="2rem" width="60%" />
|
|
116
|
+
<Skeleton height="1rem" width="40%" />
|
|
117
|
+
<Skeleton variant="rectangle" height="12rem" />
|
|
118
|
+
</div>
|
|
119
|
+
{:else if error}
|
|
120
|
+
<div class={unstyled ? undefined : "stuic-checkout-complete-step-error"}>
|
|
121
|
+
<div class={unstyled ? undefined : "stuic-checkout-alert"} role="alert">
|
|
122
|
+
{error}
|
|
123
|
+
</div>
|
|
124
|
+
<div class={unstyled ? undefined : "stuic-checkout-complete-step-error-actions"}>
|
|
125
|
+
{#if onReturnToCheckout}
|
|
126
|
+
<Button variant="outline" onclick={onReturnToCheckout}>
|
|
127
|
+
{t("checkout.step.return_to_checkout")}
|
|
128
|
+
</Button>
|
|
129
|
+
{/if}
|
|
130
|
+
{#if onContinueShopping}
|
|
131
|
+
<Button intent="primary" onclick={onContinueShopping}>
|
|
132
|
+
{t("checkout.complete.continue_shopping")}
|
|
133
|
+
</Button>
|
|
134
|
+
{/if}
|
|
135
|
+
</div>
|
|
136
|
+
</div>
|
|
137
|
+
{:else}
|
|
138
|
+
<CheckoutOrderConfirmation
|
|
139
|
+
{order}
|
|
140
|
+
{orderId}
|
|
141
|
+
{emailSent}
|
|
142
|
+
{formatPrice}
|
|
143
|
+
{onContinueShopping}
|
|
144
|
+
{successIcon}
|
|
145
|
+
{header}
|
|
146
|
+
{orderNumber}
|
|
147
|
+
footer={confirmationFooter}
|
|
148
|
+
t={tProp}
|
|
149
|
+
{unstyled}
|
|
150
|
+
/>
|
|
151
|
+
{/if}
|
|
152
|
+
</div>
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { Snippet } from "svelte";
|
|
2
|
+
import type { HTMLAttributes } from "svelte/elements";
|
|
3
|
+
import type { TranslateFn } from "../../types.js";
|
|
4
|
+
import type { CheckoutOrderData, CheckoutStep } from "./_internal/checkout-types.js";
|
|
5
|
+
export interface Props extends Omit<HTMLAttributes<HTMLDivElement>, "children"> {
|
|
6
|
+
/** Completed order data */
|
|
7
|
+
order: CheckoutOrderData;
|
|
8
|
+
/** Order ID */
|
|
9
|
+
orderId: string;
|
|
10
|
+
/** Whether confirmation email was sent */
|
|
11
|
+
emailSent?: boolean;
|
|
12
|
+
/** Whether the step is loading (e.g., completing payment in background) */
|
|
13
|
+
isLoading?: boolean;
|
|
14
|
+
/** Error message */
|
|
15
|
+
error?: string | null;
|
|
16
|
+
currentStep?: string;
|
|
17
|
+
steps?: CheckoutStep[];
|
|
18
|
+
onStepNavigate?: (step: CheckoutStep) => void;
|
|
19
|
+
/** Called when "Continue Shopping" is clicked */
|
|
20
|
+
onContinueShopping?: () => void;
|
|
21
|
+
/** Called when "Return to Checkout" is clicked (from error state) */
|
|
22
|
+
onReturnToCheckout?: () => void;
|
|
23
|
+
formatPrice?: (v: number) => string;
|
|
24
|
+
/** Success icon HTML override */
|
|
25
|
+
successIcon?: string;
|
|
26
|
+
/** Override the confirmation header */
|
|
27
|
+
header?: Snippet<[{
|
|
28
|
+
orderId: string;
|
|
29
|
+
}]>;
|
|
30
|
+
/** Override order number display */
|
|
31
|
+
orderNumber?: Snippet<[{
|
|
32
|
+
orderId: string;
|
|
33
|
+
}]>;
|
|
34
|
+
/** Additional content after the confirmation */
|
|
35
|
+
confirmationFooter?: Snippet<[{
|
|
36
|
+
orderId: string;
|
|
37
|
+
order: CheckoutOrderData;
|
|
38
|
+
}]>;
|
|
39
|
+
t?: TranslateFn;
|
|
40
|
+
unstyled?: boolean;
|
|
41
|
+
class?: string;
|
|
42
|
+
el?: HTMLDivElement;
|
|
43
|
+
}
|
|
44
|
+
declare const CheckoutCompleteStep: import("svelte").Component<Props, {}, "el">;
|
|
45
|
+
type CheckoutCompleteStep = ReturnType<typeof CheckoutCompleteStep>;
|
|
46
|
+
export default CheckoutCompleteStep;
|