@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
@@ -1,6 +1,7 @@
1
1
  "use client";
2
2
 
3
3
  import { useState } from "react";
4
+ import { useTranslations } from "next-intl";
4
5
  import { Button } from "@/components/ui/button";
5
6
  import { Input } from "@/components/ui/input";
6
7
  import { Card } from "@/components/ui/card";
@@ -38,6 +39,10 @@ export function AddressForm({
38
39
  isLoading = false,
39
40
  className,
40
41
  }: AddressFormProps) {
42
+ const t = useTranslations("checkout");
43
+ const tc = useTranslations("common");
44
+ const tAccount = useTranslations("account");
45
+
41
46
  const [formData, setFormData] = useState<AddressFormData>(
42
47
  address || {
43
48
  firstName: "",
@@ -68,25 +73,25 @@ export function AddressForm({
68
73
  const newErrors: Partial<Record<keyof AddressFormData, string>> = {};
69
74
 
70
75
  if (!formData.firstName.trim()) {
71
- newErrors.firstName = "First name is required";
76
+ newErrors.firstName = t("validation.firstNameRequired");
72
77
  }
73
78
  if (!formData.lastName.trim()) {
74
- newErrors.lastName = "Last name is required";
79
+ newErrors.lastName = t("validation.lastNameRequired");
75
80
  }
76
81
  if (!formData.address1.trim()) {
77
- newErrors.address1 = "Address is required";
82
+ newErrors.address1 = t("validation.addressRequired");
78
83
  }
79
84
  if (!formData.city.trim()) {
80
- newErrors.city = "City is required";
85
+ newErrors.city = t("validation.cityRequired");
81
86
  }
82
87
  if (!formData.province.trim()) {
83
- newErrors.province = "Province/State is required";
88
+ newErrors.province = t("validation.provinceRequired");
84
89
  }
85
90
  if (!formData.zip.trim()) {
86
- newErrors.zip = "Postal code is required";
91
+ newErrors.zip = t("validation.zipRequired");
87
92
  }
88
93
  if (!formData.country.trim()) {
89
- newErrors.country = "Country is required";
94
+ newErrors.country = t("validation.countryRequired");
90
95
  }
91
96
 
92
97
  setErrors(newErrors);
@@ -113,7 +118,7 @@ export function AddressForm({
113
118
  htmlFor="firstName"
114
119
  className="block text-sm font-medium text-foreground mb-1"
115
120
  >
116
- First Name *
121
+ {t("address.firstName")} *
117
122
  </label>
118
123
  <Input
119
124
  id="firstName"
@@ -134,7 +139,7 @@ export function AddressForm({
134
139
  htmlFor="lastName"
135
140
  className="block text-sm font-medium text-foreground mb-1"
136
141
  >
137
- Last Name *
142
+ {t("address.lastName")} *
138
143
  </label>
139
144
  <Input
140
145
  id="lastName"
@@ -156,7 +161,7 @@ export function AddressForm({
156
161
  htmlFor="company"
157
162
  className="block text-sm font-medium text-foreground mb-1"
158
163
  >
159
- Company (optional)
164
+ {`${t("address.company")} (${tc("optional")})`}
160
165
  </label>
161
166
  <Input
162
167
  id="company"
@@ -173,7 +178,7 @@ export function AddressForm({
173
178
  htmlFor="address1"
174
179
  className="block text-sm font-medium text-foreground mb-1"
175
180
  >
176
- Address *
181
+ {t("address.address1")} *
177
182
  </label>
178
183
  <Input
179
184
  id="address1"
@@ -194,7 +199,7 @@ export function AddressForm({
194
199
  htmlFor="address2"
195
200
  className="block text-sm font-medium text-foreground mb-1"
196
201
  >
197
- Apartment, suite, etc. (optional)
202
+ {`${t("address.address2")} (${tc("optional")})`}
198
203
  </label>
199
204
  <Input
200
205
  id="address2"
@@ -212,7 +217,7 @@ export function AddressForm({
212
217
  htmlFor="city"
213
218
  className="block text-sm font-medium text-foreground mb-1"
214
219
  >
215
- City *
220
+ {t("address.city")} *
216
221
  </label>
217
222
  <Input
218
223
  id="city"
@@ -233,7 +238,7 @@ export function AddressForm({
233
238
  htmlFor="province"
234
239
  className="block text-sm font-medium text-foreground mb-1"
235
240
  >
236
- Province/State *
241
+ {t("address.province")} *
237
242
  </label>
238
243
  <Input
239
244
  id="province"
@@ -254,7 +259,7 @@ export function AddressForm({
254
259
  htmlFor="zip"
255
260
  className="block text-sm font-medium text-foreground mb-1"
256
261
  >
257
- Postal Code *
262
+ {t("address.zip")} *
258
263
  </label>
259
264
  <Input
260
265
  id="zip"
@@ -276,7 +281,7 @@ export function AddressForm({
276
281
  htmlFor="country"
277
282
  className="block text-sm font-medium text-foreground mb-1"
278
283
  >
279
- Country *
284
+ {t("address.country")} *
280
285
  </label>
281
286
  <Input
282
287
  id="country"
@@ -297,7 +302,7 @@ export function AddressForm({
297
302
  htmlFor="phone"
298
303
  className="block text-sm font-medium text-foreground mb-1"
299
304
  >
300
- Phone (optional)
305
+ {`${t("address.phone")} (${tc("optional")})`}
301
306
  </label>
302
307
  <Input
303
308
  id="phone"
@@ -322,14 +327,14 @@ export function AddressForm({
322
327
  htmlFor="isDefault"
323
328
  className="text-sm font-medium text-foreground"
324
329
  >
325
- Set as default address
330
+ {tAccount("setAsDefault")}
326
331
  </label>
327
332
  </div>
328
333
 
329
334
  {/* Form Actions */}
330
335
  <div className="flex gap-3 pt-4">
331
336
  <Button type="submit" disabled={isLoading} className="flex-1">
332
- {isLoading ? "Saving..." : address ? "Update Address" : "Add Address"}
337
+ {isLoading ? tc("saving") : address ? tAccount("editAddress") : tAccount("addAddress")}
333
338
  </Button>
334
339
  {onCancel && (
335
340
  <Button
@@ -338,7 +343,7 @@ export function AddressForm({
338
343
  onClick={onCancel}
339
344
  disabled={isLoading}
340
345
  >
341
- Cancel
346
+ {tc("cancel")}
342
347
  </Button>
343
348
  )}
344
349
  </div>
@@ -4,6 +4,7 @@ import { MapPin, Edit, Trash2, Plus } from "lucide-react";
4
4
  import { Button } from "@/components/ui/button";
5
5
  import { Badge } from "@/components/ui/badge";
6
6
  import { Card } from "@/components/ui/card";
7
+ import { useTranslations } from "next-intl";
7
8
 
8
9
  export interface Address {
9
10
  id: string;
@@ -40,11 +41,11 @@ export function AddressList({
40
41
  onAdd,
41
42
  className,
42
43
  }: AddressListProps) {
44
+ const t = useTranslations("account");
45
+
43
46
  const handleDelete = (id: string, address: Address) => {
44
47
  if (
45
- confirm(
46
- `Are you sure you want to delete the address at ${address.address1}?`
47
- )
48
+ confirm(t("deleteAddressConfirm", { address: address.address1 }))
48
49
  ) {
49
50
  onDelete?.(id);
50
51
  }
@@ -55,15 +56,15 @@ export function AddressList({
55
56
  <div className="rounded-lg border border-border bg-muted/50 p-12 text-center">
56
57
  <MapPin className="mx-auto h-12 w-12 text-muted-foreground mb-4" />
57
58
  <h2 className="text-xl font-semibold text-foreground mb-2">
58
- No addresses saved
59
+ {t("noAddressesSaved")}
59
60
  </h2>
60
61
  <p className="text-muted-foreground mb-6">
61
- Add an address to make checkout faster
62
+ {t("addAddressDescription")}
62
63
  </p>
63
64
  {onAdd && (
64
65
  <Button onClick={onAdd}>
65
66
  <Plus className="mr-2 h-4 w-4" />
66
- Add Your First Address
67
+ {t("addFirstAddress")}
67
68
  </Button>
68
69
  )}
69
70
  </div>
@@ -78,7 +79,7 @@ export function AddressList({
78
79
  <div className="mb-4 flex items-start justify-between">
79
80
  <div className="flex items-center gap-2">
80
81
  <MapPin className="h-5 w-5 text-muted-foreground" />
81
- {address.isDefault && <Badge variant="default">Default</Badge>}
82
+ {address.isDefault && <Badge variant="default">{t("defaultBadge")}</Badge>}
82
83
  </div>
83
84
  <div className="flex gap-2">
84
85
  {onEdit && (
@@ -87,7 +88,7 @@ export function AddressList({
87
88
  size="sm"
88
89
  className="h-8 w-8 p-0"
89
90
  onClick={() => onEdit(address)}
90
- aria-label="Edit address"
91
+ aria-label={t("editAddress")}
91
92
  >
92
93
  <Edit className="h-4 w-4" />
93
94
  </Button>
@@ -98,7 +99,7 @@ export function AddressList({
98
99
  size="sm"
99
100
  className="h-8 w-8 p-0 text-destructive hover:text-destructive"
100
101
  onClick={() => handleDelete(address.id, address)}
101
- aria-label="Delete address"
102
+ aria-label={t("deleteAddress")}
102
103
  >
103
104
  <Trash2 className="h-4 w-4" />
104
105
  </Button>
@@ -133,7 +134,7 @@ export function AddressList({
133
134
  className="mt-4 w-full"
134
135
  onClick={() => onSetDefault(address.id)}
135
136
  >
136
- Set as Default
137
+ {t("setAsDefault")}
137
138
  </Button>
138
139
  )}
139
140
  </Card>
@@ -1,6 +1,7 @@
1
1
  "use client";
2
2
 
3
3
  import { Package, Truck, CheckCircle, XCircle } from "lucide-react";
4
+ import { useTranslations } from "next-intl";
4
5
  import { Badge } from "@/components/ui/badge";
5
6
  import { Card } from "@/components/ui/card";
6
7
  import { Separator } from "@/components/ui/separator";
@@ -54,6 +55,7 @@ export interface OrderDetailsProps {
54
55
  * OrderDetails - Display detailed information about a single order
55
56
  */
56
57
  export function OrderDetails({ order, className }: OrderDetailsProps) {
58
+ const t = useTranslations("account");
57
59
  const getStatusIcon = (status: OrderDetailsData["status"]) => {
58
60
  switch (status) {
59
61
  case "delivered":
@@ -131,10 +133,10 @@ export function OrderDetails({ order, className }: OrderDetailsProps) {
131
133
  <div className="flex items-start justify-between mb-4">
132
134
  <div>
133
135
  <h2 className="text-2xl font-bold text-foreground mb-2">
134
- Order {order.orderNumber}
136
+ {t("orderNumber", { number: order.orderNumber })}
135
137
  </h2>
136
138
  <p className="text-sm text-muted-foreground">
137
- Placed on {formatDate(order.date)}
139
+ {t("placedOn")} {formatDate(order.date)}
138
140
  </p>
139
141
  </div>
140
142
  <div className="flex items-center gap-2">
@@ -146,7 +148,7 @@ export function OrderDetails({ order, className }: OrderDetailsProps) {
146
148
  {order.trackingNumber && (
147
149
  <div className="mt-4 p-4 bg-muted/50 rounded-lg">
148
150
  <p className="text-sm font-medium text-foreground mb-1">
149
- Tracking Number
151
+ {t("trackingNumber")}
150
152
  </p>
151
153
  <p className="text-sm text-muted-foreground font-mono">
152
154
  {order.trackingNumber}
@@ -157,7 +159,7 @@ export function OrderDetails({ order, className }: OrderDetailsProps) {
157
159
  {order.estimatedDelivery && (
158
160
  <div className="mt-4 p-4 bg-muted/50 rounded-lg">
159
161
  <p className="text-sm font-medium text-foreground mb-1">
160
- Estimated Delivery
162
+ {t("estimatedDelivery")}
161
163
  </p>
162
164
  <p className="text-sm text-muted-foreground">
163
165
  {formatDate(order.estimatedDelivery)}
@@ -169,7 +171,7 @@ export function OrderDetails({ order, className }: OrderDetailsProps) {
169
171
  {/* Order Items */}
170
172
  <Card className="p-6 mb-6">
171
173
  <h3 className="text-lg font-semibold text-foreground mb-4">
172
- Order Items
174
+ {t("orderItems")}
173
175
  </h3>
174
176
  <div className="space-y-4">
175
177
  {order.items.map((item) => (
@@ -191,7 +193,7 @@ export function OrderDetails({ order, className }: OrderDetailsProps) {
191
193
  </p>
192
194
  )}
193
195
  <p className="text-sm text-muted-foreground">
194
- Quantity: {item.quantity}
196
+ {t("itemCount", { count: item.quantity })}
195
197
  </p>
196
198
  </div>
197
199
  <div className="text-right">
@@ -208,26 +210,26 @@ export function OrderDetails({ order, className }: OrderDetailsProps) {
208
210
  {/* Order Summary */}
209
211
  <div className="space-y-2">
210
212
  <div className="flex justify-between text-sm">
211
- <span className="text-muted-foreground">Subtotal</span>
213
+ <span className="text-muted-foreground">{t("subtotal")}</span>
212
214
  <span className="text-foreground">
213
215
  {formatPrice(order.subtotal, order.currency)}
214
216
  </span>
215
217
  </div>
216
218
  <div className="flex justify-between text-sm">
217
- <span className="text-muted-foreground">Shipping</span>
219
+ <span className="text-muted-foreground">{t("shippingLabel")}</span>
218
220
  <span className="text-foreground">
219
221
  {formatPrice(order.shipping, order.currency)}
220
222
  </span>
221
223
  </div>
222
224
  <div className="flex justify-between text-sm">
223
- <span className="text-muted-foreground">Tax</span>
225
+ <span className="text-muted-foreground">{t("taxLabel")}</span>
224
226
  <span className="text-foreground">
225
227
  {formatPrice(order.tax, order.currency)}
226
228
  </span>
227
229
  </div>
228
230
  <Separator className="my-2" />
229
231
  <div className="flex justify-between text-base font-semibold">
230
- <span className="text-foreground">Total</span>
232
+ <span className="text-foreground">{t("orderTotal")}</span>
231
233
  <span className="text-foreground">
232
234
  {formatPrice(order.total, order.currency)}
233
235
  </span>
@@ -240,7 +242,7 @@ export function OrderDetails({ order, className }: OrderDetailsProps) {
240
242
  {order.shippingAddress && (
241
243
  <Card className="p-6">
242
244
  <h3 className="text-lg font-semibold text-foreground mb-4">
243
- Shipping Address
245
+ {t("shippingAddress")}
244
246
  </h3>
245
247
  {formatAddress(order.shippingAddress)}
246
248
  </Card>
@@ -249,7 +251,7 @@ export function OrderDetails({ order, className }: OrderDetailsProps) {
249
251
  {order.billingAddress && (
250
252
  <Card className="p-6">
251
253
  <h3 className="text-lg font-semibold text-foreground mb-4">
252
- Billing Address
254
+ {t("billingAddress")}
253
255
  </h3>
254
256
  {formatAddress(order.billingAddress)}
255
257
  </Card>
@@ -1,12 +1,23 @@
1
1
  "use client";
2
2
 
3
- import Link from "next/link";
3
+ import { Link } from "@/i18n/navigation";
4
+ import { useTranslations } from "next-intl";
5
+ import { useLocale } from "next-intl";
4
6
  import { Package, ChevronRight } from "lucide-react";
5
7
  import { Badge } from "@/components/ui/badge";
6
8
  import { Button } from "@/components/ui/button";
7
9
  import { formatAmount } from "@doswiftly/storefront-sdk";
8
10
  import type { OrderSummaryFields } from "@/lib/graphql/fragments";
9
11
 
12
+ const STATUS_KEY_MAP: Record<string, string> = {
13
+ DELIVERED: "delivered",
14
+ FULFILLED: "fulfilled",
15
+ IN_TRANSIT: "shipped",
16
+ PARTIALLY_FULFILLED: "partiallyFulfilled",
17
+ UNFULFILLED: "processing",
18
+ RETURNED: "returned",
19
+ };
20
+
10
21
  export interface OrderHistoryProps {
11
22
  orders: OrderSummaryFields[];
12
23
  className?: string;
@@ -16,6 +27,9 @@ export interface OrderHistoryProps {
16
27
  * OrderHistory - Display list of customer orders
17
28
  */
18
29
  export function OrderHistory({ orders, className }: OrderHistoryProps) {
30
+ const t = useTranslations("account");
31
+ const locale = useLocale();
32
+
19
33
  const getStatusBadge = (status: string) => {
20
34
  const variants: Record<string, "default" | "secondary" | "success" | "warning"> = {
21
35
  DELIVERED: "success",
@@ -26,24 +40,20 @@ export function OrderHistory({ orders, className }: OrderHistoryProps) {
26
40
  RETURNED: "secondary",
27
41
  };
28
42
 
29
- const labels: Record<string, string> = {
30
- DELIVERED: "Delivered",
31
- FULFILLED: "Fulfilled",
32
- IN_TRANSIT: "Shipped",
33
- PARTIALLY_FULFILLED: "Partially Fulfilled",
34
- UNFULFILLED: "Processing",
35
- RETURNED: "Returned",
36
- };
43
+ const statusKey = STATUS_KEY_MAP[status];
44
+ const label = statusKey
45
+ ? t(`orderStatuses.${statusKey}`)
46
+ : status;
37
47
 
38
48
  return (
39
49
  <Badge variant={variants[status] ?? "secondary"}>
40
- {labels[status] ?? status}
50
+ {label}
41
51
  </Badge>
42
52
  );
43
53
  };
44
54
 
45
55
  const formatDate = (dateString: string) => {
46
- return new Date(dateString).toLocaleDateString("pl-PL", {
56
+ return new Date(dateString).toLocaleDateString(locale, {
47
57
  year: "numeric",
48
58
  month: "long",
49
59
  day: "numeric",
@@ -55,13 +65,13 @@ export function OrderHistory({ orders, className }: OrderHistoryProps) {
55
65
  <div className="rounded-lg border border-border bg-muted/50 p-12 text-center">
56
66
  <Package className="mx-auto h-12 w-12 text-muted-foreground mb-4" />
57
67
  <h2 className="text-xl font-semibold text-foreground mb-2">
58
- No orders yet
68
+ {t("noOrders")}
59
69
  </h2>
60
70
  <p className="text-muted-foreground mb-6">
61
- Start shopping to see your orders here
71
+ {t("startShoppingDescription")}
62
72
  </p>
63
73
  <Button asChild>
64
- <Link href="/products">Browse Products</Link>
74
+ <Link href="/products">{t("browseProducts")}</Link>
65
75
  </Button>
66
76
  </div>
67
77
  );
@@ -80,20 +90,20 @@ export function OrderHistory({ orders, className }: OrderHistoryProps) {
80
90
  <div className="flex-1">
81
91
  <div className="flex items-center gap-3 mb-2">
82
92
  <h3 className="text-lg font-semibold text-foreground">
83
- Order {order.orderNumber}
93
+ {t("orderNumber", { number: order.orderNumber })}
84
94
  </h3>
85
95
  {getStatusBadge(order.fulfillmentStatus)}
86
96
  </div>
87
97
  <div className="space-y-1 text-sm text-muted-foreground">
88
- <p>Placed on {formatDate(order.processedAt)}</p>
98
+ <p>{t("placedOn")} {formatDate(order.processedAt)}</p>
89
99
  <p>
90
- {order.lineItemsCount} {order.lineItemsCount === 1 ? "item" : "items"}
100
+ {t("itemCount", { count: order.lineItemsCount })}
91
101
  </p>
92
102
  </div>
93
103
  </div>
94
104
  <div className="flex items-center gap-4">
95
105
  <div className="text-right">
96
- <p className="text-sm text-muted-foreground">Total</p>
106
+ <p className="text-sm text-muted-foreground">{t("orderTotal")}</p>
97
107
  <p className="text-lg font-semibold text-foreground">
98
108
  {formatAmount(order.totalPrice.amount, order.totalPrice.currencyCode)}
99
109
  </p>
@@ -1,8 +1,8 @@
1
1
  "use client";
2
2
 
3
3
  import { useState, useRef, useEffect } from "react";
4
- import Link from "next/link";
5
- import { useRouter } from "next/navigation";
4
+ import { Link, useRouter } from "@/i18n/navigation";
5
+ import { useTranslations } from "next-intl";
6
6
  import { User, LogOut, Package, MapPin, Settings } from "lucide-react";
7
7
  import { Button } from "@/components/ui/button";
8
8
  import { cn } from "@/lib/utils";
@@ -14,6 +14,8 @@ export interface AccountMenuProps {
14
14
  }
15
15
 
16
16
  export function AccountMenu({ customerName, className }: AccountMenuProps) {
17
+ const t = useTranslations("account");
18
+ const tAuth = useTranslations("auth");
17
19
  const router = useRouter();
18
20
  const [isOpen, setIsOpen] = useState(false);
19
21
  const menuRef = useRef<HTMLDivElement>(null);
@@ -46,22 +48,22 @@ export function AccountMenu({ customerName, className }: AccountMenuProps) {
46
48
 
47
49
  const menuItems = [
48
50
  {
49
- label: "My Account",
51
+ label: t("title"),
50
52
  href: "/account",
51
53
  icon: User,
52
54
  },
53
55
  {
54
- label: "Orders",
56
+ label: t("orders"),
55
57
  href: "/account/orders",
56
58
  icon: Package,
57
59
  },
58
60
  {
59
- label: "Addresses",
61
+ label: t("addresses"),
60
62
  href: "/account/addresses",
61
63
  icon: MapPin,
62
64
  },
63
65
  {
64
- label: "Settings",
66
+ label: t("settings"),
65
67
  href: "/account/settings",
66
68
  icon: Settings,
67
69
  },
@@ -75,7 +77,7 @@ export function AccountMenu({ customerName, className }: AccountMenuProps) {
75
77
  size="sm"
76
78
  onClick={() => setIsOpen(!isOpen)}
77
79
  className="flex items-center gap-2"
78
- aria-label="Account menu"
80
+ aria-label={t("title")}
79
81
  aria-expanded={isOpen}
80
82
  >
81
83
  <User className="h-5 w-5" />
@@ -122,7 +124,7 @@ export function AccountMenu({ customerName, className }: AccountMenuProps) {
122
124
  className="flex w-full items-center gap-3 px-4 py-2 text-sm text-destructive hover:bg-muted transition-colors disabled:opacity-50"
123
125
  >
124
126
  <LogOut className="h-4 w-4" />
125
- {isLoggingOut ? "Signing out..." : "Sign Out"}
127
+ {isLoggingOut ? tAuth("signingOut") : tAuth("signOut")}
126
128
  </button>
127
129
  </div>
128
130
  </div>
@@ -1,25 +1,18 @@
1
1
  "use client";
2
2
 
3
3
  import { useState } from "react";
4
- import { useRouter, useSearchParams } from "next/navigation";
5
- import Link from "next/link";
4
+ import { useSearchParams } from "next/navigation";
5
+ import { useRouter, Link } from "@/i18n/navigation";
6
+ import { useTranslations } from "next-intl";
6
7
  import { z } from "zod";
7
8
  import { Button } from "@/components/ui/button";
8
9
  import { Input } from "@/components/ui/input";
9
10
  import { useAuth } from "@/hooks/use-auth";
10
11
 
11
- const loginSchema = z.object({
12
- email: z
13
- .string()
14
- .min(1, "Email is required")
15
- .email("Please enter a valid email address"),
16
- password: z
17
- .string()
18
- .min(1, "Password is required")
19
- .min(8, "Password must be at least 8 characters"),
20
- });
21
-
22
- type LoginFormData = z.infer<typeof loginSchema>;
12
+ type LoginFormData = {
13
+ email: string;
14
+ password: string;
15
+ };
23
16
 
24
17
  export interface LoginFormProps {
25
18
  onSuccess?: () => void;
@@ -27,10 +20,22 @@ export interface LoginFormProps {
27
20
  }
28
21
 
29
22
  export function LoginForm({ onSuccess, redirectTo }: LoginFormProps) {
23
+ const t = useTranslations("auth");
30
24
  const router = useRouter();
31
25
  const searchParams = useSearchParams();
32
26
  const defaultRedirect = redirectTo || searchParams?.get("redirect") || "/account";
33
27
 
28
+ const loginSchema = z.object({
29
+ email: z
30
+ .string()
31
+ .min(1, t("validation.emailInvalid"))
32
+ .email(t("validation.emailInvalid")),
33
+ password: z
34
+ .string()
35
+ .min(1, t("validation.passwordMinLength"))
36
+ .min(8, t("validation.passwordMinLength")),
37
+ });
38
+
34
39
  const [email, setEmail] = useState("");
35
40
  const [password, setPassword] = useState("");
36
41
  const [error, setError] = useState("");
@@ -60,7 +65,7 @@ export function LoginForm({ onSuccess, redirectTo }: LoginFormProps) {
60
65
  const loginResult = await login(email, password);
61
66
 
62
67
  if (!loginResult.success) {
63
- setError(loginResult.userErrors[0]?.message || "Login failed");
68
+ setError(loginResult.userErrors[0]?.message || t("loginFailed"));
64
69
  return;
65
70
  }
66
71
 
@@ -70,7 +75,7 @@ export function LoginForm({ onSuccess, redirectTo }: LoginFormProps) {
70
75
  router.push(defaultRedirect);
71
76
  }
72
77
  } catch {
73
- setError("An error occurred. Please try again.");
78
+ setError(t("unexpectedError"));
74
79
  }
75
80
  };
76
81
 
@@ -87,7 +92,7 @@ export function LoginForm({ onSuccess, redirectTo }: LoginFormProps) {
87
92
  htmlFor="email"
88
93
  className="text-sm font-medium text-foreground"
89
94
  >
90
- Email
95
+ {t("email")}
91
96
  </label>
92
97
  <Input
93
98
  id="email"
@@ -113,13 +118,13 @@ export function LoginForm({ onSuccess, redirectTo }: LoginFormProps) {
113
118
  htmlFor="password"
114
119
  className="text-sm font-medium text-foreground"
115
120
  >
116
- Password
121
+ {t("password")}
117
122
  </label>
118
123
  <Link
119
124
  href="/auth/forgot-password"
120
125
  className="text-xs text-primary hover:underline"
121
126
  >
122
- Forgot password?
127
+ {t("forgotPassword")}
123
128
  </Link>
124
129
  </div>
125
130
  <Input
@@ -145,16 +150,16 @@ export function LoginForm({ onSuccess, redirectTo }: LoginFormProps) {
145
150
  className="w-full"
146
151
  disabled={isLoggingIn}
147
152
  >
148
- {isLoggingIn ? "Signing in..." : "Sign In"}
153
+ {isLoggingIn ? t("signingIn") : t("signIn")}
149
154
  </Button>
150
155
 
151
156
  <div className="text-center text-sm text-muted-foreground">
152
- Don't have an account?{" "}
157
+ {t("noAccount")}{" "}
153
158
  <Link
154
159
  href="/auth/register"
155
160
  className="font-medium text-primary hover:underline"
156
161
  >
157
- Sign up
162
+ {t("signUp")}
158
163
  </Link>
159
164
  </div>
160
165
  </form>