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