basic functionnalities
This commit is contained in:
parent
f820f0142b
commit
0461ef6f93
24
src/components/app-router.jsx
Normal file
24
src/components/app-router.jsx
Normal file
@ -0,0 +1,24 @@
|
||||
import { Route, Routes } from 'react-router-dom';
|
||||
import NotFound from '../pages/errors/404';
|
||||
import Home from '../pages/home';
|
||||
import Planning from '../pages/planning';
|
||||
import Playlists from '../pages/playlists';
|
||||
import Playlist from '../pages/playlist';
|
||||
import Files from '../pages/files';
|
||||
import Authentication from '../pages/auth';
|
||||
|
||||
const AppRouter = () => {
|
||||
return (
|
||||
<Routes>
|
||||
<Route path="/" element={<Home />} />
|
||||
<Route path="/planning" element={<Planning />} />
|
||||
<Route path="/playlists" element={<Playlists />} />
|
||||
<Route path="/files" element={<Files />} />
|
||||
<Route path="/playlist/:id" element={<Playlist />} />
|
||||
<Route path="/auth" element={<Authentication />} />
|
||||
<Route path="*" element={<NotFound />} />
|
||||
</Routes>
|
||||
);
|
||||
};
|
||||
|
||||
export default AppRouter;
|
16
src/components/layout.jsx
Normal file
16
src/components/layout.jsx
Normal file
@ -0,0 +1,16 @@
|
||||
import { AppShell } from '@mantine/core';
|
||||
import HeaderSearch from './header';
|
||||
import AppRouter from './app-router';
|
||||
import { BrowserRouter } from 'react-router-dom';
|
||||
|
||||
const Layout = () => {
|
||||
return (
|
||||
<BrowserRouter>
|
||||
<AppShell mx="md" header={<HeaderSearch />}>
|
||||
<AppRouter />
|
||||
</AppShell>
|
||||
</BrowserRouter>
|
||||
);
|
||||
};
|
||||
|
||||
export default Layout;
|
32
src/components/toggle-colorscheme.jsx
Normal file
32
src/components/toggle-colorscheme.jsx
Normal file
@ -0,0 +1,32 @@
|
||||
import { Switch, Group, useMantineTheme, createStyles } from '@mantine/core';
|
||||
import { IconSun, IconMoonStars } from '@tabler/icons-react';
|
||||
import { useColorSchemeToggle } from '../tools/color-scheme-toggle'
|
||||
|
||||
const useStyles = createStyles((theme) => ({
|
||||
group: {
|
||||
[theme.fn.smallerThan('xs')]: {
|
||||
display: 'none',
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
||||
const SwitchToggle = () => {
|
||||
const { classes } = useStyles();
|
||||
const [ colorScheme, toggleColorScheme ] = useColorSchemeToggle();
|
||||
|
||||
const theme = useMantineTheme()
|
||||
|
||||
return (
|
||||
<Group position="center" my={30} className={classes.group}>
|
||||
<Switch
|
||||
checked={colorScheme === 'dark'}
|
||||
onChange={toggleColorScheme}
|
||||
size="lg"
|
||||
onLabel={<IconSun color={theme.white} size="1.25rem" stroke={1.5} />}
|
||||
offLabel={<IconMoonStars color={theme.colors.gray[6]} size="1.25rem" stroke={1.5} />}
|
||||
/>
|
||||
</Group>
|
||||
);
|
||||
};
|
||||
|
||||
export default SwitchToggle;
|
67
src/pages/auth.jsx
Normal file
67
src/pages/auth.jsx
Normal file
@ -0,0 +1,67 @@
|
||||
import { TextInput, PasswordInput, Checkbox, Anchor, Paper, Title, Container, Group, Button } from '@mantine/core';
|
||||
import { isNotEmpty, useForm } from '@mantine/form';
|
||||
import { useAuth } from '../tools/auth-provider';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { useEffect } from 'react';
|
||||
|
||||
const Authentication = () => {
|
||||
const { setRole } = useAuth();
|
||||
const navigate = useNavigate();
|
||||
const form = useForm({
|
||||
initialValues: {
|
||||
name: '',
|
||||
password: '',
|
||||
remember: false,
|
||||
},
|
||||
validate: {
|
||||
name: isNotEmpty('Name is required'),
|
||||
password: isNotEmpty('Password is required'),
|
||||
},
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
localStorage.setItem('role', form.values.name);
|
||||
}, [form.values.name]);
|
||||
|
||||
const handleLogin = (e) => {
|
||||
e.preventDefault();
|
||||
if (form.validate().hasErrors) return;
|
||||
setRole(form.values.name);
|
||||
navigate('/');
|
||||
};
|
||||
|
||||
return (
|
||||
<Container size={420} my={40}>
|
||||
<Title
|
||||
align="center"
|
||||
sx={(theme) => ({ fontFamily: `Greycliff CF, ${theme.fontFamily}`, fontWeight: 900 })}
|
||||
>
|
||||
Connect to signage
|
||||
</Title>
|
||||
|
||||
<Paper withBorder shadow="md" p={30} mt={30} radius="md">
|
||||
<form onSubmit={handleLogin}>
|
||||
<TextInput label="Name" placeholder="Your name" {...form.getInputProps('name')} withAsterisk />
|
||||
<PasswordInput
|
||||
label="Password"
|
||||
placeholder="Your password"
|
||||
mt="md"
|
||||
{...form.getInputProps('password')}
|
||||
withAsterisk
|
||||
/>
|
||||
<Group position="apart" mt="lg">
|
||||
<Checkbox label="Remember me" />
|
||||
<Anchor size="sm" href="https://www.youtube.com/watch?v=dQw4w9WgXcQ&pp=ygUJcmljayByb2xs">
|
||||
Forgot password(s)?
|
||||
</Anchor>
|
||||
</Group>
|
||||
<Button fullWidth mt="xl" type="submit">
|
||||
Sign in
|
||||
</Button>
|
||||
</form>
|
||||
</Paper>
|
||||
</Container>
|
||||
);
|
||||
};
|
||||
|
||||
export default Authentication;
|
63
src/pages/errors/404.jsx
Normal file
63
src/pages/errors/404.jsx
Normal file
@ -0,0 +1,63 @@
|
||||
import { createStyles, Title, Text, Button, Container, Group, rem } from '@mantine/core';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
|
||||
const useStyles = createStyles((theme) => ({
|
||||
root: {
|
||||
paddingTop: rem(80),
|
||||
paddingBottom: rem(80),
|
||||
},
|
||||
|
||||
label: {
|
||||
textAlign: 'center',
|
||||
fontWeight: 900,
|
||||
fontSize: rem(220),
|
||||
lineHeight: 1,
|
||||
marginBottom: `calc(${theme.spacing.xl} * 1.5)`,
|
||||
color: theme.colorScheme === 'dark' ? theme.colors.dark[4] : theme.colors.gray[2],
|
||||
|
||||
[theme.fn.smallerThan('sm')]: {
|
||||
fontSize: rem(120),
|
||||
},
|
||||
},
|
||||
|
||||
title: {
|
||||
fontFamily: `Greycliff CF, ${theme.fontFamily}`,
|
||||
textAlign: 'center',
|
||||
fontWeight: 900,
|
||||
fontSize: rem(38),
|
||||
|
||||
[theme.fn.smallerThan('sm')]: {
|
||||
fontSize: rem(32),
|
||||
},
|
||||
},
|
||||
|
||||
description: {
|
||||
maxWidth: rem(500),
|
||||
margin: 'auto',
|
||||
marginTop: theme.spacing.xl,
|
||||
marginBottom: `calc(${theme.spacing.xl} * 1.5)`,
|
||||
},
|
||||
}));
|
||||
|
||||
const NotFound = () => {
|
||||
const { classes } = useStyles();
|
||||
const navigate = useNavigate();
|
||||
|
||||
return (
|
||||
<Container className={classes.root}>
|
||||
<div className={classes.label}>404</div>
|
||||
<Title className={classes.title}>You have found a secret place.</Title>
|
||||
<Text color="dimmed" size="lg" align="center" className={classes.description}>
|
||||
Unfortunately, this is only a 404 page. You may have mistyped the address, or the page has been moved to
|
||||
another URL.
|
||||
</Text>
|
||||
<Group position="center">
|
||||
<Button variant="subtle" size="md" onClick={() => navigate('/')}>
|
||||
Take me back to home page
|
||||
</Button>
|
||||
</Group>
|
||||
</Container>
|
||||
);
|
||||
};
|
||||
|
||||
export default NotFound;
|
19
src/tools/auth-provider.js
Normal file
19
src/tools/auth-provider.js
Normal file
@ -0,0 +1,19 @@
|
||||
import { createContext, useState, useContext } from 'react';
|
||||
|
||||
const AuthContext = createContext();
|
||||
|
||||
const AuthProvider = ({ children }) => {
|
||||
const [role, setRole] = useState(localStorage.getItem('role') ?? 'user');
|
||||
|
||||
return <AuthContext.Provider value={{ role, setRole }}>{children}</AuthContext.Provider>;
|
||||
};
|
||||
|
||||
const logout = () => {
|
||||
localStorage.removeItem('role');
|
||||
window.location.href = '/auth';
|
||||
};
|
||||
|
||||
const useAuth = () => useContext(AuthContext);
|
||||
|
||||
export default AuthContext;
|
||||
export { AuthProvider, logout, useAuth };
|
15
src/tools/color-scheme-toggle.jsx
Normal file
15
src/tools/color-scheme-toggle.jsx
Normal file
@ -0,0 +1,15 @@
|
||||
import { useLocalStorage, useColorScheme } from '@mantine/hooks';
|
||||
|
||||
const useColorSchemeToggle = function(){
|
||||
const defaultColorScheme = useColorScheme()
|
||||
const [colorScheme, setColorScheme] = useLocalStorage({
|
||||
key: 'mantine-color-scheme',
|
||||
defaultValue: defaultColorScheme,
|
||||
getInitialValueInEffect: true,
|
||||
});
|
||||
const toggleColorScheme = () =>
|
||||
setColorScheme((colorScheme === 'dark' ? 'light' : 'dark'));
|
||||
return [ colorScheme, toggleColorScheme ];
|
||||
};
|
||||
|
||||
export { useColorSchemeToggle };
|
8
src/tools/grant-access.jsx
Normal file
8
src/tools/grant-access.jsx
Normal file
@ -0,0 +1,8 @@
|
||||
import { useAuth } from './auth-provider';
|
||||
|
||||
const GrantAccess = ({ roles, children }) => {
|
||||
const { role } = useAuth();
|
||||
return roles.includes(role) ? children : null;
|
||||
};
|
||||
|
||||
export default GrantAccess;
|
16
src/tools/timeUtil.js
Normal file
16
src/tools/timeUtil.js
Normal file
@ -0,0 +1,16 @@
|
||||
export const parseTime = (preparationTime) => {
|
||||
let res = '';
|
||||
let hours = Math.floor(preparationTime / 3600);
|
||||
res += hours > 0 ? `${hours}h` : '';
|
||||
|
||||
let min = Math.floor((preparationTime % 3600) / 60);
|
||||
if (min > 0 && res != '') res += ' ';
|
||||
res += min > 0 ? `${min}m` : '';
|
||||
|
||||
let sec = Math.floor((preparationTime % 3600) % 60);
|
||||
if (sec > 0 && res != '') res += ' ';
|
||||
res += sec > 0 ? `${sec}s` : '';
|
||||
|
||||
if (res == '') res = '0s';
|
||||
return res;
|
||||
};
|
Loading…
Reference in New Issue
Block a user