@doswiftly/cli 0.2.6 → 1.0.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/CHANGELOG.md +650 -0
- package/dist/commands/deploy.d.ts.map +1 -1
- package/dist/commands/deploy.js +6 -1
- package/dist/commands/deploy.js.map +1 -1
- package/package.json +1 -1
- package/templates/storefront-nextjs-shadcn/.github/workflows/build-template.yml +2 -1
- package/templates/storefront-nextjs-shadcn/.github/workflows/deploy.yml +5 -1
- package/templates/storefront-nextjs-shadcn/.github/workflows/preview.yml +3 -1
- package/templates/storefront-nextjs-shadcn/app/[locale]/account/addresses/page.tsx +10 -10
- package/templates/storefront-nextjs-shadcn/app/[locale]/account/loyalty/page.tsx +1 -1
- package/templates/storefront-nextjs-shadcn/app/[locale]/account/orders/[id]/page.tsx +9 -9
- package/templates/storefront-nextjs-shadcn/app/[locale]/account/orders/[id]/tracking/page.tsx +1 -1
- package/templates/storefront-nextjs-shadcn/app/[locale]/account/orders/page.tsx +2 -2
- package/templates/storefront-nextjs-shadcn/app/[locale]/account/settings/page.tsx +3 -3
- package/templates/storefront-nextjs-shadcn/app/[locale]/categories/page.tsx +1 -1
- package/templates/storefront-nextjs-shadcn/app/[locale]/checkout/page.tsx +74 -74
- package/templates/storefront-nextjs-shadcn/app/[locale]/products/[slug]/product-client.tsx +1 -1
- package/templates/storefront-nextjs-shadcn/app/[locale]/products/products-client.tsx +4 -4
- package/templates/storefront-nextjs-shadcn/app/api/auth/whoami/route.ts +6 -0
- package/templates/storefront-nextjs-shadcn/components/account/address-form.tsx +43 -43
- package/templates/storefront-nextjs-shadcn/components/account/address-list.tsx +9 -9
- package/templates/storefront-nextjs-shadcn/components/account/customer-info.fragment.graphql +5 -5
- package/templates/storefront-nextjs-shadcn/components/account/order-details.tsx +8 -8
- package/templates/storefront-nextjs-shadcn/components/account/order-history.tsx +2 -2
- package/templates/storefront-nextjs-shadcn/components/account/order-summary.fragment.graphql +15 -13
- package/templates/storefront-nextjs-shadcn/components/cart/cart-line.fragment.graphql +6 -6
- package/templates/storefront-nextjs-shadcn/components/discount/discount-code-input.tsx +10 -10
- package/templates/storefront-nextjs-shadcn/components/gift-card/gift-card-input.tsx +9 -9
- package/templates/storefront-nextjs-shadcn/components/order/delivery-estimate.tsx +2 -2
- package/templates/storefront-nextjs-shadcn/components/product/product-card.tsx +1 -1
- package/templates/storefront-nextjs-shadcn/components/seo/product-json-ld.ts +1 -1
- package/templates/storefront-nextjs-shadcn/hooks/use-auth-sync.ts +43 -25
- package/templates/storefront-nextjs-shadcn/hooks/use-cart-actions.ts +1 -1
- package/templates/storefront-nextjs-shadcn/hooks/use-cart-sync.ts +14 -14
- package/templates/storefront-nextjs-shadcn/lib/graphql/hooks.ts +101 -112
- package/templates/storefront-nextjs-shadcn/lib/graphql/query-keys.ts +2 -2
- package/templates/storefront-nextjs-shadcn/lib/graphql/server.ts +29 -12
- package/templates/storefront-nextjs-shadcn/lib/graphql/types.ts +1 -1
- package/templates/storefront-nextjs-shadcn/messages/en.json +6 -6
- package/templates/storefront-nextjs-shadcn/messages/pl.json +6 -6
- package/templates/storefront-nextjs-shadcn/package.json +4 -1
- package/templates/storefront-nextjs-shadcn/stores/checkout-store.ts +8 -8
|
@@ -7,15 +7,15 @@ import { useCartStore } from "@/stores/cart-store";
|
|
|
7
7
|
import { useCartSync } from "@/hooks/use-cart-sync";
|
|
8
8
|
import {
|
|
9
9
|
useCheckoutCreate,
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
10
|
+
useCheckoutUpdateEmail,
|
|
11
|
+
useCheckoutUpdateShippingAddress,
|
|
12
|
+
useCheckoutUpdateBillingAddress,
|
|
13
|
+
useCheckoutSelectShippingRate,
|
|
14
|
+
useCheckoutApplyDiscountCode,
|
|
15
|
+
useCheckoutRemoveDiscountCode,
|
|
16
|
+
useCheckoutApplyGiftCard,
|
|
17
|
+
useCheckoutRemoveGiftCard,
|
|
18
|
+
useCheckoutUpdateGiftCardRecipient,
|
|
19
19
|
useCheckoutComplete,
|
|
20
20
|
useCheckout,
|
|
21
21
|
} from "@/lib/graphql/hooks";
|
|
@@ -81,11 +81,11 @@ interface ShippingRate {
|
|
|
81
81
|
interface AddressForm {
|
|
82
82
|
firstName: string;
|
|
83
83
|
lastName: string;
|
|
84
|
-
|
|
85
|
-
|
|
84
|
+
streetLine1: string;
|
|
85
|
+
streetLine2: string;
|
|
86
86
|
city: string;
|
|
87
|
-
|
|
88
|
-
|
|
87
|
+
state: string;
|
|
88
|
+
postalCode: string;
|
|
89
89
|
country: string;
|
|
90
90
|
phone: string;
|
|
91
91
|
company: string;
|
|
@@ -109,11 +109,11 @@ interface CheckoutFormState {
|
|
|
109
109
|
const emptyAddress: AddressForm = {
|
|
110
110
|
firstName: "",
|
|
111
111
|
lastName: "",
|
|
112
|
-
|
|
113
|
-
|
|
112
|
+
streetLine1: "",
|
|
113
|
+
streetLine2: "",
|
|
114
114
|
city: "",
|
|
115
|
-
|
|
116
|
-
|
|
115
|
+
state: "",
|
|
116
|
+
postalCode: "",
|
|
117
117
|
country: "PL",
|
|
118
118
|
phone: "",
|
|
119
119
|
company: "",
|
|
@@ -179,12 +179,12 @@ function AddressFormFields({ prefix, values, onChange, errors }: AddressFormFiel
|
|
|
179
179
|
</div>
|
|
180
180
|
|
|
181
181
|
<div>
|
|
182
|
-
<Label htmlFor={`${prefix}_address1`}>{t("address.
|
|
182
|
+
<Label htmlFor={`${prefix}_address1`}>{t("address.streetLine1")} *</Label>
|
|
183
183
|
<Input
|
|
184
184
|
id={`${prefix}_address1`}
|
|
185
|
-
placeholder={t("address.
|
|
186
|
-
value={values.
|
|
187
|
-
onChange={(e) => onChange("
|
|
185
|
+
placeholder={t("address.streetLine1Placeholder")}
|
|
186
|
+
value={values.streetLine1}
|
|
187
|
+
onChange={(e) => onChange("streetLine1", e.target.value)}
|
|
188
188
|
className={errors[`${prefix}_address1`] ? "border-destructive" : ""}
|
|
189
189
|
/>
|
|
190
190
|
{errors[`${prefix}_address1`] && (
|
|
@@ -193,22 +193,22 @@ function AddressFormFields({ prefix, values, onChange, errors }: AddressFormFiel
|
|
|
193
193
|
</div>
|
|
194
194
|
|
|
195
195
|
<div>
|
|
196
|
-
<Label htmlFor={`${prefix}_address2`}>{t("address.
|
|
196
|
+
<Label htmlFor={`${prefix}_address2`}>{t("address.streetLine2")} ({tc("optional")})</Label>
|
|
197
197
|
<Input
|
|
198
198
|
id={`${prefix}_address2`}
|
|
199
|
-
value={values.
|
|
200
|
-
onChange={(e) => onChange("
|
|
199
|
+
value={values.streetLine2}
|
|
200
|
+
onChange={(e) => onChange("streetLine2", e.target.value)}
|
|
201
201
|
/>
|
|
202
202
|
</div>
|
|
203
203
|
|
|
204
204
|
<div className="grid gap-4 sm:grid-cols-2">
|
|
205
205
|
<div>
|
|
206
|
-
<Label htmlFor={`${prefix}_zip`}>{t("address.
|
|
206
|
+
<Label htmlFor={`${prefix}_zip`}>{t("address.postalCode")} *</Label>
|
|
207
207
|
<Input
|
|
208
208
|
id={`${prefix}_zip`}
|
|
209
|
-
placeholder={t("address.
|
|
210
|
-
value={values.
|
|
211
|
-
onChange={(e) => onChange("
|
|
209
|
+
placeholder={t("address.postalCodePlaceholder")}
|
|
210
|
+
value={values.postalCode}
|
|
211
|
+
onChange={(e) => onChange("postalCode", e.target.value)}
|
|
212
212
|
className={errors[`${prefix}_zip`] ? "border-destructive" : ""}
|
|
213
213
|
/>
|
|
214
214
|
{errors[`${prefix}_zip`] && (
|
|
@@ -249,11 +249,11 @@ function AddressFormFields({ prefix, values, onChange, errors }: AddressFormFiel
|
|
|
249
249
|
)}
|
|
250
250
|
</div>
|
|
251
251
|
<div>
|
|
252
|
-
<Label htmlFor={`${prefix}_province`}>{t("address.
|
|
252
|
+
<Label htmlFor={`${prefix}_province`}>{t("address.state")} ({tc("optional")})</Label>
|
|
253
253
|
<Input
|
|
254
254
|
id={`${prefix}_province`}
|
|
255
|
-
value={values.
|
|
256
|
-
onChange={(e) => onChange("
|
|
255
|
+
value={values.state}
|
|
256
|
+
onChange={(e) => onChange("state", e.target.value)}
|
|
257
257
|
/>
|
|
258
258
|
</div>
|
|
259
259
|
</div>
|
|
@@ -290,11 +290,11 @@ export default function CheckoutPage() {
|
|
|
290
290
|
const addressSchema = z.object({
|
|
291
291
|
firstName: z.string().min(1, t("validation.firstNameRequired")),
|
|
292
292
|
lastName: z.string().min(1, t("validation.lastNameRequired")),
|
|
293
|
-
|
|
294
|
-
|
|
293
|
+
streetLine1: z.string().min(1, t("validation.addressRequired")),
|
|
294
|
+
streetLine2: z.string().optional(),
|
|
295
295
|
city: z.string().min(1, t("validation.cityRequired")),
|
|
296
|
-
|
|
297
|
-
|
|
296
|
+
state: z.string().optional(),
|
|
297
|
+
postalCode: z.string().min(1, t("validation.zipRequired")),
|
|
298
298
|
country: z.string().min(2, t("validation.countryRequired")),
|
|
299
299
|
phone: z.string().optional(),
|
|
300
300
|
company: z.string().optional(),
|
|
@@ -340,15 +340,15 @@ export default function CheckoutPage() {
|
|
|
340
340
|
|
|
341
341
|
// Mutations
|
|
342
342
|
const createCheckout = useCheckoutCreate();
|
|
343
|
-
const updateEmail =
|
|
344
|
-
const updateShippingAddress =
|
|
345
|
-
const updateBillingAddress =
|
|
346
|
-
const updateShippingLine =
|
|
347
|
-
const applyDiscount =
|
|
348
|
-
const removeDiscount =
|
|
349
|
-
const applyGiftCard =
|
|
350
|
-
const removeGiftCard =
|
|
351
|
-
const updateGiftCardRecipient =
|
|
343
|
+
const updateEmail = useCheckoutUpdateEmail();
|
|
344
|
+
const updateShippingAddress = useCheckoutUpdateShippingAddress();
|
|
345
|
+
const updateBillingAddress = useCheckoutUpdateBillingAddress();
|
|
346
|
+
const updateShippingLine = useCheckoutSelectShippingRate();
|
|
347
|
+
const applyDiscount = useCheckoutApplyDiscountCode();
|
|
348
|
+
const removeDiscount = useCheckoutRemoveDiscountCode();
|
|
349
|
+
const applyGiftCard = useCheckoutApplyGiftCard();
|
|
350
|
+
const removeGiftCard = useCheckoutRemoveGiftCard();
|
|
351
|
+
const updateGiftCardRecipient = useCheckoutUpdateGiftCardRecipient();
|
|
352
352
|
const completeCheckout = useCheckoutComplete();
|
|
353
353
|
const queryClient = useQueryClient();
|
|
354
354
|
|
|
@@ -359,7 +359,7 @@ export default function CheckoutPage() {
|
|
|
359
359
|
// Sync discount codes from checkout (transferred from cart) to form state
|
|
360
360
|
useEffect(() => {
|
|
361
361
|
if ((checkout?.discountCodes?.length ?? 0) > 0 && !formState.appliedDiscountCode) {
|
|
362
|
-
const applicableCode = checkout?.discountCodes?.find((dc) => dc.
|
|
362
|
+
const applicableCode = checkout?.discountCodes?.find((dc) => dc.isApplicable);
|
|
363
363
|
if (applicableCode) {
|
|
364
364
|
setFormState((prev) => ({
|
|
365
365
|
...prev,
|
|
@@ -439,8 +439,8 @@ export default function CheckoutPage() {
|
|
|
439
439
|
email: formState.email,
|
|
440
440
|
});
|
|
441
441
|
|
|
442
|
-
if (emailResult.
|
|
443
|
-
toast.error(emailResult.
|
|
442
|
+
if (emailResult.checkoutUpdateEmail.userErrors?.length > 0) {
|
|
443
|
+
toast.error(emailResult.checkoutUpdateEmail.userErrors[0].message);
|
|
444
444
|
return;
|
|
445
445
|
}
|
|
446
446
|
}
|
|
@@ -530,8 +530,8 @@ export default function CheckoutPage() {
|
|
|
530
530
|
},
|
|
531
531
|
});
|
|
532
532
|
|
|
533
|
-
if (addressResult.
|
|
534
|
-
toast.error(addressResult.
|
|
533
|
+
if (addressResult.checkoutUpdateShippingAddress.userErrors?.length > 0) {
|
|
534
|
+
toast.error(addressResult.checkoutUpdateShippingAddress.userErrors[0].message);
|
|
535
535
|
return;
|
|
536
536
|
}
|
|
537
537
|
|
|
@@ -548,8 +548,8 @@ export default function CheckoutPage() {
|
|
|
548
548
|
},
|
|
549
549
|
});
|
|
550
550
|
|
|
551
|
-
if (billingResult.
|
|
552
|
-
toast.error(billingResult.
|
|
551
|
+
if (billingResult.checkoutUpdateBillingAddress.userErrors?.length > 0) {
|
|
552
|
+
toast.error(billingResult.checkoutUpdateBillingAddress.userErrors[0].message);
|
|
553
553
|
return;
|
|
554
554
|
}
|
|
555
555
|
|
|
@@ -584,8 +584,8 @@ export default function CheckoutPage() {
|
|
|
584
584
|
shippingRateHandle: formState.selectedShippingRate,
|
|
585
585
|
});
|
|
586
586
|
|
|
587
|
-
if (shippingResult.
|
|
588
|
-
toast.error(shippingResult.
|
|
587
|
+
if (shippingResult.checkoutSelectShippingRate.userErrors?.length > 0) {
|
|
588
|
+
toast.error(shippingResult.checkoutSelectShippingRate.userErrors[0].message);
|
|
589
589
|
return;
|
|
590
590
|
}
|
|
591
591
|
|
|
@@ -673,7 +673,7 @@ export default function CheckoutPage() {
|
|
|
673
673
|
discountCode: formState.discountCode.trim(),
|
|
674
674
|
});
|
|
675
675
|
|
|
676
|
-
const payload = result.
|
|
676
|
+
const payload = result.checkoutApplyDiscountCode;
|
|
677
677
|
|
|
678
678
|
if (payload?.userErrors?.length > 0) {
|
|
679
679
|
toast.error(payload.userErrors[0].message);
|
|
@@ -709,8 +709,8 @@ export default function CheckoutPage() {
|
|
|
709
709
|
discountCode: formState.appliedDiscountCode,
|
|
710
710
|
});
|
|
711
711
|
|
|
712
|
-
if (result.
|
|
713
|
-
toast.error(result.
|
|
712
|
+
if (result.checkoutRemoveDiscountCode.userErrors?.length > 0) {
|
|
713
|
+
toast.error(result.checkoutRemoveDiscountCode.userErrors[0].message);
|
|
714
714
|
return;
|
|
715
715
|
}
|
|
716
716
|
|
|
@@ -746,8 +746,8 @@ export default function CheckoutPage() {
|
|
|
746
746
|
giftCardCode: formState.giftCardCode.trim().toUpperCase(),
|
|
747
747
|
});
|
|
748
748
|
|
|
749
|
-
if (result.
|
|
750
|
-
const error = result.
|
|
749
|
+
if (result.checkoutApplyGiftCard.userErrors?.length > 0) {
|
|
750
|
+
const error = result.checkoutApplyGiftCard.userErrors[0];
|
|
751
751
|
// Translate common error codes to user-friendly messages
|
|
752
752
|
const errorMessages: Record<string, string> = {
|
|
753
753
|
GIFT_CARD_NOT_FOUND: t("errors.giftCardNotFound"),
|
|
@@ -783,8 +783,8 @@ export default function CheckoutPage() {
|
|
|
783
783
|
giftCardCode,
|
|
784
784
|
});
|
|
785
785
|
|
|
786
|
-
if (result.
|
|
787
|
-
toast.error(result.
|
|
786
|
+
if (result.checkoutRemoveGiftCard.userErrors?.length > 0) {
|
|
787
|
+
toast.error(result.checkoutRemoveGiftCard.userErrors[0].message);
|
|
788
788
|
return;
|
|
789
789
|
}
|
|
790
790
|
|
|
@@ -1409,15 +1409,15 @@ export default function CheckoutPage() {
|
|
|
1409
1409
|
<p className="text-sm text-muted-foreground">
|
|
1410
1410
|
{checkout.shippingAddress.firstName} {checkout.shippingAddress.lastName}
|
|
1411
1411
|
<br />
|
|
1412
|
-
{checkout.shippingAddress.
|
|
1413
|
-
{checkout.shippingAddress.
|
|
1412
|
+
{checkout.shippingAddress.streetLine1}
|
|
1413
|
+
{checkout.shippingAddress.streetLine2 && (
|
|
1414
1414
|
<>
|
|
1415
1415
|
<br />
|
|
1416
|
-
{checkout.shippingAddress.
|
|
1416
|
+
{checkout.shippingAddress.streetLine2}
|
|
1417
1417
|
</>
|
|
1418
1418
|
)}
|
|
1419
1419
|
<br />
|
|
1420
|
-
{checkout.shippingAddress.
|
|
1420
|
+
{checkout.shippingAddress.postalCode} {checkout.shippingAddress.city}
|
|
1421
1421
|
<br />
|
|
1422
1422
|
{countries.find((c) => c.code === checkout.shippingAddress?.country)?.name ||
|
|
1423
1423
|
checkout.shippingAddress.country}
|
|
@@ -1574,7 +1574,7 @@ export default function CheckoutPage() {
|
|
|
1574
1574
|
)}
|
|
1575
1575
|
</div>
|
|
1576
1576
|
<p className="font-medium">
|
|
1577
|
-
{formatPrice(item.
|
|
1577
|
+
{formatPrice(item.total.amount)}
|
|
1578
1578
|
</p>
|
|
1579
1579
|
</div>
|
|
1580
1580
|
))
|
|
@@ -1740,7 +1740,7 @@ export default function CheckoutPage() {
|
|
|
1740
1740
|
<span className="text-muted-foreground">{tCart("products")}</span>
|
|
1741
1741
|
<span>
|
|
1742
1742
|
{formatPrice(
|
|
1743
|
-
checkout?.
|
|
1743
|
+
checkout?.cost?.subtotal?.amount ||
|
|
1744
1744
|
items.reduce(
|
|
1745
1745
|
(sum, item) => sum + parseFloat(item.price.amount) * item.quantity,
|
|
1746
1746
|
0
|
|
@@ -1753,7 +1753,7 @@ export default function CheckoutPage() {
|
|
|
1753
1753
|
{checkout?.shippingLine ? (
|
|
1754
1754
|
<div className="flex justify-between text-sm">
|
|
1755
1755
|
<span className="text-muted-foreground">{tCart("shipping")}</span>
|
|
1756
|
-
<span>{formatPrice(checkout
|
|
1756
|
+
<span>{formatPrice(checkout?.cost?.totalShipping?.amount || "0")}</span>
|
|
1757
1757
|
</div>
|
|
1758
1758
|
) : (
|
|
1759
1759
|
<div className="flex justify-between text-sm">
|
|
@@ -1763,18 +1763,18 @@ export default function CheckoutPage() {
|
|
|
1763
1763
|
)}
|
|
1764
1764
|
|
|
1765
1765
|
{/* Discount */}
|
|
1766
|
-
{checkout?.totalDiscounts && parseFloat(checkout
|
|
1766
|
+
{checkout?.totalDiscounts && parseFloat(checkout?.cost?.totalDiscounts.amount) > 0 && (
|
|
1767
1767
|
<div className="flex justify-between text-sm text-green-600">
|
|
1768
1768
|
<span>{tCart("discount")}</span>
|
|
1769
|
-
<span>-{formatPrice(checkout
|
|
1769
|
+
<span>-{formatPrice(checkout?.cost?.totalDiscounts.amount)}</span>
|
|
1770
1770
|
</div>
|
|
1771
1771
|
)}
|
|
1772
1772
|
|
|
1773
1773
|
{/* Tax */}
|
|
1774
|
-
{checkout?.totalTax && parseFloat(checkout
|
|
1774
|
+
{checkout?.totalTax && parseFloat(checkout?.cost?.totalTax.amount) > 0 && (
|
|
1775
1775
|
<div className="flex justify-between text-sm">
|
|
1776
1776
|
<span className="text-muted-foreground">{tCart("tax")}</span>
|
|
1777
|
-
<span>{formatPrice(checkout
|
|
1777
|
+
<span>{formatPrice(checkout?.cost?.totalTax.amount)}</span>
|
|
1778
1778
|
</div>
|
|
1779
1779
|
)}
|
|
1780
1780
|
|
|
@@ -1791,7 +1791,7 @@ export default function CheckoutPage() {
|
|
|
1791
1791
|
<span>{tCart("total")}</span>
|
|
1792
1792
|
<span>
|
|
1793
1793
|
{formatPrice(
|
|
1794
|
-
checkout?.
|
|
1794
|
+
checkout?.cost?.total?.amount ||
|
|
1795
1795
|
items.reduce(
|
|
1796
1796
|
(sum, item) => sum + parseFloat(item.price.amount) * item.quantity,
|
|
1797
1797
|
0
|
|
@@ -1802,8 +1802,8 @@ export default function CheckoutPage() {
|
|
|
1802
1802
|
|
|
1803
1803
|
{/* Payment Due (if different from total due to gift cards) */}
|
|
1804
1804
|
{checkout?.paymentDue &&
|
|
1805
|
-
checkout?.
|
|
1806
|
-
parseFloat(checkout.paymentDue.amount) !== parseFloat(checkout.
|
|
1805
|
+
checkout?.cost?.total &&
|
|
1806
|
+
parseFloat(checkout.paymentDue.amount) !== parseFloat(checkout.cost.total.amount) && (
|
|
1807
1807
|
<div className="flex justify-between border-t pt-2 text-lg font-bold text-primary">
|
|
1808
1808
|
<span>{tCart("paymentDue")}</span>
|
|
1809
1809
|
<span>{formatPrice(checkout.paymentDue.amount)}</span>
|
|
@@ -129,7 +129,7 @@ export function ProductClient({ product: initialProduct, similarProducts = [] }:
|
|
|
129
129
|
[showConfigValidation],
|
|
130
130
|
);
|
|
131
131
|
|
|
132
|
-
// Live surcharge preview — doliczane do ceny wariantu na przycisku (
|
|
132
|
+
// Live surcharge preview — doliczane do ceny wariantu na przycisku (industry-standard dynamic checkout).
|
|
133
133
|
const surcharge = useMemo(
|
|
134
134
|
() => computeConfiguratorSurcharge(configuratorAttributes, configuratorSelections),
|
|
135
135
|
[configuratorAttributes, configuratorSelections],
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
import { FilterMobileSheet } from "@/components/product/filter-mobile-sheet";
|
|
16
16
|
import { Skeleton } from "@/components/ui/skeleton";
|
|
17
17
|
import { Pagination } from "@/components/ui/pagination";
|
|
18
|
-
import { useProducts,
|
|
18
|
+
import { useProducts, useProductFilters } from "@/lib/graphql/hooks";
|
|
19
19
|
import type {
|
|
20
20
|
ProductFilterInput,
|
|
21
21
|
AttributeFilterInput,
|
|
@@ -102,7 +102,7 @@ export function ProductsClient() {
|
|
|
102
102
|
const {
|
|
103
103
|
data: filtersData,
|
|
104
104
|
isLoading: isFiltersLoading,
|
|
105
|
-
} =
|
|
105
|
+
} = useProductFilters(
|
|
106
106
|
{
|
|
107
107
|
categoryId,
|
|
108
108
|
collectionId,
|
|
@@ -114,7 +114,7 @@ export function ProductsClient() {
|
|
|
114
114
|
const products = data?.products ?? [];
|
|
115
115
|
const totalCount = data?.totalCount ?? 0;
|
|
116
116
|
const totalPages = Math.ceil(totalCount / limit);
|
|
117
|
-
const availableFilters = filtersData?.
|
|
117
|
+
const availableFilters = filtersData?.productFilters;
|
|
118
118
|
|
|
119
119
|
// Show dimming when transition or fetch is in progress (but data exists)
|
|
120
120
|
const showDimming = (isPending || isProductsFetching) && products.length > 0;
|
|
@@ -368,7 +368,7 @@ export function ProductsClient() {
|
|
|
368
368
|
<FilterMobileSheet
|
|
369
369
|
{...filterProps}
|
|
370
370
|
activeFilterCount={activeFilterCount}
|
|
371
|
-
totalProducts={availableFilters?.
|
|
371
|
+
totalProducts={availableFilters?.matchCount}
|
|
372
372
|
/>
|
|
373
373
|
<p className="text-sm text-muted-foreground">
|
|
374
374
|
{totalCount > 0
|
|
@@ -11,11 +11,11 @@ export interface AddressFormData {
|
|
|
11
11
|
firstName: string;
|
|
12
12
|
lastName: string;
|
|
13
13
|
company?: string;
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
streetLine1: string;
|
|
15
|
+
streetLine2?: string;
|
|
16
16
|
city: string;
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
state: string;
|
|
18
|
+
postalCode: string;
|
|
19
19
|
country: string;
|
|
20
20
|
phone?: string;
|
|
21
21
|
isDefault?: boolean;
|
|
@@ -48,11 +48,11 @@ export function AddressForm({
|
|
|
48
48
|
firstName: "",
|
|
49
49
|
lastName: "",
|
|
50
50
|
company: "",
|
|
51
|
-
|
|
52
|
-
|
|
51
|
+
streetLine1: "",
|
|
52
|
+
streetLine2: "",
|
|
53
53
|
city: "",
|
|
54
|
-
|
|
55
|
-
|
|
54
|
+
state: "",
|
|
55
|
+
postalCode: "",
|
|
56
56
|
country: "Poland",
|
|
57
57
|
phone: "",
|
|
58
58
|
isDefault: false,
|
|
@@ -78,17 +78,17 @@ export function AddressForm({
|
|
|
78
78
|
if (!formData.lastName.trim()) {
|
|
79
79
|
newErrors.lastName = t("validation.lastNameRequired");
|
|
80
80
|
}
|
|
81
|
-
if (!formData.
|
|
82
|
-
newErrors.
|
|
81
|
+
if (!formData.streetLine1.trim()) {
|
|
82
|
+
newErrors.streetLine1 = t("validation.addressRequired");
|
|
83
83
|
}
|
|
84
84
|
if (!formData.city.trim()) {
|
|
85
85
|
newErrors.city = t("validation.cityRequired");
|
|
86
86
|
}
|
|
87
|
-
if (!formData.
|
|
88
|
-
newErrors.
|
|
87
|
+
if (!formData.state.trim()) {
|
|
88
|
+
newErrors.state = t("validation.provinceRequired");
|
|
89
89
|
}
|
|
90
|
-
if (!formData.
|
|
91
|
-
newErrors.
|
|
90
|
+
if (!formData.postalCode.trim()) {
|
|
91
|
+
newErrors.postalCode = t("validation.zipRequired");
|
|
92
92
|
}
|
|
93
93
|
if (!formData.country.trim()) {
|
|
94
94
|
newErrors.country = t("validation.countryRequired");
|
|
@@ -175,37 +175,37 @@ export function AddressForm({
|
|
|
175
175
|
{/* Address 1 */}
|
|
176
176
|
<div>
|
|
177
177
|
<label
|
|
178
|
-
htmlFor="
|
|
178
|
+
htmlFor="streetLine1"
|
|
179
179
|
className="block text-sm font-medium text-foreground mb-1"
|
|
180
180
|
>
|
|
181
|
-
{t("address.
|
|
181
|
+
{t("address.streetLine1")} *
|
|
182
182
|
</label>
|
|
183
183
|
<Input
|
|
184
|
-
id="
|
|
184
|
+
id="streetLine1"
|
|
185
185
|
type="text"
|
|
186
|
-
value={formData.
|
|
187
|
-
onChange={(e) => handleChange("
|
|
186
|
+
value={formData.streetLine1}
|
|
187
|
+
onChange={(e) => handleChange("streetLine1", e.target.value)}
|
|
188
188
|
disabled={isLoading}
|
|
189
|
-
className={errors.
|
|
189
|
+
className={errors.streetLine1 ? "border-red-500" : ""}
|
|
190
190
|
/>
|
|
191
|
-
{errors.
|
|
192
|
-
<p className="mt-1 text-sm text-red-600">{errors.
|
|
191
|
+
{errors.streetLine1 && (
|
|
192
|
+
<p className="mt-1 text-sm text-red-600">{errors.streetLine1}</p>
|
|
193
193
|
)}
|
|
194
194
|
</div>
|
|
195
195
|
|
|
196
196
|
{/* Address 2 */}
|
|
197
197
|
<div>
|
|
198
198
|
<label
|
|
199
|
-
htmlFor="
|
|
199
|
+
htmlFor="streetLine2"
|
|
200
200
|
className="block text-sm font-medium text-foreground mb-1"
|
|
201
201
|
>
|
|
202
|
-
{`${t("address.
|
|
202
|
+
{`${t("address.streetLine2")} (${tc("optional")})`}
|
|
203
203
|
</label>
|
|
204
204
|
<Input
|
|
205
|
-
id="
|
|
205
|
+
id="streetLine2"
|
|
206
206
|
type="text"
|
|
207
|
-
value={formData.
|
|
208
|
-
onChange={(e) => handleChange("
|
|
207
|
+
value={formData.streetLine2 || ""}
|
|
208
|
+
onChange={(e) => handleChange("streetLine2", e.target.value)}
|
|
209
209
|
disabled={isLoading}
|
|
210
210
|
/>
|
|
211
211
|
</div>
|
|
@@ -235,42 +235,42 @@ export function AddressForm({
|
|
|
235
235
|
{/* Province */}
|
|
236
236
|
<div>
|
|
237
237
|
<label
|
|
238
|
-
htmlFor="
|
|
238
|
+
htmlFor="state"
|
|
239
239
|
className="block text-sm font-medium text-foreground mb-1"
|
|
240
240
|
>
|
|
241
|
-
{t("address.
|
|
241
|
+
{t("address.state")} *
|
|
242
242
|
</label>
|
|
243
243
|
<Input
|
|
244
|
-
id="
|
|
244
|
+
id="state"
|
|
245
245
|
type="text"
|
|
246
|
-
value={formData.
|
|
247
|
-
onChange={(e) => handleChange("
|
|
246
|
+
value={formData.state}
|
|
247
|
+
onChange={(e) => handleChange("state", e.target.value)}
|
|
248
248
|
disabled={isLoading}
|
|
249
|
-
className={errors.
|
|
249
|
+
className={errors.state ? "border-red-500" : ""}
|
|
250
250
|
/>
|
|
251
|
-
{errors.
|
|
252
|
-
<p className="mt-1 text-sm text-red-600">{errors.
|
|
251
|
+
{errors.state && (
|
|
252
|
+
<p className="mt-1 text-sm text-red-600">{errors.state}</p>
|
|
253
253
|
)}
|
|
254
254
|
</div>
|
|
255
255
|
|
|
256
256
|
{/* Postal Code */}
|
|
257
257
|
<div>
|
|
258
258
|
<label
|
|
259
|
-
htmlFor="
|
|
259
|
+
htmlFor="postalCode"
|
|
260
260
|
className="block text-sm font-medium text-foreground mb-1"
|
|
261
261
|
>
|
|
262
|
-
{t("address.
|
|
262
|
+
{t("address.postalCode")} *
|
|
263
263
|
</label>
|
|
264
264
|
<Input
|
|
265
|
-
id="
|
|
265
|
+
id="postalCode"
|
|
266
266
|
type="text"
|
|
267
|
-
value={formData.
|
|
268
|
-
onChange={(e) => handleChange("
|
|
267
|
+
value={formData.postalCode}
|
|
268
|
+
onChange={(e) => handleChange("postalCode", e.target.value)}
|
|
269
269
|
disabled={isLoading}
|
|
270
|
-
className={errors.
|
|
270
|
+
className={errors.postalCode ? "border-red-500" : ""}
|
|
271
271
|
/>
|
|
272
|
-
{errors.
|
|
273
|
-
<p className="mt-1 text-sm text-red-600">{errors.
|
|
272
|
+
{errors.postalCode && (
|
|
273
|
+
<p className="mt-1 text-sm text-red-600">{errors.postalCode}</p>
|
|
274
274
|
)}
|
|
275
275
|
</div>
|
|
276
276
|
</div>
|
|
@@ -11,11 +11,11 @@ export interface Address {
|
|
|
11
11
|
firstName: string;
|
|
12
12
|
lastName: string;
|
|
13
13
|
company?: string;
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
streetLine1: string;
|
|
15
|
+
streetLine2?: string;
|
|
16
16
|
city: string;
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
state: string;
|
|
18
|
+
postalCode: string;
|
|
19
19
|
country: string;
|
|
20
20
|
phone?: string;
|
|
21
21
|
isDefault: boolean;
|
|
@@ -45,7 +45,7 @@ export function AddressList({
|
|
|
45
45
|
|
|
46
46
|
const handleDelete = (id: string, address: Address) => {
|
|
47
47
|
if (
|
|
48
|
-
confirm(t("deleteAddressConfirm", { address: address.
|
|
48
|
+
confirm(t("deleteAddressConfirm", { address: address.streetLine1 }))
|
|
49
49
|
) {
|
|
50
50
|
onDelete?.(id);
|
|
51
51
|
}
|
|
@@ -114,12 +114,12 @@ export function AddressList({
|
|
|
114
114
|
{address.company && (
|
|
115
115
|
<p className="text-muted-foreground">{address.company}</p>
|
|
116
116
|
)}
|
|
117
|
-
<p className="text-muted-foreground">{address.
|
|
118
|
-
{address.
|
|
119
|
-
<p className="text-muted-foreground">{address.
|
|
117
|
+
<p className="text-muted-foreground">{address.streetLine1}</p>
|
|
118
|
+
{address.streetLine2 && (
|
|
119
|
+
<p className="text-muted-foreground">{address.streetLine2}</p>
|
|
120
120
|
)}
|
|
121
121
|
<p className="text-muted-foreground">
|
|
122
|
-
{address.city}, {address.
|
|
122
|
+
{address.city}, {address.state} {address.postalCode}
|
|
123
123
|
</p>
|
|
124
124
|
<p className="text-muted-foreground">{address.country}</p>
|
|
125
125
|
{address.phone && (
|
package/templates/storefront-nextjs-shadcn/components/account/customer-info.fragment.graphql
CHANGED
|
@@ -14,7 +14,7 @@ fragment CustomerInfoFields on Customer {
|
|
|
14
14
|
lastName
|
|
15
15
|
displayName
|
|
16
16
|
phone
|
|
17
|
-
|
|
17
|
+
isEmailVerified
|
|
18
18
|
ordersCount
|
|
19
19
|
totalSpent {
|
|
20
20
|
amount
|
|
@@ -24,11 +24,11 @@ fragment CustomerInfoFields on Customer {
|
|
|
24
24
|
id
|
|
25
25
|
firstName
|
|
26
26
|
lastName
|
|
27
|
-
|
|
28
|
-
|
|
27
|
+
streetLine1
|
|
28
|
+
streetLine2
|
|
29
29
|
city
|
|
30
|
-
|
|
31
|
-
|
|
30
|
+
state
|
|
31
|
+
postalCode
|
|
32
32
|
country
|
|
33
33
|
phone
|
|
34
34
|
}
|
|
@@ -20,11 +20,11 @@ export interface OrderAddress {
|
|
|
20
20
|
firstName: string;
|
|
21
21
|
lastName: string;
|
|
22
22
|
company?: string;
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
streetLine1: string;
|
|
24
|
+
streetLine2?: string;
|
|
25
25
|
city: string;
|
|
26
|
-
|
|
27
|
-
|
|
26
|
+
state: string;
|
|
27
|
+
postalCode: string;
|
|
28
28
|
country: string;
|
|
29
29
|
phone?: string;
|
|
30
30
|
}
|
|
@@ -111,12 +111,12 @@ export function OrderDetails({ order, className }: OrderDetailsProps) {
|
|
|
111
111
|
{address.company && (
|
|
112
112
|
<p className="text-muted-foreground">{address.company}</p>
|
|
113
113
|
)}
|
|
114
|
-
<p className="text-muted-foreground">{address.
|
|
115
|
-
{address.
|
|
116
|
-
<p className="text-muted-foreground">{address.
|
|
114
|
+
<p className="text-muted-foreground">{address.streetLine1}</p>
|
|
115
|
+
{address.streetLine2 && (
|
|
116
|
+
<p className="text-muted-foreground">{address.streetLine2}</p>
|
|
117
117
|
)}
|
|
118
118
|
<p className="text-muted-foreground">
|
|
119
|
-
{address.city}, {address.
|
|
119
|
+
{address.city}, {address.state} {address.postalCode}
|
|
120
120
|
</p>
|
|
121
121
|
<p className="text-muted-foreground">{address.country}</p>
|
|
122
122
|
{address.phone && (
|