Add Login

This commit is contained in:
lsw
2022-11-01 15:10:14 +09:00
parent 2da217f3d0
commit 1fa0d95cb0
11 changed files with 197 additions and 42 deletions

View File

@@ -1 +1,5 @@
REACT_APP_API_URL='http://localhost:4000'
REACT_APP_MODE=prod
REACT_APP_API_URL='http://localhost:4000'
REACT_APP_ID=vanillameta
REACT_APP_PWD=vanillameta
REACT_APP_TOKEN=TOKEN1VB2GS3SWJYDS

View File

@@ -1 +1,5 @@
REACT_APP_API_URL='https://dev-api.vanillameta.net/v1'
REACT_APP_MODE=dev
REACT_APP_API_URL='https://dev-api.vanillameta.net/v1'
REACT_APP_ID=vanillameta
REACT_APP_PWD=vanillameta
REACT_APP_TOKEN=TOKEN1VB2GS3SWJYDS

View File

@@ -1 +1,5 @@
REACT_APP_API_URL='http://localhost:4000'
REACT_APP_MODE=local
REACT_APP_API_URL='http://localhost:4000'
REACT_APP_ID=vanillameta
REACT_APP_PWD=vanillameta
REACT_APP_TOKEN=TOKEN1VB2GS3SWJYDS

View File

