forked from VinokurovVE/tests
Layout, Pages, Dashboard, MUI
This commit is contained in:
@ -1,22 +1,31 @@
|
||||
import { BrowserRouter as Router, Routes,Route} from "react-router-dom"
|
||||
import { BrowserRouter as Router, Route, Routes } from "react-router-dom"
|
||||
import Main from "./pages/Main"
|
||||
import Users from "./pages/Users"
|
||||
import Roles from "./pages/Roles"
|
||||
import Main from "./pages/Main"
|
||||
import NotFound from "./pages/NotFound"
|
||||
import Navigate from "./components/Navigate"
|
||||
import DashboardLayout from "./layouts/DashboardLayout"
|
||||
import MainLayout from "./layouts/MainLayout"
|
||||
import SignIn from "./pages/auth/SignIn"
|
||||
import ApiTest from "./pages/ApiTest"
|
||||
|
||||
function App() {
|
||||
return (
|
||||
<>
|
||||
<Navigate />
|
||||
<Router>
|
||||
<Routes>
|
||||
<Route index path="/" element={ <Main />} />
|
||||
<Route path="/user" element={ <Users />} />
|
||||
<Route path="/role" element={ <Roles />} />
|
||||
<Route path="*" element={<NotFound />}/>
|
||||
</Routes>
|
||||
</Router>
|
||||
<Router>
|
||||
<Routes>
|
||||
<Route element={<MainLayout/>}>
|
||||
<Route path="/auth/signin" element={<SignIn/>}/>
|
||||
</Route>
|
||||
|
||||
<Route element={<DashboardLayout />}>
|
||||
<Route path="/" element={<Main />} />
|
||||
<Route path="/user" element={<Users />} />
|
||||
<Route path="/role" element={<Roles />} />
|
||||
<Route path="/api-test" element={<ApiTest />} />
|
||||
<Route path="*" element={<NotFound />} />
|
||||
</Route>
|
||||
</Routes>
|
||||
</Router>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { useState, useEffect, useMemo } from 'react';
|
||||
export function useDataFetching<T> (url:string, initData:T):T{
|
||||
export function useDataFetching<T>(url: string, initData: T): T {
|
||||
const [data, setData] = useState<T>(initData);
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
const fetchData = async () => {
|
||||
const response = await fetch(url);
|
||||
|
@ -1,21 +0,0 @@
|
||||
export default function Navigate(){
|
||||
return(
|
||||
<>
|
||||
<nav className="bg-white border-gray-200 dark:bg-gray-900">
|
||||
<div className="max-w-screen-xl flex flex-wrap items-center justify-between mx-auto p-4">
|
||||
<ul className="font-medium flex flex-col p-4 md:p-0 mt-4 border border-gray-100 rounded-lg bg-gray-50 md:flex-row md:space-x-8 rtl:space-x-reverse md:mt-0 md:border-0 md:bg-white dark:bg-gray-800 md:dark:bg-gray-900 dark:border-gray-700">
|
||||
<li>
|
||||
<a href="/" className="block py-2 px-3 text-gray-900 rounded hover:bg-gray-100 md:hover:bg-transparent md:border-0 md:hover:text-blue-700 md:p-0 dark:text-white md:dark:hover:text-blue-500 dark:hover:bg-gray-700 dark:hover:text-white md:dark:hover:bg-transparent">Главная</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="/user" className="block py-2 px-3 text-gray-900 rounded hover:bg-gray-100 md:hover:bg-transparent md:border-0 md:hover:text-blue-700 md:p-0 dark:text-white md:dark:hover:text-blue-500 dark:hover:bg-gray-700 dark:hover:text-white md:dark:hover:bg-transparent">Пользователи</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="/role" className="block py-2 px-3 text-gray-900 rounded hover:bg-gray-100 md:hover:bg-transparent md:border-0 md:hover:text-blue-700 md:p-0 dark:text-white md:dark:hover:text-blue-500 dark:hover:bg-gray-700 dark:hover:text-white md:dark:hover:bg-transparent">Роли</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
</>
|
||||
)
|
||||
}
|
@ -0,0 +1,171 @@
|
||||
import * as React from 'react';
|
||||
import AppBar from '@mui/material/AppBar';
|
||||
import Box from '@mui/material/Box';
|
||||
import CssBaseline from '@mui/material/CssBaseline';
|
||||
import Divider from '@mui/material/Divider';
|
||||
import Drawer from '@mui/material/Drawer';
|
||||
import IconButton from '@mui/material/IconButton';
|
||||
import InboxIcon from '@mui/icons-material/MoveToInbox';
|
||||
import List from '@mui/material/List';
|
||||
import ListItem from '@mui/material/ListItem';
|
||||
import ListItemButton from '@mui/material/ListItemButton';
|
||||
import ListItemIcon from '@mui/material/ListItemIcon';
|
||||
import ListItemText from '@mui/material/ListItemText';
|
||||
import MailIcon from '@mui/icons-material/Mail';
|
||||
import MenuIcon from '@mui/icons-material/Menu';
|
||||
import Toolbar from '@mui/material/Toolbar';
|
||||
import Typography from '@mui/material/Typography';
|
||||
|
||||
const drawerWidth = 240;
|
||||
|
||||
export default function ResponsiveDrawer() {
|
||||
//const { window } = props;
|
||||
const [mobileOpen, setMobileOpen] = React.useState(false);
|
||||
const [isClosing, setIsClosing] = React.useState(false);
|
||||
|
||||
const handleDrawerClose = () => {
|
||||
setIsClosing(true);
|
||||
setMobileOpen(false);
|
||||
};
|
||||
|
||||
const handleDrawerTransitionEnd = () => {
|
||||
setIsClosing(false);
|
||||
};
|
||||
|
||||
const handleDrawerToggle = () => {
|
||||
if (!isClosing) {
|
||||
setMobileOpen(!mobileOpen);
|
||||
}
|
||||
};
|
||||
|
||||
const drawer = (
|
||||
<div>
|
||||
<Toolbar />
|
||||
|
||||
<Divider />
|
||||
|
||||
<List>
|
||||
{['Inbox', 'Starred', 'Send email', 'Drafts'].map((text, index) => (
|
||||
<ListItem key={text} disablePadding>
|
||||
<ListItemButton>
|
||||
<ListItemIcon>
|
||||
{index % 2 === 0 ? <InboxIcon /> : <MailIcon />}
|
||||
</ListItemIcon>
|
||||
<ListItemText primary={text} />
|
||||
</ListItemButton>
|
||||
</ListItem>
|
||||
))}
|
||||
</List>
|
||||
|
||||
<Divider />
|
||||
|
||||
<List>
|
||||
{['All mail', 'Trash', 'Spam'].map((text, index) => (
|
||||
<ListItem key={text} disablePadding>
|
||||
<ListItemButton>
|
||||
<ListItemIcon>
|
||||
{index % 2 === 0 ? <InboxIcon /> : <MailIcon />}
|
||||
</ListItemIcon>
|
||||
<ListItemText primary={text} />
|
||||
</ListItemButton>
|
||||
</ListItem>
|
||||
))}
|
||||
</List>
|
||||
</div>
|
||||
);
|
||||
|
||||
return (
|
||||
<Box sx={{ display: 'flex' }}>
|
||||
<CssBaseline />
|
||||
<AppBar
|
||||
position="fixed"
|
||||
sx={{
|
||||
width: { sm: `calc(100% - ${drawerWidth}px)` },
|
||||
ml: { sm: `${drawerWidth}px` },
|
||||
}}
|
||||
>
|
||||
<Toolbar>
|
||||
<IconButton
|
||||
color="inherit"
|
||||
aria-label="open drawer"
|
||||
edge="start"
|
||||
onClick={handleDrawerToggle}
|
||||
sx={{ mr: 2, display: { sm: 'none' } }}
|
||||
>
|
||||
<MenuIcon />
|
||||
</IconButton>
|
||||
<Typography variant="h6" noWrap component="div">
|
||||
Dashboard
|
||||
</Typography>
|
||||
</Toolbar>
|
||||
</AppBar>
|
||||
|
||||
<Box
|
||||
component="nav"
|
||||
sx={{ width: { sm: drawerWidth }, flexShrink: { sm: 0 } }}
|
||||
aria-label="mailbox folders"
|
||||
>
|
||||
{/* The implementation can be swapped with js to avoid SEO duplication of links. */}
|
||||
<Drawer
|
||||
variant="temporary"
|
||||
open={mobileOpen}
|
||||
onTransitionEnd={handleDrawerTransitionEnd}
|
||||
onClose={handleDrawerClose}
|
||||
ModalProps={{
|
||||
keepMounted: true, // Better open performance on mobile.
|
||||
}}
|
||||
sx={{
|
||||
display: { xs: 'block', sm: 'none' },
|
||||
'& .MuiDrawer-paper': { boxSizing: 'border-box', width: drawerWidth },
|
||||
}}
|
||||
>
|
||||
{drawer}
|
||||
</Drawer>
|
||||
<Drawer
|
||||
variant="permanent"
|
||||
sx={{
|
||||
display: { xs: 'none', sm: 'block' },
|
||||
'& .MuiDrawer-paper': { boxSizing: 'border-box', width: drawerWidth },
|
||||
}}
|
||||
open
|
||||
>
|
||||
{drawer}
|
||||
</Drawer>
|
||||
</Box>
|
||||
|
||||
<Box
|
||||
component="main"
|
||||
sx={{ flexGrow: 1, p: 3, width: { sm: `calc(100% - ${drawerWidth}px)` } }}
|
||||
>
|
||||
<Toolbar />
|
||||
<Typography paragraph>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
|
||||
tempor incididunt ut labore et dolore magna aliqua. Rhoncus dolor purus non
|
||||
enim praesent elementum facilisis leo vel. Risus at ultrices mi tempus
|
||||
imperdiet. Semper risus in hendrerit gravida rutrum quisque non tellus.
|
||||
Convallis convallis tellus id interdum velit laoreet id donec ultrices.
|
||||
Odio morbi quis commodo odio aenean sed adipiscing. Amet nisl suscipit
|
||||
adipiscing bibendum est ultricies integer quis. Cursus euismod quis viverra
|
||||
nibh cras. Metus vulputate eu scelerisque felis imperdiet proin fermentum
|
||||
leo. Mauris commodo quis imperdiet massa tincidunt. Cras tincidunt lobortis
|
||||
feugiat vivamus at augue. At augue eget arcu dictum varius duis at
|
||||
consectetur lorem. Velit sed ullamcorper morbi tincidunt. Lorem donec massa
|
||||
sapien faucibus et molestie ac.
|
||||
</Typography>
|
||||
<Typography paragraph>
|
||||
Consequat mauris nunc congue nisi vitae suscipit. Fringilla est ullamcorper
|
||||
eget nulla facilisi etiam dignissim diam. Pulvinar elementum integer enim
|
||||
neque volutpat ac tincidunt. Ornare suspendisse sed nisi lacus sed viverra
|
||||
tellus. Purus sit amet volutpat consequat mauris. Elementum eu facilisis
|
||||
sed odio morbi. Euismod lacinia at quis risus sed vulputate odio. Morbi
|
||||
tincidunt ornare massa eget egestas purus viverra accumsan in. In hendrerit
|
||||
gravida rutrum quisque non tellus orci ac. Pellentesque nec nam aliquam sem
|
||||
et tortor. Habitant morbi tristique senectus et. Adipiscing elit duis
|
||||
tristique sollicitudin nibh sit. Ornare aenean euismod elementum nisi quis
|
||||
eleifend. Commodo viverra maecenas accumsan lacus vel facilisis. Nulla
|
||||
posuere sollicitudin aliquam ultrices sagittis orci a.
|
||||
</Typography>
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
}
|
30
frontend_reactjs/src/components/navigation/NavTabs.tsx
Normal file
30
frontend_reactjs/src/components/navigation/NavTabs.tsx
Normal file
@ -0,0 +1,30 @@
|
||||
import { Tab, Tabs } from "@mui/material"
|
||||
import { Link, matchPath, useLocation } from "react-router-dom"
|
||||
|
||||
function useRouteMatch(patterns: readonly string[]) {
|
||||
const { pathname } = useLocation()
|
||||
|
||||
for (let i = 0; i < patterns.length; i += 1) {
|
||||
const pattern = patterns[i]
|
||||
const possibleMatch = matchPath(pattern, pathname)
|
||||
if (possibleMatch !== null) {
|
||||
return possibleMatch
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
export default function NavTabs() {
|
||||
const routeMatch = useRouteMatch(['/', '/user', '/role']);
|
||||
const currentTab = routeMatch?.pattern?.path;
|
||||
|
||||
return (
|
||||
<Tabs value={currentTab}>
|
||||
<Tab label="Главная" value="/" to="/" component={Link} />
|
||||
<Tab label="Пользователи" value="/user" to="/user" component={Link} />
|
||||
<Tab label="Роли" value="/role" to="/role" component={Link} />
|
||||
</Tabs>
|
||||
);
|
||||
|
||||
}
|
0
frontend_reactjs/src/constants/index.ts
Normal file
0
frontend_reactjs/src/constants/index.ts
Normal file
183
frontend_reactjs/src/layouts/DashboardLayout.tsx
Normal file
183
frontend_reactjs/src/layouts/DashboardLayout.tsx
Normal file
@ -0,0 +1,183 @@
|
||||
// Layout for dashboard with responsive drawer
|
||||
|
||||
import { Outlet } from "react-router-dom"
|
||||
import * as React from 'react';
|
||||
import AppBar from '@mui/material/AppBar';
|
||||
import Box from '@mui/material/Box';
|
||||
import CssBaseline from '@mui/material/CssBaseline';
|
||||
import Divider from '@mui/material/Divider';
|
||||
import Drawer from '@mui/material/Drawer';
|
||||
import IconButton from '@mui/material/IconButton';
|
||||
import List from '@mui/material/List';
|
||||
import ListItem from '@mui/material/ListItem';
|
||||
import ListItemButton from '@mui/material/ListItemButton';
|
||||
import ListItemIcon from '@mui/material/ListItemIcon';
|
||||
import ListItemText from '@mui/material/ListItemText';
|
||||
import MenuIcon from '@mui/icons-material/Menu';
|
||||
import Toolbar from '@mui/material/Toolbar';
|
||||
import Typography from '@mui/material/Typography';
|
||||
import { Api, ExitToApp, Home, People, Settings, Shield } from "@mui/icons-material";
|
||||
|
||||
const drawerWidth = 240;
|
||||
|
||||
export default function DashboardLayout() {
|
||||
//const { window } = props;
|
||||
const [mobileOpen, setMobileOpen] = React.useState(false);
|
||||
const [isClosing, setIsClosing] = React.useState(false);
|
||||
|
||||
const handleDrawerClose = () => {
|
||||
setIsClosing(true);
|
||||
setMobileOpen(false);
|
||||
};
|
||||
|
||||
const handleDrawerTransitionEnd = () => {
|
||||
setIsClosing(false);
|
||||
};
|
||||
|
||||
const handleDrawerToggle = () => {
|
||||
if (!isClosing) {
|
||||
setMobileOpen(!mobileOpen);
|
||||
}
|
||||
};
|
||||
|
||||
const pages = [
|
||||
{
|
||||
label: "Главная",
|
||||
path: "/",
|
||||
icon: <Home />
|
||||
},
|
||||
{
|
||||
label: "Пользователи",
|
||||
path: "/user",
|
||||
icon: <People />
|
||||
},
|
||||
{
|
||||
label: "Роли",
|
||||
path: "/role",
|
||||
icon: <Shield />
|
||||
},
|
||||
{
|
||||
label: "API Test",
|
||||
path: "/api-test",
|
||||
icon: <Api />
|
||||
},
|
||||
]
|
||||
|
||||
const misc = [
|
||||
{
|
||||
label: "Настройки",
|
||||
path: "/settings",
|
||||
icon: <Settings />
|
||||
},
|
||||
{
|
||||
label: "Выход",
|
||||
path: "/signOut",
|
||||
icon: <ExitToApp />
|
||||
}
|
||||
]
|
||||
|
||||
const drawer = (
|
||||
<div>
|
||||
<Toolbar />
|
||||
|
||||
<Divider />
|
||||
|
||||
<List>
|
||||
{pages.map((item, index) => (
|
||||
<ListItem key={index} disablePadding>
|
||||
<ListItemButton href={item.path}>
|
||||
<ListItemIcon>
|
||||
{item.icon}
|
||||
</ListItemIcon>
|
||||
<ListItemText primary={item.label} />
|
||||
</ListItemButton>
|
||||
</ListItem>
|
||||
))}
|
||||
</List>
|
||||
|
||||
<Divider />
|
||||
|
||||
<List>
|
||||
{misc.map((item, index) => (
|
||||
<ListItem key={index} disablePadding>
|
||||
<ListItemButton href={item.path}>
|
||||
<ListItemIcon>
|
||||
{item.icon}
|
||||
</ListItemIcon>
|
||||
<ListItemText primary={item.label} />
|
||||
</ListItemButton>
|
||||
</ListItem>
|
||||
))}
|
||||
</List>
|
||||
</div>
|
||||
);
|
||||
|
||||
return (
|
||||
<Box sx={{ display: 'flex' }}>
|
||||
<CssBaseline />
|
||||
<AppBar
|
||||
position="fixed"
|
||||
sx={{
|
||||
width: { sm: `calc(100% - ${drawerWidth}px)` },
|
||||
ml: { sm: `${drawerWidth}px` },
|
||||
}}
|
||||
>
|
||||
<Toolbar>
|
||||
<IconButton
|
||||
color="inherit"
|
||||
aria-label="open drawer"
|
||||
edge="start"
|
||||
onClick={handleDrawerToggle}
|
||||
sx={{ mr: 2, display: { sm: 'none' } }}
|
||||
>
|
||||
<MenuIcon />
|
||||
</IconButton>
|
||||
<Typography variant="h6" noWrap component="div">
|
||||
Dashboard
|
||||
</Typography>
|
||||
</Toolbar>
|
||||
</AppBar>
|
||||
|
||||
<Box
|
||||
component="nav"
|
||||
sx={{ width: { sm: drawerWidth }, flexShrink: { sm: 0 } }}
|
||||
aria-label="mailbox folders"
|
||||
>
|
||||
{/* The implementation can be swapped with js to avoid SEO duplication of links. */}
|
||||
<Drawer
|
||||
variant="temporary"
|
||||
open={mobileOpen}
|
||||
onTransitionEnd={handleDrawerTransitionEnd}
|
||||
onClose={handleDrawerClose}
|
||||
ModalProps={{
|
||||
keepMounted: true, // Better open performance on mobile.
|
||||
}}
|
||||
sx={{
|
||||
display: { xs: 'block', sm: 'none' },
|
||||
'& .MuiDrawer-paper': { boxSizing: 'border-box', width: drawerWidth },
|
||||
}}
|
||||
>
|
||||
{drawer}
|
||||
</Drawer>
|
||||
<Drawer
|
||||
variant="permanent"
|
||||
sx={{
|
||||
display: { xs: 'none', sm: 'block' },
|
||||
'& .MuiDrawer-paper': { boxSizing: 'border-box', width: drawerWidth },
|
||||
}}
|
||||
open
|
||||
>
|
||||
{drawer}
|
||||
</Drawer>
|
||||
</Box>
|
||||
|
||||
<Box
|
||||
component="main"
|
||||
sx={{ flexGrow: 1, p: 3, width: { sm: `calc(100% - ${drawerWidth}px)` } }}
|
||||
>
|
||||
<Toolbar />
|
||||
<Outlet />
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
}
|
11
frontend_reactjs/src/layouts/MainLayout.tsx
Normal file
11
frontend_reactjs/src/layouts/MainLayout.tsx
Normal file
@ -0,0 +1,11 @@
|
||||
// Layout for fullscreen pages
|
||||
|
||||
import { Outlet } from "react-router-dom";
|
||||
|
||||
export default function MainLayout() {
|
||||
return (
|
||||
<>
|
||||
<Outlet/>
|
||||
</>
|
||||
)
|
||||
}
|
@ -2,8 +2,20 @@ import React from 'react'
|
||||
import ReactDOM from 'react-dom/client'
|
||||
import App from './App.tsx'
|
||||
import './index.css'
|
||||
import { registerSW } from 'virtual:pwa-register'
|
||||
|
||||
ReactDOM.createRoot(document.getElementById('root')!).render(
|
||||
const updateSW = registerSW({
|
||||
onNeedRefresh() {
|
||||
if (confirm("New content available. Reload?")) {
|
||||
updateSW(true);
|
||||
}
|
||||
},
|
||||
onOfflineReady() {
|
||||
console.log("offline ready");
|
||||
},
|
||||
});
|
||||
|
||||
ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
|
||||
<React.StrictMode>
|
||||
<App />
|
||||
</React.StrictMode>,
|
||||
|
23
frontend_reactjs/src/pages/ApiTest.tsx
Normal file
23
frontend_reactjs/src/pages/ApiTest.tsx
Normal file
@ -0,0 +1,23 @@
|
||||
import { useEffect, useState } from "react"
|
||||
import UserService from "../services/UserService"
|
||||
import AuthService from "../services/AuthService"
|
||||
import { Button } from "@mui/material"
|
||||
|
||||
export default function ApiTest() {
|
||||
const [temp, setTemp] = useState<any>(null)
|
||||
|
||||
const hello = async () => {
|
||||
await AuthService.hello().then(response => {
|
||||
setTemp(response)
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div>{JSON.stringify(temp)}</div>
|
||||
<Button onClick={() => hello()}>
|
||||
Hello
|
||||
</Button>
|
||||
</>
|
||||
)
|
||||
}
|
@ -1,3 +1,7 @@
|
||||
export default function Main (){
|
||||
return ( <><h1>Main page</h1></>)
|
||||
export default function Main() {
|
||||
return (
|
||||
<>
|
||||
Главная
|
||||
</>
|
||||
)
|
||||
}
|
@ -1,3 +1,7 @@
|
||||
export default function NotFound (){
|
||||
return ( <><h1>Page not found</h1></>)
|
||||
export default function NotFound() {
|
||||
return (
|
||||
<>
|
||||
<h1>Page not found</h1>
|
||||
</>
|
||||
)
|
||||
}
|
@ -1,26 +1,26 @@
|
||||
import { useState} from 'react'
|
||||
import { useState } from 'react'
|
||||
import RoleCard from '../components/RoleCard'
|
||||
import Modal from '../components/Modal'
|
||||
import useDataFetching from '../components/FetchingData'
|
||||
|
||||
interface IRoleCard{
|
||||
id: number
|
||||
name: string
|
||||
}
|
||||
interface IRoleCard {
|
||||
id: number
|
||||
name: string
|
||||
}
|
||||
interface Props {
|
||||
showModal: boolean;
|
||||
}
|
||||
function Users() {
|
||||
const [showModal, setShowModal] = useState<Props>({showModal: false});
|
||||
const cards = useDataFetching<IRoleCard[]>("http://localhost:8000/auth/role/",[])
|
||||
|
||||
showModal: boolean;
|
||||
}
|
||||
function Roles() {
|
||||
const [showModal, setShowModal] = useState<Props>({ showModal: false });
|
||||
const cards = useDataFetching<IRoleCard[]>(`${import.meta.env.VITE_API_URL}/auth/role/`, [])
|
||||
|
||||
return (
|
||||
<div>
|
||||
{cards.map((card, index) => <RoleCard key={index} {...card}/>)}
|
||||
<button className='absolute w-0 h-0' onClick={() => setShowModal({showModal:true})}>+</button>
|
||||
<Modal {...showModal}/>
|
||||
{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 Users
|
||||
export default Roles
|
@ -1,16 +1,16 @@
|
||||
import Card from '../components/Card'
|
||||
import useDataFetching from '../components/FetchingData'
|
||||
interface ICard{
|
||||
interface ICard {
|
||||
firstname: string
|
||||
lastname: string
|
||||
email: string
|
||||
}
|
||||
|
||||
function Users() {
|
||||
const cards= useDataFetching<ICard[]>("http://localhost:8000/auth/user/",[])
|
||||
const cards = useDataFetching<ICard[]>(`${import.meta.env.VITE_API_URL}/auth/user/`, [])
|
||||
return (
|
||||
<div>
|
||||
{cards.map((card, index) => <Card key={index} {...card}/>)}
|
||||
{cards.map((card, index) => <Card key={index} {...card} />)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
9
frontend_reactjs/src/pages/auth/SignIn.tsx
Normal file
9
frontend_reactjs/src/pages/auth/SignIn.tsx
Normal file
@ -0,0 +1,9 @@
|
||||
import React from 'react'
|
||||
|
||||
const SignIn = () => {
|
||||
return (
|
||||
<div>SignIn</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default SignIn
|
0
frontend_reactjs/src/pages/auth/SignUp.tsx
Normal file
0
frontend_reactjs/src/pages/auth/SignUp.tsx
Normal file
7
frontend_reactjs/src/services/AuthService.ts
Normal file
7
frontend_reactjs/src/services/AuthService.ts
Normal file
@ -0,0 +1,7 @@
|
||||
import axios from "axios";
|
||||
|
||||
export default class AuthService {
|
||||
static async hello() {
|
||||
return await axios.get(`${import.meta.env.VITE_API_AUTH_URL}/hello`)
|
||||
}
|
||||
}
|
29
frontend_reactjs/src/services/UserService.ts
Normal file
29
frontend_reactjs/src/services/UserService.ts
Normal file
@ -0,0 +1,29 @@
|
||||
// Data mockup
|
||||
let users =
|
||||
[
|
||||
{
|
||||
"email": "string",
|
||||
"login": "string",
|
||||
"phone": "string",
|
||||
"name": "string",
|
||||
"surname": "string",
|
||||
"is_active": true,
|
||||
"id": 0,
|
||||
"role_id": 2
|
||||
}
|
||||
]
|
||||
|
||||
export default class UserService {
|
||||
static async getUsers() {
|
||||
new Promise((resolve, reject) => {
|
||||
if (!users) {
|
||||
return setTimeout(
|
||||
() => reject(new Error('Users not found')),
|
||||
250
|
||||
)
|
||||
}
|
||||
|
||||
setTimeout(() => resolve(users), 250)
|
||||
})
|
||||
}
|
||||
}
|
0
frontend_reactjs/src/store/auth-store.ts
Normal file
0
frontend_reactjs/src/store/auth-store.ts
Normal file
Reference in New Issue
Block a user