feat: add user management

This commit is contained in:
Elias Schneider
2022-12-05 15:53:24 +01:00
parent 31b3f6cb2f
commit 7a3967fd6f
25 changed files with 751 additions and 47 deletions

View File

@@ -0,0 +1,154 @@
import {
Button,
Center,
Container,
Group,
Paper,
PasswordInput,
Stack,
Text,
TextInput,
Title,
} from "@mantine/core";
import { useForm, yupResolver } from "@mantine/form";
import { useModals } from "@mantine/modals";
import { useRouter } from "next/router";
import * as yup from "yup";
import useUser from "../../hooks/user.hook";
import authService from "../../services/auth.service";
import userService from "../../services/user.service";
import toast from "../../utils/toast.util";
const Account = () => {
const user = useUser();
const modals = useModals();
const router = useRouter();
const accountForm = useForm({
initialValues: {
username: user?.username,
email: user?.email,
},
validate: yupResolver(
yup.object().shape({
email: yup.string().email(),
username: yup.string().min(3),
})
),
});
const passwordForm = useForm({
initialValues: {
oldPassword: "",
password: "",
},
validate: yupResolver(
yup.object().shape({
oldPassword: yup.string().min(8),
password: yup.string().min(8),
})
),
});
if (!user) {
router.push("/");
return;
}
return (
<Container size="sm">
<Title order={3} mb="xs">
My account
</Title>
<Paper withBorder p="xl">
<Title order={5} mb="xs">
Account Info
</Title>
<form
onSubmit={accountForm.onSubmit((values) =>
userService
.updateCurrentUser({
username: values.username,
email: values.email,
})
.then(() => toast.success("User updated successfully"))
.catch(toast.axiosError)
)}
>
<Stack>
<TextInput
label="Username"
{...accountForm.getInputProps("username")}
/>
<TextInput
type="email"
label="Email"
{...accountForm.getInputProps("email")}
/>
<Group position="right">
<Button type="submit">Save</Button>
</Group>
</Stack>
</form>
</Paper>
<Paper withBorder p="xl" mt="lg">
<Title order={5} mb="xs">
Password
</Title>
<form
onSubmit={passwordForm.onSubmit((values) =>
authService
.updatePassword(values.oldPassword, values.password)
.then(() => {
toast.success("Password updated successfully");
passwordForm.reset();
})
.catch(toast.axiosError)
)}
>
<Stack>
<PasswordInput
label="Old password"
{...passwordForm.getInputProps("oldPassword")}
/>
<PasswordInput
label="New password"
{...passwordForm.getInputProps("password")}
/>
<Group position="right">
<Button type="submit">Save</Button>
</Group>
</Stack>
</form>
</Paper>
<Center mt={80}>
<Button
variant="light"
color="red"
onClick={() =>
modals.openConfirmModal({
title: "Account deletion",
children: (
<Text size="sm">
Do you really want to delete your account including all your
active shares?
</Text>
),
labels: { confirm: "Delete", cancel: "Cancel" },
confirmProps: { color: "red" },
onConfirm: async () => {
await userService.removeCurrentUser();
window.location.reload();
},
})
}
>
Delete Account
</Button>
</Center>
</Container>
);
};
export default Account;

View File

@@ -1,9 +1,12 @@
import { Space } from "@mantine/core";
import { Space, Title } from "@mantine/core";
import AdminConfigTable from "../../components/admin/AdminConfigTable";
const AdminConfig = () => {
return (
<>
<Title mb={30} order={3}>
Configuration
</Title>
<AdminConfigTable />
<Space h="xl" />
</>

View File

@@ -0,0 +1,62 @@
import { Col, Container, createStyles, Grid, Paper, Text } from "@mantine/core";
import Link from "next/link";
import { TbSettings, TbUsers } from "react-icons/tb";
const managementOptions = [
{
title: "User management",
icon: TbUsers,
route: "/admin/users",
},
{
title: "Configuration",
icon: TbSettings,
route: "/admin/config",
},
];
const useStyles = createStyles((theme) => ({
item: {
display: "flex",
flexDirection: "column",
alignItems: "center",
justifyContent: "center",
textAlign: "center",
height: 90,
"&:hover": {
boxShadow: `${theme.shadows.sm} !important`,
transform: "scale(1.01)",
},
},
}));
const Admin = () => {
const { classes, theme } = useStyles();
return (
<Container size="xl">
<Paper withBorder radius="md" p={40}>
<Grid mt="md">
{managementOptions.map((item) => {
return (
<Col xs={6} key={item.route}>
<Paper
withBorder
component={Link}
href={item.route}
key={item.title}
className={classes.item}
>
<item.icon color={theme.colors.victoria[5]} size={35} />
<Text mt={7}>{item.title}</Text>
</Paper>
</Col>
);
})}
</Grid>
</Paper>
</Container>
);
};
export default Admin;

View File

@@ -0,0 +1,73 @@
import { Button, Group, Space, Text, Title } from "@mantine/core";
import { useModals } from "@mantine/modals";
import { useEffect, useState } from "react";
import { TbPlus } from "react-icons/tb";
import ManageUserTable from "../../components/admin/ManageUserTable";
import showCreateUserModal from "../../components/admin/showCreateUserModal";
import userService from "../../services/user.service";
import User from "../../types/user.type";
import toast from "../../utils/toast.util";
const Users = () => {
const [users, setUsers] = useState<User[]>([]);
const [isLoading, setIsLoading] = useState(true);
const modals = useModals();
const getUsers = () => {
setIsLoading(true);
userService.list().then((users) => {
setUsers(users);
setIsLoading(false);
});
};
const deleteUser = (user: User) => {
modals.openConfirmModal({
title: `Delete ${user.username}?`,
children: (
<Text size="sm">
Do you really want to delete <b>{user.username}</b> and all his
shares?
</Text>
),
labels: { confirm: "Delete", cancel: "Cancel" },
confirmProps: { color: "red" },
onConfirm: async () => {
userService
.remove(user.id)
.then(() => setUsers(users.filter((v) => v.id != user.id)))
.catch(toast.axiosError);
},
});
};
useEffect(() => {
getUsers();
}, []);
return (
<>
<Group position="apart" align="baseline" mb={20}>
<Title mb={30} order={3}>
User management
</Title>
<Button
onClick={() => showCreateUserModal(modals, getUsers)}
leftIcon={<TbPlus size={20} />}
>
Create
</Button>
</Group>
<ManageUserTable
users={users}
getUsers={getUsers}
deleteUser={deleteUser}
isLoading={isLoading}
/>
<Space h="xl" />
</>
);
};
export default Users;