@@ -42,7 +42,7 @@
"web-vitals": "^2.1.4"
},
"scripts": {
"start": "craco start",
"start": "env-cmd -f .env.local craco start",
"start:dev": "env-cmd -f .env.development craco start",
"start:local": "env-cmd -f .env.local craco start",
"build": "craco build",

View File

@@ -1,6 +1,5 @@
import React, { useEffect } from 'react';
import React from 'react';
import { CssBaseline } from '@mui/material';
import Layout from './layouts/Layout';
import Router from './router';
import 'tui-grid/dist/tui-grid.css';
import Grid from 'tui-grid';
@@ -59,9 +58,7 @@ function App() {
return (
<>
<CssBaseline />
<Layout>
<Router />
</Layout>
<Router />
</>
);
}

View File

@@ -0,0 +1,34 @@
import { createContext, useContext, useState } from 'react';
const AuthContext = createContext(null);
export const AuthProvider = ({ children }) => {
const [token, setToken] = useState(null);
const handleLogin = async (id, pwd) => {
return new Promise((resolve, reject) => {
if (id === process.env.REACT_APP_ID && pwd === process.env.REACT_APP_PWD) {
setToken(process.env.REACT_APP_TOKEN);
setTimeout(() => resolve(process.env.REACT_APP_TOKEN), 1000);
} else {
reject(new Error('User ID or password incorrect.'));
}
});
};
const handleLogout = () => {
setToken(null);
};
const value = {
token,
onLogin: handleLogin,
onLogout: handleLogout,
};
return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;
};
export const useAuth = () => {
return useContext(AuthContext);
};

View File

@@ -10,6 +10,7 @@ import App from './App';
import './index.css';
import { LayoutProvider } from '@/contexts/LayoutContext';
import { LoadingProvider } from '@/contexts/LoadingContext';
import { AuthProvider } from '@/contexts/AuthContext';
// alert optional configuration
const options = {
@@ -25,11 +26,13 @@ root.render(
<LayoutProvider>
<LoadingProvider>
<BrowserRouter>
<ThemeProvider theme={theme}>
<AlertProvider template={AlertTemplate} {...options}>
<App />
</AlertProvider>
</ThemeProvider>
<AuthProvider>
<ThemeProvider theme={theme}>
<AlertProvider template={AlertTemplate} {...options}>
<App />
</AlertProvider>
</ThemeProvider>
</AuthProvider>
</BrowserRouter>
</LoadingProvider>
</LayoutProvider>,

View File

@@ -4,8 +4,10 @@ import { Box, Stack } from '@mui/material';
import Header from './Header/Header';
import Footer from './Footer/Footer';
import { LayoutContext } from '@/contexts/LayoutContext';
import { Outlet } from 'react-router-dom';
function Layout(props) {
const Layout = props => {
const { children } = props;
const headerHeight = 65;
const footerHeight = 50;
@@ -33,11 +35,11 @@ function Layout(props) {
minHeight: `calc(100% - ${footerHeight}px)`,
}}
>
{props.children}
{children || <Outlet />}
</Stack>
<Footer height={footerHeight} />
</Box>
);
}
};
export default Layout;

View File

@@ -0,0 +1,83 @@
import React, { useContext, useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { Box, Stack, Button, Checkbox, Container, FormControlLabel, Link, TextField, Typography } from '@mui/material';
import { useAlert } from 'react-alert';
import { useAuth } from '@/contexts/AuthContext';
import { LoadingContext } from '@/contexts/LoadingContext';
function Copyright(props: any) {
return (
<Typography variant="body2" color="text.secondary" align="center" {...props}>
<Link color="inherit" href="https://vanillabrain.com/" sx={{ textDecoration: 'none' }}>
@Vanilla Meta
</Link>{' '}
{new Date().getFullYear()}
{'.'}
</Typography>
);
}
const Login = () => {
const { onLogin } = useAuth();
const navigate = useNavigate();
const alert = useAlert();
const { showLoading, hideLoading } = useContext(LoadingContext);
const [userInfo] = useState({
userId: process.env.REACT_APP_MODE === 'local' ? process.env.REACT_APP_ID : '',
userPwd: process.env.REACT_APP_MODE === 'local' ? process.env.REACT_APP_PWD : '',
});
const handleLogin = async event => {
event.preventDefault();
showLoading();
await onLogin(event.target.userId.value, event.target.userPwd.value)
.then(res => {
if (res) {
navigate('/dashboard');
}
})
.catch(error => {
alert.info(`${error}`);
console.log('error', error);
})
.finally(() => {
hideLoading();
});
};
return (
<Container component="main" maxWidth="xs">
<Box
sx={{
marginTop: 8,
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
}}
>
<Typography component="h1" variant="h5">
Sign in
</Typography>
<Stack component="form" onSubmit={handleLogin} noValidate sx={{ mt: 1 }} spacing="20px">
<TextField margin="normal" required fullWidth id="userId" label="ID" name="email" defaultValue={userInfo.userId} />
<TextField
margin="normal"
required
fullWidth
name="userPwd"
defaultValue={userInfo.userPwd}
label="Password"
type="password"
id="password"
/>
<FormControlLabel control={<Checkbox value="remember" color="primary" />} label="Remember me" />
<Button type="submit" fullWidth variant="contained" sx={{ mt: 3, mb: 2 }}>
Sign In
</Button>
</Stack>
</Box>
<Copyright sx={{ mt: 8, mb: 4 }} />
</Container>
);
};
export default Login;

View File

@@ -0,0 +1,12 @@
import { Navigate } from 'react-router-dom';
import { useAuth } from '@/contexts/AuthContext';
export const ProtectedRoute = ({ children }) => {
const { token } = useAuth();
console.log('ProtectedRoute', token);
if (!token) {
return <Navigate to="/login" replace />;
}
return children;
};

View File

@@ -13,38 +13,50 @@ import WidgetModify from '@/pages/Widget/WidgetModify';
import DashboardView from '@/pages/Dashboard/DashboardView';
import DashboardCreate from '@/pages/Dashboard/DashboardCreate';
import DashboardModify from '@/pages/Dashboard/DashboardModify';
import Login from '@/pages/Login';
import { ProtectedRoute } from '@/router/ProtectedRoute';
import Layout from '@/layouts/Layout';
function Router() {
return (
<Routes>
<Route path="/" element={<Navigate to="/dashboard" />} />
<Route path="/dashboard" element={<Dashboard />} />
<Route path="/dashboard/:dashboardId" element={<DashboardView />} />
<Route path="/dashboard/create" element={<DashboardCreate />}>
<Route path=":createType" element={<DashboardCreate />} />
</Route>
<Route path="/dashboard/modify" element={<DashboardModify />}>
<Route path=":dashboardId" element={<DashboardModify />} />
</Route>
<Route path="/widget" element={<Widget />} />
<Route path="/widget/:widgetId" element={<WidgetView />} />
<Route path="/widget/create" element={<WidgetCreate />} />
<Route path="/widget/modify" element={<WidgetModify />}>
<Route path=":widgetId" element={<WidgetModify />} />
</Route>
<Route
path="/"
element={
<ProtectedRoute>
<Layout />
</ProtectedRoute>
}
>
<Route path="/dashboard" element={<Dashboard />} />
<Route path="/dashboard/:dashboardId" element={<DashboardView />} />
<Route path="/dashboard/create" element={<DashboardCreate />}>
<Route path=":createType" element={<DashboardCreate />} />
</Route>
<Route path="/dashboard/modify" element={<DashboardModify />}>
<Route path=":dashboardId" element={<DashboardModify />} />
</Route>
<Route path="/widget" element={<Widget />} />
<Route path="/widget/:widgetId" element={<WidgetView />} />
<Route path="/widget/create" element={<WidgetCreate />} />
<Route path="/widget/modify" element={<WidgetModify />}>
<Route path=":widgetId" element={<WidgetModify />} />
</Route>
<Route path="/data" element={<Data />} />
<Route path="/data/source/create" element={<DataSource />} />
<Route path="/data/source/modify" element={<DataSource />}>
<Route path=":sourceId" element={<DataSource />} />
</Route>
<Route path="/data" element={<Data />} />
<Route path="/data/source/create" element={<DataSource />} />
<Route path="/data/source/modify" element={<DataSource />}>
<Route path=":sourceId" element={<DataSource />} />
</Route>
<Route path="/data/set/create" element={<DataSet />}>
<Route path=":sourceId" element={<DataSet />} />
</Route>
<Route path="/data/set/modify" element={<DataSet />}>
<Route path=":setId" element={<DataSet />} />
<Route path="/data/set/create" element={<DataSet />}>
<Route path=":sourceId" element={<DataSet />} />
</Route>
<Route path="/data/set/modify" element={<DataSet />}>
<Route path=":setId" element={<DataSet />} />
</Route>
</Route>
<Route path="/login" element={<Login />} />
<Route path="/*" element={<Status404 />} />
</Routes>
);