Rename interfaces, AppBar changes

This commit is contained in:
cracklesparkle
2024-06-28 12:33:07 +09:00
parent c41e59cd86
commit af1d497715
13 changed files with 165 additions and 80 deletions

View File

@ -10,7 +10,7 @@ import ApiTest from "./pages/ApiTest"
import SignUp from "./pages/auth/SignUp" import SignUp from "./pages/auth/SignUp"
import { initAuth, useAuthStore } from "./store/auth" import { initAuth, useAuthStore } from "./store/auth"
import { useEffect, useState } from "react" import { useEffect, useState } from "react"
import { CircularProgress } from "@mui/material" import { Box, CircularProgress, Container } from "@mui/material"
function App() { function App() {
const auth = useAuthStore() const auth = useAuthStore()
@ -33,7 +33,10 @@ function App() {
) )
} else { } else {
return ( return (
<> <Box sx={{
width: "100%",
height: "100vh"
}}>
<Router> <Router>
<Routes> <Routes>
<Route element={<MainLayout />}> <Route element={<MainLayout />}>
@ -50,7 +53,7 @@ function App() {
</Route> </Route>
</Routes> </Routes>
</Router> </Router>
</> </Box>
) )
} }
} }

View File

@ -6,9 +6,7 @@ import MenuItem from '@mui/material/MenuItem';
import ListItemIcon from '@mui/material/ListItemIcon'; import ListItemIcon from '@mui/material/ListItemIcon';
import Divider from '@mui/material/Divider'; import Divider from '@mui/material/Divider';
import IconButton from '@mui/material/IconButton'; import IconButton from '@mui/material/IconButton';
import Typography from '@mui/material/Typography';
import Tooltip from '@mui/material/Tooltip'; import Tooltip from '@mui/material/Tooltip';
import PersonAdd from '@mui/icons-material/PersonAdd';
import Settings from '@mui/icons-material/Settings'; import Settings from '@mui/icons-material/Settings';
import Logout from '@mui/icons-material/Logout'; import Logout from '@mui/icons-material/Logout';

View File

@ -9,7 +9,8 @@ export default function DataTable(props: Props) {
return ( return (
<DataGrid <DataGrid
style={{ width: "100%", height: "100%" }} autoHeight
style={{ width: "100%" }}
rows={props.rows} rows={props.rows}
columns={props.columns} columns={props.columns}
initialState={{ initialState={{
@ -19,9 +20,16 @@ export default function DataTable(props: Props) {
}} }}
pageSizeOptions={[10, 20, 50, 100]} pageSizeOptions={[10, 20, 50, 100]}
checkboxSelection checkboxSelection
disableRowSelectionOnClick disableRowSelectionOnClick
processRowUpdate={(updatedRow, originalRow) => {
console.log(updatedRow)
return updatedRow
}}
onProcessRowUpdateError={(error)=>{
console.log(error)
}}
/> />
); );
} }

View File

@ -1,11 +1,97 @@
import React from 'react' import { SubmitHandler, useForm } from 'react-hook-form';
import { IRoleCreate } from '../../interfaces/role';
import { AxiosResponse } from 'axios';
import { ApiResponse } from '../../interfaces/auth';
import RoleService from '../../services/RoleService';
import { Box, Button, Modal, TextField, Typography } from '@mui/material';
const CreateRoleModal = () => { interface Props {
return ( open: boolean;
<div> setOpen: (state: boolean) => void;
</div>
)
} }
export default CreateRoleModal const style = {
position: 'absolute' as 'absolute',
top: '50%',
left: '50%',
transform: 'translate(-50%, -50%)',
width: 400,
bgcolor: 'background.paper',
boxShadow: 24,
borderRadius: 2,
p: 4,
display: "flex",
flexDirection: "column",
gap: "8px"
}
export default function CreateRoleModal({
open,
setOpen
}: Props) {
const { register, handleSubmit, formState: { errors } } = useForm<IRoleCreate>({
defaultValues: {
name: '',
description: ''
}
})
const onSubmit: SubmitHandler<IRoleCreate> = async (data) => {
try {
const response: AxiosResponse<ApiResponse> = await RoleService.createRole(data)
console.log(response.data)
} catch (error) {
console.error(error)
}
}
return (
<Modal
open={open}
onClose={() => setOpen(false)}
aria-labelledby="modal-modal-title"
aria-describedby="modal-modal-description"
>
<form onSubmit={handleSubmit(onSubmit)}>
<Box sx={style}>
<Typography variant="h6" component="h6" gutterBottom>
Создание роли
</Typography>
<TextField
fullWidth
margin="normal"
label="Название"
required
{...register('name', { required: 'Название обязательно' })}
error={!!errors.name}
helperText={errors.name?.message}
/>
<TextField
fullWidth
margin="normal"
label="Описание"
{...register('description')}
error={!!errors.description}
helperText={errors.description?.message}
/>
<Box sx={{
display: "flex",
gap: "8px"
}}>
<Button type="submit" variant="contained" color="primary">
Добавить пользователя
</Button>
<Button type="button" variant="outlined" color="primary" onClick={() => setOpen(false)}>
Отмена
</Button>
</Box>
</Box>
</form>
</Modal>
)
}

