Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(core): enforce use of next-intl's navigation APIs #1361

Merged
merged 3 commits into from
Sep 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/beige-clouds-whisper.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@bigcommerce/catalyst-core": patch
---

Enforce use of next-intl's wrapper navigation APIs.
22 changes: 21 additions & 1 deletion core/.eslintrc.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,21 @@ const config = {
name: 'next/link',
message: "Please import 'Link' from '~/components/Link' instead.",
},
{
name: '~/i18n/routing',
importNames: ['Link'],
message: "Please import 'Link' from '~/components/Link' instead.",
},
{
name: 'next/router',
importNames: ['useRouter'],
message: 'Please import from `~/i18n/routing` instead.',
},
{
name: 'next/navigation',
importNames: ['redirect', 'permanentRedirect', 'useRouter', 'usePathname'],
message: 'Please import from `~/i18n/routing` instead.',
},
],
},
],
Expand All @@ -37,7 +52,12 @@ const config = {
},
],
},
ignorePatterns: ['client/generated/**/*.ts', 'playwright-report/**', 'test-results/**', '**/google_analytics4.js'],
ignorePatterns: [
'client/generated/**/*.ts',
'playwright-report/**',
'test-results/**',
'**/google_analytics4.js',
],
};

module.exports = config;
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { redirect } from 'next/navigation';
import { useTranslations } from 'next-intl';

import { redirect } from '~/i18n/routing';

import { ChangePasswordForm } from './_components/change-password-form';

