@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.
Files changed (147) hide show
  1. package/dist/commands/deploy.d.ts +20 -0
  2. package/dist/commands/deploy.d.ts.map +1 -1
  3. package/dist/commands/deploy.js +219 -6
  4. package/dist/commands/deploy.js.map +1 -1
  5. package/package.json +4 -4
  6. package/templates/storefront-minimal/.github/workflows/build-template.yml +10 -0
  7. package/templates/storefront-minimal/wrangler.toml +11 -0
  8. package/templates/storefront-nextjs/.github/workflows/build-template.yml +10 -0
  9. package/templates/storefront-nextjs/wrangler.toml +11 -0
  10. package/templates/storefront-nextjs-shadcn/.github/workflows/build-template.yml +10 -0
  11. package/templates/storefront-nextjs-shadcn/CLAUDE.md +29 -5
  12. package/templates/storefront-nextjs-shadcn/app/{about → [locale]/about}/page.tsx +17 -14
  13. package/templates/storefront-nextjs-shadcn/app/{account → [locale]/account}/addresses/page.tsx +19 -15
  14. package/templates/storefront-nextjs-shadcn/app/{account → [locale]/account}/error.tsx +8 -5
  15. package/templates/storefront-nextjs-shadcn/app/{account → [locale]/account}/loyalty/page.tsx +39 -34
  16. package/templates/storefront-nextjs-shadcn/app/{account → [locale]/account}/orders/[id]/page.tsx +9 -7
  17. package/templates/storefront-nextjs-shadcn/app/{account → [locale]/account}/orders/[id]/tracking/page.tsx +27 -25
  18. package/templates/storefront-nextjs-shadcn/app/{account → [locale]/account}/orders/page.tsx +13 -9
  19. package/templates/storefront-nextjs-shadcn/app/{account → [locale]/account}/page.tsx +1 -2
  20. package/templates/storefront-nextjs-shadcn/app/{account → [locale]/account}/settings/page.tsx +1 -1
  21. package/templates/storefront-nextjs-shadcn/app/{auth → [locale]/auth}/forgot-password/page.tsx +14 -12
  22. package/templates/storefront-nextjs-shadcn/app/{auth → [locale]/auth}/login/page.tsx +5 -2
  23. package/templates/storefront-nextjs-shadcn/app/{auth → [locale]/auth}/register/page.tsx +5 -2
  24. package/templates/storefront-nextjs-shadcn/app/{blog → [locale]/blog}/[slug]/page.tsx +1 -1
  25. package/templates/storefront-nextjs-shadcn/app/{cart → [locale]/cart}/page.tsx +14 -10
  26. package/templates/storefront-nextjs-shadcn/app/{categories → [locale]/categories}/[slug]/category-products-client.tsx +4 -2
  27. package/templates/storefront-nextjs-shadcn/app/{categories → [locale]/categories}/page.tsx +13 -8
  28. package/templates/storefront-nextjs-shadcn/app/{checkout → [locale]/checkout}/error.tsx +1 -1
  29. package/templates/storefront-nextjs-shadcn/app/{checkout → [locale]/checkout}/page.tsx +228 -184
  30. package/templates/storefront-nextjs-shadcn/app/{checkout → [locale]/checkout}/success/[orderId]/page.tsx +36 -34
  31. package/templates/storefront-nextjs-shadcn/app/{collections → [locale]/collections}/[handle]/page.tsx +5 -3
  32. package/templates/storefront-nextjs-shadcn/app/{collections → [locale]/collections}/page.tsx +13 -8
  33. package/templates/storefront-nextjs-shadcn/app/{contact → [locale]/contact}/page.tsx +24 -21
  34. package/templates/storefront-nextjs-shadcn/app/{error.tsx → [locale]/error.tsx} +13 -8
  35. package/templates/storefront-nextjs-shadcn/app/[locale]/layout.tsx +92 -0
  36. package/templates/storefront-nextjs-shadcn/app/{not-found.tsx → [locale]/not-found.tsx} +13 -18
  37. package/templates/storefront-nextjs-shadcn/app/{page.tsx → [locale]/page.tsx} +8 -4
  38. package/templates/storefront-nextjs-shadcn/app/{products → [locale]/products}/[slug]/error.tsx +1 -1
  39. package/templates/storefront-nextjs-shadcn/app/{products → [locale]/products}/[slug]/page.tsx +11 -8
  40. package/templates/storefront-nextjs-shadcn/app/{products → [locale]/products}/[slug]/product-client.tsx +3 -1
  41. package/templates/storefront-nextjs-shadcn/app/{products → [locale]/products}/page.tsx +6 -3
  42. package/templates/storefront-nextjs-shadcn/app/{products → [locale]/products}/products-client.tsx +14 -10
  43. package/templates/storefront-nextjs-shadcn/app/{wishlist → [locale]/wishlist}/page.tsx +21 -25
  44. package/templates/storefront-nextjs-shadcn/app/layout.tsx +6 -68
  45. package/templates/storefront-nextjs-shadcn/components/account/address-form.tsx +25 -20
  46. package/templates/storefront-nextjs-shadcn/components/account/address-list.tsx +11 -10
  47. package/templates/storefront-nextjs-shadcn/components/account/order-details.tsx +14 -12
  48. package/templates/storefront-nextjs-shadcn/components/account/order-history.tsx +28 -18
  49. package/templates/storefront-nextjs-shadcn/components/auth/account-menu.tsx +10 -8
  50. package/templates/storefront-nextjs-shadcn/components/auth/login-form.tsx +27 -22
  51. package/templates/storefront-nextjs-shadcn/components/auth/register-form.tsx +48 -43
  52. package/templates/storefront-nextjs-shadcn/components/blog/blog-card.tsx +1 -1
  53. package/templates/storefront-nextjs-shadcn/components/blog/blog-sidebar.tsx +1 -1
  54. package/templates/storefront-nextjs-shadcn/components/brand/brand-card.tsx +1 -1
  55. package/templates/storefront-nextjs-shadcn/components/cart/cart-drawer.tsx +7 -4
  56. package/templates/storefront-nextjs-shadcn/components/cart/cart-icon.tsx +1 -1
  57. package/templates/storefront-nextjs-shadcn/components/cart/cart-item.tsx +7 -5
  58. package/templates/storefront-nextjs-shadcn/components/cart/cart-summary.tsx +9 -7
  59. package/templates/storefront-nextjs-shadcn/components/cart/promo-code-input.tsx +8 -5
  60. package/templates/storefront-nextjs-shadcn/components/cart/shipping-estimator.tsx +18 -15
  61. package/templates/storefront-nextjs-shadcn/components/checkout/payment-method-card.tsx +15 -25
  62. package/templates/storefront-nextjs-shadcn/components/checkout/payment-step.tsx +10 -8
  63. package/templates/storefront-nextjs-shadcn/components/checkout/tax-breakdown.tsx +9 -6
  64. package/templates/storefront-nextjs-shadcn/components/commerce/currency-selector.tsx +5 -3
  65. package/templates/storefront-nextjs-shadcn/components/commerce/pagination.tsx +8 -5
  66. package/templates/storefront-nextjs-shadcn/components/commerce/product-actions.tsx +5 -3
  67. package/templates/storefront-nextjs-shadcn/components/commerce/search-input.tsx +8 -7
  68. package/templates/storefront-nextjs-shadcn/components/common/category-card.tsx +1 -1
  69. package/templates/storefront-nextjs-shadcn/components/common/collection-card.tsx +1 -1
  70. package/templates/storefront-nextjs-shadcn/components/common/social-share.tsx +9 -6
  71. package/templates/storefront-nextjs-shadcn/components/discount/discount-breakdown.tsx +21 -11
  72. package/templates/storefront-nextjs-shadcn/components/discount/discount-code-input.tsx +16 -13
  73. package/templates/storefront-nextjs-shadcn/components/error/error-boundary.tsx +53 -28
  74. package/templates/storefront-nextjs-shadcn/components/filters/dynamic-attribute-filters.tsx +7 -5
  75. package/templates/storefront-nextjs-shadcn/components/gift-card/gift-card-balance.tsx +19 -15
  76. package/templates/storefront-nextjs-shadcn/components/gift-card/gift-card-input.tsx +12 -9
  77. package/templates/storefront-nextjs-shadcn/components/home/category-grid.tsx +8 -5
  78. package/templates/storefront-nextjs-shadcn/components/home/featured-collections.tsx +1 -1
  79. package/templates/storefront-nextjs-shadcn/components/home/featured-products.tsx +12 -8
  80. package/templates/storefront-nextjs-shadcn/components/home/hero-section.tsx +13 -8
  81. package/templates/storefront-nextjs-shadcn/components/home/newsletter-signup.tsx +10 -8
  82. package/templates/storefront-nextjs-shadcn/components/layout/breadcrumbs.tsx +37 -12
  83. package/templates/storefront-nextjs-shadcn/components/layout/currency-selector.tsx +5 -2
  84. package/templates/storefront-nextjs-shadcn/components/layout/footer.tsx +24 -23
  85. package/templates/storefront-nextjs-shadcn/components/layout/header.tsx +20 -12
  86. package/templates/storefront-nextjs-shadcn/components/layout/language-switcher.tsx +54 -0
  87. package/templates/storefront-nextjs-shadcn/components/layout/mobile-menu.tsx +33 -30
  88. package/templates/storefront-nextjs-shadcn/components/layout/navigation.tsx +27 -24
  89. package/templates/storefront-nextjs-shadcn/components/loyalty/referral-section.tsx +23 -24
  90. package/templates/storefront-nextjs-shadcn/components/product/add-to-cart-button.tsx +6 -14
  91. package/templates/storefront-nextjs-shadcn/components/product/b2b-price-display.tsx +1 -1
  92. package/templates/storefront-nextjs-shadcn/components/product/filter-active-pills.tsx +4 -1
  93. package/templates/storefront-nextjs-shadcn/components/product/filter-mobile-sheet.tsx +7 -4
  94. package/templates/storefront-nextjs-shadcn/components/product/filter-price-range.tsx +5 -3
  95. package/templates/storefront-nextjs-shadcn/components/product/product-card.tsx +8 -6
  96. package/templates/storefront-nextjs-shadcn/components/product/product-filters.tsx +3 -1
  97. package/templates/storefront-nextjs-shadcn/components/product/product-image.tsx +3 -7
  98. package/templates/storefront-nextjs-shadcn/components/product/product-sort.tsx +26 -13
  99. package/templates/storefront-nextjs-shadcn/components/product/review-form.tsx +25 -27
  100. package/templates/storefront-nextjs-shadcn/components/providers/language-sync-provider.tsx +27 -0
  101. package/templates/storefront-nextjs-shadcn/components/providers/stores-provider.tsx +40 -7
  102. package/templates/storefront-nextjs-shadcn/components/returns/return-request-form.tsx +56 -70
  103. package/templates/storefront-nextjs-shadcn/components/search/search-bar.tsx +7 -4
  104. package/templates/storefront-nextjs-shadcn/components/shipping/shipping-method-selector.tsx +12 -9
  105. package/templates/storefront-nextjs-shadcn/components/ui/empty-state.tsx +23 -12
  106. package/templates/storefront-nextjs-shadcn/components/wishlist/wishlist-button.tsx +7 -4
  107. package/templates/storefront-nextjs-shadcn/components/wishlist/wishlist-icon.tsx +1 -1
  108. package/templates/storefront-nextjs-shadcn/components/wishlist/wishlist-item.tsx +2 -10
  109. package/templates/storefront-nextjs-shadcn/generated/graphql.ts +1159 -551
  110. package/templates/storefront-nextjs-shadcn/hooks/index.ts +1 -0
  111. package/templates/storefront-nextjs-shadcn/hooks/use-cart-actions.ts +22 -249
  112. package/templates/storefront-nextjs-shadcn/hooks/use-cart-di.ts +67 -0
  113. package/templates/storefront-nextjs-shadcn/hooks/use-cart-sync.ts +3 -3
  114. package/templates/storefront-nextjs-shadcn/i18n/navigation.ts +12 -0
  115. package/templates/storefront-nextjs-shadcn/i18n/request.ts +17 -0
  116. package/templates/storefront-nextjs-shadcn/i18n/routing.ts +17 -0
  117. package/templates/storefront-nextjs-shadcn/lib/graphql/config.ts +1 -0
  118. package/templates/storefront-nextjs-shadcn/lib/graphql/hooks.ts +41 -8
  119. package/templates/storefront-nextjs-shadcn/lib/graphql/query-keys.ts +20 -18
  120. package/templates/storefront-nextjs-shadcn/lib/graphql/server.ts +2 -1
  121. package/templates/storefront-nextjs-shadcn/messages/en.json +869 -0
  122. package/templates/storefront-nextjs-shadcn/messages/pl.json +869 -0
  123. package/templates/storefront-nextjs-shadcn/next.config.ts +6 -5
  124. package/templates/storefront-nextjs-shadcn/package.json +3 -2
  125. package/templates/storefront-nextjs-shadcn/proxy.ts +115 -46
  126. package/templates/storefront-nextjs-shadcn/stores/cart-store.ts +24 -58
  127. package/templates/storefront-nextjs-shadcn/wrangler.toml +11 -0
  128. /package/templates/storefront-nextjs-shadcn/app/{account → [locale]/account}/loading.tsx +0 -0
  129. /package/templates/storefront-nextjs-shadcn/app/{account → [locale]/account}/orders/[id]/loading.tsx +0 -0
  130. /package/templates/storefront-nextjs-shadcn/app/{blog → [locale]/blog}/[slug]/loading.tsx +0 -0
  131. /package/templates/storefront-nextjs-shadcn/app/{blog → [locale]/blog}/loading.tsx +0 -0
  132. /package/templates/storefront-nextjs-shadcn/app/{blog → [locale]/blog}/page.tsx +0 -0
  133. /package/templates/storefront-nextjs-shadcn/app/{brands → [locale]/brands}/[slug]/page.tsx +0 -0
  134. /package/templates/storefront-nextjs-shadcn/app/{brands → [locale]/brands}/page.tsx +0 -0
  135. /package/templates/storefront-nextjs-shadcn/app/{cart → [locale]/cart}/loading.tsx +0 -0
  136. /package/templates/storefront-nextjs-shadcn/app/{categories → [locale]/categories}/[slug]/loading.tsx +0 -0
  137. /package/templates/storefront-nextjs-shadcn/app/{categories → [locale]/categories}/[slug]/page.tsx +0 -0
  138. /package/templates/storefront-nextjs-shadcn/app/{checkout → [locale]/checkout}/loading.tsx +0 -0
  139. /package/templates/storefront-nextjs-shadcn/app/{collections → [locale]/collections}/[handle]/loading.tsx +0 -0
  140. /package/templates/storefront-nextjs-shadcn/app/{collections → [locale]/collections}/loading.tsx +0 -0
  141. /package/templates/storefront-nextjs-shadcn/app/{products → [locale]/products}/[slug]/loading.tsx +0 -0
  142. /package/templates/storefront-nextjs-shadcn/app/{products → [locale]/products}/loading.tsx +0 -0
  143. /package/templates/storefront-nextjs-shadcn/app/{returns → [locale]/returns}/page.tsx +0 -0
  144. /package/templates/storefront-nextjs-shadcn/app/{search → [locale]/search}/loading.tsx +0 -0
  145. /package/templates/storefront-nextjs-shadcn/app/{search → [locale]/search}/page.tsx +0 -0
  146. /package/templates/storefront-nextjs-shadcn/app/{search → [locale]/search}/search-client.tsx +0 -0
  147. /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("Skopiowano do schowka");
