diff --git a/apps/storefront/src/app/[locale]/(auth)/confirm-account-registration/page.tsx b/apps/storefront/src/app/[locale]/(auth)/confirm-account-registration/page.tsx index e8f504a..aa25adc 100644 --- a/apps/storefront/src/app/[locale]/(auth)/confirm-account-registration/page.tsx +++ b/apps/storefront/src/app/[locale]/(auth)/confirm-account-registration/page.tsx @@ -1,6 +1,6 @@ -import { redirect } from "next/navigation"; -import { getTranslations } from "next-intl/server"; +import { getLocale, getTranslations } from "next-intl/server"; +import { redirect } from "@/i18n/routing"; import { paths } from "@/lib/paths"; import { authService } from "@/services"; @@ -11,6 +11,7 @@ export default async function ConfirmAccountRegistrationPage(props: { const t = await getTranslations(); const email = searchParams?.email; const token = searchParams?.token; + const locale = await getLocale(); if (!email) { return t("auth.confirm-missing-email"); @@ -23,7 +24,10 @@ export default async function ConfirmAccountRegistrationPage(props: { const data = await authService.confirmAccount(searchParams); if (data.isSuccess) { - redirect(paths.signIn.asPath({ query: { confirmationSuccess: "true" } })); + redirect({ + href: paths.signIn.asPath({ query: { confirmationSuccess: "true" } }), + locale, + }); } if ("errors" in data) { diff --git a/apps/storefront/src/app/[locale]/(auth)/confirm-new-email/page.tsx b/apps/storefront/src/app/[locale]/(auth)/confirm-new-email/page.tsx index 69aeabc..1134452 100644 --- a/apps/storefront/src/app/[locale]/(auth)/confirm-new-email/page.tsx +++ b/apps/storefront/src/app/[locale]/(auth)/confirm-new-email/page.tsx @@ -1,7 +1,7 @@ -import { redirect } from "next/navigation"; -import { getTranslations } from "next-intl/server"; +import { getLocale, getTranslations } from "next-intl/server"; import { getAccessToken } from "@/auth"; +import { redirect } from "@/i18n/routing"; import { paths } from "@/lib/paths"; import { getCurrentRegion } from "@/regions/server"; import { userService } from "@/services"; @@ -12,6 +12,7 @@ export default async function ConfirmEmailChangePage(props: { const searchParams = await props.searchParams; const token = searchParams?.token ?? ""; const accessToken = await getAccessToken(); + const locale = await getLocale(); const [region, t] = await Promise.all([ getCurrentRegion(), @@ -26,7 +27,7 @@ export default async function ConfirmEmailChangePage(props: { }); if (data?.user?.id && !data?.errors.length) { - redirect(paths.signIn.asPath()); + redirect({ href: paths.signIn.asPath(), locale }); } if (data?.errors) { diff --git a/apps/storefront/src/app/[locale]/(checkout)/checkout/(checkout-details)/delivery-method/page.tsx b/apps/storefront/src/app/[locale]/(checkout)/checkout/(checkout-details)/delivery-method/page.tsx index 5e5ab81..b74c720 100644 --- a/apps/storefront/src/app/[locale]/(checkout)/checkout/(checkout-details)/delivery-method/page.tsx +++ b/apps/storefront/src/app/[locale]/(checkout)/checkout/(checkout-details)/delivery-method/page.tsx @@ -1,8 +1,9 @@ import { cookies } from "next/headers"; -import { redirect } from "next/navigation"; +import { getLocale } from "next-intl/server"; import { getAccessToken } from "@/auth"; import { COOKIE_KEY } from "@/config"; +import { redirect } from "@/i18n/routing"; import { deleteCheckoutIdCookie } from "@/lib/actions/checkout"; import { paths } from "@/lib/paths"; import { getCurrentRegion } from "@/regions/server"; @@ -16,13 +17,12 @@ import { DeliveryMethodForm } from "./form"; export default async function Page() { const checkoutId = (await cookies()).get(COOKIE_KEY.checkoutId)?.value; - const accessToken = await getAccessToken(); - + const locale = await getLocale(); const region = await getCurrentRegion(); if (!checkoutId) { - redirect(paths.cart.asPath()); + redirect({ href: paths.cart.asPath(), locale }); } const { checkout } = await checkoutService.checkoutGet({ @@ -33,7 +33,7 @@ export default async function Page() { if (!checkout) { await deleteCheckoutIdCookie(); - redirect(paths.cart.asPath()); + redirect({ href: paths.cart.asPath(), locale }); } if (checkout.problems.insufficientStock.length) { diff --git a/apps/storefront/src/app/[locale]/(checkout)/checkout/(checkout-details)/shipping-address/page.tsx b/apps/storefront/src/app/[locale]/(checkout)/checkout/(checkout-details)/shipping-address/page.tsx index a3b3193..95f8764 100644 --- a/apps/storefront/src/app/[locale]/(checkout)/checkout/(checkout-details)/shipping-address/page.tsx +++ b/apps/storefront/src/app/[locale]/(checkout)/checkout/(checkout-details)/shipping-address/page.tsx @@ -1,10 +1,11 @@ import { cookies } from "next/headers"; -import { redirect } from "next/navigation"; +import { getLocale } from "next-intl/server"; import type { CountryCode } from "@nimara/codegen/schema"; import { getAccessToken } from "@/auth"; import { COOKIE_KEY } from "@/config"; +import { redirect } from "@/i18n/routing"; import { deleteCheckoutIdCookie } from "@/lib/actions/checkout"; import { paths } from "@/lib/paths"; import { getCurrentRegion } from "@/regions/server"; @@ -23,13 +24,14 @@ export default async function Page(props: { searchParams: SearchParams }) { const searchParams = await props.searchParams; const checkoutId = (await cookies()).get(COOKIE_KEY.checkoutId)?.value; const accessToken = await getAccessToken(); + const locale = await getLocale(); const region = await getCurrentRegion(); const marketCountryCode = region.market.countryCode; if (!checkoutId) { - redirect(paths.cart.asPath()); + redirect({ href: paths.cart.asPath(), locale }); } const { checkout } = await checkoutService.checkoutGet({ @@ -40,7 +42,7 @@ export default async function Page(props: { searchParams: SearchParams }) { if (!checkout) { await deleteCheckoutIdCookie(); - redirect(paths.cart.asPath()); + redirect({ href: paths.cart.asPath(), locale }); } if (checkout.problems.insufficientStock.length) { diff --git a/apps/storefront/src/app/[locale]/(checkout)/checkout/(checkout-details)/user-details/page.tsx b/apps/storefront/src/app/[locale]/(checkout)/checkout/(checkout-details)/user-details/page.tsx index 1dec445..ccc7007 100644 --- a/apps/storefront/src/app/[locale]/(checkout)/checkout/(checkout-details)/user-details/page.tsx +++ b/apps/storefront/src/app/[locale]/(checkout)/checkout/(checkout-details)/user-details/page.tsx @@ -1,8 +1,9 @@ import { cookies } from "next/headers"; -import { redirect } from "next/navigation"; +import { getLocale } from "next-intl/server"; import { getAccessToken } from "@/auth"; import { COOKIE_KEY } from "@/config"; +import { redirect } from "@/i18n/routing"; import { deleteCheckoutIdCookie } from "@/lib/actions/checkout"; import { paths } from "@/lib/paths"; import { getCurrentRegion } from "@/regions/server"; @@ -16,11 +17,11 @@ import { UserDetailsForm } from "./form"; export default async function Page() { const checkoutId = (await cookies()).get(COOKIE_KEY.checkoutId)?.value; - + const locale = await getLocale(); const region = await getCurrentRegion(); if (!checkoutId) { - redirect(paths.cart.asPath()); + redirect({ href: paths.cart.asPath(), locale }); } const accessToken = await getAccessToken(); @@ -43,7 +44,7 @@ export default async function Page() { if (!checkout) { await deleteCheckoutIdCookie(); - redirect(paths.cart.asPath()); + redirect({ href: paths.cart.asPath(), locale }); } if (checkout.problems.insufficientStock.length) { diff --git a/apps/storefront/src/app/[locale]/(checkout)/checkout/page.tsx b/apps/storefront/src/app/[locale]/(checkout)/checkout/page.tsx index baa75d1..465fc32 100644 --- a/apps/storefront/src/app/[locale]/(checkout)/checkout/page.tsx +++ b/apps/storefront/src/app/[locale]/(checkout)/checkout/page.tsx @@ -1,8 +1,9 @@ import { cookies } from "next/headers"; -import { redirect } from "next/navigation"; +import { getLocale } from "next-intl/server"; import { getAccessToken } from "@/auth"; import { COOKIE_KEY } from "@/config"; +import { redirect } from "@/i18n/routing"; import { deleteCheckoutIdCookie } from "@/lib/actions/checkout"; import { paths } from "@/lib/paths"; import { getCurrentRegion } from "@/regions/server"; @@ -11,6 +12,7 @@ import { checkoutService, userService } from "@/services"; export default async function Page() { const checkoutId = (await cookies()).get(COOKIE_KEY.checkoutId)?.value; const accessToken = await getAccessToken(); + const locale = await getLocale(); const [region, user] = await Promise.all([ getCurrentRegion(), @@ -18,7 +20,7 @@ export default async function Page() { ]); if (!checkoutId) { - redirect(paths.cart.asPath()); + redirect({ href: paths.cart.asPath(), locale }); } const { checkout } = await checkoutService.checkoutGet({ @@ -27,27 +29,22 @@ export default async function Page() { countryCode: region.market.countryCode, }); - // TODO handle different cases - // if checkout is empty? what than? how to check it? - // checkout?.order?.status === "complete"; // how to check it - // in case of gone or its an order? different redirect in this cases? - if (!checkout) { await deleteCheckoutIdCookie(); - redirect(paths.cart.asPath()); + redirect({ href: paths.cart.asPath(), locale }); } if (!checkout.email && !user?.email) { - redirect(paths.checkout.userDetails.asPath()); + redirect({ href: paths.checkout.userDetails.asPath(), locale }); } if (user?.email || !checkout.shippingAddress) { - redirect(paths.checkout.shippingAddress.asPath()); + redirect({ href: paths.checkout.shippingAddress.asPath(), locale }); } if (!checkout.deliveryMethod) { - redirect(paths.checkout.deliveryMethod.asPath()); + redirect({ href: paths.checkout.deliveryMethod.asPath(), locale }); } - redirect(paths.checkout.payment.asPath()); + redirect({ href: paths.checkout.payment.asPath(), locale }); } diff --git a/apps/storefront/src/app/[locale]/(main)/account/privacy-settings/actions.ts b/apps/storefront/src/app/[locale]/(main)/account/privacy-settings/actions.ts index 65de593..d001048 100644 --- a/apps/storefront/src/app/[locale]/(main)/account/privacy-settings/actions.ts +++ b/apps/storefront/src/app/[locale]/(main)/account/privacy-settings/actions.ts @@ -1,8 +1,9 @@ "use server"; -import { redirect } from "next/navigation"; +import { getLocale } from "next-intl/server"; import { getAccessToken } from "@/auth"; +import { redirect } from "@/i18n/routing"; import { paths } from "@/lib/paths"; import { getStoreUrl } from "@/lib/server"; import { getCurrentRegion } from "@/regions/server"; @@ -10,7 +11,7 @@ import { userService } from "@/services"; export async function requestUserAccountDeletion() { const region = await getCurrentRegion(); - + const locale = await getLocale(); const accessToken = await getAccessToken(); const data = await userService.accountRequestDeletion({ @@ -20,12 +21,16 @@ export async function requestUserAccountDeletion() { }); if (data?.errors.length) { - redirect( - paths.account.privacySettings.asPath({ query: { error: "true" } }), - ); + redirect({ + href: paths.account.privacySettings.asPath({ query: { error: "true" } }), + locale, + }); } - redirect( - paths.account.privacySettings.asPath({ query: { emailSent: "true" } }), - ); + redirect({ + href: paths.account.privacySettings.asPath({ + query: { emailSent: "true" }, + }), + locale, + }); } diff --git a/apps/storefront/src/app/[locale]/(main)/payment/confirmation/page.tsx b/apps/storefront/src/app/[locale]/(main)/payment/confirmation/page.tsx index bc8f84b..a5da1d6 100644 --- a/apps/storefront/src/app/[locale]/(main)/payment/confirmation/page.tsx +++ b/apps/storefront/src/app/[locale]/(main)/payment/confirmation/page.tsx @@ -1,5 +1,6 @@ -import { redirect } from "next/navigation"; +import { getLocale } from "next-intl/server"; +import { redirect } from "@/i18n/routing"; import { getCheckoutOrRedirect } from "@/lib/checkout"; import { paths, QUERY_PARAMS } from "@/lib/paths"; import { checkoutService, paymentService } from "@/services"; @@ -10,6 +11,7 @@ type SearchParams = Promise>; export default async function Page(props: { searchParams: SearchParams }) { const searchParams = await props.searchParams; + const locale = await getLocale(); const checkout = await getCheckoutOrRedirect(); let errors: { code: string; type: string }[] = []; @@ -25,12 +27,13 @@ export default async function Page(props: { searchParams: SearchParams }) { }); if (orderCreateData.orderId) { - redirect( - paths.order.confirmation.asPath({ + redirect({ + href: paths.order.confirmation.asPath({ id: orderCreateData.orderId, query: { [QUERY_PARAMS.orderPlace]: "true" }, }), - ); + locale, + }); } else { errors = orderCreateData.errors; } @@ -38,13 +41,14 @@ export default async function Page(props: { searchParams: SearchParams }) { const error = paymentResultData.errors?.[0]; const errorCode = error ? `${error.type}.${error.code}` : "payment.default"; - redirect( - paths.checkout.payment.asPath({ + redirect({ + href: paths.checkout.payment.asPath({ query: { [QUERY_PARAMS.errorCode]: errorCode, }, }), - ); + locale, + }); } return ( diff --git a/apps/storefront/src/app/[locale]/(main)/search/actions.ts b/apps/storefront/src/app/[locale]/(main)/search/actions.ts index 90050ec..debf58e 100644 --- a/apps/storefront/src/app/[locale]/(main)/search/actions.ts +++ b/apps/storefront/src/app/[locale]/(main)/search/actions.ts @@ -1,8 +1,9 @@ "use server"; -import { redirect } from "next/navigation"; +import { getLocale } from "next-intl/server"; import { DEFAULT_SORT_BY } from "@/config"; +import { redirect } from "@/i18n/routing"; import { paths } from "@/lib/paths"; const passThroughParams = ["sortBy", "limit", "q"] as const; @@ -13,6 +14,7 @@ export const handleFiltersFormSubmit = async ( ) => { const formClear = formData.has("clear"); const params = new URLSearchParams(); + const locale = await getLocale(); formData.forEach((value, key) => { if (value && typeof value === "string" && !formClear) { @@ -42,9 +44,10 @@ export const handleFiltersFormSubmit = async ( } }); - return redirect( - paths.search.asPath({ + return redirect({ + href: paths.search.asPath({ query: Object.fromEntries(params), }), - ); + locale, + }); }; diff --git a/apps/storefront/src/components/account-menu/actions.ts b/apps/storefront/src/components/account-menu/actions.ts index f01be30..da012b5 100644 --- a/apps/storefront/src/components/account-menu/actions.ts +++ b/apps/storefront/src/components/account-menu/actions.ts @@ -1,15 +1,17 @@ "use server"; import { revalidatePath } from "next/cache"; -import { redirect } from "next/navigation"; +import { getLocale } from "next-intl/server"; import { signOut } from "@/auth"; +import { redirect } from "@/i18n/routing"; import { handleLogout } from "@/lib/actions/auth"; import { paths } from "@/lib/paths"; import { errorService } from "@/services"; export async function logout() { await handleLogout(); + const locale = await getLocale(); try { await signOut(); @@ -18,5 +20,8 @@ export async function logout() { } revalidatePath(paths.home.asPath()); - redirect(paths.home.asPath({ query: { loggedOut: "true" } })); + redirect({ + href: paths.home.asPath({ query: { loggedOut: "true" } }), + locale, + }); } diff --git a/apps/storefront/src/components/header/actions.ts b/apps/storefront/src/components/header/actions.ts index cd50177..f7a01bd 100644 --- a/apps/storefront/src/components/header/actions.ts +++ b/apps/storefront/src/components/header/actions.ts @@ -1,14 +1,19 @@ "use server"; -import { redirect } from "next/navigation"; +import { getLocale } from "next-intl/server"; import { z } from "zod"; +import { redirect } from "@/i18n/routing"; import { paths } from "@/lib/paths"; const searchFormSchema = z.object({ query: z.string().default("") }); export const performSearch = async (formData: FormData) => { const parsedFormData = searchFormSchema.parse(Object.fromEntries(formData)); + const locale = await getLocale(); - redirect(paths.search.asPath({ query: { q: parsedFormData.query } })); + redirect({ + href: paths.search.asPath({ query: { q: parsedFormData.query } }), + locale, + }); }; diff --git a/apps/storefront/src/components/summary/side-summary.tsx b/apps/storefront/src/components/summary/side-summary.tsx index 62d1404..f2ff02b 100644 --- a/apps/storefront/src/components/summary/side-summary.tsx +++ b/apps/storefront/src/components/summary/side-summary.tsx @@ -1,11 +1,11 @@ import { cookies } from "next/headers"; -import { redirect } from "next/navigation"; -import { getTranslations } from "next-intl/server"; +import { getLocale, getTranslations } from "next-intl/server"; import { Button } from "@nimara/ui/components/button"; import { Sheet, SheetContent, SheetTrigger } from "@nimara/ui/components/sheet"; import { COOKIE_KEY } from "@/config"; +import { redirect } from "@/i18n/routing"; import { paths } from "@/lib/paths"; import { getCurrentRegion } from "@/regions/server"; import { checkoutService } from "@/services"; @@ -15,13 +15,14 @@ import { Summary } from "./summary"; export const SideSummary = async () => { const checkoutId = (await cookies()).get(COOKIE_KEY.checkoutId)?.value; - const [t, region] = await Promise.all([ + const [t, region, locale] = await Promise.all([ getTranslations("common"), getCurrentRegion(), + getLocale(), ]); if (!checkoutId) { - redirect(paths.cart.asPath()); + redirect({ href: paths.cart.asPath(), locale }); } const { checkout } = await checkoutService.checkoutGet({ @@ -31,7 +32,7 @@ export const SideSummary = async () => { }); if (!checkout) { - redirect(paths.cart.asPath()); + redirect({ href: paths.cart.asPath(), locale }); } return ( diff --git a/apps/storefront/src/i18n/routing.ts b/apps/storefront/src/i18n/routing.ts index 29e517c..b77b38d 100644 --- a/apps/storefront/src/i18n/routing.ts +++ b/apps/storefront/src/i18n/routing.ts @@ -24,5 +24,9 @@ export const routing = defineRouting({ }, }); -export const { Link, redirect, usePathname, useRouter } = - createNavigation(routing); +const { redirect: _redirect } = createNavigation(routing); + +// Help TypeScript detect unreachable code +export const redirect: typeof _redirect = _redirect; + +export const { Link, usePathname, useRouter } = createNavigation(routing); diff --git a/apps/storefront/src/lib/checkout.ts b/apps/storefront/src/lib/checkout.ts index 84ec5b6..d57ebc5 100644 --- a/apps/storefront/src/lib/checkout.ts +++ b/apps/storefront/src/lib/checkout.ts @@ -1,9 +1,10 @@ import { cookies } from "next/headers"; -import { redirect } from "next/navigation"; +import { getLocale } from "next-intl/server"; import { type Address } from "@nimara/domain/objects/Address"; import { COOKIE_KEY } from "@/config"; +import { redirect } from "@/i18n/routing"; import { deleteCheckoutIdCookie } from "@/lib/actions/checkout"; import { paths } from "@/lib/paths"; import { getCurrentRegion } from "@/regions/server"; @@ -15,11 +16,11 @@ export const getCheckoutOrRedirect = async (): Promise< NonNullable > => { const checkoutId = (await cookies()).get(COOKIE_KEY.checkoutId)?.value; - + const locale = await getLocale(); const region = await getCurrentRegion(); if (!checkoutId) { - redirect(paths.cart.asPath()); + redirect({ href: paths.cart.asPath(), locale }); } const { checkout } = await checkoutService.checkoutGet({ @@ -30,7 +31,7 @@ export const getCheckoutOrRedirect = async (): Promise< if (!checkout) { await deleteCheckoutIdCookie(); - redirect(paths.cart.asPath()); + redirect({ href: paths.cart.asPath(), locale }); } return checkout;