bid-tool/auto-bid-admin/src/components/user-menu.tsx

181 lines
4.5 KiB
TypeScript

import {
Avatar,
Button,
LoadingOverlay,
Menu,
Modal,
PasswordInput,
} from "@mantine/core";
import { useForm, zodResolver } from "@mantine/form";
import { useDisclosure } from "@mantine/hooks";
import {
IconCode,
IconKey,
IconLogout,
IconSettings,
IconUser,
} from "@tabler/icons-react";
import { useState } from "react";
import { useNavigate } from "react-router";
import { Link } from "react-router-dom";
import { z } from "zod";
import { changePassword, logout } from "../apis/auth";
import { useConfirmStore } from "../lib/zustand/use-confirm";
import Links from "../system/links";
const schema = z
.object({
currentPassword: z
.string()
.min(6, "Current password must be at least 6 characters"),
newPassword: z
.string()
.min(6, "New password must be at least 6 characters"),
confirmPassword: z.string(),
})
.refine((data) => data.newPassword === data.confirmPassword, {
path: ["confirmPassword"],
message: "Passwords do not match",
});
export default function UserMenu() {
const [opened, { open, close }] = useDisclosure(false);
const { setConfirm } = useConfirmStore();
const [loading, setLoading] = useState(false);
const navigate = useNavigate();
const form = useForm({
initialValues: {
currentPassword: "",
newPassword: "",
confirmPassword: "",
},
validate: zodResolver(schema),
});
const handleSubmit = async (values: typeof form.values) => {
await handleChangePassword(values);
};
const handleLogout = async () => {
setConfirm({
title: "Are you wan't to logout?",
message: "This account will logout !",
okButton: { value: "Logout" },
handleOk: async () => {
const data = await logout();
if (data && data.data) {
navigate(Links.LOGIN);
}
},
});
};
const handleChangePassword = async (values: typeof form.values) => {
setConfirm({
title: "Are you wan't to update password",
message: "This account will change password !",
okButton: { value: "Sure" },
handleOk: async () => {
setLoading(true);
const data = await changePassword({
newPassword: values.newPassword,
password: values.currentPassword,
});
setLoading(false);
if (data && data.data) {
navigate(Links.LOGIN);
close();
}
},
});
};
return (
<>
<Menu shadow="md" width={200}>
<Menu.Target>
<Avatar color="blue" radius="xl" className="cursor-pointer">
<IconUser size={20} />
</Avatar>
</Menu.Target>
<Menu.Dropdown>
<Menu.Label>Account</Menu.Label>
<Menu.Item onClick={open} leftSection={<IconSettings size={14} />}>
Change password
</Menu.Item>
<Menu.Item
component={Link}
to={Links.GENERATE_KEYS}
leftSection={<IconKey size={14} />}
>
Keys
</Menu.Item>
<Menu.Item
component={Link}
to={Links.CONFIGS}
leftSection={<IconCode size={14} />}
>
Configs
</Menu.Item>
<Menu.Divider />
<Menu.Item
onClick={handleLogout}
color="red"
leftSection={<IconLogout size={14} />}
>
Logout
</Menu.Item>
</Menu.Dropdown>
</Menu>
<Modal
className="relative"
opened={opened}
onClose={close}
title="Change password"
centered
>
<form
onSubmit={form.onSubmit(handleSubmit)}
className="flex flex-col gap-2.5"
>
<PasswordInput
size="sm"
label="Current password"
{...form.getInputProps("currentPassword")}
/>
<PasswordInput
size="sm"
label="New password"
{...form.getInputProps("newPassword")}
/>
<PasswordInput
size="sm"
label="Confirm password"
{...form.getInputProps("confirmPassword")}
/>
<Button type="submit" fullWidth size="sm" mt="md">
Change
</Button>
</form>
<LoadingOverlay
visible={loading}
zIndex={1000}
overlayProps={{ blur: 2 }}
/>
</Modal>
</>
);
}