feat(auth): admin user updates added

if a password change happens then an email will be sent to the user.
This commit is contained in:
2025-03-30 08:40:49 -05:00
parent 09c0825194
commit a48d4bd5af
12 changed files with 569 additions and 131 deletions

View File

@@ -0,0 +1,43 @@
import {
Accordion,
AccordionContent,
AccordionItem,
AccordionTrigger,
} from "@/components/ui/accordion";
import { getUsers } from "@/utils/querys/admin/users";
import { useQuery } from "@tanstack/react-query";
import UserCard from "./components/UserCard";
export default function UserPage() {
const { data, isError, error, isLoading } = useQuery(getUsers());
if (isLoading) return <div className="m-auto">Loading users...</div>;
if (isError)
return (
<div className="m-auto">
There was an error getting the users.... {JSON.stringify(error)}
</div>
);
return (
<div className="m-2 w-dvw">
<Accordion type="single" collapsible>
{data.map((u: any) => {
return (
<AccordionItem key={u.user_id} value={u.user_id}>
<AccordionTrigger>
<span>{u.username}</span>
</AccordionTrigger>
<AccordionContent>
<div>
<UserCard user={u} />
</div>
</AccordionContent>
</AccordionItem>
);
})}
</Accordion>
</div>
);
}

View File

@@ -0,0 +1,183 @@
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { userFormOptions } from "@/utils/formStuff/options/userformOptions";
import { generatePassword } from "@/utils/passwordGen";
import { useForm } from "@tanstack/react-form";
import axios from "axios";
import { toast } from "sonner";
export default function UserCard(data: any) {
const token = localStorage.getItem("auth_token");
const form = useForm({
...userFormOptions(data.user),
onSubmit: async ({ value }) => {
// Do something with form data
const userData = { ...value, user_id: data.user.user_id };
try {
const res = await axios.patch(
"/api/auth/updateuser",
userData,
{
headers: {
Authorization: `Bearer ${token}`,
},
}
);
if (res.data.success) {
toast.success(res.data.message);
form.reset();
} else {
res.data.message;
}
} catch (error) {
console.log(error);
}
},
});
return (
<div>
<form
onSubmit={(e) => {
e.preventDefault();
e.stopPropagation();
}}
>
<form.Field
name="username"
validators={{
// We can choose between form-wide and field-specific validators
onChange: ({ value }) =>
value.length > 3
? undefined
: "Username must be longer than 3 letters",
}}
children={(field) => {
return (
<div className="m-2 min-w-48 max-w-96 p-2">
<Label htmlFor="username">Username</Label>
<Input
name={field.name}
value={field.state.value}
onBlur={field.handleBlur}
//type="number"
onChange={(e) =>
field.handleChange(e.target.value)
}
/>
{field.state.meta.errors.length ? (
<em>{field.state.meta.errors.join(",")}</em>
) : null}
</div>
);
}}
/>
<form.Field
name="email"
validators={{
// We can choose between form-wide and field-specific validators
onChange: ({ value }) =>
value.length > 3
? undefined
: "You must enter a correct ",
}}
children={(field) => {
return (
<div className="m-2 min-w-48 max-w-96 p-2">
<Label htmlFor="email">Email</Label>
<Input
name={field.name}
value={field.state.value}
onBlur={field.handleBlur}
//type="number"
onChange={(e) =>
field.handleChange(e.target.value)
}
/>
{field.state.meta.errors.length ? (
<em>{field.state.meta.errors.join(",")}</em>
) : null}
</div>
);
}}
/>
<form.Field
name="password"
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="password">
Change Password
</Label>
<div className="mt-2 flex flex-row">
<Input
name={field.name}
value={field.state.value}
onBlur={field.handleBlur}
//type="number"
onChange={(e) =>
field.handleChange(e.target.value)
}
/>
<Button
className="ml-2"
onClick={() =>
field.handleChange(
generatePassword(8)
)
}
>
Random password
</Button>
</div>
{field.state.meta.errors.length ? (
<em>{field.state.meta.errors.join(",")}</em>
) : null}
</div>
);
}}
/>
</form>
<div>
<Button onClick={form.handleSubmit}>Save</Button>
</div>
</div>
);
}