Skip to content
Open
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
2 changes: 1 addition & 1 deletion e2e/fixtures/auth.fixtures.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export class LoginFixture {
async run(username: string, password: string) {
await expect(this.page.getByText('Welcome back, please login')).toBeVisible();
await this.page.getByLabel('Username').fill(username);
await this.page.getByLabel('Password').fill(password);
await this.page.getByLabel('Password', { exact: true }).fill(password);
await this.page.getByRole('button', { name: 'Login' }).click();
}

Expand Down
32 changes: 24 additions & 8 deletions frontend/src/components/auth/login-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import {
} from "../ui/form";
import { loginSchema, LoginSchema } from "@/schemas/login-schema";
import z from "zod";
import { useState } from "react";
import { Eye, EyeOff } from "lucide-react";

interface Props {
onSubmit: (data: LoginSchema) => void;
Expand All @@ -23,6 +25,7 @@ interface Props {
export const LoginForm = (props: Props) => {
const { onSubmit, loading, formId } = props;
const { t } = useTranslation();
const [showPassword, setShowPassword] = useState(false);

z.config({
customError: (iss) =>
Expand Down Expand Up @@ -61,15 +64,28 @@ export const LoginForm = (props: Props) => {
<FormItem className="gap-0">
<div className="relative mb-1">
<FormLabel className="mb-2">{t("loginPassword")}</FormLabel>
<FormControl>
<Input
placeholder={t("loginPassword").toLowerCase()}
type="password"
<div className="relative">
<FormControl>
<Input
placeholder={t("loginPassword").toLowerCase()}
type={showPassword ? "text" : "password"}
disabled={loading}
autoComplete="current-password"
className="pr-10"
{...field}
/>
</FormControl>
<button
type="button"
aria-label={t("loginPasswordToggle")}
aria-pressed={showPassword}
disabled={loading}
autoComplete="current-password"
{...field}
/>
</FormControl>
onClick={() => setShowPassword(!showPassword)}
className="text-muted-foreground absolute right-0 top-0 h-9 px-3 rounded-r-md opacity-50 hover:opacity-100 focus-visible:opacity-100 transition-opacity hover:cursor-pointer disabled:pointer-events-none outline-none focus-visible:ring-ring/50 focus-visible:ring-[3px] [&_svg]:size-4"
>
{showPassword ? <EyeOff /> : <Eye />}
</button>
</div>
<a
href="/forgot-password"
onClick={(e) => {
Expand Down
1 change: 1 addition & 0 deletions frontend/src/lib/i18n/locales/en-US.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"loginDivider": "Or",
"loginUsername": "Username",
"loginPassword": "Password",
"loginPasswordToggle": "Toggle password visibility",
"loginSubmit": "Login",
"loginFailTitle": "Failed to log in",
"loginFailSubtitle": "Please check your username and password",
Expand Down
1 change: 1 addition & 0 deletions frontend/src/lib/i18n/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"loginDivider": "Or",
"loginUsername": "Username",
"loginPassword": "Password",
"loginPasswordToggle": "Toggle password visibility",
"loginSubmit": "Login",
"loginFailTitle": "Failed to log in",
"loginFailSubtitle": "Please check your username and password",
Expand Down