From 75b686ffc79ef4c1c5e035ccc17ad76655cf04c4 Mon Sep 17 00:00:00 2001 From: Muhammad Zain Tariq <49867382+mzaintariq@users.noreply.github.com> Date: Wed, 3 Dec 2025 18:29:27 +0500 Subject: [PATCH 01/14] localization first pass --- .../account-member-credentials-schema.ts | 0 .../src/app/{ => [lang]}/(auth)/actions.ts | 10 +- .../src/app/{ => [lang]}/(auth)/layout.tsx | 6 +- .../{ => [lang]}/(auth)/login/LoginForm.tsx | 6 +- .../app/{ => [lang]}/(auth)/login/page.tsx | 4 +- .../src/app/{ => [lang]}/(auth)/not-found.tsx | 0 .../app/{ => [lang]}/(auth)/register/page.tsx | 10 +- .../(checkout)/checkout/AccountCheckout.tsx | 8 +- .../(checkout)/checkout/AccountDisplay.tsx | 10 +- .../checkout/AccoutCheckoutForm.tsx | 4 +- .../(checkout)/checkout/BillingForm.tsx | 10 +- .../(checkout)/checkout/CheckoutFooter.tsx | 4 +- .../(checkout)/checkout/CheckoutSidebar.tsx | 20 ++- .../(checkout)/checkout/CheckoutViews.tsx | 0 .../checkout/ConfirmationSidebar.tsx | 14 +- .../(checkout)/checkout/DeliveryForm.tsx | 12 +- .../(checkout)/checkout/GuestCheckout.tsx | 4 +- .../(checkout)/checkout/GuestInformation.tsx | 8 +- .../(checkout)/checkout/OrderConfirmation.tsx | 6 +- .../checkout/OrderConfirmationProvider.tsx | 0 .../(checkout)/checkout/PaymentForm.tsx | 2 +- .../(checkout)/checkout/ShippingForm.tsx | 8 +- .../(checkout)/checkout/ShippingSelector.tsx | 8 +- .../checkout/SubmitCheckoutButton.tsx | 2 +- .../(checkout)/checkout/actions.ts | 16 +- .../(checkout)/checkout/checkout-provider.tsx | 4 +- .../checkout/extract-cart-item-media.ts | 0 .../{ => [lang]}/(checkout)/checkout/page.tsx | 8 +- .../(checkout)/checkout/useShippingMethod.tsx | 0 .../app/{ => [lang]}/(checkout)/layout.tsx | 6 +- .../app/{ => [lang]}/(checkout)/not-found.tsx | 0 .../{ => [lang]}/(store)/ClientProvider.tsx | 0 .../{ => [lang]}/(store)/StoreProvider.tsx | 4 +- .../app/{ => [lang]}/(store)/about/page.tsx | 2 +- .../(store)/account/AccountNavigation.tsx | 2 +- .../account/addresses/DeleteAddressBtn.tsx | 2 +- .../addresses/[addressId]/UpdateForm.tsx | 10 +- .../account/addresses/[addressId]/page.tsx | 10 +- .../(store)/account/addresses/actions.ts | 8 +- .../(store)/account/addresses/add/AddForm.tsx | 10 +- .../(store)/account/addresses/add/page.tsx | 8 +- .../(store)/account/addresses/page.tsx | 12 +- .../{ => [lang]}/(store)/account/layout.tsx | 0 .../(store)/account/orders/OrderItem.tsx | 2 +- .../account/orders/OrderItemWithDetails.tsx | 2 +- .../orders/[orderId]/OrderLineItem.tsx | 0 .../orders/[orderId]/ProductThumbnail.tsx | 0 .../(store)/account/orders/[orderId]/page.tsx | 14 +- .../(store)/account/orders/page.tsx | 12 +- .../account/orders/resolve-shopper-order.ts | 0 .../(store)/account/summary/YourInfoForm.tsx | 6 +- .../(store)/account/summary/actions.ts | 8 +- .../(store)/account/summary/page.tsx | 14 +- .../{ => [lang]}/(store)/cart/CartItem.tsx | 6 +- .../(store)/cart/CartItemWide.tsx | 4 +- .../{ => [lang]}/(store)/cart/CartSidebar.tsx | 8 +- .../app/{ => [lang]}/(store)/cart/YourBag.tsx | 2 +- .../app/{ => [lang]}/(store)/cart/page.tsx | 8 +- .../src/app/{ => [lang]}/(store)/faq/page.tsx | 2 +- .../src/app/{ => [lang]}/(store)/layout.tsx | 12 +- .../app/{ => [lang]}/(store)/not-found.tsx | 0 .../src/app/{ => [lang]}/(store)/page.tsx | 4 +- .../[productId]/actions/cart-actions.ts | 12 +- .../(store)/products/[productId]/page.tsx | 26 ++-- .../(store)/search/[[...node]]/layout.tsx | 2 +- .../(store)/search/[[...node]]/page.tsx | 2 +- .../{ => [lang]}/(store)/search/search.tsx | 2 +- .../{ => [lang]}/(store)/shipping/page.tsx | 2 +- .../app/{ => [lang]}/(store)/support/page.tsx | 2 +- .../app/{ => [lang]}/(store)/terms/page.tsx | 2 +- .../{ => [lang]}/configuration-error/page.tsx | 0 examples/core/src/app/{ => [lang]}/error.tsx | 0 examples/core/src/app/{ => [lang]}/layout.tsx | 2 +- .../core/src/app/{ => [lang]}/not-found.tsx | 0 .../core/src/app/{ => [lang]}/providers.tsx | 6 +- examples/core/src/components/breadcrumb.tsx | 2 +- .../core/src/components/cart/CartSheet.tsx | 2 +- .../components/cart/RemoveCartItemButton.tsx | 2 +- .../components/cart/RemoveCartItemXButton.tsx | 2 +- .../cart/RemoveCartPromotionXButton.tsx | 2 +- .../components/checkout-item/CheckoutItem.tsx | 2 +- .../core/src/components/footer/Footer.tsx | 144 ++++++++++-------- .../components/header/AccountMobileMenu.tsx | 2 +- .../core/src/components/header/Header.tsx | 4 + .../header/account/AccountPopover.tsx | 2 +- .../header/account/AccountSwitcher.tsx | 2 +- .../header/locale/LocaleSelector.tsx | 26 ++++ .../navigation/MobileAccountSwitcher.tsx | 2 +- .../components/number-input/NumberInput.tsx | 2 +- .../product/bundles/BundleProductForm.tsx | 2 +- .../product/standard/SimpleProductForm.tsx | 2 +- .../variations/VariationProductForm.tsx | 2 +- .../src/components/search/MobileFilters.tsx | 2 +- .../src/components/search/SearchResults.tsx | 4 +- ...ate-cookie-from-generate-token-response.ts | 2 +- examples/core/src/lib/get-locale-currency.ts | 29 ++++ examples/core/src/lib/get-locale-path.ts | 6 + examples/core/src/lib/i18n.ts | 8 + .../retrieve-account-member-credentials.ts | 2 +- examples/core/src/middleware.ts | 22 ++- 100 files changed, 404 insertions(+), 293 deletions(-) rename examples/core/src/app/{ => [lang]}/(auth)/account-member-credentials-schema.ts (100%) rename examples/core/src/app/{ => [lang]}/(auth)/actions.ts (90%) rename examples/core/src/app/{ => [lang]}/(auth)/layout.tsx (85%) rename examples/core/src/app/{ => [lang]}/(auth)/login/LoginForm.tsx (90%) rename examples/core/src/app/{ => [lang]}/(auth)/login/page.tsx (90%) rename examples/core/src/app/{ => [lang]}/(auth)/not-found.tsx (100%) rename examples/core/src/app/{ => [lang]}/(auth)/register/page.tsx (89%) rename examples/core/src/app/{ => [lang]}/(checkout)/checkout/AccountCheckout.tsx (84%) rename examples/core/src/app/{ => [lang]}/(checkout)/checkout/AccountDisplay.tsx (85%) rename examples/core/src/app/{ => [lang]}/(checkout)/checkout/AccoutCheckoutForm.tsx (95%) rename examples/core/src/app/{ => [lang]}/(checkout)/checkout/BillingForm.tsx (94%) rename examples/core/src/app/{ => [lang]}/(checkout)/checkout/CheckoutFooter.tsx (86%) rename examples/core/src/app/{ => [lang]}/(checkout)/checkout/CheckoutSidebar.tsx (90%) rename examples/core/src/app/{ => [lang]}/(checkout)/checkout/CheckoutViews.tsx (100%) rename examples/core/src/app/{ => [lang]}/(checkout)/checkout/ConfirmationSidebar.tsx (86%) rename examples/core/src/app/{ => [lang]}/(checkout)/checkout/DeliveryForm.tsx (89%) rename examples/core/src/app/{ => [lang]}/(checkout)/checkout/GuestCheckout.tsx (95%) rename examples/core/src/app/{ => [lang]}/(checkout)/checkout/GuestInformation.tsx (92%) rename examples/core/src/app/{ => [lang]}/(checkout)/checkout/OrderConfirmation.tsx (95%) rename examples/core/src/app/{ => [lang]}/(checkout)/checkout/OrderConfirmationProvider.tsx (100%) rename examples/core/src/app/{ => [lang]}/(checkout)/checkout/PaymentForm.tsx (95%) rename examples/core/src/app/{ => [lang]}/(checkout)/checkout/ShippingForm.tsx (95%) rename examples/core/src/app/{ => [lang]}/(checkout)/checkout/ShippingSelector.tsx (89%) rename examples/core/src/app/{ => [lang]}/(checkout)/checkout/SubmitCheckoutButton.tsx (89%) rename examples/core/src/app/{ => [lang]}/(checkout)/checkout/actions.ts (92%) rename examples/core/src/app/{ => [lang]}/(checkout)/checkout/checkout-provider.tsx (97%) rename examples/core/src/app/{ => [lang]}/(checkout)/checkout/extract-cart-item-media.ts (100%) rename examples/core/src/app/{ => [lang]}/(checkout)/checkout/page.tsx (92%) rename examples/core/src/app/{ => [lang]}/(checkout)/checkout/useShippingMethod.tsx (100%) rename examples/core/src/app/{ => [lang]}/(checkout)/layout.tsx (85%) rename examples/core/src/app/{ => [lang]}/(checkout)/not-found.tsx (100%) rename examples/core/src/app/{ => [lang]}/(store)/ClientProvider.tsx (100%) rename examples/core/src/app/{ => [lang]}/(store)/StoreProvider.tsx (83%) rename examples/core/src/app/{ => [lang]}/(store)/about/page.tsx (56%) rename examples/core/src/app/{ => [lang]}/(store)/account/AccountNavigation.tsx (96%) rename examples/core/src/app/{ => [lang]}/(store)/account/addresses/DeleteAddressBtn.tsx (88%) rename examples/core/src/app/{ => [lang]}/(store)/account/addresses/[addressId]/UpdateForm.tsx (94%) rename examples/core/src/app/{ => [lang]}/(store)/account/addresses/[addressId]/page.tsx (82%) rename examples/core/src/app/{ => [lang]}/(store)/account/addresses/actions.ts (93%) rename examples/core/src/app/{ => [lang]}/(store)/account/addresses/add/AddForm.tsx (93%) rename examples/core/src/app/{ => [lang]}/(store)/account/addresses/add/page.tsx (76%) rename examples/core/src/app/{ => [lang]}/(store)/account/addresses/page.tsx (87%) rename examples/core/src/app/{ => [lang]}/(store)/account/layout.tsx (100%) rename examples/core/src/app/{ => [lang]}/(store)/account/orders/OrderItem.tsx (96%) rename examples/core/src/app/{ => [lang]}/(store)/account/orders/OrderItemWithDetails.tsx (92%) rename examples/core/src/app/{ => [lang]}/(store)/account/orders/[orderId]/OrderLineItem.tsx (100%) rename examples/core/src/app/{ => [lang]}/(store)/account/orders/[orderId]/ProductThumbnail.tsx (100%) rename examples/core/src/app/{ => [lang]}/(store)/account/orders/[orderId]/page.tsx (91%) rename examples/core/src/app/{ => [lang]}/(store)/account/orders/page.tsx (84%) rename examples/core/src/app/{ => [lang]}/(store)/account/orders/resolve-shopper-order.ts (100%) rename examples/core/src/app/{ => [lang]}/(store)/account/summary/YourInfoForm.tsx (88%) rename examples/core/src/app/{ => [lang]}/(store)/account/summary/actions.ts (81%) rename examples/core/src/app/{ => [lang]}/(store)/account/summary/page.tsx (85%) rename examples/core/src/app/{ => [lang]}/(store)/cart/CartItem.tsx (97%) rename examples/core/src/app/{ => [lang]}/(store)/cart/CartItemWide.tsx (92%) rename examples/core/src/app/{ => [lang]}/(store)/cart/CartSidebar.tsx (81%) rename examples/core/src/app/{ => [lang]}/(store)/cart/YourBag.tsx (92%) rename examples/core/src/app/{ => [lang]}/(store)/cart/page.tsx (90%) rename examples/core/src/app/{ => [lang]}/(store)/faq/page.tsx (55%) rename examples/core/src/app/{ => [lang]}/(store)/layout.tsx (78%) rename examples/core/src/app/{ => [lang]}/(store)/not-found.tsx (100%) rename examples/core/src/app/{ => [lang]}/(store)/page.tsx (84%) rename examples/core/src/app/{ => [lang]}/(store)/products/[productId]/actions/cart-actions.ts (89%) rename examples/core/src/app/{ => [lang]}/(store)/products/[productId]/page.tsx (81%) rename examples/core/src/app/{ => [lang]}/(store)/search/[[...node]]/layout.tsx (79%) rename examples/core/src/app/{ => [lang]}/(store)/search/[[...node]]/page.tsx (98%) rename examples/core/src/app/{ => [lang]}/(store)/search/search.tsx (83%) rename examples/core/src/app/{ => [lang]}/(store)/shipping/page.tsx (58%) rename examples/core/src/app/{ => [lang]}/(store)/support/page.tsx (58%) rename examples/core/src/app/{ => [lang]}/(store)/terms/page.tsx (60%) rename examples/core/src/app/{ => [lang]}/configuration-error/page.tsx (100%) rename examples/core/src/app/{ => [lang]}/error.tsx (100%) rename examples/core/src/app/{ => [lang]}/layout.tsx (81%) rename examples/core/src/app/{ => [lang]}/not-found.tsx (100%) rename examples/core/src/app/{ => [lang]}/providers.tsx (82%) create mode 100644 examples/core/src/components/header/locale/LocaleSelector.tsx create mode 100644 examples/core/src/lib/get-locale-currency.ts create mode 100644 examples/core/src/lib/get-locale-path.ts create mode 100644 examples/core/src/lib/i18n.ts diff --git a/examples/core/src/app/(auth)/account-member-credentials-schema.ts b/examples/core/src/app/[lang]/(auth)/account-member-credentials-schema.ts similarity index 100% rename from examples/core/src/app/(auth)/account-member-credentials-schema.ts rename to examples/core/src/app/[lang]/(auth)/account-member-credentials-schema.ts diff --git a/examples/core/src/app/(auth)/actions.ts b/examples/core/src/app/[lang]/(auth)/actions.ts similarity index 90% rename from examples/core/src/app/(auth)/actions.ts rename to examples/core/src/app/[lang]/(auth)/actions.ts index 8c30377b..db8e8334 100644 --- a/examples/core/src/app/(auth)/actions.ts +++ b/examples/core/src/app/[lang]/(auth)/actions.ts @@ -3,13 +3,13 @@ import { z } from "zod"; import { cookies } from "next/headers"; import { redirect } from "next/navigation"; -import { ACCOUNT_MEMBER_TOKEN_COOKIE_NAME } from "../../lib/cookie-constants"; -import { retrieveAccountMemberCredentials } from "../../lib/retrieve-account-member-credentials"; +import { ACCOUNT_MEMBER_TOKEN_COOKIE_NAME } from "src/lib/cookie-constants"; +import { retrieveAccountMemberCredentials } from "src/lib/retrieve-account-member-credentials"; import { revalidatePath, revalidateTag } from "next/cache"; -import { getErrorMessage } from "../../lib/get-error-message"; -import { createElasticPathClient } from "../../lib/create-elastic-path-client"; +import { getErrorMessage } from "src/lib/get-error-message"; +import { createElasticPathClient } from "src/lib/create-elastic-path-client"; import { postV2AccountMembersTokens } from "@epcc-sdk/sdks-shopper"; -import { createCookieFromGenerateTokenResponse } from "../../lib/create-cookie-from-generate-token-response"; +import { createCookieFromGenerateTokenResponse } from "src/lib/create-cookie-from-generate-token-response"; const loginSchema = z.object({ email: z.string().email(), diff --git a/examples/core/src/app/(auth)/layout.tsx b/examples/core/src/app/[lang]/(auth)/layout.tsx similarity index 85% rename from examples/core/src/app/(auth)/layout.tsx rename to examples/core/src/app/[lang]/(auth)/layout.tsx index 56503731..15a92cc9 100644 --- a/examples/core/src/app/(auth)/layout.tsx +++ b/examples/core/src/app/[lang]/(auth)/layout.tsx @@ -1,9 +1,9 @@ import localFont from "next/font/local"; import { ReactNode } from "react"; -import { getStoreInitialState } from "../../lib/get-store-initial-state"; +import { getStoreInitialState } from "src/lib/get-store-initial-state"; import { Providers } from "../providers"; import clsx from "clsx"; -import { createElasticPathClient } from "../../lib/create-elastic-path-client"; +import { createElasticPathClient } from "src/lib/create-elastic-path-client"; const SITE_NAME = process.env.NEXT_PUBLIC_SITE_NAME; const baseUrl = process.env.NEXT_PUBLIC_VERCEL_URL @@ -23,7 +23,7 @@ export const metadata = { }; const inter = localFont({ - src: "../../../public/fonts/Inter-VariableFont_opsz,wght.ttf", + src: "../../../../public/fonts/Inter-VariableFont_opsz,wght.ttf", display: "swap", variable: "--font-inter", }); diff --git a/examples/core/src/app/(auth)/login/LoginForm.tsx b/examples/core/src/app/[lang]/(auth)/login/LoginForm.tsx similarity index 90% rename from examples/core/src/app/(auth)/login/LoginForm.tsx rename to examples/core/src/app/[lang]/(auth)/login/LoginForm.tsx index a89c4a5c..dc6c0187 100644 --- a/examples/core/src/app/(auth)/login/LoginForm.tsx +++ b/examples/core/src/app/[lang]/(auth)/login/LoginForm.tsx @@ -1,9 +1,9 @@ "use client"; import { login } from "../actions"; -import { Label } from "../../../components/label/Label"; -import { Input } from "../../../components/input/Input"; -import { FormStatusButton } from "../../../components/button/FormStatusButton"; +import { Label } from "src/components/label/Label"; +import { Input } from "src/components/input/Input"; +import { FormStatusButton } from "src/components/button/FormStatusButton"; import { useState } from "react"; export function LoginForm({ returnUrl }: { returnUrl?: string }) { diff --git a/examples/core/src/app/(auth)/login/page.tsx b/examples/core/src/app/[lang]/(auth)/login/page.tsx similarity index 90% rename from examples/core/src/app/(auth)/login/page.tsx rename to examples/core/src/app/[lang]/(auth)/login/page.tsx index 779f82fd..82ab5163 100644 --- a/examples/core/src/app/(auth)/login/page.tsx +++ b/examples/core/src/app/[lang]/(auth)/login/page.tsx @@ -1,6 +1,6 @@ -import EpLogo from "../../../components/icons/ep-logo"; +import EpLogo from "src/components/icons/ep-logo"; import { cookies } from "next/headers"; -import { isAccountMemberAuthenticated } from "../../../lib/is-account-member-authenticated"; +import { isAccountMemberAuthenticated } from "src/lib/is-account-member-authenticated"; import { redirect } from "next/navigation"; import Link from "next/link"; import { LoginForm } from "./LoginForm"; diff --git a/examples/core/src/app/(auth)/not-found.tsx b/examples/core/src/app/[lang]/(auth)/not-found.tsx similarity index 100% rename from examples/core/src/app/(auth)/not-found.tsx rename to examples/core/src/app/[lang]/(auth)/not-found.tsx diff --git a/examples/core/src/app/(auth)/register/page.tsx b/examples/core/src/app/[lang]/(auth)/register/page.tsx similarity index 89% rename from examples/core/src/app/(auth)/register/page.tsx rename to examples/core/src/app/[lang]/(auth)/register/page.tsx index b41553e7..c40543f3 100644 --- a/examples/core/src/app/(auth)/register/page.tsx +++ b/examples/core/src/app/[lang]/(auth)/register/page.tsx @@ -1,12 +1,12 @@ import { register } from "../actions"; -import EpLogo from "../../../components/icons/ep-logo"; +import EpLogo from "src/components/icons/ep-logo"; import { cookies } from "next/headers"; -import { isAccountMemberAuthenticated } from "../../../lib/is-account-member-authenticated"; +import { isAccountMemberAuthenticated } from "src/lib/is-account-member-authenticated"; import { redirect } from "next/navigation"; import Link from "next/link"; -import { Label } from "../../../components/label/Label"; -import { Input } from "../../../components/input/Input"; -import { FormStatusButton } from "../../../components/button/FormStatusButton"; +import { Label } from "src/components/label/Label"; +import { Input } from "src/components/input/Input"; +import { FormStatusButton } from "src/components/button/FormStatusButton"; export default async function Register() { const cookieStore = await cookies(); diff --git a/examples/core/src/app/(checkout)/checkout/AccountCheckout.tsx b/examples/core/src/app/[lang]/(checkout)/checkout/AccountCheckout.tsx similarity index 84% rename from examples/core/src/app/(checkout)/checkout/AccountCheckout.tsx rename to examples/core/src/app/[lang]/(checkout)/checkout/AccountCheckout.tsx index 78abf139..f5d43e9e 100644 --- a/examples/core/src/app/(checkout)/checkout/AccountCheckout.tsx +++ b/examples/core/src/app/[lang]/(checkout)/checkout/AccountCheckout.tsx @@ -1,17 +1,17 @@ import { getSelectedAccount, retrieveAccountMemberCredentials, -} from "../../../lib/retrieve-account-member-credentials"; +} from "src/lib/retrieve-account-member-credentials"; import { cookies } from "next/headers"; -import { ACCOUNT_MEMBER_TOKEN_COOKIE_NAME } from "../../../lib/cookie-constants"; +import { ACCOUNT_MEMBER_TOKEN_COOKIE_NAME } from "src/lib/cookie-constants"; import { getV2AccountAddresses, getV2AccountMembersAccountMemberId, ResponseCurrency, } from "@epcc-sdk/sdks-shopper"; -import { createElasticPathClient } from "../../../lib/create-elastic-path-client"; +import { createElasticPathClient } from "src/lib/create-elastic-path-client"; import { getACart } from "@epcc-sdk/sdks-shopper"; -import { TAGS } from "../../../lib/constants"; +import { TAGS } from "src/lib/constants"; import { AccountCheckoutForm } from "./AccoutCheckoutForm"; export async function AccountCheckout({ diff --git a/examples/core/src/app/(checkout)/checkout/AccountDisplay.tsx b/examples/core/src/app/[lang]/(checkout)/checkout/AccountDisplay.tsx similarity index 85% rename from examples/core/src/app/(checkout)/checkout/AccountDisplay.tsx rename to examples/core/src/app/[lang]/(checkout)/checkout/AccountDisplay.tsx index 5f4faf35..ae2a806f 100644 --- a/examples/core/src/app/(checkout)/checkout/AccountDisplay.tsx +++ b/examples/core/src/app/[lang]/(checkout)/checkout/AccountDisplay.tsx @@ -1,13 +1,13 @@ "use client"; -import { Button } from "../../../components/button/Button"; -import { FormControl, FormField } from "../../../components/form/Form"; -import { Input } from "../../../components/input/Input"; +import { Button } from "src/components/button/Button"; +import { FormControl, FormField } from "src/components/form/Form"; +import { Input } from "src/components/input/Input"; import React, { useEffect, useTransition } from "react"; import { useFormContext } from "react-hook-form"; -import { CheckoutForm as CheckoutFormSchemaType } from "../../../components/checkout/form-schema/checkout-form-schema"; +import { CheckoutForm as CheckoutFormSchemaType } from "src/components/checkout/form-schema/checkout-form-schema"; import { logout } from "../../(auth)/actions"; -import { Skeleton } from "../../../components/skeleton/Skeleton"; +import { Skeleton } from "src/components/skeleton/Skeleton"; import { AccountMemberResponse } from "@epcc-sdk/sdks-shopper"; export function AccountDisplay({ diff --git a/examples/core/src/app/(checkout)/checkout/AccoutCheckoutForm.tsx b/examples/core/src/app/[lang]/(checkout)/checkout/AccoutCheckoutForm.tsx similarity index 95% rename from examples/core/src/app/(checkout)/checkout/AccoutCheckoutForm.tsx rename to examples/core/src/app/[lang]/(checkout)/checkout/AccoutCheckoutForm.tsx index 56f8b8d0..86b69cc4 100644 --- a/examples/core/src/app/(checkout)/checkout/AccoutCheckoutForm.tsx +++ b/examples/core/src/app/[lang]/(checkout)/checkout/AccoutCheckoutForm.tsx @@ -1,6 +1,6 @@ import Link from "next/link"; -import EpIcon from "../../../components/icons/ep-icon"; -import { Separator } from "../../../components/separator/Separator"; +import EpIcon from "src/components/icons/ep-icon"; +import { Separator } from "src/components/separator/Separator"; import { DeliveryForm } from "./DeliveryForm"; import { PaymentForm } from "./PaymentForm"; import { BillingForm } from "./BillingForm"; diff --git a/examples/core/src/app/(checkout)/checkout/BillingForm.tsx b/examples/core/src/app/[lang]/(checkout)/checkout/BillingForm.tsx similarity index 94% rename from examples/core/src/app/(checkout)/checkout/BillingForm.tsx rename to examples/core/src/app/[lang]/(checkout)/checkout/BillingForm.tsx index 8c1b95e4..e549506a 100644 --- a/examples/core/src/app/(checkout)/checkout/BillingForm.tsx +++ b/examples/core/src/app/[lang]/(checkout)/checkout/BillingForm.tsx @@ -1,17 +1,17 @@ "use client"; -import { CheckoutForm as CheckoutFormSchemaType } from "../../../components/checkout/form-schema/checkout-form-schema"; -import { Checkbox } from "../../../components/Checkbox"; +import { CheckoutForm as CheckoutFormSchemaType } from "src/components/checkout/form-schema/checkout-form-schema"; +import { Checkbox } from "src/components/Checkbox"; import { FormControl, FormField, FormItem, FormLabel, FormMessage, -} from "../../../components/form/Form"; +} from "src/components/form/Form"; import { useFormContext, useWatch } from "react-hook-form"; -import { Input } from "../../../components/input/Input"; +import { Input } from "src/components/input/Input"; import React, { useEffect } from "react"; -import { CountryCombobox } from "../../../components/combobox/CountryCombobox"; +import { CountryCombobox } from "src/components/combobox/CountryCombobox"; export function BillingForm() { const form = useFormContext(); diff --git a/examples/core/src/app/(checkout)/checkout/CheckoutFooter.tsx b/examples/core/src/app/[lang]/(checkout)/checkout/CheckoutFooter.tsx similarity index 86% rename from examples/core/src/app/(checkout)/checkout/CheckoutFooter.tsx rename to examples/core/src/app/[lang]/(checkout)/checkout/CheckoutFooter.tsx index 9882b3a1..3379a522 100644 --- a/examples/core/src/app/(checkout)/checkout/CheckoutFooter.tsx +++ b/examples/core/src/app/[lang]/(checkout)/checkout/CheckoutFooter.tsx @@ -1,6 +1,6 @@ -import { Separator } from "../../../components/separator/Separator"; +import { Separator } from "src/components/separator/Separator"; import Link from "next/link"; -import EpLogo from "../../../components/icons/ep-logo"; +import EpLogo from "src/components/icons/ep-logo"; import * as React from "react"; export function CheckoutFooter() { diff --git a/examples/core/src/app/(checkout)/checkout/CheckoutSidebar.tsx b/examples/core/src/app/[lang]/(checkout)/checkout/CheckoutSidebar.tsx similarity index 90% rename from examples/core/src/app/(checkout)/checkout/CheckoutSidebar.tsx rename to examples/core/src/app/[lang]/(checkout)/checkout/CheckoutSidebar.tsx index d06b60ef..60694ced 100644 --- a/examples/core/src/app/(checkout)/checkout/CheckoutSidebar.tsx +++ b/examples/core/src/app/[lang]/(checkout)/checkout/CheckoutSidebar.tsx @@ -1,25 +1,23 @@ "use client"; -import { Separator } from "../../../components/separator/Separator"; -import { CartDiscounts } from "../../../components/cart/CartDiscounts"; +import { Separator } from "src/components/separator/Separator"; +import { CartDiscounts } from "src/components/cart/CartDiscounts"; import * as React from "react"; import { ItemSidebarItems, ItemSidebarPromotions, ItemSidebarTotals, - ItemSidebarTotalsDiscount, - ItemSidebarTotalsSubTotal, ItemSidebarTotalsTax, resolveTotalInclShipping, -} from "../../../components/checkout-sidebar/ItemSidebar"; +} from "src/components/checkout-sidebar/ItemSidebar"; import { staticDeliveryMethods } from "./useShippingMethod"; -import { cn } from "../../../lib/cn"; +import { cn } from "src/lib/cn"; import { useWatch } from "react-hook-form"; -import { EP_CURRENCY_CODE } from "../../../lib/resolve-ep-currency-code"; -import { formatCurrency } from "../../../lib/format-currency"; -import { LoadingDots } from "../../../components/LoadingDots"; +import { EP_CURRENCY_CODE } from "src/lib/resolve-ep-currency-code"; +import { formatCurrency } from "src/lib/format-currency"; +import { LoadingDots } from "src/components/LoadingDots"; import { getACart, ResponseCurrency } from "@epcc-sdk/sdks-shopper"; -import { ItemSidebarHideable } from "../../../components/checkout-sidebar/ItemSidebarHideable"; -import { groupCartItems } from "../../../lib/group-cart-items"; +import { ItemSidebarHideable } from "src/components/checkout-sidebar/ItemSidebarHideable"; +import { groupCartItems } from "src/lib/group-cart-items"; export function CheckoutSidebar({ cart, diff --git a/examples/core/src/app/(checkout)/checkout/CheckoutViews.tsx b/examples/core/src/app/[lang]/(checkout)/checkout/CheckoutViews.tsx similarity index 100% rename from examples/core/src/app/(checkout)/checkout/CheckoutViews.tsx rename to examples/core/src/app/[lang]/(checkout)/checkout/CheckoutViews.tsx diff --git a/examples/core/src/app/(checkout)/checkout/ConfirmationSidebar.tsx b/examples/core/src/app/[lang]/(checkout)/checkout/ConfirmationSidebar.tsx similarity index 86% rename from examples/core/src/app/(checkout)/checkout/ConfirmationSidebar.tsx rename to examples/core/src/app/[lang]/(checkout)/checkout/ConfirmationSidebar.tsx index 87670a54..70f577c4 100644 --- a/examples/core/src/app/(checkout)/checkout/ConfirmationSidebar.tsx +++ b/examples/core/src/app/[lang]/(checkout)/checkout/ConfirmationSidebar.tsx @@ -1,6 +1,6 @@ "use client"; -import { Separator } from "../../../components/separator/Separator"; -import { CartDiscountsReadOnly } from "../../../components/cart/CartDiscounts"; +import { Separator } from "src/components/separator/Separator"; +import { CartDiscountsReadOnly } from "src/components/cart/CartDiscounts"; import * as React from "react"; import { ItemSidebarItems, @@ -9,12 +9,12 @@ import { ItemSidebarTotalsSubTotal, ItemSidebarTotalsTax, resolveTotalInclShipping, -} from "../../../components/checkout-sidebar/ItemSidebar"; +} from "src/components/checkout-sidebar/ItemSidebar"; import { staticDeliveryMethods } from "./useShippingMethod"; -import { EP_CURRENCY_CODE } from "../../../lib/resolve-ep-currency-code"; -import { LoadingDots } from "../../../components/LoadingDots"; -import { ItemSidebarHideable } from "../../../components/checkout-sidebar/ItemSidebarHideable"; -import { groupCartItems } from "../../../lib/group-cart-items"; +import { EP_CURRENCY_CODE } from "src/lib/resolve-ep-currency-code"; +import { LoadingDots } from "src/components/LoadingDots"; +import { ItemSidebarHideable } from "src/components/checkout-sidebar/ItemSidebarHideable"; +import { groupCartItems } from "src/lib/group-cart-items"; import { ResponseCurrency } from "@epcc-sdk/sdks-shopper"; import { useOrderConfirmation } from "./OrderConfirmationProvider"; diff --git a/examples/core/src/app/(checkout)/checkout/DeliveryForm.tsx b/examples/core/src/app/[lang]/(checkout)/checkout/DeliveryForm.tsx similarity index 89% rename from examples/core/src/app/(checkout)/checkout/DeliveryForm.tsx rename to examples/core/src/app/[lang]/(checkout)/checkout/DeliveryForm.tsx index 9ba73ff5..18619847 100644 --- a/examples/core/src/app/(checkout)/checkout/DeliveryForm.tsx +++ b/examples/core/src/app/[lang]/(checkout)/checkout/DeliveryForm.tsx @@ -1,25 +1,25 @@ "use client"; -import { CheckoutForm as CheckoutFormSchemaType } from "../../../components/checkout/form-schema/checkout-form-schema"; +import { CheckoutForm as CheckoutFormSchemaType } from "src/components/checkout/form-schema/checkout-form-schema"; import { RadioGroup, RadioGroupItem, -} from "../../../components/radio-group/RadioGroup"; -import { Label } from "../../../components/label/Label"; -import { cn } from "../../../lib/cn"; +} from "src/components/radio-group/RadioGroup"; +import { Label } from "src/components/label/Label"; +import { cn } from "src/lib/cn"; import { FormControl, FormField, FormItem, FormLabel, FormMessage, -} from "../../../components/form/Form"; +} from "src/components/form/Form"; import { useFormContext } from "react-hook-form"; import { LightBulbIcon } from "@heroicons/react/24/outline"; import { Alert, AlertDescription, AlertTitle, -} from "../../../components/alert/Alert"; +} from "src/components/alert/Alert"; import { staticDeliveryMethods } from "./useShippingMethod"; export function DeliveryForm() { diff --git a/examples/core/src/app/(checkout)/checkout/GuestCheckout.tsx b/examples/core/src/app/[lang]/(checkout)/checkout/GuestCheckout.tsx similarity index 95% rename from examples/core/src/app/(checkout)/checkout/GuestCheckout.tsx rename to examples/core/src/app/[lang]/(checkout)/checkout/GuestCheckout.tsx index f83084f1..e036c8bf 100644 --- a/examples/core/src/app/(checkout)/checkout/GuestCheckout.tsx +++ b/examples/core/src/app/[lang]/(checkout)/checkout/GuestCheckout.tsx @@ -2,12 +2,12 @@ import { GuestInformation } from "./GuestInformation"; import { ShippingForm } from "./ShippingForm"; import Link from "next/link"; -import EpIcon from "../../../components/icons/ep-icon"; +import EpIcon from "src/components/icons/ep-icon"; import { DeliveryForm } from "./DeliveryForm"; import { PaymentForm } from "./PaymentForm"; import { BillingForm } from "./BillingForm"; import { SubmitCheckoutButton } from "./SubmitCheckoutButton"; -import { Separator } from "../../../components/separator/Separator"; +import { Separator } from "src/components/separator/Separator"; import * as React from "react"; import { CheckoutSidebar } from "./CheckoutSidebar"; import { getACart, ResponseCurrency } from "@epcc-sdk/sdks-shopper"; diff --git a/examples/core/src/app/(checkout)/checkout/GuestInformation.tsx b/examples/core/src/app/[lang]/(checkout)/checkout/GuestInformation.tsx similarity index 92% rename from examples/core/src/app/(checkout)/checkout/GuestInformation.tsx rename to examples/core/src/app/[lang]/(checkout)/checkout/GuestInformation.tsx index 92009e61..6f42315f 100644 --- a/examples/core/src/app/(checkout)/checkout/GuestInformation.tsx +++ b/examples/core/src/app/[lang]/(checkout)/checkout/GuestInformation.tsx @@ -3,7 +3,7 @@ import { AnonymousCheckoutForm, SubscriptionCheckoutForm, -} from "../../../components/checkout/form-schema/checkout-form-schema"; +} from "src/components/checkout/form-schema/checkout-form-schema"; import Link from "next/link"; import { usePathname } from "next/navigation"; import { @@ -13,11 +13,11 @@ import { FormItem, FormLabel, FormMessage, -} from "../../../components/form/Form"; -import { Input } from "../../../components/input/Input"; +} from "src/components/form/Form"; +import { Input } from "src/components/input/Input"; import React from "react"; import { useFormContext, useWatch } from "react-hook-form"; -import { Checkbox } from "../../../components/Checkbox"; +import { Checkbox } from "src/components/Checkbox"; export function GuestInformation() { const pathname = usePathname(); diff --git a/examples/core/src/app/(checkout)/checkout/OrderConfirmation.tsx b/examples/core/src/app/[lang]/(checkout)/checkout/OrderConfirmation.tsx similarity index 95% rename from examples/core/src/app/(checkout)/checkout/OrderConfirmation.tsx rename to examples/core/src/app/[lang]/(checkout)/checkout/OrderConfirmation.tsx index 959ba3c5..49e460fb 100644 --- a/examples/core/src/app/(checkout)/checkout/OrderConfirmation.tsx +++ b/examples/core/src/app/[lang]/(checkout)/checkout/OrderConfirmation.tsx @@ -1,11 +1,11 @@ "use client"; import { ConfirmationSidebar } from "./ConfirmationSidebar"; import Link from "next/link"; -import EpIcon from "../../../components/icons/ep-icon"; +import EpIcon from "src/components/icons/ep-icon"; import * as React from "react"; -import { Separator } from "../../../components/separator/Separator"; +import { Separator } from "src/components/separator/Separator"; import { CheckoutFooter } from "./CheckoutFooter"; -import { Button } from "../../../components/button/Button"; +import { Button } from "src/components/button/Button"; import { ResponseCurrency } from "@epcc-sdk/sdks-shopper"; import { PaymentCompleteResponse } from "./actions"; diff --git a/examples/core/src/app/(checkout)/checkout/OrderConfirmationProvider.tsx b/examples/core/src/app/[lang]/(checkout)/checkout/OrderConfirmationProvider.tsx similarity index 100% rename from examples/core/src/app/(checkout)/checkout/OrderConfirmationProvider.tsx rename to examples/core/src/app/[lang]/(checkout)/checkout/OrderConfirmationProvider.tsx diff --git a/examples/core/src/app/(checkout)/checkout/PaymentForm.tsx b/examples/core/src/app/[lang]/(checkout)/checkout/PaymentForm.tsx similarity index 95% rename from examples/core/src/app/(checkout)/checkout/PaymentForm.tsx rename to examples/core/src/app/[lang]/(checkout)/checkout/PaymentForm.tsx index ad609d01..e8002516 100644 --- a/examples/core/src/app/(checkout)/checkout/PaymentForm.tsx +++ b/examples/core/src/app/[lang]/(checkout)/checkout/PaymentForm.tsx @@ -4,7 +4,7 @@ import { Alert, AlertDescription, AlertTitle, -} from "../../../components/alert/Alert"; +} from "src/components/alert/Alert"; export function PaymentForm() { return ( diff --git a/examples/core/src/app/(checkout)/checkout/ShippingForm.tsx b/examples/core/src/app/[lang]/(checkout)/checkout/ShippingForm.tsx similarity index 95% rename from examples/core/src/app/(checkout)/checkout/ShippingForm.tsx rename to examples/core/src/app/[lang]/(checkout)/checkout/ShippingForm.tsx index bbef2821..3ae77d9a 100644 --- a/examples/core/src/app/(checkout)/checkout/ShippingForm.tsx +++ b/examples/core/src/app/[lang]/(checkout)/checkout/ShippingForm.tsx @@ -1,6 +1,6 @@ "use client"; -import { CheckoutForm as CheckoutFormSchemaType } from "../../../components/checkout/form-schema/checkout-form-schema"; +import { CheckoutForm as CheckoutFormSchemaType } from "src/components/checkout/form-schema/checkout-form-schema"; import { useFormContext } from "react-hook-form"; import { FormControl, @@ -8,10 +8,10 @@ import { FormItem, FormLabel, FormMessage, -} from "../../../components/form/Form"; -import { Input } from "../../../components/input/Input"; +} from "src/components/form/Form"; +import { Input } from "src/components/input/Input"; import React from "react"; -import { CountryCombobox } from "../../../components/combobox/CountryCombobox"; +import { CountryCombobox } from "src/components/combobox/CountryCombobox"; export function ShippingForm() { const form = useFormContext(); diff --git a/examples/core/src/app/(checkout)/checkout/ShippingSelector.tsx b/examples/core/src/app/[lang]/(checkout)/checkout/ShippingSelector.tsx similarity index 89% rename from examples/core/src/app/(checkout)/checkout/ShippingSelector.tsx rename to examples/core/src/app/[lang]/(checkout)/checkout/ShippingSelector.tsx index c3731df2..dc1b0b3e 100644 --- a/examples/core/src/app/(checkout)/checkout/ShippingSelector.tsx +++ b/examples/core/src/app/[lang]/(checkout)/checkout/ShippingSelector.tsx @@ -5,12 +5,12 @@ import { SelectItem, SelectTrigger, SelectValue, -} from "../../../components/select/Select"; +} from "src/components/select/Select"; import { useFormContext } from "react-hook-form"; -import { CheckoutForm as CheckoutFormSchemaType } from "../../../components/checkout/form-schema/checkout-form-schema"; +import { CheckoutForm as CheckoutFormSchemaType } from "src/components/checkout/form-schema/checkout-form-schema"; import { useEffect } from "react"; -import { Skeleton } from "../../../components/skeleton/Skeleton"; -import { Button } from "../../../components/button/Button"; +import { Skeleton } from "src/components/skeleton/Skeleton"; +import { Button } from "src/components/button/Button"; import Link from "next/link"; import { AccountAddressResponse } from "@epcc-sdk/sdks-shopper"; diff --git a/examples/core/src/app/(checkout)/checkout/SubmitCheckoutButton.tsx b/examples/core/src/app/[lang]/(checkout)/checkout/SubmitCheckoutButton.tsx similarity index 89% rename from examples/core/src/app/(checkout)/checkout/SubmitCheckoutButton.tsx rename to examples/core/src/app/[lang]/(checkout)/checkout/SubmitCheckoutButton.tsx index 37a12087..8aafed43 100644 --- a/examples/core/src/app/(checkout)/checkout/SubmitCheckoutButton.tsx +++ b/examples/core/src/app/[lang]/(checkout)/checkout/SubmitCheckoutButton.tsx @@ -1,7 +1,7 @@ "use client"; import { useCheckout } from "./checkout-provider"; -import { StatusButton } from "../../../components/button/StatusButton"; +import { StatusButton } from "src/components/button/StatusButton"; import { CartResponse } from "@epcc-sdk/sdks-shopper"; export function SubmitCheckoutButton({ cart }: { cart: CartResponse }) { diff --git a/examples/core/src/app/(checkout)/checkout/actions.ts b/examples/core/src/app/[lang]/(checkout)/checkout/actions.ts similarity index 92% rename from examples/core/src/app/(checkout)/checkout/actions.ts rename to examples/core/src/app/[lang]/(checkout)/checkout/actions.ts index 8d04636f..c2ec8d90 100644 --- a/examples/core/src/app/(checkout)/checkout/actions.ts +++ b/examples/core/src/app/[lang]/(checkout)/checkout/actions.ts @@ -5,8 +5,8 @@ import { staticDeliveryMethods } from "./useShippingMethod"; import { CheckoutForm, checkoutFormSchema, -} from "../../../components/checkout/form-schema/checkout-form-schema"; -import { createElasticPathClient } from "../../../lib/create-elastic-path-client"; +} from "src/components/checkout/form-schema/checkout-form-schema"; +import { createElasticPathClient } from "src/lib/create-elastic-path-client"; import { manageCarts, checkoutApi, @@ -23,18 +23,18 @@ import { postV2AccountMembersTokens, CartsResponse, } from "@epcc-sdk/sdks-shopper"; -import { getCartCookieServer } from "../../../lib/cart-cookie-server"; +import { getCartCookieServer } from "src/lib/cart-cookie-server"; import { cookies } from "next/headers"; import { getSelectedAccount, retrieveAccountMemberCredentials, -} from "../../../lib/retrieve-account-member-credentials"; -import { ACCOUNT_MEMBER_TOKEN_COOKIE_NAME } from "../../../lib/cookie-constants"; +} from "src/lib/retrieve-account-member-credentials"; +import { ACCOUNT_MEMBER_TOKEN_COOKIE_NAME } from "src/lib/cookie-constants"; import { revalidatePath, revalidateTag } from "next/cache"; -import { extractCartItemProductIds } from "../../../lib/extract-cart-item-product-ids"; +import { extractCartItemProductIds } from "src/lib/extract-cart-item-product-ids"; import { extractCartItemMedia } from "./extract-cart-item-media"; -import { generatePassword } from "../../../lib/generate-password"; -import { createCookieFromGenerateTokenResponse } from "../../../lib/create-cookie-from-generate-token-response"; +import { generatePassword } from "src/lib/generate-password"; +import { createCookieFromGenerateTokenResponse } from "src/lib/create-cookie-from-generate-token-response"; const PASSWORD_PROFILE_ID = process.env.NEXT_PUBLIC_PASSWORD_PROFILE_ID!; diff --git a/examples/core/src/app/(checkout)/checkout/checkout-provider.tsx b/examples/core/src/app/[lang]/(checkout)/checkout/checkout-provider.tsx similarity index 97% rename from examples/core/src/app/(checkout)/checkout/checkout-provider.tsx rename to examples/core/src/app/[lang]/(checkout)/checkout/checkout-provider.tsx index 29183178..c53348ed 100644 --- a/examples/core/src/app/(checkout)/checkout/checkout-provider.tsx +++ b/examples/core/src/app/[lang]/(checkout)/checkout/checkout-provider.tsx @@ -8,9 +8,9 @@ import { CheckoutForm, NonAccountCheckoutForm, nonAccountCheckoutFormSchema, -} from "../../../components/checkout/form-schema/checkout-form-schema"; +} from "src/components/checkout/form-schema/checkout-form-schema"; import { zodResolver } from "@hookform/resolvers/zod"; -import { Form } from "../../../components/form/Form"; +import { Form } from "src/components/form/Form"; import { ShippingMethod, staticDeliveryMethods } from "./useShippingMethod"; import { getACart } from "@epcc-sdk/sdks-shopper"; import { paymentComplete } from "./actions"; diff --git a/examples/core/src/app/(checkout)/checkout/extract-cart-item-media.ts b/examples/core/src/app/[lang]/(checkout)/checkout/extract-cart-item-media.ts similarity index 100% rename from examples/core/src/app/(checkout)/checkout/extract-cart-item-media.ts rename to examples/core/src/app/[lang]/(checkout)/checkout/extract-cart-item-media.ts diff --git a/examples/core/src/app/(checkout)/checkout/page.tsx b/examples/core/src/app/[lang]/(checkout)/checkout/page.tsx similarity index 92% rename from examples/core/src/app/(checkout)/checkout/page.tsx rename to examples/core/src/app/[lang]/(checkout)/checkout/page.tsx index 9eed768e..97a930fb 100644 --- a/examples/core/src/app/(checkout)/checkout/page.tsx +++ b/examples/core/src/app/[lang]/(checkout)/checkout/page.tsx @@ -1,14 +1,14 @@ import { Metadata } from "next"; import { AccountCheckout } from "./AccountCheckout"; -import { CART_COOKIE_NAME } from "../../../lib/cookie-constants"; +import { CART_COOKIE_NAME } from "src/lib/cookie-constants"; import { GuestCheckout } from "./GuestCheckout"; import { cookies } from "next/headers"; import { notFound } from "next/navigation"; import { CheckoutViews } from "./CheckoutViews"; import { getAllCurrencies, getACart, getByContextProduct } from "@epcc-sdk/sdks-shopper"; -import { createElasticPathClient } from "../../../lib/create-elastic-path-client"; +import { createElasticPathClient } from "src/lib/create-elastic-path-client"; import { OrderConfirmationProvider } from "./OrderConfirmationProvider"; -import { TAGS } from "../../../lib/constants"; +import { TAGS } from "src/lib/constants"; import { isAccountAuthenticated } from "@epcc-sdk/sdks-nextjs"; export const metadata: Metadata = { @@ -32,7 +32,7 @@ export default async function CheckoutPage() { }, next: { tags: [TAGS.cart], - }, + } }); // Fetch product details for each cart item to get original sale price diff --git a/examples/core/src/app/(checkout)/checkout/useShippingMethod.tsx b/examples/core/src/app/[lang]/(checkout)/checkout/useShippingMethod.tsx similarity index 100% rename from examples/core/src/app/(checkout)/checkout/useShippingMethod.tsx rename to examples/core/src/app/[lang]/(checkout)/checkout/useShippingMethod.tsx diff --git a/examples/core/src/app/(checkout)/layout.tsx b/examples/core/src/app/[lang]/(checkout)/layout.tsx similarity index 85% rename from examples/core/src/app/(checkout)/layout.tsx rename to examples/core/src/app/[lang]/(checkout)/layout.tsx index c311381e..9de4e672 100644 --- a/examples/core/src/app/(checkout)/layout.tsx +++ b/examples/core/src/app/[lang]/(checkout)/layout.tsx @@ -1,9 +1,9 @@ import localFont from "next/font/local"; import { ReactNode } from "react"; -import { getStoreInitialState } from "../../lib/get-store-initial-state"; +import { getStoreInitialState } from "src/lib/get-store-initial-state"; import { Providers } from "../providers"; import clsx from "clsx"; -import { createElasticPathClient } from "../../lib/create-elastic-path-client"; +import { createElasticPathClient } from "src/lib/create-elastic-path-client"; const SITE_NAME = process.env.NEXT_PUBLIC_SITE_NAME; const baseUrl = process.env.NEXT_PUBLIC_VERCEL_URL @@ -23,7 +23,7 @@ export const metadata = { }; const inter = localFont({ - src: "../../../public/fonts/Inter-VariableFont_opsz,wght.ttf", + src: "../../../../public/fonts/Inter-VariableFont_opsz,wght.ttf", display: "swap", variable: "--font-inter", }); diff --git a/examples/core/src/app/(checkout)/not-found.tsx b/examples/core/src/app/[lang]/(checkout)/not-found.tsx similarity index 100% rename from examples/core/src/app/(checkout)/not-found.tsx rename to examples/core/src/app/[lang]/(checkout)/not-found.tsx diff --git a/examples/core/src/app/(store)/ClientProvider.tsx b/examples/core/src/app/[lang]/(store)/ClientProvider.tsx similarity index 100% rename from examples/core/src/app/(store)/ClientProvider.tsx rename to examples/core/src/app/[lang]/(store)/ClientProvider.tsx diff --git a/examples/core/src/app/(store)/StoreProvider.tsx b/examples/core/src/app/[lang]/(store)/StoreProvider.tsx similarity index 83% rename from examples/core/src/app/(store)/StoreProvider.tsx rename to examples/core/src/app/[lang]/(store)/StoreProvider.tsx index a789a1e5..389f7360 100644 --- a/examples/core/src/app/(store)/StoreProvider.tsx +++ b/examples/core/src/app/[lang]/(store)/StoreProvider.tsx @@ -1,8 +1,8 @@ "use client"; import React, { createContext, ReactNode, useContext } from "react"; -import { InitialState } from "../../lib/get-store-initial-state"; -import { NavigationNode } from "../../lib/build-site-navigation"; +import { InitialState } from "src/lib/get-store-initial-state"; +import { NavigationNode } from "src/lib/build-site-navigation"; interface StoreState { nav?: NavigationNode[]; diff --git a/examples/core/src/app/(store)/about/page.tsx b/examples/core/src/app/[lang]/(store)/about/page.tsx similarity index 56% rename from examples/core/src/app/(store)/about/page.tsx rename to examples/core/src/app/[lang]/(store)/about/page.tsx index fc900ed0..6935aac9 100644 --- a/examples/core/src/app/(store)/about/page.tsx +++ b/examples/core/src/app/[lang]/(store)/about/page.tsx @@ -1,4 +1,4 @@ -import Blurb from "../../../components/shared/blurb"; +import Blurb from "src/components/shared/blurb"; export default function About() { return ; diff --git a/examples/core/src/app/(store)/account/AccountNavigation.tsx b/examples/core/src/app/[lang]/(store)/account/AccountNavigation.tsx similarity index 96% rename from examples/core/src/app/(store)/account/AccountNavigation.tsx rename to examples/core/src/app/[lang]/(store)/account/AccountNavigation.tsx index 15324a86..496d5a95 100644 --- a/examples/core/src/app/(store)/account/AccountNavigation.tsx +++ b/examples/core/src/app/[lang]/(store)/account/AccountNavigation.tsx @@ -1,7 +1,7 @@ "use client"; import Link from "next/link"; import { usePathname } from "next/navigation"; -import { Button } from "../../../components/button/Button"; +import { Button } from "src/components/button/Button"; import { logout } from "../../(auth)/actions"; import { useTransition } from "react"; diff --git a/examples/core/src/app/(store)/account/addresses/DeleteAddressBtn.tsx b/examples/core/src/app/[lang]/(store)/account/addresses/DeleteAddressBtn.tsx similarity index 88% rename from examples/core/src/app/(store)/account/addresses/DeleteAddressBtn.tsx rename to examples/core/src/app/[lang]/(store)/account/addresses/DeleteAddressBtn.tsx index 6f255b7c..585fe967 100644 --- a/examples/core/src/app/(store)/account/addresses/DeleteAddressBtn.tsx +++ b/examples/core/src/app/[lang]/(store)/account/addresses/DeleteAddressBtn.tsx @@ -1,7 +1,7 @@ "use client"; import { deleteAddress } from "./actions"; -import { FormStatusButton } from "../../../../components/button/FormStatusButton"; +import { FormStatusButton } from "src/components/button/FormStatusButton"; import { TrashIcon } from "@heroicons/react/24/outline"; import React from "react"; diff --git a/examples/core/src/app/(store)/account/addresses/[addressId]/UpdateForm.tsx b/examples/core/src/app/[lang]/(store)/account/addresses/[addressId]/UpdateForm.tsx similarity index 94% rename from examples/core/src/app/(store)/account/addresses/[addressId]/UpdateForm.tsx rename to examples/core/src/app/[lang]/(store)/account/addresses/[addressId]/UpdateForm.tsx index 5ceb32be..49710935 100644 --- a/examples/core/src/app/(store)/account/addresses/[addressId]/UpdateForm.tsx +++ b/examples/core/src/app/[lang]/(store)/account/addresses/[addressId]/UpdateForm.tsx @@ -1,16 +1,16 @@ import { updateAddress } from "../actions"; -import { Label } from "../../../../../components/label/Label"; -import { Input } from "../../../../../components/input/Input"; +import { Label } from "src/components/label/Label"; +import { Input } from "src/components/input/Input"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, -} from "../../../../../components/select/Select"; -import { FormStatusButton } from "../../../../../components/button/FormStatusButton"; +} from "src/components/select/Select"; +import { FormStatusButton } from "src/components/button/FormStatusButton"; import React from "react"; -import { countries as staticCountries } from "../../../../../lib/all-countries"; +import { countries as staticCountries } from "src/lib/all-countries"; import { AccountAddressResponse } from "@epcc-sdk/sdks-shopper"; export function UpdateForm({ diff --git a/examples/core/src/app/(store)/account/addresses/[addressId]/page.tsx b/examples/core/src/app/[lang]/(store)/account/addresses/[addressId]/page.tsx similarity index 82% rename from examples/core/src/app/(store)/account/addresses/[addressId]/page.tsx rename to examples/core/src/app/[lang]/(store)/account/addresses/[addressId]/page.tsx index d8c3dbc3..eacb33cd 100644 --- a/examples/core/src/app/(store)/account/addresses/[addressId]/page.tsx +++ b/examples/core/src/app/[lang]/(store)/account/addresses/[addressId]/page.tsx @@ -3,15 +3,15 @@ import { notFound, redirect } from "next/navigation"; import { getSelectedAccount, retrieveAccountMemberCredentials, -} from "../../../../../lib/retrieve-account-member-credentials"; -import { ACCOUNT_MEMBER_TOKEN_COOKIE_NAME } from "../../../../../lib/cookie-constants"; -import { Button } from "../../../../../components/button/Button"; +} from "src/lib/retrieve-account-member-credentials"; +import { ACCOUNT_MEMBER_TOKEN_COOKIE_NAME } from "src/lib/cookie-constants"; +import { Button } from "src/components/button/Button"; import Link from "next/link"; import { ArrowLeftIcon } from "@heroicons/react/24/outline"; import React from "react"; -import { Separator } from "../../../../../components/separator/Separator"; +import { Separator } from "src/components/separator/Separator"; import { UpdateForm } from "./UpdateForm"; -import { createElasticPathClient } from "../../../../../lib/create-elastic-path-client"; +import { createElasticPathClient } from "src/lib/create-elastic-path-client"; import { getV2AccountAddress } from "@epcc-sdk/sdks-shopper"; export const dynamic = "force-dynamic"; diff --git a/examples/core/src/app/(store)/account/addresses/actions.ts b/examples/core/src/app/[lang]/(store)/account/addresses/actions.ts similarity index 93% rename from examples/core/src/app/(store)/account/addresses/actions.ts rename to examples/core/src/app/[lang]/(store)/account/addresses/actions.ts index 45fa86b7..3b037d2b 100644 --- a/examples/core/src/app/(store)/account/addresses/actions.ts +++ b/examples/core/src/app/[lang]/(store)/account/addresses/actions.ts @@ -5,12 +5,12 @@ import { cookies } from "next/headers"; import { getSelectedAccount, retrieveAccountMemberCredentials, -} from "../../../../lib/retrieve-account-member-credentials"; -import { ACCOUNT_MEMBER_TOKEN_COOKIE_NAME } from "../../../../lib/cookie-constants"; +} from "src/lib/retrieve-account-member-credentials"; +import { ACCOUNT_MEMBER_TOKEN_COOKIE_NAME } from "src/lib/cookie-constants"; import { revalidatePath, revalidateTag } from "next/cache"; -import { shippingAddressSchema } from "../../../../components/checkout/form-schema/checkout-form-schema"; +import { shippingAddressSchema } from "src/components/checkout/form-schema/checkout-form-schema"; import { redirect } from "next/navigation"; -import { createElasticPathClient } from "../../../../lib/create-elastic-path-client"; +import { createElasticPathClient } from "src/lib/create-elastic-path-client"; import { deleteV2AccountAddress, postV2AccountAddress, diff --git a/examples/core/src/app/(store)/account/addresses/add/AddForm.tsx b/examples/core/src/app/[lang]/(store)/account/addresses/add/AddForm.tsx similarity index 93% rename from examples/core/src/app/(store)/account/addresses/add/AddForm.tsx rename to examples/core/src/app/[lang]/(store)/account/addresses/add/AddForm.tsx index ef23a7b0..54c7f623 100644 --- a/examples/core/src/app/(store)/account/addresses/add/AddForm.tsx +++ b/examples/core/src/app/[lang]/(store)/account/addresses/add/AddForm.tsx @@ -1,16 +1,16 @@ import { addAddress } from "../actions"; -import { Label } from "../../../../../components/label/Label"; -import { Input } from "../../../../../components/input/Input"; +import { Label } from "src/components/label/Label"; +import { Input } from "src/components/input/Input"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, -} from "../../../../../components/select/Select"; -import { FormStatusButton } from "../../../../../components/button/FormStatusButton"; +} from "src/components/select/Select"; +import { FormStatusButton } from "src/components/button/FormStatusButton"; import React from "react"; -import { countries as staticCountries } from "../../../../../lib/all-countries"; +import { countries as staticCountries } from "src/lib/all-countries"; export function AddForm() { const countries = staticCountries; diff --git a/examples/core/src/app/(store)/account/addresses/add/page.tsx b/examples/core/src/app/[lang]/(store)/account/addresses/add/page.tsx similarity index 76% rename from examples/core/src/app/(store)/account/addresses/add/page.tsx rename to examples/core/src/app/[lang]/(store)/account/addresses/add/page.tsx index 12641f83..a294ed59 100644 --- a/examples/core/src/app/(store)/account/addresses/add/page.tsx +++ b/examples/core/src/app/[lang]/(store)/account/addresses/add/page.tsx @@ -1,12 +1,12 @@ import { cookies } from "next/headers"; import { redirect } from "next/navigation"; -import { retrieveAccountMemberCredentials } from "../../../../../lib/retrieve-account-member-credentials"; -import { ACCOUNT_MEMBER_TOKEN_COOKIE_NAME } from "../../../../../lib/cookie-constants"; -import { Button } from "../../../../../components/button/Button"; +import { retrieveAccountMemberCredentials } from "src/lib/retrieve-account-member-credentials"; +import { ACCOUNT_MEMBER_TOKEN_COOKIE_NAME } from "src/lib/cookie-constants"; +import { Button } from "src/components/button/Button"; import Link from "next/link"; import { ArrowLeftIcon } from "@heroicons/react/24/outline"; import React from "react"; -import { Separator } from "../../../../../components/separator/Separator"; +import { Separator } from "src/components/separator/Separator"; import { AddForm } from "./AddForm"; export const dynamic = "force-dynamic"; diff --git a/examples/core/src/app/(store)/account/addresses/page.tsx b/examples/core/src/app/[lang]/(store)/account/addresses/page.tsx similarity index 87% rename from examples/core/src/app/(store)/account/addresses/page.tsx rename to examples/core/src/app/[lang]/(store)/account/addresses/page.tsx index 30939238..4ca5ea5b 100644 --- a/examples/core/src/app/(store)/account/addresses/page.tsx +++ b/examples/core/src/app/[lang]/(store)/account/addresses/page.tsx @@ -1,19 +1,19 @@ import { PencilSquareIcon, PlusIcon } from "@heroicons/react/24/outline"; import { cookies } from "next/headers"; -import { ACCOUNT_MEMBER_TOKEN_COOKIE_NAME } from "../../../../lib/cookie-constants"; +import { ACCOUNT_MEMBER_TOKEN_COOKIE_NAME } from "src/lib/cookie-constants"; import { redirect } from "next/navigation"; import { getSelectedAccount, retrieveAccountMemberCredentials, -} from "../../../../lib/retrieve-account-member-credentials"; +} from "src/lib/retrieve-account-member-credentials"; import Link from "next/link"; -import { Button } from "../../../../components/button/Button"; -import { Separator } from "../../../../components/separator/Separator"; +import { Button } from "src/components/button/Button"; +import { Separator } from "src/components/separator/Separator"; import React from "react"; import { DeleteAddressBtn } from "./DeleteAddressBtn"; -import { createElasticPathClient } from "../../../../lib/create-elastic-path-client"; +import { createElasticPathClient } from "src/lib/create-elastic-path-client"; import { getV2AccountAddresses } from "@epcc-sdk/sdks-shopper"; -import { TAGS } from "../../../../lib/constants"; +import { TAGS } from "src/lib/constants"; export const dynamic = "force-dynamic"; diff --git a/examples/core/src/app/(store)/account/layout.tsx b/examples/core/src/app/[lang]/(store)/account/layout.tsx similarity index 100% rename from examples/core/src/app/(store)/account/layout.tsx rename to examples/core/src/app/[lang]/(store)/account/layout.tsx diff --git a/examples/core/src/app/(store)/account/orders/OrderItem.tsx b/examples/core/src/app/[lang]/(store)/account/orders/OrderItem.tsx similarity index 96% rename from examples/core/src/app/(store)/account/orders/OrderItem.tsx rename to examples/core/src/app/[lang]/(store)/account/orders/OrderItem.tsx index 0324a301..ceae9e61 100644 --- a/examples/core/src/app/(store)/account/orders/OrderItem.tsx +++ b/examples/core/src/app/[lang]/(store)/account/orders/OrderItem.tsx @@ -1,7 +1,7 @@ import { ReactNode } from "react"; import { ProductThumbnail } from "./[orderId]/ProductThumbnail"; import Link from "next/link"; -import { formatIsoDateString } from "../../../../lib/format-iso-date-string"; +import { formatIsoDateString } from "src/lib/format-iso-date-string"; import { OrderItemResponse, OrderResponse } from "@epcc-sdk/sdks-shopper"; export type OrderItemProps = { diff --git a/examples/core/src/app/(store)/account/orders/OrderItemWithDetails.tsx b/examples/core/src/app/[lang]/(store)/account/orders/OrderItemWithDetails.tsx similarity index 92% rename from examples/core/src/app/(store)/account/orders/OrderItemWithDetails.tsx rename to examples/core/src/app/[lang]/(store)/account/orders/OrderItemWithDetails.tsx index 03bffaa0..a65ba3a7 100644 --- a/examples/core/src/app/(store)/account/orders/OrderItemWithDetails.tsx +++ b/examples/core/src/app/[lang]/(store)/account/orders/OrderItemWithDetails.tsx @@ -1,5 +1,5 @@ import { OrderItem, OrderItemProps, sortOrderItems } from "./OrderItem"; -import { formatIsoDateString } from "../../../../lib/format-iso-date-string"; +import { formatIsoDateString } from "src/lib/format-iso-date-string"; export function OrderItemWithDetails(props: Omit) { const sortedOrderItems = sortOrderItems(props.orderItems); diff --git a/examples/core/src/app/(store)/account/orders/[orderId]/OrderLineItem.tsx b/examples/core/src/app/[lang]/(store)/account/orders/[orderId]/OrderLineItem.tsx similarity index 100% rename from examples/core/src/app/(store)/account/orders/[orderId]/OrderLineItem.tsx rename to examples/core/src/app/[lang]/(store)/account/orders/[orderId]/OrderLineItem.tsx diff --git a/examples/core/src/app/(store)/account/orders/[orderId]/ProductThumbnail.tsx b/examples/core/src/app/[lang]/(store)/account/orders/[orderId]/ProductThumbnail.tsx similarity index 100% rename from examples/core/src/app/(store)/account/orders/[orderId]/ProductThumbnail.tsx rename to examples/core/src/app/[lang]/(store)/account/orders/[orderId]/ProductThumbnail.tsx diff --git a/examples/core/src/app/(store)/account/orders/[orderId]/page.tsx b/examples/core/src/app/[lang]/(store)/account/orders/[orderId]/page.tsx similarity index 91% rename from examples/core/src/app/(store)/account/orders/[orderId]/page.tsx rename to examples/core/src/app/[lang]/(store)/account/orders/[orderId]/page.tsx index 45c702bf..dd185f2f 100644 --- a/examples/core/src/app/(store)/account/orders/[orderId]/page.tsx +++ b/examples/core/src/app/[lang]/(store)/account/orders/[orderId]/page.tsx @@ -1,17 +1,17 @@ import { cookies } from "next/headers"; -import { ACCOUNT_MEMBER_TOKEN_COOKIE_NAME } from "../../../../../lib/cookie-constants"; +import { ACCOUNT_MEMBER_TOKEN_COOKIE_NAME } from "src/lib/cookie-constants"; import { notFound, redirect } from "next/navigation"; -import { retrieveAccountMemberCredentials } from "../../../../../lib/retrieve-account-member-credentials"; -import { Button } from "../../../../../components/button/Button"; +import { retrieveAccountMemberCredentials } from "src/lib/retrieve-account-member-credentials"; +import { Button } from "src/components/button/Button"; import { ArrowLeftIcon } from "@heroicons/react/24/outline"; import Link from "next/link"; -import { formatIsoDateString } from "../../../../../lib/format-iso-date-string"; +import { formatIsoDateString } from "src/lib/format-iso-date-string"; import { OrderLineItem } from "./OrderLineItem"; -import { createElasticPathClient } from "../../../../../lib/create-elastic-path-client"; +import { createElasticPathClient } from "src/lib/create-elastic-path-client"; import { getAnOrder, getByContextAllProducts } from "@epcc-sdk/sdks-shopper"; import { resolveShopperOrder } from "../resolve-shopper-order"; -import { extractCartItemProductIds } from "../../../../../lib/extract-cart-item-product-ids"; -import { TAGS } from "../../../../../lib/constants"; +import { extractCartItemProductIds } from "src/lib/extract-cart-item-product-ids"; +import { TAGS } from "src/lib/constants"; import { extractCartItemMedia } from "../../../../(checkout)/checkout/extract-cart-item-media"; export const dynamic = "force-dynamic"; diff --git a/examples/core/src/app/(store)/account/orders/page.tsx b/examples/core/src/app/[lang]/(store)/account/orders/page.tsx similarity index 84% rename from examples/core/src/app/(store)/account/orders/page.tsx rename to examples/core/src/app/[lang]/(store)/account/orders/page.tsx index 9551631d..c1e8808c 100644 --- a/examples/core/src/app/(store)/account/orders/page.tsx +++ b/examples/core/src/app/[lang]/(store)/account/orders/page.tsx @@ -1,16 +1,16 @@ import { cookies } from "next/headers"; -import { ACCOUNT_MEMBER_TOKEN_COOKIE_NAME } from "../../../../lib/cookie-constants"; +import { ACCOUNT_MEMBER_TOKEN_COOKIE_NAME } from "src/lib/cookie-constants"; import { notFound, redirect } from "next/navigation"; -import { retrieveAccountMemberCredentials } from "../../../../lib/retrieve-account-member-credentials"; -import { ResourcePagination } from "../../../../components/pagination/ResourcePagination"; -import { DEFAULT_PAGINATION_LIMIT, TAGS } from "../../../../lib/constants"; +import { retrieveAccountMemberCredentials } from "src/lib/retrieve-account-member-credentials"; +import { ResourcePagination } from "src/components/pagination/ResourcePagination"; +import { DEFAULT_PAGINATION_LIMIT, TAGS } from "src/lib/constants"; import { OrderItemWithDetails } from "./OrderItemWithDetails"; -import { createElasticPathClient } from "../../../../lib/create-elastic-path-client"; +import { createElasticPathClient } from "src/lib/create-elastic-path-client"; import { getByContextAllProducts, getCustomerOrders, } from "@epcc-sdk/sdks-shopper"; -import { extractCartItemProductIds } from "../../../../lib/extract-cart-item-product-ids"; +import { extractCartItemProductIds } from "src/lib/extract-cart-item-product-ids"; import { extractCartItemMedia } from "../../../(checkout)/checkout/extract-cart-item-media"; import { resolveShopperOrder } from "./resolve-shopper-order"; diff --git a/examples/core/src/app/(store)/account/orders/resolve-shopper-order.ts b/examples/core/src/app/[lang]/(store)/account/orders/resolve-shopper-order.ts similarity index 100% rename from examples/core/src/app/(store)/account/orders/resolve-shopper-order.ts rename to examples/core/src/app/[lang]/(store)/account/orders/resolve-shopper-order.ts diff --git a/examples/core/src/app/(store)/account/summary/YourInfoForm.tsx b/examples/core/src/app/[lang]/(store)/account/summary/YourInfoForm.tsx similarity index 88% rename from examples/core/src/app/(store)/account/summary/YourInfoForm.tsx rename to examples/core/src/app/[lang]/(store)/account/summary/YourInfoForm.tsx index 9fb96377..4edab55e 100644 --- a/examples/core/src/app/(store)/account/summary/YourInfoForm.tsx +++ b/examples/core/src/app/[lang]/(store)/account/summary/YourInfoForm.tsx @@ -1,9 +1,9 @@ "use client"; import { updateAccount } from "./actions"; -import { Label } from "../../../../components/label/Label"; -import { Input } from "../../../../components/input/Input"; -import { FormStatusButton } from "../../../../components/button/FormStatusButton"; +import { Label } from "src/components/label/Label"; +import { Input } from "src/components/input/Input"; +import { FormStatusButton } from "src/components/button/FormStatusButton"; import { useState } from "react"; export function YourInfoForm({ diff --git a/examples/core/src/app/(store)/account/summary/actions.ts b/examples/core/src/app/[lang]/(store)/account/summary/actions.ts similarity index 81% rename from examples/core/src/app/(store)/account/summary/actions.ts rename to examples/core/src/app/[lang]/(store)/account/summary/actions.ts index 42da80d0..5668e18f 100644 --- a/examples/core/src/app/(store)/account/summary/actions.ts +++ b/examples/core/src/app/[lang]/(store)/account/summary/actions.ts @@ -2,11 +2,11 @@ import { z } from "zod"; import { cookies } from "next/headers"; -import { retrieveAccountMemberCredentials } from "../../../../lib/retrieve-account-member-credentials"; -import { ACCOUNT_MEMBER_TOKEN_COOKIE_NAME } from "../../../../lib/cookie-constants"; +import { retrieveAccountMemberCredentials } from "src/lib/retrieve-account-member-credentials"; +import { ACCOUNT_MEMBER_TOKEN_COOKIE_NAME } from "src/lib/cookie-constants"; import { revalidatePath, revalidateTag } from "next/cache"; -import { getErrorMessage } from "../../../../lib/get-error-message"; -import { createElasticPathClient } from "../../../../lib/create-elastic-path-client"; +import { getErrorMessage } from "src/lib/get-error-message"; +import { createElasticPathClient } from "src/lib/create-elastic-path-client"; import { putV2AccountsAccountId, postV2AccountMembersTokens, diff --git a/examples/core/src/app/(store)/account/summary/page.tsx b/examples/core/src/app/[lang]/(store)/account/summary/page.tsx similarity index 85% rename from examples/core/src/app/(store)/account/summary/page.tsx rename to examples/core/src/app/[lang]/(store)/account/summary/page.tsx index c4ea6249..1e7abf72 100644 --- a/examples/core/src/app/(store)/account/summary/page.tsx +++ b/examples/core/src/app/[lang]/(store)/account/summary/page.tsx @@ -1,20 +1,20 @@ import { cookies } from "next/headers"; -import { ACCOUNT_MEMBER_TOKEN_COOKIE_NAME } from "../../../../lib/cookie-constants"; +import { ACCOUNT_MEMBER_TOKEN_COOKIE_NAME } from "src/lib/cookie-constants"; import { redirect } from "next/navigation"; import { getSelectedAccount, retrieveAccountMemberCredentials, -} from "../../../../lib/retrieve-account-member-credentials"; -import { Label } from "../../../../components/label/Label"; -import { Input } from "../../../../components/input/Input"; -import { FormStatusButton } from "../../../../components/button/FormStatusButton"; +} from "src/lib/retrieve-account-member-credentials"; +import { Label } from "src/components/label/Label"; +import { Input } from "src/components/input/Input"; +import { FormStatusButton } from "src/components/button/FormStatusButton"; import { YourInfoForm } from "./YourInfoForm"; -import { createElasticPathClient } from "../../../../lib/create-elastic-path-client"; +import { createElasticPathClient } from "src/lib/create-elastic-path-client"; import { getV2AccountsAccountId, getV2AccountMembersAccountMemberId, } from "@epcc-sdk/sdks-shopper"; -import { TAGS } from "../../../../lib/constants"; +import { TAGS } from "src/lib/constants"; export const dynamic = "force-dynamic"; diff --git a/examples/core/src/app/(store)/cart/CartItem.tsx b/examples/core/src/app/[lang]/(store)/cart/CartItem.tsx similarity index 97% rename from examples/core/src/app/(store)/cart/CartItem.tsx rename to examples/core/src/app/[lang]/(store)/cart/CartItem.tsx index 09be731d..1d4a06af 100644 --- a/examples/core/src/app/(store)/cart/CartItem.tsx +++ b/examples/core/src/app/[lang]/(store)/cart/CartItem.tsx @@ -1,8 +1,8 @@ import { ProductThumbnail } from "../account/orders/[orderId]/ProductThumbnail"; -import { NumberInput } from "../../../components/number-input/NumberInput"; +import { NumberInput } from "src/components/number-input/NumberInput"; import Link from "next/link"; -import { RemoveCartItemButton } from "../../../components/cart/RemoveCartItemButton"; -import { Item } from "../../../lib/group-cart-items"; +import { RemoveCartItemButton } from "src/components/cart/RemoveCartItemButton"; +import { Item } from "src/lib/group-cart-items"; import { ResponseCurrency } from "@epcc-sdk/sdks-shopper"; import { calculateMultiItemOriginalTotal, calculateSaleAmount, calculateTotalSavings, getFormattedPercentage, getFormattedValue } from "src/lib/price-calculation"; diff --git a/examples/core/src/app/(store)/cart/CartItemWide.tsx b/examples/core/src/app/[lang]/(store)/cart/CartItemWide.tsx similarity index 92% rename from examples/core/src/app/(store)/cart/CartItemWide.tsx rename to examples/core/src/app/[lang]/(store)/cart/CartItemWide.tsx index b2b35e17..9a96b795 100644 --- a/examples/core/src/app/(store)/cart/CartItemWide.tsx +++ b/examples/core/src/app/[lang]/(store)/cart/CartItemWide.tsx @@ -1,8 +1,8 @@ import { ProductThumbnail } from "../account/orders/[orderId]/ProductThumbnail"; import Link from "next/link"; -import { NumberInput } from "../../../components/number-input/NumberInput"; +import { NumberInput } from "src/components/number-input/NumberInput"; import { CartItemProps } from "./CartItem"; -import { RemoveCartItemButton } from "../../../components/cart/RemoveCartItemButton"; +import { RemoveCartItemButton } from "src/components/cart/RemoveCartItemButton"; export function CartItemWide({ item, thumbnail }: CartItemProps) { return ( diff --git a/examples/core/src/app/(store)/cart/CartSidebar.tsx b/examples/core/src/app/[lang]/(store)/cart/CartSidebar.tsx similarity index 81% rename from examples/core/src/app/(store)/cart/CartSidebar.tsx rename to examples/core/src/app/[lang]/(store)/cart/CartSidebar.tsx index ec435739..e7190437 100644 --- a/examples/core/src/app/(store)/cart/CartSidebar.tsx +++ b/examples/core/src/app/[lang]/(store)/cart/CartSidebar.tsx @@ -1,5 +1,5 @@ -import { Separator } from "../../../components/separator/Separator"; -import { CartDiscounts } from "../../../components/cart/CartDiscounts"; +import { Separator } from "src/components/separator/Separator"; +import { CartDiscounts } from "src/components/cart/CartDiscounts"; import * as React from "react"; import { ItemSidebarPromotions, @@ -8,9 +8,9 @@ import { ItemSidebarTotalsDiscount, ItemSidebarTotalsSubTotal, ItemSidebarTotalsTax, -} from "../../../components/checkout-sidebar/ItemSidebar"; +} from "src/components/checkout-sidebar/ItemSidebar"; import { CartEntityResponse } from "@epcc-sdk/sdks-shopper"; -import { groupCartItems } from "../../../lib/group-cart-items"; +import { groupCartItems } from "src/lib/group-cart-items"; export function CartSidebar({ cart }: { cart: CartEntityResponse }) { const meta = cart.data?.meta!; diff --git a/examples/core/src/app/(store)/cart/YourBag.tsx b/examples/core/src/app/[lang]/(store)/cart/YourBag.tsx similarity index 92% rename from examples/core/src/app/(store)/cart/YourBag.tsx rename to examples/core/src/app/[lang]/(store)/cart/YourBag.tsx index d2fa5af6..0c428106 100644 --- a/examples/core/src/app/(store)/cart/YourBag.tsx +++ b/examples/core/src/app/[lang]/(store)/cart/YourBag.tsx @@ -1,6 +1,6 @@ import { CartItemWide } from "./CartItemWide"; import { CartIncluded } from "@epcc-sdk/sdks-shopper"; -import { groupCartItems } from "../../../lib/group-cart-items"; +import { groupCartItems } from "src/lib/group-cart-items"; export function YourBag({ cart, diff --git a/examples/core/src/app/(store)/cart/page.tsx b/examples/core/src/app/[lang]/(store)/cart/page.tsx similarity index 90% rename from examples/core/src/app/(store)/cart/page.tsx rename to examples/core/src/app/[lang]/(store)/cart/page.tsx index 1c320c43..11bd6611 100644 --- a/examples/core/src/app/(store)/cart/page.tsx +++ b/examples/core/src/app/[lang]/(store)/cart/page.tsx @@ -1,13 +1,13 @@ import { YourBag } from "./YourBag"; import { CartSidebar } from "./CartSidebar"; -import { Button } from "../../../components/button/Button"; +import { Button } from "src/components/button/Button"; import Link from "next/link"; import { LockClosedIcon } from "@heroicons/react/24/solid"; import { getACart } from "@epcc-sdk/sdks-shopper"; -import { CART_COOKIE_NAME } from "../../../lib/cookie-constants"; +import { CART_COOKIE_NAME } from "src/lib/cookie-constants"; import { cookies } from "next/headers"; -import { createElasticPathClient } from "../../../lib/create-elastic-path-client"; -import { TAGS } from "../../../lib/constants"; +import { createElasticPathClient } from "src/lib/create-elastic-path-client"; +import { TAGS } from "src/lib/constants"; export default async function CartPage() { const cartCookie = (await cookies()).get(CART_COOKIE_NAME); diff --git a/examples/core/src/app/(store)/faq/page.tsx b/examples/core/src/app/[lang]/(store)/faq/page.tsx similarity index 55% rename from examples/core/src/app/(store)/faq/page.tsx rename to examples/core/src/app/[lang]/(store)/faq/page.tsx index 786734bc..4151724f 100644 --- a/examples/core/src/app/(store)/faq/page.tsx +++ b/examples/core/src/app/[lang]/(store)/faq/page.tsx @@ -1,4 +1,4 @@ -import Blurb from "../../../components/shared/blurb"; +import Blurb from "src/components/shared/blurb"; export default function FAQ() { return ; diff --git a/examples/core/src/app/(store)/layout.tsx b/examples/core/src/app/[lang]/(store)/layout.tsx similarity index 78% rename from examples/core/src/app/(store)/layout.tsx rename to examples/core/src/app/[lang]/(store)/layout.tsx index 97f1d40e..9586b9e3 100644 --- a/examples/core/src/app/(store)/layout.tsx +++ b/examples/core/src/app/[lang]/(store)/layout.tsx @@ -1,11 +1,11 @@ import { ReactNode, Suspense } from "react"; import localFont from "next/font/local"; -import { getStoreInitialState } from "../../lib/get-store-initial-state"; +import { getStoreInitialState } from "src/lib/get-store-initial-state"; import { Providers } from "../providers"; -import Header from "../../components/header/Header"; -import { Toaster } from "../../components/toast/toaster"; -import Footer from "../../components/footer/Footer"; -import { createElasticPathClient } from "../../lib/create-elastic-path-client"; +import Header from "src/components/header/Header"; +import { Toaster } from "src/components/toast/toaster"; +import Footer from "src/components/footer/Footer"; +import { createElasticPathClient } from "src/lib/create-elastic-path-client"; const { SITE_NAME } = process.env; const baseUrl = process.env.NEXT_PUBLIC_VERCEL_URL @@ -31,7 +31,7 @@ export const metadata = { export const revalidate = 300; const inter = localFont({ - src: "../../../public/fonts/Inter-VariableFont_opsz,wght.ttf", + src: "../../../../public/fonts/Inter-VariableFont_opsz,wght.ttf", display: "swap", variable: "--font-inter", }); diff --git a/examples/core/src/app/(store)/not-found.tsx b/examples/core/src/app/[lang]/(store)/not-found.tsx similarity index 100% rename from examples/core/src/app/(store)/not-found.tsx rename to examples/core/src/app/[lang]/(store)/not-found.tsx diff --git a/examples/core/src/app/(store)/page.tsx b/examples/core/src/app/[lang]/(store)/page.tsx similarity index 84% rename from examples/core/src/app/(store)/page.tsx rename to examples/core/src/app/[lang]/(store)/page.tsx index 6f87cd28..074b4c9f 100644 --- a/examples/core/src/app/(store)/page.tsx +++ b/examples/core/src/app/[lang]/(store)/page.tsx @@ -1,5 +1,5 @@ -import PromotionBanner from "../../components/promotion-banner/PromotionBanner"; -import FeaturedProducts from "../../components/featured-products/FeaturedProducts"; +import PromotionBanner from "src/components/promotion-banner/PromotionBanner"; +import FeaturedProducts from "src/components/featured-products/FeaturedProducts"; import { Suspense } from "react"; export default async function Home() { diff --git a/examples/core/src/app/(store)/products/[productId]/actions/cart-actions.ts b/examples/core/src/app/[lang]/(store)/products/[productId]/actions/cart-actions.ts similarity index 89% rename from examples/core/src/app/(store)/products/[productId]/actions/cart-actions.ts rename to examples/core/src/app/[lang]/(store)/products/[productId]/actions/cart-actions.ts index ad0ac9b8..46e53c0d 100644 --- a/examples/core/src/app/(store)/products/[productId]/actions/cart-actions.ts +++ b/examples/core/src/app/[lang]/(store)/products/[productId]/actions/cart-actions.ts @@ -2,8 +2,8 @@ import { cookies } from "next/headers"; import { z } from "zod"; -import { CART_COOKIE_NAME } from "../../../../../lib/cookie-constants"; -import { simpleProductSchema } from "../../../../../components/product/standard/SimpleProductForm"; +import { CART_COOKIE_NAME } from "src/lib/cookie-constants"; +import { simpleProductSchema } from "src/components/product/standard/SimpleProductForm"; import { manageCarts, deleteACartItem, @@ -11,9 +11,9 @@ import { deleteAPromotionViaPromotionCode, } from "@epcc-sdk/sdks-shopper"; import { revalidateTag } from "next/cache"; -import { createElasticPathClient } from "../../../../../lib/create-elastic-path-client"; -import { createBundleFormSchema } from "../../../../../components/product/bundles/validation-schema"; -import { formSelectedOptionsToData } from "../../../../../components/product/bundles/form-parsers"; +import { createElasticPathClient } from "src/lib/create-elastic-path-client"; +import { createBundleFormSchema } from "src/components/product/bundles/validation-schema"; +import { formSelectedOptionsToData } from "src/components/product/bundles/form-parsers"; /** * addToCartAction - Server Action that adds an item to the cart @@ -39,7 +39,7 @@ export async function addToCartAction( quantity: data.quantity, ...(data.location && { location: data.location }), }, - }, + } }); await revalidateTag("cart"); diff --git a/examples/core/src/app/(store)/products/[productId]/page.tsx b/examples/core/src/app/[lang]/(store)/products/[productId]/page.tsx similarity index 81% rename from examples/core/src/app/(store)/products/[productId]/page.tsx rename to examples/core/src/app/[lang]/(store)/products/[productId]/page.tsx index 0c7b4cd7..045f91f6 100644 --- a/examples/core/src/app/(store)/products/[productId]/page.tsx +++ b/examples/core/src/app/[lang]/(store)/products/[productId]/page.tsx @@ -7,19 +7,21 @@ import { getAllFiles, ElasticPathFile, listLocations, + getAllCurrencies, } from "@epcc-sdk/sdks-shopper"; -import { createElasticPathClient } from "../../../../lib/create-elastic-path-client"; -import { SimpleProductContent } from "../../../../components/product/standard/SimpleProductContent"; -import { SimpleProductProvider } from "../../../../components/product/standard/SimpleProductProvider"; -import { VariationProductProvider } from "../../../../components/product/variations/VariationProductProvider"; -import { VariationProductContent } from "../../../../components/product/variations/VariationProductContent"; -import { BundleProductProvider } from "../../../../components/product/bundles/BundleProductProvider"; -import { BundleProductContent } from "../../../../components/product/bundles/BundleProductContent"; +import { createElasticPathClient } from "src/lib/create-elastic-path-client"; +import { SimpleProductContent } from "src/components/product/standard/SimpleProductContent"; +import { SimpleProductProvider } from "src/components/product/standard/SimpleProductProvider"; +import { VariationProductProvider } from "src/components/product/variations/VariationProductProvider"; +import { VariationProductContent } from "src/components/product/variations/VariationProductContent"; +import { BundleProductProvider } from "src/components/product/bundles/BundleProductProvider"; +import { BundleProductContent } from "src/components/product/bundles/BundleProductContent"; +import { getCurrency } from "src/lib/get-locale-currency"; export const dynamic = "force-dynamic"; type Props = { - params: Promise<{ productId: string }>; + params: Promise<{ productId: string; lang?: string; }>; }; export async function generateMetadata(props: Props): Promise { @@ -35,7 +37,7 @@ export async function generateMetadata(props: Props): Promise { }, query: { include: ["main_image", "files", "component_products"], - }, + } }); if (!product.data?.data) { @@ -51,6 +53,7 @@ export async function generateMetadata(props: Props): Promise { export default async function ProductPage(props: Props) { const params = await props.params; const client = createElasticPathClient(); + const currency = await getCurrency(params.lang) const productPromise = getByContextProduct({ client, path: { @@ -59,7 +62,12 @@ export default async function ProductPage(props: Props) { query: { include: ["main_image", "files", "component_products"], }, + headers: { + "Accept-Language": params.lang, + "X-Moltin-Currency": currency?.code + } }); + const inventoryPromise = getStock({ client, path: { diff --git a/examples/core/src/app/(store)/search/[[...node]]/layout.tsx b/examples/core/src/app/[lang]/(store)/search/[[...node]]/layout.tsx similarity index 79% rename from examples/core/src/app/(store)/search/[[...node]]/layout.tsx rename to examples/core/src/app/[lang]/(store)/search/[[...node]]/layout.tsx index 937b6e50..d213c077 100644 --- a/examples/core/src/app/(store)/search/[[...node]]/layout.tsx +++ b/examples/core/src/app/[lang]/(store)/search/[[...node]]/layout.tsx @@ -1,5 +1,5 @@ import { ReactNode } from "react"; -import Breadcrumb from "../../../../components/breadcrumb"; +import Breadcrumb from "src/components/breadcrumb"; export default function SearchLayout({ children }: { children: ReactNode }) { return ( diff --git a/examples/core/src/app/(store)/search/[[...node]]/page.tsx b/examples/core/src/app/[lang]/(store)/search/[[...node]]/page.tsx similarity index 98% rename from examples/core/src/app/(store)/search/[[...node]]/page.tsx rename to examples/core/src/app/[lang]/(store)/search/[[...node]]/page.tsx index b4d6f5aa..676afcc8 100644 --- a/examples/core/src/app/(store)/search/[[...node]]/page.tsx +++ b/examples/core/src/app/[lang]/(store)/search/[[...node]]/page.tsx @@ -1,7 +1,7 @@ import { Search } from "../search"; import { Metadata } from "next"; import { notFound } from "next/navigation"; -import { createElasticPathClient } from "../../../../lib/create-elastic-path-client"; +import { createElasticPathClient } from "src/lib/create-elastic-path-client"; import { Client, getByContextAllHierarchies, diff --git a/examples/core/src/app/(store)/search/search.tsx b/examples/core/src/app/[lang]/(store)/search/search.tsx similarity index 83% rename from examples/core/src/app/(store)/search/search.tsx rename to examples/core/src/app/[lang]/(store)/search/search.tsx index f88f2ab8..9254dea8 100644 --- a/examples/core/src/app/(store)/search/search.tsx +++ b/examples/core/src/app/[lang]/(store)/search/search.tsx @@ -1,5 +1,5 @@ "use client"; -import SearchResults from "../../../components/search/SearchResults"; +import SearchResults from "src/components/search/SearchResults"; import React from "react"; import { usePathname } from "next/navigation"; import { ProductListData } from "@epcc-sdk/sdks-shopper"; diff --git a/examples/core/src/app/(store)/shipping/page.tsx b/examples/core/src/app/[lang]/(store)/shipping/page.tsx similarity index 58% rename from examples/core/src/app/(store)/shipping/page.tsx rename to examples/core/src/app/[lang]/(store)/shipping/page.tsx index d5ee20b4..43cbfb5f 100644 --- a/examples/core/src/app/(store)/shipping/page.tsx +++ b/examples/core/src/app/[lang]/(store)/shipping/page.tsx @@ -1,4 +1,4 @@ -import Blurb from "../../../components/shared/blurb"; +import Blurb from "src/components/shared/blurb"; export default function Shipping() { return ; diff --git a/examples/core/src/app/(store)/support/page.tsx b/examples/core/src/app/[lang]/(store)/support/page.tsx similarity index 58% rename from examples/core/src/app/(store)/support/page.tsx rename to examples/core/src/app/[lang]/(store)/support/page.tsx index 13430886..3db9642e 100644 --- a/examples/core/src/app/(store)/support/page.tsx +++ b/examples/core/src/app/[lang]/(store)/support/page.tsx @@ -1,4 +1,4 @@ -import Blurb from "../../../components/shared/blurb"; +import Blurb from "src/components/shared/blurb"; export default function Support() { return ; diff --git a/examples/core/src/app/(store)/terms/page.tsx b/examples/core/src/app/[lang]/(store)/terms/page.tsx similarity index 60% rename from examples/core/src/app/(store)/terms/page.tsx rename to examples/core/src/app/[lang]/(store)/terms/page.tsx index 3b651abc..655a926a 100644 --- a/examples/core/src/app/(store)/terms/page.tsx +++ b/examples/core/src/app/[lang]/(store)/terms/page.tsx @@ -1,4 +1,4 @@ -import Blurb from "../../../components/shared/blurb"; +import Blurb from "src/components/shared/blurb"; export default function Terms() { return ; diff --git a/examples/core/src/app/configuration-error/page.tsx b/examples/core/src/app/[lang]/configuration-error/page.tsx similarity index 100% rename from examples/core/src/app/configuration-error/page.tsx rename to examples/core/src/app/[lang]/configuration-error/page.tsx diff --git a/examples/core/src/app/error.tsx b/examples/core/src/app/[lang]/error.tsx similarity index 100% rename from examples/core/src/app/error.tsx rename to examples/core/src/app/[lang]/error.tsx diff --git a/examples/core/src/app/layout.tsx b/examples/core/src/app/[lang]/layout.tsx similarity index 81% rename from examples/core/src/app/layout.tsx rename to examples/core/src/app/[lang]/layout.tsx index d87bb7de..25455632 100644 --- a/examples/core/src/app/layout.tsx +++ b/examples/core/src/app/[lang]/layout.tsx @@ -1,5 +1,5 @@ import { ReactNode } from "react"; -import "../styles/globals.css"; +import "../../styles/globals.css"; export default async function RootLayout({ children, diff --git a/examples/core/src/app/not-found.tsx b/examples/core/src/app/[lang]/not-found.tsx similarity index 100% rename from examples/core/src/app/not-found.tsx rename to examples/core/src/app/[lang]/not-found.tsx diff --git a/examples/core/src/app/providers.tsx b/examples/core/src/app/[lang]/providers.tsx similarity index 82% rename from examples/core/src/app/providers.tsx rename to examples/core/src/app/[lang]/providers.tsx index 9b49394d..f06b6324 100644 --- a/examples/core/src/app/providers.tsx +++ b/examples/core/src/app/[lang]/providers.tsx @@ -1,11 +1,11 @@ "use client"; import { ReactNode, useMemo } from "react"; import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; -import { Events } from "../lib/event-context"; +import { Events } from "src/lib/event-context"; import { StoreProvider } from "./(store)/StoreProvider"; -import { InitialState } from "../lib/get-store-initial-state"; +import { InitialState } from "src/lib/get-store-initial-state"; import { ClientProvider } from "./(store)/ClientProvider"; -import { createElasticPathClient } from "../lib/create-elastic-path-client"; +import { createElasticPathClient } from "src/lib/create-elastic-path-client"; const queryClient = new QueryClient({ defaultOptions: { diff --git a/examples/core/src/components/breadcrumb.tsx b/examples/core/src/components/breadcrumb.tsx index 82898736..f98db2e5 100644 --- a/examples/core/src/components/breadcrumb.tsx +++ b/examples/core/src/components/breadcrumb.tsx @@ -1,5 +1,5 @@ "use client"; -import { useStore } from "../app/(store)/StoreProvider"; +import { useStore } from "../app/[lang]/(store)/StoreProvider"; import { createBreadcrumb } from "../lib/create-breadcrumb"; import Link from "next/link"; import { buildBreadcrumbLookup } from "../lib/build-breadcrumb-lookup"; diff --git a/examples/core/src/components/cart/CartSheet.tsx b/examples/core/src/components/cart/CartSheet.tsx index 719341bd..9efdeb04 100644 --- a/examples/core/src/components/cart/CartSheet.tsx +++ b/examples/core/src/components/cart/CartSheet.tsx @@ -10,7 +10,7 @@ import { } from "../sheet/Sheet"; import { Button } from "../button/Button"; import { LockClosedIcon, XMarkIcon } from "@heroicons/react/24/solid"; -import { CartItem } from "../../app/(store)/cart/CartItem"; +import { CartItem } from "../../app/[lang]/(store)/cart/CartItem"; import { Separator } from "../separator/Separator"; import { ShoppingBagIcon } from "@heroicons/react/24/outline"; import { Fragment } from "react"; diff --git a/examples/core/src/components/cart/RemoveCartItemButton.tsx b/examples/core/src/components/cart/RemoveCartItemButton.tsx index 465ee396..18dd190d 100644 --- a/examples/core/src/components/cart/RemoveCartItemButton.tsx +++ b/examples/core/src/components/cart/RemoveCartItemButton.tsx @@ -2,7 +2,7 @@ import { useNotify } from "../../hooks/use-event"; import { useQueryClient } from "@tanstack/react-query"; import { useTransition } from "react"; -import { removeCartItemAction } from "../../app/(store)/products/[productId]/actions/cart-actions"; +import { removeCartItemAction } from "../../app/[lang]/(store)/products/[productId]/actions/cart-actions"; import { getCookie } from "cookies-next/client"; import { CART_COOKIE_NAME } from "../../lib/cookie-constants"; import { getACartQueryKey } from "@epcc-sdk/sdks-shopper/react-query"; diff --git a/examples/core/src/components/cart/RemoveCartItemXButton.tsx b/examples/core/src/components/cart/RemoveCartItemXButton.tsx index 9b43b13c..82a5bad3 100644 --- a/examples/core/src/components/cart/RemoveCartItemXButton.tsx +++ b/examples/core/src/components/cart/RemoveCartItemXButton.tsx @@ -2,7 +2,7 @@ import { useNotify } from "../../hooks/use-event"; import { useQueryClient } from "@tanstack/react-query"; import { useTransition } from "react"; -import { removeCartItemAction } from "../../app/(store)/products/[productId]/actions/cart-actions"; +import { removeCartItemAction } from "../../app/[lang]/(store)/products/[productId]/actions/cart-actions"; import { getCookie } from "cookies-next/client"; import { CART_COOKIE_NAME } from "../../lib/cookie-constants"; import { getACartQueryKey } from "@epcc-sdk/sdks-shopper/react-query"; diff --git a/examples/core/src/components/cart/RemoveCartPromotionXButton.tsx b/examples/core/src/components/cart/RemoveCartPromotionXButton.tsx index c2363441..1247305a 100644 --- a/examples/core/src/components/cart/RemoveCartPromotionXButton.tsx +++ b/examples/core/src/components/cart/RemoveCartPromotionXButton.tsx @@ -2,7 +2,7 @@ import { useNotify } from "../../hooks/use-event"; import { useQueryClient } from "@tanstack/react-query"; import { useTransition } from "react"; -import { removeCartPromotionAction } from "../../app/(store)/products/[productId]/actions/cart-actions"; +import { removeCartPromotionAction } from "../../app/[lang]/(store)/products/[productId]/actions/cart-actions"; import { getCookie } from "cookies-next/client"; import { CART_COOKIE_NAME } from "../../lib/cookie-constants"; import { getACartQueryKey } from "@epcc-sdk/sdks-shopper/react-query"; diff --git a/examples/core/src/components/checkout-item/CheckoutItem.tsx b/examples/core/src/components/checkout-item/CheckoutItem.tsx index c9e92341..2e9e4e53 100644 --- a/examples/core/src/components/checkout-item/CheckoutItem.tsx +++ b/examples/core/src/components/checkout-item/CheckoutItem.tsx @@ -1,5 +1,5 @@ "use client"; -import { ProductThumbnail } from "../../app/(store)/account/orders/[orderId]/ProductThumbnail"; +import { ProductThumbnail } from "../../app/[lang]/(store)/account/orders/[orderId]/ProductThumbnail"; import Link from "next/link"; import { Item } from "../../lib/group-cart-items"; import { formatCurrency } from "src/lib/format-currency"; diff --git a/examples/core/src/components/footer/Footer.tsx b/examples/core/src/components/footer/Footer.tsx index 2bfe4faa..0147bf42 100644 --- a/examples/core/src/components/footer/Footer.tsx +++ b/examples/core/src/components/footer/Footer.tsx @@ -1,77 +1,91 @@ +"use client"; import Link from "next/link"; import { PhoneIcon, InformationCircleIcon } from "@heroicons/react/24/solid"; import { GitHubIcon } from "../icons/github-icon"; import EpLogo from "../icons/ep-logo"; import type { JSX } from "react"; +import { useLocalePath } from "src/lib/get-locale-path"; -const Footer = (): JSX.Element => ( -
-
-
-
- -
-
- - Home - - - Shipping - - - FAQ - -
-
- - About - - - Terms - - - Support - -
-
-
- - {" "} - - - - {" "} - - - - - +const Footer = (): JSX.Element => { + const home = useLocalePath("/"); + const shipping = useLocalePath("/shipping"); + const faq = useLocalePath("/faq"); + const about = useLocalePath("/about"); + const terms = useLocalePath("/terms"); + const support = useLocalePath("/support"); + + console.log("home: ", home) + console.log("shipping: ", shipping) + + return ( +
+
+
+
+ +
+
+ + Home + + + Shipping + + + FAQ + +
+
+ + About + + + Terms + + + Support + +
+
+
+ + {" "} + + + + {" "} + + + + + +
-
-); + ); +}; export default Footer; diff --git a/examples/core/src/components/header/AccountMobileMenu.tsx b/examples/core/src/components/header/AccountMobileMenu.tsx index 54d2c710..5bffece6 100644 --- a/examples/core/src/components/header/AccountMobileMenu.tsx +++ b/examples/core/src/components/header/AccountMobileMenu.tsx @@ -9,7 +9,7 @@ import { UserCircleIcon, UserPlusIcon, } from "@heroicons/react/24/outline"; -import { logout } from "../../app/(auth)/actions"; +import { logout } from "../../app/[lang]/(auth)/actions"; import { SheetClose } from "../sheet/Sheet"; import { ButtonHTMLAttributes, forwardRef } from "react"; import { Slot } from "@radix-ui/react-slot"; diff --git a/examples/core/src/components/header/Header.tsx b/examples/core/src/components/header/Header.tsx index 841bcec4..fc24d1fc 100644 --- a/examples/core/src/components/header/Header.tsx +++ b/examples/core/src/components/header/Header.tsx @@ -6,6 +6,7 @@ import { Suspense } from "react"; import { AccountMenu } from "./account/AccountMenu"; import { Cart } from "./navigation/Cart"; import { Skeleton } from "../skeleton/Skeleton"; +import { LocaleSelector } from "./locale/LocaleSelector"; const Header = async () => { return ( @@ -25,6 +26,9 @@ const Header = async () => {
+
+ +
}> diff --git a/examples/core/src/components/header/account/AccountPopover.tsx b/examples/core/src/components/header/account/AccountPopover.tsx index e2661e7e..2712ab27 100644 --- a/examples/core/src/components/header/account/AccountPopover.tsx +++ b/examples/core/src/components/header/account/AccountPopover.tsx @@ -2,7 +2,7 @@ import { ReactNode, useState } from "react"; import { usePathname } from "next/navigation"; -import { logout } from "../../../app/(auth)/actions"; +import { logout } from "../../../app/[lang]/(auth)/actions"; import { ArrowLeftOnRectangleIcon, ArrowRightOnRectangleIcon, diff --git a/examples/core/src/components/header/account/AccountSwitcher.tsx b/examples/core/src/components/header/account/AccountSwitcher.tsx index 30f305c6..533df80a 100644 --- a/examples/core/src/components/header/account/AccountSwitcher.tsx +++ b/examples/core/src/components/header/account/AccountSwitcher.tsx @@ -1,6 +1,6 @@ "use server"; -import { selectedAccount } from "../../../app/(auth)/actions"; +import { selectedAccount } from "../../../app/[lang]/(auth)/actions"; import { CheckCircleIcon, UserCircleIcon } from "@heroicons/react/24/outline"; import { cookies } from "next/headers"; import { retrieveAccountMemberCredentials } from "../../../lib/retrieve-account-member-credentials"; diff --git a/examples/core/src/components/header/locale/LocaleSelector.tsx b/examples/core/src/components/header/locale/LocaleSelector.tsx new file mode 100644 index 00000000..a8850ead --- /dev/null +++ b/examples/core/src/components/header/locale/LocaleSelector.tsx @@ -0,0 +1,26 @@ +"use client"; +import { useRouter, usePathname } from "next/navigation"; +import { SUPPORTED_LOCALES } from "src/lib/i18n"; + +export const LocaleSelector = () => { + const router = useRouter(); + const pathname = usePathname(); + const currentLocale = pathname.split("/")[1]; + + const handleChange = (e: React.ChangeEvent) => { + const newLocale = e.target.value; + const segments = pathname.split("/"); + segments[1] = newLocale; + router.push(segments.join("/")); + }; + + return ( + + ); +}; \ No newline at end of file diff --git a/examples/core/src/components/header/navigation/MobileAccountSwitcher.tsx b/examples/core/src/components/header/navigation/MobileAccountSwitcher.tsx index 0624d143..b397a171 100644 --- a/examples/core/src/components/header/navigation/MobileAccountSwitcher.tsx +++ b/examples/core/src/components/header/navigation/MobileAccountSwitcher.tsx @@ -1,6 +1,6 @@ "use client"; -import { selectedAccount } from "../../../app/(auth)/actions"; +import { selectedAccount } from "../../../app/[lang]/(auth)/actions"; import { CheckCircleIcon, UserCircleIcon } from "@heroicons/react/24/outline"; import { SwitchButton } from "../account/switch-button"; import { Separator } from "../../separator/Separator"; diff --git a/examples/core/src/components/number-input/NumberInput.tsx b/examples/core/src/components/number-input/NumberInput.tsx index f3e43272..8a723148 100644 --- a/examples/core/src/components/number-input/NumberInput.tsx +++ b/examples/core/src/components/number-input/NumberInput.tsx @@ -11,7 +11,7 @@ import { FormItem, FormMessage, } from "../form/Form"; -import { updateCartItemAction } from "../../app/(store)/products/[productId]/actions/cart-actions"; +import { updateCartItemAction } from "../../app/[lang]/(store)/products/[productId]/actions/cart-actions"; import { getCookie } from "cookies-next/client"; import { CART_COOKIE_NAME } from "../../lib/cookie-constants"; import { getACartQueryKey } from "@epcc-sdk/sdks-shopper/react-query"; diff --git a/examples/core/src/components/product/bundles/BundleProductForm.tsx b/examples/core/src/components/product/bundles/BundleProductForm.tsx index db5f4144..43db7ff9 100644 --- a/examples/core/src/components/product/bundles/BundleProductForm.tsx +++ b/examples/core/src/components/product/bundles/BundleProductForm.tsx @@ -7,7 +7,7 @@ import { useForm } from "react-hook-form"; import { z } from "zod"; import { zodResolver } from "@hookform/resolvers/zod"; import { Form } from "../../form/Form"; -import { addToBundleAction } from "../../../app/(store)/products/[productId]/actions/cart-actions"; +import { addToBundleAction } from "../../../app/[lang]/(store)/products/[productId]/actions/cart-actions"; import { useQueryClient } from "@tanstack/react-query"; import { getCookie } from "cookies-next/client"; import { CART_COOKIE_NAME } from "../../../lib/cookie-constants"; diff --git a/examples/core/src/components/product/standard/SimpleProductForm.tsx b/examples/core/src/components/product/standard/SimpleProductForm.tsx index dbdb8ee0..6fa1957c 100644 --- a/examples/core/src/components/product/standard/SimpleProductForm.tsx +++ b/examples/core/src/components/product/standard/SimpleProductForm.tsx @@ -8,7 +8,7 @@ import { useForm } from "react-hook-form"; import { z } from "zod"; import { zodResolver } from "@hookform/resolvers/zod"; import { Form } from "../../form/Form"; -import { addToCartAction } from "../../../app/(store)/products/[productId]/actions/cart-actions"; +import { addToCartAction } from "../../../app/[lang]/(store)/products/[productId]/actions/cart-actions"; import { useQueryClient } from "@tanstack/react-query"; import { getCookie } from "cookies-next/client"; import { CART_COOKIE_NAME } from "../../../lib/cookie-constants"; diff --git a/examples/core/src/components/product/variations/VariationProductForm.tsx b/examples/core/src/components/product/variations/VariationProductForm.tsx index 2b245b79..707e48f9 100644 --- a/examples/core/src/components/product/variations/VariationProductForm.tsx +++ b/examples/core/src/components/product/variations/VariationProductForm.tsx @@ -7,7 +7,7 @@ import { useForm } from "react-hook-form"; import { z } from "zod"; import { zodResolver } from "@hookform/resolvers/zod"; import { Form } from "../../form/Form"; -import { addToCartAction } from "../../../app/(store)/products/[productId]/actions/cart-actions"; +import { addToCartAction } from "../../../app/[lang]/(store)/products/[productId]/actions/cart-actions"; import { useQueryClient } from "@tanstack/react-query"; import { getCookie } from "cookies-next/client"; import { CART_COOKIE_NAME } from "../../../lib/cookie-constants"; diff --git a/examples/core/src/components/search/MobileFilters.tsx b/examples/core/src/components/search/MobileFilters.tsx index 21b51a84..358a4e23 100644 --- a/examples/core/src/components/search/MobileFilters.tsx +++ b/examples/core/src/components/search/MobileFilters.tsx @@ -3,7 +3,7 @@ import { Dialog, Transition } from "@headlessui/react"; import { Dispatch, Fragment, SetStateAction, type JSX } from "react"; import { XMarkIcon } from "@heroicons/react/24/solid"; import NodeMenu from "./NodeMenu"; -import { useStore } from "../../app/(store)/StoreProvider"; +import { useStore } from "../../app/[lang]/(store)/StoreProvider"; interface IMobileFilters { lookup?: BreadcrumbLookup; diff --git a/examples/core/src/components/search/SearchResults.tsx b/examples/core/src/components/search/SearchResults.tsx index 7a20d3ab..9f5fe587 100644 --- a/examples/core/src/components/search/SearchResults.tsx +++ b/examples/core/src/components/search/SearchResults.tsx @@ -8,8 +8,8 @@ import { BreadcrumbLookup } from "../../lib/types/breadcrumb-lookup"; import { buildBreadcrumbLookup } from "../../lib/build-breadcrumb-lookup"; import MobileFilters from "./MobileFilters"; import { ProductListData } from "@epcc-sdk/sdks-shopper"; -import { useStore } from "../../app/(store)/StoreProvider"; -import { useElasticPathClient } from "../../app/(store)/ClientProvider"; +import { useStore } from "../../app/[lang]/(store)/StoreProvider"; +import { useElasticPathClient } from "../../app/[lang]/(store)/ClientProvider"; import { ResourcePagination } from "../pagination/ResourcePagination"; interface ISearchResults { diff --git a/examples/core/src/lib/create-cookie-from-generate-token-response.ts b/examples/core/src/lib/create-cookie-from-generate-token-response.ts index dfe455b7..c576d21b 100644 --- a/examples/core/src/lib/create-cookie-from-generate-token-response.ts +++ b/examples/core/src/lib/create-cookie-from-generate-token-response.ts @@ -7,7 +7,7 @@ import { import { AccountMemberCredential, AccountMemberCredentials, -} from "../app/(auth)/account-member-credentials-schema"; +} from "../app/[lang]/(auth)/account-member-credentials-schema"; export type AccountMemberAuthResponse = NonNullable< Awaited>["data"] diff --git a/examples/core/src/lib/get-locale-currency.ts b/examples/core/src/lib/get-locale-currency.ts new file mode 100644 index 00000000..69573d7f --- /dev/null +++ b/examples/core/src/lib/get-locale-currency.ts @@ -0,0 +1,29 @@ +import { getAllCurrencies } from "@epcc-sdk/sdks-shopper"; +import { createElasticPathClient } from "./create-elastic-path-client"; +import { TAGS } from "./constants"; +import { LOCALE_TO_CURRENCY } from "./i18n"; + +export async function getCurrency(lang?: string) { + const client = createElasticPathClient(); + + const currenciesResponse = await getAllCurrencies({ + client, + next: { + tags: [TAGS.currencies], + }, + }); + + const currencies = currenciesResponse.data?.data || []; + + if (!currencies.length) return undefined; + + const preferredCode = lang ? LOCALE_TO_CURRENCY[lang] : undefined; + + let currency = currencies.find((c) => c.code === preferredCode && c.enabled) + + if (!currency) { + currency = currencies.find((c) => c.default && c.enabled); + } + + return currency; +} \ No newline at end of file diff --git a/examples/core/src/lib/get-locale-path.ts b/examples/core/src/lib/get-locale-path.ts new file mode 100644 index 00000000..eb5c7de5 --- /dev/null +++ b/examples/core/src/lib/get-locale-path.ts @@ -0,0 +1,6 @@ +import { useParams } from "next/navigation"; + +export function useLocalePath(path: string) { + const { lang } = useParams(); + return lang ? `/${lang}${path}` : path; +} diff --git a/examples/core/src/lib/i18n.ts b/examples/core/src/lib/i18n.ts new file mode 100644 index 00000000..c69bfdde --- /dev/null +++ b/examples/core/src/lib/i18n.ts @@ -0,0 +1,8 @@ +export const SUPPORTED_LOCALES = ["en", "fr", "de", "es", "en-GB"]; + +export const LOCALE_TO_CURRENCY: Record = { + en: "USD", + fr: "EUR", + de: "EUR", + "en-GB": "GBP", +}; diff --git a/examples/core/src/lib/retrieve-account-member-credentials.ts b/examples/core/src/lib/retrieve-account-member-credentials.ts index 33fdee1c..39bbbaa0 100644 --- a/examples/core/src/lib/retrieve-account-member-credentials.ts +++ b/examples/core/src/lib/retrieve-account-member-credentials.ts @@ -3,7 +3,7 @@ import { AccountMemberCredential, AccountMemberCredentials, accountMemberCredentialsSchema, -} from "../app/(auth)/account-member-credentials-schema"; +} from "../app/[lang]/(auth)/account-member-credentials-schema"; export function getSelectedAccount( memberCredentials: AccountMemberCredentials, diff --git a/examples/core/src/middleware.ts b/examples/core/src/middleware.ts index a409e123..ec8a6fe0 100644 --- a/examples/core/src/middleware.ts +++ b/examples/core/src/middleware.ts @@ -1,16 +1,34 @@ -import { NextFetchEvent, NextRequest } from "next/server"; +import { NextFetchEvent, NextRequest, NextResponse } from "next/server"; import { implicitAuthMiddleware } from "./lib/middleware/implicit-auth-middleware"; import { cartCookieMiddleware } from "./lib/middleware/cart-cookie-middleware"; import { composeMiddleware } from "./lib/middleware/run-middleware"; +import { SUPPORTED_LOCALES } from "./lib/i18n"; export const config = { matcher: ["/", "/((?!_next|api|favicon|configuration-error).*)"], }; export async function middleware(req: NextRequest, event: NextFetchEvent) { + console.log("req: ", req) + const acceptLanguage = req.headers.get("accept-language"); + const firstLang = acceptLanguage?.split(",")[0] ?? ""; + const browserLocale = firstLang.split("-")[0] || "en"; + + const DEFAULT_LOCALE = browserLocale; + + const url = req.nextUrl.clone(); + const pathSegments = url.pathname.split("/").filter(Boolean); + + const locale = pathSegments[0] ?? ""; + + if (!SUPPORTED_LOCALES.includes(locale)) { + url.pathname = `/${DEFAULT_LOCALE}${url.pathname}`; + return NextResponse.redirect(url); + } + const runner = composeMiddleware([ implicitAuthMiddleware, cartCookieMiddleware, ]); return runner(req, event); -} +} \ No newline at end of file From 59cde6da45923deaa458bcc4d2ef6c55d1d99ded Mon Sep 17 00:00:00 2001 From: Muhammad Zain Tariq <49867382+mzaintariq@users.noreply.github.com> Date: Thu, 4 Dec 2025 13:21:19 +0500 Subject: [PATCH 02/14] Cart Currency Logic --- .../(checkout)/checkout/CheckoutSidebar.tsx | 10 ++++--- .../app/[lang]/(checkout)/checkout/page.tsx | 29 +++++++++++++----- .../src/app/[lang]/(store)/cart/CartItem.tsx | 2 +- .../core/src/app/[lang]/(store)/layout.tsx | 9 ++++-- .../[productId]/actions/cart-actions.ts | 14 ++++++++- .../(store)/products/[productId]/page.tsx | 15 ++++++++-- .../core/src/components/cart/CartSheet.tsx | 11 +++---- .../checkout-sidebar/AddPromotion.tsx | 6 ++-- .../checkout-sidebar/ItemSidebar.tsx | 4 +-- .../components/checkout-sidebar/actions.ts | 5 +++- .../core/src/components/header/Header.tsx | 4 +-- .../src/components/header/navigation/Cart.tsx | 30 +++++++++++++------ .../components/number-input/NumberInput.tsx | 7 +++-- .../product/bundles/BundleProductForm.tsx | 6 ++-- .../product/bundles/BundleProductProvider.tsx | 4 +++ .../product/standard/SimpleProductForm.tsx | 7 +++-- .../standard/SimpleProductProvider.tsx | 5 +++- .../variations/VariationProductForm.tsx | 6 ++-- .../variations/VariationProductProvider.tsx | 5 +++- examples/core/src/lib/get-locale-currency.ts | 27 ++++++----------- examples/core/src/middleware.ts | 1 - 21 files changed, 139 insertions(+), 68 deletions(-) diff --git a/examples/core/src/app/[lang]/(checkout)/checkout/CheckoutSidebar.tsx b/examples/core/src/app/[lang]/(checkout)/checkout/CheckoutSidebar.tsx index 60694ced..19eb5528 100644 --- a/examples/core/src/app/[lang]/(checkout)/checkout/CheckoutSidebar.tsx +++ b/examples/core/src/app/[lang]/(checkout)/checkout/CheckoutSidebar.tsx @@ -18,6 +18,8 @@ import { LoadingDots } from "src/components/LoadingDots"; import { getACart, ResponseCurrency } from "@epcc-sdk/sdks-shopper"; import { ItemSidebarHideable } from "src/components/checkout-sidebar/ItemSidebarHideable"; import { groupCartItems } from "src/lib/group-cart-items"; +import { useParams } from "next/navigation"; +import { getPreferredCurrency } from "src/lib/get-locale-currency"; export function CheckoutSidebar({ cart, @@ -28,9 +30,9 @@ export function CheckoutSidebar({ }) { const shippingMethod = useWatch({ name: "shippingMethod" }); - const storeCurrency = currencies?.find( - (currency) => currency.code === EP_CURRENCY_CODE, - ); + const { lang } = useParams(); + const cartCurrencyCode = cart.data?.meta?.display_price?.with_tax?.currency; + const storeCurrency = getPreferredCurrency(lang as string, currencies, cartCurrencyCode); const groupedItems = groupCartItems(cart?.included?.items ?? []); const { regular, promotion, itemLevelPromotion, subscription_offerings } = groupedItems; @@ -103,7 +105,7 @@ export function CheckoutSidebar({ items={[...regular, ...subscription_offerings]} storeCurrency={storeCurrency} /> - + getByContextProduct({ client, path: { product_id: item.product_id! }, + headers: { + "Accept-Language": params?.lang, + "X-Moltin-Currency": currencyUpdated?.code, + } }) ); const productDetails = await Promise.all(productDetailsPromises || []); @@ -59,13 +79,6 @@ export default async function CheckoutPage() { notFound(); } - const currencies = await getAllCurrencies({ - client, - next: { - tags: [TAGS.currencies], - }, - }); - const isAccount = await isAccountAuthenticated(); return ( diff --git a/examples/core/src/app/[lang]/(store)/cart/CartItem.tsx b/examples/core/src/app/[lang]/(store)/cart/CartItem.tsx index 1d4a06af..eeaf16c5 100644 --- a/examples/core/src/app/[lang]/(store)/cart/CartItem.tsx +++ b/examples/core/src/app/[lang]/(store)/cart/CartItem.tsx @@ -182,7 +182,7 @@ export function CartItem({ item, thumbnail, currency }: CartItemProps) { <> )}
- +
diff --git a/examples/core/src/app/[lang]/(store)/layout.tsx b/examples/core/src/app/[lang]/(store)/layout.tsx index 9586b9e3..d884260d 100644 --- a/examples/core/src/app/[lang]/(store)/layout.tsx +++ b/examples/core/src/app/[lang]/(store)/layout.tsx @@ -38,19 +38,24 @@ const inter = localFont({ export default async function StoreLayout({ children, + params, }: { children: ReactNode; + params: { lang: string }; }) { + const resolvedParams = await params; + const lang = resolvedParams?.lang; + const client = await createElasticPathClient(); const initialState = await getStoreInitialState(client); return ( - + {/* headless ui needs this div - https://github.com/tailwindlabs/headlessui/issues/2752#issuecomment-1745272229 */}
-
+
{children}
diff --git a/examples/core/src/app/[lang]/(store)/products/[productId]/actions/cart-actions.ts b/examples/core/src/app/[lang]/(store)/products/[productId]/actions/cart-actions.ts index 46e53c0d..af31b230 100644 --- a/examples/core/src/app/[lang]/(store)/products/[productId]/actions/cart-actions.ts +++ b/examples/core/src/app/[lang]/(store)/products/[productId]/actions/cart-actions.ts @@ -9,6 +9,7 @@ import { deleteACartItem, updateACartItem, deleteAPromotionViaPromotionCode, + deleteAllCartItems, } from "@epcc-sdk/sdks-shopper"; import { revalidateTag } from "next/cache"; import { createElasticPathClient } from "src/lib/create-elastic-path-client"; @@ -20,6 +21,7 @@ import { formSelectedOptionsToData } from "src/components/product/bundles/form-p */ export async function addToCartAction( data: z.infer, + currencyCode?: string ) { const cartCookie = (await cookies()).get(CART_COOKIE_NAME); @@ -39,6 +41,9 @@ export async function addToCartAction( quantity: data.quantity, ...(data.location && { location: data.location }), }, + }, + headers: { + "X-Moltin-Currency": currencyCode, } }); @@ -55,6 +60,7 @@ export async function addToCartAction( */ export async function addToBundleAction( data: z.infer>, + currencyCode?: string ) { const cartCookie = (await cookies()).get(CART_COOKIE_NAME); @@ -78,6 +84,9 @@ export async function addToBundleAction( ...(data.location && { location: data.location }), }, }, + headers: { + "X-Moltin-Currency": currencyCode, + } }); await revalidateTag("cart"); @@ -120,7 +129,7 @@ export async function updateCartItemAction(data: { cartItemId: string; quantity: number; location?: string; -}) { +}, currencyCode?: string ) { const cartCookie = (await cookies()).get(CART_COOKIE_NAME); if (!cartCookie) { @@ -139,6 +148,9 @@ export async function updateCartItemAction(data: { ...(data.location && { location: data.location }), }, }, + headers: { + "X-Moltin-Currency": currencyCode, + }, }); await revalidateTag("cart"); diff --git a/examples/core/src/app/[lang]/(store)/products/[productId]/page.tsx b/examples/core/src/app/[lang]/(store)/products/[productId]/page.tsx index 045f91f6..ec5a0b90 100644 --- a/examples/core/src/app/[lang]/(store)/products/[productId]/page.tsx +++ b/examples/core/src/app/[lang]/(store)/products/[productId]/page.tsx @@ -16,7 +16,8 @@ import { VariationProductProvider } from "src/components/product/variations/Vari import { VariationProductContent } from "src/components/product/variations/VariationProductContent"; import { BundleProductProvider } from "src/components/product/bundles/BundleProductProvider"; import { BundleProductContent } from "src/components/product/bundles/BundleProductContent"; -import { getCurrency } from "src/lib/get-locale-currency"; +import { getPreferredCurrency } from "src/lib/get-locale-currency"; +import { TAGS } from "src/lib/constants"; export const dynamic = "force-dynamic"; @@ -53,7 +54,13 @@ export async function generateMetadata(props: Props): Promise { export default async function ProductPage(props: Props) { const params = await props.params; const client = createElasticPathClient(); - const currency = await getCurrency(params.lang) + const currencies = await getAllCurrencies({ + client, + next: { + tags: [TAGS.currencies], + }, + }); + const currency = getPreferredCurrency(params?.lang, currencies.data?.data || []); const productPromise = getByContextProduct({ client, path: { @@ -119,6 +126,7 @@ export default async function ProductPage(props: Props) { product={productResponse.data} inventory={inventoryResponse.data?.data} locations={locationResponse.data?.data} + currency={currency} > @@ -131,6 +139,7 @@ export default async function ProductPage(props: Props) { componentImageFiles={componentImageFiles} inventory={inventoryResponse.data?.data} locations={locationResponse.data?.data} + currency={currency} > @@ -144,6 +153,7 @@ export default async function ProductPage(props: Props) { parentProduct={parentProduct?.data} inventory={inventoryResponse.data?.data} locations={locationResponse.data?.data} + currency={currency} > @@ -155,6 +165,7 @@ export default async function ProductPage(props: Props) { product={productResponse.data} inventory={inventoryResponse.data?.data} locations={locationResponse.data?.data} + currency={currency} > diff --git a/examples/core/src/components/cart/CartSheet.tsx b/examples/core/src/components/cart/CartSheet.tsx index 9efdeb04..a2cac59e 100644 --- a/examples/core/src/components/cart/CartSheet.tsx +++ b/examples/core/src/components/cart/CartSheet.tsx @@ -19,8 +19,9 @@ import Link from "next/link"; import { getACart, ResponseCurrency } from "@epcc-sdk/sdks-shopper"; import { groupCartItems } from "../../lib/group-cart-items"; import { RemoveCartPromotionXButton } from "./RemoveCartPromotionXButton"; -import { EP_CURRENCY_CODE } from "src/lib/resolve-ep-currency-code"; import { formatCurrency } from "src/lib/format-currency"; +import { useParams } from "next/navigation"; +import { getPreferredCurrency } from "src/lib/get-locale-currency"; export function CartSheet({ cart, @@ -38,9 +39,9 @@ export function CartSheet({ const discountedValues = cart.data?.meta?.display_price?.discount; const hasPromotion = discountedValues && discountedValues.amount !== 0; - const storeCurrency = currencies?.find( - (currency) => currency.code === EP_CURRENCY_CODE, - ); + const { lang } = useParams(); + const cartCurrencyCode = cart.data?.meta?.display_price?.with_tax?.currency; + const storeCurrency = getPreferredCurrency(lang as string, currencies, cartCurrencyCode); // CART TOTAL BEFORE DISCOUNTS (SALE + PROMOTIONS) const cartItems = cart.included?.items ?? []; @@ -159,7 +160,7 @@ export function CartSheet({ {/* Bottom */}
- +
{mergedPromotions.length > 0 && mergedPromotions.map((promotion) => { diff --git a/examples/core/src/components/checkout-sidebar/AddPromotion.tsx b/examples/core/src/components/checkout-sidebar/AddPromotion.tsx index a45c1900..ccc67e56 100644 --- a/examples/core/src/components/checkout-sidebar/AddPromotion.tsx +++ b/examples/core/src/components/checkout-sidebar/AddPromotion.tsx @@ -13,6 +13,8 @@ import { getACartQueryKey } from "@epcc-sdk/sdks-shopper/react-query"; import { getCookie } from "cookies-next/client"; import { CART_COOKIE_NAME } from "../../lib/cookie-constants"; import { useNotify } from "../../hooks/use-event"; +import { useParams } from "next/navigation"; +import { ResponseCurrency } from "@epcc-sdk/sdks-shopper"; const cartErrorOptions = { scope: "cart", @@ -20,7 +22,7 @@ const cartErrorOptions = { action: "add-promotion", } as const; -export function AddPromotion() { +export function AddPromotion(props: {currencyCode: string | undefined}) { const [showInput, setShowInput] = useState(false); const queryClient = useQueryClient(); const [error, setError] = useState(undefined); @@ -30,7 +32,7 @@ export function AddPromotion() { setError(undefined); try { - const result = await applyDiscount(formData); + const result = await applyDiscount(formData, props?.currencyCode || ""); if (result.error) { notify({ diff --git a/examples/core/src/components/checkout-sidebar/ItemSidebar.tsx b/examples/core/src/components/checkout-sidebar/ItemSidebar.tsx index 8930e233..57259b80 100644 --- a/examples/core/src/components/checkout-sidebar/ItemSidebar.tsx +++ b/examples/core/src/components/checkout-sidebar/ItemSidebar.tsx @@ -91,10 +91,10 @@ export function ItemSidebarItems({ items, storeCurrency }: { items: Item[], stor ); } -export function ItemSidebarPromotions() { +export function ItemSidebarPromotions(props: {currencyCode: string | undefined}) { return (
- +
); } diff --git a/examples/core/src/components/checkout-sidebar/actions.ts b/examples/core/src/components/checkout-sidebar/actions.ts index 30d0d5e9..0d553755 100644 --- a/examples/core/src/components/checkout-sidebar/actions.ts +++ b/examples/core/src/components/checkout-sidebar/actions.ts @@ -11,7 +11,7 @@ const applyDiscountSchema = z.object({ code: z.string(), }); -export async function applyDiscount(formData: FormData) { +export async function applyDiscount(formData: FormData, currencyCode: string) { try { const client = await createElasticPathClient(); @@ -43,6 +43,9 @@ export async function applyDiscount(formData: FormData) { code: validatedFormData.data.code, }, }, + headers: { + "X-Moltin-Currency": currencyCode, + }, }); await revalidateTag("cart"); diff --git a/examples/core/src/components/header/Header.tsx b/examples/core/src/components/header/Header.tsx index fc24d1fc..86ac4cb4 100644 --- a/examples/core/src/components/header/Header.tsx +++ b/examples/core/src/components/header/Header.tsx @@ -8,7 +8,7 @@ import { Cart } from "./navigation/Cart"; import { Skeleton } from "../skeleton/Skeleton"; import { LocaleSelector } from "./locale/LocaleSelector"; -const Header = async () => { +const Header = async ({ lang }: { lang: string }) => { return (
@@ -31,7 +31,7 @@ const Header = async () => {
}> - +
diff --git a/examples/core/src/components/header/navigation/Cart.tsx b/examples/core/src/components/header/navigation/Cart.tsx index d1fc7763..cc495640 100644 --- a/examples/core/src/components/header/navigation/Cart.tsx +++ b/examples/core/src/components/header/navigation/Cart.tsx @@ -6,8 +6,9 @@ import { cookies } from "next/headers"; import { CART_COOKIE_NAME } from "../../../lib/cookie-constants"; import { getACart, getAllCurrencies, getByContextAllProducts } from "@epcc-sdk/sdks-shopper"; import { TAGS } from "../../../lib/constants"; +import { getPreferredCurrency } from "src/lib/get-locale-currency"; -export async function Cart() { +export async function Cart({ lang }: { lang: string }) { const client = createElasticPathClient(); const cartId = (await cookies()).get(CART_COOKIE_NAME)?.value; @@ -16,6 +17,14 @@ export async function Cart() { return null; } + const currencies = await getAllCurrencies({ + client, + next: { + tags: [TAGS.currencies], + }, + }); + const currency = await getPreferredCurrency(lang, currencies.data?.data || []); + const cartResponse = await getACart({ client, path: { @@ -27,8 +36,15 @@ export async function Cart() { next: { tags: [TAGS.cart], }, + headers: { + "Accept-Language": lang, + "X-Moltin-Currency": currency?.code + } }); + const cartCurrency = cartResponse.data?.data?.meta?.display_price?.with_tax?.currency; + const currencyUpdated = getPreferredCurrency(lang, currencies.data?.data || [], cartCurrency); + // Fetch product details for each cart item to get original sale price const cartItems = cartResponse?.data?.included?.items; const productIds = cartItems?.map(item => item.product_id).filter(Boolean); @@ -36,6 +52,10 @@ export async function Cart() { client, query: { filter: `in(id,${productIds?.join(",")})`, + }, + headers: { + "Accept-Language": lang, + "X-Moltin-Currency": currencyUpdated?.code, } }); const productDetails = productDetailsResponse.data?.data || []; @@ -49,14 +69,6 @@ export async function Cart() { }; }); - // Fetch currencies - const currencies = await getAllCurrencies({ - client, - next: { - tags: [TAGS.currencies], - }, - }); - if (!cartResponse.data) { console.error("No cart found"); return null; diff --git a/examples/core/src/components/number-input/NumberInput.tsx b/examples/core/src/components/number-input/NumberInput.tsx index 8a723148..6c71f465 100644 --- a/examples/core/src/components/number-input/NumberInput.tsx +++ b/examples/core/src/components/number-input/NumberInput.tsx @@ -20,11 +20,13 @@ import { useNotify } from "../../hooks/use-event"; import { useQueryClient } from "@tanstack/react-query"; import { cn } from "../../lib/cn"; import { Item } from "../../lib/group-cart-items"; +import { ResponseCurrency } from "@epcc-sdk/sdks-shopper"; import type { JSX } from "react"; interface NumberInputProps { item: Item; + currency?: ResponseCurrency; } const quantitySchema = z.object({ @@ -39,9 +41,10 @@ const cartErrorOptions = { action: "update-cart-item", } as const; -export const NumberInput = ({ item }: NumberInputProps): JSX.Element => { +export const NumberInput = ({ item, currency }: NumberInputProps): JSX.Element => { const notify = useNotify(); const queryClient = useQueryClient(); + const currencyCode = currency?.code; const values = useMemo(() => { return { @@ -66,7 +69,7 @@ export const NumberInput = ({ item }: NumberInputProps): JSX.Element => { cartItemId: itemId, quantity, location, - }); + }, currencyCode); if (result.error) { notify({ diff --git a/examples/core/src/components/product/bundles/BundleProductForm.tsx b/examples/core/src/components/product/bundles/BundleProductForm.tsx index 43db7ff9..32f22cd6 100644 --- a/examples/core/src/components/product/bundles/BundleProductForm.tsx +++ b/examples/core/src/components/product/bundles/BundleProductForm.tsx @@ -1,6 +1,6 @@ "use client"; import { getACartQueryKey } from "@epcc-sdk/sdks-shopper/react-query"; -import { ProductData, StockLocations } from "@epcc-sdk/sdks-shopper"; +import { ProductData, ResponseCurrency, StockLocations } from "@epcc-sdk/sdks-shopper"; import { ReactNode, useMemo } from "react"; import { useNotify } from "../../../hooks/use-event"; import { useForm } from "react-hook-form"; @@ -25,10 +25,12 @@ export function BundleProductForm({ product, locations, children, + currency, }: { product: ProductData; locations?: StockLocations; children: ReactNode; + currency?: ResponseCurrency; }) { const notify = useNotify(); const queryClient = useQueryClient(); @@ -56,7 +58,7 @@ export function BundleProductForm({ async function handleSubmit(data: z.infer) { try { - const result = await addToBundleAction(data); + const result = await addToBundleAction(data, currency?.code); if (result.error) { notify({ ...cartErrorOptions, diff --git a/examples/core/src/components/product/bundles/BundleProductProvider.tsx b/examples/core/src/components/product/bundles/BundleProductProvider.tsx index 1136dfc8..40ccc9cb 100644 --- a/examples/core/src/components/product/bundles/BundleProductProvider.tsx +++ b/examples/core/src/components/product/bundles/BundleProductProvider.tsx @@ -5,6 +5,7 @@ import { Location, Product, ProductData, + ResponseCurrency, StockResponse, } from "@epcc-sdk/sdks-shopper"; import { createContext, ReactNode, type JSX, useContext, useMemo } from "react"; @@ -22,6 +23,7 @@ export interface BundleProductProvider { inventory?: StockResponse; children: ReactNode; locations?: Location[]; + currency?: ResponseCurrency; } export interface BundleProductContextType { @@ -39,6 +41,7 @@ export function BundleProductProvider({ product: sourceProduct, children, locations, + currency, }: BundleProductProvider): JSX.Element { const productContext = useCreateShopperProductContext( sourceProduct, @@ -73,6 +76,7 @@ export function BundleProductProvider({ {children} diff --git a/examples/core/src/components/product/standard/SimpleProductForm.tsx b/examples/core/src/components/product/standard/SimpleProductForm.tsx index 6fa1957c..639a801c 100644 --- a/examples/core/src/components/product/standard/SimpleProductForm.tsx +++ b/examples/core/src/components/product/standard/SimpleProductForm.tsx @@ -1,5 +1,5 @@ "use client"; -import { ProductData } from "@epcc-sdk/sdks-shopper"; +import { ProductData, ResponseCurrency } from "@epcc-sdk/sdks-shopper"; import { getACartQueryKey } from "@epcc-sdk/sdks-shopper/react-query"; import { type StockLocations } from "@epcc-sdk/sdks-shopper"; import { ReactNode } from "react"; @@ -12,6 +12,7 @@ import { addToCartAction } from "../../../app/[lang]/(store)/products/[productId import { useQueryClient } from "@tanstack/react-query"; import { getCookie } from "cookies-next/client"; import { CART_COOKIE_NAME } from "../../../lib/cookie-constants"; +import { useParams } from "next/navigation"; export const simpleProductSchema = z.object({ productId: z.string(), @@ -29,10 +30,12 @@ export function SimpleProductForm({ product, locations, children, + currency, }: { product: ProductData; locations?: StockLocations; children: ReactNode; + currency?: ResponseCurrency; }) { const notify = useNotify(); const queryClient = useQueryClient(); @@ -48,7 +51,7 @@ export function SimpleProductForm({ async function handleSubmit(data: z.infer) { try { - const result = await addToCartAction(data); + const result = await addToCartAction(data, currency?.code); if (result.error) { notify({ diff --git a/examples/core/src/components/product/standard/SimpleProductProvider.tsx b/examples/core/src/components/product/standard/SimpleProductProvider.tsx index e183da6c..d6904523 100644 --- a/examples/core/src/components/product/standard/SimpleProductProvider.tsx +++ b/examples/core/src/components/product/standard/SimpleProductProvider.tsx @@ -1,5 +1,5 @@ "use client"; -import { Location, ProductData, StockResponse } from "@epcc-sdk/sdks-shopper"; +import { Location, ProductData, ResponseCurrency, StockResponse } from "@epcc-sdk/sdks-shopper"; import { ReactNode, type JSX } from "react"; import { ShopperProductProvider, @@ -12,6 +12,7 @@ export interface SimpleProductProvider { inventory?: StockResponse; children: ReactNode; locations?: Location[]; + currency?: ResponseCurrency; } export function SimpleProductProvider({ @@ -19,6 +20,7 @@ export function SimpleProductProvider({ product, children, locations, + currency, }: SimpleProductProvider): JSX.Element { const productContext = useCreateShopperProductContext( product, @@ -31,6 +33,7 @@ export function SimpleProductProvider({ {children} diff --git a/examples/core/src/components/product/variations/VariationProductForm.tsx b/examples/core/src/components/product/variations/VariationProductForm.tsx index 707e48f9..ec4a5f7e 100644 --- a/examples/core/src/components/product/variations/VariationProductForm.tsx +++ b/examples/core/src/components/product/variations/VariationProductForm.tsx @@ -1,6 +1,6 @@ import { ProductData } from "@epcc-sdk/sdks-shopper"; import { getACartQueryKey } from "@epcc-sdk/sdks-shopper/react-query"; -import type { StockLocations } from "@epcc-sdk/sdks-shopper"; +import type { ResponseCurrency, StockLocations } from "@epcc-sdk/sdks-shopper"; import { ReactNode } from "react"; import { useNotify } from "../../../hooks/use-event"; import { useForm } from "react-hook-form"; @@ -29,10 +29,12 @@ export function VariationProductForm({ product, locations, children, + currency, }: { product: ProductData; locations?: StockLocations; children: ReactNode; + currency?: ResponseCurrency; }) { const notify = useNotify(); const queryClient = useQueryClient(); @@ -48,7 +50,7 @@ export function VariationProductForm({ async function handleSubmit(data: z.infer) { try { - const result = await addToCartAction(data); + const result = await addToCartAction(data, currency?.code); if (result.error) { notify({ diff --git a/examples/core/src/components/product/variations/VariationProductProvider.tsx b/examples/core/src/components/product/variations/VariationProductProvider.tsx index 45652cd2..a2cad866 100644 --- a/examples/core/src/components/product/variations/VariationProductProvider.tsx +++ b/examples/core/src/components/product/variations/VariationProductProvider.tsx @@ -25,7 +25,7 @@ import { createEmptyOptionDict, mapOptionsToVariation, } from "./util/map-options-to-variations"; -import type { Location, ProductMeta } from "@epcc-sdk/sdks-shopper"; +import type { Location, ProductMeta, ResponseCurrency } from "@epcc-sdk/sdks-shopper"; export interface VariationProductProvider { product: ProductData; @@ -33,6 +33,7 @@ export interface VariationProductProvider { inventory?: StockResponse; children: ReactNode; locations?: Location[]; + currency?: ResponseCurrency; } export interface VariationProductContextType { @@ -56,6 +57,7 @@ export function VariationProductProvider({ children, parentProduct, locations, + currency, }: VariationProductProvider): JSX.Element { const productContext = useCreateShopperProductContext( sourceProduct, @@ -100,6 +102,7 @@ export function VariationProductProvider({ {children} diff --git a/examples/core/src/lib/get-locale-currency.ts b/examples/core/src/lib/get-locale-currency.ts index 69573d7f..53ad4c58 100644 --- a/examples/core/src/lib/get-locale-currency.ts +++ b/examples/core/src/lib/get-locale-currency.ts @@ -1,28 +1,19 @@ -import { getAllCurrencies } from "@epcc-sdk/sdks-shopper"; -import { createElasticPathClient } from "./create-elastic-path-client"; -import { TAGS } from "./constants"; +import { ResponseCurrency } from "@epcc-sdk/sdks-shopper"; import { LOCALE_TO_CURRENCY } from "./i18n"; -export async function getCurrency(lang?: string) { - const client = createElasticPathClient(); - - const currenciesResponse = await getAllCurrencies({ - client, - next: { - tags: [TAGS.currencies], - }, - }); - - const currencies = currenciesResponse.data?.data || []; - +export function getPreferredCurrency(lang: string | undefined, currencies: ResponseCurrency[], cartCurrencyCode?: string) { if (!currencies.length) return undefined; - const preferredCode = lang ? LOCALE_TO_CURRENCY[lang] : undefined; + const preferredCode = cartCurrencyCode + ? cartCurrencyCode + : lang + ? LOCALE_TO_CURRENCY[lang] + : undefined - let currency = currencies.find((c) => c.code === preferredCode && c.enabled) + let currency = currencies.find((c: any) => c.code === preferredCode && c.enabled) if (!currency) { - currency = currencies.find((c) => c.default && c.enabled); + currency = currencies.find((c: any) => c.default && c.enabled); } return currency; diff --git a/examples/core/src/middleware.ts b/examples/core/src/middleware.ts index ec8a6fe0..94753ddc 100644 --- a/examples/core/src/middleware.ts +++ b/examples/core/src/middleware.ts @@ -9,7 +9,6 @@ export const config = { }; export async function middleware(req: NextRequest, event: NextFetchEvent) { - console.log("req: ", req) const acceptLanguage = req.headers.get("accept-language"); const firstLang = acceptLanguage?.split(",")[0] ?? ""; const browserLocale = firstLang.split("-")[0] || "en"; From b75beee3626343c282725edeab647c0fa82816ba Mon Sep 17 00:00:00 2001 From: Muhammad Zain Tariq <49867382+mzaintariq@users.noreply.github.com> Date: Thu, 4 Dec 2025 13:22:29 +0500 Subject: [PATCH 03/14] Clear cart on locale change --- .../[productId]/actions/cart-actions.ts | 25 +++++++ .../locale/ConfirmLocaleChangeModal.tsx | 40 +++++++++++ .../header/locale/LocaleSelector.tsx | 66 ++++++++++++++++--- 3 files changed, 123 insertions(+), 8 deletions(-) create mode 100644 examples/core/src/components/header/locale/ConfirmLocaleChangeModal.tsx diff --git a/examples/core/src/app/[lang]/(store)/products/[productId]/actions/cart-actions.ts b/examples/core/src/app/[lang]/(store)/products/[productId]/actions/cart-actions.ts index af31b230..534e66d2 100644 --- a/examples/core/src/app/[lang]/(store)/products/[productId]/actions/cart-actions.ts +++ b/examples/core/src/app/[lang]/(store)/products/[productId]/actions/cart-actions.ts @@ -184,3 +184,28 @@ export async function removeCartPromotionAction(data: { promoCode: string }) { error: result.error, }; } + +/** + * removeAllCartItemsAction - Server Action that removes all items from the cart + */ +export async function removeAllCartItemsAction() { + const cartCookie = (await cookies()).get(CART_COOKIE_NAME); + + if (!cartCookie) { + throw new Error("No cart cookie found. Cannot remove product from cart."); + } + + const client = createElasticPathClient(); + + const result = await deleteAllCartItems({ + client, + path: { cartID: cartCookie.value }, + }); + + await revalidateTag("cart"); + + return { + data: result.data, + error: result.error, + }; +} diff --git a/examples/core/src/components/header/locale/ConfirmLocaleChangeModal.tsx b/examples/core/src/components/header/locale/ConfirmLocaleChangeModal.tsx new file mode 100644 index 00000000..30d87d6f --- /dev/null +++ b/examples/core/src/components/header/locale/ConfirmLocaleChangeModal.tsx @@ -0,0 +1,40 @@ +"use client"; +import React from "react"; + +export function ConfirmLocaleChangeModal({ + open, + onConfirm, + onCancel, +}: { + open: boolean; + onConfirm: () => void; + onCancel: () => void; +}) { + if (!open) return null; + + return ( +
+
+

Change Language?

+

+ Changing locale will empty your cart. Continue? +

+ +
+ + +
+
+
+ ); +} diff --git a/examples/core/src/components/header/locale/LocaleSelector.tsx b/examples/core/src/components/header/locale/LocaleSelector.tsx index a8850ead..7b1854bb 100644 --- a/examples/core/src/components/header/locale/LocaleSelector.tsx +++ b/examples/core/src/components/header/locale/LocaleSelector.tsx @@ -1,26 +1,76 @@ "use client"; import { useRouter, usePathname } from "next/navigation"; import { SUPPORTED_LOCALES } from "src/lib/i18n"; +import { ConfirmLocaleChangeModal } from "./ConfirmLocaleChangeModal"; +import { useState } from "react"; +import { removeAllCartItemsAction } from "src/app/[lang]/(store)/products/[productId]/actions/cart-actions"; +import { useNotify } from "src/hooks/use-event"; export const LocaleSelector = () => { const router = useRouter(); const pathname = usePathname(); + const notify = useNotify(); const currentLocale = pathname.split("/")[1]; + const [pendingLocale, setPendingLocale] = useState(null); + const [showModal, setShowModal] = useState(false); const handleChange = (e: React.ChangeEvent) => { const newLocale = e.target.value; + if (newLocale === currentLocale) return; + setPendingLocale(newLocale); + setShowModal(true); + }; + + const clearCart = async () => { + try { + const result = await removeAllCartItemsAction() + if (result.error) { + notify({ + scope: "cart", + type: "error", + action: "remove-cart-item", + message: (result.error as any).errors[0]?.detail, + cause: { + type: "cart-store-error", + cause: new Error(JSON.stringify(result.error)), + }, + }) + } else { + notify({ + scope: "cart", + type: "success", + action: "remove-cart-item", + message: "Successfully removed all cart items", + }) + } + } catch (e) { + console.error("Failed clearing cart", e); + } + }; + + const confirmChange = async () => { + if (!pendingLocale) return; + await clearCart(); const segments = pathname.split("/"); - segments[1] = newLocale; + segments[1] = pendingLocale; + setShowModal(false); router.push(segments.join("/")); }; return ( - + <> + + setShowModal(false)} + /> + ); }; \ No newline at end of file From c98a186caceb0f8452c246963195fa96a3c7e8d7 Mon Sep 17 00:00:00 2001 From: Muhammad Zain Tariq <49867382+mzaintariq@users.noreply.github.com> Date: Thu, 4 Dec 2025 13:22:50 +0500 Subject: [PATCH 04/14] use currency object formatting to format currency --- examples/core/src/lib/format-currency.tsx | 33 +++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/examples/core/src/lib/format-currency.tsx b/examples/core/src/lib/format-currency.tsx index 694a2b93..004443b1 100644 --- a/examples/core/src/lib/format-currency.tsx +++ b/examples/core/src/lib/format-currency.tsx @@ -7,11 +7,40 @@ export function formatCurrency( locals?: Parameters[0]; } = { locals: "en-US" }, ) { - const { decimal_places = 2, code } = currency; + const { + decimal_places = 2, + decimal_point = ".", + thousand_separator = ",", + format = "{price} {code}", + code, + } = currency; const resolvedAmount = amount / Math.pow(10, decimal_places); - return new Intl.NumberFormat(options.locals, { + const [integerPart, decimalPartRaw] = resolvedAmount + .toFixed(decimal_places) + .split("."); + + const integerWithGrouping = integerPart?.replace( + /\B(?=(\d{3})+(?!\d))/g, + thousand_separator + ); + + const formattedNumber = `${integerWithGrouping}${decimal_point}${decimalPartRaw}`; + + const isNegative = resolvedAmount < 0; + + const absoluteFormattedNumber = formattedNumber.replace(/^-/, ""); + + let finalFormatted = format + .replace("{price}", absoluteFormattedNumber) + .replace("{code}", code ?? ""); + + if (isNegative) { + finalFormatted = `-${finalFormatted}`; + } + + return finalFormatted || new Intl.NumberFormat(options.locals, { style: "currency", maximumFractionDigits: decimal_places, minimumFractionDigits: decimal_places, From 9ae400d3ec3a3746da1f7e475cb0f1707ce9a434 Mon Sep 17 00:00:00 2001 From: Muhammad Zain Tariq <49867382+mzaintariq@users.noreply.github.com> Date: Thu, 4 Dec 2025 17:30:51 +0500 Subject: [PATCH 05/14] build fixes --- .../[lang]/(checkout)/checkout/CheckoutSidebar.tsx | 1 - .../core/src/app/[lang]/(checkout)/checkout/page.tsx | 11 ++++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/core/src/app/[lang]/(checkout)/checkout/CheckoutSidebar.tsx b/examples/core/src/app/[lang]/(checkout)/checkout/CheckoutSidebar.tsx index 19eb5528..e58b4a43 100644 --- a/examples/core/src/app/[lang]/(checkout)/checkout/CheckoutSidebar.tsx +++ b/examples/core/src/app/[lang]/(checkout)/checkout/CheckoutSidebar.tsx @@ -12,7 +12,6 @@ import { import { staticDeliveryMethods } from "./useShippingMethod"; import { cn } from "src/lib/cn"; import { useWatch } from "react-hook-form"; -import { EP_CURRENCY_CODE } from "src/lib/resolve-ep-currency-code"; import { formatCurrency } from "src/lib/format-currency"; import { LoadingDots } from "src/components/LoadingDots"; import { getACart, ResponseCurrency } from "@epcc-sdk/sdks-shopper"; diff --git a/examples/core/src/app/[lang]/(checkout)/checkout/page.tsx b/examples/core/src/app/[lang]/(checkout)/checkout/page.tsx index c6dde960..b72ece29 100644 --- a/examples/core/src/app/[lang]/(checkout)/checkout/page.tsx +++ b/examples/core/src/app/[lang]/(checkout)/checkout/page.tsx @@ -15,9 +15,10 @@ import { getPreferredCurrency } from "src/lib/get-locale-currency"; export const metadata: Metadata = { title: "Checkout", }; -export default async function CheckoutPage({ params }: { params: { lang: string }; }) { +export default async function CheckoutPage({ params }: { params: Promise<{ lang: string }> }) { const cartCookie = (await cookies()).get(CART_COOKIE_NAME); const client = createElasticPathClient(); + const { lang } = await params; if (!cartCookie) { throw new Error("Cart cookie not found"); @@ -29,7 +30,7 @@ export default async function CheckoutPage({ params }: { params: { lang: string tags: [TAGS.currencies], }, }); - const currency = getPreferredCurrency(params?.lang, currencies.data?.data || []); + const currency = getPreferredCurrency(lang, currencies.data?.data || []); const cartResponse = await getACart({ client, @@ -43,13 +44,13 @@ export default async function CheckoutPage({ params }: { params: { lang: string tags: [TAGS.cart], }, headers: { - "Accept-Language": params?.lang, + "Accept-Language": lang, "X-Moltin-Currency": currency?.code, } }); const cartCurrency = cartResponse.data?.data?.meta?.display_price?.with_tax?.currency; - const currencyUpdated = getPreferredCurrency(params?.lang, currencies.data?.data || [], cartCurrency); + const currencyUpdated = getPreferredCurrency(lang, currencies.data?.data || [], cartCurrency); // Fetch product details for each cart item to get original sale price const cartItems = cartResponse?.data?.included?.items; @@ -58,7 +59,7 @@ export default async function CheckoutPage({ params }: { params: { lang: string client, path: { product_id: item.product_id! }, headers: { - "Accept-Language": params?.lang, + "Accept-Language": lang, "X-Moltin-Currency": currencyUpdated?.code, } }) From c9ec2f13e214ee93b7ad551140e11b9aad3f3e67 Mon Sep 17 00:00:00 2001 From: Muhammad Zain Tariq <49867382+mzaintariq@users.noreply.github.com> Date: Thu, 4 Dec 2025 17:32:49 +0500 Subject: [PATCH 06/14] cart page updates --- .../app/[lang]/(store)/cart/CartItemWide.tsx | 192 +++++++++++++++--- .../app/[lang]/(store)/cart/CartSidebar.tsx | 100 ++++++++- .../src/app/[lang]/(store)/cart/YourBag.tsx | 6 +- .../core/src/app/[lang]/(store)/cart/page.tsx | 53 ++++- 4 files changed, 308 insertions(+), 43 deletions(-) diff --git a/examples/core/src/app/[lang]/(store)/cart/CartItemWide.tsx b/examples/core/src/app/[lang]/(store)/cart/CartItemWide.tsx index 9a96b795..e1d763a3 100644 --- a/examples/core/src/app/[lang]/(store)/cart/CartItemWide.tsx +++ b/examples/core/src/app/[lang]/(store)/cart/CartItemWide.tsx @@ -3,8 +3,52 @@ import Link from "next/link"; import { NumberInput } from "src/components/number-input/NumberInput"; import { CartItemProps } from "./CartItem"; import { RemoveCartItemButton } from "src/components/cart/RemoveCartItemButton"; +import { calculateMultiItemOriginalTotal, calculateSaleAmount, calculateTotalSavings, getFormattedPercentage, getFormattedValue } from "src/lib/price-calculation"; -export function CartItemWide({ item, thumbnail }: CartItemProps) { +export function CartItemWide({ item, thumbnail, currency }: CartItemProps) { + if (!item) { + return
Missing cart item data
; + } + + console.log("CartItemWide currency:", currency); + + let itemLink = null; + if (item.product_id) { + itemLink = `/products/${item.product_id}`; + } + + const itemDisplayPrice = item.meta?.display_price?.with_tax?.unit; + const fallbackDisplayPrice = (item as any).productDetail?.meta?.display_price?.without_tax; + const originalDisplayPrice = (item as any).productDetail?.meta?.original_display_price?.without_tax; + const finalOriginalPrice = originalDisplayPrice + ? originalDisplayPrice + : fallbackDisplayPrice && + fallbackDisplayPrice.amount !== itemDisplayPrice?.amount + ? fallbackDisplayPrice + : undefined; + + // TOTAL BEFORE SALE PRICING + const multiItemOriginalTotal = calculateMultiItemOriginalTotal(item); + const formattedMultiItemOriginalTotal = getFormattedValue(multiItemOriginalTotal!, currency!); + + // SALE SAVINGS CALCULATION + const saleAmount = calculateSaleAmount(item); + const formattedSaleAmount = getFormattedValue(saleAmount!, currency!); + + // SALE SAVINGS PERCENTAGE CALCULATION + const formattedSalePercentage = getFormattedPercentage(saleAmount!, multiItemOriginalTotal!); + + // TOTAL SAVINGS CALCULATION + const itemTotalSavings = calculateTotalSavings(item); + const formattedTotalSavings = getFormattedValue(itemTotalSavings!, currency!); + + // TOTAL SAVINGS PERCENTAGE CALCULATION + const itemWithoutDiscountAmount = item.meta?.display_price?.without_discount?.value?.amount; + const discountPercentFormatted = getFormattedPercentage(itemTotalSavings!, (multiItemOriginalTotal || itemWithoutDiscountAmount)!); + + // ITEM PROMOTIONS + const itemDiscounts = (item as any)?.meta?.display_price?.discounts as Record | undefined; + return (
{/* Thumbnail */} @@ -12,40 +56,132 @@ export function CartItemWide({ item, thumbnail }: CartItemProps) {
{/* Details */} -
-
-
- - - {item?.name} - - +
+
+
+ {itemLink ? ( + + {item.name} + + ) : ( + {item.name} + )} + - Quantity: {item?.quantity} + Quantity: {item.quantity} - {item?.type === "cart_item" && item?.location && ( - - Location: {item?.location} +
+ +
+ + {item.meta?.display_price?.with_tax?.unit?.formatted} + + + {!finalOriginalPrice && + item.meta?.display_price?.without_discount?.unit?.amount && + item.meta?.display_price.without_discount.unit?.amount !== + item.meta?.display_price.with_tax?.unit?.amount && ( + + {item.meta?.display_price.without_discount.unit?.formatted} + + )} + + {finalOriginalPrice?.amount && + item.meta?.display_price && + finalOriginalPrice?.amount !== + item.meta?.display_price.with_tax?.unit?.amount && ( + + {finalOriginalPrice?.formatted} + + )} + + {originalDisplayPrice ? ( + + SALE + ) : ( + <> )}
-
- - -
-
-
- - {item?.meta?.display_price?.with_tax?.value?.formatted} - - {item?.meta?.display_price?.without_discount?.value?.amount && - item?.meta?.display_price?.without_discount?.value?.amount !== - item?.meta?.display_price.with_tax?.value?.amount && ( - - {item?.meta?.display_price?.without_discount.value?.formatted} + + {item.quantity > 1 && ( +
+
+ + Line total: ({item.quantity} x{" "} + {item.meta?.display_price?.with_tax?.unit?.formatted}) + +
+ +
+ + {item.meta?.display_price?.with_tax?.value?.formatted} + + + {!formattedMultiItemOriginalTotal && + item.meta?.display_price?.without_discount?.value?.amount && + item.meta?.display_price.without_discount.value?.amount !== + item.meta?.display_price.with_tax?.value?.amount && ( + + {item.meta?.display_price.without_discount.value?.formatted} + + )} + + {formattedMultiItemOriginalTotal && ( + + {formattedMultiItemOriginalTotal} + + )} +
+
+ )} + + {/* SALE PRICE */} + {formattedSaleAmount ? ( +
+ + {originalDisplayPrice + ? `Sale (${formattedSalePercentage} off)` + : `Bulk offer (${formattedSalePercentage} off)`} + + + ({formattedSaleAmount}) - )} +
+ ) : ( + <> + )} + + {/* PROMO PRICES */} + {itemDiscounts && + Object.entries(itemDiscounts).map(([key, discount]) => ( +
+ Promo ({key}) + + ({discount.formatted}) + +
+ ))} + + {/* TOTAL SAVINGS */} + {item.meta?.display_price?.discount?.value?.amount ? ( +
+ + You save{" "} + + {formattedTotalSavings} + {" "} + ({discountPercentFormatted}) + +
+ ) : ( + <> + )} +
+ + +
); diff --git a/examples/core/src/app/[lang]/(store)/cart/CartSidebar.tsx b/examples/core/src/app/[lang]/(store)/cart/CartSidebar.tsx index e7190437..94ab9b77 100644 --- a/examples/core/src/app/[lang]/(store)/cart/CartSidebar.tsx +++ b/examples/core/src/app/[lang]/(store)/cart/CartSidebar.tsx @@ -5,35 +5,119 @@ import { ItemSidebarPromotions, ItemSidebarSumTotal, ItemSidebarTotals, - ItemSidebarTotalsDiscount, - ItemSidebarTotalsSubTotal, ItemSidebarTotalsTax, } from "src/components/checkout-sidebar/ItemSidebar"; -import { CartEntityResponse } from "@epcc-sdk/sdks-shopper"; +import { getACart, ResponseCurrency } from "@epcc-sdk/sdks-shopper"; import { groupCartItems } from "src/lib/group-cart-items"; +import { formatCurrency } from "src/lib/format-currency"; -export function CartSidebar({ cart }: { cart: CartEntityResponse }) { +export function CartSidebar({ + cart, + storeCurrency, +}: { + cart: NonNullable>["data"]>; + storeCurrency: ResponseCurrency | undefined; +}) { const meta = cart.data?.meta!; const groupedItems = groupCartItems(cart.included?.items ?? []); + const discountedValues = cart.data?.meta?.display_price?.discount; + const hasPromotion = discountedValues && discountedValues.amount !== 0; + + // CART TOTAL BEFORE DISCOUNTS (SALE + PROMOTIONS) + const cartItems = cart.included?.items ?? []; + const totalCartValue = cartItems.reduce((acc, item) => { + const itemOriginalPrice = + (item as any).productDetail?.meta?.original_display_price?.without_tax + ?.amount || + (item as any).productDetail?.meta?.display_price?.without_tax?.amount || + 0 + const itemQuantity = (item as any).quantity || 1; + return acc + (itemOriginalPrice * itemQuantity) + }, 0); + const formattedCartTotal = totalCartValue + ? formatCurrency( + totalCartValue || 0, + storeCurrency || { code: "USD", decimal_places: 2 }, + ) + : undefined + + // TOTAL SALE PRICE SAVINGS + const totalCartValueWithoutDiscount = cartItems.reduce((acc, item) => { + const itemWithoudDiscount = + item?.meta?.display_price?.without_discount?.value?.amount || 0 + return acc + itemWithoudDiscount + }, 0); + const cartSavings = totalCartValueWithoutDiscount - totalCartValue + const formattedCartSavings = cartSavings + ? formatCurrency( + cartSavings || 0, + storeCurrency || { code: "USD", decimal_places: 2 }, + ) + : undefined + const hasSalePricing = cartSavings !== 0 + + // TOTAL CART SAVINGS + const totalCartValueWithoutTax = cart.data?.meta?.display_price?.without_tax?.amount || 0; + const totalCartSavings = totalCartValueWithoutTax - totalCartValue + const formattedTotalCartSavings = totalCartSavings + ? formatCurrency( + totalCartSavings || 0, + storeCurrency || { code: "USD", decimal_places: 2 }, + ) + : undefined + return (
- + {/* Totals */} - + {(hasSalePricing || hasPromotion) && ( + <> +
+ Total before discounts + {formattedCartTotal} +
+ {hasSalePricing && ( +
+ Sale markdowns + {formattedCartSavings} +
+ )} + {hasPromotion && ( +
+ Promo savings + + {discountedValues.formatted} + +
+ )} + + )} +
+ Sub Total + + {cart.data?.meta?.display_price?.without_tax?.formatted} + +
Shipping Calculated at checkout
- - +
{/* Sum Total */} + {/* Total Savings */} + {(hasSalePricing || hasPromotion) && ( +
+ Your savings + {formattedTotalCartSavings} +
+ )}
); } diff --git a/examples/core/src/app/[lang]/(store)/cart/YourBag.tsx b/examples/core/src/app/[lang]/(store)/cart/YourBag.tsx index 0c428106..24932e9b 100644 --- a/examples/core/src/app/[lang]/(store)/cart/YourBag.tsx +++ b/examples/core/src/app/[lang]/(store)/cart/YourBag.tsx @@ -1,11 +1,13 @@ import { CartItemWide } from "./CartItemWide"; -import { CartIncluded } from "@epcc-sdk/sdks-shopper"; +import { CartIncluded, ResponseCurrency } from "@epcc-sdk/sdks-shopper"; import { groupCartItems } from "src/lib/group-cart-items"; export function YourBag({ cart, + currency, }: { cart: NonNullable; + currency?: ResponseCurrency; }) { const groupedItems = groupCartItems(cart ?? []); const items = [ @@ -21,7 +23,7 @@ export function YourBag({ key={item.id} className="self-stretch border-t border-zinc-300 py-5" > - + ); })} diff --git a/examples/core/src/app/[lang]/(store)/cart/page.tsx b/examples/core/src/app/[lang]/(store)/cart/page.tsx index 11bd6611..d7a9a728 100644 --- a/examples/core/src/app/[lang]/(store)/cart/page.tsx +++ b/examples/core/src/app/[lang]/(store)/cart/page.tsx @@ -3,20 +3,30 @@ import { CartSidebar } from "./CartSidebar"; import { Button } from "src/components/button/Button"; import Link from "next/link"; import { LockClosedIcon } from "@heroicons/react/24/solid"; -import { getACart } from "@epcc-sdk/sdks-shopper"; +import { getACart, getAllCurrencies, getByContextProduct } from "@epcc-sdk/sdks-shopper"; import { CART_COOKIE_NAME } from "src/lib/cookie-constants"; import { cookies } from "next/headers"; import { createElasticPathClient } from "src/lib/create-elastic-path-client"; import { TAGS } from "src/lib/constants"; +import { getPreferredCurrency } from "src/lib/get-locale-currency"; -export default async function CartPage() { +export default async function CartPage({ params }: { params: Promise<{ lang: string }> }) { const cartCookie = (await cookies()).get(CART_COOKIE_NAME); const client = createElasticPathClient(); + const { lang } = await params; if (!cartCookie) { throw new Error("Cart cookie not found"); } + const currencies = await getAllCurrencies({ + client, + next: { + tags: [TAGS.currencies], + }, + }); + const currency = getPreferredCurrency(lang, currencies.data?.data || []); + const cartResponse = await getACart({ path: { cartID: cartCookie.value, @@ -28,13 +38,43 @@ export default async function CartPage() { next: { tags: [TAGS.cart], }, + headers: { + "Accept-Language": lang, + "X-Moltin-Currency": currency?.code, + } + }); + + const cartCurrency = cartResponse.data?.data?.meta?.display_price?.with_tax?.currency; + const currencyUpdated = getPreferredCurrency(lang, currencies.data?.data || [], cartCurrency); + + // Fetch product details for each cart item to get original sale price + const cartItems = cartResponse?.data?.included?.items; + const productDetailsPromises = cartItems?.map(item => + getByContextProduct({ + client, + path: { product_id: item.product_id! }, + headers: { + "Accept-Language": lang, + "X-Moltin-Currency": currencyUpdated?.code, + } + }) + ); + const productDetails = await Promise.all(productDetailsPromises || []); + + // Merge product details into cart items + const cartItemsWithDetails = cartResponse?.data?.included?.items?.map(item => { + const productDetail = productDetails.find(pd => pd.data?.data?.id === item.product_id)?.data?.data; + return { + ...item, + productDetail, + }; }); if (!cartResponse.data) { return
Cart items not found
; } - const items = cartResponse.data.included?.items!; + const items = cartItemsWithDetails!; return ( <> @@ -45,12 +85,15 @@ export default async function CartPage() {

Your Bag

{/* Cart Items */} - +
{/* Sidebar */}
- +
diff --git a/examples/core/src/app/[lang]/(checkout)/checkout/ShippingSelector.tsx b/examples/core/src/app/[lang]/(checkout)/checkout/ShippingSelector.tsx index dc1b0b3e..4e0368bb 100644 --- a/examples/core/src/app/[lang]/(checkout)/checkout/ShippingSelector.tsx +++ b/examples/core/src/app/[lang]/(checkout)/checkout/ShippingSelector.tsx @@ -11,7 +11,7 @@ import { CheckoutForm as CheckoutFormSchemaType } from "src/components/checkout/ import { useEffect } from "react"; import { Skeleton } from "src/components/skeleton/Skeleton"; import { Button } from "src/components/button/Button"; -import Link from "next/link"; +import { LocaleLink } from "src/components/LocaleLink"; import { AccountAddressResponse } from "@epcc-sdk/sdks-shopper"; export function ShippingSelector({ @@ -80,7 +80,7 @@ export function ShippingSelector({ className="text-base font-normal" type="button" > - Add new... + Add new... diff --git a/examples/core/src/app/[lang]/(checkout)/not-found.tsx b/examples/core/src/app/[lang]/(checkout)/not-found.tsx index d97d88f4..b568b0d7 100644 --- a/examples/core/src/app/[lang]/(checkout)/not-found.tsx +++ b/examples/core/src/app/[lang]/(checkout)/not-found.tsx @@ -1,13 +1,13 @@ -import Link from "next/link"; +import { LocaleLink } from "src/components/LocaleLink"; export default function NotFound() { return (
404 - The page could not be found. - + Back to home - +
); } diff --git a/examples/core/src/app/[lang]/(store)/account/AccountNavigation.tsx b/examples/core/src/app/[lang]/(store)/account/AccountNavigation.tsx index 496d5a95..a08bf414 100644 --- a/examples/core/src/app/[lang]/(store)/account/AccountNavigation.tsx +++ b/examples/core/src/app/[lang]/(store)/account/AccountNavigation.tsx @@ -1,5 +1,5 @@ "use client"; -import Link from "next/link"; +import { LocaleLink } from "src/components/LocaleLink"; import { usePathname } from "next/navigation"; import { Button } from "src/components/button/Button"; import { logout } from "../../(auth)/actions"; @@ -18,7 +18,7 @@ export function AccountNavigation() { asChild reversed={!pathname.startsWith("/account/summary")} > - Account Info + Account Info
  • @@ -27,7 +27,7 @@ export function AccountNavigation() { asChild reversed={!pathname.startsWith("/account/orders")} > - My Orders + My Orders
  • @@ -36,7 +36,7 @@ export function AccountNavigation() { asChild reversed={!pathname.startsWith("/account/addresses")} > - Addresses + Addresses
  • diff --git a/examples/core/src/app/[lang]/(store)/account/addresses/[addressId]/page.tsx b/examples/core/src/app/[lang]/(store)/account/addresses/[addressId]/page.tsx index eacb33cd..bdf365c8 100644 --- a/examples/core/src/app/[lang]/(store)/account/addresses/[addressId]/page.tsx +++ b/examples/core/src/app/[lang]/(store)/account/addresses/[addressId]/page.tsx @@ -6,7 +6,7 @@ import { } from "src/lib/retrieve-account-member-credentials"; import { ACCOUNT_MEMBER_TOKEN_COOKIE_NAME } from "src/lib/cookie-constants"; import { Button } from "src/components/button/Button"; -import Link from "next/link"; +import { LocaleLink } from "src/components/LocaleLink"; import { ArrowLeftIcon } from "@heroicons/react/24/outline"; import React from "react"; import { Separator } from "src/components/separator/Separator"; @@ -54,10 +54,10 @@ export default async function Address(props: {
    diff --git a/examples/core/src/app/[lang]/(store)/account/addresses/add/page.tsx b/examples/core/src/app/[lang]/(store)/account/addresses/add/page.tsx index a294ed59..cd95df5f 100644 --- a/examples/core/src/app/[lang]/(store)/account/addresses/add/page.tsx +++ b/examples/core/src/app/[lang]/(store)/account/addresses/add/page.tsx @@ -3,7 +3,7 @@ import { redirect } from "next/navigation"; import { retrieveAccountMemberCredentials } from "src/lib/retrieve-account-member-credentials"; import { ACCOUNT_MEMBER_TOKEN_COOKIE_NAME } from "src/lib/cookie-constants"; import { Button } from "src/components/button/Button"; -import Link from "next/link"; +import { LocaleLink } from "src/components/LocaleLink"; import { ArrowLeftIcon } from "@heroicons/react/24/outline"; import React from "react"; import { Separator } from "src/components/separator/Separator"; @@ -27,10 +27,10 @@ export default async function AddAddress() {
    diff --git a/examples/core/src/app/[lang]/(store)/account/addresses/page.tsx b/examples/core/src/app/[lang]/(store)/account/addresses/page.tsx index 4ca5ea5b..cc3ff2c6 100644 --- a/examples/core/src/app/[lang]/(store)/account/addresses/page.tsx +++ b/examples/core/src/app/[lang]/(store)/account/addresses/page.tsx @@ -6,7 +6,7 @@ import { getSelectedAccount, retrieveAccountMemberCredentials, } from "src/lib/retrieve-account-member-credentials"; -import Link from "next/link"; +import { LocaleLink } from "src/components/LocaleLink"; import { Button } from "src/components/button/Button"; import { Separator } from "src/components/separator/Separator"; import React from "react"; @@ -69,10 +69,10 @@ export default async function Addresses() {
    @@ -83,10 +83,10 @@ export default async function Addresses() {
    diff --git a/examples/core/src/app/[lang]/(store)/account/orders/OrderItem.tsx b/examples/core/src/app/[lang]/(store)/account/orders/OrderItem.tsx index ceae9e61..abea298f 100644 --- a/examples/core/src/app/[lang]/(store)/account/orders/OrderItem.tsx +++ b/examples/core/src/app/[lang]/(store)/account/orders/OrderItem.tsx @@ -1,6 +1,6 @@ import { ReactNode } from "react"; import { ProductThumbnail } from "./[orderId]/ProductThumbnail"; -import Link from "next/link"; +import { LocaleLink } from "src/components/LocaleLink"; import { formatIsoDateString } from "src/lib/format-iso-date-string"; import { OrderItemResponse, OrderResponse } from "@epcc-sdk/sdks-shopper"; @@ -29,22 +29,22 @@ export function OrderItem({ return (
    - + - +
    Order # {order.external_ref ?? order.id} - +

    {formatOrderItemsTitle(sortedOrderItems)}

    - +
    {children}
    diff --git a/examples/core/src/app/[lang]/(store)/account/orders/[orderId]/OrderLineItem.tsx b/examples/core/src/app/[lang]/(store)/account/orders/[orderId]/OrderLineItem.tsx index 9c690fbf..d0ddf63e 100644 --- a/examples/core/src/app/[lang]/(store)/account/orders/[orderId]/OrderLineItem.tsx +++ b/examples/core/src/app/[lang]/(store)/account/orders/[orderId]/OrderLineItem.tsx @@ -1,5 +1,5 @@ import { ProductThumbnail } from "./ProductThumbnail"; -import Link from "next/link"; +import { LocaleLink } from "src/components/LocaleLink"; import { ElasticPathFile, OrderItemResponse } from "@epcc-sdk/sdks-shopper"; export function OrderLineItem({ @@ -12,20 +12,20 @@ export function OrderLineItem({ return (
    - + - +
    - +

    {orderItem.name}

    - +
    Quantity: {orderItem.quantity} diff --git a/examples/core/src/app/[lang]/(store)/account/orders/[orderId]/page.tsx b/examples/core/src/app/[lang]/(store)/account/orders/[orderId]/page.tsx index dd185f2f..99953c29 100644 --- a/examples/core/src/app/[lang]/(store)/account/orders/[orderId]/page.tsx +++ b/examples/core/src/app/[lang]/(store)/account/orders/[orderId]/page.tsx @@ -4,7 +4,7 @@ import { notFound, redirect } from "next/navigation"; import { retrieveAccountMemberCredentials } from "src/lib/retrieve-account-member-credentials"; import { Button } from "src/components/button/Button"; import { ArrowLeftIcon } from "@heroicons/react/24/outline"; -import Link from "next/link"; +import { LocaleLink } from "src/components/LocaleLink"; import { formatIsoDateString } from "src/lib/format-iso-date-string"; import { OrderLineItem } from "./OrderLineItem"; import { createElasticPathClient } from "src/lib/create-elastic-path-client"; @@ -91,10 +91,10 @@ export default async function Order(props: {
    diff --git a/examples/core/src/app/[lang]/(store)/cart/CartItem.tsx b/examples/core/src/app/[lang]/(store)/cart/CartItem.tsx index eeaf16c5..49f0e4e7 100644 --- a/examples/core/src/app/[lang]/(store)/cart/CartItem.tsx +++ b/examples/core/src/app/[lang]/(store)/cart/CartItem.tsx @@ -1,6 +1,6 @@ import { ProductThumbnail } from "../account/orders/[orderId]/ProductThumbnail"; import { NumberInput } from "src/components/number-input/NumberInput"; -import Link from "next/link"; +import { LocaleLink } from "src/components/LocaleLink"; import { RemoveCartItemButton } from "src/components/cart/RemoveCartItemButton"; import { Item } from "src/lib/group-cart-items"; import { ResponseCurrency } from "@epcc-sdk/sdks-shopper"; @@ -63,9 +63,9 @@ export function CartItem({ item, thumbnail, currency }: CartItemProps) {
    {itemLink ? ( - + {item.name} - + ) : ( {item.name} )} diff --git a/examples/core/src/app/[lang]/(store)/cart/CartItemWide.tsx b/examples/core/src/app/[lang]/(store)/cart/CartItemWide.tsx index e1d763a3..65a520c3 100644 --- a/examples/core/src/app/[lang]/(store)/cart/CartItemWide.tsx +++ b/examples/core/src/app/[lang]/(store)/cart/CartItemWide.tsx @@ -1,5 +1,5 @@ import { ProductThumbnail } from "../account/orders/[orderId]/ProductThumbnail"; -import Link from "next/link"; +import { LocaleLink } from "src/components/LocaleLink"; import { NumberInput } from "src/components/number-input/NumberInput"; import { CartItemProps } from "./CartItem"; import { RemoveCartItemButton } from "src/components/cart/RemoveCartItemButton"; @@ -10,8 +10,6 @@ export function CartItemWide({ item, thumbnail, currency }: CartItemProps) { return
    Missing cart item data
    ; } - console.log("CartItemWide currency:", currency); - let itemLink = null; if (item.product_id) { itemLink = `/products/${item.product_id}`; @@ -60,9 +58,9 @@ export function CartItemWide({ item, thumbnail, currency }: CartItemProps) {
    {itemLink ? ( - + {item.name} - + ) : ( {item.name} )} diff --git a/examples/core/src/app/[lang]/(store)/cart/page.tsx b/examples/core/src/app/[lang]/(store)/cart/page.tsx index d7a9a728..41635340 100644 --- a/examples/core/src/app/[lang]/(store)/cart/page.tsx +++ b/examples/core/src/app/[lang]/(store)/cart/page.tsx @@ -1,7 +1,7 @@ import { YourBag } from "./YourBag"; import { CartSidebar } from "./CartSidebar"; import { Button } from "src/components/button/Button"; -import Link from "next/link"; +import { LocaleLink } from "src/components/LocaleLink"; import { LockClosedIcon } from "@heroicons/react/24/solid"; import { getACart, getAllCurrencies, getByContextProduct } from "@epcc-sdk/sdks-shopper"; import { CART_COOKIE_NAME } from "src/lib/cookie-constants"; @@ -95,10 +95,10 @@ export default async function CartPage({ params }: { params: Promise<{ lang: str storeCurrency={currencyUpdated} />
    @@ -112,7 +112,7 @@ export default async function CartPage({ params }: { params: Promise<{ lang: str

    Your cart is empty

    diff --git a/examples/core/src/app/[lang]/(store)/not-found.tsx b/examples/core/src/app/[lang]/(store)/not-found.tsx index d97d88f4..b568b0d7 100644 --- a/examples/core/src/app/[lang]/(store)/not-found.tsx +++ b/examples/core/src/app/[lang]/(store)/not-found.tsx @@ -1,13 +1,13 @@ -import Link from "next/link"; +import { LocaleLink } from "src/components/LocaleLink"; export default function NotFound() { return (
    404 - The page could not be found. - + Back to home - +
    ); } diff --git a/examples/core/src/app/[lang]/configuration-error/page.tsx b/examples/core/src/app/[lang]/configuration-error/page.tsx index 6ce5e299..b67b3869 100644 --- a/examples/core/src/app/[lang]/configuration-error/page.tsx +++ b/examples/core/src/app/[lang]/configuration-error/page.tsx @@ -1,4 +1,4 @@ -import Link from "next/link"; +import { LocaleLink } from "src/components/LocaleLink"; import { Metadata } from "next"; export const metadata: Metadata = { @@ -29,12 +29,12 @@ export default async function ConfigurationErrorPage(props: Props) { There is a problem with the stores setup - Refresh - + diff --git a/examples/core/src/app/[lang]/error.tsx b/examples/core/src/app/[lang]/error.tsx index f4724026..d96ffebd 100644 --- a/examples/core/src/app/[lang]/error.tsx +++ b/examples/core/src/app/[lang]/error.tsx @@ -1,5 +1,5 @@ "use client"; -import Link from "next/link"; +import { LocaleLink } from "../../components/LocaleLink"; export default function GlobalError({ error, @@ -15,9 +15,9 @@ export default function GlobalError({ {error.digest} - Internal server error. - + Back to home - + @@ -243,7 +243,7 @@ export function CartSheet({ asChild className="self-stretch" > - Go to bag + Go to bag diff --git a/examples/core/src/components/checkout-item/CheckoutItem.tsx b/examples/core/src/components/checkout-item/CheckoutItem.tsx index 2e9e4e53..cdabd7a3 100644 --- a/examples/core/src/components/checkout-item/CheckoutItem.tsx +++ b/examples/core/src/components/checkout-item/CheckoutItem.tsx @@ -1,8 +1,7 @@ "use client"; import { ProductThumbnail } from "../../app/[lang]/(store)/account/orders/[orderId]/ProductThumbnail"; -import Link from "next/link"; +import { LocaleLink } from "../LocaleLink"; import { Item } from "../../lib/group-cart-items"; -import { formatCurrency } from "src/lib/format-currency"; import { ResponseCurrency } from "@epcc-sdk/sdks-shopper"; import { calculateMultiItemOriginalTotal, calculateSaleAmount, calculateTotalSavings, getFormattedPercentage, getFormattedValue } from "src/lib/price-calculation"; @@ -62,9 +61,9 @@ export function CheckoutItem({
    - + {item.name} - + Quantity: {item.quantity}
    diff --git a/examples/core/src/components/featured-products/FeaturedProducts.tsx b/examples/core/src/components/featured-products/FeaturedProducts.tsx index fa5c52d1..bf786a5c 100644 --- a/examples/core/src/components/featured-products/FeaturedProducts.tsx +++ b/examples/core/src/components/featured-products/FeaturedProducts.tsx @@ -1,6 +1,6 @@ "use server"; import clsx from "clsx"; -import Link from "next/link"; +import { LocaleLink } from "../LocaleLink"; import { ArrowRightIcon, EyeSlashIcon } from "@heroicons/react/24/outline"; import Image from "next/image"; import { fetchFeaturedProducts } from "./fetchFeaturedProducts"; @@ -33,14 +33,14 @@ export default async function FeaturedProducts({ {title} {linkProps && ( - {linkProps.text} - + )}
      {products.map((product) => ( - +
    • @@ -78,7 +78,7 @@ export default async function FeaturedProducts({ {product.meta?.display_price?.without_tax?.formatted}

    • - +
      ))}
    diff --git a/examples/core/src/components/footer/Footer.tsx b/examples/core/src/components/footer/Footer.tsx index 0147bf42..4b9c2fa0 100644 --- a/examples/core/src/components/footer/Footer.tsx +++ b/examples/core/src/components/footer/Footer.tsx @@ -1,23 +1,13 @@ "use client"; import Link from "next/link"; +import { LocaleLink } from "../LocaleLink"; import { PhoneIcon, InformationCircleIcon } from "@heroicons/react/24/solid"; import { GitHubIcon } from "../icons/github-icon"; import EpLogo from "../icons/ep-logo"; import type { JSX } from "react"; -import { useLocalePath } from "src/lib/get-locale-path"; const Footer = (): JSX.Element => { - const home = useLocalePath("/"); - const shipping = useLocalePath("/shipping"); - const faq = useLocalePath("/faq"); - const about = useLocalePath("/about"); - const terms = useLocalePath("/terms"); - const support = useLocalePath("/support"); - - console.log("home: ", home) - console.log("shipping: ", shipping) - return (
    @@ -26,26 +16,26 @@ const Footer = (): JSX.Element => {
    - + Home - - + + Shipping - - + + FAQ - +
    - + About - - + + Terms - - + + Support - +
    diff --git a/examples/core/src/components/header/AccountMobileMenu.tsx b/examples/core/src/components/header/AccountMobileMenu.tsx index 5bffece6..2d81dbdc 100644 --- a/examples/core/src/components/header/AccountMobileMenu.tsx +++ b/examples/core/src/components/header/AccountMobileMenu.tsx @@ -1,6 +1,6 @@ "use client"; import { usePathname } from "next/navigation"; -import Link from "next/link"; +import { LocaleLink } from "../LocaleLink"; import { ArrowLeftOnRectangleIcon, ArrowRightOnRectangleIcon, @@ -35,13 +35,13 @@ export function AccountMobileMenu({ pathname={{ target: "/login", current: pathname }} asChild > - +
    @@ -51,10 +51,10 @@ export function AccountMobileMenu({ pathname={{ target: "/register", current: pathname }} asChild > - +
    @@ -68,10 +68,10 @@ export function AccountMobileMenu({ pathname={{ target: "/account/summary", current: pathname }} asChild > - +
    @@ -81,13 +81,13 @@ export function AccountMobileMenu({ pathname={{ target: "/account/orders", current: pathname }} asChild > - + @@ -97,10 +97,10 @@ export function AccountMobileMenu({ pathname={{ target: "/account/addresses", current: pathname }} asChild > - + diff --git a/examples/core/src/components/header/Header.tsx b/examples/core/src/components/header/Header.tsx index 86ac4cb4..1bda1af2 100644 --- a/examples/core/src/components/header/Header.tsx +++ b/examples/core/src/components/header/Header.tsx @@ -1,6 +1,6 @@ import MobileNavBar from "./navigation/MobileNavBar"; import NavBar from "./navigation/NavBar"; -import Link from "next/link"; +import { LocaleLink } from "../LocaleLink"; import EpIcon from "../icons/ep-icon"; import { Suspense } from "react"; import { AccountMenu } from "./account/AccountMenu"; @@ -14,9 +14,9 @@ const Header = async ({ lang }: { lang: string }) => {
    - + - +
    diff --git a/examples/core/src/components/header/account/AccountPopover.tsx b/examples/core/src/components/header/account/AccountPopover.tsx index 2712ab27..1858307e 100644 --- a/examples/core/src/components/header/account/AccountPopover.tsx +++ b/examples/core/src/components/header/account/AccountPopover.tsx @@ -12,7 +12,7 @@ import { UserIcon, UserPlusIcon, } from "@heroicons/react/24/outline"; -import Link from "next/link"; +import { LocaleLink } from "../../LocaleLink"; import { AccountMemberResponse } from "@epcc-sdk/sdks-shopper"; import { retrieveAccountMemberCredentials } from "../../../lib/retrieve-account-member-credentials"; import { @@ -63,13 +63,13 @@ export function AccountPopover({ pathname.startsWith("/login") && "font-semibold", )} > - +
    @@ -79,13 +79,13 @@ export function AccountPopover({ pathname.startsWith("/register") && "font-semibold", )} > - +
    @@ -99,13 +99,13 @@ export function AccountPopover({ pathname.startsWith("/summary") && "font-semibold", )} > - +
    @@ -115,13 +115,13 @@ export function AccountPopover({ pathname.startsWith("/orders") && "font-semibold", )} > - +
    @@ -131,10 +131,10 @@ export function AccountPopover({ pathname.startsWith("/addresses") && "font-semibold", )} > - +
    diff --git a/examples/core/src/components/header/navigation/MobileNavBar.tsx b/examples/core/src/components/header/navigation/MobileNavBar.tsx index dc6f0525..98a2cb57 100644 --- a/examples/core/src/components/header/navigation/MobileNavBar.tsx +++ b/examples/core/src/components/header/navigation/MobileNavBar.tsx @@ -1,5 +1,5 @@ "use server"; -import Link from "next/link"; +import { LocaleLink } from "src/components/LocaleLink"; import EpIcon from "../../icons/ep-icon"; import { MobileNavBarButton } from "./MobileNavBarButton"; import { buildSiteNavigation } from "../../../lib/build-site-navigation"; @@ -102,9 +102,9 @@ export default async function MobileNavBar() { accountMemberTokens={accountMemberCookie} />
    - + - +
    }> diff --git a/examples/core/src/components/header/navigation/NavBarPopover.tsx b/examples/core/src/components/header/navigation/NavBarPopover.tsx index cb580196..59df4fe0 100644 --- a/examples/core/src/components/header/navigation/NavBarPopover.tsx +++ b/examples/core/src/components/header/navigation/NavBarPopover.tsx @@ -9,7 +9,7 @@ import { NavigationMenuList, NavigationMenuTrigger, } from "../../navigation-menu/NavigationMenu"; -import Link from "next/link"; +import { LocaleLink } from "src/components/LocaleLink"; import { ArrowRightIcon } from "@heroicons/react/20/solid"; export function NavBarPopover({ @@ -22,7 +22,7 @@ export function NavBarPopover({
    {item.name} {item.children.map((child: NavigationNode) => ( - {child.name} - + ))} - + Browse All - +
    ); }; @@ -63,7 +63,7 @@ export function NavBarPopover({ )}

    - - +
    diff --git a/examples/core/src/components/header/navigation/NavItemContent.tsx b/examples/core/src/components/header/navigation/NavItemContent.tsx index d9abb444..703f1cf5 100644 --- a/examples/core/src/components/header/navigation/NavItemContent.tsx +++ b/examples/core/src/components/header/navigation/NavItemContent.tsx @@ -1,4 +1,4 @@ -import Link from "next/link"; +import { LocaleLink } from "../../LocaleLink"; import { NavigationNode } from "../../../lib/build-site-navigation"; import { ArrowRightIcon } from "@heroicons/react/20/solid"; @@ -15,7 +15,7 @@ const NavItemContent = ({ item, setOpen }: IProps): JSX.Element => {
    {item.name} {item.children.map((child: NavigationNode) => ( - setOpen && setOpen(false)} @@ -23,16 +23,16 @@ const NavItemContent = ({ item, setOpen }: IProps): JSX.Element => { className="hover:text-brand-primary hover:underline" > {child.name} - + ))} - setOpen && setOpen(false)} passHref className="hover:text-brand-primary hover:underline font-semibold" > Browse All - +
    ); }; @@ -45,7 +45,7 @@ const NavItemContent = ({ item, setOpen }: IProps): JSX.Element => { })}
    - setOpen && setOpen(false)} @@ -53,7 +53,7 @@ const NavItemContent = ({ item, setOpen }: IProps): JSX.Element => { > Browse All {item.name} - + ); }; diff --git a/examples/core/src/components/search/Hit.tsx b/examples/core/src/components/search/Hit.tsx index 58bac822..22193ebf 100644 --- a/examples/core/src/components/search/Hit.tsx +++ b/examples/core/src/components/search/Hit.tsx @@ -1,4 +1,4 @@ -import Link from "next/link"; +import { LocaleLink } from "../LocaleLink"; import Price from "../product/Price"; import StrikePrice from "../product/StrikePrice"; import { EP_CURRENCY_CODE } from "../../lib/resolve-ep-currency-code"; @@ -26,7 +26,7 @@ export default function HitComponent({ return ( <> - +
    - +

    {hit.attributes?.name}

    - +
    {hit.attributes?.description} @@ -80,7 +80,7 @@ export default function HitComponent({
    - +
    ); } diff --git a/examples/core/src/components/search/NodeMenu.tsx b/examples/core/src/components/search/NodeMenu.tsx index 9d0b0563..3a6b199e 100644 --- a/examples/core/src/components/search/NodeMenu.tsx +++ b/examples/core/src/components/search/NodeMenu.tsx @@ -1,6 +1,6 @@ import { clsx } from "clsx"; import { usePathname } from "next/navigation"; -import Link from "next/link"; +import { LocaleLink } from "../LocaleLink"; import type { JSX } from "react"; import { NavigationNode } from "../../lib/build-site-navigation"; @@ -34,7 +34,7 @@ function MenuItem({ item }: MenuItemProps): JSX.Element { activeItem && clsx("ais-HierarchicalMenu-item--selected"), )} > - {item.name} - + {activeItem && !!item.children?.length && (
    diff --git a/examples/core/src/lib/get-locale-path.ts b/examples/core/src/lib/get-locale-path.ts deleted file mode 100644 index eb5c7de5..00000000 --- a/examples/core/src/lib/get-locale-path.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { useParams } from "next/navigation"; - -export function useLocalePath(path: string) { - const { lang } = useParams(); - return lang ? `/${lang}${path}` : path; -} From 2e770aca82f03494d0531655a4cf18259e017fe6 Mon Sep 17 00:00:00 2001 From: Muhammad Zain Tariq <49867382+mzaintariq@users.noreply.github.com> Date: Thu, 4 Dec 2025 18:23:40 +0500 Subject: [PATCH 08/14] update i18n file --- .../(checkout)/checkout/CheckoutSidebar.tsx | 2 +- .../app/[lang]/(checkout)/checkout/page.tsx | 2 +- .../core/src/app/[lang]/(store)/cart/page.tsx | 2 +- .../(store)/products/[productId]/page.tsx | 2 +- .../core/src/components/cart/CartSheet.tsx | 2 +- .../src/components/header/navigation/Cart.tsx | 2 +- examples/core/src/lib/get-locale-currency.ts | 20 ------------------- examples/core/src/lib/i18n.ts | 20 +++++++++++++++++++ 8 files changed, 26 insertions(+), 26 deletions(-) delete mode 100644 examples/core/src/lib/get-locale-currency.ts diff --git a/examples/core/src/app/[lang]/(checkout)/checkout/CheckoutSidebar.tsx b/examples/core/src/app/[lang]/(checkout)/checkout/CheckoutSidebar.tsx index e58b4a43..c3b85787 100644 --- a/examples/core/src/app/[lang]/(checkout)/checkout/CheckoutSidebar.tsx +++ b/examples/core/src/app/[lang]/(checkout)/checkout/CheckoutSidebar.tsx @@ -18,7 +18,7 @@ import { getACart, ResponseCurrency } from "@epcc-sdk/sdks-shopper"; import { ItemSidebarHideable } from "src/components/checkout-sidebar/ItemSidebarHideable"; import { groupCartItems } from "src/lib/group-cart-items"; import { useParams } from "next/navigation"; -import { getPreferredCurrency } from "src/lib/get-locale-currency"; +import { getPreferredCurrency } from "src/lib/i18n"; export function CheckoutSidebar({ cart, diff --git a/examples/core/src/app/[lang]/(checkout)/checkout/page.tsx b/examples/core/src/app/[lang]/(checkout)/checkout/page.tsx index b72ece29..146b85e7 100644 --- a/examples/core/src/app/[lang]/(checkout)/checkout/page.tsx +++ b/examples/core/src/app/[lang]/(checkout)/checkout/page.tsx @@ -10,7 +10,7 @@ import { createElasticPathClient } from "src/lib/create-elastic-path-client"; import { OrderConfirmationProvider } from "./OrderConfirmationProvider"; import { TAGS } from "src/lib/constants"; import { isAccountAuthenticated } from "@epcc-sdk/sdks-nextjs"; -import { getPreferredCurrency } from "src/lib/get-locale-currency"; +import { getPreferredCurrency } from "src/lib/i18n"; export const metadata: Metadata = { title: "Checkout", diff --git a/examples/core/src/app/[lang]/(store)/cart/page.tsx b/examples/core/src/app/[lang]/(store)/cart/page.tsx index 41635340..0537803b 100644 --- a/examples/core/src/app/[lang]/(store)/cart/page.tsx +++ b/examples/core/src/app/[lang]/(store)/cart/page.tsx @@ -8,7 +8,7 @@ import { CART_COOKIE_NAME } from "src/lib/cookie-constants"; import { cookies } from "next/headers"; import { createElasticPathClient } from "src/lib/create-elastic-path-client"; import { TAGS } from "src/lib/constants"; -import { getPreferredCurrency } from "src/lib/get-locale-currency"; +import { getPreferredCurrency } from "src/lib/i18n"; export default async function CartPage({ params }: { params: Promise<{ lang: string }> }) { const cartCookie = (await cookies()).get(CART_COOKIE_NAME); diff --git a/examples/core/src/app/[lang]/(store)/products/[productId]/page.tsx b/examples/core/src/app/[lang]/(store)/products/[productId]/page.tsx index ec5a0b90..52742f03 100644 --- a/examples/core/src/app/[lang]/(store)/products/[productId]/page.tsx +++ b/examples/core/src/app/[lang]/(store)/products/[productId]/page.tsx @@ -16,7 +16,7 @@ import { VariationProductProvider } from "src/components/product/variations/Vari import { VariationProductContent } from "src/components/product/variations/VariationProductContent"; import { BundleProductProvider } from "src/components/product/bundles/BundleProductProvider"; import { BundleProductContent } from "src/components/product/bundles/BundleProductContent"; -import { getPreferredCurrency } from "src/lib/get-locale-currency"; +import { getPreferredCurrency } from "src/lib/i18n"; import { TAGS } from "src/lib/constants"; export const dynamic = "force-dynamic"; diff --git a/examples/core/src/components/cart/CartSheet.tsx b/examples/core/src/components/cart/CartSheet.tsx index d96cc399..d6c5c901 100644 --- a/examples/core/src/components/cart/CartSheet.tsx +++ b/examples/core/src/components/cart/CartSheet.tsx @@ -21,7 +21,7 @@ import { groupCartItems } from "../../lib/group-cart-items"; import { RemoveCartPromotionXButton } from "./RemoveCartPromotionXButton"; import { formatCurrency } from "src/lib/format-currency"; import { useParams } from "next/navigation"; -import { getPreferredCurrency } from "src/lib/get-locale-currency"; +import { getPreferredCurrency } from "src/lib/i18n"; export function CartSheet({ cart, diff --git a/examples/core/src/components/header/navigation/Cart.tsx b/examples/core/src/components/header/navigation/Cart.tsx index cc495640..dea4e987 100644 --- a/examples/core/src/components/header/navigation/Cart.tsx +++ b/examples/core/src/components/header/navigation/Cart.tsx @@ -6,7 +6,7 @@ import { cookies } from "next/headers"; import { CART_COOKIE_NAME } from "../../../lib/cookie-constants"; import { getACart, getAllCurrencies, getByContextAllProducts } from "@epcc-sdk/sdks-shopper"; import { TAGS } from "../../../lib/constants"; -import { getPreferredCurrency } from "src/lib/get-locale-currency"; +import { getPreferredCurrency } from "src/lib/i18n"; export async function Cart({ lang }: { lang: string }) { const client = createElasticPathClient(); diff --git a/examples/core/src/lib/get-locale-currency.ts b/examples/core/src/lib/get-locale-currency.ts deleted file mode 100644 index 53ad4c58..00000000 --- a/examples/core/src/lib/get-locale-currency.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { ResponseCurrency } from "@epcc-sdk/sdks-shopper"; -import { LOCALE_TO_CURRENCY } from "./i18n"; - -export function getPreferredCurrency(lang: string | undefined, currencies: ResponseCurrency[], cartCurrencyCode?: string) { - if (!currencies.length) return undefined; - - const preferredCode = cartCurrencyCode - ? cartCurrencyCode - : lang - ? LOCALE_TO_CURRENCY[lang] - : undefined - - let currency = currencies.find((c: any) => c.code === preferredCode && c.enabled) - - if (!currency) { - currency = currencies.find((c: any) => c.default && c.enabled); - } - - return currency; -} \ No newline at end of file diff --git a/examples/core/src/lib/i18n.ts b/examples/core/src/lib/i18n.ts index c69bfdde..c74ec79c 100644 --- a/examples/core/src/lib/i18n.ts +++ b/examples/core/src/lib/i18n.ts @@ -1,3 +1,5 @@ +import { ResponseCurrency } from "@epcc-sdk/sdks-shopper"; + export const SUPPORTED_LOCALES = ["en", "fr", "de", "es", "en-GB"]; export const LOCALE_TO_CURRENCY: Record = { @@ -6,3 +8,21 @@ export const LOCALE_TO_CURRENCY: Record = { de: "EUR", "en-GB": "GBP", }; + +export function getPreferredCurrency(lang: string | undefined, currencies: ResponseCurrency[], cartCurrencyCode?: string) { + if (!currencies.length) return undefined; + + const preferredCode = cartCurrencyCode + ? cartCurrencyCode + : lang + ? LOCALE_TO_CURRENCY[lang] + : undefined + + let currency = currencies.find((c: any) => c.code === preferredCode && c.enabled) + + if (!currency) { + currency = currencies.find((c: any) => c.default && c.enabled); + } + + return currency; +}; From 40dba1f3c326572e139c220e485529d6013063db Mon Sep 17 00:00:00 2001 From: Muhammad Zain Tariq <49867382+mzaintariq@users.noreply.github.com> Date: Thu, 4 Dec 2025 22:49:06 +0500 Subject: [PATCH 09/14] update redirects to use lang/locale --- .../core/src/app/[lang]/(auth)/actions.ts | 15 ++++---- .../src/app/[lang]/(auth)/login/LoginForm.tsx | 4 +- .../core/src/app/[lang]/(auth)/login/page.tsx | 6 ++- .../src/app/[lang]/(auth)/register/page.tsx | 13 +++++-- .../(checkout)/checkout/AccountDisplay.tsx | 4 +- .../app/[lang]/(checkout)/checkout/actions.ts | 3 +- .../(checkout)/checkout/checkout-provider.tsx | 7 +++- .../(store)/account/AccountNavigation.tsx | 5 ++- .../account/addresses/[addressId]/page.tsx | 5 ++- .../(store)/account/addresses/actions.ts | 4 +- .../(store)/account/addresses/add/AddForm.tsx | 4 +- .../(store)/account/addresses/add/page.tsx | 8 ++-- .../[lang]/(store)/account/addresses/page.tsx | 6 ++- .../(store)/account/orders/[orderId]/page.tsx | 5 ++- .../[lang]/(store)/account/orders/page.tsx | 6 ++- .../[lang]/(store)/account/summary/page.tsx | 5 ++- .../components/header/AccountMobileMenu.tsx | 36 +++++++++--------- .../core/src/components/header/Header.tsx | 2 +- .../components/header/account/AccountMenu.tsx | 4 +- .../header/account/AccountPopover.tsx | 38 +++++++++---------- .../header/account/AccountSwitcher.tsx | 3 +- .../navigation/MobileAccountSwitcher.tsx | 3 ++ 22 files changed, 110 insertions(+), 76 deletions(-) diff --git a/examples/core/src/app/[lang]/(auth)/actions.ts b/examples/core/src/app/[lang]/(auth)/actions.ts index db8e8334..7ac98038 100644 --- a/examples/core/src/app/[lang]/(auth)/actions.ts +++ b/examples/core/src/app/[lang]/(auth)/actions.ts @@ -32,7 +32,7 @@ const PASSWORD_PROFILE_ID = process.env.NEXT_PUBLIC_PASSWORD_PROFILE_ID!; const loginErrorMessage = "Failed to login, make sure your email and password are correct"; -export async function login(props: FormData) { +export async function login(props: FormData, lang: string) { const client = createElasticPathClient(); const rawEntries = Object.fromEntries(props.entries()); @@ -77,15 +77,15 @@ export async function login(props: FormData) { }; } - redirect(returnUrl ?? "/"); + redirect(returnUrl ?? (lang ? `/${lang}/` : "/")); } -export async function logout() { +export async function logout(lang?: string) { const cookieStore = await cookies(); cookieStore.delete(ACCOUNT_MEMBER_TOKEN_COOKIE_NAME); - redirect("/"); + redirect(lang ? `/${lang}/` : "/"); } export async function selectedAccount(args: FormData) { @@ -106,8 +106,9 @@ export async function selectedAccount(args: FormData) { ACCOUNT_MEMBER_TOKEN_COOKIE_NAME, ); + const lang = args?.get("lang")?.toString(); if (!accountMemberCredentials) { - redirect("/login"); + redirect(lang ? `/${lang}/login` : "/login"); return; } @@ -141,7 +142,7 @@ export async function selectedAccount(args: FormData) { await Promise.all(promises); } -export async function register(data: FormData) { +export async function register(data: FormData, lang: string) { const client = await createElasticPathClient(); const validatedProps = registerSchema.safeParse( @@ -178,5 +179,5 @@ export async function register(data: FormData) { cookieStore.set(createCookieFromGenerateTokenResponse(result.data)); - redirect("/"); + redirect(lang ? `/${lang}/` : "/"); } diff --git a/examples/core/src/app/[lang]/(auth)/login/LoginForm.tsx b/examples/core/src/app/[lang]/(auth)/login/LoginForm.tsx index dc6c0187..3d5d434e 100644 --- a/examples/core/src/app/[lang]/(auth)/login/LoginForm.tsx +++ b/examples/core/src/app/[lang]/(auth)/login/LoginForm.tsx @@ -5,12 +5,14 @@ import { Label } from "src/components/label/Label"; import { Input } from "src/components/input/Input"; import { FormStatusButton } from "src/components/button/FormStatusButton"; import { useState } from "react"; +import { useParams } from "next/navigation"; export function LoginForm({ returnUrl }: { returnUrl?: string }) { + const { lang } = useParams(); const [error, setError] = useState(undefined); async function loginAction(formData: FormData) { - const result = await login(formData); + const result = await login(formData, lang as string); if ("error" in result) { setError(result.error); diff --git a/examples/core/src/app/[lang]/(auth)/login/page.tsx b/examples/core/src/app/[lang]/(auth)/login/page.tsx index c0a7e639..8d306b0b 100644 --- a/examples/core/src/app/[lang]/(auth)/login/page.tsx +++ b/examples/core/src/app/[lang]/(auth)/login/page.tsx @@ -8,15 +8,19 @@ import { LoginForm } from "./LoginForm"; export default async function Login( props: { searchParams: Promise<{ returnUrl?: string }>; + params: Promise<{ lang?: string }>; } ) { const searchParams = await props.searchParams; const { returnUrl } = searchParams; + const params = await props.params; + const { lang } = params; + const cookieStore = await cookies(); if (isAccountMemberAuthenticated(cookieStore)) { - redirect("/account/summary"); + redirect(lang ? `/${lang}/account/summary` : "/account/summary"); } return ( diff --git a/examples/core/src/app/[lang]/(auth)/register/page.tsx b/examples/core/src/app/[lang]/(auth)/register/page.tsx index 9a9f28d1..4c3a756c 100644 --- a/examples/core/src/app/[lang]/(auth)/register/page.tsx +++ b/examples/core/src/app/[lang]/(auth)/register/page.tsx @@ -8,10 +8,11 @@ import { Label } from "src/components/label/Label"; import { Input } from "src/components/input/Input"; import { FormStatusButton } from "src/components/button/FormStatusButton"; -export default async function Register() { +export default async function Register({ params }: { params: Promise<{ lang: string }> }) { + const { lang } = await params; const cookieStore = await cookies(); if (isAccountMemberAuthenticated(cookieStore)) { - redirect("/account/summary"); + redirect(lang ? `/${lang}/account/summary` : "/account/summary"); } return ( @@ -27,7 +28,13 @@ export default async function Register() {
    - + { + "use server" + await register(formData, lang as string) + }} + >
    diff --git a/examples/core/src/app/[lang]/(checkout)/checkout/AccountDisplay.tsx b/examples/core/src/app/[lang]/(checkout)/checkout/AccountDisplay.tsx index ae2a806f..2fe1c99a 100644 --- a/examples/core/src/app/[lang]/(checkout)/checkout/AccountDisplay.tsx +++ b/examples/core/src/app/[lang]/(checkout)/checkout/AccountDisplay.tsx @@ -9,12 +9,14 @@ import { CheckoutForm as CheckoutFormSchemaType } from "src/components/checkout/ import { logout } from "../../(auth)/actions"; import { Skeleton } from "src/components/skeleton/Skeleton"; import { AccountMemberResponse } from "@epcc-sdk/sdks-shopper"; +import { useParams } from "next/navigation"; export function AccountDisplay({ accountMember, }: { accountMember: AccountMemberResponse; }) { + const { lang } = useParams(); const { control, setValue } = useFormContext(); const [_isPending, startTransition] = useTransition(); @@ -46,7 +48,7 @@ export function AccountDisplay({ diff --git a/examples/core/src/app/[lang]/(checkout)/checkout/actions.ts b/examples/core/src/app/[lang]/(checkout)/checkout/actions.ts index c2ec8d90..d7f7b40f 100644 --- a/examples/core/src/app/[lang]/(checkout)/checkout/actions.ts +++ b/examples/core/src/app/[lang]/(checkout)/checkout/actions.ts @@ -48,6 +48,7 @@ export type PaymentCompleteResponse = { export async function paymentComplete( props: CheckoutForm, + lang: string, ): Promise { const client = createElasticPathClient(); @@ -162,7 +163,7 @@ export async function paymentComplete( ); if (!accountMemberCredentials) { - return redirect("/login"); + return redirect(lang ? `/${lang}/login` : "/login"); } const selectedAccount = getSelectedAccount(accountMemberCredentials); diff --git a/examples/core/src/app/[lang]/(checkout)/checkout/checkout-provider.tsx b/examples/core/src/app/[lang]/(checkout)/checkout/checkout-provider.tsx index c53348ed..4ab4d7f2 100644 --- a/examples/core/src/app/[lang]/(checkout)/checkout/checkout-provider.tsx +++ b/examples/core/src/app/[lang]/(checkout)/checkout/checkout-provider.tsx @@ -15,6 +15,7 @@ import { ShippingMethod, staticDeliveryMethods } from "./useShippingMethod"; import { getACart } from "@epcc-sdk/sdks-shopper"; import { paymentComplete } from "./actions"; import { useSetOrderConfirmation } from "./OrderConfirmationProvider"; +import { useParams } from "next/navigation"; type CheckoutContext = { cart?: NonNullable>["data"]>; @@ -114,6 +115,7 @@ export function GuestCheckoutProvider({ children, type, }: CheckoutProviderProps) { + const { lang } = useParams(); const [isPending, startTransition] = useTransition(); const setConfirmationData = useSetOrderConfirmation(); @@ -125,7 +127,7 @@ export function GuestCheckoutProvider({ async function handleSubmit(data: CheckoutForm) { startTransition(async () => { - const result = await paymentComplete(data); + const result = await paymentComplete(data, lang as string); setConfirmationData(result); }); } @@ -150,6 +152,7 @@ export function GuestCheckoutProvider({ export function AccountCheckoutProvider({ children, }: Omit) { + const { lang } = useParams(); const [isPending, startTransition] = useTransition(); const setConfirmationData = useSetOrderConfirmation(); @@ -160,7 +163,7 @@ export function AccountCheckoutProvider({ async function handleSubmit(data: CheckoutForm) { startTransition(async () => { - const result = await paymentComplete(data); + const result = await paymentComplete(data, lang as string); setConfirmationData(result); }); } diff --git a/examples/core/src/app/[lang]/(store)/account/AccountNavigation.tsx b/examples/core/src/app/[lang]/(store)/account/AccountNavigation.tsx index a08bf414..ae7cdfcc 100644 --- a/examples/core/src/app/[lang]/(store)/account/AccountNavigation.tsx +++ b/examples/core/src/app/[lang]/(store)/account/AccountNavigation.tsx @@ -1,11 +1,12 @@ "use client"; import { LocaleLink } from "src/components/LocaleLink"; -import { usePathname } from "next/navigation"; +import { useParams, usePathname } from "next/navigation"; import { Button } from "src/components/button/Button"; import { logout } from "../../(auth)/actions"; import { useTransition } from "react"; export function AccountNavigation() { + const { lang } = useParams(); const pathname = usePathname(); const [_isPending, startTransition] = useTransition(); @@ -43,7 +44,7 @@ export function AccountNavigation() { diff --git a/examples/core/src/app/[lang]/(store)/account/addresses/[addressId]/page.tsx b/examples/core/src/app/[lang]/(store)/account/addresses/[addressId]/page.tsx index bdf365c8..4d51b1ad 100644 --- a/examples/core/src/app/[lang]/(store)/account/addresses/[addressId]/page.tsx +++ b/examples/core/src/app/[lang]/(store)/account/addresses/[addressId]/page.tsx @@ -17,10 +17,11 @@ import { getV2AccountAddress } from "@epcc-sdk/sdks-shopper"; export const dynamic = "force-dynamic"; export default async function Address(props: { - params: Promise<{ addressId: string }>; + params: Promise<{ addressId: string, lang: string }>; }) { const params = await props.params; const cookieStore = await cookies(); + const lang = params?.lang; const accountMemberCookie = retrieveAccountMemberCredentials( cookieStore, @@ -28,7 +29,7 @@ export default async function Address(props: { ); if (!accountMemberCookie) { - return redirect("/login"); + return redirect(lang ? `/${lang}/login` : "/login"); } const { addressId } = params; diff --git a/examples/core/src/app/[lang]/(store)/account/addresses/actions.ts b/examples/core/src/app/[lang]/(store)/account/addresses/actions.ts index 3b037d2b..8df65901 100644 --- a/examples/core/src/app/[lang]/(store)/account/addresses/actions.ts +++ b/examples/core/src/app/[lang]/(store)/account/addresses/actions.ts @@ -138,7 +138,7 @@ export async function updateAddress(formData: FormData) { } } -export async function addAddress(formData: FormData) { +export async function addAddress(formData: FormData, lang?: string) { const client = await createElasticPathClient(); const rawEntries = Object.fromEntries(formData.entries()); @@ -196,5 +196,5 @@ export async function addAddress(formData: FormData) { await Promise.all(revalidatePromises); - redirect(redirectUrl); + redirect(lang ? `/${lang}${redirectUrl}`: redirectUrl); } diff --git a/examples/core/src/app/[lang]/(store)/account/addresses/add/AddForm.tsx b/examples/core/src/app/[lang]/(store)/account/addresses/add/AddForm.tsx index 54c7f623..7c2cfdc7 100644 --- a/examples/core/src/app/[lang]/(store)/account/addresses/add/AddForm.tsx +++ b/examples/core/src/app/[lang]/(store)/account/addresses/add/AddForm.tsx @@ -12,14 +12,14 @@ import { FormStatusButton } from "src/components/button/FormStatusButton"; import React from "react"; import { countries as staticCountries } from "src/lib/all-countries"; -export function AddForm() { +export function AddForm({ lang }: { lang: string }) { const countries = staticCountries; return ( { "use server"; - await addAddress(formData); + await addAddress(formData, lang); }} className="flex flex-col gap-5" > diff --git a/examples/core/src/app/[lang]/(store)/account/addresses/add/page.tsx b/examples/core/src/app/[lang]/(store)/account/addresses/add/page.tsx index cd95df5f..7ef16fab 100644 --- a/examples/core/src/app/[lang]/(store)/account/addresses/add/page.tsx +++ b/examples/core/src/app/[lang]/(store)/account/addresses/add/page.tsx @@ -11,7 +11,9 @@ import { AddForm } from "./AddForm"; export const dynamic = "force-dynamic"; -export default async function AddAddress() { +export default async function AddAddress({ params }: { params: Promise<{ lang: string }> }) { + const { lang } = await params; + const cookieStore = await cookies(); const accountMemberCookie = retrieveAccountMemberCredentials( @@ -20,7 +22,7 @@ export default async function AddAddress() { ); if (!accountMemberCookie) { - return redirect("/login"); + return redirect(lang ? `/${lang}/login` : "/login"); } return ( @@ -36,7 +38,7 @@ export default async function AddAddress() {

    Add Address

    - +
    ); diff --git a/examples/core/src/app/[lang]/(store)/account/addresses/page.tsx b/examples/core/src/app/[lang]/(store)/account/addresses/page.tsx index cc3ff2c6..ca51fa43 100644 --- a/examples/core/src/app/[lang]/(store)/account/addresses/page.tsx +++ b/examples/core/src/app/[lang]/(store)/account/addresses/page.tsx @@ -17,7 +17,9 @@ import { TAGS } from "src/lib/constants"; export const dynamic = "force-dynamic"; -export default async function Addresses() { + +export default async function Addresses({ params }: { params: Promise<{ lang: string }> }) { + const { lang } = await params; const cookieStore = await cookies(); const accountMemberCookie = retrieveAccountMemberCredentials( @@ -26,7 +28,7 @@ export default async function Addresses() { ); if (!accountMemberCookie) { - return redirect("/login"); + return redirect(lang ? `/${lang}/login` : "/login"); } const selectedAccount = getSelectedAccount(accountMemberCookie); diff --git a/examples/core/src/app/[lang]/(store)/account/orders/[orderId]/page.tsx b/examples/core/src/app/[lang]/(store)/account/orders/[orderId]/page.tsx index 99953c29..d86aea40 100644 --- a/examples/core/src/app/[lang]/(store)/account/orders/[orderId]/page.tsx +++ b/examples/core/src/app/[lang]/(store)/account/orders/[orderId]/page.tsx @@ -17,10 +17,11 @@ import { extractCartItemMedia } from "../../../../(checkout)/checkout/extract-ca export const dynamic = "force-dynamic"; export default async function Order(props: { - params: Promise<{ orderId: string }>; + params: Promise<{ orderId: string, lang: string }>; }) { const params = await props.params; const cookieStore = await cookies(); + const lang = params?.lang; const accountMemberCookie = retrieveAccountMemberCredentials( cookieStore, @@ -28,7 +29,7 @@ export default async function Order(props: { ); if (!accountMemberCookie) { - return redirect("/login"); + return redirect(lang ? `/${lang}/login` : "/login"); } const client = createElasticPathClient(); diff --git a/examples/core/src/app/[lang]/(store)/account/orders/page.tsx b/examples/core/src/app/[lang]/(store)/account/orders/page.tsx index c1e8808c..2cfc6c1e 100644 --- a/examples/core/src/app/[lang]/(store)/account/orders/page.tsx +++ b/examples/core/src/app/[lang]/(store)/account/orders/page.tsx @@ -22,10 +22,14 @@ export default async function Orders(props: { offset?: string; page?: string; }>; + params?: Promise<{ lang: string }>; }) { const searchParams = await props.searchParams; const limit = Number(searchParams?.limit) || DEFAULT_PAGINATION_LIMIT; const offset = Number(searchParams?.offset) || 0; + + const params = await props.params; + const lang = params?.lang; const cookieStore = await cookies(); @@ -35,7 +39,7 @@ export default async function Orders(props: { ); if (!accountMemberCookie) { - return redirect("/login"); + return redirect(lang ? `/${lang}/login` : "/login"); } const client = await createElasticPathClient(); diff --git a/examples/core/src/app/[lang]/(store)/account/summary/page.tsx b/examples/core/src/app/[lang]/(store)/account/summary/page.tsx index 1e7abf72..9cd77604 100644 --- a/examples/core/src/app/[lang]/(store)/account/summary/page.tsx +++ b/examples/core/src/app/[lang]/(store)/account/summary/page.tsx @@ -18,7 +18,8 @@ import { TAGS } from "src/lib/constants"; export const dynamic = "force-dynamic"; -export default async function AccountSummary() { +export default async function AccountSummary({ params }: { params: Promise<{ lang: string }> }) { + const { lang } = await params; const cookieStore = await cookies(); const accountMemberCookie = retrieveAccountMemberCredentials( @@ -27,7 +28,7 @@ export default async function AccountSummary() { ); if (!accountMemberCookie) { - return redirect("/login"); + return redirect(lang ? `/${lang}/login` : "/login"); } const client = createElasticPathClient(); diff --git a/examples/core/src/components/header/AccountMobileMenu.tsx b/examples/core/src/components/header/AccountMobileMenu.tsx index 2d81dbdc..caf3cbb9 100644 --- a/examples/core/src/components/header/AccountMobileMenu.tsx +++ b/examples/core/src/components/header/AccountMobileMenu.tsx @@ -1,5 +1,5 @@ "use client"; -import { usePathname } from "next/navigation"; +import { useParams, usePathname } from "next/navigation"; import { LocaleLink } from "../LocaleLink"; import { ArrowLeftOnRectangleIcon, @@ -21,6 +21,7 @@ export function AccountMobileMenu({ }: { account: AccountMemberResponse; }) { + const { lang } = useParams(); const pathname = usePathname(); const isAccountAuthed = !!account; @@ -105,24 +106,21 @@ export function AccountMobileMenu({
    - - - - - - + + logout(lang as string)} + > + +
    )} diff --git a/examples/core/src/components/header/Header.tsx b/examples/core/src/components/header/Header.tsx index 1bda1af2..13960e54 100644 --- a/examples/core/src/components/header/Header.tsx +++ b/examples/core/src/components/header/Header.tsx @@ -29,7 +29,7 @@ const Header = async ({ lang }: { lang: string }) => {
    - + }> diff --git a/examples/core/src/components/header/account/AccountMenu.tsx b/examples/core/src/components/header/account/AccountMenu.tsx index a64c91fa..a0759461 100644 --- a/examples/core/src/components/header/account/AccountMenu.tsx +++ b/examples/core/src/components/header/account/AccountMenu.tsx @@ -6,7 +6,7 @@ import { retrieveAccountMemberCredentials } from "../../../lib/retrieve-account- import { cookies } from "next/headers"; import { ACCOUNT_MEMBER_TOKEN_COOKIE_NAME } from "../../../lib/cookie-constants"; -export async function AccountMenu() { +export async function AccountMenu({ lang }: { lang: string }) { const client = createElasticPathClient(); const accountMemberCookie = retrieveAccountMemberCredentials( @@ -27,7 +27,7 @@ export async function AccountMenu() { } + accountSwitcher={} /> ); } diff --git a/examples/core/src/components/header/account/AccountPopover.tsx b/examples/core/src/components/header/account/AccountPopover.tsx index 1858307e..df70dde3 100644 --- a/examples/core/src/components/header/account/AccountPopover.tsx +++ b/examples/core/src/components/header/account/AccountPopover.tsx @@ -1,7 +1,7 @@ "use client"; import { ReactNode, useState } from "react"; -import { usePathname } from "next/navigation"; +import { useParams, usePathname } from "next/navigation"; import { logout } from "../../../app/[lang]/(auth)/actions"; import { ArrowLeftOnRectangleIcon, @@ -32,6 +32,7 @@ export function AccountPopover({ account?: AccountMemberResponse; accountMemberTokens?: ReturnType; }) { + const { lang } = useParams(); const pathname = usePathname(); const [open, setOpen] = useState(false); @@ -39,7 +40,7 @@ export function AccountPopover({ const isAccountAuthed = account !== undefined; function logoutAction() { - logout(); + logout(lang as string); setOpen(true); } @@ -138,23 +139,22 @@ export function AccountPopover({
    -
    - - - - + + +
    )} diff --git a/examples/core/src/components/header/account/AccountSwitcher.tsx b/examples/core/src/components/header/account/AccountSwitcher.tsx index 533df80a..799c5c34 100644 --- a/examples/core/src/components/header/account/AccountSwitcher.tsx +++ b/examples/core/src/components/header/account/AccountSwitcher.tsx @@ -7,7 +7,7 @@ import { retrieveAccountMemberCredentials } from "../../../lib/retrieve-account- import { ACCOUNT_MEMBER_TOKEN_COOKIE_NAME } from "../../../lib/cookie-constants"; import { SwitchButton } from "./switch-button"; -export async function AccountSwitcher() { +export async function AccountSwitcher({ lang }: { lang: string }) { const cookieStore = await cookies(); const accountMemberCookie = retrieveAccountMemberCredentials( cookieStore, @@ -27,6 +27,7 @@ export async function AccountSwitcher() { selectedAccountId === value.account_id ? CheckCircleIcon : UserCircleIcon; return (
    + >; }) { + const { lang } = useParams(); if (!account || !accountMemberTokens) { return null; } @@ -47,6 +49,7 @@ export function MobileAccountSwitcher({ : UserCircleIcon; return ( + Date: Fri, 5 Dec 2025 14:58:23 +0500 Subject: [PATCH 10/14] Update layout.tsx --- examples/core/src/app/[lang]/(store)/layout.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/core/src/app/[lang]/(store)/layout.tsx b/examples/core/src/app/[lang]/(store)/layout.tsx index d884260d..692c4383 100644 --- a/examples/core/src/app/[lang]/(store)/layout.tsx +++ b/examples/core/src/app/[lang]/(store)/layout.tsx @@ -41,7 +41,7 @@ export default async function StoreLayout({ params, }: { children: ReactNode; - params: { lang: string }; + params: Promise<{ lang: string }>; }) { const resolvedParams = await params; const lang = resolvedParams?.lang; From 5d2161c9ab3105f123234df315cc8bb44945c5bf Mon Sep 17 00:00:00 2001 From: Muhammad Zain Tariq <49867382+mzaintariq@users.noreply.github.com> Date: Wed, 10 Dec 2025 14:41:08 +0500 Subject: [PATCH 11/14] checkout fix for locale/currency --- .../checkout/AccoutCheckoutForm.tsx | 4 +-- .../(checkout)/checkout/CheckoutViews.tsx | 7 +++-- .../checkout/ConfirmationSidebar.tsx | 8 +++-- .../(checkout)/checkout/GuestCheckout.tsx | 4 +-- .../checkout/SubmitCheckoutButton.tsx | 31 +++++++++++++++++-- .../app/[lang]/(checkout)/checkout/actions.ts | 29 +++++++++++++++++ .../(checkout)/checkout/checkout-provider.tsx | 17 ++++++++-- examples/core/src/lib/i18n.ts | 2 +- 8 files changed, 85 insertions(+), 17 deletions(-) diff --git a/examples/core/src/app/[lang]/(checkout)/checkout/AccoutCheckoutForm.tsx b/examples/core/src/app/[lang]/(checkout)/checkout/AccoutCheckoutForm.tsx index 1c3738c2..22f80700 100644 --- a/examples/core/src/app/[lang]/(checkout)/checkout/AccoutCheckoutForm.tsx +++ b/examples/core/src/app/[lang]/(checkout)/checkout/AccoutCheckoutForm.tsx @@ -29,7 +29,7 @@ export function AccountCheckoutForm({ currencies: ResponseCurrency[]; }) { return ( - +
    @@ -58,7 +58,7 @@ export function AccountCheckoutForm({
    - {cart.data && } + {cart.data && }
    diff --git a/examples/core/src/app/[lang]/(checkout)/checkout/CheckoutViews.tsx b/examples/core/src/app/[lang]/(checkout)/checkout/CheckoutViews.tsx index f0cb0611..a28c540e 100644 --- a/examples/core/src/app/[lang]/(checkout)/checkout/CheckoutViews.tsx +++ b/examples/core/src/app/[lang]/(checkout)/checkout/CheckoutViews.tsx @@ -1,9 +1,9 @@ "use client"; -import { ReactNode, useEffect } from "react"; +import { ReactNode, use, useEffect } from "react"; import { OrderConfirmation } from "./OrderConfirmation"; import { useOrderConfirmation } from "./OrderConfirmationProvider"; -import { useRouter } from "next/navigation"; +import { useParams, useRouter } from "next/navigation"; import { getACart, ResponseCurrency } from "@epcc-sdk/sdks-shopper"; export function CheckoutViews({ @@ -17,10 +17,11 @@ export function CheckoutViews({ }) { const confirmationData = useOrderConfirmation(); const router = useRouter(); + const { lang } = useParams(); useEffect(() => { if (!confirmationData && (cartResponse.included?.items?.length ?? 0) < 1) { - router.push("/cart"); + router.push(lang ? `/${lang}/cart` : "/cart"); } }, [cartResponse]); diff --git a/examples/core/src/app/[lang]/(checkout)/checkout/ConfirmationSidebar.tsx b/examples/core/src/app/[lang]/(checkout)/checkout/ConfirmationSidebar.tsx index 70f577c4..d7eab6b8 100644 --- a/examples/core/src/app/[lang]/(checkout)/checkout/ConfirmationSidebar.tsx +++ b/examples/core/src/app/[lang]/(checkout)/checkout/ConfirmationSidebar.tsx @@ -17,6 +17,8 @@ import { ItemSidebarHideable } from "src/components/checkout-sidebar/ItemSidebar import { groupCartItems } from "src/lib/group-cart-items"; import { ResponseCurrency } from "@epcc-sdk/sdks-shopper"; import { useOrderConfirmation } from "./OrderConfirmationProvider"; +import { useParams } from "next/navigation"; +import { getPreferredCurrency } from "src/lib/i18n"; export function ConfirmationSidebar({ currencies, @@ -43,9 +45,9 @@ export function ConfirmationSidebar({ method.value === shippingMethodCustomItem.sku, )?.amount; - const storeCurrency = currencies?.find( - (currency) => currency.code === EP_CURRENCY_CODE, - ); + const { lang } = useParams(); + const orderCurrencyCode = order.meta?.display_price?.with_tax?.currency; + const storeCurrency = getPreferredCurrency(lang as string, currencies, orderCurrencyCode); const formattedTotalAmountInclShipping = order.meta?.display_price?.with_tax?.amount !== undefined && diff --git a/examples/core/src/app/[lang]/(checkout)/checkout/GuestCheckout.tsx b/examples/core/src/app/[lang]/(checkout)/checkout/GuestCheckout.tsx index 5154ca2a..783c22dd 100644 --- a/examples/core/src/app/[lang]/(checkout)/checkout/GuestCheckout.tsx +++ b/examples/core/src/app/[lang]/(checkout)/checkout/GuestCheckout.tsx @@ -25,7 +25,7 @@ export function GuestCheckout({ return item.type === "subscription_item"; }) ?? false; return ( - +
    @@ -53,7 +53,7 @@ export function GuestCheckout({
    - {cart?.data && } + {cart?.data && }
    diff --git a/examples/core/src/app/[lang]/(checkout)/checkout/SubmitCheckoutButton.tsx b/examples/core/src/app/[lang]/(checkout)/checkout/SubmitCheckoutButton.tsx index 8aafed43..6c4770c6 100644 --- a/examples/core/src/app/[lang]/(checkout)/checkout/SubmitCheckoutButton.tsx +++ b/examples/core/src/app/[lang]/(checkout)/checkout/SubmitCheckoutButton.tsx @@ -2,11 +2,36 @@ import { useCheckout } from "./checkout-provider"; import { StatusButton } from "src/components/button/StatusButton"; -import { CartResponse } from "@epcc-sdk/sdks-shopper"; +import { CartResponse, ResponseCurrency } from "@epcc-sdk/sdks-shopper"; +import { staticDeliveryMethods } from "./useShippingMethod"; +import { useWatch } from "react-hook-form"; +import { useParams } from "next/navigation"; +import { getPreferredCurrency } from "src/lib/i18n"; +import { resolveTotalInclShipping } from "src/components/checkout-sidebar/ItemSidebar"; -export function SubmitCheckoutButton({ cart }: { cart: CartResponse }) { +export function SubmitCheckoutButton({ cart, currencies }: { cart: CartResponse; currencies: ResponseCurrency[]; }) { const { handleSubmit, completePayment, isCompleting } = useCheckout(); + const { lang } = useParams(); + const cartCurrencyCode = cart.meta?.display_price?.with_tax?.currency; + const storeCurrency = getPreferredCurrency(lang as string, currencies, cartCurrencyCode); + + const shippingMethod = useWatch({ name: "shippingMethod" }); + const shippingAmount = staticDeliveryMethods.find( + (method) => method.value === shippingMethod, + )?.amount; + + const formattedTotalAmountInclShipping = + cart.meta?.display_price?.with_tax?.amount !== undefined && + shippingAmount !== undefined && + storeCurrency + ? resolveTotalInclShipping( + shippingAmount, + cart.meta.display_price.with_tax.amount, + storeCurrency, + ) + : cart.meta?.display_price?.with_tax?.formatted; + return ( - {`Pay ${cart.meta?.display_price?.with_tax?.formatted}`} + {`Pay ${formattedTotalAmountInclShipping}`} ); } diff --git a/examples/core/src/app/[lang]/(checkout)/checkout/actions.ts b/examples/core/src/app/[lang]/(checkout)/checkout/actions.ts index d7f7b40f..845a94fa 100644 --- a/examples/core/src/app/[lang]/(checkout)/checkout/actions.ts +++ b/examples/core/src/app/[lang]/(checkout)/checkout/actions.ts @@ -49,6 +49,7 @@ export type PaymentCompleteResponse = { export async function paymentComplete( props: CheckoutForm, lang: string, + currencyCode?: string, ): Promise { const client = createElasticPathClient(); @@ -100,6 +101,10 @@ export async function paymentComplete( }, }, }, + headers: { + "Accept-Language": lang, + "X-Moltin-Currency": currencyCode, + }, }); if (!cartInclShippingResponse.data?.data) { @@ -193,6 +198,10 @@ export async function paymentComplete( shipping_address: checkoutProps.shippingAddress as ShippingAddress, }, }, + headers: { + "Accept-Language": lang, + "X-Moltin-Currency": currencyCode, + }, }); } else { createdOrderResonse = await checkoutApi({ @@ -210,6 +219,10 @@ export async function paymentComplete( shipping_address: checkoutProps.shippingAddress as ShippingAddress, }, }, + headers: { + "Accept-Language": lang, + "X-Moltin-Currency": currencyCode, + }, }); } @@ -232,6 +245,10 @@ export async function paymentComplete( method: "purchase", }, }, + headers: { + "Accept-Language": lang, + "X-Moltin-Currency": currencyCode, + }, }); /** @@ -246,6 +263,10 @@ export async function paymentComplete( query: { include: ["items"], }, + headers: { + "Accept-Language": lang, + "X-Moltin-Currency": currencyCode, + }, }); const items = cartResponse.data?.included?.items ?? []; @@ -258,6 +279,10 @@ export async function paymentComplete( filter: `in(id,${productIds})`, include: ["main_image"], }, + headers: { + "Accept-Language": lang, + "X-Moltin-Currency": currencyCode, + }, }); const images = extractCartItemMedia({ @@ -274,6 +299,10 @@ export async function paymentComplete( path: { cartID: cartId, }, + headers: { + "Accept-Language": lang, + "X-Moltin-Currency": currencyCode, + }, }); const revalidatePromises = [revalidatePath("/cart"), revalidateTag("cart")]; diff --git a/examples/core/src/app/[lang]/(checkout)/checkout/checkout-provider.tsx b/examples/core/src/app/[lang]/(checkout)/checkout/checkout-provider.tsx index 4ab4d7f2..20a0aec1 100644 --- a/examples/core/src/app/[lang]/(checkout)/checkout/checkout-provider.tsx +++ b/examples/core/src/app/[lang]/(checkout)/checkout/checkout-provider.tsx @@ -12,10 +12,11 @@ import { import { zodResolver } from "@hookform/resolvers/zod"; import { Form } from "src/components/form/Form"; import { ShippingMethod, staticDeliveryMethods } from "./useShippingMethod"; -import { getACart } from "@epcc-sdk/sdks-shopper"; +import { getACart, ResponseCurrency } from "@epcc-sdk/sdks-shopper"; import { paymentComplete } from "./actions"; import { useSetOrderConfirmation } from "./OrderConfirmationProvider"; import { useParams } from "next/navigation"; +import { getPreferredCurrency } from "src/lib/i18n"; type CheckoutContext = { cart?: NonNullable>["data"]>; @@ -31,6 +32,8 @@ const CheckoutContext = createContext(null); type CheckoutProviderProps = { children?: React.ReactNode; type: "subscription" | "guest"; + cart?: NonNullable>["data"]>; + currencies?: ResponseCurrency[]; }; const guestFormDefaults = { @@ -114,8 +117,12 @@ const accountFormDefaults = { export function GuestCheckoutProvider({ children, type, + cart, + currencies = [], }: CheckoutProviderProps) { const { lang } = useParams(); + const cartCurrencyCode = cart?.data?.meta?.display_price?.with_tax?.currency; + const storeCurrency = getPreferredCurrency(lang as string, currencies, cartCurrencyCode); const [isPending, startTransition] = useTransition(); const setConfirmationData = useSetOrderConfirmation(); @@ -127,7 +134,7 @@ export function GuestCheckoutProvider({ async function handleSubmit(data: CheckoutForm) { startTransition(async () => { - const result = await paymentComplete(data, lang as string); + const result = await paymentComplete(data, lang as string, storeCurrency?.code); setConfirmationData(result); }); } @@ -151,8 +158,12 @@ export function GuestCheckoutProvider({ export function AccountCheckoutProvider({ children, + cart, + currencies = [], }: Omit) { const { lang } = useParams(); + const cartCurrencyCode = cart?.data?.meta?.display_price?.with_tax?.currency; + const storeCurrency = getPreferredCurrency(lang as string, currencies, cartCurrencyCode); const [isPending, startTransition] = useTransition(); const setConfirmationData = useSetOrderConfirmation(); @@ -163,7 +174,7 @@ export function AccountCheckoutProvider({ async function handleSubmit(data: CheckoutForm) { startTransition(async () => { - const result = await paymentComplete(data, lang as string); + const result = await paymentComplete(data, lang as string, storeCurrency?.code); setConfirmationData(result); }); } diff --git a/examples/core/src/lib/i18n.ts b/examples/core/src/lib/i18n.ts index c74ec79c..a3930fe6 100644 --- a/examples/core/src/lib/i18n.ts +++ b/examples/core/src/lib/i18n.ts @@ -10,7 +10,7 @@ export const LOCALE_TO_CURRENCY: Record = { }; export function getPreferredCurrency(lang: string | undefined, currencies: ResponseCurrency[], cartCurrencyCode?: string) { - if (!currencies.length) return undefined; + if (!currencies?.length) return undefined; const preferredCode = cartCurrencyCode ? cartCurrencyCode From aefadf196bbbf79e83de0036606cb194f1864c14 Mon Sep 17 00:00:00 2001 From: Muhammad Zain Tariq <49867382+mzaintariq@users.noreply.github.com> Date: Wed, 10 Dec 2025 14:42:34 +0500 Subject: [PATCH 12/14] Update CheckoutViews.tsx --- .../core/src/app/[lang]/(checkout)/checkout/CheckoutViews.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/core/src/app/[lang]/(checkout)/checkout/CheckoutViews.tsx b/examples/core/src/app/[lang]/(checkout)/checkout/CheckoutViews.tsx index a28c540e..fb3867e0 100644 --- a/examples/core/src/app/[lang]/(checkout)/checkout/CheckoutViews.tsx +++ b/examples/core/src/app/[lang]/(checkout)/checkout/CheckoutViews.tsx @@ -1,6 +1,6 @@ "use client"; -import { ReactNode, use, useEffect } from "react"; +import { ReactNode, useEffect } from "react"; import { OrderConfirmation } from "./OrderConfirmation"; import { useOrderConfirmation } from "./OrderConfirmationProvider"; import { useParams, useRouter } from "next/navigation"; From 9c1c1536333d106759652465c9a088e4d82804e6 Mon Sep 17 00:00:00 2001 From: Muhammad Zain Tariq <49867382+mzaintariq@users.noreply.github.com> Date: Wed, 10 Dec 2025 14:53:51 +0500 Subject: [PATCH 13/14] fix to keep lang when selecting variation --- .../product/variations/ProductVariations.tsx | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/examples/core/src/components/product/variations/ProductVariations.tsx b/examples/core/src/components/product/variations/ProductVariations.tsx index dd8a6ca1..d4e7583f 100644 --- a/examples/core/src/components/product/variations/ProductVariations.tsx +++ b/examples/core/src/components/product/variations/ProductVariations.tsx @@ -5,7 +5,7 @@ import clsx from "clsx"; import { SkuChangeOpacityWrapper } from "../SkuChangeOpacityWrapper"; import { useVariationProduct } from "./useVariationContext"; import { SkuChangingContext } from "../../../lib/sku-changing-context"; -import { useRouter } from "next/navigation"; +import { useParams, useRouter } from "next/navigation"; import { getSkuIdFromOptions } from "../../../lib/product-helper"; import { allVariationsHaveSelectedOption } from "./util/all-variations-have-selected-option"; @@ -17,6 +17,8 @@ const getSelectedOption = ( }; const ProductVariations = () => { + const { lang } = useParams(); + const { variations, variationsMatrix, @@ -44,7 +46,12 @@ const ProductVariations = () => { allVariationsHaveSelectedOption(selectedOptions, variations) ) { context?.setIsChangingSku(true); - router.replace(`/products/${selectedSkuId}`, { scroll: false }); + router.replace( + lang + ? `/${lang}/products/${selectedSkuId}` + : `/products/${selectedSkuId}`, + { scroll: false }, + ); context?.setIsChangingSku(false); } }, [ From 9d725cb28796cf0415cb9d856763cdb238f04ca2 Mon Sep 17 00:00:00 2001 From: Muhammad Zain Tariq <49867382+mzaintariq@users.noreply.github.com> Date: Wed, 10 Dec 2025 17:41:30 +0500 Subject: [PATCH 14/14] fix build issue --- .../src/app/[lang]/(checkout)/checkout/CheckoutViews.tsx | 1 + .../app/[lang]/(checkout)/checkout/ConfirmationSidebar.tsx | 5 ++--- .../src/app/[lang]/(checkout)/checkout/OrderConfirmation.tsx | 4 +++- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/examples/core/src/app/[lang]/(checkout)/checkout/CheckoutViews.tsx b/examples/core/src/app/[lang]/(checkout)/checkout/CheckoutViews.tsx index fb3867e0..cd13a41c 100644 --- a/examples/core/src/app/[lang]/(checkout)/checkout/CheckoutViews.tsx +++ b/examples/core/src/app/[lang]/(checkout)/checkout/CheckoutViews.tsx @@ -34,6 +34,7 @@ export function CheckoutViews({ ); } diff --git a/examples/core/src/app/[lang]/(checkout)/checkout/ConfirmationSidebar.tsx b/examples/core/src/app/[lang]/(checkout)/checkout/ConfirmationSidebar.tsx index d7eab6b8..d7d879a1 100644 --- a/examples/core/src/app/[lang]/(checkout)/checkout/ConfirmationSidebar.tsx +++ b/examples/core/src/app/[lang]/(checkout)/checkout/ConfirmationSidebar.tsx @@ -11,19 +11,19 @@ import { resolveTotalInclShipping, } from "src/components/checkout-sidebar/ItemSidebar"; import { staticDeliveryMethods } from "./useShippingMethod"; -import { EP_CURRENCY_CODE } from "src/lib/resolve-ep-currency-code"; import { LoadingDots } from "src/components/LoadingDots"; import { ItemSidebarHideable } from "src/components/checkout-sidebar/ItemSidebarHideable"; import { groupCartItems } from "src/lib/group-cart-items"; import { ResponseCurrency } from "@epcc-sdk/sdks-shopper"; import { useOrderConfirmation } from "./OrderConfirmationProvider"; -import { useParams } from "next/navigation"; import { getPreferredCurrency } from "src/lib/i18n"; export function ConfirmationSidebar({ currencies, + lang, }: { currencies: ResponseCurrency[]; + lang: string; }) { const confirmationData = useOrderConfirmation(); @@ -45,7 +45,6 @@ export function ConfirmationSidebar({ method.value === shippingMethodCustomItem.sku, )?.amount; - const { lang } = useParams(); const orderCurrencyCode = order.meta?.display_price?.with_tax?.currency; const storeCurrency = getPreferredCurrency(lang as string, currencies, orderCurrencyCode); diff --git a/examples/core/src/app/[lang]/(checkout)/checkout/OrderConfirmation.tsx b/examples/core/src/app/[lang]/(checkout)/checkout/OrderConfirmation.tsx index c7ee69f7..dd9a5e76 100644 --- a/examples/core/src/app/[lang]/(checkout)/checkout/OrderConfirmation.tsx +++ b/examples/core/src/app/[lang]/(checkout)/checkout/OrderConfirmation.tsx @@ -12,9 +12,11 @@ import { PaymentCompleteResponse } from "./actions"; export function OrderConfirmation({ currencies, confirmationData, + lang, }: { currencies: ResponseCurrency[]; confirmationData: PaymentCompleteResponse; + lang: string; }) { if (!confirmationData) { return null; @@ -90,7 +92,7 @@ export function OrderConfirmation({
    {`Order #${orderId}`} - +