export const metadata = {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
'use server';

import { isRedirectError } from 'next/dist/client/components/redirect';
import { redirect } from 'next/navigation';

import { Credentials, signIn } from '~/auth';
import { redirect } from '~/i18n/routing';

export const login = async (_previousState: unknown, formData: FormData) => {
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ export const LoginForm = () => {
const [state, formAction] = useFormState(login, { status: 'idle' });
const { accountState } = useAccountStatusContext();

const isFormInvalid = state.status === 'error';
const isFormInvalid = state?.status === 'error';

const handleInputValidation = (e: ChangeEvent<HTMLInputElement>) => {
const validationStatus = e.target.validity.valueMissing;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
'use server';

import { isRedirectError } from 'next/dist/client/components/redirect';
import { redirect } from 'next/navigation';

import { Credentials, signIn } from '~/auth';
import { redirect } from '~/i18n/routing';

export const login = async (formData: FormData) => {
try {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
'use client';

import { useRouter } from 'next/navigation';
import { useTranslations } from 'next-intl';
import { ChangeEvent, useEffect, useRef, useState } from 'react';
import { useFormStatus } from 'react-dom';
Expand All @@ -19,6 +18,7 @@ import {
Input,
} from '~/components/ui/form';
import { Message } from '~/components/ui/message';
import { useRouter } from '~/i18n/routing';

import { resetPassword } from '../../_actions/reset-password';

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
'use client';

import { usePathname, useRouter, useSearchParams } from 'next/navigation';
import { useSearchParams } from 'next/navigation';
import { useTranslations } from 'next-intl';
import { FormEvent, useRef, useTransition } from 'react';

Expand All @@ -9,6 +9,7 @@ import { Accordions } from '~/components/ui/accordions';
import { Button } from '~/components/ui/button';
import { Checkbox, Input, Label } from '~/components/ui/form';
import { Rating } from '~/components/ui/rating';
import { usePathname, useRouter } from '~/i18n/routing';
import { cn } from '~/lib/utils';

import type { Facet, PageType } from '../types';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
'use client';

import { usePathname, useRouter, useSearchParams } from 'next/navigation';
import { useSearchParams } from 'next/navigation';
import { useTranslations } from 'next-intl';
import { useTransition } from 'react';

import { Tag } from '~/components/ui/tag';
import { usePathname, useRouter } from '~/i18n/routing';

import type { Facet, PageType, PublicParamKeys } from '../types';

Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
'use client';

import { usePathname, useRouter, useSearchParams } from 'next/navigation';
import { useSearchParams } from 'next/navigation';
import { useTranslations } from 'next-intl';
import { useTransition } from 'react';

import { Select } from '~/components/ui/form';
import { usePathname, useRouter } from '~/i18n/routing';

export function SortBy() {
const router = useRouter();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
'use client';

import { usePathname } from 'next/navigation';
import { createContext, ReactNode, useContext, useEffect, useState } from 'react';

import { usePathname } from '~/i18n/routing';

import { State as AccountState } from '../settings/change-password/_actions/change-password';

const defaultState: AccountState = { status: 'idle', message: '' };
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
'use client';

import { useRouter } from 'next/navigation';
import { useTranslations } from 'next-intl';
import { MouseEvent, useEffect, useRef, useState } from 'react';
import { useFormStatus } from 'react-dom';
Expand Down Expand Up @@ -35,6 +34,7 @@ import { Link } from '~/components/link';
import { Button } from '~/components/ui/button';
import { Field, Form, FormSubmit } from '~/components/ui/form';
import { Message } from '~/components/ui/message';
import { useRouter } from '~/i18n/routing';

import { useAccountStatusContext } from '../../../_components/account-status-provider';
import { addAddress } from '../_actions/add-address';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
'use client';

import { useRouter } from 'next/navigation';
import { useTranslations } from 'next-intl';
import { MouseEvent, useEffect, useRef, useState } from 'react';
import { useFormStatus } from 'react-dom';
Expand Down Expand Up @@ -36,6 +35,7 @@ import { Link } from '~/components/link';
import { Button } from '~/components/ui/button';
import { Field, Form, FormSubmit } from '~/components/ui/form';
import { Message } from '~/components/ui/message';
import { useRouter } from '~/i18n/routing';

import { useAccountStatusContext } from '../../../../_components/account-status-provider';
import { Modal } from '../../../../_components/modal';
Expand Down
2 changes: 1 addition & 1 deletion core/app/[locale]/(default)/account/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { redirect } from 'next/navigation';
import { PropsWithChildren } from 'react';

import { auth } from '~/auth';
import { redirect } from '~/i18n/routing';

export default async function AccountLayout({ children }: PropsWithChildren) {
const session = await auth();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
'use server';

import { redirect } from 'next/navigation';
import { z } from 'zod';

import { getSessionCustomerId } from '~/auth';
import { client } from '~/client';
import { graphql } from '~/client/graphql';
import { redirect } from '~/i18n/routing';

const CheckoutRedirectMutation = graphql(`
mutation CheckoutRedirectMutation($cartId: String!) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { removeEdgesAndNodes } from '@bigcommerce/catalyst-client';
import { usePathname, useRouter, useSearchParams } from 'next/navigation';
import { useSearchParams } from 'next/navigation';

import { FragmentOf } from '~/client/graphql';
import { Label, PickList, RadioGroup, RectangleList, Select, Swatch } from '~/components/ui/form';
import { usePathname, useRouter } from '~/i18n/routing';

import { useProductFieldController } from '../../use-product-form';
import { ErrorMessage } from '../shared/error-message';
Expand Down
2 changes: 1 addition & 1 deletion core/app/admin/route.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { redirect } from 'next/navigation';
import { redirect } from '~/i18n/routing';

const canonicalDomain: string = process.env.BIGCOMMERCE_GRAPHQL_API_DOMAIN ?? 'mybigcommerce.com';
const BIGCOMMERCE_STORE_HASH = process.env.BIGCOMMERCE_STORE_HASH;
Expand Down
2 changes: 1 addition & 1 deletion core/app/xmlsitemap.php/route.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* eslint-disable check-file/folder-naming-convention */
import { permanentRedirect } from 'next/navigation';
import { permanentRedirect } from '~/i18n/routing';

/*
* This route is used to redirect the legacy Stencil sitemap that lives on /xmlsitemap.php
Expand Down
3 changes: 1 addition & 2 deletions core/components/header/_actions/logout.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
'use server';

import { redirect } from 'next/navigation';

import { signOut } from '~/auth';
import { redirect } from '~/i18n/routing';

export const logout = async () => {
await signOut({ redirect: false });
Expand Down
3 changes: 2 additions & 1 deletion core/components/ui/pagination/pagination.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { ChevronLeft, ChevronRight } from 'lucide-react';
import { usePathname, useSearchParams } from 'next/navigation';
import { useSearchParams } from 'next/navigation';

import { Link as CustomLink } from '~/components/link';
import { usePathname } from '~/i18n/routing';
import { cn } from '~/lib/utils';

interface Props {
Expand Down
5 changes: 4 additions & 1 deletion core/i18n/routing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,4 +84,7 @@ export const routing = defineRouting({

// Lightweight wrappers around Next.js' navigation APIs
// that will consider the routing configuration
export const { Link, redirect, usePathname, useRouter } = createSharedPathnamesNavigation(routing);
// Redirect will append locale prefix even when in default locale
// More info: https://github.com/amannn/next-intl/issues/1335
export const { Link, redirect, usePathname, useRouter, permanentRedirect } =
createSharedPathnamesNavigation(routing);
2 changes: 1 addition & 1 deletion core/tests/ui/desktop/e2e/login.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ test('Account login and logout', async ({ page }) => {

await page.getByRole('menuitem', { name: 'Log out' }).click();

await page.waitForURL('/login/');
await page.waitForURL('/en/login/');

await expect(page.getByRole('heading', { name: 'Log in' })).toBeVisible();
});
2 changes: 1 addition & 1 deletion core/tests/ui/desktop/e2e/register.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,6 @@ test('Account register', async ({ page }) => {

await page.getByRole('button', { name: 'Create account' }).click();

await expect(page).toHaveURL('/account/');
await expect(page).toHaveURL('/en/account/');
await expect(page.getByText('Your account has been successfully created')).toBeVisible();
});
Loading