mirror of
https://github.com/swissmakers/swiss-datashare.git
synced 2026-04-19 13:33:13 +02:00
feat: add user management
This commit is contained in:
154
frontend/src/pages/account/index.tsx
Normal file
154
frontend/src/pages/account/index.tsx
Normal 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;
|
||||
@@ -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" />
|
||||
</>
|
||||
|
||||
62
frontend/src/pages/admin/index.tsx
Normal file
62
frontend/src/pages/admin/index.tsx
Normal 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;
|
||||
73
frontend/src/pages/admin/users.tsx
Normal file
73
frontend/src/pages/admin/users.tsx
Normal 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;
|
||||
Reference in New Issue
Block a user