36
+ toast.success(t("copied"));
35
37
  setTimeout(() => setCopied(false), 2000);
36
38
  } catch {
37
- toast.error("Nie udało się skopiować");
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: `Zamówienie ${orderId}`,
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 ? "Zamówienie oczekuje na płatność" : "Dziękujemy za zamówienie!"}
68
+ {isPendingPayment ? t("pendingPayment") : t("thankYou")}
67
69
  </h1>
68
70
  <p className="mb-8 text-muted-foreground">
69
71
  {isPendingPayment
70
- ? "Po otrzymaniu płatności rozpoczniemy realizację zamówienia."
71
- : "Twoje zamówienie zostało potwierdzone i wkrótce zostanie wysłane."}
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">Potwierdzenie zamówienia</CardTitle>
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">Numer zamówienia</span>
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">Email potwierdzający</p>
92
+ <p className="font-medium">{t("confirmationEmail")}</p>
91
93
  <p className="text-sm text-muted-foreground">
92
- Wysłaliśmy potwierdzenie ze szczegółami zamówienia.
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">Śledzenie przesyłki</p>
102
+ <p className="font-medium">{t("tracking")}</p>
101
103
  <p className="text-sm text-muted-foreground">
102
- Otrzymasz numer śledzenia, gdy paczka zostanie wysłana.
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>Dane do przelewu bankowego</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">Bank</span>
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">Numer konta</span>
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">Odbiorca</span>
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">Tytuł przelewu</span>
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
- Realizacja zamówienia rozpocznie się po zaksięgowaniu wpłaty (zazwyczaj 1-2 dni robocze).
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">Co dalej?</CardTitle>
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">Wykonaj przelew</p>
178
+ <p className="font-medium">{t("stepMakeTransfer")}</p>
177
179
  <p className="text-sm text-muted-foreground">
