ghost-extension-wallet/src/containers/WalletPopup/pages/ChangePassword.tsx
Uncle Fatso d3274222f9
rewrite extension around new UX
Signed-off-by: Uncle Fatso <uncle.fatso@ghostchain.io>
2026-10-08 18:25:56 +03:00

215 lines
10 KiB
TypeScript

import { useForm, SubmitHandler } from "react-hook-form"
import { rpc } from "../api"
import { z } from "zod"
import { zodResolver } from "@hookform/resolvers/zod"
import { Layout2 } from "@/components/Layout2"
import {
Card,
CardContent,
CardHeader,
CardTitle,
CardDescription,
CardFooter,
} from "@/components/ui/card"
import {
Form,
FormField,
FormItem,
FormLabel,
FormControl,
FormMessage,
} from "@/components/ui/form"
import { Input } from "@/components/ui/input"
import { Button } from "@/components/ui/button"
import { ArrowLeft, EyeOffIcon, EyeIcon } from "lucide-react"
import { cn } from "@/lib/utils"
import { useNavigate } from "react-router-dom"
import { useState } from "react"
import { Header } from "../components"
const changePasswordSchema = z
.object({
currentPassword: z.string().min(1, "Current password is required"),
newPassword: z.string().min(1, "New password is required"),
newPasswordConfirm: z.string(),
})
.refine((data) => data.newPassword === data.newPasswordConfirm, {
message: "New password and confirm new password must match",
path: ["newPasswordConfirm"],
})
type FormFields = z.infer<typeof changePasswordSchema>
export const ChangePassword = () => {
const navigate = useNavigate()
const [showCurrentPassword, setShowCurrentPassword] = useState(false)
const [showNewPassword, setShowNewPassword] = useState(false)
const [showConfirmNewPassword, setShowConfirmNewPassword] = useState(false)
const form = useForm<FormFields>({
resolver: zodResolver(changePasswordSchema),
})
const {
handleSubmit,
reset,
formState: { isSubmitting },
control,
setError,
} = form
const onSubmit: SubmitHandler<FormFields> = async ({
currentPassword,
newPassword,
}) => {
try {
// await rpc.client.changePassword(currentPassword, newPassword)
reset()
navigate("/settings")
} catch (e) {
setError("currentPassword", {
type: "server",
message: "Current password is incorrect",
})
}
}
return (
<Layout2 innerClassName="bg-muted">
<Header />
<Form {...form}>
<form className="relative grow" onSubmit={handleSubmit(onSubmit)}>
<Card className="border-none bg-muted h-full flex flex-col flex-grow w-full max-w-md shadow-none">
<CardHeader>
<CardTitle>Change Password</CardTitle>
</CardHeader>
<CardContent className="content-center flex flex-col flex-grow justify-start">
<FormField
control={control}
name="currentPassword"
render={({ field, fieldState }) => (
<FormItem className="grid gap-2 mb-4">
<FormControl>
<div className="relative">
<Input
{...field}
aria-label="Current Password"
type={showCurrentPassword ? "text" : "password"}
className="pr-10"
placeholder="Enter current password"
/>
<button
className="absolute -translate-y-1/2 top-1/2 -translate-x-1/2 right-2"
onClick={() => setShowCurrentPassword(!showCurrentPassword)}
>
{showCurrentPassword ? (
<EyeOffIcon className="w-5 h-5" />
) : (
<EyeIcon className="w-5 h-5" />
)}
</button>
</div>
</FormControl>
{fieldState.invalid && fieldState.error?.message && (
<span className="text-xs text-red-500">
{fieldState.error?.message}
</span>
)}
</FormItem>
)}
/>
<FormField
control={control}
name="newPassword"
render={({ field, fieldState }) => (
<FormItem className="grid gap-2 mb-4">
<FormControl>
<div className="relative">
<Input
{...field}
aria-label="New Password"
type={showNewPassword ? "text" : "password"}
className="pr-10"
placeholder="Enter new password"
/>
<button
className="absolute -translate-y-1/2 top-1/2 -translate-x-1/2 right-2"
onClick={() => setShowNewPassword(!showNewPassword)}
>
{showNewPassword ? (
<EyeOffIcon className="w-5 h-5" />
) : (
<EyeIcon className="w-5 h-5" />
)}
</button>
</div>
</FormControl>
{fieldState.invalid && fieldState.error?.message && (
<span className="text-xs text-red-500">
{fieldState.error?.message}
</span>
)}
</FormItem>
)}
/>
<FormField
control={control}
name="newPasswordConfirm"
render={({ field, fieldState }) => (
<FormItem className="grid gap-2 mb-4">
<FormControl>
<div className="relative">
<Input
{...field}
aria-label="Confirm New Password"
type={showConfirmNewPassword ? "text" : "password"}
className="pr-10"
placeholder="Confirm new password"
/>
<button
onClick={() => setShowConfirmNewPassword(!showConfirmNewPassword)}
className="absolute -translate-y-1/2 top-1/2 -translate-x-1/2 right-2"
>
{showConfirmNewPassword ? (
<EyeOffIcon className="w-5 h-5" />
) : (
<EyeIcon className="w-5 h-5" />
)}
</button>
</div>
</FormControl>
{fieldState.invalid && fieldState.error?.message && (
<span className="text-xs text-red-500">
{fieldState.error?.message}
</span>
)}
</FormItem>
)}
/>
</CardContent>
<CardFooter className="flex flex-col space-y-4 justify-end">
<Button disabled={isSubmitting} type="submit" size="full" className={cn("text-lg py-3")}>
Change Password
</Button>
<Button
disabled={isSubmitting}
variant="secondary"
size="full"
className={cn("text-lg py-3")}
onClick={() => navigate("/settings")}
>
<ArrowLeft
className="w-5 h-5 mr-2"
aria-hidden="true"
/>
Back
</Button>
</CardFooter>
</Card>
</form>
</Form>
</Layout2>
)
}