@doswiftly/cli 0.1.19 → 0.1.20
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/commands/deploy.d.ts +20 -0
- package/dist/commands/deploy.d.ts.map +1 -1
- package/dist/commands/deploy.js +219 -6
- package/dist/commands/deploy.js.map +1 -1
- package/package.json +4 -4
- package/templates/storefront-minimal/.github/workflows/build-template.yml +10 -0
- package/templates/storefront-minimal/wrangler.toml +11 -0
- package/templates/storefront-nextjs/.github/workflows/build-template.yml +10 -0
- package/templates/storefront-nextjs/wrangler.toml +11 -0
- package/templates/storefront-nextjs-shadcn/.github/workflows/build-template.yml +10 -0
- package/templates/storefront-nextjs-shadcn/CLAUDE.md +29 -5
- package/templates/storefront-nextjs-shadcn/app/{about → [locale]/about}/page.tsx +17 -14
- package/templates/storefront-nextjs-shadcn/app/{account → [locale]/account}/addresses/page.tsx +19 -15
- package/templates/storefront-nextjs-shadcn/app/{account → [locale]/account}/error.tsx +8 -5
- package/templates/storefront-nextjs-shadcn/app/{account → [locale]/account}/loyalty/page.tsx +39 -34
- package/templates/storefront-nextjs-shadcn/app/{account → [locale]/account}/orders/[id]/page.tsx +9 -7
- package/templates/storefront-nextjs-shadcn/app/{account → [locale]/account}/orders/[id]/tracking/page.tsx +27 -25
- package/templates/storefront-nextjs-shadcn/app/{account → [locale]/account}/orders/page.tsx +13 -9
- package/templates/storefront-nextjs-shadcn/app/{account → [locale]/account}/page.tsx +1 -2
- package/templates/storefront-nextjs-shadcn/app/{account → [locale]/account}/settings/page.tsx +1 -1
- package/templates/storefront-nextjs-shadcn/app/{auth → [locale]/auth}/forgot-password/page.tsx +14 -12
- package/templates/storefront-nextjs-shadcn/app/{auth → [locale]/auth}/login/page.tsx +5 -2
- package/templates/storefront-nextjs-shadcn/app/{auth → [locale]/auth}/register/page.tsx +5 -2
- package/templates/storefront-nextjs-shadcn/app/{blog → [locale]/blog}/[slug]/page.tsx +1 -1
- package/templates/storefront-nextjs-shadcn/app/{cart → [locale]/cart}/page.tsx +14 -10
- package/templates/storefront-nextjs-shadcn/app/{categories → [locale]/categories}/[slug]/category-products-client.tsx +4 -2
- package/templates/storefront-nextjs-shadcn/app/{categories → [locale]/categories}/page.tsx +13 -8
- package/templates/storefront-nextjs-shadcn/app/{checkout → [locale]/checkout}/error.tsx +1 -1
- package/templates/storefront-nextjs-shadcn/app/{checkout → [locale]/checkout}/page.tsx +228 -184
- package/templates/storefront-nextjs-shadcn/app/{checkout → [locale]/checkout}/success/[orderId]/page.tsx +36 -34
- package/templates/storefront-nextjs-shadcn/app/{collections → [locale]/collections}/[handle]/page.tsx +5 -3
- package/templates/storefront-nextjs-shadcn/app/{collections → [locale]/collections}/page.tsx +13 -8
- package/templates/storefront-nextjs-shadcn/app/{contact → [locale]/contact}/page.tsx +24 -21
- package/templates/storefront-nextjs-shadcn/app/{error.tsx → [locale]/error.tsx} +13 -8
- package/templates/storefront-nextjs-shadcn/app/[locale]/layout.tsx +92 -0
- package/templates/storefront-nextjs-shadcn/app/{not-found.tsx → [locale]/not-found.tsx} +13 -18
- package/templates/storefront-nextjs-shadcn/app/{page.tsx → [locale]/page.tsx} +8 -4
- package/templates/storefront-nextjs-shadcn/app/{products → [locale]/products}/[slug]/error.tsx +1 -1
- package/templates/storefront-nextjs-shadcn/app/{products → [locale]/products}/[slug]/page.tsx +11 -8
- package/templates/storefront-nextjs-shadcn/app/{products → [locale]/products}/[slug]/product-client.tsx +3 -1
- package/templates/storefront-nextjs-shadcn/app/{products → [locale]/products}/page.tsx +6 -3
- package/templates/storefront-nextjs-shadcn/app/{products → [locale]/products}/products-client.tsx +14 -10
- package/templates/storefront-nextjs-shadcn/app/{wishlist → [locale]/wishlist}/page.tsx +21 -25
- package/templates/storefront-nextjs-shadcn/app/layout.tsx +6 -68
- package/templates/storefront-nextjs-shadcn/components/account/address-form.tsx +25 -20
- package/templates/storefront-nextjs-shadcn/components/account/address-list.tsx +11 -10
- package/templates/storefront-nextjs-shadcn/components/account/order-details.tsx +14 -12
- package/templates/storefront-nextjs-shadcn/components/account/order-history.tsx +28 -18
- package/templates/storefront-nextjs-shadcn/components/auth/account-menu.tsx +10 -8
- package/templates/storefront-nextjs-shadcn/components/auth/login-form.tsx +27 -22
- package/templates/storefront-nextjs-shadcn/components/auth/register-form.tsx +48 -43
- package/templates/storefront-nextjs-shadcn/components/blog/blog-card.tsx +1 -1
- package/templates/storefront-nextjs-shadcn/components/blog/blog-sidebar.tsx +1 -1
- package/templates/storefront-nextjs-shadcn/components/brand/brand-card.tsx +1 -1
- package/templates/storefront-nextjs-shadcn/components/cart/cart-drawer.tsx +7 -4
- package/templates/storefront-nextjs-shadcn/components/cart/cart-icon.tsx +1 -1
- package/templates/storefront-nextjs-shadcn/components/cart/cart-item.tsx +7 -5
- package/templates/storefront-nextjs-shadcn/components/cart/cart-summary.tsx +9 -7
- package/templates/storefront-nextjs-shadcn/components/cart/promo-code-input.tsx +8 -5
- package/templates/storefront-nextjs-shadcn/components/cart/shipping-estimator.tsx +18 -15
- package/templates/storefront-nextjs-shadcn/components/checkout/payment-method-card.tsx +15 -25
- package/templates/storefront-nextjs-shadcn/components/checkout/payment-step.tsx +10 -8
- package/templates/storefront-nextjs-shadcn/components/checkout/tax-breakdown.tsx +9 -6
- package/templates/storefront-nextjs-shadcn/components/commerce/currency-selector.tsx +5 -3
- package/templates/storefront-nextjs-shadcn/components/commerce/pagination.tsx +8 -5
- package/templates/storefront-nextjs-shadcn/components/commerce/product-actions.tsx +5 -3
- package/templates/storefront-nextjs-shadcn/components/commerce/search-input.tsx +8 -7
- package/templates/storefront-nextjs-shadcn/components/common/category-card.tsx +1 -1
- package/templates/storefront-nextjs-shadcn/components/common/collection-card.tsx +1 -1
- package/templates/storefront-nextjs-shadcn/components/common/social-share.tsx +9 -6
- package/templates/storefront-nextjs-shadcn/components/discount/discount-breakdown.tsx +21 -11
- package/templates/storefront-nextjs-shadcn/components/discount/discount-code-input.tsx +16 -13
- package/templates/storefront-nextjs-shadcn/components/error/error-boundary.tsx +53 -28
- package/templates/storefront-nextjs-shadcn/components/filters/dynamic-attribute-filters.tsx +7 -5
- package/templates/storefront-nextjs-shadcn/components/gift-card/gift-card-balance.tsx +19 -15
- package/templates/storefront-nextjs-shadcn/components/gift-card/gift-card-input.tsx +12 -9
- package/templates/storefront-nextjs-shadcn/components/home/category-grid.tsx +8 -5
- package/templates/storefront-nextjs-shadcn/components/home/featured-collections.tsx +1 -1
- package/templates/storefront-nextjs-shadcn/components/home/featured-products.tsx +12 -8
- package/templates/storefront-nextjs-shadcn/components/home/hero-section.tsx +13 -8
- package/templates/storefront-nextjs-shadcn/components/home/newsletter-signup.tsx +10 -8
- package/templates/storefront-nextjs-shadcn/components/layout/breadcrumbs.tsx +37 -12
- package/templates/storefront-nextjs-shadcn/components/layout/currency-selector.tsx +5 -2
- package/templates/storefront-nextjs-shadcn/components/layout/footer.tsx +24 -23
- package/templates/storefront-nextjs-shadcn/components/layout/header.tsx +20 -12
- package/templates/storefront-nextjs-shadcn/components/layout/language-switcher.tsx +54 -0
- package/templates/storefront-nextjs-shadcn/components/layout/mobile-menu.tsx +33 -30
- package/templates/storefront-nextjs-shadcn/components/layout/navigation.tsx +27 -24
- package/templates/storefront-nextjs-shadcn/components/loyalty/referral-section.tsx +23 -24
- package/templates/storefront-nextjs-shadcn/components/product/add-to-cart-button.tsx +6 -14
- package/templates/storefront-nextjs-shadcn/components/product/b2b-price-display.tsx +1 -1
- package/templates/storefront-nextjs-shadcn/components/product/filter-active-pills.tsx +4 -1
- package/templates/storefront-nextjs-shadcn/components/product/filter-mobile-sheet.tsx +7 -4
- package/templates/storefront-nextjs-shadcn/components/product/filter-price-range.tsx +5 -3
- package/templates/storefront-nextjs-shadcn/components/product/product-card.tsx +8 -6
- package/templates/storefront-nextjs-shadcn/components/product/product-filters.tsx +3 -1
- package/templates/storefront-nextjs-shadcn/components/product/product-image.tsx +3 -7
- package/templates/storefront-nextjs-shadcn/components/product/product-sort.tsx +26 -13
- package/templates/storefront-nextjs-shadcn/components/product/review-form.tsx +25 -27
- package/templates/storefront-nextjs-shadcn/components/providers/language-sync-provider.tsx +27 -0
- package/templates/storefront-nextjs-shadcn/components/providers/stores-provider.tsx +40 -7
- package/templates/storefront-nextjs-shadcn/components/returns/return-request-form.tsx +56 -70
- package/templates/storefront-nextjs-shadcn/components/search/search-bar.tsx +7 -4
- package/templates/storefront-nextjs-shadcn/components/shipping/shipping-method-selector.tsx +12 -9
- package/templates/storefront-nextjs-shadcn/components/ui/empty-state.tsx +23 -12
- package/templates/storefront-nextjs-shadcn/components/wishlist/wishlist-button.tsx +7 -4
- package/templates/storefront-nextjs-shadcn/components/wishlist/wishlist-icon.tsx +1 -1
- package/templates/storefront-nextjs-shadcn/components/wishlist/wishlist-item.tsx +2 -10
- package/templates/storefront-nextjs-shadcn/generated/graphql.ts +1159 -551
- package/templates/storefront-nextjs-shadcn/hooks/index.ts +1 -0
- package/templates/storefront-nextjs-shadcn/hooks/use-cart-actions.ts +22 -249
- package/templates/storefront-nextjs-shadcn/hooks/use-cart-di.ts +67 -0
- package/templates/storefront-nextjs-shadcn/hooks/use-cart-sync.ts +3 -3
- package/templates/storefront-nextjs-shadcn/i18n/navigation.ts +12 -0
- package/templates/storefront-nextjs-shadcn/i18n/request.ts +17 -0
- package/templates/storefront-nextjs-shadcn/i18n/routing.ts +17 -0
- package/templates/storefront-nextjs-shadcn/lib/graphql/config.ts +1 -0
- package/templates/storefront-nextjs-shadcn/lib/graphql/hooks.ts +41 -8
- package/templates/storefront-nextjs-shadcn/lib/graphql/query-keys.ts +20 -18
- package/templates/storefront-nextjs-shadcn/lib/graphql/server.ts +2 -1
- package/templates/storefront-nextjs-shadcn/messages/en.json +869 -0
- package/templates/storefront-nextjs-shadcn/messages/pl.json +869 -0
- package/templates/storefront-nextjs-shadcn/next.config.ts +6 -5
- package/templates/storefront-nextjs-shadcn/package.json +3 -2
- package/templates/storefront-nextjs-shadcn/proxy.ts +115 -46
- package/templates/storefront-nextjs-shadcn/stores/cart-store.ts +24 -58
- package/templates/storefront-nextjs-shadcn/wrangler.toml +11 -0
- /package/templates/storefront-nextjs-shadcn/app/{account → [locale]/account}/loading.tsx +0 -0
- /package/templates/storefront-nextjs-shadcn/app/{account → [locale]/account}/orders/[id]/loading.tsx +0 -0
- /package/templates/storefront-nextjs-shadcn/app/{blog → [locale]/blog}/[slug]/loading.tsx +0 -0
- /package/templates/storefront-nextjs-shadcn/app/{blog → [locale]/blog}/loading.tsx +0 -0
- /package/templates/storefront-nextjs-shadcn/app/{blog → [locale]/blog}/page.tsx +0 -0
- /package/templates/storefront-nextjs-shadcn/app/{brands → [locale]/brands}/[slug]/page.tsx +0 -0
- /package/templates/storefront-nextjs-shadcn/app/{brands → [locale]/brands}/page.tsx +0 -0
- /package/templates/storefront-nextjs-shadcn/app/{cart → [locale]/cart}/loading.tsx +0 -0
- /package/templates/storefront-nextjs-shadcn/app/{categories → [locale]/categories}/[slug]/loading.tsx +0 -0
- /package/templates/storefront-nextjs-shadcn/app/{categories → [locale]/categories}/[slug]/page.tsx +0 -0
- /package/templates/storefront-nextjs-shadcn/app/{checkout → [locale]/checkout}/loading.tsx +0 -0
- /package/templates/storefront-nextjs-shadcn/app/{collections → [locale]/collections}/[handle]/loading.tsx +0 -0
- /package/templates/storefront-nextjs-shadcn/app/{collections → [locale]/collections}/loading.tsx +0 -0
- /package/templates/storefront-nextjs-shadcn/app/{products → [locale]/products}/[slug]/loading.tsx +0 -0
- /package/templates/storefront-nextjs-shadcn/app/{products → [locale]/products}/loading.tsx +0 -0
- /package/templates/storefront-nextjs-shadcn/app/{returns → [locale]/returns}/page.tsx +0 -0
- /package/templates/storefront-nextjs-shadcn/app/{search → [locale]/search}/loading.tsx +0 -0
- /package/templates/storefront-nextjs-shadcn/app/{search → [locale]/search}/page.tsx +0 -0
- /package/templates/storefront-nextjs-shadcn/app/{search → [locale]/search}/search-client.tsx +0 -0
- /package/templates/storefront-nextjs-shadcn/app/{shipping → [locale]/shipping}/page.tsx +0 -0
|
@@ -53,14 +53,15 @@ graphql/
|
|
|
53
53
|
└── custom.example.graphql # Example custom operations
|
|
54
54
|
|
|
55
55
|
stores/ # Zustand stores (Context pattern via SDK createStoreContext)
|
|
56
|
-
├── cart-store.ts #
|
|
56
|
+
├── cart-store.ts # Re-export facade from SDK (createCartStore with DI)
|
|
57
57
|
├── checkout-store.ts # Checkout form state with persistence
|
|
58
58
|
└── wishlist-store.ts # Wishlist state with persistence
|
|
59
59
|
|
|
60
60
|
hooks/
|
|
61
61
|
├── use-auth.ts # Thin wrapper over SDK useAuth + httpOnly cookies
|
|
62
62
|
├── use-auth-sync.ts # Detects auth desync (cookie vs store)
|
|
63
|
-
├── use-cart-
|
|
63
|
+
├── use-cart-di.ts # CartActions DI implementation (GraphQL transport for SDK cart store)
|
|
64
|
+
├── use-cart-actions.ts # Cart mutations UX wrapper (debounce, openCart — delegates to SDK store)
|
|
64
65
|
├── use-cart-sync.ts # Cart data from server (maps GraphQL → CartItemData)
|
|
65
66
|
└── use-filter-params.ts # URL-driven filter state
|
|
66
67
|
|
|
@@ -72,19 +73,22 @@ generated/
|
|
|
72
73
|
|
|
73
74
|
Template importuje z `@doswiftly/storefront-sdk`:
|
|
74
75
|
- **Core (`.`)**: `AUTH_COOKIE_NAME`, `matchesRoute`, `createSetTokenHandler`, `createClearTokenHandler`, `createAuthTokenClient`, `formatPrice`, `formatAmount`, `sanitizeHtml`, `normalizeConnection`
|
|
75
|
-
- **React (`./react`)**: `StorefrontProvider`, `useAuthStore`, `useCurrencyStore`, `useAuthHydrated`, `useStorefrontClient`, `useHydrated`, `useDebouncedValue`, `createStoreContext`
|
|
76
|
+
- **React (`./react`)**: `StorefrontProvider`, `useAuthStore`, `useCurrencyStore`, `useAuthHydrated`, `useStorefrontClient`, `useHydrated`, `useDebouncedValue`, `createStoreContext`, `createCartStore`, `CartProvider`, `useCartStore`, `useCartStoreApi`
|
|
76
77
|
- **Server (`./react/server`)**: `getStorefrontClient`, `getCurrencyFromCookieAsync`
|
|
77
78
|
- **Auth hooks**: `useAuth` (bazowy, owinięty w `hooks/use-auth.ts`)
|
|
78
79
|
|
|
79
80
|
**Store pattern**: Zustand stores używają `createStore()` (vanilla) + React Context via `createStoreContext()` from SDK.
|
|
80
81
|
Hooki `useAuthStore`/`useCurrencyStore` wymagają owinięcia w `StorefrontProvider`.
|
|
81
|
-
|
|
82
|
+
**Cart store** pochodzi z SDK (`createCartStore` z DI pattern) — template dostarcza `CartActions` via `hooks/use-cart-di.ts`.
|
|
83
|
+
Template stores (checkout, wishlist) wymagają `StoresProvider` (wewnątrz `StorefrontProvider`).
|
|
82
84
|
`useAuthHydrated()` zwraca `true` po rehydracji persist z localStorage.
|
|
83
85
|
`useHydrated()` zwraca `true` po hydration SSR → client.
|
|
84
86
|
|
|
87
|
+
**Cart DI pattern**: SDK orchestruje stan (init, mutations, error handling), template dostarcza transport via `CartActions` interface.
|
|
88
|
+
`StoresProvider` wiąże DI: `createCartStore({ getActions: () => actionsRef.current, onMutationSuccess, onMutationError })`.
|
|
89
|
+
|
|
85
90
|
Template NIE importuje z SDK:
|
|
86
91
|
- React Query hooks — są LOCAL w `lib/graphql/hooks.ts`
|
|
87
|
-
- Cart actions — LOCAL w `hooks/use-cart-actions.ts`
|
|
88
92
|
- Data types — LOCAL via codegen (`generated/graphql.ts`)
|
|
89
93
|
|
|
90
94
|
## Data Fetching
|
|
@@ -189,6 +193,26 @@ Cart mutations use three layers of protection:
|
|
|
189
193
|
8. **Query keys**: Zawsze z `queryKeys.*` (nie hardcoded arrays)
|
|
190
194
|
9. **Config**: Zawsze z `graphqlConfig` (nie duplikuj env var resolution)
|
|
191
195
|
|
|
196
|
+
## i18n (next-intl + SDK)
|
|
197
|
+
|
|
198
|
+
**Architecture**: Dynamic locales from backend, static defaultLocale from env var.
|
|
199
|
+
|
|
200
|
+
**Env vars**:
|
|
201
|
+
- `NEXT_PUBLIC_DEFAULT_LOCALE` — default locale for URL routing (fallback: `'pl'`). Controls which locale is hidden in URL (`as-needed` prefix). After changing defaultLanguage in admin panel, update this env var in `.env.local` and restart dev server.
|
|
202
|
+
|
|
203
|
+
**Locale flow**:
|
|
204
|
+
- `proxy.ts` middleware fetches `supportedLanguages` from backend (cached 60s) — fully dynamic
|
|
205
|
+
- `routing.ts` exports `defaultLocale` (env+fallback) and `localePrefix` — no `defineRouting`, no hardcoded locales
|
|
206
|
+
- `navigation.ts` uses `createNavigation` without `locales` — any locale string accepted at runtime
|
|
207
|
+
- `layout.tsx` validates locale against `shop.supportedLanguages` from backend
|
|
208
|
+
|
|
209
|
+
**Language cookie**: Single `preferred-language` cookie (1 year) — serves both:
|
|
210
|
+
- next-intl middleware (locale detection/routing, via `localeCookie.name` override in proxy.ts)
|
|
211
|
+
- SDK language store (X-Lang header for backend, framework-agnostic)
|
|
212
|
+
- Cookie name constant: `LANGUAGE_COOKIE_NAME` exported from `@doswiftly/storefront-sdk`
|
|
213
|
+
|
|
214
|
+
**Known limitation**: `defaultLocale` is static (env var). Changing it requires `.env.local` update + restart. Dynamic `supportedLanguages` (add/remove locale) works immediately — no restart needed.
|
|
215
|
+
|
|
192
216
|
## GraphQL Operations
|
|
193
217
|
|
|
194
218
|
Operacje i schemat sa zdefiniowane w:
|
|
@@ -1,31 +1,34 @@
|
|
|
1
|
+
import { getTranslations } from "next-intl/server";
|
|
1
2
|
import { Breadcrumbs } from "@/components/layout/breadcrumbs";
|
|
2
3
|
|
|
3
|
-
export default function AboutPage() {
|
|
4
|
+
export default async function AboutPage() {
|
|
5
|
+
const t = await getTranslations("about");
|
|
6
|
+
|
|
4
7
|
return (
|
|
5
8
|
<div className="container mx-auto px-4 py-8">
|
|
6
9
|
<Breadcrumbs className="mb-6" />
|
|
7
|
-
|
|
10
|
+
|
|
8
11
|
<div className="mx-auto max-w-3xl">
|
|
9
|
-
<h1 className="mb-6 text-4xl font-bold text-foreground">
|
|
10
|
-
|
|
12
|
+
<h1 className="mb-6 text-4xl font-bold text-foreground">{t("title")}</h1>
|
|
13
|
+
|
|
11
14
|
<div className="prose prose-gray max-w-none">
|
|
12
15
|
<p className="text-lg text-muted-foreground">
|
|
13
|
-
|
|
16
|
+
{t("welcome")}
|
|
14
17
|
</p>
|
|
15
|
-
|
|
16
|
-
<h2 className="mt-8 text-2xl font-semibold text-foreground">
|
|
18
|
+
|
|
19
|
+
<h2 className="mt-8 text-2xl font-semibold text-foreground">{t("ourStory")}</h2>
|
|
17
20
|
<p className="text-muted-foreground">
|
|
18
|
-
|
|
21
|
+
{t("ourStoryText")}
|
|
19
22
|
</p>
|
|
20
|
-
|
|
21
|
-
<h2 className="mt-8 text-2xl font-semibold text-foreground">
|
|
23
|
+
|
|
24
|
+
<h2 className="mt-8 text-2xl font-semibold text-foreground">{t("ourMission")}</h2>
|
|
22
25
|
<p className="text-muted-foreground">
|
|
23
|
-
|
|
26
|
+
{t("ourMissionText")}
|
|
24
27
|
</p>
|
|
25
|
-
|
|
26
|
-
<h2 className="mt-8 text-2xl font-semibold text-foreground">
|
|
28
|
+
|
|
29
|
+
<h2 className="mt-8 text-2xl font-semibold text-foreground">{t("contactTitle")}</h2>
|
|
27
30
|
<p className="text-muted-foreground">
|
|
28
|
-
|
|
31
|
+
{t("contactText")}
|
|
29
32
|
</p>
|
|
30
33
|
</div>
|
|
31
34
|
</div>
|
package/templates/storefront-nextjs-shadcn/app/{account → [locale]/account}/addresses/page.tsx
RENAMED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
3
|
import { useState, useCallback } from "react";
|
|
4
|
-
import Link from "
|
|
4
|
+
import { Link } from "@/i18n/navigation";
|
|
5
|
+
import { useTranslations } from "next-intl";
|
|
5
6
|
import { Plus } from "lucide-react";
|
|
6
7
|
import { useAuthStore, useAuthHydrated } from "@doswiftly/storefront-sdk/react";
|
|
7
8
|
import {
|
|
@@ -30,6 +31,7 @@ import {
|
|
|
30
31
|
} from "@/components/ui/dialog";
|
|
31
32
|
|
|
32
33
|
export default function AddressesPage() {
|
|
34
|
+
const t = useTranslations("account");
|
|
33
35
|
const hydrated = useHydrated();
|
|
34
36
|
const authHydrated = useAuthHydrated();
|
|
35
37
|
const accessToken = useAuthStore((s) => s.accessToken);
|
|
@@ -52,11 +54,11 @@ export default function AddressesPage() {
|
|
|
52
54
|
|
|
53
55
|
const deleteMutation = useCustomerAddressDelete({
|
|
54
56
|
onSuccess: (data) => checkUserErrors(data, 'customerAddressDelete'),
|
|
55
|
-
onError: () => setMutationError('
|
|
57
|
+
onError: () => setMutationError(t('failedDelete')),
|
|
56
58
|
});
|
|
57
59
|
const setDefaultMutation = useCustomerDefaultAddressUpdate({
|
|
58
60
|
onSuccess: (data) => checkUserErrors(data, 'customerDefaultAddressUpdate'),
|
|
59
|
-
onError: () => setMutationError('
|
|
61
|
+
onError: () => setMutationError(t('failedSetDefault')),
|
|
60
62
|
});
|
|
61
63
|
|
|
62
64
|
const createMutation = useCustomerAddressCreate({
|
|
@@ -65,7 +67,7 @@ export default function AddressesPage() {
|
|
|
65
67
|
setIsFormOpen(false);
|
|
66
68
|
}
|
|
67
69
|
},
|
|
68
|
-
onError: () => setMutationError('
|
|
70
|
+
onError: () => setMutationError(t('failedCreate')),
|
|
69
71
|
});
|
|
70
72
|
|
|
71
73
|
const updateMutation = useCustomerAddressUpdate({
|
|
@@ -74,7 +76,7 @@ export default function AddressesPage() {
|
|
|
74
76
|
setIsFormOpen(false);
|
|
75
77
|
}
|
|
76
78
|
},
|
|
77
|
-
onError: () => setMutationError('
|
|
79
|
+
onError: () => setMutationError(t('failedUpdate')),
|
|
78
80
|
});
|
|
79
81
|
|
|
80
82
|
const addresses = (customerData?.customer?.addresses ?? []).map((addr) => ({
|
|
@@ -103,7 +105,7 @@ export default function AddressesPage() {
|
|
|
103
105
|
};
|
|
104
106
|
|
|
105
107
|
const handleDelete = (id: string) => {
|
|
106
|
-
if (confirm("
|
|
108
|
+
if (confirm(t("deleteConfirm"))) {
|
|
107
109
|
deleteMutation.mutate(id);
|
|
108
110
|
}
|
|
109
111
|
};
|
|
@@ -162,11 +164,13 @@ export default function AddressesPage() {
|
|
|
162
164
|
<div className="container mx-auto px-4 py-8">
|
|
163
165
|
<Breadcrumbs className="mb-6" />
|
|
164
166
|
<div className="rounded-lg border border-destructive bg-destructive/10 p-8 text-center text-sm text-destructive">
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
167
|
+
{t.rich("signInToManage", {
|
|
168
|
+
link: (chunks) => (
|
|
169
|
+
<Link href="/auth/login?redirect=/account/addresses" className="font-medium underline">
|
|
170
|
+
{chunks}
|
|
171
|
+
</Link>
|
|
172
|
+
),
|
|
173
|
+
})}
|
|
170
174
|
</div>
|
|
171
175
|
</div>
|
|
172
176
|
);
|
|
@@ -178,14 +182,14 @@ export default function AddressesPage() {
|
|
|
178
182
|
|
|
179
183
|
<div className="mb-8 flex items-center justify-between">
|
|
180
184
|
<div>
|
|
181
|
-
<h1 className="text-3xl font-bold text-foreground">
|
|
185
|
+
<h1 className="text-3xl font-bold text-foreground">{t("addresses")}</h1>
|
|
182
186
|
<p className="mt-2 text-muted-foreground">
|
|
183
|
-
|
|
187
|
+
{t("manageAddresses")}
|
|
184
188
|
</p>
|
|
185
189
|
</div>
|
|
186
190
|
<Button onClick={handleAdd}>
|
|
187
191
|
<Plus className="mr-2 h-4 w-4" />
|
|
188
|
-
|
|
192
|
+
{t("addAddress")}
|
|
189
193
|
</Button>
|
|
190
194
|
</div>
|
|
191
195
|
|
|
@@ -207,7 +211,7 @@ export default function AddressesPage() {
|
|
|
207
211
|
<DialogContent className="max-w-2xl max-h-[90vh] overflow-y-auto">
|
|
208
212
|
<DialogHeader>
|
|
209
213
|
<DialogTitle>
|
|
210
|
-
{editingAddress ? "
|
|
214
|
+
{editingAddress ? t("editAddress") : t("addNewAddress")}
|
|
211
215
|
</DialogTitle>
|
|
212
216
|
</DialogHeader>
|
|
213
217
|
<AddressForm
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
3
|
import { useEffect } from "react";
|
|
4
|
-
import
|
|
4
|
+
import { useTranslations } from "next-intl";
|
|
5
|
+
import { Link } from "@/i18n/navigation";
|
|
5
6
|
import { AlertCircle } from "lucide-react";
|
|
6
7
|
import { Button } from "@/components/ui/button";
|
|
7
8
|
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
|
@@ -13,6 +14,8 @@ export default function AccountError({
|
|
|
13
14
|
error: Error & { digest?: string };
|
|
14
15
|
reset: () => void;
|
|
15
16
|
}) {
|
|
17
|
+
const t = useTranslations("errors");
|
|
18
|
+
|
|
16
19
|
useEffect(() => {
|
|
17
20
|
console.error("[Account Error]", error);
|
|
18
21
|
}, [error]);
|
|
@@ -23,17 +26,17 @@ export default function AccountError({
|
|
|
23
26
|
<CardHeader>
|
|
24
27
|
<CardTitle className="flex items-center gap-2 text-destructive">
|
|
25
28
|
<AlertCircle className="h-5 w-5" />
|
|
26
|
-
|
|
29
|
+
{t("somethingWentWrong")}
|
|
27
30
|
</CardTitle>
|
|
28
31
|
</CardHeader>
|
|
29
32
|
<CardContent className="space-y-4">
|
|
30
33
|
<p className="text-sm text-muted-foreground">
|
|
31
|
-
|
|
34
|
+
{t("couldNotLoadAccount")}
|
|
32
35
|
</p>
|
|
33
36
|
<div className="flex gap-3">
|
|
34
|
-
<Button onClick={reset}>
|
|
37
|
+
<Button onClick={reset}>{t("tryAgain")}</Button>
|
|
35
38
|
<Button variant="outline" asChild>
|
|
36
|
-
<Link href="/">
|
|
39
|
+
<Link href="/">{t("goHome")}</Link>
|
|
37
40
|
</Button>
|
|
38
41
|
</div>
|
|
39
42
|
</CardContent>
|
package/templates/storefront-nextjs-shadcn/app/{account → [locale]/account}/loyalty/page.tsx
RENAMED
|
@@ -15,7 +15,8 @@
|
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
17
|
import { useState } from 'react';
|
|
18
|
-
import
|
|
18
|
+
import { useTranslations } from 'next-intl';
|
|
19
|
+
import { Link } from '@/i18n/navigation';
|
|
19
20
|
import { ArrowLeft, Gift, Award, History, Loader2, Users, AlertCircle } from 'lucide-react';
|
|
20
21
|
import { Button } from '@/components/ui/button';
|
|
21
22
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
|
@@ -40,6 +41,9 @@ import {
|
|
|
40
41
|
} from '@/lib/graphql/hooks';
|
|
41
42
|
|
|
42
43
|
export default function LoyaltyPage() {
|
|
44
|
+
const t = useTranslations("account");
|
|
45
|
+
const tl = useTranslations("loyalty.page");
|
|
46
|
+
const ta = useTranslations("auth");
|
|
43
47
|
const [activeTab, setActiveTab] = useState('overview');
|
|
44
48
|
const { isAuthenticated } = useAuthStore();
|
|
45
49
|
const isHydrated = useAuthHydrated();
|
|
@@ -86,7 +90,7 @@ export default function LoyaltyPage() {
|
|
|
86
90
|
};
|
|
87
91
|
}
|
|
88
92
|
|
|
89
|
-
throw new Error('
|
|
93
|
+
throw new Error(tl('redeemFailed'));
|
|
90
94
|
} catch (error) {
|
|
91
95
|
throw error;
|
|
92
96
|
}
|
|
@@ -110,7 +114,7 @@ export default function LoyaltyPage() {
|
|
|
110
114
|
<Link href="/account">
|
|
111
115
|
<Button variant="ghost" size="sm" className="mb-4">
|
|
112
116
|
<ArrowLeft className="h-4 w-4 mr-2" />
|
|
113
|
-
|
|
117
|
+
{t("backToAccount")}
|
|
114
118
|
</Button>
|
|
115
119
|
</Link>
|
|
116
120
|
|
|
@@ -118,15 +122,15 @@ export default function LoyaltyPage() {
|
|
|
118
122
|
<CardHeader>
|
|
119
123
|
<CardTitle className="flex items-center gap-2">
|
|
120
124
|
<Award className="h-5 w-5" />
|
|
121
|
-
|
|
125
|
+
{t("loyalty")}
|
|
122
126
|
</CardTitle>
|
|
123
127
|
</CardHeader>
|
|
124
128
|
<CardContent>
|
|
125
129
|
<p className="text-muted-foreground mb-4">
|
|
126
|
-
|
|
130
|
+
{tl("signInToView")}
|
|
127
131
|
</p>
|
|
128
132
|
<Link href="/auth/login?redirect=/account/loyalty">
|
|
129
|
-
<Button className="w-full">
|
|
133
|
+
<Button className="w-full">{ta("signIn")}</Button>
|
|
130
134
|
</Link>
|
|
131
135
|
</CardContent>
|
|
132
136
|
</Card>
|
|
@@ -152,14 +156,14 @@ export default function LoyaltyPage() {
|
|
|
152
156
|
<Link href="/account">
|
|
153
157
|
<Button variant="ghost" size="sm" className="mb-4">
|
|
154
158
|
<ArrowLeft className="h-4 w-4 mr-2" />
|
|
155
|
-
|
|
159
|
+
{t("backToAccount")}
|
|
156
160
|
</Button>
|
|
157
161
|
</Link>
|
|
158
162
|
|
|
159
163
|
<Alert variant="destructive">
|
|
160
164
|
<AlertCircle className="h-4 w-4" />
|
|
161
165
|
<AlertDescription>
|
|
162
|
-
|
|
166
|
+
{tl("loadFailed")}
|
|
163
167
|
</AlertDescription>
|
|
164
168
|
</Alert>
|
|
165
169
|
</div>
|
|
@@ -173,14 +177,14 @@ export default function LoyaltyPage() {
|
|
|
173
177
|
<Link href="/account">
|
|
174
178
|
<Button variant="ghost" size="sm" className="mb-4">
|
|
175
179
|
<ArrowLeft className="h-4 w-4 mr-2" />
|
|
176
|
-
|
|
180
|
+
{t("backToAccount")}
|
|
177
181
|
</Button>
|
|
178
182
|
</Link>
|
|
179
183
|
|
|
180
184
|
<Alert>
|
|
181
185
|
<AlertCircle className="h-4 w-4" />
|
|
182
186
|
<AlertDescription>
|
|
183
|
-
|
|
187
|
+
{tl("unavailable")}
|
|
184
188
|
</AlertDescription>
|
|
185
189
|
</Alert>
|
|
186
190
|
</div>
|
|
@@ -194,7 +198,7 @@ export default function LoyaltyPage() {
|
|
|
194
198
|
<Link href="/account">
|
|
195
199
|
<Button variant="ghost" size="sm" className="mb-4">
|
|
196
200
|
<ArrowLeft className="h-4 w-4 mr-2" />
|
|
197
|
-
|
|
201
|
+
{t("backToAccount")}
|
|
198
202
|
</Button>
|
|
199
203
|
</Link>
|
|
200
204
|
|
|
@@ -202,16 +206,15 @@ export default function LoyaltyPage() {
|
|
|
202
206
|
<CardHeader>
|
|
203
207
|
<CardTitle className="flex items-center gap-2">
|
|
204
208
|
<Award className="h-5 w-5" />
|
|
205
|
-
|
|
209
|
+
{tl("joinTitle")}
|
|
206
210
|
</CardTitle>
|
|
207
211
|
</CardHeader>
|
|
208
212
|
<CardContent>
|
|
209
213
|
<p className="text-muted-foreground mb-4">
|
|
210
|
-
|
|
211
|
-
przy pierwszym zakupie.
|
|
214
|
+
{tl("joinDescription")}
|
|
212
215
|
</p>
|
|
213
216
|
<Link href="/products">
|
|
214
|
-
<Button className="w-full">
|
|
217
|
+
<Button className="w-full">{t("browseProducts")}</Button>
|
|
215
218
|
</Link>
|
|
216
219
|
</CardContent>
|
|
217
220
|
</Card>
|
|
@@ -229,15 +232,15 @@ export default function LoyaltyPage() {
|
|
|
229
232
|
<Link href="/account">
|
|
230
233
|
<Button variant="ghost" size="sm" className="mb-4">
|
|
231
234
|
<ArrowLeft className="h-4 w-4 mr-2" />
|
|
232
|
-
|
|
235
|
+
{t("backToAccount")}
|
|
233
236
|
</Button>
|
|
234
237
|
</Link>
|
|
235
238
|
|
|
236
239
|
<div className="flex items-center justify-between">
|
|
237
240
|
<div>
|
|
238
|
-
<h1 className="text-3xl font-bold mb-2">
|
|
241
|
+
<h1 className="text-3xl font-bold mb-2">{t("loyalty")}</h1>
|
|
239
242
|
<p className="text-muted-foreground">
|
|
240
|
-
|
|
243
|
+
{tl("collectAndRedeem", { pointsName: settings?.pointsName ?? 'punkty' })}
|
|
241
244
|
</p>
|
|
242
245
|
</div>
|
|
243
246
|
{member.tier && <TierBadge tier={member.tier.type} name={member.tier.name} size="lg" />}
|
|
@@ -249,20 +252,20 @@ export default function LoyaltyPage() {
|
|
|
249
252
|
<TabsList className="mb-6">
|
|
250
253
|
<TabsTrigger value="overview" className="gap-2">
|
|
251
254
|
<Award className="h-4 w-4" />
|
|
252
|
-
|
|
255
|
+
{tl("tabOverview")}
|
|
253
256
|
</TabsTrigger>
|
|
254
257
|
<TabsTrigger value="rewards" className="gap-2">
|
|
255
258
|
<Gift className="h-4 w-4" />
|
|
256
|
-
|
|
259
|
+
{tl("tabRewards")}
|
|
257
260
|
</TabsTrigger>
|
|
258
261
|
<TabsTrigger value="history" className="gap-2">
|
|
259
262
|
<History className="h-4 w-4" />
|
|
260
|
-
|
|
263
|
+
{tl("tabHistory")}
|
|
261
264
|
</TabsTrigger>
|
|
262
265
|
{showReferralTab && (
|
|
263
266
|
<TabsTrigger value="referral" className="gap-2">
|
|
264
267
|
<Users className="h-4 w-4" />
|
|
265
|
-
|
|
268
|
+
{tl("tabReferrals")}
|
|
266
269
|
</TabsTrigger>
|
|
267
270
|
)}
|
|
268
271
|
</TabsList>
|
|
@@ -279,11 +282,11 @@ export default function LoyaltyPage() {
|
|
|
279
282
|
<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">
|
|
280
283
|
<h3 className="font-semibold mb-4 flex items-center gap-2">
|
|
281
284
|
<Award className="h-5 w-5 text-amber-600" />
|
|
282
|
-
|
|
285
|
+
{tl("tierBenefits", { tierName: member.tier.name })}
|
|
283
286
|
</h3>
|
|
284
287
|
<div className="grid grid-cols-1 sm:grid-cols-3 gap-4 text-sm">
|
|
285
288
|
<div className="p-3 bg-white/50 dark:bg-black/20 rounded-lg">
|
|
286
|
-
<div className="font-medium">
|
|
289
|
+
<div className="font-medium">{tl("pointsMultiplier")}</div>
|
|
287
290
|
<div className="text-2xl font-bold text-amber-600">x{member.tier.pointsMultiplier}</div>
|
|
288
291
|
</div>
|
|
289
292
|
{member.tier.customBenefits?.slice(0, 2).map((benefit, idx) => (
|
|
@@ -311,16 +314,16 @@ export default function LoyaltyPage() {
|
|
|
311
314
|
<div className="flex flex-wrap gap-4">
|
|
312
315
|
<Button onClick={() => setActiveTab('rewards')}>
|
|
313
316
|
<Gift className="h-4 w-4 mr-2" />
|
|
314
|
-
|
|
317
|
+
{tl("browseRewards")}
|
|
315
318
|
</Button>
|
|
316
319
|
<Button variant="outline" onClick={() => setActiveTab('history')}>
|
|
317
320
|
<History className="h-4 w-4 mr-2" />
|
|
318
|
-
|
|
321
|
+
{tl("viewHistory")}
|
|
319
322
|
</Button>
|
|
320
323
|
{showReferralTab && (
|
|
321
324
|
<Button variant="outline" onClick={() => setActiveTab('referral')}>
|
|
322
325
|
<Users className="h-4 w-4 mr-2" />
|
|
323
|
-
|
|
326
|
+
{tl("referFriend")}
|
|
324
327
|
</Button>
|
|
325
328
|
)}
|
|
326
329
|
</div>
|
|
@@ -329,9 +332,9 @@ export default function LoyaltyPage() {
|
|
|
329
332
|
{/* Rewards Tab */}
|
|
330
333
|
<TabsContent value="rewards">
|
|
331
334
|
<div className="mb-6">
|
|
332
|
-
<h2 className="text-xl font-semibold mb-2">
|
|
335
|
+
<h2 className="text-xl font-semibold mb-2">{tl("availableRewards")}</h2>
|
|
333
336
|
<p className="text-muted-foreground">
|
|
334
|
-
|
|
337
|
+
{tl("redeemDescription", { pointsName: settings?.pointsName ?? 'punkty' })}
|
|
335
338
|
</p>
|
|
336
339
|
</div>
|
|
337
340
|
<RewardsCatalog
|
|
@@ -345,8 +348,8 @@ export default function LoyaltyPage() {
|
|
|
345
348
|
{/* History Tab */}
|
|
346
349
|
<TabsContent value="history">
|
|
347
350
|
<div className="mb-6">
|
|
348
|
-
<h2 className="text-xl font-semibold mb-2">
|
|
349
|
-
<p className="text-muted-foreground">
|
|
351
|
+
<h2 className="text-xl font-semibold mb-2">{tl("pointsHistory")}</h2>
|
|
352
|
+
<p className="text-muted-foreground">{tl("historyDescription")}</p>
|
|
350
353
|
</div>
|
|
351
354
|
<PointsHistory transactions={transactions} />
|
|
352
355
|
</TabsContent>
|
|
@@ -355,10 +358,12 @@ export default function LoyaltyPage() {
|
|
|
355
358
|
{showReferralTab && referralStats && (
|
|
356
359
|
<TabsContent value="referral">
|
|
357
360
|
<div className="mb-6">
|
|
358
|
-
<h2 className="text-xl font-semibold mb-2">
|
|
361
|
+
<h2 className="text-xl font-semibold mb-2">{tl("referFriend")}</h2>
|
|
359
362
|
<p className="text-muted-foreground">
|
|
360
|
-
|
|
361
|
-
|
|
363
|
+
{tl("referFriendDescription", {
|
|
364
|
+
points: settings?.referralPoints ?? 0,
|
|
365
|
+
pointsName: settings?.pointsName ?? 'punktów',
|
|
366
|
+
})}
|
|
362
367
|
</p>
|
|
363
368
|
</div>
|
|
364
369
|
<ReferralSection
|
package/templates/storefront-nextjs-shadcn/app/{account → [locale]/account}/orders/[id]/page.tsx
RENAMED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
3
|
import { useParams } from "next/navigation";
|
|
4
|
-
import Link from "
|
|
4
|
+
import { Link } from "@/i18n/navigation";
|
|
5
|
+
import { useTranslations } from "next-intl";
|
|
5
6
|
import { ChevronLeft } from "lucide-react";
|
|
6
7
|
import { useCustomerOrder } from "@/lib/graphql/hooks";
|
|
7
8
|
import { useHydrated } from "@doswiftly/storefront-sdk/react";
|
|
@@ -13,6 +14,7 @@ import {
|
|
|
13
14
|
} from "@/components/account/order-details";
|
|
14
15
|
|
|
15
16
|
export default function OrderDetailPage() {
|
|
17
|
+
const t = useTranslations("account");
|
|
16
18
|
const params = useParams();
|
|
17
19
|
const orderId = params.id as string;
|
|
18
20
|
const hydrated = useHydrated();
|
|
@@ -36,10 +38,10 @@ export default function OrderDetailPage() {
|
|
|
36
38
|
return (
|
|
37
39
|
<div className="container mx-auto px-4 py-8">
|
|
38
40
|
<div className="text-center">
|
|
39
|
-
<h1 className="text-2xl font-bold text-destructive">
|
|
40
|
-
<p className="mt-2 text-muted-foreground">
|
|
41
|
+
<h1 className="text-2xl font-bold text-destructive">{t("failedLoadOrder")}</h1>
|
|
42
|
+
<p className="mt-2 text-muted-foreground">{t("tryAgainLater")}</p>
|
|
41
43
|
<Link href="/account/orders">
|
|
42
|
-
<Button className="mt-4">
|
|
44
|
+
<Button className="mt-4">{t("backToOrders")}</Button>
|
|
43
45
|
</Link>
|
|
44
46
|
</div>
|
|
45
47
|
</div>
|
|
@@ -50,9 +52,9 @@ export default function OrderDetailPage() {
|
|
|
50
52
|
return (
|
|
51
53
|
<div className="container mx-auto px-4 py-8">
|
|
52
54
|
<div className="text-center">
|
|
53
|
-
<h1 className="text-2xl font-bold">
|
|
55
|
+
<h1 className="text-2xl font-bold">{t("orderNotFound")}</h1>
|
|
54
56
|
<Link href="/account/orders">
|
|
55
|
-
<Button className="mt-4">
|
|
57
|
+
<Button className="mt-4">{t("backToOrders")}</Button>
|
|
56
58
|
</Link>
|
|
57
59
|
</div>
|
|
58
60
|
</div>
|
|
@@ -106,7 +108,7 @@ export default function OrderDetailPage() {
|
|
|
106
108
|
<Button variant="ghost" asChild>
|
|
107
109
|
<Link href="/account/orders">
|
|
108
110
|
<ChevronLeft className="mr-2 h-4 w-4" />
|
|
109
|
-
|
|
111
|
+
{t("backToOrders")}
|
|
110
112
|
</Link>
|
|
111
113
|
</Button>
|
|
112
114
|
</div>
|