Skip to content

Commit

Permalink
Merge pull request sinamics#496 from sinamics/translate-auth-pages
Browse files Browse the repository at this point in the history
Added translations to public auth pages
  • Loading branch information
sinamics authored Aug 17, 2024
2 parents 796c445 + e7690e7 commit 71ab890
Show file tree
Hide file tree
Showing 23 changed files with 526 additions and 94 deletions.
22 changes: 16 additions & 6 deletions src/__tests__/components/loginForm.test.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { render, screen, fireEvent, waitFor } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { signIn } from "next-auth/react";
import { NextIntlClientProvider } from "next-intl";
import { useRouter } from "next/router";
import { toast } from "react-hot-toast";
import CredentialsForm from "~/components/auth/credentialsForm";
import { ErrorCode } from "~/utils/errorCode";
import enTranslation from "~/locales/en/common.json";

jest.mock("next-auth/react", () => ({
signIn: jest.fn(),
Expand All @@ -20,6 +22,14 @@ jest.mock("react-hot-toast", () => ({
},
}));

const renderWithIntl = (ui, { locale = "en", messages = enTranslation } = {}) => {
return render(
<NextIntlClientProvider locale={locale} messages={messages}>
{ui}
</NextIntlClientProvider>,
);
};

describe("CredentialsForm", () => {
beforeEach(() => {
(signIn as jest.Mock).mockReset();
Expand All @@ -28,7 +38,7 @@ describe("CredentialsForm", () => {
});

it("updates email and password inputs on change", () => {
render(<CredentialsForm />);
renderWithIntl(<CredentialsForm />);

const emailInput = screen.getByPlaceholderText("[email protected]");
const passwordInput = screen.getByPlaceholderText("Enter your password");
Expand All @@ -41,7 +51,7 @@ describe("CredentialsForm", () => {
});

it("submits the form with correct email and password", async () => {
render(<CredentialsForm />);
renderWithIntl(<CredentialsForm />);

(signIn as jest.Mock).mockResolvedValue({ ok: true });

Expand All @@ -62,7 +72,7 @@ describe("CredentialsForm", () => {
});

it("shows TOTP input when second factor is required", async () => {
render(<CredentialsForm />);
renderWithIntl(<CredentialsForm />);

(signIn as jest.Mock).mockResolvedValue({ error: ErrorCode.SecondFactorRequired });

Expand All @@ -80,7 +90,7 @@ describe("CredentialsForm", () => {
});

it("handles error response from signIn", async () => {
render(<CredentialsForm />);
renderWithIntl(<CredentialsForm />);

const errorMessage = "Invalid credentials";
(signIn as jest.Mock).mockResolvedValue({ ok: false, error: errorMessage });
Expand All @@ -102,7 +112,7 @@ describe("CredentialsForm", () => {
const mockPush = jest.fn();
(useRouter as jest.Mock).mockReturnValue({ push: mockPush });

render(<CredentialsForm />);
renderWithIntl(<CredentialsForm />);

(signIn as jest.Mock).mockResolvedValue({ ok: true });

Expand All @@ -120,7 +130,7 @@ describe("CredentialsForm", () => {
});

it("handles network errors", async () => {
render(<CredentialsForm />);
renderWithIntl(<CredentialsForm />);

const errorMessage = "Network error";
(signIn as jest.Mock).mockRejectedValue(new Error(errorMessage));
Expand Down
15 changes: 8 additions & 7 deletions src/components/auth/credentialsForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import Link from "next/link";
import TOTPInput from "./totpInput";
import FormSubmitButtons from "./formSubmitButton";
import FormInput from "./formInput";
import { useTranslations } from "next-intl";

interface FormData {
email: string;
Expand All @@ -16,7 +17,7 @@ interface FormData {

const CredentialsForm: React.FC = () => {
const router = useRouter();

const t = useTranslations();
const [totpCode, setTotpCode] = useState("");
const [showOTP, setShowOTP] = useState<boolean>(false);
const [loading, setLoading] = useState({ credentials: false, oauth: false });
Expand Down Expand Up @@ -68,12 +69,12 @@ const CredentialsForm: React.FC = () => {
{!showOTP && (
<>
<FormInput
label="Email"
label={t("authPages.form.email")}
name="email"
type="email"
value={formData.email}
onChange={handleChange}
placeholder="[email protected]"
placeholder={t("authPages.form.emailPlaceholder")}
icon={
<svg
xmlns="http://www.w3.org/2000/svg"
Expand All @@ -87,12 +88,12 @@ const CredentialsForm: React.FC = () => {
}
/>
<FormInput
label="Password"
label={t("authPages.form.password")}
name="password"
type="password"
value={formData.password}
onChange={handleChange}
placeholder="Enter your password"
placeholder={t("authPages.form.passwordPlaceholder")}
icon={
<svg
xmlns="http://www.w3.org/2000/svg"
Expand All @@ -114,7 +115,7 @@ const CredentialsForm: React.FC = () => {
href="/auth/forgotPassword"
className="cursor-pointer text-blue-500 hover:text-blue-700"
>
Forgot your password?
{t("authPages.form.forgotPassword")}
</Link>
</div>
</div>
Expand All @@ -124,7 +125,7 @@ const CredentialsForm: React.FC = () => {
<div className="pt-5">
<FormSubmitButtons
loading={loading.credentials}
title={showOTP ? "Verify TOTP" : "Sign in"}
title={showOTP ? t("authPages.form.verify2FA") : t("authPages.form.signIn")}
/>
</div>
</form>
Expand Down
8 changes: 5 additions & 3 deletions src/components/auth/forgotPasswordForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@ import { toast } from "react-hot-toast";
import { useTrpcApiErrorHandler } from "~/hooks/useTrpcApiHandler";
import FormInput from "./formInput";
import FormSubmitButtons from "./formSubmitButton";
import { useTranslations } from "next-intl";

interface FormData {
email: string;
}

const ForgotPasswordForm: React.FC = () => {
const t = useTranslations();
const [loading, setLoading] = useState(false);
const [formData, setFormData] = useState<FormData>({
email: "",
Expand Down Expand Up @@ -47,12 +49,12 @@ const ForgotPasswordForm: React.FC = () => {
return (
<form className="space-y-5" onSubmit={submitHandler}>
<FormInput
label="Email"
label={t("authPages.form.email")}
name="email"
type="text"
value={formData.email}
onChange={handleChange}
placeholder="[email protected]"
placeholder={t("authPages.form.emailPlaceholder")}
icon={
<svg
xmlns="http://www.w3.org/2000/svg"
Expand All @@ -66,7 +68,7 @@ const ForgotPasswordForm: React.FC = () => {
}
/>
<div className="pt-5">
<FormSubmitButtons loading={loading} title="Send Email" />
<FormSubmitButtons loading={loading} title={t("authPages.form.sendMail")} />
</div>
</form>
);
Expand Down
8 changes: 5 additions & 3 deletions src/components/auth/mfaRecoveryForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@ import { toast } from "react-hot-toast";
import { useTrpcApiErrorHandler } from "~/hooks/useTrpcApiHandler";
import FormInput from "./formInput";
import FormSubmitButtons from "./formSubmitButton";
import { useTranslations } from "next-intl";

interface FormData {
email: string;
}

const MfaRecoveryForm: React.FC = () => {
const t = useTranslations();
const [loading, setLoading] = useState(false);

const [formData, setFormData] = useState<FormData>({
Expand Down Expand Up @@ -47,12 +49,12 @@ const MfaRecoveryForm: React.FC = () => {
return (
<form className="space-y-5" onSubmit={submitHandler}>
<FormInput
label="Email"
label={t("authPages.form.email")}
name="email"
type="email"
value={formData.email}
onChange={handleChange}
placeholder="[email protected]"
placeholder={t("authPages.form.emailPlaceholder")}
icon={
<svg
xmlns="http://www.w3.org/2000/svg"
Expand All @@ -67,7 +69,7 @@ const MfaRecoveryForm: React.FC = () => {
/>

<div className="pt-5">
<FormSubmitButtons loading={loading} title="Send Email" />
<FormSubmitButtons loading={loading} title={t("authPages.form.sendMail")} />
</div>
</form>
);
Expand Down
6 changes: 5 additions & 1 deletion src/components/auth/oauthLogin.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { useRouter } from "next/router";
import { useState, useEffect } from "react";
import { toast } from "react-hot-toast";
import cn from "classnames";
import { useTranslations } from "next-intl";

interface OAuthProvider {
id: string;
Expand All @@ -13,6 +14,7 @@ interface OAuthProvider {
}

const OAuthLogin: React.FC = () => {
const t = useTranslations();
const router = useRouter();
const [loading, setLoading] = useState(false);
const [providers, setProviders] = useState<Record<string, OAuthProvider>>({});
Expand Down Expand Up @@ -70,7 +72,9 @@ const OAuthLogin: React.FC = () => {
disabled={loading}
>
{loading ? <span className="loading loading-spinner"></span> : null}
Sign in with {provider.name}
{t("authPages.form.signInWith", {
provider: provider.name,
})}
</button>
))}
</div>
Expand Down
20 changes: 11 additions & 9 deletions src/components/auth/registerForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { api } from "~/utils/api";
import { useTrpcApiErrorHandler } from "~/hooks/useTrpcApiHandler";
import FormInput from "./formInput";
import FormSubmitButtons from "./formSubmitButton";
import { useTranslations } from "next-intl";
interface FormData {
email: string;
password: string;
Expand All @@ -14,6 +15,7 @@ interface FormData {
}

const RegisterForm: React.FC = () => {
const t = useTranslations();
const router = useRouter();
const { invite } = router.query as { invite?: string };

Expand Down Expand Up @@ -63,21 +65,21 @@ const RegisterForm: React.FC = () => {
<form className="space-y-5" onSubmit={submitHandler}>
{invite && (
<FormInput
label="Code"
label={t("authPages.form.invitationCode")}
name="ztnetInvitationCode"
type="text"
value={formData.ztnetInvitationCode}
onChange={handleChange}
placeholder="Invitation code"
placeholder={t("authPages.form.invitationCodePlaceholder")}
/>
)}
<FormInput
label="Name"
label={t("authPages.form.name")}
name="name"
type="text"
value={formData.name}
onChange={handleChange}
placeholder="First & Last Name"
placeholder={t("authPages.form.namePlaceholder")}
icon={
<svg
xmlns="http://www.w3.org/2000/svg"
Expand All @@ -90,12 +92,12 @@ const RegisterForm: React.FC = () => {
}
/>
<FormInput
label="Email"
label={t("authPages.form.email")}
name="email"
type="email"
value={formData.email}
onChange={handleChange}
placeholder="[email protected]"
placeholder={t("authPages.form.emailPlaceholder")}
icon={
<svg
xmlns="http://www.w3.org/2000/svg"
Expand All @@ -109,12 +111,12 @@ const RegisterForm: React.FC = () => {
}
/>
<FormInput
label="Password"
label={t("authPages.form.password")}
name="password"
type="password"
value={formData.password}
onChange={handleChange}
placeholder="Enter your password"
placeholder={t("authPages.form.passwordPlaceholder")}
icon={
<svg
xmlns="http://www.w3.org/2000/svg"
Expand All @@ -131,7 +133,7 @@ const RegisterForm: React.FC = () => {
}
/>
<div className="pt-5">
<FormSubmitButtons loading={loading} title="Sign Up" />
<FormSubmitButtons loading={loading} title={t("authPages.form.signUp")} />
</div>
</form>
);
Expand Down
Loading

0 comments on commit 71ab890

Please sign in to comment.