@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
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
import { useEffect, useState } from "react";
|
|
4
4
|
import { useSearchParams } from "next/navigation";
|
|
5
|
+
import { useTranslations } from "next-intl";
|
|
6
|
+
import { Link } from "@/i18n/navigation";
|
|
5
7
|
import { CheckCircle, Package, Mail, ArrowRight, Clock, Building2, Copy, Check } from "lucide-react";
|
|
6
|
-
import Link from "next/link";
|
|
7
8
|
import { Button } from "@/components/ui/button";
|
|
8
9
|
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
|
9
10
|
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
|
|
@@ -14,6 +15,7 @@ interface OrderSuccessPageProps {
|
|
|
14
15
|
}
|
|
15
16
|
|
|
16
17
|
export default function OrderSuccessPage({ params }: OrderSuccessPageProps) {
|
|
18
|
+
const t = useTranslations("checkout.success");
|
|
17
19
|
const [orderId, setOrderId] = useState<string>("");
|
|
18
20
|
const [copied, setCopied] = useState(false);
|
|
19
21
|
const searchParams = useSearchParams();
|
|
@@ -31,10 +33,10 @@ export default function OrderSuccessPage({ params }: OrderSuccessPageProps) {
|
|
|
31
33
|
try {
|
|
32
34
|
await navigator.clipboard.writeText(text);
|
|
33
35
|
setCopied(true);
|
|
34
|
-
toast.success("
|
|
36
|
+
toast.success(t("copied"));
|
|
35
37
|
setTimeout(() => setCopied(false), 2000);
|
|
36
38
|
} catch {
|
|
37
|
-
toast.error("
|
|
39
|
+
toast.error(t("copyFailed"));
|
|
38
40
|
}
|
|
39
41
|
};
|
|
40
42
|
|
|
@@ -43,7 +45,7 @@ export default function OrderSuccessPage({ params }: OrderSuccessPageProps) {
|
|
|
43
45
|
bankName: "Bank XYZ",
|
|
44
46
|
accountNumber: "PL12 3456 7890 1234 5678 9012 3456",
|
|
45
47
|
recipientName: "DoSwiftly Sp. z o.o.",
|
|
46
|
-
transferTitle:
|
|
48
|
+
transferTitle: t("bankTransfer.orderTitle", { orderId }),
|
|
47
49
|
amount: "---", // Would be fetched from order
|
|
48
50
|
};
|
|
49
51
|
|
|
@@ -63,23 +65,23 @@ export default function OrderSuccessPage({ params }: OrderSuccessPageProps) {
|
|
|
63
65
|
|
|
64
66
|
{/* Heading */}
|
|
65
67
|
<h1 className="mb-2 text-3xl font-bold">
|
|
66
|
-
{isPendingPayment ? "
|
|
68
|
+
{isPendingPayment ? t("pendingPayment") : t("thankYou")}
|
|
67
69
|
</h1>
|
|
68
70
|
<p className="mb-8 text-muted-foreground">
|
|
69
71
|
{isPendingPayment
|
|
70
|
-
? "
|
|
71
|
-
: "
|
|
72
|
+
? t("pendingDescription")
|
|
73
|
+
: t("confirmedDescription")}
|
|
72
74
|
</p>
|
|
73
75
|
|
|
74
76
|
{/* Order Number */}
|
|
75
77
|
<Card className="mb-8">
|
|
76
78
|
<CardHeader>
|
|
77
|
-
<CardTitle className="text-lg">
|
|
79
|
+
<CardTitle className="text-lg">{t("orderConfirmation")}</CardTitle>
|
|
78
80
|
</CardHeader>
|
|
79
81
|
<CardContent>
|
|
80
82
|
<div className="space-y-4">
|
|
81
83
|
<div className="flex items-center justify-between border-b pb-4">
|
|
82
|
-
<span className="text-muted-foreground">
|
|
84
|
+
<span className="text-muted-foreground">{t("orderNumber")}</span>
|
|
83
85
|
<span className="font-mono font-medium">{orderId || "..."}</span>
|
|
84
86
|
</div>
|
|
85
87
|
|
|
@@ -87,9 +89,9 @@ export default function OrderSuccessPage({ params }: OrderSuccessPageProps) {
|
|
|
87
89
|
<div className="flex items-start gap-3">
|
|
88
90
|
<Mail className="mt-1 h-5 w-5 text-muted-foreground" />
|
|
89
91
|
<div className="text-left">
|
|
90
|
-
<p className="font-medium">
|
|
92
|
+
<p className="font-medium">{t("confirmationEmail")}</p>
|
|
91
93
|
<p className="text-sm text-muted-foreground">
|
|
92
|
-
|
|
94
|
+
{t("emailSent")}
|
|
93
95
|
</p>
|
|
94
96
|
</div>
|
|
95
97
|
</div>
|
|
@@ -97,9 +99,9 @@ export default function OrderSuccessPage({ params }: OrderSuccessPageProps) {
|
|
|
97
99
|
<div className="flex items-start gap-3">
|
|
98
100
|
<Package className="mt-1 h-5 w-5 text-muted-foreground" />
|
|
99
101
|
<div className="text-left">
|
|
100
|
-
<p className="font-medium"
|
|
102
|
+
<p className="font-medium">{t("tracking")}</p>
|
|
101
103
|
<p className="text-sm text-muted-foreground">
|
|
102
|
-
|
|
104
|
+
{t("trackingInfo")}
|
|
103
105
|
</p>
|
|
104
106
|
</div>
|
|
105
107
|
</div>
|
|
@@ -112,15 +114,15 @@ export default function OrderSuccessPage({ params }: OrderSuccessPageProps) {
|
|
|
112
114
|
{isBankTransfer && (
|
|
113
115
|
<Alert className="mb-8 text-left">
|
|
114
116
|
<Building2 className="h-4 w-4" />
|
|
115
|
-
<AlertTitle>
|
|
117
|
+
<AlertTitle>{t("bankTransfer.title")}</AlertTitle>
|
|
116
118
|
<AlertDescription className="mt-4 space-y-3">
|
|
117
119
|
<div className="grid gap-3">
|
|
118
120
|
<div className="flex items-center justify-between">
|
|
119
|
-
<span className="text-sm text-muted-foreground">
|
|
121
|
+
<span className="text-sm text-muted-foreground">{t("bankTransfer.bankName")}</span>
|
|
120
122
|
<span className="font-medium">{bankTransferDetails.bankName}</span>
|
|
121
123
|
</div>
|
|
122
124
|
<div className="flex items-center justify-between gap-2">
|
|
123
|
-
<span className="text-sm text-muted-foreground">
|
|
125
|
+
<span className="text-sm text-muted-foreground">{t("bankTransfer.accountNumber")}</span>
|
|
124
126
|
<div className="flex items-center gap-2">
|
|
125
127
|
<span className="font-mono text-sm">{bankTransferDetails.accountNumber}</span>
|
|
126
128
|
<Button
|
|
@@ -134,11 +136,11 @@ export default function OrderSuccessPage({ params }: OrderSuccessPageProps) {
|
|
|
134
136
|
</div>
|
|
135
137
|
</div>
|
|
136
138
|
<div className="flex items-center justify-between">
|
|
137
|
-
<span className="text-sm text-muted-foreground">
|
|
139
|
+
<span className="text-sm text-muted-foreground">{t("bankTransfer.recipient")}</span>
|
|
138
140
|
<span className="font-medium">{bankTransferDetails.recipientName}</span>
|
|
139
141
|
</div>
|
|
140
142
|
<div className="flex items-center justify-between gap-2">
|
|
141
|
-
<span className="text-sm text-muted-foreground">
|
|
143
|
+
<span className="text-sm text-muted-foreground">{t("bankTransfer.transferTitle")}</span>
|
|
142
144
|
<div className="flex items-center gap-2">
|
|
143
145
|
<span className="font-medium">{bankTransferDetails.transferTitle}</span>
|
|
144
146
|
<Button
|
|
@@ -153,7 +155,7 @@ export default function OrderSuccessPage({ params }: OrderSuccessPageProps) {
|
|
|
153
155
|
</div>
|
|
154
156
|
</div>
|
|
155
157
|
<p className="mt-4 text-sm text-muted-foreground">
|
|
156
|
-
|
|
158
|
+
{t("bankTransfer.processingNote")}
|
|
157
159
|
</p>
|
|
158
160
|
</AlertDescription>
|
|
159
161
|
</Alert>
|
|
@@ -162,7 +164,7 @@ export default function OrderSuccessPage({ params }: OrderSuccessPageProps) {
|
|
|
162
164
|
{/* What's Next */}
|
|
163
165
|
<Card className="mb-8">
|
|
164
166
|
<CardHeader>
|
|
165
|
-
<CardTitle className="text-lg">
|
|
167
|
+
<CardTitle className="text-lg">{t("whatsNext")}</CardTitle>
|
|
166
168
|
</CardHeader>
|
|
167
169
|
<CardContent>
|
|
168
170
|
<ol className="space-y-3 text-left">
|
|
@@ -173,9 +175,9 @@ export default function OrderSuccessPage({ params }: OrderSuccessPageProps) {
|
|
|
173
175
|
1
|
|
174
176
|
</span>
|
|
175
177
|
<div>
|
|
176
|
-
<p className="font-medium">
|
|
178
|
+
<p className="font-medium">{t("stepMakeTransfer")}</p>
|
|
177
179
|
<p className="text-sm text-muted-foreground">
|
|
178
|
-
|
|
180
|
+
{t("stepMakeTransferDesc")}
|
|
179
181
|
</p>
|
|
180
182
|
</div>
|
|
181
183
|
</li>
|
|
@@ -184,9 +186,9 @@ export default function OrderSuccessPage({ params }: OrderSuccessPageProps) {
|
|
|
184
186
|
2
|
|
185
187
|
</span>
|
|
186
188
|
<div>
|
|
187
|
-
<p className="font-medium">
|
|
189
|
+
<p className="font-medium">{t("stepPaymentConfirmation")}</p>
|
|
188
190
|
<p className="text-sm text-muted-foreground">
|
|
189
|
-
|
|
191
|
+
{t("stepPaymentConfirmationDesc")}
|
|
190
192
|
</p>
|
|
191
193
|
</div>
|
|
192
194
|
</li>
|
|
@@ -197,9 +199,9 @@ export default function OrderSuccessPage({ params }: OrderSuccessPageProps) {
|
|
|
197
199
|
1
|
|
198
200
|
</span>
|
|
199
201
|
<div>
|
|
200
|
-
<p className="font-medium">
|
|
202
|
+
<p className="font-medium">{t("stepProcessing")}</p>
|
|
201
203
|
<p className="text-sm text-muted-foreground">
|
|
202
|
-
|
|
204
|
+
{t("stepProcessingDesc")}
|
|
203
205
|
</p>
|
|
204
206
|
</div>
|
|
205
207
|
</li>
|
|
@@ -209,9 +211,9 @@ export default function OrderSuccessPage({ params }: OrderSuccessPageProps) {
|
|
|
209
211
|
{isBankTransfer ? 3 : 2}
|
|
210
212
|
</span>
|
|
211
213
|
<div>
|
|
212
|
-
<p className="font-medium">
|
|
214
|
+
<p className="font-medium">{t("stepShipping")}</p>
|
|
213
215
|
<p className="text-sm text-muted-foreground">
|
|
214
|
-
|
|
216
|
+
{t("stepShippingDesc")}
|
|
215
217
|
</p>
|
|
216
218
|
</div>
|
|
217
219
|
</li>
|
|
@@ -220,9 +222,9 @@ export default function OrderSuccessPage({ params }: OrderSuccessPageProps) {
|
|
|
220
222
|
{isBankTransfer ? 4 : 3}
|
|
221
223
|
</span>
|
|
222
224
|
<div>
|
|
223
|
-
<p className="font-medium">
|
|
225
|
+
<p className="font-medium">{t("stepDelivery")}</p>
|
|
224
226
|
<p className="text-sm text-muted-foreground">
|
|
225
|
-
|
|
227
|
+
{t("stepDeliveryDesc")}
|
|
226
228
|
</p>
|
|
227
229
|
</div>
|
|
228
230
|
</li>
|
|
@@ -234,20 +236,20 @@ export default function OrderSuccessPage({ params }: OrderSuccessPageProps) {
|
|
|
234
236
|
<div className="flex flex-col gap-4 sm:flex-row sm:justify-center">
|
|
235
237
|
<Button asChild>
|
|
236
238
|
<Link href="/products">
|
|
237
|
-
|
|
239
|
+
{t("continueShopping")}
|
|
238
240
|
<ArrowRight className="ml-2 h-4 w-4" />
|
|
239
241
|
</Link>
|
|
240
242
|
</Button>
|
|
241
243
|
<Button variant="outline" asChild>
|
|
242
|
-
<Link href="/account/orders">
|
|
244
|
+
<Link href="/account/orders">{t("myOrders")}</Link>
|
|
243
245
|
</Button>
|
|
244
246
|
</div>
|
|
245
247
|
|
|
246
248
|
{/* Help */}
|
|
247
249
|
<p className="mt-8 text-sm text-muted-foreground">
|
|
248
|
-
|
|
250
|
+
{t("needHelp")}{" "}
|
|
249
251
|
<Link href="/contact" className="text-primary underline underline-offset-4">
|
|
250
|
-
|
|
252
|
+
{t("contactUs")}
|
|
251
253
|
</Link>
|
|
252
254
|
</p>
|
|
253
255
|
</div>
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
3
|
import { useParams } from "next/navigation";
|
|
4
|
+
import { useTranslations } from "next-intl";
|
|
4
5
|
import { ProductGrid } from "@/components/product/product-grid";
|
|
5
6
|
import { Breadcrumbs } from "@/components/layout/breadcrumbs";
|
|
6
7
|
import { Skeleton } from "@/components/ui/skeleton";
|
|
@@ -9,6 +10,7 @@ import { useCollection } from "@/lib/graphql/hooks";
|
|
|
9
10
|
export default function CollectionPage() {
|
|
10
11
|
const params = useParams();
|
|
11
12
|
const handle = params.handle as string;
|
|
13
|
+
const t = useTranslations("collections");
|
|
12
14
|
|
|
13
15
|
// Fetch collection using GraphQL
|
|
14
16
|
const { data, isLoading, error } = useCollection(handle);
|
|
@@ -39,10 +41,10 @@ export default function CollectionPage() {
|
|
|
39
41
|
<Breadcrumbs className="mb-6" />
|
|
40
42
|
<div className="rounded-lg border border-border bg-muted/50 p-12 text-center">
|
|
41
43
|
<h1 className="text-2xl font-bold text-foreground mb-2">
|
|
42
|
-
|
|
44
|
+
{t("notFound")}
|
|
43
45
|
</h1>
|
|
44
46
|
<p className="text-muted-foreground">
|
|
45
|
-
|
|
47
|
+
{t("notFoundDescription")}
|
|
46
48
|
</p>
|
|
47
49
|
</div>
|
|
48
50
|
</div>
|
|
@@ -67,7 +69,7 @@ export default function CollectionPage() {
|
|
|
67
69
|
columns={4}
|
|
68
70
|
priorityCount={8}
|
|
69
71
|
showBadges
|
|
70
|
-
emptyMessage="
|
|
72
|
+
emptyMessage={t("noProducts")}
|
|
71
73
|
/>
|
|
72
74
|
</div>
|
|
73
75
|
);
|
package/templates/storefront-nextjs-shadcn/app/{collections → [locale]/collections}/page.tsx
RENAMED
|
@@ -1,17 +1,22 @@
|
|
|
1
1
|
import { Metadata } from "next";
|
|
2
|
-
import
|
|
2
|
+
import { getTranslations } from "next-intl/server";
|
|
3
|
+
import { Link } from "@/i18n/navigation";
|
|
3
4
|
import { Card } from "@/components/ui/card";
|
|
4
5
|
import { fetchCollections } from "@/lib/graphql/server";
|
|
5
6
|
|
|
6
|
-
export
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
export async function generateMetadata(): Promise<Metadata> {
|
|
8
|
+
const t = await getTranslations("collections");
|
|
9
|
+
return {
|
|
10
|
+
title: t("title"),
|
|
11
|
+
description: t("description"),
|
|
12
|
+
};
|
|
13
|
+
}
|
|
10
14
|
|
|
11
15
|
// Enable ISR with 60 second revalidation
|
|
12
16
|
export const revalidate = 60;
|
|
13
17
|
|
|
14
18
|
export default async function CollectionsPage() {
|
|
19
|
+
const t = await getTranslations("collections");
|
|
15
20
|
let collectionList: Awaited<ReturnType<typeof fetchCollections>>['collections'] = [];
|
|
16
21
|
|
|
17
22
|
try {
|
|
@@ -24,15 +29,15 @@ export default async function CollectionsPage() {
|
|
|
24
29
|
return (
|
|
25
30
|
<div className="container mx-auto px-4 py-8">
|
|
26
31
|
<div className="mb-8">
|
|
27
|
-
<h1 className="text-3xl font-bold text-foreground">
|
|
32
|
+
<h1 className="text-3xl font-bold text-foreground">{t("title")}</h1>
|
|
28
33
|
<p className="mt-2 text-muted-foreground">
|
|
29
|
-
|
|
34
|
+
{t("description")}
|
|
30
35
|
</p>
|
|
31
36
|
</div>
|
|
32
37
|
|
|
33
38
|
{collectionList.length === 0 ? (
|
|
34
39
|
<div className="rounded-lg border border-border bg-muted/50 p-12 text-center">
|
|
35
|
-
<p className="text-muted-foreground">
|
|
40
|
+
<p className="text-muted-foreground">{t("noCollections")}</p>
|
|
36
41
|
</div>
|
|
37
42
|
) : (
|
|
38
43
|
<div className="grid grid-cols-1 gap-6 md:grid-cols-2 lg:grid-cols-3">
|
|
@@ -1,20 +1,23 @@
|
|
|
1
|
+
import { getTranslations } from "next-intl/server";
|
|
1
2
|
import { Breadcrumbs } from "@/components/layout/breadcrumbs";
|
|
2
3
|
import { Mail, Phone, MapPin } from "lucide-react";
|
|
3
4
|
import { Button } from "@/components/ui/button";
|
|
4
5
|
import { Input } from "@/components/ui/input";
|
|
5
6
|
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
|
6
7
|
|
|
7
|
-
export default function ContactPage() {
|
|
8
|
+
export default async function ContactPage() {
|
|
9
|
+
const t = await getTranslations("contact");
|
|
10
|
+
|
|
8
11
|
return (
|
|
9
12
|
<div className="container mx-auto px-4 py-8">
|
|
10
13
|
<Breadcrumbs className="mb-6" />
|
|
11
|
-
|
|
14
|
+
|
|
12
15
|
<div className="mx-auto max-w-4xl">
|
|
13
|
-
<h1 className="mb-6 text-4xl font-bold text-foreground">
|
|
16
|
+
<h1 className="mb-6 text-4xl font-bold text-foreground">{t("title")}</h1>
|
|
14
17
|
<p className="mb-8 text-lg text-muted-foreground">
|
|
15
|
-
|
|
18
|
+
{t("description")}
|
|
16
19
|
</p>
|
|
17
|
-
|
|
20
|
+
|
|
18
21
|
<div className="grid gap-8 md:grid-cols-3">
|
|
19
22
|
{/* Contact Info */}
|
|
20
23
|
<div className="space-y-6">
|
|
@@ -22,7 +25,7 @@ export default function ContactPage() {
|
|
|
22
25
|
<CardHeader>
|
|
23
26
|
<CardTitle className="flex items-center gap-2 text-base">
|
|
24
27
|
<Mail className="h-5 w-5" />
|
|
25
|
-
|
|
28
|
+
{t("emailLabel")}
|
|
26
29
|
</CardTitle>
|
|
27
30
|
</CardHeader>
|
|
28
31
|
<CardContent>
|
|
@@ -31,12 +34,12 @@ export default function ContactPage() {
|
|
|
31
34
|
</p>
|
|
32
35
|
</CardContent>
|
|
33
36
|
</Card>
|
|
34
|
-
|
|
37
|
+
|
|
35
38
|
<Card>
|
|
36
39
|
<CardHeader>
|
|
37
40
|
<CardTitle className="flex items-center gap-2 text-base">
|
|
38
41
|
<Phone className="h-5 w-5" />
|
|
39
|
-
|
|
42
|
+
{t("phoneLabel")}
|
|
40
43
|
</CardTitle>
|
|
41
44
|
</CardHeader>
|
|
42
45
|
<CardContent>
|
|
@@ -45,12 +48,12 @@ export default function ContactPage() {
|
|
|
45
48
|
</p>
|
|
46
49
|
</CardContent>
|
|
47
50
|
</Card>
|
|
48
|
-
|
|
51
|
+
|
|
49
52
|
<Card>
|
|
50
53
|
<CardHeader>
|
|
51
54
|
<CardTitle className="flex items-center gap-2 text-base">
|
|
52
55
|
<MapPin className="h-5 w-5" />
|
|
53
|
-
|
|
56
|
+
{t("addressLabel")}
|
|
54
57
|
</CardTitle>
|
|
55
58
|
</CardHeader>
|
|
56
59
|
<CardContent>
|
|
@@ -61,48 +64,48 @@ export default function ContactPage() {
|
|
|
61
64
|
</CardContent>
|
|
62
65
|
</Card>
|
|
63
66
|
</div>
|
|
64
|
-
|
|
67
|
+
|
|
65
68
|
{/* Contact Form */}
|
|
66
69
|
<Card className="md:col-span-2">
|
|
67
70
|
<CardHeader>
|
|
68
|
-
<CardTitle>
|
|
71
|
+
<CardTitle>{t("formTitle")}</CardTitle>
|
|
69
72
|
</CardHeader>
|
|
70
73
|
<CardContent>
|
|
71
74
|
<form className="space-y-4">
|
|
72
75
|
<div className="grid gap-4 sm:grid-cols-2">
|
|
73
76
|
<div className="space-y-2">
|
|
74
77
|
<label htmlFor="name" className="text-sm font-medium">
|
|
75
|
-
|
|
78
|
+
{t("name")}
|
|
76
79
|
</label>
|
|
77
|
-
<Input id="name" placeholder="
|
|
80
|
+
<Input id="name" placeholder={t("namePlaceholder")} required />
|
|
78
81
|
</div>
|
|
79
82
|
<div className="space-y-2">
|
|
80
83
|
<label htmlFor="email" className="text-sm font-medium">
|
|
81
|
-
|
|
84
|
+
{t("email")}
|
|
82
85
|
</label>
|
|
83
|
-
<Input id="email" type="email" placeholder="
|
|
86
|
+
<Input id="email" type="email" placeholder={t("emailPlaceholder")} required />
|
|
84
87
|
</div>
|
|
85
88
|
</div>
|
|
86
89
|
<div className="space-y-2">
|
|
87
90
|
<label htmlFor="subject" className="text-sm font-medium">
|
|
88
|
-
|
|
91
|
+
{t("subject")}
|
|
89
92
|
</label>
|
|
90
|
-
<Input id="subject" placeholder="
|
|
93
|
+
<Input id="subject" placeholder={t("subjectPlaceholder")} required />
|
|
91
94
|
</div>
|
|
92
95
|
<div className="space-y-2">
|
|
93
96
|
<label htmlFor="message" className="text-sm font-medium">
|
|
94
|
-
|
|
97
|
+
{t("message")}
|
|
95
98
|
</label>
|
|
96
99
|
<textarea
|
|
97
100
|
id="message"
|
|
98
101
|
rows={6}
|
|
99
102
|
className="w-full rounded-md border border-border bg-background px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-ring"
|
|
100
|
-
placeholder="
|
|
103
|
+
placeholder={t("messagePlaceholder")}
|
|
101
104
|
required
|
|
102
105
|
/>
|
|
103
106
|
</div>
|
|
104
107
|
<Button type="submit" className="w-full">
|
|
105
|
-
|
|
108
|
+
{t("send")}
|
|
106
109
|
</Button>
|
|
107
110
|
</form>
|
|
108
111
|
</CardContent>
|
|
@@ -10,7 +10,8 @@
|
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
12
|
import { useEffect } from 'react';
|
|
13
|
-
import
|
|
13
|
+
import { useTranslations } from 'next-intl';
|
|
14
|
+
import { Link } from '@/i18n/navigation';
|
|
14
15
|
import { AlertTriangle, RefreshCcw, Home, ShoppingBag } from 'lucide-react';
|
|
15
16
|
import { Button } from '@/components/ui/button';
|
|
16
17
|
import { Card, CardContent, CardHeader, CardTitle, CardDescription } from '@/components/ui/card';
|
|
@@ -21,6 +22,10 @@ interface ErrorPageProps {
|
|
|
21
22
|
}
|
|
22
23
|
|
|
23
24
|
export default function ErrorPage({ error, reset }: ErrorPageProps) {
|
|
25
|
+
const t = useTranslations('errors');
|
|
26
|
+
const tNav = useTranslations('nav');
|
|
27
|
+
const tNotFound = useTranslations('notFound');
|
|
28
|
+
|
|
24
29
|
useEffect(() => {
|
|
25
30
|
// Log error to console in development
|
|
26
31
|
if (process.env.NODE_ENV === 'development') {
|
|
@@ -36,9 +41,9 @@ export default function ErrorPage({ error, reset }: ErrorPageProps) {
|
|
|
36
41
|
<div className="mx-auto mb-4 flex h-16 w-16 items-center justify-center rounded-full bg-destructive/10">
|
|
37
42
|
<AlertTriangle className="h-8 w-8 text-destructive" />
|
|
38
43
|
</div>
|
|
39
|
-
<CardTitle className="text-2xl">
|
|
44
|
+
<CardTitle className="text-2xl">{t("somethingWentWrong")}</CardTitle>
|
|
40
45
|
<CardDescription className="text-base">
|
|
41
|
-
|
|
46
|
+
{t("unexpectedError")}
|
|
42
47
|
</CardDescription>
|
|
43
48
|
</CardHeader>
|
|
44
49
|
<CardContent className="space-y-4">
|
|
@@ -56,20 +61,20 @@ export default function ErrorPage({ error, reset }: ErrorPageProps) {
|
|
|
56
61
|
<div className="flex flex-col gap-3">
|
|
57
62
|
<Button onClick={reset} className="w-full">
|
|
58
63
|
<RefreshCcw className="mr-2 h-4 w-4" />
|
|
59
|
-
|
|
64
|
+
{t("tryAgain")}
|
|
60
65
|
</Button>
|
|
61
66
|
|
|
62
67
|
<div className="flex gap-3">
|
|
63
68
|
<Button variant="outline" asChild className="flex-1">
|
|
64
69
|
<Link href="/">
|
|
65
70
|
<Home className="mr-2 h-4 w-4" />
|
|
66
|
-
|
|
71
|
+
{t("goHome")}
|
|
67
72
|
</Link>
|
|
68
73
|
</Button>
|
|
69
74
|
<Button variant="outline" asChild className="flex-1">
|
|
70
75
|
<Link href="/products">
|
|
71
76
|
<ShoppingBag className="mr-2 h-4 w-4" />
|
|
72
|
-
|
|
77
|
+
{tNav("products")}
|
|
73
78
|
</Link>
|
|
74
79
|
</Button>
|
|
75
80
|
</div>
|
|
@@ -77,9 +82,9 @@ export default function ErrorPage({ error, reset }: ErrorPageProps) {
|
|
|
77
82
|
|
|
78
83
|
{/* Help text */}
|
|
79
84
|
<p className="text-sm text-muted-foreground">
|
|
80
|
-
|
|
85
|
+
{tNotFound("needHelp")}{' '}
|
|
81
86
|
<Link href="/contact" className="text-primary underline underline-offset-4">
|
|
82
|
-
|
|
87
|
+
{tNotFound("contactUs")}
|
|
83
88
|
</Link>
|
|
84
89
|
.
|
|
85
90
|
</p>
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { cookies } from "next/headers";
|
|
2
|
+
import { NextIntlClientProvider } from "next-intl";
|
|
3
|
+
import { notFound } from "next/navigation";
|
|
4
|
+
import { defaultLocale } from "@/i18n/routing";
|
|
5
|
+
import { Header } from "@/components/layout/header";
|
|
6
|
+
import { Footer } from "@/components/layout/footer";
|
|
7
|
+
import { QueryProvider } from "@/components/providers/query-provider";
|
|
8
|
+
import { StorefrontProvider } from "@doswiftly/storefront-sdk/react";
|
|
9
|
+
import { ThemeProvider } from "@/components/providers/theme-provider";
|
|
10
|
+
import { StoresProvider } from "@/components/providers/stores-provider";
|
|
11
|
+
import { LanguageSyncProvider } from "@/components/providers/language-sync-provider";
|
|
12
|
+
import { Toaster } from "sonner";
|
|
13
|
+
import { fetchShop } from "@/lib/graphql/server";
|
|
14
|
+
import { themeConfig } from "@/lib/theme/theme-config";
|
|
15
|
+
import { graphqlConfig } from "@/lib/graphql/config";
|
|
16
|
+
import { AUTH_COOKIE_NAME } from "@doswiftly/storefront-sdk";
|
|
17
|
+
|
|
18
|
+
export const revalidate = 60;
|
|
19
|
+
|
|
20
|
+
type Props = {
|
|
21
|
+
children: React.ReactNode;
|
|
22
|
+
params: Promise<{ locale: string }>;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export default async function LocaleLayout({ children, params }: Props) {
|
|
26
|
+
const { locale } = await params;
|
|
27
|
+
|
|
28
|
+
let shopData;
|
|
29
|
+
try {
|
|
30
|
+
shopData = await fetchShop();
|
|
31
|
+
} catch (error) {
|
|
32
|
+
console.error(
|
|
33
|
+
"[LocaleLayout] Failed to fetch shop data, using fallback:",
|
|
34
|
+
error instanceof Error ? error.message : error
|
|
35
|
+
);
|
|
36
|
+
shopData = {
|
|
37
|
+
shop: {
|
|
38
|
+
id: "fallback",
|
|
39
|
+
name: process.env.NEXT_PUBLIC_SITE_NAME || "Store",
|
|
40
|
+
currencyCode: "PLN",
|
|
41
|
+
supportedCurrencies: ["PLN"],
|
|
42
|
+
paymentCurrencies: ["PLN"],
|
|
43
|
+
defaultLanguage: defaultLocale,
|
|
44
|
+
supportedLanguages: [defaultLocale],
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Validate locale against backend's supportedLanguages (SSOT)
|
|
50
|
+
const supported = shopData.shop.supportedLanguages;
|
|
51
|
+
if (supported && supported.length > 0 && !supported.includes(locale)) {
|
|
52
|
+
notFound();
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const cookieStore = await cookies();
|
|
56
|
+
const hasAuthToken = !!cookieStore.get(AUTH_COOKIE_NAME)?.value;
|
|
57
|
+
|
|
58
|
+
return (
|
|
59
|
+
<ThemeProvider
|
|
60
|
+
attribute={themeConfig.attribute}
|
|
61
|
+
defaultTheme={themeConfig.defaultTheme}
|
|
62
|
+
enableSystem={themeConfig.enableSystem}
|
|
63
|
+
disableTransitionOnChange={themeConfig.disableTransitionOnChange}
|
|
64
|
+
storageKey={themeConfig.storageKey}
|
|
65
|
+
>
|
|
66
|
+
<NextIntlClientProvider>
|
|
67
|
+
<QueryProvider>
|
|
68
|
+
<StorefrontProvider
|
|
69
|
+
config={{
|
|
70
|
+
apiUrl: graphqlConfig.apiUrl,
|
|
71
|
+
shopSlug: graphqlConfig.shopSlug,
|
|
72
|
+
}}
|
|
73
|
+
shopData={shopData.shop}
|
|
74
|
+
initialIsAuthenticated={hasAuthToken}
|
|
75
|
+
initialLanguage={locale}
|
|
76
|
+
>
|
|
77
|
+
<LanguageSyncProvider locale={locale}>
|
|
78
|
+
<StoresProvider>
|
|
79
|
+
<div className="flex min-h-screen flex-col">
|
|
80
|
+
<Header />
|
|
81
|
+
<main className="flex-1">{children}</main>
|
|
82
|
+
<Footer />
|
|
83
|
+
</div>
|
|
84
|
+
<Toaster position="bottom-right" richColors />
|
|
85
|
+
</StoresProvider>
|
|
86
|
+
</LanguageSyncProvider>
|
|
87
|
+
</StorefrontProvider>
|
|
88
|
+
</QueryProvider>
|
|
89
|
+
</NextIntlClientProvider>
|
|
90
|
+
</ThemeProvider>
|
|
91
|
+
);
|
|
92
|
+
}
|