Files
lstV2/frontend/src/components/user/PasswordChange.tsx

194 lines
8.4 KiB
TypeScript

import { useForm } from "@tanstack/react-form";
import { useNavigate } from "@tanstack/react-router";
import axios from "axios";
import { useState } from "react";
import { toast } from "sonner";
import { LstCard } from "../extendedUI/LstCard";
import { CardContent, CardHeader } from "../ui/card";
import { Label } from "../ui/label";
import { Input } from "../ui/input";
import { Button } from "../ui/button";
export default function PasswordChange() {
const [saving, setSaving] = useState(false);
const token = localStorage.getItem("auth_token");
const navigate = useNavigate();
const form = useForm({
defaultValues: {
password: "",
confirmPassword: "",
},
onSubmit: async ({ value }) => {
setSaving(true);
try {
const res = await axios.patch("/api/auth/profile", value, {
headers: { Authorization: `Bearer ${token}` },
});
//console.log(res.data);
if (res.data.success) {
localStorage.removeItem("auth_token");
navigate({ to: "/login" });
form.reset();
toast.success(`Your password was just updated.`);
setSaving(false);
}
if (!res.data.success) {
toast.error(res.data.message);
setSaving(false);
}
} catch (error) {
console.log(error);
toast.error("There was an error updating your password");
setSaving(false);
}
},
});
return (
<div>
<LstCard className="w-96 ml-7">
<CardHeader>
<p>Password Change Form</p>
</CardHeader>
<CardContent>
<form
onSubmit={(e) => {
e.preventDefault();
e.stopPropagation();
}}
>
<form.Field
name="password"
// We can choose between form-wide and field-specific validators
validators={{
onChangeAsyncDebounceMs: 500,
onChangeAsync: ({ value }) => {
// if (
// window.location.pathname.includes(
// "/users"
// ) &&
// value.length === 0
// ) {
// return;
// }
if (value.length < 4) {
return "Password must be at least 4 characters long.";
}
if (!/[A-Z]/.test(value)) {
return "Password must contain at least one uppercase letter.";
}
if (!/[a-z]/.test(value)) {
return "Password must contain at least one lower case letter.";
}
if (!/[0-9]/.test(value)) {
return "Password must contain at least one number.";
}
if (
!/[!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?]/.test(
value
)
) {
return "Password must contain at least one special character.";
}
},
}}
children={(field) => {
return (
<div className="m-2 min-w-48 max-w-96 p-2">
<Label
htmlFor="password1"
className="mb-2"
>
Password
</Label>
<Input
name={field.name}
value={field.state.value}
onBlur={field.handleBlur}
type="password"
onChange={(e) =>
field.handleChange(
e.target.value
)
}
/>
{field.state.meta.errors.length ? (
<em>
{field.state.meta.errors.join(
","
)}
</em>
) : null}
</div>
);
}}
/>
<form.Field
name="confirmPassword"
validators={{
onChange: ({ value, fieldApi }) => {
const password =
fieldApi.form.getFieldValue("password");
if (value !== password) {
return "Passwords do not match.";
}
},
}}
>
{(field) => {
return (
<div className="m-2 min-w-48 max-w-96 p-2">
<Label
htmlFor="confirmPassword"
className="mb-2"
>
Confirm Password
</Label>
<Input
name={field.name}
value={field.state.value}
onBlur={field.handleBlur}
type="password"
onChange={(e) =>
field.handleChange(
e.target.value
)
}
/>
{field.state.meta.errors.length ? (
<em>
{field.state.meta.errors.join(
", "
)}
</em>
) : null}
</div>
);
}}
</form.Field>
<div className="mt-4 ml-4 flex justify-end">
<Button
type="submit"
onClick={form.handleSubmit}
disabled={saving}
>
Save
</Button>
</div>
</form>
</CardContent>
</LstCard>
</div>
);
}