View File

@ -3,7 +3,7 @@ import { AxiosResponse } from 'axios';
import { SubmitHandler, useForm } from 'react-hook-form'; import { SubmitHandler, useForm } from 'react-hook-form';
import { ApiResponse } from '../../interfaces/auth'; import { ApiResponse } from '../../interfaces/auth';
import UserService from '../../services/UserService'; import UserService from '../../services/UserService';
import { CreateUserFormData } from '../../interfaces/user'; import { IUserCreate } from '../../interfaces/user';
interface Props { interface Props {
open: boolean; open: boolean;
@ -29,7 +29,7 @@ export default function CreateUserModal({
open, open,
setOpen, setOpen,
}: Props) { }: Props) {
const { register, handleSubmit, formState: { errors } } = useForm<CreateUserFormData>({ const { register, handleSubmit, formState: { errors } } = useForm<IUserCreate>({
defaultValues: { defaultValues: {
email: '', email: '',
login: '', login: '',
@ -41,7 +41,7 @@ export default function CreateUserModal({
} }
}) })
const onSubmit: SubmitHandler<CreateUserFormData> = async (data) => { const onSubmit: SubmitHandler<IUserCreate> = async (data) => {
try { try {
const response: AxiosResponse<ApiResponse> = await UserService.createUser(data) const response: AxiosResponse<ApiResponse> = await UserService.createUser(data)
console.log(response.data) console.log(response.data)

View File

@ -16,18 +16,6 @@ export interface UserCreds extends User {
password: string; password: string;
} }
export interface Role {
name: string;
description?: string | null;
id: number;
}
export interface RoleCreate {
name: string;
description?: string | null;
}
export interface AuthState { export interface AuthState {
isAuthenticated: boolean; isAuthenticated: boolean;
token: string | null; token: string | null;

View File

@ -0,0 +1,10 @@
export interface IRole {
name: string;
description?: string | null;
id: number;
}
export interface IRoleCreate {
name: string;
description?: string | null;
}

View File

@ -1,4 +1,4 @@
export interface CreateUserFormData { export interface IUserCreate {
email: string; email: string;
login: string; login: string;
phone: string; phone: string;

View File

@ -128,7 +128,10 @@ export default function DashboardLayout() {
return ( return (
<ThemeProvider theme={innerTheme}> <ThemeProvider theme={innerTheme}>
<Box sx={{ display: 'flex' }}> <Box sx={{
display: 'flex',
height: "100%"
}}>
<CssBaseline /> <CssBaseline />
<AppBar position="absolute" open={open}> <AppBar position="absolute" open={open}>
<Toolbar <Toolbar
@ -143,7 +146,7 @@ export default function DashboardLayout() {
onClick={toggleDrawer} onClick={toggleDrawer}
sx={{ sx={{
marginRight: '36px', marginRight: '36px',
...(open && { display: 'none' }), //...(open && { display: 'none' }),
}} }}
> >
<MenuIcon /> <MenuIcon />
@ -187,16 +190,18 @@ export default function DashboardLayout() {
}} }}
> >
<Box display="flex" justifyContent={'space-between'} width={"100%"}> <Box display="flex" justifyContent={'space-between'} width={"100%"}>
<IconButton onClick={toggleDrawer}>
<ChevronLeftIcon />
</IconButton>
</Box> </Box>
</Toolbar> </Toolbar>
<Divider /> <Divider />
<List component="nav"> <List component="nav">
{pages.map((item, index) => ( {pages.map((item, index) => (
<ListItem key={index} disablePadding> <ListItem
key={index}
disablePadding
>
<ListItemButton <ListItemButton
onClick={() => { onClick={() => {
navigate(item.path) navigate(item.path)
@ -207,7 +212,9 @@ export default function DashboardLayout() {
<ListItemIcon> <ListItemIcon>
{item.icon} {item.icon}
</ListItemIcon> </ListItemIcon>
<ListItemText primary={item.label} /> <ListItemText
primary={item.label}
/>
</ListItemButton> </ListItemButton>
</ListItem> </ListItem>
))} ))}

View File

@ -1,32 +1,24 @@
import { useState } from 'react' import { useState } from 'react'
import RoleCard from '../components/RoleCard' import { Box, Button, CircularProgress } from '@mui/material'
import Modal from '../components/Modal'
import useDataFetching from '../components/FetchingData'
import RoleService from '../services/RoleService'
import { Box, Button } from '@mui/material'
import DataTable from '../components/DataTable' import DataTable from '../components/DataTable'
import { GridColDef } from '@mui/x-data-grid' import { GridColDef } from '@mui/x-data-grid'
import { useRoles } from '../hooks/swrHooks'
import CreateRoleModal from '../components/modals/CreateRoleModal'
interface IRoleCard { export default function Roles() {
id: number const { roles, isError, isLoading } = useRoles()
name: string
description: string
}
interface Props { const [open, setOpen] = useState(false)
showModal: boolean;
}
function Roles() {
const [showModal, setShowModal] = useState<Props>({ showModal: false });
const cards = useDataFetching<IRoleCard[]>(`${import.meta.env.VITE_API_AUTH_URL}/auth/roles/`, [])
const columns: GridColDef[] = [ const columns: GridColDef[] = [
{ field: 'id', headerName: 'ID', type: "number", width: 70 }, { field: 'id', headerName: 'ID', type: "number", width: 70 },
{ field: 'name', headerName: 'Название', width: 90 }, { field: 'name', headerName: 'Название', width: 90, editable: true },
{ field: 'description', headerName: 'Описание', width: 90 }, { field: 'description', headerName: 'Описание', width: 90, editable: true },
]; ];
if (isError) return <div>Произошла ошибка при получении данных.</div>
if (isLoading) return <CircularProgress />
return ( return (
<Box sx={{ <Box sx={{
display: 'flex', display: 'flex',
@ -35,23 +27,16 @@ function Roles() {
gap: '16px', gap: '16px',
flexGrow: 1 flexGrow: 1
}}> }}>
<Button onClick={() => console.log("TODO: Add")}> <Button onClick={() => setOpen(true)}>
Добавить роль Добавить роль
</Button> </Button>
{cards && <CreateRoleModal
<DataTable rows={cards} columns={columns} /> open={open}
} setOpen={setOpen}
/>
<DataTable rows={roles} columns={columns} />
</Box> </Box>
) )
return (
<div>
{cards.length > 0 && cards.map((card, index) => <RoleCard key={index} {...card} />)}
<button className='absolute w-0 h-0' onClick={() => setShowModal({ showModal: true })}>+</button>
<Modal {...showModal} />
</div>
)
} }
export default Roles

View File

@ -2,7 +2,7 @@ import { Box, Button, CircularProgress } from "@mui/material"
import DataTable from "../components/DataTable" import DataTable from "../components/DataTable"
import { GridColDef } from "@mui/x-data-grid" import { GridColDef } from "@mui/x-data-grid"
import { useRoles, useUsers } from "../hooks/swrHooks" import { useRoles, useUsers } from "../hooks/swrHooks"
import { Role } from "../interfaces/auth" import { IRole } from "../interfaces/role"
import { useState } from "react" import { useState } from "react"
import CreateUserModal from "../components/modals/CreateUserModal" import CreateUserModal from "../components/modals/CreateUserModal"
@ -26,7 +26,7 @@ export default function Users() {
headerName: 'Роль', headerName: 'Роль',
valueGetter: (value, row) => { valueGetter: (value, row) => {
if (roles) { if (roles) {
const roleName = roles.find((role: Role) => role.id === value).name const roleName = roles.find((role: IRole) => role.id === value).name
return roleName return roleName
} else { } else {
return value return value

View File

@ -3,10 +3,10 @@ import { TextField, Button, Container, Typography, Box } from '@mui/material';
import { AxiosResponse } from 'axios'; import { AxiosResponse } from 'axios';
import { ApiResponse } from '../../interfaces/auth'; import { ApiResponse } from '../../interfaces/auth';
import UserService from '../../services/UserService'; import UserService from '../../services/UserService';
import { CreateUserFormData } from '../../interfaces/user'; import { IUserCreate } from '../../interfaces/user';
const SignUp = () => { const SignUp = () => {
const { register, handleSubmit, formState: { errors } } = useForm<CreateUserFormData>({ const { register, handleSubmit, formState: { errors } } = useForm<IUserCreate>({
defaultValues: { defaultValues: {
email: '', email: '',
login: '', login: '',
@ -19,7 +19,7 @@ const SignUp = () => {
}) })
const onSubmit: SubmitHandler<CreateUserFormData> = async (data) => { const onSubmit: SubmitHandler<IUserCreate> = async (data) => {
try { try {
const response: AxiosResponse<ApiResponse> = await UserService.createUser(data) const response: AxiosResponse<ApiResponse> = await UserService.createUser(data)
console.log('Успешная регистрация:', response.data); console.log('Успешная регистрация:', response.data);

View File

@ -1,12 +1,12 @@
import axiosInstance from "../http/axiosInstance"; import axiosInstance from "../http/axiosInstance";
import { Role, RoleCreate } from "../interfaces/auth"; import { IRoleCreate } from "../interfaces/role";
export default class RoleService { export default class RoleService {
static async getRoles() { static async getRoles() {
return await axiosInstance.get(`/auth/roles`) return await axiosInstance.get(`/auth/roles`)
} }
static async createRole(data: RoleCreate) { static async createRole(data: IRoleCreate) {
return await axiosInstance.post(`/auth/roles/`, data) return await axiosInstance.post(`/auth/roles/`, data)
} }