178
- Prześlij płatność na podane powyżej konto bankowe.
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">Potwierdzenie płatności</p>
189
+ <p className="font-medium">{t("stepPaymentConfirmation")}</p>
188
190
  <p className="text-sm text-muted-foreground">
189
- Po zaksięgowaniu wpłaty otrzymasz email z potwierdzeniem.
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">Przetwarzanie zamówienia</p>
202
+ <p className="font-medium">{t("stepProcessing")}</p>
201
203
  <p className="text-sm text-muted-foreground">
202
- Przygotowujemy Twoje zamówienie do wysyłki.
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">Wysyłka</p>
214
+ <p className="font-medium">{t("stepShipping")}</p>
213
215
  <p className="text-sm text-muted-foreground">
214
- Po wysłaniu otrzymasz email z numerem śledzenia przesyłki.
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">Dostawa</p>
225
+ <p className="font-medium">{t("stepDelivery")}</p>
224
226
  <p className="text-sm text-muted-foreground">
225
- Paczka zostanie dostarczona pod wskazany adres.
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
- Kontynuuj zakupy
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">Moje zamówienia</Link>
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
- Potrzebujesz pomocy?{" "}
250
+ {t("needHelp")}{" "}
249
251
  <Link href="/contact" className="text-primary underline underline-offset-4">
