all of the linting

main
Cameron Clough 2022-01-10 01:40:47 +00:00
parent df44a9f49e
commit 0e6b7c7d3a
23 changed files with 519 additions and 364 deletions

View File

@ -4,9 +4,9 @@ import React, { useState } from 'react';
import Login from './components/views/login'; import Login from './components/views/login';
import UserAdmin from './components/views/useradmin'; import UserAdmin from './components/views/useradmin';
import GlobalSnack from './components/widgets/globalSnack'; import GlobalSnack from './components/widgets/globalSnack';
import DeviceStore from './context/devices'; import DevicesProvider from './context/devices';
import ToastStore from './context/toast'; import ToastProvider from './context/toast';
import { UserProvider } from './context/users'; import UserProvider from './context/users';
import * as authenticationController from './controllers/authentication'; import * as authenticationController from './controllers/authentication';
// Connection opened // Connection opened
@ -34,16 +34,15 @@ function App() {
<CssBaseline /> <CssBaseline />
<UserProvider> <UserProvider>
<DeviceStore> <DevicesProvider>
<ToastStore> <ToastProvider>
<GlobalSnack /> <GlobalSnack />
{session ? <UserAdmin /> : <Login />} {session ? <UserAdmin /> : <Login />}
</ToastStore> </ToastProvider>
</DeviceStore> </DevicesProvider>
</UserProvider> </UserProvider>
</ThemeProvider> </ThemeProvider>

View File

@ -1,13 +1,14 @@
import React from 'react';
import PropTypes from 'prop-types';
import Grid from '@mui/material/Grid'; import Grid from '@mui/material/Grid';
import GoogleMapReact from 'google-map-react'; import GoogleMapReact from 'google-map-react';
import React from 'react';
import { Scrollbars } from 'react-custom-scrollbars'; import { Scrollbars } from 'react-custom-scrollbars';
import DrivesTable from './tabPane'; import DrivesTable from './tabPane';
function DeviceLastSeenMap() { function DeviceLastSeenMap() {
return ( return (
<div style={{ height: '500px', width: 'calc(100%)' }}> <div style={{ height: '500px', width: 'calc(100%)' }}>
<GoogleMapReact <GoogleMapReact
height="100px" height="100px"
bootstrapURLKeys={{ key: process.env.REACT_APP_GMAPS_API_KEY }} bootstrapURLKeys={{ key: process.env.REACT_APP_GMAPS_API_KEY }}
@ -103,14 +104,16 @@ function DeviceLastSeenMap() {
); );
} }
export default function SignIn(props) { function DeviceData(props) {
return ( const { device } = props;
<div style={{
height: '100%',
width: '100%',
}}
>
return (
<div
style={{
height: '100%',
width: '100%',
}}
>
<Scrollbars autoHeightMin="100%" autoHeightMax="100%"> <Scrollbars autoHeightMin="100%" autoHeightMax="100%">
<Grid container style={{ padding: 30 }}> <Grid container style={{ padding: 30 }}>
<Grid item xs={12}> <Grid item xs={12}>
@ -118,12 +121,18 @@ export default function SignIn(props) {
</Grid> </Grid>
<Grid item xs={12}> <Grid item xs={12}>
<DrivesTable dongleId={props.device.dongle_id} /> <DrivesTable dongleId={device.dongle_id} />
</Grid> </Grid>
</Grid> </Grid>
</Scrollbars> </Scrollbars>
</div> </div>
); );
} }
DeviceData.propTypes = {
device: PropTypes.shape({
dongle_id: PropTypes.string.isRequired,
}).isRequired,
};
export default DeviceData;

View File

@ -1,9 +1,10 @@
import React, { useEffect } from 'react';
import PropTypes from 'prop-types';
import ButtonBase from '@mui/material/ButtonBase'; import ButtonBase from '@mui/material/ButtonBase';
import Chip from '@mui/material/Chip'; import Chip from '@mui/material/Chip';
import Divider from '@mui/material/Divider'; import Divider from '@mui/material/Divider';
import Grid from '@mui/material/Grid'; import Grid from '@mui/material/Grid';
import Typography from '@mui/material/Typography'; import Typography from '@mui/material/Typography';
import React, { useEffect } from 'react';
const stylezz = { const stylezz = {
margin: '0px 2px 0px 0px', margin: '0px 2px 0px 0px',
@ -22,10 +23,11 @@ function timeSince(date) {
return 'just now'; return 'just now';
} }
export default function SignIn(props) { function DeviceOverview(props) {
const [state, setState] = React.useState({ count: 0, last_seen: 0 });
const { device } = props; const { device } = props;
const [state, setState] = React.useState({ count: 0, last_seen: 0 });
// Reloads component to update X time ago // Reloads component to update X time ago
// TODO prevent X time ago from being refreshed when the device has been // TODO prevent X time ago from being refreshed when the device has been
// updated to show offline. // updated to show offline.
@ -72,7 +74,6 @@ export default function SignIn(props) {
</Typography> </Typography>
<div> <div>
{device.online {device.online
? <Chip style={{ background: '#004d40', ...stylezz }} label="Online" size="small" variant="outlined" /> ? <Chip style={{ background: '#004d40', ...stylezz }} label="Online" size="small" variant="outlined" />
: <Chip style={{ background: '#b71c1c', ...stylezz }} label={`Offline ${deviceLastSeen}`} size="small" variant="outlined" />} : <Chip style={{ background: '#b71c1c', ...stylezz }} label={`Offline ${deviceLastSeen}`} size="small" variant="outlined" />}
@ -84,6 +85,15 @@ export default function SignIn(props) {
</ButtonBase> </ButtonBase>
<Divider /> <Divider />
</div> </div>
); );
} }
DeviceOverview.propTypes = {
device: PropTypes.shape({
dongle_id: PropTypes.string.isRequired,
last_seen: PropTypes.string.isRequired,
online: PropTypes.bool.isRequired,
}).isRequired,
};
export default DeviceOverview;

View File

@ -1,6 +1,5 @@
import DeleteIcon from '@mui/icons-material/Delete'; import React, { useContext, useEffect } from 'react';
import FavoriteBorderIcon from '@mui/icons-material/FavoriteBorder'; import PropTypes from 'prop-types';
import OpenInNewIcon from '@mui/icons-material/OpenInNew';
import { Skeleton } from '@mui/material'; import { Skeleton } from '@mui/material';
import Box from '@mui/material/Box'; import Box from '@mui/material/Box';
import IconButton from '@mui/material/IconButton'; import IconButton from '@mui/material/IconButton';
@ -12,9 +11,12 @@ import TableContainer from '@mui/material/TableContainer';
import TableHead from '@mui/material/TableHead'; import TableHead from '@mui/material/TableHead';
import TableRow from '@mui/material/TableRow'; import TableRow from '@mui/material/TableRow';
import Tooltip from '@mui/material/Tooltip'; import Tooltip from '@mui/material/Tooltip';
import React, { useContext, useEffect } from 'react'; import DeleteIcon from '@mui/icons-material/Delete';
import { context as DeviceContext } from '../../../context/devices'; import FavoriteBorderIcon from '@mui/icons-material/FavoriteBorder';
import { context as SnackbarContext } from '../../../context/toast'; import OpenInNewIcon from '@mui/icons-material/OpenInNew';
import { DevicesContext } from '../../../context/devices';
import { ToastContext } from '../../../context/toast';
import * as deviceController from '../../../controllers/devices'; import * as deviceController from '../../../controllers/devices';
import * as helpers from '../../../controllers/helpers'; import * as helpers from '../../../controllers/helpers';
@ -29,20 +31,26 @@ function loading() {
); );
} }
export default function EnhancedTable(props) { function BootLogsTable(props) {
const [state, dispatch] = useContext(DeviceContext); const { dongleId } = props;
const [, notifDispatch] = useContext(SnackbarContext); const [state, dispatch] = useContext(DevicesContext);
const [, notifDispatch] = useContext(ToastContext);
useEffect(() => { useEffect(() => {
deviceController.getBootlogs(props.dongleId).then((res) => { deviceController.getBootlogs(dongleId).then((res) => {
// TODO: why set timeout 1?
setTimeout(() => { setTimeout(() => {
dispatch({ type: 'update_dongle_bootlogs', dongle_id: props.dongleId, bootlogs: res.data }); dispatch({
type: 'update_dongle_bootlogs',
dongle_id: dongleId,
bootlogs: res.data,
});
}, 1); }, 1);
}).catch(() => { }).catch(() => {
notifDispatch({ type: 'NEW_TOAST', msg: 'Failed to load bootlogs' }); notifDispatch({ type: 'NEW_TOAST', msg: 'Failed to load bootlogs' });
}); });
}, [dispatch, notifDispatch, props.dongleId]); }, [dispatch, notifDispatch, dongleId]);
return ( return (
<Box sx={{ width: '100%' }}> <Box sx={{ width: '100%' }}>
@ -65,14 +73,13 @@ export default function EnhancedTable(props) {
<TableBody> <TableBody>
{/* if you don't need to support IE11, you can replace the `stableSort` call with: {/* if you don't need to support IE11, you can replace the `stableSort` call with:
rows.slice().sort(getComparator(order, orderBy)) */} rows.slice().sort(getComparator(order, orderBy)) */}
{state.dongles[props.dongleId].boot ? state.dongles[props.dongleId].boot.map((row) => ( {state.dongles[dongleId].boot ? state.dongles[dongleId].boot.map((row) => (
<TableRow hover> <TableRow hover>
<TableCell>{helpers.formatDate(row.date)}</TableCell> <TableCell>{helpers.formatDate(row.date)}</TableCell>
<TableCell>{row.name}</TableCell> <TableCell>{row.name}</TableCell>
<TableCell>{`${Math.round(row.size / 1024)} MiB`}</TableCell> <TableCell>{`${Math.round(row.size / 1024)} MiB`}</TableCell>
<TableCell> <TableCell>
<Tooltip title="Open in new window"> <Tooltip title="Open in new window">
<IconButton size="small" onClick={() => window.open(row.permalink, '_blank')}> <IconButton size="small" onClick={() => window.open(row.permalink, '_blank')}>
<OpenInNewIcon fontSize="inherit" /> <OpenInNewIcon fontSize="inherit" />
</IconButton> </IconButton>
@ -100,3 +107,9 @@ export default function EnhancedTable(props) {
</Box> </Box>
); );
} }
BootLogsTable.propTypes = {
dongleId: PropTypes.string.isRequired,
};
export default BootLogsTable;

View File

@ -54,31 +54,26 @@ function RichContent(props) {
</AccordionDetails> </AccordionDetails>
</Accordion> </Accordion>
) )
} }
} }
*/ */
export default function Console() { function ConsoleTable() {
return ( return (
<Box sx={{ width: '100%' }}> <Box sx={{ width: '100%' }}>
<Paper sx={{ width: '100%', mb: 2 }}> <Paper sx={{ width: '100%', mb: 2 }}>
{/* {/*
Object.keys(state).map(key => { Object.keys(state).map(key => {
console.log(key, state[key]) console.log(key, state[key])
return (<RichContent content={state[key]} key1={key} />) return (<RichContent content={state[key]} key1={key} />)
} }
) )
*/} */}
</Paper> </Paper>
</Box> </Box>
); );
} }
export default ConsoleTable;

View File

@ -1,8 +1,5 @@
// eslint-disable-next-line react-hooks/exhaustive-deps import React, { useContext, useEffect } from 'react';
import PropTypes from 'prop-types';
import DeleteIcon from '@mui/icons-material/Delete';
import FavoriteBorderIcon from '@mui/icons-material/FavoriteBorder';
import OpenInNewIcon from '@mui/icons-material/OpenInNew';
import { Skeleton } from '@mui/material'; import { Skeleton } from '@mui/material';
import Box from '@mui/material/Box'; import Box from '@mui/material/Box';
import IconButton from '@mui/material/IconButton'; import IconButton from '@mui/material/IconButton';
@ -14,17 +11,17 @@ import TableContainer from '@mui/material/TableContainer';
import TableHead from '@mui/material/TableHead'; import TableHead from '@mui/material/TableHead';
import TableRow from '@mui/material/TableRow'; import TableRow from '@mui/material/TableRow';
import Tooltip from '@mui/material/Tooltip'; import Tooltip from '@mui/material/Tooltip';
import React, { useContext, useEffect } from 'react'; import DeleteIcon from '@mui/icons-material/Delete';
import { context as DeviceContext } from '../../../context/devices'; import FavoriteBorderIcon from '@mui/icons-material/FavoriteBorder';
import OpenInNewIcon from '@mui/icons-material/OpenInNew';
import { ACTIONS, DevicesContext } from '../../../context/devices';
import * as deviceController from '../../../controllers/devices'; import * as deviceController from '../../../controllers/devices';
import * as helpers from '../../../controllers/helpers'; import * as helpers from '../../../controllers/helpers';
function buildContent(row) { function buildContent(row) {
return ( return (
<TableRow <TableRow hover>
hover
>
<TableCell>{helpers.formatDate(row.date)}</TableCell> <TableCell>{helpers.formatDate(row.date)}</TableCell>
<TableCell>{row.name}</TableCell> <TableCell>{row.name}</TableCell>
<TableCell>{`${Math.round(row.size / 1024)} MiB`}</TableCell> <TableCell>{`${Math.round(row.size / 1024)} MiB`}</TableCell>
@ -47,7 +44,6 @@ function buildContent(row) {
<DeleteIcon fontSize="inherit" /> <DeleteIcon fontSize="inherit" />
</IconButton> </IconButton>
</Tooltip> </Tooltip>
</TableCell> </TableCell>
</TableRow> </TableRow>
); );
@ -64,17 +60,23 @@ function loading() {
); );
} }
export default function EnhancedTable(props) { function CrashLogsTable(props) {
// eslint-disable-next-line no-unused-vars const { dongleId } = props;
const [state, dispatch] = useContext(DeviceContext);
useEffect(() => {
deviceController.getCrashlogs(props.dongleId).then((res) => {
dispatch({ type: 'update_dongle_bootlogs', dongle_id: props.dongleId, bootlogs: res.data });
});
}, [dispatch, props.dongleId]);
console.log('drives', state.dongles[props.dongleId]); // eslint-disable-next-line no-unused-vars
console.log('drives', typeof state.dongles[props.dongleId]); const [state, dispatch] = useContext(DevicesContext);
useEffect(() => {
deviceController.getCrashlogs(dongleId).then((res) => {
dispatch({
type: ACTIONS.UPDATE_DONGLE_BOOTLOGS,
dongle_id: dongleId,
bootlogs: res.data,
});
});
}, [dispatch, dongleId]);
console.log('drives', state.dongles[dongleId]);
console.log('drives', typeof state.dongles[dongleId]);
return ( return (
<Box sx={{ width: '100%' }}> <Box sx={{ width: '100%' }}>
@ -95,10 +97,11 @@ export default function EnhancedTable(props) {
</TableHead> </TableHead>
<TableBody> <TableBody>
{state.dongles[props.dongleId].crash {state.dongles[dongleId].crash
? state.dongles[props.dongleId].crash.length > 0 ? state.dongles[props.dongleId].crash.map(buildContent) : <p> No drives </p> ? (state.dongles[dongleId].crash.length > 0
? state.dongles[dongleId].crash.map(buildContent)
: <p> No drives </p>)
: [1, 1, 1, 1, 1].map(loading)} : [1, 1, 1, 1, 1].map(loading)}
</TableBody> </TableBody>
</Table> </Table>
</TableContainer> </TableContainer>
@ -107,3 +110,9 @@ export default function EnhancedTable(props) {
</Box> </Box>
); );
} }
CrashLogsTable.propTypes = {
dongleId: PropTypes.string.isRequired,
};
export default CrashLogsTable;

View File

@ -1,37 +1,43 @@
import ContentCopyIcon from '@mui/icons-material/ContentCopy'; import React, { useContext } from 'react';
import PropTypes from 'prop-types';
import Grid from '@mui/material/Grid'; import Grid from '@mui/material/Grid';
import IconButton from '@mui/material/IconButton'; import IconButton from '@mui/material/IconButton';
import Skeleton from '@mui/material/Skeleton'; import Skeleton from '@mui/material/Skeleton';
import Tooltip from '@mui/material/Tooltip'; import Tooltip from '@mui/material/Tooltip';
import Typography from '@mui/material/Typography'; import Typography from '@mui/material/Typography';
import React, { useContext } from 'react'; import ContentCopyIcon from '@mui/icons-material/ContentCopy';
import { context as DeviceContext } from '../../../context/devices';
import { context as SnackbarContext } from '../../../context/toast'; import { DevicesContext } from '../../../context/devices';
import { ACTIONS as ToastActions, ToastContext } from '../../../context/toast';
import * as helpers from '../../../controllers/helpers'; import * as helpers from '../../../controllers/helpers';
export default function SignIn(props) { function DeviceInfo(props) {
const [state] = useContext(DeviceContext); const { dongleId } = props;
const [, notifDispatch] = useContext(SnackbarContext);
const [devicesState] = useContext(DevicesContext);
const [, toastDispatch] = useContext(ToastContext);
if (!devicesState.dongles[dongleId]) {
return (<p>no</p>);
}
function pubKeyClipboard(newClip) { function pubKeyClipboard(newClip) {
navigator.clipboard.writeText(newClip).then(() => { navigator.clipboard.writeText(newClip).then(() => {
notifDispatch({ toastDispatch({
type: 'NEW_TOAST', type: ToastActions.NEW_TOAST,
open: true, open: true,
msg: 'Successfully copied to clipboard!', msg: 'Successfully copied to clipboard!',
}); });
}, () => { }, () => {
notifDispatch({ toastDispatch({
type: 'NEW_TOAST', type: ToastActions.NEW_TOAST,
open: true, open: true,
msg: 'Failed to write to clipboard!', msg: 'Failed to write to clipboard!',
}); });
}); });
} }
if (!state.dongles[props.dongleId]) { return (<p>no</p>); } const dongle = devicesState.dongles[dongleId];
const dongle = state.dongles[props.dongleId];
if (!dongle) { if (!dongle) {
return ( return (
<Grid container> <Grid container>
@ -40,15 +46,13 @@ export default function SignIn(props) {
<Skeleton animation="wave" /> <Skeleton animation="wave" />
<Skeleton animation="wave" /> <Skeleton animation="wave" />
</Grid> </Grid>
</Grid> </Grid>
); );
} }
return ( return (
<div className="wrapper" style={{ marginTop: '10px' }}> <div className="wrapper" style={{ marginTop: '10px' }}>
<Typography variant="body1">{state.dongles[props.dongleId].dongle_id}</Typography> <Typography variant="body1">{devicesState.dongles[dongleId].dongle_id}</Typography>
<Grid container> <Grid container>
<Grid item xs={3}> <Grid item xs={3}>
@ -97,3 +101,9 @@ export default function SignIn(props) {
</div> </div>
); );
} }
DeviceInfo.propTypes = {
dongleId: PropTypes.string.isRequired,
};
export default DeviceInfo;

View File

@ -1,6 +1,5 @@
import DeleteIcon from '@mui/icons-material/Delete'; import React, { useContext, useEffect, useState } from 'react';
import FavoriteBorderIcon from '@mui/icons-material/FavoriteBorder'; import PropTypes from 'prop-types';
import OpenInNewIcon from '@mui/icons-material/OpenInNew';
import { Skeleton } from '@mui/material'; import { Skeleton } from '@mui/material';
import Box from '@mui/material/Box'; import Box from '@mui/material/Box';
import IconButton from '@mui/material/IconButton'; import IconButton from '@mui/material/IconButton';
@ -12,27 +11,32 @@ import TableContainer from '@mui/material/TableContainer';
import TableHead from '@mui/material/TableHead'; import TableHead from '@mui/material/TableHead';
import TableRow from '@mui/material/TableRow'; import TableRow from '@mui/material/TableRow';
import Tooltip from '@mui/material/Tooltip'; import Tooltip from '@mui/material/Tooltip';
import React, { useContext, useEffect, useState } from 'react'; import DeleteIcon from '@mui/icons-material/Delete';
import { context as DeviceContext } from '../../../context/devices'; import FavoriteBorderIcon from '@mui/icons-material/FavoriteBorder';
import { context as SnackbarContext } from '../../../context/toast'; import OpenInNewIcon from '@mui/icons-material/OpenInNew';
import { DevicesContext } from '../../../context/devices';
import { ToastContext } from '../../../context/toast';
import * as deviceController from '../../../controllers/devices'; import * as deviceController from '../../../controllers/devices';
import * as helpers from '../../../controllers/helpers'; import * as helpers from '../../../controllers/helpers';
import ViewDrive from './view_drive'; import ViewDrive from './view_drive';
export default function EnhancedTable(props) { function DrivesLogTable(props) {
const [deviceState, dispatch] = useContext(DeviceContext); const { dongleId } = props;
const [, notifDispatch] = useContext(SnackbarContext);
const [devicesState, dispatch] = useContext(DevicesContext);
const [, notifDispatch] = useContext(ToastContext);
const [state, setState] = useState({ selectedSegment: null }); const [state, setState] = useState({ selectedSegment: null });
useEffect(() => { useEffect(() => {
deviceController.getDrives(props.dongleId).then((res) => { deviceController.getDrives(dongleId).then((res) => {
setTimeout(() => { setTimeout(() => {
dispatch({ type: 'update_dongle_drive', dongle_id: props.dongleId, drives: res.data }); dispatch({ type: 'update_dongle_drive', dongle_id: dongleId, drives: res.data });
}, 1); }, 1);
}).catch(() => { }).catch(() => {
notifDispatch({ type: 'NEW_TOAST', msg: 'Failed to load drives' }); notifDispatch({ type: 'NEW_TOAST', msg: 'Failed to load drives' });
}); });
}, [dispatch, notifDispatch, props.dongleId]); }, [dispatch, notifDispatch, dongleId]);
return ( return (
<Box sx={{ width: '100%' }}> <Box sx={{ width: '100%' }}>
@ -61,57 +65,58 @@ export default function EnhancedTable(props) {
<TableBody> <TableBody>
{/* if you don't need to support IE11, you can replace the `stableSort` call with: {/* if you don't need to support IE11, you can replace the `stableSort` call with:
rows.slice().sort(getComparator(order, orderBy)) */} rows.slice().sort(getComparator(order, orderBy)) */}
{deviceState.dongles[props.dongleId].drives ? deviceState.dongles[props.dongleId].drives.map((row, index) => { {devicesState.dongles[dongleId].drives
let metadata; ? devicesState.dongles[dongleId].drives.map((row, index) => {
let metadata;
try { try {
metadata = JSON.parse(row.metadata); metadata = JSON.parse(row.metadata);
} catch (err) { metadata = {}; } } catch (err) { metadata = {}; }
return ( return (
<TableRow <TableRow
hover hover
onClick={() => { state.selectedSegment === index ? setState({ ...state, selectedSegment: null }) : setState({ ...state, selectedSegment: index }); }} onClick={() => (state.selectedSegment === index
> ? setState({ ...state, selectedSegment: null })
<TableCell : setState({ ...state, selectedSegment: index }))}
scope="row"
> >
{row.identifier} <TableCell scope="row">
</TableCell> {row.identifier}
</TableCell>
<TableCell>{metadata.hasOwnProperty('CarParams1') ? metadata.CarParams.CarName : 'Glorious Skoda'}</TableCell> <TableCell>{metadata.CarParams ? metadata.CarParams.CarName : 'Glorious Skoda'}</TableCell>
<TableCell>{metadata.hasOwnProperty('InitData1') ? metadata.InitData.Version : 'Lemon boy'}</TableCell> <TableCell>{metadata.InitData ? metadata.InitData.Version : 'Lemon boy'}</TableCell>
<TableCell>{`${Math.round(row.filesize / 1024)} MiB`}</TableCell> <TableCell>{`${Math.round(row.filesize / 1024)} MiB`}</TableCell>
<TableCell>{helpers.formatDuration(row.duration)}</TableCell> <TableCell>{helpers.formatDuration(row.duration)}</TableCell>
<TableCell>{Math.round(row.distance_meters / 1000)}</TableCell> <TableCell>{Math.round(row.distance_meters / 1000)}</TableCell>
<TableCell>{row.upload_complete.toString()}</TableCell> <TableCell>{row.upload_complete.toString()}</TableCell>
<TableCell>{row.is_processed.toString()}</TableCell> <TableCell>{row.is_processed.toString()}</TableCell>
<TableCell>{helpers.formatDate(row.drive_date)}</TableCell> <TableCell>{helpers.formatDate(row.drive_date)}</TableCell>
<TableCell> <TableCell>
<Tooltip title="Open in new window"> <Tooltip title="Open in new window">
<IconButton size="small"> <IconButton size="small">
<OpenInNewIcon fontSize="inherit" /> <OpenInNewIcon fontSize="inherit" />
</IconButton> </IconButton>
</Tooltip> </Tooltip>
<Tooltip title="Preserve"> <Tooltip title="Preserve">
<IconButton size="small"> <IconButton size="small">
<FavoriteBorderIcon fontSize="inherit" /> <FavoriteBorderIcon fontSize="inherit" />
</IconButton> </IconButton>
</Tooltip> </Tooltip>
<Tooltip title="Delete"> <Tooltip title="Delete">
<IconButton size="small"> <IconButton size="small">
<DeleteIcon fontSize="inherit" /> <DeleteIcon fontSize="inherit" />
</IconButton> </IconButton>
</Tooltip> </Tooltip>
</TableCell> </TableCell>
</TableRow> </TableRow>
); );
}) })
: [1, 1, 1, 1, 1].map((v) => ( : [1, 1, 1, 1, 1].map(() => (
<TableRow> <TableRow>
<TableCell padding="checkbox"> <TableCell padding="checkbox">
<Skeleton animation="wave" /> <Skeleton animation="wave" />
@ -138,7 +143,15 @@ export default function EnhancedTable(props) {
</TableContainer> </TableContainer>
</Paper> </Paper>
{state.selectedSegment ? <ViewDrive dongleId={props.dongleId} drive={state.selectedSegment} /> : null } {state.selectedSegment
? <ViewDrive dongleId={dongleId} drive={state.selectedSegment} />
: null }
</Box> </Box>
); );
} }
DrivesLogTable.propTypes = {
dongleId: PropTypes.string.isRequired,
};
export default DrivesLogTable;

View File

@ -1,16 +1,20 @@
import React from 'react';
import PropTypes from 'prop-types';
import Box from '@mui/material/Box'; import Box from '@mui/material/Box';
import Tab from '@mui/material/Tab'; import Tab from '@mui/material/Tab';
import Tabs from '@mui/material/Tabs'; import Tabs from '@mui/material/Tabs';
import React from 'react';
import BootLogsTable from './boot'; import BootLogsTable from './boot';
import Console from './console'; import ConsoleTable from './console';
import CrashLogsTable from './crash'; import CrashLogsTable from './crash';
import DeviceInfo from './device'; import DeviceInfo from './device';
import DrivesLogTable from './drives'; import DrivesLogTable from './drives';
function TabPanel(props) { function TabPanel(props) {
const { const {
children, value, index, ...other children,
value,
index,
} = props; } = props;
return ( return (
@ -19,7 +23,6 @@ function TabPanel(props) {
hidden={value !== index} hidden={value !== index}
id={`simple-tabpanel-${index}`} id={`simple-tabpanel-${index}`}
aria-labelledby={`simple-tab-${index}`} aria-labelledby={`simple-tab-${index}`}
{...other}
> >
{value === index && ( {value === index && (
<div style={{ padding: '5px' }}> <div style={{ padding: '5px' }}>
@ -30,7 +33,15 @@ function TabPanel(props) {
); );
} }
export default function SignIn(props) { TabPanel.propTypes = {
children: PropTypes.node.isRequired,
index: PropTypes.number.isRequired,
value: PropTypes.number.isRequired,
};
function TabPane(props) {
const { dongleId } = props;
const [value, setValue] = React.useState(0); const [value, setValue] = React.useState(0);
const handleChange = (event, newValue) => { const handleChange = (event, newValue) => {
@ -39,7 +50,6 @@ export default function SignIn(props) {
return ( return (
<div className="wrapper"> <div className="wrapper">
<Box sx={{ borderBottom: 1, borderColor: 'divider' }}> <Box sx={{ borderBottom: 1, borderColor: 'divider' }}>
<Tabs <Tabs
value={value} value={value}
@ -56,24 +66,26 @@ export default function SignIn(props) {
</Tabs> </Tabs>
</Box> </Box>
<TabPanel value={value} index={0}> <TabPanel value={value} index={0}>
<DeviceInfo dongleId={props.dongleId} /> <DeviceInfo dongleId={dongleId} />
</TabPanel> </TabPanel>
<TabPanel value={value} index={1}> <TabPanel value={value} index={1}>
<DrivesLogTable dongleId={props.dongleId} /> <DrivesLogTable dongleId={dongleId} />
</TabPanel> </TabPanel>
<TabPanel value={value} index={2}> <TabPanel value={value} index={2}>
<CrashLogsTable dongleId={props.dongleId} /> <CrashLogsTable dongleId={dongleId} />
</TabPanel> </TabPanel>
<TabPanel value={value} index={3}> <TabPanel value={value} index={3}>
<BootLogsTable dongleId={props.dongleId} /> <BootLogsTable dongleId={dongleId} />
</TabPanel> </TabPanel>
<TabPanel value={value} index={4}> <TabPanel value={value} index={4}>
<Console dongleId={props.dongleId} /> <ConsoleTable dongleId={dongleId} />
</TabPanel> </TabPanel>
{
}
</div> </div>
); );
} }
TabPane.propTypes = {
dongleId: PropTypes.string.isRequired,
};
export default TabPane;

View File

@ -1,3 +1,5 @@
import React, { useContext, useState } from 'react';
import PropTypes from 'prop-types';
import OpenInNewIcon from '@mui/icons-material/OpenInNew'; import OpenInNewIcon from '@mui/icons-material/OpenInNew';
import Box from '@mui/material/Box'; import Box from '@mui/material/Box';
import IconButton from '@mui/material/IconButton'; import IconButton from '@mui/material/IconButton';
@ -9,38 +11,41 @@ import TableContainer from '@mui/material/TableContainer';
import TableHead from '@mui/material/TableHead'; import TableHead from '@mui/material/TableHead';
import TableRow from '@mui/material/TableRow'; import TableRow from '@mui/material/TableRow';
import Tooltip from '@mui/material/Tooltip'; import Tooltip from '@mui/material/Tooltip';
import React, { useContext, useState } from 'react';
import Typography from '@mui/material/Typography'; import Typography from '@mui/material/Typography';
import { context as DeviceContext } from '../../../context/devices';
import { DevicesContext } from '../../../context/devices';
import * as deviceController from '../../../controllers/devices'; import * as deviceController from '../../../controllers/devices';
export default function EnhancedTable(props) { function ViewDrive(props) {
const [deviceState] = useContext(DeviceContext); const {
dongleId,
drive: driveId,
} = props;
const [deviceState] = useContext(DevicesContext);
const [state, setState] = useState({ const [state, setState] = useState({
loading: true, firstReqSent: false, segment: null, drive: null, loading: true, firstReqSent: false, segment: null, driveId: null,
}); });
if (state.drive === null) { if (state.drive === null) {
setState({ ...state, drive: props.drive }); setState({ ...state, driveId });
} }
if (props.drive !== state.drive) { if (driveId !== state.drive) {
setState({ setState({
...state, loading: true, firstReqSent: false, segment: null, drive: props.drive, ...state, loading: true, firstReqSent: false, segment: null, driveId,
}); });
} }
const dongle_id = props.dongleId; const dongle = deviceState.dongles[dongleId];
const drive_id = props.drive;
const dongle = deviceState.dongles[dongle_id];
console.log('view drive', dongle); console.log('view drive', dongle);
console.log('drives', dongle.drives); console.log('drives', dongle.drives);
if (!dongle || !dongle.drives) return (<p>loading</p>); if (!dongle || !dongle.drives) return (<p>loading</p>);
if (state.segment === null) { if (state.segment === null) {
// TODO Make this not run multiple times // TODO Make this not run multiple times
deviceController.getDriveSegments(dongle_id, dongle.drives[drive_id].identifier).then((res) => { deviceController.getDriveSegments(dongleId, dongle.drives[driveId].identifier).then((res) => {
console.log('my res', res.data); console.log('my res', res.data);
if (res.data === null) { if (res.data === null) {
setState({ setState({
@ -56,7 +61,7 @@ export default function EnhancedTable(props) {
// test // test
const drive = dongle.drives[drive_id]; const drive = dongle.drives[driveId];
let vehicle = ''; let vehicle = '';
let version = ''; let version = '';
@ -76,8 +81,12 @@ export default function EnhancedTable(props) {
} }
if (metadata.CarParams) { if (metadata.CarParams) {
if (metadata.CarParams.CarName !== undefined) vehicle += `${metadata.CarParams.CarName.toUpperCase()} `; if (metadata.CarParams.CarName !== undefined) {
if (metadata.CarParams.CarFingerprint !== undefined) vehicle += (metadata.CarParams.CarFingerprint.toUpperCase()); vehicle += `${metadata.CarParams.CarName.toUpperCase()} `;
}
if (metadata.CarParams.CarFingerprint !== undefined) {
vehicle += (metadata.CarParams.CarFingerprint.toUpperCase());
}
} }
} catch (exception) { console.log(exception); } } catch (exception) { console.log(exception); }
@ -99,7 +108,6 @@ export default function EnhancedTable(props) {
url: `${driveUrl}/${segment}/${directoryTree.children[i].children[c].name}`, url: `${driveUrl}/${segment}/${directoryTree.children[i].children[c].name}`,
name: directoryTree.children[i].children[c].name, name: directoryTree.children[i].children[c].name,
fileSize: directoryTree.children[i].children[c].size, fileSize: directoryTree.children[i].children[c].size,
}; };
} }
@ -112,7 +120,6 @@ export default function EnhancedTable(props) {
return ( return (
<Box sx={{ width: '100%' }}> <Box sx={{ width: '100%' }}>
<Paper sx={{ width: '100%', mb: 2, padding: '20px' }}> <Paper sx={{ width: '100%', mb: 2, padding: '20px' }}>
<Typography variant="body1"> <Typography variant="body1">
<b>Vehicle:</b> <b>Vehicle:</b>
{' '} {' '}
@ -157,33 +164,41 @@ export default function EnhancedTable(props) {
</TableHead> </TableHead>
<TableBody> <TableBody>
{ {
directorySegments ? Object.keys(directorySegments).map((key, index) => Object.keys(directorySegments[key]).map((key1, index1) => ( directorySegments
<TableRow hover> ? Object.keys(directorySegments)
<TableCell>{key}</TableCell> .map((key) => Object.keys(directorySegments[key])
<TableCell>{directorySegments[key][key1].name}</TableCell> .map((key1) => (
<TableCell>{`${Math.round(directorySegments[key][key1].fileSize / 1024)} MiB`}</TableCell> <TableRow hover>
<TableCell>{key}</TableCell>
<TableCell> <TableCell>{directorySegments[key][key1].name}</TableCell>
<Tooltip title="Open in new window"> <TableCell>{`${Math.round(directorySegments[key][key1].fileSize / 1024)} MiB`}</TableCell>
<IconButton size="small" onClick={() => window.open(directorySegments[key][key1].url, '_blank')}>
<OpenInNewIcon fontSize="inherit" />
</IconButton>
</Tooltip>
</TableCell>
</TableRow>
))) : null
}
<TableCell>
<Tooltip title="Open in new window">
<IconButton size="small" onClick={() => window.open(directorySegments[key][key1].url, '_blank')}>
<OpenInNewIcon fontSize="inherit" />
</IconButton>
</Tooltip>
</TableCell>
</TableRow>
)))
: null
}
</TableBody> </TableBody>
</Table> </Table>
</TableContainer> </TableContainer>
</Paper> </Paper>
</Box> </Box>
); );
} }
ViewDrive.propTypes = {
dongleId: PropTypes.string.isRequired,
drive: PropTypes.string.isRequired,
};
export default ViewDrive;
/* /*
var dongleIdHash = crypto.createHmac('sha256', config.applicationSalt).update(device.dongle_id).digest('hex'); var dongleIdHash = crypto.createHmac('sha256', config.applicationSalt).update(device.dongle_id).digest('hex');

View File

@ -1,28 +1,10 @@
import { createTheme, ThemeProvider } from '@mui/material/styles'; import React from 'react';
import React, { useContext, useState } from 'react';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import { UserContext } from '../../context/users'; import { createTheme, ThemeProvider } from '@mui/material/styles';
const theme = createTheme(); const theme = createTheme();
export default function SignIn() { function Home() {
const [loading, setLoading] = useState(false);
const [state, dispatch] = useContext(UserContext);
console.log('component', state);
const handleSubmit = (event) => {
dispatch({ type: 'toggle_button' });
event.preventDefault();
const data = new FormData(event.currentTarget);
// eslint-disable-next-line no-console
console.log({
email: data.get('email'),
password: data.get('password'),
});
setLoading(true);
};
return ( return (
<ThemeProvider theme={theme}> <ThemeProvider theme={theme}>
<p>hello</p> <p>hello</p>
@ -32,3 +14,5 @@ export default function SignIn() {
</ThemeProvider> </ThemeProvider>
); );
} }
export default Home;

View File

@ -1,3 +1,4 @@
import React, { useContext, useState } from 'react';
import LoadingButton from '@mui/lab/LoadingButton'; import LoadingButton from '@mui/lab/LoadingButton';
import Box from '@mui/material/Box'; import Box from '@mui/material/Box';
import Container from '@mui/material/Container'; import Container from '@mui/material/Container';
@ -6,7 +7,7 @@ import Link from '@mui/material/Link';
import Paper from '@mui/material/Paper'; import Paper from '@mui/material/Paper';
import TextField from '@mui/material/TextField'; import TextField from '@mui/material/TextField';
import Typography from '@mui/material/Typography'; import Typography from '@mui/material/Typography';
import React, { useContext, useState } from 'react';
import { UserContext } from '../../context/users'; import { UserContext } from '../../context/users';
export default function SignIn() { export default function SignIn() {

View File

@ -1,17 +1,17 @@
import React, { useContext } from 'react';
import Grid from '@mui/material/Grid'; import Grid from '@mui/material/Grid';
import Paper from '@mui/material/Paper'; import Paper from '@mui/material/Paper';
import { Scrollbars } from 'rc-scrollbars'; import { Scrollbars } from 'rc-scrollbars';
import React, { useContext } from 'react';
import { context as DeviceContext } from '../../context/devices'; import { DevicesContext } from '../../context/devices';
import DeviceData from '../device/deviceData'; import DeviceData from '../device/deviceData';
import DeviceOverview from '../device/overview'; import DeviceOverview from '../device/overview';
export default function SignIn() { export default function SignIn() {
const [deviceState] = useContext(DeviceContext); const [deviceState] = useContext(DevicesContext);
return ( return (
<div className="wrapper"> <div className="wrapper">
<Grid <Grid
container container
spacing={0} spacing={0}
@ -23,18 +23,17 @@ export default function SignIn() {
<Paper style={{ minHeight: '100%', maxHeight: '100%', margin: '0' }}> <Paper style={{ minHeight: '100%', maxHeight: '100%', margin: '0' }}>
<Scrollbars autoHeight autoHeightMin="calc(100vh - 14px)" autoHeightMax="calc(100% - 14px)"> <Scrollbars autoHeight autoHeightMin="calc(100vh - 14px)" autoHeightMax="calc(100% - 14px)">
<div style={{ padding: '5px' }}> <div style={{ padding: '5px' }}>
{deviceState ? Object.keys(deviceState.dongles).map((key) => <DeviceOverview device={deviceState.dongles[key]} />) : <p>no</p>} {deviceState
? (Object.keys(deviceState.dongles)
.map((key) => <DeviceOverview device={deviceState.dongles[key]} />))
: <p>no</p>}
</div> </div>
</Scrollbars> </Scrollbars>
</Paper> </Paper>
</Grid> </Grid>
<Grid item xs={12} md={8} lg={9} sm={6} xl={10}> <Grid item xs={12} md={8} lg={9} sm={6} xl={10}>
{deviceState.dongles['53331425'] ? <DeviceData device={deviceState.dongles['53331425']} /> : <p>no</p>} {deviceState.dongles['53331425'] ? <DeviceData device={deviceState.dongles['53331425']} /> : <p>no</p>}
</Grid> </Grid>
</Grid> </Grid>
</div> </div>

View File

@ -1,12 +1,13 @@
import Snackbar from '@mui/material/Snackbar';
import React, { useContext } from 'react'; import React, { useContext } from 'react';
import { context as DeviceContext } from '../../context/toast'; import Snackbar from '@mui/material/Snackbar';
export default function Toast(props) { import { ACTIONS, ToastContext } from '../../context/toast';
const [state, dispatch] = useContext(DeviceContext);
function Toast() {
const [state, dispatch] = useContext(ToastContext);
const handleClose = () => { const handleClose = () => {
dispatch({ type: 'CLOSE_TOAST' }); dispatch({ type: ACTIONS.CLOSE_TOAST });
}; };
return ( return (
@ -19,3 +20,5 @@ export default function Toast(props) {
/> />
); );
} }
export default Toast;

View File

@ -0,0 +1,10 @@
const ACTIONS = {
ADD_DATA: 'add_data',
FETCH_ALL_DONGLES: 'fetch_all_dongles',
UPDATE_DONGLE_DRIVE: 'update_dongle_drive',
UPDATE_DONGLE_BOOTLOGS: 'update_dongle_bootlogs',
UPDATE_DONGLE_CRASHLOGS: 'update_dongle_crashlogs',
USER_AUTHENTICATION: 'user_authentication',
};
export default ACTIONS;

View File

@ -1,125 +1,68 @@
import React, { createContext, useEffect, useReducer } from 'react'; import React, {
createContext,
useEffect,
useMemo,
useReducer,
} from 'react';
import PropTypes from 'prop-types';
import * as deviceController from '../../controllers/devices'; import * as deviceController from '../../controllers/devices';
function process(state, action) { import ACTIONS from './actions';
if (action.type !== 'ADD_DATA') { return state; } import reducer from './reducer';
switch (action.data.command) {
case 'dongle_status':
return {
...state,
dongles: {
...state.dongles,
[action.data.data.dongle_id]: {
...state.dongles[action.data.data.dongle_id],
online: action.data.data.online,
last_seen: action.data.data.time,
dongle_id: action.data.data.dongle_id,
},
},
};
default:
return state;
}
}
export const Reducer = (state, action) => {
console.log('input', state, action);
switch (action.type) {
case 'ADD_DATA':
return process(state, action);
case 'fetch_all_dongles':
console.log('fetch', action);
return {
...state,
dongles: action.data,
};
case 'update_dongle_drive':
return {
...state,
dongles: {
...state.dongles,
[action.dongle_id]: {
...state.dongles[action.dongle_id],
drives: action.drives,
},
},
};
case 'update_dongle_bootlogs':
return {
...state,
dongles: {
...state.dongles,
[action.dongle_id]: {
...state.dongles[action.dongle_id],
boot: action.bootlogs,
},
},
};
case 'update_dongle_crashlogs':
return {
...state,
dongles: {
...state.dongles,
[action.dongle_id]: {
...state.dongles[action.dongle_id],
crash: action.crashlogs,
},
},
};
case 'user_authentication':
return {
...state,
user: action.user,
};
default:
return state;
}
};
const initialState = { const initialState = {
dongles: {}, dongles: {},
}; };
function Store({ children }) { const DevicesContext = createContext(initialState);
console.log('STORE HAS BEEN RERENDERED');
const [state, dispatch] = useReducer(Reducer, initialState); function DevicesProvider({ children }) {
const [state, dispatch] = useReducer(reducer, initialState);
useEffect(() => { useEffect(() => {
const ws = new WebSocket('ws://localhost:81'); const ws = new WebSocket('ws://localhost:81');
ws.onmessage = ({ data }) => { ws.onmessage = ({ data }) => {
data = JSON.parse(data); const payload = JSON.parse(data);
console.log('Message'); console.log('devices onmessage', payload);
if (data.id) {
dispatch({ type: 'ADD_DATA', id: data.id, data }); if (!payload.id) {
dispatch({ type: ACTIONS.ADD_DATA, data: payload });
} }
}; };
deviceController.getAllDevices().then((devices) => { deviceController.getAllDevices().then((devices) => {
console.log('store', devices); console.log('devices store', devices);
dispatch({ type: 'fetch_all_dongles', data: devices }); dispatch({ type: ACTIONS.FETCH_ALL_DONGLES, data: devices });
}); });
return () => { return () => {
// Clean up the websocket
try { try {
ws.close(); ws.close();
} catch (e) { } } catch (e) {
// do nothing
}
}; };
}, []); }, []);
const contextValue = useMemo(() => ([state, dispatch]), [state, dispatch]);
return ( return (
<context.Provider value={[state, dispatch]}> <DevicesContext.Provider value={contextValue}>
{children} { children }
</context.Provider> </DevicesContext.Provider>
); );
} }
export const context = createContext(initialState); DevicesProvider.propTypes = {
export default Store; children: PropTypes.node.isRequired,
};
export default DevicesProvider;
export {
ACTIONS,
DevicesContext,
};

View File

@ -0,0 +1,87 @@
import ACTIONS from './actions';
function process(state, action) {
if (action.type !== ACTIONS.ADD_DATA) {
return state;
}
switch (action.data.command) {
case 'dongle_status':
return {
...state,
dongles: {
...state.dongles,
[action.data.data.dongle_id]: {
...state.dongles[action.data.data.dongle_id],
online: action.data.data.online,
last_seen: action.data.data.time,
dongle_id: action.data.data.dongle_id,
},
},
};
default:
return state;
}
}
function reducer(state, action) {
console.log('input', state, action);
switch (action.type) {
case ACTIONS.ADD_DATA:
return process(state, action);
case ACTIONS.FETCH_ALL_DONGLES:
console.log('fetch', action);
return {
...state,
dongles: action.data,
};
case ACTIONS.UPDATE_DONGLE_DRIVE:
return {
...state,
dongles: {
...state.dongles,
[action.dongle_id]: {
...state.dongles[action.dongle_id],
drives: action.drives,
},
},
};
case ACTIONS.UPDATE_DONGLE_BOOTLOGS:
return {
...state,
dongles: {
...state.dongles,
[action.dongle_id]: {
...state.dongles[action.dongle_id],
boot: action.bootlogs,
},
},
};
case ACTIONS.UPDATE_DONGLE_CRASHLOGS:
return {
...state,
dongles: {
...state.dongles,
[action.dongle_id]: {
...state.dongles[action.dongle_id],
crash: action.crashlogs,
},
},
};
case ACTIONS.USER_AUTHENTICATION:
return {
...state,
user: action.user,
};
default:
return state;
}
}
export default reducer;

View File

@ -0,0 +1,6 @@
const ACTIONS = {
NEW_TOAST: 'new_toast',
CLOSE_TOAST: 'close_toast',
};
export default ACTIONS;

View File

@ -1,19 +1,34 @@
import React, { createContext, useReducer } from 'react'; import React, { createContext, useMemo, useReducer } from 'react';
import Reducer from './reducer'; import PropTypes from 'prop-types';
import ACTIONS from './actions';
import reducer from './reducer';
const initialState = { const initialState = {
open: false, open: false,
message: null, message: null,
}; };
function Store({ children }) { const ToastContext = createContext(initialState);
const [state, dispatch] = useReducer(Reducer, initialState);
function ToastProvider({ children }) {
const [state, dispatch] = useReducer(reducer, initialState);
const contextValue = useMemo(() => ([state, dispatch]), [state, dispatch]);
return ( return (
<context.Provider value={[state, dispatch]}> <ToastContext.Provider value={contextValue}>
{children} {children}
</context.Provider> </ToastContext.Provider>
); );
} }
export const context = createContext(initialState); ToastProvider.propTypes = {
export default Store; children: PropTypes.node.isRequired,
};
export default ToastProvider;
export {
ACTIONS,
ToastContext,
};

View File

@ -1,12 +1,14 @@
const Reducer = (state, action) => { import ACTIONS from './actions';
function reducer(state, action) {
switch (action.type) { switch (action.type) {
case 'NEW_TOAST': case ACTIONS.NEW_TOAST:
return { return {
...state, ...state,
open: action.open, open: action.open,
msg: action.message, msg: action.message,
}; };
case 'CLOSE_TOAST': case ACTIONS.CLOSE_TOAST:
return { return {
...state, ...state,
open: false, open: false,
@ -15,6 +17,6 @@ const Reducer = (state, action) => {
default: default:
return state; return state;
} }
}; }
export default Reducer; export default reducer;

View File

@ -0,0 +1,5 @@
const ACTIONS = {
SIGN_OUT: 'sign_out',
};
export default ACTIONS;

View File

@ -1,17 +1,38 @@
import React from 'react'; import React, { createContext, useMemo, useReducer } from 'react';
import { reducer, initialState } from './reducer'; import PropTypes from 'prop-types';
export const UserContext = React.createContext({ import ACTIONS from './actions';
state: initialState, import reducer from './reducer';
dispatch: () => null,
});
export function UserProvider({ children }) { const initialState = {
const [state, dispatch] = React.useReducer(reducer, initialState); signedIn: false,
user: {
id: null,
username: null,
JWT: null,
},
};
const UserContext = createContext(initialState);
function UserProvider({ children }) {
const [state, dispatch] = useReducer(reducer, initialState);
const contextValue = useMemo(() => ([state, dispatch]), [state, dispatch]);
return ( return (
<UserContext.Provider value={[state, dispatch]}> <UserContext.Provider value={contextValue}>
{ children } { children }
</UserContext.Provider> </UserContext.Provider>
); );
} }
UserProvider.propTypes = {
children: PropTypes.node.isRequired,
};
export default UserProvider;
export {
ACTIONS,
UserContext,
};

View File

@ -1,7 +1,8 @@
export const reducer = (state, action) => { import ACTIONS from './actions';
switch (action.type) {
case 'sign_out':
function reducer(state, action) {
switch (action.type) {
case ACTIONS.SIGN_OUT:
return { return {
...state, ...state,
active: !state.active, active: !state.active,
@ -10,13 +11,6 @@ export const reducer = (state, action) => {
default: default:
return state; return state;
} }
}; }
export const initialState = { export default reducer;
signedIn: false,
user: {
id: null,
username: null,
JWT: null,
},
};