@doswiftly/cli 0.1.18 → 0.1.19
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/README.md +23 -323
- package/dist/commands/check.js +1 -1
- package/dist/commands/check.js.map +1 -1
- package/dist/commands/deploy.d.ts.map +1 -1
- package/dist/commands/deploy.js +39 -20
- package/dist/commands/deploy.js.map +1 -1
- package/dist/commands/doctor.js +3 -3
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/init.js +4 -4
- package/dist/commands/sdk.js +5 -5
- package/dist/commands/sdk.js.map +1 -1
- package/dist/commands/template.js +4 -4
- package/dist/commands/template.js.map +1 -1
- package/dist/commands/types.js +5 -5
- package/dist/commands/types.js.map +1 -1
- package/dist/commands/verify.js +2 -2
- package/dist/commands/verify.js.map +1 -1
- package/dist/lib/package-manager.d.ts +1 -1
- package/dist/lib/package-manager.js +1 -1
- package/package.json +1 -1
- package/templates/storefront-nextjs/README.md +16 -12
- package/templates/storefront-nextjs/app/account/orders/page.tsx +2 -2
- package/templates/storefront-nextjs/app/account/page.tsx +2 -2
- package/templates/storefront-nextjs/app/auth/login/page.tsx +1 -1
- package/templates/storefront-nextjs/app/auth/register/page.tsx +1 -1
- package/templates/storefront-nextjs/app/cart/page.tsx +1 -1
- package/templates/storefront-nextjs/app/categories/[slug]/page.tsx +2 -2
- package/templates/storefront-nextjs/app/categories/page.tsx +1 -1
- package/templates/storefront-nextjs/app/collections/[slug]/page.tsx +1 -1
- package/templates/storefront-nextjs/app/collections/page.tsx +1 -1
- package/templates/storefront-nextjs/app/page.tsx +1 -1
- package/templates/storefront-nextjs/app/products/[slug]/page.tsx +1 -1
- package/templates/storefront-nextjs/app/products/page.tsx +2 -2
- package/templates/storefront-nextjs/app/search/page.tsx +1 -1
- package/templates/storefront-nextjs/components/auth/auth-guard.tsx +1 -1
- package/templates/storefront-nextjs/components/commerce/add-to-cart-button.tsx +1 -1
- package/templates/storefront-nextjs/components/commerce/cart-icon.tsx +1 -1
- package/templates/storefront-nextjs/components/commerce/currency-selector.tsx +2 -2
- package/templates/storefront-nextjs/components/commerce/product-filters.tsx +1 -1
- package/templates/storefront-nextjs/components/commerce/product-price.tsx +1 -1
- package/templates/storefront-nextjs/components/commerce/search-input.tsx +1 -1
- package/templates/storefront-nextjs/components/commerce/sort-select.tsx +1 -1
- package/templates/storefront-nextjs/components/providers.tsx +1 -1
- package/templates/storefront-nextjs/lib/currency.tsx +3 -3
- package/templates/storefront-nextjs/lib/format.ts +1 -1
- package/templates/storefront-nextjs/lib/graphql-queries.ts +3 -3
- package/templates/storefront-nextjs/package.dev.json +1 -1
- package/templates/storefront-nextjs/package.json +1 -1
- package/templates/storefront-nextjs/package.json.template +1 -1
- package/templates/storefront-nextjs-shadcn/.github/workflows/deploy.yml +47 -0
- package/templates/storefront-nextjs-shadcn/.github/workflows/preview.yml +47 -0
- package/templates/storefront-nextjs-shadcn/CLAUDE.md +148 -35
- package/templates/storefront-nextjs-shadcn/README.md +29 -162
- package/templates/storefront-nextjs-shadcn/app/account/addresses/page.tsx +98 -91
- package/templates/storefront-nextjs-shadcn/app/account/error.tsx +43 -0
- package/templates/storefront-nextjs-shadcn/app/account/loading.tsx +19 -0
- package/templates/storefront-nextjs-shadcn/app/account/loyalty/page.tsx +53 -162
- package/templates/storefront-nextjs-shadcn/app/account/orders/[id]/loading.tsx +60 -0
- package/templates/storefront-nextjs-shadcn/app/account/orders/[id]/page.tsx +36 -47
- package/templates/storefront-nextjs-shadcn/app/account/orders/page.tsx +46 -29
- package/templates/storefront-nextjs-shadcn/app/account/page.tsx +8 -5
- package/templates/storefront-nextjs-shadcn/app/account/settings/page.tsx +108 -71
- package/templates/storefront-nextjs-shadcn/app/api/auth/clear-token/route.ts +2 -86
- package/templates/storefront-nextjs-shadcn/app/api/auth/set-token/route.ts +2 -124
- package/templates/storefront-nextjs-shadcn/app/auth/forgot-password/page.tsx +10 -5
- package/templates/storefront-nextjs-shadcn/app/blog/[slug]/loading.tsx +17 -0
- package/templates/storefront-nextjs-shadcn/app/blog/[slug]/page.tsx +43 -2
- package/templates/storefront-nextjs-shadcn/app/blog/loading.tsx +19 -0
- package/templates/storefront-nextjs-shadcn/app/brands/page.tsx +2 -1
- package/templates/storefront-nextjs-shadcn/app/cart/loading.tsx +26 -0
- package/templates/storefront-nextjs-shadcn/app/cart/page.tsx +6 -3
- package/templates/storefront-nextjs-shadcn/app/categories/[slug]/category-products-client.tsx +56 -0
- package/templates/storefront-nextjs-shadcn/app/categories/[slug]/loading.tsx +32 -0
- package/templates/storefront-nextjs-shadcn/app/categories/[slug]/page.tsx +76 -59
- package/templates/storefront-nextjs-shadcn/app/categories/page.tsx +8 -4
- package/templates/storefront-nextjs-shadcn/app/checkout/error.tsx +43 -0
- package/templates/storefront-nextjs-shadcn/app/checkout/loading.tsx +31 -0
- package/templates/storefront-nextjs-shadcn/app/checkout/page.tsx +116 -79
- package/templates/storefront-nextjs-shadcn/app/collections/[handle]/loading.tsx +19 -0
- package/templates/storefront-nextjs-shadcn/app/collections/[handle]/page.tsx +1 -1
- package/templates/storefront-nextjs-shadcn/app/collections/loading.tsx +18 -0
- package/templates/storefront-nextjs-shadcn/app/collections/page.tsx +7 -4
- package/templates/storefront-nextjs-shadcn/app/global-error.tsx +117 -0
- package/templates/storefront-nextjs-shadcn/app/globals.css +8 -0
- package/templates/storefront-nextjs-shadcn/app/layout.tsx +46 -11
- package/templates/storefront-nextjs-shadcn/app/products/[slug]/error.tsx +43 -0
- package/templates/storefront-nextjs-shadcn/app/products/[slug]/loading.tsx +29 -0
- package/templates/storefront-nextjs-shadcn/app/products/[slug]/page.tsx +6 -6
- package/templates/storefront-nextjs-shadcn/app/products/[slug]/product-client.tsx +15 -61
- package/templates/storefront-nextjs-shadcn/app/products/loading.tsx +32 -0
- package/templates/storefront-nextjs-shadcn/app/products/products-client.tsx +405 -151
- package/templates/storefront-nextjs-shadcn/app/search/loading.tsx +18 -0
- package/templates/storefront-nextjs-shadcn/app/wishlist/page.tsx +8 -5
- package/templates/storefront-nextjs-shadcn/codegen.ts +48 -31
- package/templates/storefront-nextjs-shadcn/components/account/customer-info.fragment.graphql +36 -0
- package/templates/storefront-nextjs-shadcn/components/account/order-details.tsx +3 -1
- package/templates/storefront-nextjs-shadcn/components/account/order-history.tsx +26 -24
- package/templates/storefront-nextjs-shadcn/components/account/order-summary.fragment.graphql +36 -0
- package/templates/storefront-nextjs-shadcn/components/auth/account-menu.tsx +9 -9
- package/templates/storefront-nextjs-shadcn/components/auth/login-form.tsx +11 -37
- package/templates/storefront-nextjs-shadcn/components/auth/register-form.tsx +37 -23
- package/templates/storefront-nextjs-shadcn/components/cart/cart-drawer.tsx +4 -3
- package/templates/storefront-nextjs-shadcn/components/cart/cart-icon.tsx +8 -5
- package/templates/storefront-nextjs-shadcn/components/cart/cart-item.tsx +1 -1
- package/templates/storefront-nextjs-shadcn/components/cart/cart-line.fragment.graphql +53 -0
- package/templates/storefront-nextjs-shadcn/components/cart/cart-summary.tsx +1 -1
- package/templates/storefront-nextjs-shadcn/components/cart/shipping-estimator.tsx +22 -7
- package/templates/storefront-nextjs-shadcn/components/commerce/currency-selector.tsx +2 -2
- package/templates/storefront-nextjs-shadcn/components/commerce/product-actions.tsx +1 -1
- package/templates/storefront-nextjs-shadcn/components/commerce/search-input.tsx +2 -2
- package/templates/storefront-nextjs-shadcn/components/common/price-display.tsx +35 -11
- package/templates/storefront-nextjs-shadcn/components/discount/discount-breakdown.tsx +1 -1
- package/templates/storefront-nextjs-shadcn/components/discount/discount-code-input.tsx +3 -3
- package/templates/storefront-nextjs-shadcn/components/filters/range-slider-filter.tsx +5 -5
- package/templates/storefront-nextjs-shadcn/components/gift-card/gift-card-input.tsx +2 -2
- package/templates/storefront-nextjs-shadcn/components/home/category-grid.tsx +2 -1
- package/templates/storefront-nextjs-shadcn/components/home/collection-card.fragment.graphql +21 -0
- package/templates/storefront-nextjs-shadcn/components/home/featured-collections.tsx +2 -12
- package/templates/storefront-nextjs-shadcn/components/home/index.ts +0 -1
- package/templates/storefront-nextjs-shadcn/components/hydrated.tsx +24 -0
- package/templates/storefront-nextjs-shadcn/components/layout/breadcrumbs.tsx +4 -4
- package/templates/storefront-nextjs-shadcn/components/layout/category-node.fragment.graphql +22 -0
- package/templates/storefront-nextjs-shadcn/components/layout/currency-selector.tsx +2 -2
- package/templates/storefront-nextjs-shadcn/components/layout/header.tsx +33 -23
- package/templates/storefront-nextjs-shadcn/components/loyalty/points-balance.tsx +2 -11
- package/templates/storefront-nextjs-shadcn/components/loyalty/points-history.tsx +8 -25
- package/templates/storefront-nextjs-shadcn/components/loyalty/referral-section.tsx +10 -19
- package/templates/storefront-nextjs-shadcn/components/loyalty/rewards-catalog.tsx +17 -41
- package/templates/storefront-nextjs-shadcn/components/loyalty/tier-progress.tsx +2 -29
- package/templates/storefront-nextjs-shadcn/components/order/index.ts +6 -1
- package/templates/storefront-nextjs-shadcn/components/product/b2b-price-display.tsx +3 -1
- package/templates/storefront-nextjs-shadcn/components/product/filter-active-pills.tsx +69 -0
- package/templates/storefront-nextjs-shadcn/components/product/filter-mobile-sheet.tsx +84 -0
- package/templates/storefront-nextjs-shadcn/components/product/filter-price-range.tsx +138 -0
- package/templates/storefront-nextjs-shadcn/components/product/index.ts +9 -2
- package/templates/storefront-nextjs-shadcn/components/product/product-card.fragment.graphql +49 -0
- package/templates/storefront-nextjs-shadcn/components/product/product-card.tsx +3 -31
- package/templates/storefront-nextjs-shadcn/components/product/product-detail.fragment.graphql +52 -0
- package/templates/storefront-nextjs-shadcn/components/product/product-filters.tsx +176 -123
- package/templates/storefront-nextjs-shadcn/components/product/product-grid.tsx +3 -5
- package/templates/storefront-nextjs-shadcn/components/product/product-image.tsx +2 -2
- package/templates/storefront-nextjs-shadcn/components/product/product-price.tsx +2 -2
- package/templates/storefront-nextjs-shadcn/components/product/product-reviews.tsx +5 -4
- package/templates/storefront-nextjs-shadcn/components/product/product-sort.tsx +19 -7
- package/templates/storefront-nextjs-shadcn/components/product/product-variant-selector.tsx +8 -23
- package/templates/storefront-nextjs-shadcn/components/product/product-variant.fragment.graphql +51 -0
- package/templates/storefront-nextjs-shadcn/components/product/review-card.tsx +1 -1
- package/templates/storefront-nextjs-shadcn/components/product/review-form.tsx +1 -7
- package/templates/storefront-nextjs-shadcn/components/product/savings-display.tsx +17 -2
- package/templates/storefront-nextjs-shadcn/components/product/similar-products.tsx +3 -2
- package/templates/storefront-nextjs-shadcn/components/providers/index.ts +1 -1
- package/templates/storefront-nextjs-shadcn/components/providers/stores-provider.tsx +30 -0
- package/templates/storefront-nextjs-shadcn/components/providers/theme-provider.tsx +1 -1
- package/templates/storefront-nextjs-shadcn/components/returns/index.ts +2 -2
- package/templates/storefront-nextjs-shadcn/components/returns/return-request-form.tsx +3 -2
- package/templates/storefront-nextjs-shadcn/components/search/search-results.tsx +3 -2
- package/templates/storefront-nextjs-shadcn/components/ui/form.tsx +174 -0
- package/templates/storefront-nextjs-shadcn/components/ui/index.ts +30 -2
- package/templates/storefront-nextjs-shadcn/components/ui/progress.tsx +40 -0
- package/templates/storefront-nextjs-shadcn/components/ui/sheet.tsx +107 -0
- package/templates/storefront-nextjs-shadcn/components/ui/slider.tsx +33 -0
- package/templates/storefront-nextjs-shadcn/components/ui/textarea.tsx +24 -0
- package/templates/storefront-nextjs-shadcn/components/wishlist/wishlist-icon.tsx +3 -1
- package/templates/storefront-nextjs-shadcn/generated/graphql.ts +12779 -0
- package/templates/storefront-nextjs-shadcn/graphql/custom.example.graphql +159 -0
- package/templates/storefront-nextjs-shadcn/hooks/index.ts +2 -0
- package/templates/storefront-nextjs-shadcn/hooks/use-auth-sync.ts +42 -0
- package/templates/storefront-nextjs-shadcn/hooks/use-auth.ts +17 -295
- package/templates/storefront-nextjs-shadcn/hooks/use-cart-actions.ts +51 -19
- package/templates/storefront-nextjs-shadcn/hooks/use-cart-sync.ts +13 -9
- package/templates/storefront-nextjs-shadcn/lib/auth/routes.ts +4 -17
- package/templates/storefront-nextjs-shadcn/lib/graphql/client.ts +22 -99
- package/templates/storefront-nextjs-shadcn/lib/graphql/config.ts +32 -0
- package/templates/storefront-nextjs-shadcn/lib/graphql/fragments.ts +34 -0
- package/templates/storefront-nextjs-shadcn/lib/graphql/hooks.ts +687 -632
- package/templates/storefront-nextjs-shadcn/lib/graphql/query-keys.ts +86 -0
- package/templates/storefront-nextjs-shadcn/lib/graphql/server.ts +131 -182
- package/templates/storefront-nextjs-shadcn/lib/graphql/types.ts +62 -0
- package/templates/storefront-nextjs-shadcn/lib/theme/theme-config.ts +0 -17
- package/templates/storefront-nextjs-shadcn/next-env.d.ts +6 -0
- package/templates/storefront-nextjs-shadcn/package.dev.json +1 -3
- package/templates/storefront-nextjs-shadcn/package.json +12 -13
- package/templates/storefront-nextjs-shadcn/package.json.template +6 -7
- package/templates/storefront-nextjs-shadcn/proxy.ts +3 -4
- package/templates/storefront-nextjs-shadcn/stores/cart-store.ts +41 -39
- package/templates/storefront-nextjs-shadcn/stores/checkout-store.ts +64 -75
- package/templates/storefront-nextjs-shadcn/stores/wishlist-store.ts +178 -177
- package/templates/storefront-nextjs-shadcn/tsconfig.json +23 -5
- package/templates/storefront-nextjs-shadcn/CART_INTEGRATION.md +0 -282
- package/templates/storefront-nextjs-shadcn/GRAPHQL_DOCUMENT_NAMES.md +0 -190
- package/templates/storefront-nextjs-shadcn/GRAPHQL_ERROR_HANDLING.md +0 -263
- package/templates/storefront-nextjs-shadcn/GRAPHQL_FIXES_SUMMARY.md +0 -135
- package/templates/storefront-nextjs-shadcn/GRAPHQL_INTEGRATION_COMPLETE.md +0 -142
- package/templates/storefront-nextjs-shadcn/INTEGRATION_CHECKLIST.md +0 -448
- package/templates/storefront-nextjs-shadcn/PRODUCT_DETAIL_PAGE_IMPLEMENTATION.md +0 -307
- package/templates/storefront-nextjs-shadcn/THEME_CUSTOMIZATION.md +0 -245
- package/templates/storefront-nextjs-shadcn/components/providers/currency-provider.tsx +0 -103
- package/templates/storefront-nextjs-shadcn/graphql/collections.example.ts +0 -168
- package/templates/storefront-nextjs-shadcn/graphql/products.example.ts +0 -160
- package/templates/storefront-nextjs-shadcn/lib/auth/cookies.ts +0 -220
- package/templates/storefront-nextjs-shadcn/lib/config.ts +0 -46
- package/templates/storefront-nextjs-shadcn/lib/currency/IMPLEMENTATION_SUMMARY.md +0 -254
- package/templates/storefront-nextjs-shadcn/lib/currency/README.md +0 -464
- package/templates/storefront-nextjs-shadcn/lib/currency/cookie-manager.test.ts +0 -328
- package/templates/storefront-nextjs-shadcn/lib/currency/cookie-manager.ts +0 -295
- package/templates/storefront-nextjs-shadcn/lib/currency/index.ts +0 -27
- package/templates/storefront-nextjs-shadcn/lib/format.ts +0 -226
- package/templates/storefront-nextjs-shadcn/lib/hooks.ts +0 -30
- package/templates/storefront-nextjs-shadcn/stores/auth-store.ts +0 -66
- package/templates/storefront-nextjs-shadcn/stores/currency-store.ts +0 -103
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
-
import { useState } from "react";
|
|
3
|
+
import { useState, useCallback } from "react";
|
|
4
|
+
import Link from "next/link";
|
|
4
5
|
import { Plus } from "lucide-react";
|
|
5
|
-
import {
|
|
6
|
-
import { getGraphQLClient } from "@/lib/graphql/client";
|
|
7
|
-
import { useAuthStore } from "@/stores/auth-store";
|
|
6
|
+
import { useAuthStore, useAuthHydrated } from "@doswiftly/storefront-sdk/react";
|
|
8
7
|
import {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
} from "@/
|
|
8
|
+
useCustomer,
|
|
9
|
+
useCustomerAddressCreate,
|
|
10
|
+
useCustomerAddressUpdate,
|
|
11
|
+
useCustomerAddressDelete,
|
|
12
|
+
useCustomerDefaultAddressUpdate,
|
|
13
|
+
} from "@/lib/graphql/hooks";
|
|
14
|
+
import { useHydrated } from "@doswiftly/storefront-sdk/react";
|
|
15
15
|
import { Button } from "@/components/ui/button";
|
|
16
16
|
import { Breadcrumbs } from "@/components/layout/breadcrumbs";
|
|
17
17
|
import {
|
|
@@ -30,94 +30,67 @@ import {
|
|
|
30
30
|
} from "@/components/ui/dialog";
|
|
31
31
|
|
|
32
32
|
export default function AddressesPage() {
|
|
33
|
-
const
|
|
34
|
-
const
|
|
35
|
-
const
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
const { data: customerData, isLoading } = useQuery({
|
|
39
|
-
queryKey: ["customer", "addresses", accessToken],
|
|
40
|
-
queryFn: async () => {
|
|
41
|
-
if (!accessToken) return null;
|
|
42
|
-
const result = await client.request(CustomerDocument, {
|
|
43
|
-
customerAccessToken: accessToken,
|
|
44
|
-
});
|
|
45
|
-
return result.customer;
|
|
46
|
-
},
|
|
47
|
-
enabled: !!accessToken,
|
|
48
|
-
});
|
|
33
|
+
const hydrated = useHydrated();
|
|
34
|
+
const authHydrated = useAuthHydrated();
|
|
35
|
+
const accessToken = useAuthStore((s) => s.accessToken);
|
|
36
|
+
|
|
37
|
+
const { data: customerData, isPending } = useCustomer();
|
|
49
38
|
|
|
50
39
|
const [isFormOpen, setIsFormOpen] = useState(false);
|
|
51
40
|
const [editingAddress, setEditingAddress] = useState<Address | undefined>();
|
|
41
|
+
const [mutationError, setMutationError] = useState<string | null>(null);
|
|
52
42
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
43
|
+
const checkUserErrors = useCallback(<T extends Record<string, unknown>>(data: T, operationKey: keyof T) => {
|
|
44
|
+
const payload = data?.[operationKey] as { userErrors?: Array<{ message: string }> } | undefined;
|
|
45
|
+
if (payload?.userErrors?.length) {
|
|
46
|
+
setMutationError(payload.userErrors[0].message);
|
|
47
|
+
return true;
|
|
48
|
+
}
|
|
49
|
+
setMutationError(null);
|
|
50
|
+
return false;
|
|
51
|
+
}, []);
|
|
52
|
+
|
|
53
|
+
const deleteMutation = useCustomerAddressDelete({
|
|
54
|
+
onSuccess: (data) => checkUserErrors(data, 'customerAddressDelete'),
|
|
55
|
+
onError: () => setMutationError('Failed to delete address'),
|
|
56
|
+
});
|
|
57
|
+
const setDefaultMutation = useCustomerDefaultAddressUpdate({
|
|
58
|
+
onSuccess: (data) => checkUserErrors(data, 'customerDefaultAddressUpdate'),
|
|
59
|
+
onError: () => setMutationError('Failed to set default address'),
|
|
64
60
|
});
|
|
65
61
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
customerAccessToken: accessToken!,
|
|
72
|
-
});
|
|
73
|
-
},
|
|
74
|
-
onSuccess: () => {
|
|
75
|
-
queryClient.invalidateQueries({ queryKey: ["customer", "addresses"] });
|
|
62
|
+
const createMutation = useCustomerAddressCreate({
|
|
63
|
+
onSuccess: (data) => {
|
|
64
|
+
if (!checkUserErrors(data, 'customerAddressCreate')) {
|
|
65
|
+
setIsFormOpen(false);
|
|
66
|
+
}
|
|
76
67
|
},
|
|
68
|
+
onError: () => setMutationError('Failed to create address'),
|
|
77
69
|
});
|
|
78
70
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
address,
|
|
84
|
-
}: {
|
|
85
|
-
id?: string;
|
|
86
|
-
address: any;
|
|
87
|
-
}) => {
|
|
88
|
-
if (id) {
|
|
89
|
-
return client.request(CustomerAddressUpdateDocument, {
|
|
90
|
-
id,
|
|
91
|
-
address,
|
|
92
|
-
customerAccessToken: accessToken!,
|
|
93
|
-
});
|
|
94
|
-
} else {
|
|
95
|
-
return client.request(CustomerAddressCreateDocument, {
|
|
96
|
-
address,
|
|
97
|
-
customerAccessToken: accessToken!,
|
|
98
|
-
});
|
|
71
|
+
const updateMutation = useCustomerAddressUpdate({
|
|
72
|
+
onSuccess: (data) => {
|
|
73
|
+
if (!checkUserErrors(data, 'customerAddressUpdate')) {
|
|
74
|
+
setIsFormOpen(false);
|
|
99
75
|
}
|
|
100
76
|
},
|
|
101
|
-
|
|
102
|
-
queryClient.invalidateQueries({ queryKey: ["customer", "addresses"] });
|
|
103
|
-
setIsFormOpen(false);
|
|
104
|
-
},
|
|
77
|
+
onError: () => setMutationError('Failed to update address'),
|
|
105
78
|
});
|
|
106
79
|
|
|
107
|
-
const addresses = customerData?.addresses
|
|
108
|
-
id:
|
|
109
|
-
firstName:
|
|
110
|
-
lastName:
|
|
111
|
-
company:
|
|
112
|
-
address1:
|
|
113
|
-
address2:
|
|
114
|
-
city:
|
|
115
|
-
province:
|
|
116
|
-
zip:
|
|
117
|
-
country:
|
|
118
|
-
phone:
|
|
119
|
-
isDefault:
|
|
120
|
-
}))
|
|
80
|
+
const addresses = (customerData?.customer?.addresses ?? []).map((addr) => ({
|
|
81
|
+
id: addr.id,
|
|
82
|
+
firstName: addr.firstName || "",
|
|
83
|
+
lastName: addr.lastName || "",
|
|
84
|
+
company: addr.company || "",
|
|
85
|
+
address1: addr.address1 || "",
|
|
86
|
+
address2: addr.address2 || "",
|
|
87
|
+
city: addr.city || "",
|
|
88
|
+
province: addr.province || "",
|
|
89
|
+
zip: addr.zip || "",
|
|
90
|
+
country: addr.country || "",
|
|
91
|
+
phone: addr.phone || "",
|
|
92
|
+
isDefault: addr.isDefault,
|
|
93
|
+
}));
|
|
121
94
|
|
|
122
95
|
const handleAdd = () => {
|
|
123
96
|
setEditingAddress(undefined);
|
|
@@ -153,13 +126,15 @@ export default function AddressesPage() {
|
|
|
153
126
|
phone: data.phone || null,
|
|
154
127
|
};
|
|
155
128
|
|
|
156
|
-
|
|
157
|
-
id: editingAddress
|
|
158
|
-
|
|
159
|
-
|
|
129
|
+
if (editingAddress?.id) {
|
|
130
|
+
await updateMutation.mutateAsync({ id: editingAddress.id, address });
|
|
131
|
+
} else {
|
|
132
|
+
await createMutation.mutateAsync({ address });
|
|
133
|
+
}
|
|
160
134
|
};
|
|
161
135
|
|
|
162
|
-
|
|
136
|
+
// Wait for DOM + auth persist hydration before checking accessToken
|
|
137
|
+
if (!hydrated || !authHydrated) {
|
|
163
138
|
return (
|
|
164
139
|
<div className="container mx-auto px-4 py-8">
|
|
165
140
|
<div className="animate-pulse space-y-4">
|
|
@@ -170,6 +145,33 @@ export default function AddressesPage() {
|
|
|
170
145
|
);
|
|
171
146
|
}
|
|
172
147
|
|
|
148
|
+
// Data loading (customer query fetching after accessToken is available)
|
|
149
|
+
if (isPending) {
|
|
150
|
+
return (
|
|
151
|
+
<div className="container mx-auto px-4 py-8">
|
|
152
|
+
<div className="animate-pulse space-y-4">
|
|
153
|
+
<div className="h-8 bg-muted rounded w-1/4"></div>
|
|
154
|
+
<div className="h-64 bg-muted rounded"></div>
|
|
155
|
+
</div>
|
|
156
|
+
</div>
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
if (!accessToken) {
|
|
161
|
+
return (
|
|
162
|
+
<div className="container mx-auto px-4 py-8">
|
|
163
|
+
<Breadcrumbs className="mb-6" />
|
|
164
|
+
<div className="rounded-lg border border-destructive bg-destructive/10 p-8 text-center text-sm text-destructive">
|
|
165
|
+
You need to{" "}
|
|
166
|
+
<Link href="/auth/login?redirect=/account/addresses" className="font-medium underline">
|
|
167
|
+
sign in
|
|
168
|
+
</Link>{" "}
|
|
169
|
+
to manage your addresses.
|
|
170
|
+
</div>
|
|
171
|
+
</div>
|
|
172
|
+
);
|
|
173
|
+
}
|
|
174
|
+
|
|
173
175
|
return (
|
|
174
176
|
<div className="container mx-auto px-4 py-8">
|
|
175
177
|
<Breadcrumbs className="mb-6" />
|
|
@@ -187,6 +189,12 @@ export default function AddressesPage() {
|
|
|
187
189
|
</Button>
|
|
188
190
|
</div>
|
|
189
191
|
|
|
192
|
+
{mutationError && (
|
|
193
|
+
<div className="mb-4 rounded-lg border border-destructive bg-destructive/10 p-4 text-sm text-destructive">
|
|
194
|
+
{mutationError}
|
|
195
|
+
</div>
|
|
196
|
+
)}
|
|
197
|
+
|
|
190
198
|
<AddressList
|
|
191
199
|
addresses={addresses}
|
|
192
200
|
onEdit={handleEdit}
|
|
@@ -195,7 +203,6 @@ export default function AddressesPage() {
|
|
|
195
203
|
onAdd={handleAdd}
|
|
196
204
|
/>
|
|
197
205
|
|
|
198
|
-
{/* Address Form Dialog */}
|
|
199
206
|
<Dialog open={isFormOpen} onOpenChange={setIsFormOpen}>
|
|
200
207
|
<DialogContent className="max-w-2xl max-h-[90vh] overflow-y-auto">
|
|
201
208
|
<DialogHeader>
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useEffect } from "react";
|
|
4
|
+
import Link from "next/link";
|
|
5
|
+
import { AlertCircle } from "lucide-react";
|
|
6
|
+
import { Button } from "@/components/ui/button";
|
|
7
|
+
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
|
8
|
+
|
|
9
|
+
export default function AccountError({
|
|
10
|
+
error,
|
|
11
|
+
reset,
|
|
12
|
+
}: {
|
|
13
|
+
error: Error & { digest?: string };
|
|
14
|
+
reset: () => void;
|
|
15
|
+
}) {
|
|
16
|
+
useEffect(() => {
|
|
17
|
+
console.error("[Account Error]", error);
|
|
18
|
+
}, [error]);
|
|
19
|
+
|
|
20
|
+
return (
|
|
21
|
+
<div className="container mx-auto flex min-h-[400px] items-center justify-center px-4 py-16">
|
|
22
|
+
<Card className="max-w-md">
|
|
23
|
+
<CardHeader>
|
|
24
|
+
<CardTitle className="flex items-center gap-2 text-destructive">
|
|
25
|
+
<AlertCircle className="h-5 w-5" />
|
|
26
|
+
Something went wrong
|
|
27
|
+
</CardTitle>
|
|
28
|
+
</CardHeader>
|
|
29
|
+
<CardContent className="space-y-4">
|
|
30
|
+
<p className="text-sm text-muted-foreground">
|
|
31
|
+
We couldn't load your account data. This might be a temporary issue.
|
|
32
|
+
</p>
|
|
33
|
+
<div className="flex gap-3">
|
|
34
|
+
<Button onClick={reset}>Try again</Button>
|
|
35
|
+
<Button variant="outline" asChild>
|
|
36
|
+
<Link href="/">Go to homepage</Link>
|
|
37
|
+
</Button>
|
|
38
|
+
</div>
|
|
39
|
+
</CardContent>
|
|
40
|
+
</Card>
|
|
41
|
+
</div>
|
|
42
|
+
);
|
|
43
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Skeleton } from "@/components/ui/skeleton";
|
|
2
|
+
|
|
3
|
+
export default function AccountLoading() {
|
|
4
|
+
return (
|
|
5
|
+
<div className="container mx-auto px-4 py-16">
|
|
6
|
+
<div className="mx-auto max-w-4xl">
|
|
7
|
+
<div className="mb-8">
|
|
8
|
+
<Skeleton className="mb-2 h-10 w-48" />
|
|
9
|
+
<Skeleton className="h-5 w-80" />
|
|
10
|
+
</div>
|
|
11
|
+
<div className="grid gap-6 md:grid-cols-2">
|
|
12
|
+
{[...Array(4)].map((_, i) => (
|
|
13
|
+
<Skeleton key={i} className="h-48 w-full rounded-lg" />
|
|
14
|
+
))}
|
|
15
|
+
</div>
|
|
16
|
+
</div>
|
|
17
|
+
</div>
|
|
18
|
+
);
|
|
19
|
+
}
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* Requirements: R7, R8, R10.4
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
-
import { useState
|
|
17
|
+
import { useState } from 'react';
|
|
18
18
|
import Link from 'next/link';
|
|
19
19
|
import { ArrowLeft, Gift, Award, History, Loader2, Users, AlertCircle } from 'lucide-react';
|
|
20
20
|
import { Button } from '@/components/ui/button';
|
|
@@ -27,100 +27,7 @@ import { TierProgress } from '@/components/loyalty/tier-progress';
|
|
|
27
27
|
import { RewardsCatalog } from '@/components/loyalty/rewards-catalog';
|
|
28
28
|
import { PointsHistory } from '@/components/loyalty/points-history';
|
|
29
29
|
import { ReferralSection } from '@/components/loyalty/referral-section';
|
|
30
|
-
import {
|
|
31
|
-
|
|
32
|
-
// Type imports - these match the GraphQL schema
|
|
33
|
-
type TierType = 'BRONZE' | 'SILVER' | 'GOLD' | 'PLATINUM' | 'DIAMOND';
|
|
34
|
-
|
|
35
|
-
interface CustomBenefit {
|
|
36
|
-
name: string;
|
|
37
|
-
description?: string | null;
|
|
38
|
-
icon?: string | null;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
interface LoyaltyTier {
|
|
42
|
-
id: string;
|
|
43
|
-
name: string;
|
|
44
|
-
type?: TierType | null;
|
|
45
|
-
minPoints: number;
|
|
46
|
-
minAnnualSpend?: { amount: string; currencyCode: string } | null;
|
|
47
|
-
pointsMultiplier: number;
|
|
48
|
-
customBenefits: CustomBenefit[];
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
interface PointsSummary {
|
|
52
|
-
totalPoints: number;
|
|
53
|
-
currentPoints: number;
|
|
54
|
-
pendingPoints: number;
|
|
55
|
-
redeemedPoints: number;
|
|
56
|
-
expiredPoints: number;
|
|
57
|
-
expiringPoints?: number;
|
|
58
|
-
nextExpiryDate?: string;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
interface TierProgressData {
|
|
62
|
-
currentTier: LoyaltyTier;
|
|
63
|
-
nextTier?: LoyaltyTier;
|
|
64
|
-
pointsToNextTier: number;
|
|
65
|
-
progressPercent: number;
|
|
66
|
-
spendToNextTier?: { amount: string; currencyCode: string };
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
interface LoyaltyMember {
|
|
70
|
-
id: string;
|
|
71
|
-
customerId: string;
|
|
72
|
-
points: PointsSummary;
|
|
73
|
-
tier?: LoyaltyTier;
|
|
74
|
-
tierProgress?: TierProgressData;
|
|
75
|
-
annualSpend: { amount: string; currencyCode: string };
|
|
76
|
-
lastActivityAt?: string;
|
|
77
|
-
enrolledAt: string;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
interface LoyaltyReward {
|
|
81
|
-
id: string;
|
|
82
|
-
name: string;
|
|
83
|
-
slug: string;
|
|
84
|
-
type: string;
|
|
85
|
-
pointsCost: number;
|
|
86
|
-
discountPercent?: number | null;
|
|
87
|
-
discountAmount?: { amount: string; currencyCode: string } | null;
|
|
88
|
-
description?: string | null;
|
|
89
|
-
image?: { url: string; altText?: string | null } | null;
|
|
90
|
-
available: boolean;
|
|
91
|
-
tierRequired?: LoyaltyTier | null;
|
|
92
|
-
remainingRedemptions?: number | null;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
interface LoyaltyTransaction {
|
|
96
|
-
id: string;
|
|
97
|
-
type: string;
|
|
98
|
-
points: number;
|
|
99
|
-
balanceAfter: number;
|
|
100
|
-
orderId?: string;
|
|
101
|
-
description?: string;
|
|
102
|
-
expiresAt?: string;
|
|
103
|
-
createdAt: string;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
interface LoyaltySettings {
|
|
107
|
-
enabled: boolean;
|
|
108
|
-
pointsName: string;
|
|
109
|
-
pointsPerCurrency: number;
|
|
110
|
-
pointsExpiryMonths?: number;
|
|
111
|
-
referralEnabled: boolean;
|
|
112
|
-
referralPoints?: number;
|
|
113
|
-
referralBonusPoints?: number;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
interface ReferralStats {
|
|
117
|
-
referralCode: string;
|
|
118
|
-
shareUrl: string;
|
|
119
|
-
totalReferred: number;
|
|
120
|
-
completedReferrals: number;
|
|
121
|
-
pendingReferrals: number;
|
|
122
|
-
totalPointsEarned: number;
|
|
123
|
-
}
|
|
30
|
+
import { useAuthStore, useAuthHydrated } from '@doswiftly/storefront-sdk/react';
|
|
124
31
|
|
|
125
32
|
// Real hooks from generated GraphQL
|
|
126
33
|
import {
|
|
@@ -134,20 +41,23 @@ import {
|
|
|
134
41
|
|
|
135
42
|
export default function LoyaltyPage() {
|
|
136
43
|
const [activeTab, setActiveTab] = useState('overview');
|
|
137
|
-
const { isAuthenticated } =
|
|
44
|
+
const { isAuthenticated } = useAuthStore();
|
|
45
|
+
const isHydrated = useAuthHydrated();
|
|
138
46
|
|
|
139
47
|
// Fetch loyalty data using real GraphQL hooks
|
|
140
|
-
|
|
141
|
-
const { data: rewardsData, isLoading: rewardsLoading } = useLoyaltyRewards();
|
|
142
|
-
const { data: transactionsData } = useLoyaltyTransactions({ first: 20 });
|
|
48
|
+
// Settings don't require auth — always fetch
|
|
143
49
|
const { data: settingsData } = useLoyaltySettings();
|
|
50
|
+
// All other queries require auth — hooks internally gate with `enabled: !!accessToken`
|
|
51
|
+
const { data: memberData, isLoading: memberLoading, error: memberError } = useLoyaltyMember();
|
|
52
|
+
const { data: rewardsData, isLoading: rewardsLoading, error: rewardsError } = useLoyaltyRewards();
|
|
53
|
+
const { data: transactionsData } = useLoyaltyTransactions({ first: 20 });
|
|
144
54
|
const { data: referralData } = useReferralStats();
|
|
145
55
|
const redeemMutation = useRedeemLoyaltyReward();
|
|
146
56
|
|
|
147
57
|
// Extract data from query responses
|
|
148
58
|
const member = memberData?.loyaltyMember;
|
|
149
59
|
const rewards = rewardsData?.loyaltyRewards ?? [];
|
|
150
|
-
const transactions = transactionsData?.loyaltyTransactions?.edges?.map((e
|
|
60
|
+
const transactions = transactionsData?.loyaltyTransactions?.edges?.map((e) => e.node) ?? [];
|
|
151
61
|
const settings = settingsData?.loyaltySettings;
|
|
152
62
|
const referralStats = referralData?.referralStats;
|
|
153
63
|
|
|
@@ -164,7 +74,7 @@ export default function LoyaltyPage() {
|
|
|
164
74
|
const payload = result.redeemLoyaltyReward;
|
|
165
75
|
|
|
166
76
|
if (payload?.userErrors?.length) {
|
|
167
|
-
throw new Error(payload.userErrors[0]);
|
|
77
|
+
throw new Error(payload.userErrors[0] || 'Unknown error');
|
|
168
78
|
}
|
|
169
79
|
|
|
170
80
|
if (payload?.success) {
|
|
@@ -182,6 +92,17 @@ export default function LoyaltyPage() {
|
|
|
182
92
|
}
|
|
183
93
|
};
|
|
184
94
|
|
|
95
|
+
// Show skeleton while Zustand persist is hydrating from localStorage
|
|
96
|
+
if (!isHydrated) {
|
|
97
|
+
return (
|
|
98
|
+
<div className="container max-w-6xl py-8">
|
|
99
|
+
<div className="flex items-center justify-center min-h-[400px]">
|
|
100
|
+
<Loader2 className="h-8 w-8 animate-spin text-muted-foreground" />
|
|
101
|
+
</div>
|
|
102
|
+
</div>
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
|
|
185
106
|
// Show login prompt if not authenticated
|
|
186
107
|
if (!isAuthenticated) {
|
|
187
108
|
return (
|
|
@@ -224,6 +145,27 @@ export default function LoyaltyPage() {
|
|
|
224
145
|
);
|
|
225
146
|
}
|
|
226
147
|
|
|
148
|
+
// Show error state if primary queries failed
|
|
149
|
+
if (memberError || rewardsError) {
|
|
150
|
+
return (
|
|
151
|
+
<div className="container max-w-6xl py-8">
|
|
152
|
+
<Link href="/account">
|
|
153
|
+
<Button variant="ghost" size="sm" className="mb-4">
|
|
154
|
+
<ArrowLeft className="h-4 w-4 mr-2" />
|
|
155
|
+
Powrót do konta
|
|
156
|
+
</Button>
|
|
157
|
+
</Link>
|
|
158
|
+
|
|
159
|
+
<Alert variant="destructive">
|
|
160
|
+
<AlertCircle className="h-4 w-4" />
|
|
161
|
+
<AlertDescription>
|
|
162
|
+
Nie udało się załadować danych programu lojalnościowego. Spróbuj ponownie później.
|
|
163
|
+
</AlertDescription>
|
|
164
|
+
</Alert>
|
|
165
|
+
</div>
|
|
166
|
+
);
|
|
167
|
+
}
|
|
168
|
+
|
|
227
169
|
// Show disabled program message
|
|
228
170
|
if (programDisabled) {
|
|
229
171
|
return (
|
|
@@ -277,43 +219,6 @@ export default function LoyaltyPage() {
|
|
|
277
219
|
);
|
|
278
220
|
}
|
|
279
221
|
|
|
280
|
-
// Map tier data for components
|
|
281
|
-
const tierData = member.tier
|
|
282
|
-
? {
|
|
283
|
-
id: member.tier.id,
|
|
284
|
-
name: member.tier.name,
|
|
285
|
-
type: member.tier.type,
|
|
286
|
-
minPoints: member.tier.minPoints,
|
|
287
|
-
pointsMultiplier: member.tier.pointsMultiplier,
|
|
288
|
-
customBenefits: member.tier.customBenefits ?? [],
|
|
289
|
-
}
|
|
290
|
-
: null;
|
|
291
|
-
|
|
292
|
-
const progressData = member.tierProgress
|
|
293
|
-
? {
|
|
294
|
-
currentTier: {
|
|
295
|
-
id: member.tierProgress.currentTier.id,
|
|
296
|
-
name: member.tierProgress.currentTier.name,
|
|
297
|
-
type: member.tierProgress.currentTier.type,
|
|
298
|
-
minPoints: member.tierProgress.currentTier.minPoints,
|
|
299
|
-
pointsMultiplier: member.tierProgress.currentTier.pointsMultiplier,
|
|
300
|
-
customBenefits: member.tierProgress.currentTier.customBenefits ?? [],
|
|
301
|
-
},
|
|
302
|
-
nextTier: member.tierProgress.nextTier
|
|
303
|
-
? {
|
|
304
|
-
id: member.tierProgress.nextTier.id,
|
|
305
|
-
name: member.tierProgress.nextTier.name,
|
|
306
|
-
type: member.tierProgress.nextTier.type,
|
|
307
|
-
minPoints: member.tierProgress.nextTier.minPoints,
|
|
308
|
-
pointsMultiplier: member.tierProgress.nextTier.pointsMultiplier,
|
|
309
|
-
customBenefits: member.tierProgress.nextTier.customBenefits ?? [],
|
|
310
|
-
}
|
|
311
|
-
: undefined,
|
|
312
|
-
pointsToNextTier: member.tierProgress.pointsToNextTier,
|
|
313
|
-
progressPercent: member.tierProgress.progressPercent,
|
|
314
|
-
}
|
|
315
|
-
: null;
|
|
316
|
-
|
|
317
222
|
// Check if referral tab should be shown
|
|
318
223
|
const showReferralTab = settings?.referralEnabled && referralStats;
|
|
319
224
|
|
|
@@ -335,7 +240,7 @@ export default function LoyaltyPage() {
|
|
|
335
240
|
Zbieraj {settings?.pointsName ?? 'punkty'} i wymieniaj je na nagrody
|
|
336
241
|
</p>
|
|
337
242
|
</div>
|
|
338
|
-
{
|
|
243
|
+
{member.tier && <TierBadge tier={member.tier.type} name={member.tier.name} size="lg" />}
|
|
339
244
|
</div>
|
|
340
245
|
</div>
|
|
341
246
|
|
|
@@ -366,22 +271,22 @@ export default function LoyaltyPage() {
|
|
|
366
271
|
<TabsContent value="overview" className="space-y-6">
|
|
367
272
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
|
368
273
|
<PointsBalance points={member.points} />
|
|
369
|
-
{
|
|
274
|
+
{member.tierProgress && <TierProgress progress={member.tierProgress} />}
|
|
370
275
|
</div>
|
|
371
276
|
|
|
372
277
|
{/* Tier Benefits */}
|
|
373
|
-
{
|
|
278
|
+
{member.tier && (
|
|
374
279
|
<div className="p-6 bg-gradient-to-r from-amber-50 to-yellow-50 dark:from-amber-950/30 dark:to-yellow-950/30 rounded-lg border border-amber-200 dark:border-amber-800">
|
|
375
280
|
<h3 className="font-semibold mb-4 flex items-center gap-2">
|
|
376
281
|
<Award className="h-5 w-5 text-amber-600" />
|
|
377
|
-
Twoje korzyści na poziomie {
|
|
282
|
+
Twoje korzyści na poziomie {member.tier.name}
|
|
378
283
|
</h3>
|
|
379
284
|
<div className="grid grid-cols-1 sm:grid-cols-3 gap-4 text-sm">
|
|
380
285
|
<div className="p-3 bg-white/50 dark:bg-black/20 rounded-lg">
|
|
381
286
|
<div className="font-medium">Mnożnik punktów</div>
|
|
382
|
-
<div className="text-2xl font-bold text-amber-600">x{
|
|
287
|
+
<div className="text-2xl font-bold text-amber-600">x{member.tier.pointsMultiplier}</div>
|
|
383
288
|
</div>
|
|
384
|
-
{
|
|
289
|
+
{member.tier.customBenefits?.slice(0, 2).map((benefit, idx) => (
|
|
385
290
|
<div key={idx} className="p-3 bg-white/50 dark:bg-black/20 rounded-lg">
|
|
386
291
|
<div className="font-medium">{benefit.name}</div>
|
|
387
292
|
{benefit.description && (
|
|
@@ -390,9 +295,9 @@ export default function LoyaltyPage() {
|
|
|
390
295
|
</div>
|
|
391
296
|
))}
|
|
392
297
|
</div>
|
|
393
|
-
{
|
|
298
|
+
{(member.tier.customBenefits?.length ?? 0) > 2 && (
|
|
394
299
|
<div className="mt-4 flex flex-wrap gap-2">
|
|
395
|
-
{
|
|
300
|
+
{member.tier.customBenefits?.slice(2).map((benefit, idx) => (
|
|
396
301
|
<div key={idx} className="px-3 py-1.5 bg-white/50 dark:bg-black/20 rounded-full text-sm">
|
|
397
302
|
{benefit.name}
|
|
398
303
|
</div>
|
|
@@ -430,14 +335,7 @@ export default function LoyaltyPage() {
|
|
|
430
335
|
</p>
|
|
431
336
|
</div>
|
|
432
337
|
<RewardsCatalog
|
|
433
|
-
rewards={rewards
|
|
434
|
-
...r,
|
|
435
|
-
discountAmount: r.discountAmount
|
|
436
|
-
? { amount: r.discountAmount.amount, currencyCode: r.discountAmount.currencyCode }
|
|
437
|
-
: undefined,
|
|
438
|
-
// Map tierRequired from LoyaltyTier object to just the type string
|
|
439
|
-
tierRequired: r.tierRequired?.type,
|
|
440
|
-
}))}
|
|
338
|
+
rewards={rewards}
|
|
441
339
|
currentPoints={member.points.currentPoints}
|
|
442
340
|
currentTier={member.tier?.type}
|
|
443
341
|
onRedeem={handleRedeemReward}
|
|
@@ -464,14 +362,7 @@ export default function LoyaltyPage() {
|
|
|
464
362
|
</p>
|
|
465
363
|
</div>
|
|
466
364
|
<ReferralSection
|
|
467
|
-
|
|
468
|
-
shareUrl={referralStats.shareUrl}
|
|
469
|
-
stats={{
|
|
470
|
-
totalReferred: referralStats.totalReferred,
|
|
471
|
-
completedReferrals: referralStats.completedReferrals,
|
|
472
|
-
pendingReferrals: referralStats.pendingReferrals,
|
|
473
|
-
totalPointsEarned: referralStats.totalPointsEarned,
|
|
474
|
-
}}
|
|
365
|
+
referralStats={referralStats}
|
|
475
366
|
pointsName={settings?.pointsName ?? 'punktów'}
|
|
476
367
|
referralPoints={settings?.referralPoints ?? 0}
|
|
477
368
|
bonusPoints={settings?.referralBonusPoints ?? 0}
|