250
- Skontaktuj się z nami
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
- Collection Not Found
44
+ {t("notFound")}
43
45
  </h1>
44
46
  <p className="text-muted-foreground">
45
- The collection you're looking for doesn't exist.
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="No products in this collection"
72
+ emptyMessage={t("noProducts")}
71
73
  />
72
74
  </div>
73
75
  );
@@ -1,17 +1,22 @@
1
1
  import { Metadata } from "next";
2
- import Link from "next/link";
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 const metadata: Metadata = {
7
- title: "Collections",
8
- description: "Browse our curated collections of products",
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">Collections</h1>
32
+ <h1 className="text-3xl font-bold text-foreground">{t("title")}</h1>
28
33
  <p className="mt-2 text-muted-foreground">
29
- Browse our curated collections of products
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">No collections available yet</p>
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">Contact Us</h1>
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
- Have a question? We'd love to hear from you. Send us a message and we'll respond as soon as possible.
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
- Email
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
- Phone
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
- Address
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>Send us a message</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
- Name
78
+ {t("name")}
76
79
  </label>
77
- <Input id="name" placeholder="Your name" required />
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
- Email
84
+ {t("email")}
82
85
  </label>
83
- <Input id="email" type="email" placeholder="your@email.com" required />
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
- Subject
91
+ {t("subject")}
89
92
  </label>
90
- <Input id="subject" placeholder="How can we help?" required />
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
- Message
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="Your message..."
103
+ placeholder={t("messagePlaceholder")}
101
104
  required
102
105
  />
103
106
  </div>
104
107
  <Button type="submit" className="w-full">
105
- Send Message
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 Link from 'next/link';
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">Wystąpił błąd</CardTitle>
44
+ <CardTitle className="text-2xl">{t("somethingWentWrong")}</CardTitle>
40
45
  <CardDescription className="text-base">
41
- Przepraszamy, wystąpił nieoczekiwany problem. Spróbuj odświeżyć stronę lub wróć do strony głównej.
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
- Spróbuj ponownie
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
- Strona główna
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
- Produkty
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
- Jeśli problem się powtarza,{' '}
85
+ {tNotFound("needHelp")}{' '}
81
86
  <Link href="/contact" className="text-primary underline underline-offset-4">
82
- skontaktuj się z nami
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
+ }