update jamespong14205,
This commit is contained in:
136
task1/project/003_src/client/pages/AdminHome/index.js
Normal file
136
task1/project/003_src/client/pages/AdminHome/index.js
Normal file
@@ -0,0 +1,136 @@
|
||||
import React, { useState } from 'react';
|
||||
|
||||
import { ChevronLeftOutlined } from '@mui/icons-material';
|
||||
import MenuIcon from '@mui/icons-material/Menu';
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
Drawer,
|
||||
IconButton,
|
||||
List,
|
||||
ListItem,
|
||||
ListItemButton,
|
||||
ListItemIcon,
|
||||
ListItemText,
|
||||
} from '@mui/material';
|
||||
import { useRouter } from 'next/dist/client/router';
|
||||
import Head from 'next/head';
|
||||
|
||||
export default function Home() {
|
||||
const [open, setOpen] = React.useState(false);
|
||||
const router = useRouter();
|
||||
|
||||
const [changing_page, setChangingPage] = useState(false);
|
||||
|
||||
const toggleDrawer = newOpen => () => {
|
||||
setOpen(newOpen);
|
||||
};
|
||||
|
||||
const DrawerList = (
|
||||
<Box sx={{ width: 250 }} role='presentation' onClick={toggleDrawer(false)}>
|
||||
<List>
|
||||
<ListItem key='dashboard' disablePadding>
|
||||
<ListItemButton
|
||||
onClick={() => {
|
||||
setChangingPage(true);
|
||||
router.push('/AdminLogin');
|
||||
}}
|
||||
>
|
||||
<ListItemIcon>
|
||||
<ChevronLeftOutlined />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary='Logout' />
|
||||
</ListItemButton>
|
||||
</ListItem>
|
||||
</List>
|
||||
</Box>
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
<title>admin dashboard</title>
|
||||
<meta name='description' content='Generated by create next app' />
|
||||
<link rel='icon' href='/favicon.ico' />
|
||||
</Head>
|
||||
|
||||
<Box className='main'>
|
||||
<Box
|
||||
sx={{
|
||||
//
|
||||
display: 'flex',
|
||||
flexDirection: 'flex-start',
|
||||
alignItems: 'center',
|
||||
gap: '1rem',
|
||||
//
|
||||
height: '3rem',
|
||||
}}
|
||||
>
|
||||
<IconButton aria-label='menu' onClick={toggleDrawer(true)}>
|
||||
<MenuIcon />
|
||||
</IconButton>
|
||||
<Box sx={{ fontWeight: 'bold', fontSize: '1.2rem' }}>Admin dashboard</Box>
|
||||
</Box>
|
||||
|
||||
<Box
|
||||
sx={{
|
||||
height: '90vh',
|
||||
width: '100%',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
}}
|
||||
>
|
||||
<Box sx={{}}>
|
||||
<Box style={{ paddingTop: '3rem', width: '90vw' }}>
|
||||
<Button
|
||||
variant='contained'
|
||||
disabled={changing_page}
|
||||
onClick={() => {
|
||||
setChangingPage(true);
|
||||
router.push('/SemiUrgentCaseList');
|
||||
}}
|
||||
fullWidth
|
||||
>
|
||||
<Box sx={{ fontSize: '1.1rem', padding: '1rem' }}>Semi-urgent case</Box>
|
||||
</Button>
|
||||
</Box>
|
||||
|
||||
<Box style={{ paddingTop: '3rem', width: '90vw' }}>
|
||||
<Button
|
||||
variant='contained'
|
||||
disabled={changing_page}
|
||||
onClick={() => {
|
||||
setChangingPage(true);
|
||||
router.push('/NonUrgentCaseList');
|
||||
}}
|
||||
fullWidth
|
||||
>
|
||||
<Box style={{ fontSize: '1.1rem', padding: '1rem' }}>Non-urgent case</Box>
|
||||
</Button>
|
||||
</Box>
|
||||
|
||||
<Box style={{ paddingTop: '3rem', width: '90vw' }}>
|
||||
<Button
|
||||
variant='contained'
|
||||
disabled={changing_page}
|
||||
onClick={() => {
|
||||
setChangingPage(true);
|
||||
router.push('/SearchCase');
|
||||
}}
|
||||
fullWidth
|
||||
>
|
||||
<Box style={{ fontSize: '1.1rem', padding: '1rem' }}>Search case</Box>
|
||||
</Button>
|
||||
</Box>
|
||||
</Box>
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
<Drawer open={open} onClose={toggleDrawer(false)}>
|
||||
{DrawerList}
|
||||
</Drawer>
|
||||
</>
|
||||
);
|
||||
}
|
168
task1/project/003_src/client/pages/AdminLogin/index.js
Normal file
168
task1/project/003_src/client/pages/AdminLogin/index.js
Normal file
@@ -0,0 +1,168 @@
|
||||
import { Box, Button, TextField } from '@mui/material';
|
||||
import Head from 'next/head';
|
||||
|
||||
import { ChevronLeftOutlined } from '@mui/icons-material';
|
||||
import LoginIcon from '@mui/icons-material/Login';
|
||||
import { useFormik } from 'formik';
|
||||
import { useRouter } from 'next/dist/client/router';
|
||||
import React from 'react';
|
||||
import is_development_plant from 'utils/is_development_plant';
|
||||
import * as yup from 'yup';
|
||||
|
||||
let default_init_values = {
|
||||
username: '',
|
||||
passwod: '',
|
||||
};
|
||||
|
||||
if (is_development_plant) {
|
||||
console.log('development plant');
|
||||
|
||||
default_init_values = {
|
||||
username: 'admi',
|
||||
password: 'nimda',
|
||||
};
|
||||
}
|
||||
|
||||
const validationSchema = yup.object({
|
||||
username: yup
|
||||
.string('Enter your username')
|
||||
.min(5, 'Username should be of minimum 5 characters length')
|
||||
.required('Username is required'),
|
||||
password: yup
|
||||
.string('Enter your password')
|
||||
.min(5, 'Password should be of minimum 5 characters length')
|
||||
.required('Password is required'),
|
||||
});
|
||||
|
||||
export default function Home() {
|
||||
const router = useRouter();
|
||||
const [changing_page, setChangingPage] = React.useState(false);
|
||||
|
||||
const formik = useFormik({
|
||||
initialValues: default_init_values,
|
||||
validationSchema,
|
||||
onSubmit: values => {
|
||||
fetch('/api/auth/login', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(values),
|
||||
})
|
||||
.then(res => res.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
router.push('/AdminHome');
|
||||
} else {
|
||||
alert(data.message);
|
||||
formik.resetForm();
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
console.error(err);
|
||||
alert('server error');
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
<title>admin login page</title>
|
||||
<meta name='description' content='Generated by create next app' />
|
||||
<link rel='icon' href='/favicon.ico' />
|
||||
</Head>
|
||||
|
||||
<Box
|
||||
sx={{
|
||||
height: '90vh',
|
||||
//
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
gap: '1rem',
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
//
|
||||
width: '100%',
|
||||
padding: '0 2rem',
|
||||
}}
|
||||
>
|
||||
<form onSubmit={formik.handleSubmit}>
|
||||
<Box
|
||||
sx={{
|
||||
textAlign: 'center',
|
||||
fontWeight: 'bold',
|
||||
fontSize: '1.2rem',
|
||||
marginTop: '2rem',
|
||||
marginBottom: '2rem',
|
||||
}}
|
||||
>
|
||||
Admin Login Page
|
||||
</Box>
|
||||
<TextField
|
||||
fullWidth
|
||||
variant='standard'
|
||||
id='username'
|
||||
name='username'
|
||||
value={formik.values.username}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
error={formik.touched.username && Boolean(formik.errors.username)}
|
||||
helperText={formik.touched.username && formik.errors.username}
|
||||
label='Username'
|
||||
inputProps={{ sx: { textAlign: 'center' } }}
|
||||
/>
|
||||
<TextField
|
||||
fullWidth
|
||||
variant='standard'
|
||||
id='password'
|
||||
name='password'
|
||||
value={formik.values.password}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
error={formik.touched.password && Boolean(formik.errors.password)}
|
||||
helperText={formik.touched.password && formik.errors.password}
|
||||
type='password'
|
||||
label='Password'
|
||||
inputProps={{ sx: { textAlign: 'center' } }}
|
||||
/>
|
||||
|
||||
<Box
|
||||
style={{
|
||||
paddingTop: '3rem',
|
||||
display: 'flex',
|
||||
justifyContent: 'space-around',
|
||||
}}
|
||||
>
|
||||
<Button
|
||||
disabled={changing_page || formik.isSubmitting}
|
||||
variant='outlined'
|
||||
startIcon={<ChevronLeftOutlined />}
|
||||
onClick={() => {
|
||||
setChangingPage(true);
|
||||
router.push('/');
|
||||
}}
|
||||
>
|
||||
Back
|
||||
</Button>
|
||||
<Button
|
||||
variant='contained'
|
||||
type='submit'
|
||||
startIcon={<LoginIcon />}
|
||||
disabled={!(formik.isValid && formik.dirty && !formik.isSubmitting) || changing_page}
|
||||
>
|
||||
Login
|
||||
</Button>
|
||||
</Box>
|
||||
</form>
|
||||
</Box>
|
||||
</Box>
|
||||
</>
|
||||
);
|
||||
}
|
246
task1/project/003_src/client/pages/NonUrgentCaseEdit/[id].js
Normal file
246
task1/project/003_src/client/pages/NonUrgentCaseEdit/[id].js
Normal file
@@ -0,0 +1,246 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
|
||||
import { Box, Button, TextField } from '@mui/material';
|
||||
import Head from 'next/head';
|
||||
|
||||
import { ChevronLeftOutlined } from '@mui/icons-material';
|
||||
import Loading from 'components/Loading';
|
||||
import { useFormik } from 'formik';
|
||||
import { useRouter } from 'next/dist/client/router';
|
||||
import * as yup from 'yup';
|
||||
|
||||
const validationSchema = yup.object({
|
||||
patient_name: yup
|
||||
.string('Enter your name')
|
||||
.min(2, 'Name should be of minimum 2 characters length')
|
||||
.required('Name is required'),
|
||||
patient_hkid: yup
|
||||
.string('Enter your HKID')
|
||||
.matches(/^[A-Z]{1,2}[0-9]{6}\([0-9]\)$/, 'HKID should be in format of XX123456(1-9)')
|
||||
.required('HKID is required'),
|
||||
patient_age: yup
|
||||
.number('Enter your age')
|
||||
.min(1, 'Age should be greater than 0')
|
||||
.max(90, 'Age should be less than 90')
|
||||
.required('Age is required'),
|
||||
patient_mobile: yup
|
||||
.string('Enter your mobile number')
|
||||
.matches(/^[0-9]{8}$/, 'Mobile number should be 8 numbers')
|
||||
.required('Mobile number is required'),
|
||||
});
|
||||
|
||||
export default () => {
|
||||
const router = useRouter();
|
||||
const { id } = router.query;
|
||||
|
||||
const [loading, setLoading] = React.useState(true);
|
||||
const [changing_page, setChangingPage] = useState(false);
|
||||
|
||||
const formik = useFormik({
|
||||
enableReinitialize: true,
|
||||
initialValues: {
|
||||
patient_name: '',
|
||||
patient_hkid: '',
|
||||
patient_age: 0,
|
||||
patient_mobile: '',
|
||||
bruisesScratchesMinorBurns: false,
|
||||
chestPain: false,
|
||||
headache: false,
|
||||
myMuiCheck: false,
|
||||
nauseaAndVomiting: false,
|
||||
runnyOrStuffyNose: false,
|
||||
soreThroat: false,
|
||||
},
|
||||
validationSchema,
|
||||
onSubmit: values => {
|
||||
fetch('/api/patient_queue/update_queue_item', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ id, queue_type: 'non-urgent', values }),
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.status) {
|
||||
alert('saved !');
|
||||
router.reload();
|
||||
} else {
|
||||
// alert(data.message);
|
||||
alert('sorry there are something wrong, please try again');
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
console.error(err);
|
||||
alert('server error');
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
console.log({ t: `/api/patient_queue/read_queue_item?queue_type=non-urgent&id=${id}` });
|
||||
if (id) {
|
||||
fetch(`/api/patient_queue/read_queue_item?queue_type=non-urgent&id=${id}`, {
|
||||
method: 'GET',
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.status) {
|
||||
console.log(data);
|
||||
|
||||
const {
|
||||
name,
|
||||
hkid,
|
||||
mobile,
|
||||
age,
|
||||
bruisesScratchesMinorBurns,
|
||||
chestPain,
|
||||
headache,
|
||||
myMuiCheck,
|
||||
nauseaAndVomiting,
|
||||
runnyOrStuffyNose,
|
||||
soreThroat,
|
||||
} = data.queueItem;
|
||||
|
||||
formik.setValues({
|
||||
patient_name: name,
|
||||
patient_hkid: hkid,
|
||||
patient_mobile: mobile,
|
||||
patient_age: age,
|
||||
bruisesScratchesMinorBurns,
|
||||
chestPain,
|
||||
headache,
|
||||
myMuiCheck,
|
||||
nauseaAndVomiting,
|
||||
runnyOrStuffyNose,
|
||||
soreThroat,
|
||||
});
|
||||
} else {
|
||||
alert(data.message);
|
||||
}
|
||||
|
||||
setLoading(false);
|
||||
})
|
||||
.catch(err => {
|
||||
console.error(err);
|
||||
alert('server error');
|
||||
})
|
||||
.finally(() => {
|
||||
setLoading(false);
|
||||
});
|
||||
}
|
||||
}, [id]);
|
||||
|
||||
if (loading) {
|
||||
return <Loading />;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
<title>dashboard - non-urgent case</title>
|
||||
<meta name='description' content='Generated by create next app' />
|
||||
<link rel='icon' href='/favicon.ico' />
|
||||
</Head>
|
||||
|
||||
<Box
|
||||
sx={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
minHeight: '90vh',
|
||||
}}
|
||||
>
|
||||
<form onSubmit={formik.handleSubmit}>
|
||||
<Box sx={{ marginLeft: '2rem', marginRight: '2rem' }}>
|
||||
<Box
|
||||
sx={{
|
||||
fontWeight: 'bold',
|
||||
fontSize: '1.1rem',
|
||||
marginTop: '1rem',
|
||||
marginBottom: '1rem',
|
||||
}}
|
||||
>
|
||||
Edit Registration
|
||||
</Box>
|
||||
<TextField
|
||||
fullWidth
|
||||
disabled={changing_page || formik.isSubmitting}
|
||||
variant='standard'
|
||||
id='patient_name'
|
||||
name='patient_name'
|
||||
label='Patient name'
|
||||
value={formik.values.patient_name}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
error={formik.touched.patient_name && Boolean(formik.errors.patient_name)}
|
||||
helperText={formik.touched.patient_name && formik.errors.patient_name}
|
||||
/>
|
||||
<TextField
|
||||
fullWidth
|
||||
disabled={changing_page || formik.isSubmitting}
|
||||
variant='standard'
|
||||
id='patient_hkid'
|
||||
name='patient_hkid'
|
||||
label='HKID'
|
||||
value={formik.values.patient_hkid}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
error={formik.touched.patient_hkid && Boolean(formik.errors.patient_hkid)}
|
||||
helperText={formik.touched.patient_hkid && formik.errors.patient_hkid}
|
||||
/>
|
||||
<TextField
|
||||
fullWidth
|
||||
disabled={changing_page || formik.isSubmitting}
|
||||
variant='standard'
|
||||
id='patient_age'
|
||||
name='patient_age'
|
||||
label='Age'
|
||||
value={formik.values.patient_age}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
error={formik.touched.patient_age && Boolean(formik.errors.patient_age)}
|
||||
helperText={formik.touched.patient_age && formik.errors.patient_age}
|
||||
/>
|
||||
<TextField
|
||||
fullWidth
|
||||
disabled={changing_page || formik.isSubmitting}
|
||||
variant='standard'
|
||||
id='patient_mobile'
|
||||
name='patient_mobile'
|
||||
label='Mobile'
|
||||
value={formik.values.patient_mobile}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
error={formik.touched.patient_mobile && Boolean(formik.errors.patient_mobile)}
|
||||
helperText={formik.touched.patient_mobile && formik.errors.patient_mobile}
|
||||
/>
|
||||
|
||||
<Box sx={{ marginTop: '1rem', display: 'flex', justifyContent: 'space-around' }}>
|
||||
<Button
|
||||
disabled={changing_page}
|
||||
onClick={() => {
|
||||
setChangingPage(true);
|
||||
router.push('/NonUrgentCaseList');
|
||||
}}
|
||||
variant='outline'
|
||||
startIcon={<ChevronLeftOutlined />}
|
||||
>
|
||||
Back
|
||||
</Button>
|
||||
{/* */}
|
||||
<Button
|
||||
//
|
||||
color='primary'
|
||||
variant='contained'
|
||||
type='submit'
|
||||
disabled={!(formik.isValid && formik.dirty && !formik.isSubmitting) || changing_page}
|
||||
>
|
||||
Save
|
||||
</Button>
|
||||
</Box>
|
||||
</Box>
|
||||
</form>
|
||||
</Box>
|
||||
</>
|
||||
);
|
||||
};
|
@@ -0,0 +1,40 @@
|
||||
import { ChevronLeftOutlined } from '@mui/icons-material';
|
||||
import { Box, Button } from '@mui/material';
|
||||
import { useRouter } from 'next/dist/client/router';
|
||||
import { useState } from 'react';
|
||||
|
||||
export default () => {
|
||||
const [changing_page, setChangingPage] = useState(false);
|
||||
const router = useRouter();
|
||||
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
width: '100%',
|
||||
height: '90vh',
|
||||
//
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
gap: '3rem',
|
||||
//
|
||||
fontWeight: 'bold',
|
||||
fontSize: '1.2rem',
|
||||
}}
|
||||
>
|
||||
<Box>Queue is empty</Box>
|
||||
<Button
|
||||
onClick={() => {
|
||||
setChangingPage(true);
|
||||
router.push('/AdminHome');
|
||||
}}
|
||||
startIcon={<ChevronLeftOutlined />}
|
||||
variant='outlined'
|
||||
disabled={changing_page}
|
||||
>
|
||||
Back
|
||||
</Button>
|
||||
</Box>
|
||||
);
|
||||
};
|
114
task1/project/003_src/client/pages/NonUrgentCaseList/index.js
Normal file
114
task1/project/003_src/client/pages/NonUrgentCaseList/index.js
Normal file
@@ -0,0 +1,114 @@
|
||||
import MenuIcon from '@mui/icons-material/Menu';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
|
||||
import { ChevronLeftOutlined } from '@mui/icons-material';
|
||||
import { Box, Drawer, IconButton, List, ListItem, ListItemButton, ListItemIcon, ListItemText } from '@mui/material';
|
||||
import Loading from 'components/Loading';
|
||||
import NonUrgentQueueItemCard from 'components/NonUrgentQueueItemCard';
|
||||
import { useRouter } from 'next/dist/client/router';
|
||||
import Head from 'next/head';
|
||||
import QueueIsEmpty from './QueueIsEmpty';
|
||||
|
||||
export default () => {
|
||||
const [open, setOpen] = React.useState(false);
|
||||
const [p_queue, setPQueue] = React.useState([]);
|
||||
const router = useRouter();
|
||||
const [loading, setLoading] = React.useState(true);
|
||||
|
||||
const [changing_page, setChangingPage] = useState(false);
|
||||
|
||||
const toggleDrawer = newOpen => () => {
|
||||
setOpen(newOpen);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
fetch('/api/patient_queue/non_urgent_case')
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
setPQueue(data.patient_queues);
|
||||
setLoading(false);
|
||||
});
|
||||
}, []);
|
||||
|
||||
const DrawerList = (
|
||||
<Box sx={{ width: 250 }} role='presentation' onClick={toggleDrawer(false)}>
|
||||
<List>
|
||||
<ListItem key='dashboard' disablePadding>
|
||||
<ListItemButton
|
||||
disabled={changing_page}
|
||||
onClick={() => {
|
||||
setChangingPage(true);
|
||||
router.push('/AdminHome');
|
||||
}}
|
||||
>
|
||||
<ListItemIcon>
|
||||
<ChevronLeftOutlined />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary='back to dashboard' />
|
||||
</ListItemButton>
|
||||
</ListItem>
|
||||
</List>
|
||||
</Box>
|
||||
);
|
||||
|
||||
if (loading) {
|
||||
return <Loading />;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
<title>dashboard - non-urgent case</title>
|
||||
<meta name='description' content='Generated by create next app' />
|
||||
<link rel='icon' href='/favicon.ico' />
|
||||
</Head>
|
||||
|
||||
<Box className='main'>
|
||||
<Box
|
||||
sx={{
|
||||
//
|
||||
display: 'flex',
|
||||
flexDirection: 'flex-start',
|
||||
alignItems: 'center',
|
||||
gap: '1rem',
|
||||
//
|
||||
height: '3rem',
|
||||
}}
|
||||
>
|
||||
<IconButton aria-label='menu' onClick={toggleDrawer(true)}>
|
||||
<MenuIcon />
|
||||
</IconButton>
|
||||
<Box sx={{ fontWeight: 'bold', fontSize: '1.2rem' }}>All Non-Urgent Cases</Box>
|
||||
</Box>
|
||||
{/* */}
|
||||
<Box style={{ height: '95vh', overflowY: 'scroll' }}>
|
||||
{p_queue.length === 0 ? (
|
||||
<QueueIsEmpty />
|
||||
) : (
|
||||
<>
|
||||
{p_queue.map(queue_data => (
|
||||
<NonUrgentQueueItemCard key={queue_data} queue_data={queue_data} />
|
||||
))}
|
||||
<Box
|
||||
style={{
|
||||
width: '100%',
|
||||
display: 'inline-flex',
|
||||
justifyContent: 'center',
|
||||
marginTop: '1rem',
|
||||
marginBottom: '1rem',
|
||||
}}
|
||||
>
|
||||
--end of list--
|
||||
</Box>
|
||||
</>
|
||||
)}
|
||||
</Box>
|
||||
helloworld
|
||||
</Box>
|
||||
|
||||
<Drawer open={open} onClose={toggleDrawer(false)}>
|
||||
{DrawerList}
|
||||
</Drawer>
|
||||
</>
|
||||
);
|
||||
};
|
40
task1/project/003_src/client/pages/PatientLanding/index.js
Normal file
40
task1/project/003_src/client/pages/PatientLanding/index.js
Normal file
@@ -0,0 +1,40 @@
|
||||
import { Box, Button } from '@mui/material';
|
||||
import { useRouter } from 'next/dist/client/router';
|
||||
import { useState } from 'react';
|
||||
|
||||
export default () => {
|
||||
const router = useRouter();
|
||||
const [changing_page, setChangingPage] = useState(false);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Box sx={{ width: '100%', display: 'flex', flexDirection: 'row', justifyContent: 'center', marginTop: '2rem' }}>
|
||||
<Box sx={{ fontWeight: 'bold', fontSize: '1.5rem' }}>Patient Landing</Box>
|
||||
</Box>
|
||||
<Box
|
||||
sx={{
|
||||
height: '80vh',
|
||||
width: '100%',
|
||||
display: 'inline-flex',
|
||||
flexDirection: 'column',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
}}
|
||||
>
|
||||
<Box>
|
||||
<Button
|
||||
onClick={() => {
|
||||
setChangingPage(true);
|
||||
router.push('/PatientRegister');
|
||||
}}
|
||||
variant='contained'
|
||||
disableElevation
|
||||
disabled={changing_page}
|
||||
>
|
||||
Proceed to register
|
||||
</Button>
|
||||
</Box>
|
||||
</Box>
|
||||
</>
|
||||
);
|
||||
};
|
119
task1/project/003_src/client/pages/PatientQueueDisplay/index.js
Normal file
119
task1/project/003_src/client/pages/PatientQueueDisplay/index.js
Normal file
@@ -0,0 +1,119 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
|
||||
import { Box, Button } from '@mui/material';
|
||||
import Loading from 'components/Loading';
|
||||
import { useRouter } from 'next/dist/client/router';
|
||||
import Head from 'next/head';
|
||||
|
||||
export default () => {
|
||||
const [loading, setLoading] = React.useState(true);
|
||||
const router = useRouter();
|
||||
const [changing_page, setChangingPage] = useState(false);
|
||||
|
||||
const [queue_type, setQueueType] = useState('');
|
||||
const [queue_id, setQueueId] = useState('');
|
||||
|
||||
useEffect(() => {
|
||||
let temp;
|
||||
temp = localStorage.getItem('queue_type');
|
||||
if (temp) setQueueType(temp);
|
||||
|
||||
temp = localStorage.getItem('queue_id');
|
||||
if (temp) setQueueId(temp);
|
||||
|
||||
setLoading(false);
|
||||
}, []);
|
||||
|
||||
if (loading) {
|
||||
return <Loading />;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
<title>dashboard - non-urgent case</title>
|
||||
<meta name='description' content='Generated by create next app' />
|
||||
<link rel='icon' href='/favicon.ico' />
|
||||
</Head>
|
||||
|
||||
<Box
|
||||
sx={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
minHeight: '90vh',
|
||||
}}
|
||||
>
|
||||
<Box sx={{ fontWeight: 'bold', fontSize: '1.2rem' }}>Queue Number</Box>
|
||||
<Box
|
||||
style={{
|
||||
marginTop: '1.2rem',
|
||||
|
||||
fontWeight: 'bold',
|
||||
fontSize: '6rem',
|
||||
backgroundColor: 'lightgray',
|
||||
width: '75vw',
|
||||
height: '75vw',
|
||||
borderRadius: '1rem',
|
||||
//
|
||||
display: 'inline-flex',
|
||||
flexDirection: 'column',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
//
|
||||
}}
|
||||
>
|
||||
{queue_id}
|
||||
</Box>
|
||||
|
||||
<Box sx={{ marginTop: '1rem', display: 'flex', flexDirection: 'column', alignItems: 'center' }}>
|
||||
{queue_type !== '' ? (
|
||||
<>
|
||||
<Box sx={{ fontWeight: 'bold' }}>Your waiting list category</Box>
|
||||
<Box sx={{ fontWeight: 'bold', fontSize: '1.2rem' }}>{queue_type}</Box>
|
||||
</>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
</Box>
|
||||
|
||||
<Box
|
||||
sx={{
|
||||
marginTop: '1.2rem',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
fontWeight: 'bold',
|
||||
color: 'red',
|
||||
}}
|
||||
>
|
||||
<Box sx={{}}>please screen capture </Box>
|
||||
<Box sx={{}}>for saving your Queue Number</Box>
|
||||
|
||||
<Box sx={{ marginTop: '1rem' }}>
|
||||
<Button
|
||||
disabled={changing_page}
|
||||
onClick={() => {
|
||||
localStorage.removeItem('queue_id');
|
||||
localStorage.removeItem('queue_name');
|
||||
localStorage.removeItem('queue_hkid');
|
||||
localStorage.removeItem('queue_mobile');
|
||||
localStorage.removeItem('queue_description');
|
||||
|
||||
alert('Please be informed that the queue information cleared');
|
||||
|
||||
setChangingPage(true);
|
||||
router.push('/');
|
||||
}}
|
||||
disableElevation
|
||||
variant='contained'
|
||||
>
|
||||
Clear Queue Information
|
||||
</Button>
|
||||
</Box>
|
||||
</Box>
|
||||
</Box>
|
||||
</>
|
||||
);
|
||||
};
|
318
task1/project/003_src/client/pages/PatientRegister/index.js
Normal file
318
task1/project/003_src/client/pages/PatientRegister/index.js
Normal file
@@ -0,0 +1,318 @@
|
||||
import React, { useEffect } from 'react';
|
||||
|
||||
import MailIcon from '@mui/icons-material/Mail';
|
||||
import InboxIcon from '@mui/icons-material/MoveToInbox';
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
Checkbox,
|
||||
Divider,
|
||||
Drawer,
|
||||
FormControlLabel,
|
||||
FormGroup,
|
||||
List,
|
||||
ListItem,
|
||||
ListItemButton,
|
||||
ListItemIcon,
|
||||
ListItemText,
|
||||
TextField,
|
||||
} from '@mui/material';
|
||||
import Head from 'next/head';
|
||||
|
||||
import { ChevronLeftOutlined } from '@mui/icons-material';
|
||||
import Loading from 'components/Loading';
|
||||
import { useFormik } from 'formik';
|
||||
import { useRouter } from 'next/dist/client/router';
|
||||
import * as yup from 'yup';
|
||||
|
||||
const validationSchema = yup.object({
|
||||
patient_name: yup
|
||||
.string('Enter your name')
|
||||
.min(2, 'Name should be of minimum 2 characters length')
|
||||
.required('Name is required'),
|
||||
patient_hkid: yup
|
||||
.string('Enter your HKID')
|
||||
.matches(/^[A-Z]{1,2}[0-9]{6}\([0-9]\)$/, 'HKID should be in format of XX123456(1-9)')
|
||||
.required('HKID is required'),
|
||||
patient_age: yup
|
||||
.number('Enter your age')
|
||||
.min(1, 'Age should be greater than 0')
|
||||
.max(90, 'Age should be less than 90')
|
||||
.required('Age is required'),
|
||||
patient_mobile: yup
|
||||
.string('Enter your mobile number')
|
||||
.matches(/^[0-9]{8}$/, 'Mobile number should be 8 numbers')
|
||||
.required('Mobile number is required'),
|
||||
});
|
||||
|
||||
export default () => {
|
||||
const [open, setOpen] = React.useState(false);
|
||||
const [loading, setLoading] = React.useState(true);
|
||||
const [one_symptoms_selected, setOneSymptomsSelected] = React.useState(false);
|
||||
const router = useRouter();
|
||||
|
||||
const toggleDrawer = newOpen => () => {
|
||||
setOpen(newOpen);
|
||||
};
|
||||
|
||||
const formik = useFormik({
|
||||
initialValues: {
|
||||
patient_name: '',
|
||||
patient_hkid: '',
|
||||
patient_age: 0,
|
||||
patient_mobile: '',
|
||||
bruisesScratchesMinorBurns: false,
|
||||
chestPain: false,
|
||||
headache: false,
|
||||
myMuiCheck: false,
|
||||
nauseaAndVomiting: false,
|
||||
runnyOrStuffyNose: true,
|
||||
soreThroat: false,
|
||||
},
|
||||
validationSchema,
|
||||
onSubmit: values => {
|
||||
// alert(JSON.stringify(values, null, 2));
|
||||
fetch('/api/patient_queue/register', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ values }),
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
if (data.queue) {
|
||||
alert(`registered successfully, will assign you to ${data.queue} queue`);
|
||||
} else {
|
||||
alert(`registered successfully`);
|
||||
}
|
||||
localStorage.setItem('queue_type', data.queue);
|
||||
localStorage.setItem('queue_id', data.result.id);
|
||||
localStorage.setItem('queue_name', data.result.name);
|
||||
localStorage.setItem('queue_hkid', data.result.hkid);
|
||||
localStorage.setItem('queue_mobile', data.result.mobile);
|
||||
localStorage.setItem('queue_description', data.result.description);
|
||||
|
||||
router.push('/PatientQueueDisplay');
|
||||
} else {
|
||||
// alert(data.message);
|
||||
alert('sorry there are something wrong, please try again');
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
console.error(err);
|
||||
alert('server error');
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
setOneSymptomsSelected(
|
||||
!(
|
||||
formik.values.bruisesScratchesMinorBurns ||
|
||||
formik.values.chestPain ||
|
||||
formik.values.headache ||
|
||||
formik.values.myMuiCheck ||
|
||||
formik.values.nauseaAndVomiting ||
|
||||
formik.values.runnyOrStuffyNose ||
|
||||
formik.values.soreThroat
|
||||
),
|
||||
);
|
||||
}, [formik.values]);
|
||||
|
||||
const DrawerList = (
|
||||
<Box sx={{ width: 250 }} role='presentation' onClick={toggleDrawer(false)}>
|
||||
<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>
|
||||
</Box>
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (localStorage.getItem('queue_id')) {
|
||||
router.push('/PatientQueueDisplay');
|
||||
} else {
|
||||
setLoading(false);
|
||||
}
|
||||
}, []);
|
||||
|
||||
if (loading) {
|
||||
return <Loading />;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
<title>dashboard - non-urgent case</title>
|
||||
<meta name='description' content='Generated by create next app' />
|
||||
<link rel='icon' href='/favicon.ico' />
|
||||
</Head>
|
||||
|
||||
<Box
|
||||
sx={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
minHeight: '90vh',
|
||||
}}
|
||||
>
|
||||
<form onSubmit={formik.handleSubmit}>
|
||||
<Box sx={{ marginLeft: '2rem', marginRight: '2rem' }}>
|
||||
<Box
|
||||
sx={{
|
||||
fontWeight: 'bold',
|
||||
fontSize: '1.1rem',
|
||||
marginTop: '1rem',
|
||||
marginBottom: '1rem',
|
||||
}}
|
||||
>
|
||||
Electronic Diagnosis Registration
|
||||
</Box>
|
||||
<TextField
|
||||
fullWidth
|
||||
variant='standard'
|
||||
id='patient_name'
|
||||
name='patient_name'
|
||||
label='Patient name'
|
||||
value={formik.values.patient_name}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
error={formik.touched.patient_name && Boolean(formik.errors.patient_name)}
|
||||
helperText={formik.touched.patient_name && formik.errors.patient_name}
|
||||
/>
|
||||
<TextField
|
||||
fullWidth
|
||||
variant='standard'
|
||||
id='patient_hkid'
|
||||
name='patient_hkid'
|
||||
label='HKID'
|
||||
value={formik.values.patient_hkid}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
error={formik.touched.patient_hkid && Boolean(formik.errors.patient_hkid)}
|
||||
helperText={formik.touched.patient_hkid && formik.errors.patient_hkid}
|
||||
/>
|
||||
<TextField
|
||||
fullWidth
|
||||
variant='standard'
|
||||
id='patient_age'
|
||||
name='patient_age'
|
||||
label='Age'
|
||||
value={formik.values.patient_age}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
error={formik.touched.patient_age && Boolean(formik.errors.patient_age)}
|
||||
helperText={formik.touched.patient_age && formik.errors.patient_age}
|
||||
/>
|
||||
<TextField
|
||||
fullWidth
|
||||
variant='standard'
|
||||
id='patient_mobile'
|
||||
name='patient_mobile'
|
||||
label='Mobile'
|
||||
value={formik.values.patient_mobile}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
error={formik.touched.patient_mobile && Boolean(formik.errors.patient_mobile)}
|
||||
helperText={formik.touched.patient_mobile && formik.errors.patient_mobile}
|
||||
/>
|
||||
|
||||
<Box sx={{ marginTop: '2rem' }}>
|
||||
<FormGroup>
|
||||
<Box sx={{ marginTop: '1rem', marginBottom: '1rem' }}>Reason for seeking medical advice</Box>
|
||||
{formik.dirty && one_symptoms_selected ? (
|
||||
<Box sx={{ color: 'red', fontSize: '0.8rem', fontWeight: 'bold' }}>
|
||||
Please select at least one symptom
|
||||
</Box>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
|
||||
<FormControlLabel
|
||||
control={<Checkbox />}
|
||||
label='Runny or stuffy nose'
|
||||
checked={formik.values.runnyOrStuffyNose}
|
||||
onChange={() => formik.setFieldValue('runnyOrStuffyNose', !formik.values.runnyOrStuffyNose)}
|
||||
/>
|
||||
<FormControlLabel
|
||||
control={<Checkbox />}
|
||||
label='sore throat'
|
||||
checked={formik.values.soreThroat}
|
||||
onChange={() => formik.setFieldValue('soreThroat', !formik.values.soreThroat)}
|
||||
/>
|
||||
|
||||
<FormControlLabel
|
||||
control={<Checkbox />}
|
||||
label='nausea and vomiting'
|
||||
checked={formik.values.nauseaAndVomiting}
|
||||
onChange={() => formik.setFieldValue('nauseaAndVomiting', !formik.values.nauseaAndVomiting)}
|
||||
/>
|
||||
<FormControlLabel
|
||||
control={<Checkbox />}
|
||||
label='Headache (Semi-urgent)'
|
||||
checked={formik.values.headache}
|
||||
onChange={() => formik.setFieldValue('headache', !formik.values.headache)}
|
||||
/>
|
||||
<FormControlLabel
|
||||
control={<Checkbox />}
|
||||
label='chest pain (Semi-urgent)'
|
||||
checked={formik.values.chestPain}
|
||||
onChange={() => formik.setFieldValue('chestPain', !formik.values.chestPain)}
|
||||
/>
|
||||
<FormControlLabel
|
||||
control={<Checkbox />}
|
||||
label='Bruises, scratches, minor burns (Semi-urgent)'
|
||||
checked={formik.values.bruisesScratchesMinorBurns}
|
||||
onChange={() =>
|
||||
formik.setFieldValue('bruisesScratchesMinorBurns', !formik.values.bruisesScratchesMinorBurns)
|
||||
}
|
||||
/>
|
||||
</FormGroup>
|
||||
</Box>
|
||||
<Box sx={{ marginTop: '1rem', display: 'flex', justifyContent: 'space-around' }}>
|
||||
<Button
|
||||
disabled={formik.isSubmitting}
|
||||
onClick={() => router.push('/')}
|
||||
variant='outline'
|
||||
startIcon={<ChevronLeftOutlined />}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
{/* */}
|
||||
<Button
|
||||
color='primary'
|
||||
variant='contained'
|
||||
type='submit'
|
||||
disabled={!(formik.isValid && formik.dirty && !formik.isSubmitting)}
|
||||
>
|
||||
Submit
|
||||
</Button>
|
||||
</Box>
|
||||
</Box>
|
||||
</form>
|
||||
</Box>
|
||||
|
||||
<Drawer open={open} onClose={toggleDrawer(false)}>
|
||||
{DrawerList}
|
||||
</Drawer>
|
||||
</>
|
||||
);
|
||||
};
|
@@ -0,0 +1,21 @@
|
||||
import { Box } from '@mui/material';
|
||||
|
||||
export default () => (
|
||||
<Box
|
||||
sx={{
|
||||
width: '100%',
|
||||
height: '30vh',
|
||||
//
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
gap: '3rem',
|
||||
//
|
||||
fontWeight: 'bold',
|
||||
fontSize: '1.2rem',
|
||||
}}
|
||||
>
|
||||
<Box>No result found</Box>
|
||||
</Box>
|
||||
);
|
@@ -0,0 +1,21 @@
|
||||
import { Box } from '@mui/material';
|
||||
|
||||
export default () => (
|
||||
<Box
|
||||
sx={{
|
||||
width: '100%',
|
||||
height: '30vh',
|
||||
//
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
gap: '3rem',
|
||||
//
|
||||
fontWeight: 'bold',
|
||||
fontSize: '1.2rem',
|
||||
}}
|
||||
>
|
||||
<Box>Press Search to start</Box>
|
||||
</Box>
|
||||
);
|
256
task1/project/003_src/client/pages/SearchCase/index.js
Normal file
256
task1/project/003_src/client/pages/SearchCase/index.js
Normal file
@@ -0,0 +1,256 @@
|
||||
import MenuIcon from '@mui/icons-material/Menu';
|
||||
import React, { useState } from 'react';
|
||||
|
||||
import { ChevronLeftOutlined } from '@mui/icons-material';
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
Checkbox,
|
||||
Drawer,
|
||||
FormControlLabel,
|
||||
IconButton,
|
||||
List,
|
||||
ListItem,
|
||||
ListItemButton,
|
||||
ListItemIcon,
|
||||
ListItemText,
|
||||
TextField,
|
||||
} from '@mui/material';
|
||||
import NonUrgentQueueItemCard from 'components/NonUrgentQueueItemCard';
|
||||
import SemiUrgentQueueItemCard from 'components/SemiUrgentQueueItemCard';
|
||||
import { useFormik } from 'formik';
|
||||
import { useRouter } from 'next/dist/client/router';
|
||||
import Head from 'next/head';
|
||||
import * as yup from 'yup';
|
||||
import NoResultFound from './NoResultFound';
|
||||
import PressSearchToStart from './PressSearchToStart';
|
||||
|
||||
const default_init_values = {
|
||||
semi_urgent_case: true,
|
||||
non_urgent_case: true,
|
||||
hkid: '',
|
||||
mobile: '',
|
||||
};
|
||||
|
||||
const validationSchema = yup.object({});
|
||||
|
||||
const search_input_row_sx = {
|
||||
width: '100%',
|
||||
padding: '1rem',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
justifyContent: 'flex-start',
|
||||
gap: '0.25rem',
|
||||
fontWeight: 'bold',
|
||||
};
|
||||
|
||||
const row_button_sx = {
|
||||
width: '100%',
|
||||
padding: '1rem',
|
||||
display: 'flex',
|
||||
justifyContent: 'space-around',
|
||||
gap: '0.5rem',
|
||||
};
|
||||
|
||||
export default () => {
|
||||
const [open, setOpen] = React.useState(false);
|
||||
const [p_queue, setPQueue] = React.useState([]);
|
||||
const router = useRouter();
|
||||
const [not_search_yet, setNotSearchYet] = React.useState(true);
|
||||
const [changing_page, setChangingPage] = useState(false);
|
||||
|
||||
const toggleDrawer = newOpen => () => {
|
||||
setOpen(newOpen);
|
||||
};
|
||||
|
||||
const formik = useFormik({
|
||||
initialValues: default_init_values,
|
||||
validationSchema,
|
||||
onSubmit: values => {
|
||||
setNotSearchYet(false);
|
||||
|
||||
fetch('/api/patient_queue/search', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(values),
|
||||
})
|
||||
.then(res => res.json())
|
||||
.then(data => {
|
||||
setPQueue(data.patient_queues);
|
||||
formik.setSubmitting(false);
|
||||
})
|
||||
.catch(err => {
|
||||
console.error(err);
|
||||
alert('server error');
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
const DrawerList = (
|
||||
<Box sx={{ width: 250 }} role='presentation' onClick={toggleDrawer(false)}>
|
||||
<List>
|
||||
<ListItem key='dashboard' disablePadding>
|
||||
<ListItemButton
|
||||
disabled={changing_page}
|
||||
onClick={() => {
|
||||
setChangingPage(true);
|
||||
router.push('/AdminHome');
|
||||
}}
|
||||
>
|
||||
<ListItemIcon>
|
||||
<ChevronLeftOutlined />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary='back to dashboard' />
|
||||
</ListItemButton>
|
||||
</ListItem>
|
||||
</List>
|
||||
</Box>
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
<title>dashboard - non-urgent case</title>
|
||||
<meta name='description' content='Generated by create next app' />
|
||||
<link rel='icon' href='/favicon.ico' />
|
||||
</Head>
|
||||
|
||||
<Box className='main'>
|
||||
<Box
|
||||
sx={{
|
||||
//
|
||||
display: 'flex',
|
||||
flexDirection: 'flex-start',
|
||||
alignItems: 'center',
|
||||
gap: '1rem',
|
||||
//
|
||||
height: '3rem',
|
||||
}}
|
||||
>
|
||||
<IconButton aria-label='menu' onClick={toggleDrawer(true)}>
|
||||
<MenuIcon />
|
||||
</IconButton>
|
||||
<Box sx={{ fontWeight: 'bold', fontSize: '1.2rem' }}>Search case</Box>
|
||||
</Box>
|
||||
|
||||
<Box>
|
||||
<form onSubmit={formik.handleSubmit}>
|
||||
<Box sx={search_input_row_sx}>
|
||||
<Box>Search by case type:</Box>
|
||||
<FormControlLabel
|
||||
control={<Checkbox sx={{ padding: '0.25rem 1rem' }} size='small' />}
|
||||
label='semi-urgent case'
|
||||
checked={formik.values.semi_urgent_case}
|
||||
onChange={() => formik.setFieldValue('semi_urgent_case', !formik.values.semi_urgent_case)}
|
||||
/>
|
||||
<FormControlLabel
|
||||
control={<Checkbox sx={{ padding: '0.25rem 1rem' }} size='small' />}
|
||||
label='non-urgent case'
|
||||
checked={formik.values.non_urgent_case}
|
||||
onChange={() => formik.setFieldValue('non_urgent_case', !formik.values.non_urgent_case)}
|
||||
/>
|
||||
</Box>
|
||||
<Box sx={search_input_row_sx}>
|
||||
<TextField
|
||||
fullWidth
|
||||
variant='standard'
|
||||
id='hkid'
|
||||
name='hkid'
|
||||
label='Search by HKID: Please input HKID'
|
||||
size='small'
|
||||
value={formik.values.hkid}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
error={formik.touched.hkid && Boolean(formik.errors.hkid)}
|
||||
helperText={formik.touched.hkid && formik.errors.hkid}
|
||||
/>
|
||||
</Box>
|
||||
|
||||
<Box sx={search_input_row_sx}>
|
||||
<TextField
|
||||
fullWidth
|
||||
variant='standard'
|
||||
id='mobile'
|
||||
name='mobile'
|
||||
label='Search by Mobile: Please input no.'
|
||||
size='small'
|
||||
value={formik.values.mobile}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
error={formik.touched.mobile && Boolean(formik.errors.mobile)}
|
||||
helperText={formik.touched.mobile && formik.errors.mobile}
|
||||
/>
|
||||
</Box>
|
||||
|
||||
<Box sx={row_button_sx}>
|
||||
<Button
|
||||
disabled={!formik.dirty || formik.isSubmitting}
|
||||
fullWidth
|
||||
variant='outlined'
|
||||
onClick={() => {
|
||||
setNotSearchYet(true);
|
||||
setPQueue([]);
|
||||
formik.resetForm();
|
||||
}}
|
||||
>
|
||||
Reset
|
||||
</Button>
|
||||
<Button
|
||||
// disabled={!(formik.isValid && formik.dirty && !formik.isSubmitting) || changing_page}
|
||||
fullWidth
|
||||
variant='contained'
|
||||
color='primary'
|
||||
type='submit'
|
||||
disabled={!(formik.isValid && formik.dirty && !formik.isSubmitting)}
|
||||
>
|
||||
Search
|
||||
</Button>
|
||||
</Box>
|
||||
</form>
|
||||
</Box>
|
||||
|
||||
<Box style={{ overflowY: 'scroll' }}>
|
||||
{not_search_yet ? (
|
||||
<PressSearchToStart />
|
||||
) : (
|
||||
<>
|
||||
{p_queue.length === 0 ? (
|
||||
<NoResultFound />
|
||||
) : (
|
||||
<>
|
||||
{p_queue.map(queue_data => {
|
||||
if (queue_data.queue_type === 'non-urgent')
|
||||
return (
|
||||
<NonUrgentQueueItemCard key={queue_data} queue_data={queue_data} show_edit_delete={false} />
|
||||
);
|
||||
if (queue_data.queue_type === 'semi-urgent')
|
||||
return (
|
||||
<SemiUrgentQueueItemCard key={queue_data} queue_data={queue_data} show_edit_delete={false} />
|
||||
);
|
||||
|
||||
return <></>;
|
||||
})}
|
||||
<Box
|
||||
style={{
|
||||
width: '100%',
|
||||
display: 'inline-flex',
|
||||
justifyContent: 'center',
|
||||
marginTop: '1rem',
|
||||
marginBottom: '1rem',
|
||||
}}
|
||||
>
|
||||
--end of list--
|
||||
</Box>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
<Drawer open={open} onClose={toggleDrawer(false)}>
|
||||
{DrawerList}
|
||||
</Drawer>
|
||||
</>
|
||||
);
|
||||
};
|
246
task1/project/003_src/client/pages/SemiUrgentCaseEdit/[id].js
Normal file
246
task1/project/003_src/client/pages/SemiUrgentCaseEdit/[id].js
Normal file
@@ -0,0 +1,246 @@
|
||||
import React, { useEffect } from 'react';
|
||||
|
||||
import { Box, Button, TextField } from '@mui/material';
|
||||
import Head from 'next/head';
|
||||
|
||||
import { ChevronLeftOutlined } from '@mui/icons-material';
|
||||
import Loading from 'components/Loading';
|
||||
import { useFormik } from 'formik';
|
||||
import { useRouter } from 'next/dist/client/router';
|
||||
import * as yup from 'yup';
|
||||
|
||||
const validationSchema = yup.object({
|
||||
patient_name: yup
|
||||
.string('Enter your name')
|
||||
.min(2, 'Name should be of minimum 2 characters length')
|
||||
.required('Name is required'),
|
||||
patient_hkid: yup
|
||||
.string('Enter your HKID')
|
||||
.matches(/^[A-Z]{1,2}[0-9]{6}\([0-9]\)$/, 'HKID should be in format of XX123456(1-9)')
|
||||
.required('HKID is required'),
|
||||
patient_age: yup
|
||||
.number('Enter your age')
|
||||
.min(1, 'Age should be greater than 0')
|
||||
.max(90, 'Age should be less than 90')
|
||||
.required('Age is required'),
|
||||
patient_mobile: yup
|
||||
.string('Enter your mobile number')
|
||||
.matches(/^[0-9]{8}$/, 'Mobile number should be 8 numbers')
|
||||
.required('Mobile number is required'),
|
||||
});
|
||||
|
||||
export default () => {
|
||||
const router = useRouter();
|
||||
const { id } = router.query;
|
||||
const [changing_page, setChangingPage] = React.useState(false);
|
||||
|
||||
const [loading, setLoading] = React.useState(true);
|
||||
|
||||
const formik = useFormik({
|
||||
enableReinitialize: true,
|
||||
initialValues: {
|
||||
patient_name: '',
|
||||
patient_hkid: '',
|
||||
patient_age: 0,
|
||||
patient_mobile: '',
|
||||
//
|
||||
bruisesScratchesMinorBurns: false,
|
||||
chestPain: false,
|
||||
headache: false,
|
||||
myMuiCheck: false,
|
||||
nauseaAndVomiting: false,
|
||||
runnyOrStuffyNose: false,
|
||||
soreThroat: false,
|
||||
},
|
||||
validationSchema,
|
||||
onSubmit: values => {
|
||||
fetch('/api/patient_queue/update_queue_item', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ id, queue_type: 'semi-urgent', values }),
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.status) {
|
||||
alert('saved !');
|
||||
router.reload();
|
||||
} else {
|
||||
// alert(data.message);
|
||||
alert('sorry there are something wrong, please try again');
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
console.error(err);
|
||||
alert('server error');
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
console.log({ t: `/api/patient_queue/read_queue_item?queue_type=semi-urgent&id=${id}` });
|
||||
if (id) {
|
||||
fetch(`/api/patient_queue/read_queue_item?queue_type=semi-urgent&id=${id}`, {
|
||||
method: 'GET',
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.status) {
|
||||
console.log(data);
|
||||
|
||||
const {
|
||||
name,
|
||||
hkid,
|
||||
mobile,
|
||||
age,
|
||||
bruisesScratchesMinorBurns,
|
||||
chestPain,
|
||||
headache,
|
||||
myMuiCheck,
|
||||
nauseaAndVomiting,
|
||||
runnyOrStuffyNose,
|
||||
soreThroat,
|
||||
} = data.queueItem;
|
||||
|
||||
formik.setValues({
|
||||
patient_name: name,
|
||||
patient_hkid: hkid,
|
||||
patient_mobile: mobile,
|
||||
patient_age: age,
|
||||
bruisesScratchesMinorBurns,
|
||||
chestPain,
|
||||
headache,
|
||||
myMuiCheck,
|
||||
nauseaAndVomiting,
|
||||
runnyOrStuffyNose,
|
||||
soreThroat,
|
||||
});
|
||||
} else {
|
||||
alert(data.message);
|
||||
}
|
||||
|
||||
setLoading(false);
|
||||
})
|
||||
.catch(err => {
|
||||
console.error(err);
|
||||
alert('server error');
|
||||
})
|
||||
.finally(() => {
|
||||
setLoading(false);
|
||||
});
|
||||
}
|
||||
}, [id]);
|
||||
|
||||
if (loading) {
|
||||
return <Loading />;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
<title>dashboard - non-urgent case</title>
|
||||
<meta name='description' content='Generated by create next app' />
|
||||
<link rel='icon' href='/favicon.ico' />
|
||||
</Head>
|
||||
|
||||
<Box
|
||||
sx={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
minHeight: '90vh',
|
||||
}}
|
||||
>
|
||||
<form onSubmit={formik.handleSubmit}>
|
||||
<Box sx={{ marginLeft: '2rem', marginRight: '2rem' }}>
|
||||
<Box
|
||||
sx={{
|
||||
fontWeight: 'bold',
|
||||
fontSize: '1.1rem',
|
||||
marginTop: '1rem',
|
||||
marginBottom: '1rem',
|
||||
}}
|
||||
>
|
||||
Edit Registration
|
||||
</Box>
|
||||
<TextField
|
||||
fullWidth
|
||||
disabled={changing_page || formik.isSubmitting}
|
||||
variant='standard'
|
||||
id='patient_name'
|
||||
name='patient_name'
|
||||
label='Patient name'
|
||||
value={formik.values.patient_name}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
error={formik.touched.patient_name && Boolean(formik.errors.patient_name)}
|
||||
helperText={formik.touched.patient_name && formik.errors.patient_name}
|
||||
/>
|
||||
<TextField
|
||||
fullWidth
|
||||
disabled={changing_page || formik.isSubmitting}
|
||||
variant='standard'
|
||||
id='patient_hkid'
|
||||
name='patient_hkid'
|
||||
label='HKID'
|
||||
value={formik.values.patient_hkid}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
error={formik.touched.patient_hkid && Boolean(formik.errors.patient_hkid)}
|
||||
helperText={formik.touched.patient_hkid && formik.errors.patient_hkid}
|
||||
/>
|
||||
<TextField
|
||||
fullWidth
|
||||
disabled={changing_page || formik.isSubmitting}
|
||||
variant='standard'
|
||||
id='patient_age'
|
||||
name='patient_age'
|
||||
label='Age'
|
||||
value={formik.values.patient_age}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
error={formik.touched.patient_age && Boolean(formik.errors.patient_age)}
|
||||
helperText={formik.touched.patient_age && formik.errors.patient_age}
|
||||
/>
|
||||
<TextField
|
||||
fullWidth
|
||||
disabled={changing_page || formik.isSubmitting}
|
||||
variant='standard'
|
||||
id='patient_mobile'
|
||||
name='patient_mobile'
|
||||
label='Mobile'
|
||||
value={formik.values.patient_mobile}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
error={formik.touched.patient_mobile && Boolean(formik.errors.patient_mobile)}
|
||||
helperText={formik.touched.patient_mobile && formik.errors.patient_mobile}
|
||||
/>
|
||||
|
||||
<Box sx={{ marginTop: '1rem', display: 'flex', justifyContent: 'space-around' }}>
|
||||
<Button
|
||||
disabled={changing_page || formik.isSubmitting}
|
||||
onClick={() => {
|
||||
setChangingPage(true);
|
||||
router.push('/SemiUrgentCaseList');
|
||||
}}
|
||||
variant='outline'
|
||||
startIcon={<ChevronLeftOutlined />}
|
||||
>
|
||||
Back
|
||||
</Button>
|
||||
{/* */}
|
||||
<Button
|
||||
color='primary'
|
||||
variant='contained'
|
||||
type='submit'
|
||||
disabled={!(formik.isValid && formik.dirty && !formik.isSubmitting) || changing_page}
|
||||
>
|
||||
Save
|
||||
</Button>
|
||||
</Box>
|
||||
</Box>
|
||||
</form>
|
||||
</Box>
|
||||
</>
|
||||
);
|
||||
};
|
@@ -0,0 +1,40 @@
|
||||
import { ChevronLeftOutlined } from '@mui/icons-material';
|
||||
import { Box, Button } from '@mui/material';
|
||||
import { useRouter } from 'next/dist/client/router';
|
||||
import { useState } from 'react';
|
||||
|
||||
export default () => {
|
||||
const [changing_page, setChangingPage] = useState(false);
|
||||
const router = useRouter();
|
||||
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
width: '100%',
|
||||
height: '90vh',
|
||||
//
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
gap: '3rem',
|
||||
//
|
||||
fontWeight: 'bold',
|
||||
fontSize: '1.2rem',
|
||||
}}
|
||||
>
|
||||
<Box>Queue is empty</Box>
|
||||
<Button
|
||||
onClick={() => {
|
||||
setChangingPage(true);
|
||||
router.push('/AdminHome');
|
||||
}}
|
||||
startIcon={<ChevronLeftOutlined />}
|
||||
variant='outlined'
|
||||
disabled={changing_page}
|
||||
>
|
||||
Back
|
||||
</Button>
|
||||
</Box>
|
||||
);
|
||||
};
|
112
task1/project/003_src/client/pages/SemiUrgentCaseList/index.js
Normal file
112
task1/project/003_src/client/pages/SemiUrgentCaseList/index.js
Normal file
@@ -0,0 +1,112 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
|
||||
import { ChevronLeftOutlined } from '@mui/icons-material';
|
||||
import MenuIcon from '@mui/icons-material/Menu';
|
||||
import { Box, Drawer, IconButton, List, ListItem, ListItemButton, ListItemIcon, ListItemText } from '@mui/material';
|
||||
import Loading from 'components/Loading';
|
||||
import SemiUrgentQueueItemCard from 'components/SemiUrgentQueueItemCard';
|
||||
import { useRouter } from 'next/dist/client/router';
|
||||
import Head from 'next/head';
|
||||
import QueueIsEmpty from './QueueIsEmpty';
|
||||
|
||||
export default () => {
|
||||
const [open, setOpen] = React.useState(false);
|
||||
const [p_queue, setPQueue] = React.useState([]);
|
||||
const router = useRouter();
|
||||
const [loading, setLoading] = React.useState(true);
|
||||
const [changing_page, setChangingPage] = useState(false);
|
||||
|
||||
const toggleDrawer = newOpen => () => {
|
||||
setOpen(newOpen);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
fetch('/api/patient_queue/semi_urgent_case')
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
setPQueue(data.patient_queues);
|
||||
setLoading(false);
|
||||
});
|
||||
}, []);
|
||||
|
||||
const DrawerList = (
|
||||
<Box sx={{ width: 250 }} role='presentation' onClick={toggleDrawer(false)}>
|
||||
<List>
|
||||
<ListItem key='dashboard' disablePadding>
|
||||
<ListItemButton
|
||||
disabled={changing_page}
|
||||
onClick={() => {
|
||||
setChangingPage(true);
|
||||
router.push('/AdminHome');
|
||||
}}
|
||||
>
|
||||
<ListItemIcon>
|
||||
<ChevronLeftOutlined />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary='back to dashboard' />
|
||||
</ListItemButton>
|
||||
</ListItem>
|
||||
</List>
|
||||
</Box>
|
||||
);
|
||||
|
||||
if (loading) {
|
||||
return <Loading />;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
<title>dashboard - semi-urgent case</title>
|
||||
<meta name='description' content='Generated by create next app' />
|
||||
<link rel='icon' href='/favicon.ico' />
|
||||
</Head>
|
||||
|
||||
<Box className='main'>
|
||||
<Box
|
||||
sx={{
|
||||
//
|
||||
display: 'flex',
|
||||
flexDirection: 'flex-start',
|
||||
alignItems: 'center',
|
||||
gap: '1rem',
|
||||
//
|
||||
height: '3rem',
|
||||
}}
|
||||
>
|
||||
<IconButton aria-label='menu' onClick={toggleDrawer(true)}>
|
||||
<MenuIcon />
|
||||
</IconButton>
|
||||
<Box sx={{ fontWeight: 'bold', fontSize: '1.2rem' }}>All Semi-Urgent Cases</Box>
|
||||
</Box>
|
||||
|
||||
<Box style={{ height: '95vh', overflowY: 'scroll' }}>
|
||||
{p_queue.length === 0 ? (
|
||||
<QueueIsEmpty />
|
||||
) : (
|
||||
<>
|
||||
{p_queue.map(queue_data => (
|
||||
<SemiUrgentQueueItemCard key={queue_data} queue_data={queue_data} />
|
||||
))}
|
||||
<Box
|
||||
style={{
|
||||
width: '100%',
|
||||
display: 'inline-flex',
|
||||
justifyContent: 'center',
|
||||
marginTop: '1rem',
|
||||
marginBottom: '1rem',
|
||||
}}
|
||||
>
|
||||
--end of list--
|
||||
</Box>
|
||||
</>
|
||||
)}
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
<Drawer open={open} onClose={toggleDrawer(false)}>
|
||||
{DrawerList}
|
||||
</Drawer>
|
||||
</>
|
||||
);
|
||||
};
|
18
task1/project/003_src/client/pages/_app.js
Normal file
18
task1/project/003_src/client/pages/_app.js
Normal file
@@ -0,0 +1,18 @@
|
||||
import ThemeProvider from '@/config/StyledMaterialThemeProvider';
|
||||
import theme from '@/config/theme';
|
||||
import Head from 'next/head';
|
||||
|
||||
function MyApp({ Component, pageProps }) {
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
<meta name='viewport' content='minimum-scale=1, initial-scale=1, width=device-width, shrink-to-fit=no' />
|
||||
</Head>
|
||||
<ThemeProvider theme={theme}>
|
||||
<Component {...pageProps} />
|
||||
</ThemeProvider>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default MyApp;
|
98
task1/project/003_src/client/pages/_document.js
Normal file
98
task1/project/003_src/client/pages/_document.js
Normal file
@@ -0,0 +1,98 @@
|
||||
import { ServerStyleSheets } from '@mui/styles';
|
||||
import Document, { Head, Html, Main, NextScript } from 'next/document';
|
||||
import { ServerStyleSheet } from 'styled-components';
|
||||
|
||||
import theme from '@/config/theme';
|
||||
|
||||
export default class MyDocument extends Document {
|
||||
componentDidMount() {}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Html lang='en'>
|
||||
<Head>
|
||||
<meta charSet='utf-8' />
|
||||
{/* PWA primary color */}
|
||||
<meta name='theme-color' content={theme.palette.primary.main} />
|
||||
</Head>
|
||||
<style jsx global>
|
||||
{`
|
||||
html,
|
||||
body {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, Ubuntu, Cantarell, Fica Sans,
|
||||
Droid Sans, Helvetica Neue, sans-serif;
|
||||
}
|
||||
|
||||
a {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
`}
|
||||
</style>
|
||||
<body>
|
||||
<Main />
|
||||
<NextScript />
|
||||
</body>
|
||||
</Html>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
MyDocument.getInitialProps = async ctx => {
|
||||
// Resolution order
|
||||
//
|
||||
// On the server:
|
||||
// 1. app.getInitialProps
|
||||
// 2. page.getInitialProps
|
||||
// 3. document.getInitialProps
|
||||
// 4. app.render
|
||||
// 5. page.render
|
||||
// 6. document.render
|
||||
//
|
||||
// On the server with error:
|
||||
// 1. document.getInitialProps
|
||||
// 2. app.render
|
||||
// 3. page.render
|
||||
// 4. document.render
|
||||
//
|
||||
// On the client
|
||||
// 1. app.getInitialProps
|
||||
// 2. page.getInitialProps
|
||||
// 3. app.render
|
||||
// 4. page.render
|
||||
|
||||
// Render app and page and get the context of the page with collected side effects.
|
||||
const sheets = new ServerStyleSheets();
|
||||
const sheet = new ServerStyleSheet();
|
||||
const originalRenderPage = ctx.renderPage;
|
||||
|
||||
try {
|
||||
ctx.renderPage = () =>
|
||||
originalRenderPage({
|
||||
enhanceApp: App => props => sheet.collectStyles(sheets.collect(<App {...props} />)),
|
||||
});
|
||||
|
||||
const initialProps = await Document.getInitialProps(ctx);
|
||||
|
||||
return {
|
||||
...initialProps,
|
||||
// Styles fragment is rendered after the app and page rendering finish.
|
||||
styles: (
|
||||
<>
|
||||
{initialProps.styles}
|
||||
{sheets.getStyleElement()}
|
||||
{sheet.getStyleElement()}
|
||||
{/* {flush() || null} */}
|
||||
</>
|
||||
),
|
||||
};
|
||||
} finally {
|
||||
sheet.seal();
|
||||
}
|
||||
};
|
21
task1/project/003_src/client/pages/api/auth/helloworld.js
Normal file
21
task1/project/003_src/client/pages/api/auth/helloworld.js
Normal file
@@ -0,0 +1,21 @@
|
||||
async function helloworld(req) {
|
||||
try {
|
||||
return { status: 'OK' };
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return { status: 'ERROR' };
|
||||
}
|
||||
}
|
||||
|
||||
async function handler(req, res) {
|
||||
try {
|
||||
let result = await helloworld(req);
|
||||
|
||||
return res.status(200).send(result);
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
return res.status(200).send({ status: 'error', message: 'helloworld error' });
|
||||
}
|
||||
}
|
||||
|
||||
export default handler;
|
33
task1/project/003_src/client/pages/api/auth/login.js
Normal file
33
task1/project/003_src/client/pages/api/auth/login.js
Normal file
@@ -0,0 +1,33 @@
|
||||
import Auth from './model';
|
||||
|
||||
async function login(req) {
|
||||
try {
|
||||
console.log({ test: req.body });
|
||||
const { username: incoming_username, password: incoming_password } = req.body;
|
||||
const users = await Auth.findAll();
|
||||
for (let i = 0; i < users.length; i += 1) {
|
||||
const user = users[i];
|
||||
console.log(users);
|
||||
if (user.username === incoming_username && user.password === incoming_password) {
|
||||
return { success: 'login success' };
|
||||
}
|
||||
}
|
||||
|
||||
return { message: 'login failed' };
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return { message: 'login failed' };
|
||||
}
|
||||
}
|
||||
|
||||
async function handler(req, res) {
|
||||
try {
|
||||
const result = await login(req);
|
||||
|
||||
return res.status(200).send(result);
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
return res.status(200).send({ status: 'error', message: 'helloworld error' });
|
||||
}
|
||||
}
|
||||
export default handler;
|
17
task1/project/003_src/client/pages/api/auth/model.js
Normal file
17
task1/project/003_src/client/pages/api/auth/model.js
Normal file
@@ -0,0 +1,17 @@
|
||||
import sequelize_config from 'utils/sequelize_config';
|
||||
|
||||
const { DataTypes } = require('sequelize');
|
||||
|
||||
const Auth = sequelize_config.define(
|
||||
'Auths',
|
||||
{
|
||||
uid: { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true, unique: true },
|
||||
username: { type: DataTypes.STRING, allowNull: false },
|
||||
password: { type: DataTypes.STRING, allowNull: false },
|
||||
session: { type: DataTypes.STRING, allowNull: false, defaultValue: '' },
|
||||
role: { type: DataTypes.STRING, allowNull: false },
|
||||
},
|
||||
{ timestamps: false },
|
||||
);
|
||||
|
||||
export default Auth;
|
20
task1/project/003_src/client/pages/api/helloworld.js
Normal file
20
task1/project/003_src/client/pages/api/helloworld.js
Normal file
@@ -0,0 +1,20 @@
|
||||
async function helloworld(req) {
|
||||
try {
|
||||
return { status: 'OK' };
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
|
||||
async function handler(req, res) {
|
||||
try {
|
||||
let result = await helloworld(req);
|
||||
|
||||
return res.status(200).send(result);
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
res.status(200).send({ status: 'error', message: 'helloworld error' });
|
||||
}
|
||||
}
|
||||
|
||||
export default handler;
|
@@ -0,0 +1,39 @@
|
||||
import { NonUrgentQueue, SemiUrgentQueue } from './model';
|
||||
|
||||
async function deleteQueueById(req, res) {
|
||||
try {
|
||||
const { id } = req.query;
|
||||
const { queue_type } = req.query;
|
||||
|
||||
if (!id || !queue_type) {
|
||||
return res.status(400).send({ status: 'error', message: 'id and queue_type are required' });
|
||||
}
|
||||
|
||||
switch (queue_type) {
|
||||
case 'semi-urgent':
|
||||
await SemiUrgentQueue.destroy({ where: { id } });
|
||||
return { status: 'OK' };
|
||||
case 'non-urgent':
|
||||
await NonUrgentQueue.destroy({ where: { id } });
|
||||
return { status: 'OK' };
|
||||
default:
|
||||
return res.status(400).send({ status: 'error', message: 'invalid queue_type' });
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return { status: 'error' };
|
||||
}
|
||||
}
|
||||
|
||||
async function handler(req, res) {
|
||||
try {
|
||||
const result = await deleteQueueById(req, res);
|
||||
|
||||
return res.status(200).send(result);
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
return res.status(200).send({ status: 'error', message: 'list error' });
|
||||
}
|
||||
}
|
||||
|
||||
export default handler;
|
25
task1/project/003_src/client/pages/api/patient_queue/list.js
Normal file
25
task1/project/003_src/client/pages/api/patient_queue/list.js
Normal file
@@ -0,0 +1,25 @@
|
||||
import { PatientQueue } from './model';
|
||||
|
||||
async function list() {
|
||||
try {
|
||||
const patient_queues = await PatientQueue.findAll();
|
||||
|
||||
return { status: 'OK', patient_queues };
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return { status: 'ERROR' };
|
||||
}
|
||||
}
|
||||
|
||||
async function handler(req, res) {
|
||||
try {
|
||||
const result = await list(req);
|
||||
|
||||
return res.status(200).send(result);
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
return res.status(200).send({ status: 'error', message: 'list error' });
|
||||
}
|
||||
}
|
||||
|
||||
export default handler;
|
@@ -0,0 +1,55 @@
|
||||
const { DataTypes } = require('sequelize');
|
||||
const sequelize_config = require('../../../utils/sequelize_config');
|
||||
|
||||
const PatientQueue = sequelize_config.define(
|
||||
'PatientQueue',
|
||||
{
|
||||
id: { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true, unique: true },
|
||||
description: { type: DataTypes.STRING, allowNull: false },
|
||||
},
|
||||
{ timestamps: false },
|
||||
);
|
||||
|
||||
const SemiUrgentQueue = sequelize_config.define(
|
||||
'SemiUrgentQueue',
|
||||
{
|
||||
id: { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true, unique: true },
|
||||
name: { type: DataTypes.STRING, allowNull: false },
|
||||
hkid: { type: DataTypes.STRING, allowNull: false },
|
||||
mobile: { type: DataTypes.STRING, allowNull: false },
|
||||
age: { type: DataTypes.INTEGER, allowNull: false },
|
||||
description: { type: DataTypes.STRING, allowNull: false },
|
||||
//
|
||||
bruisesScratchesMinorBurns: { type: DataTypes.BOOLEAN, allowNull: false, defaultValue: false },
|
||||
chestPain: { type: DataTypes.BOOLEAN, allowNull: false, defaultValue: false },
|
||||
headache: { type: DataTypes.BOOLEAN, allowNull: false, defaultValue: false },
|
||||
myMuiCheck: { type: DataTypes.BOOLEAN, allowNull: false, defaultValue: false },
|
||||
nauseaAndVomiting: { type: DataTypes.BOOLEAN, allowNull: false, defaultValue: false },
|
||||
runnyOrStuffyNose: { type: DataTypes.BOOLEAN, allowNull: false, defaultValue: false },
|
||||
soreThroat: { type: DataTypes.BOOLEAN, allowNull: false, defaultValue: false },
|
||||
},
|
||||
{ timestamps: false },
|
||||
);
|
||||
|
||||
const NonUrgentQueue = sequelize_config.define(
|
||||
'NonUrgentQueue',
|
||||
{
|
||||
id: { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true, unique: true },
|
||||
name: { type: DataTypes.STRING, allowNull: false },
|
||||
hkid: { type: DataTypes.STRING, allowNull: false },
|
||||
mobile: { type: DataTypes.STRING, allowNull: false },
|
||||
age: { type: DataTypes.INTEGER, allowNull: false },
|
||||
description: { type: DataTypes.STRING, allowNull: false },
|
||||
//
|
||||
bruisesScratchesMinorBurns: { type: DataTypes.BOOLEAN, allowNull: false, defaultValue: false },
|
||||
chestPain: { type: DataTypes.BOOLEAN, allowNull: false, defaultValue: false },
|
||||
headache: { type: DataTypes.BOOLEAN, allowNull: false, defaultValue: false },
|
||||
myMuiCheck: { type: DataTypes.BOOLEAN, allowNull: false, defaultValue: false },
|
||||
nauseaAndVomiting: { type: DataTypes.BOOLEAN, allowNull: false, defaultValue: false },
|
||||
runnyOrStuffyNose: { type: DataTypes.BOOLEAN, allowNull: false, defaultValue: false },
|
||||
soreThroat: { type: DataTypes.BOOLEAN, allowNull: false, defaultValue: false },
|
||||
},
|
||||
{ timestamps: false },
|
||||
);
|
||||
|
||||
export { NonUrgentQueue, PatientQueue, SemiUrgentQueue };
|
@@ -0,0 +1,24 @@
|
||||
import { NonUrgentQueue } from './model';
|
||||
|
||||
async function list() {
|
||||
try {
|
||||
const patient_queues = await NonUrgentQueue.findAll();
|
||||
|
||||
return { status: 'OK', patient_queues };
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
|
||||
async function handler(req, res) {
|
||||
try {
|
||||
const result = await list(req);
|
||||
|
||||
return res.status(200).send(result);
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
return res.status(200).send({ status: 'error', message: 'list error' });
|
||||
}
|
||||
}
|
||||
|
||||
export default handler;
|
@@ -0,0 +1,46 @@
|
||||
import { NonUrgentQueue, SemiUrgentQueue } from './model';
|
||||
|
||||
async function readQueueById(req, res) {
|
||||
try {
|
||||
const { id } = req.query;
|
||||
const { queue_type } = req.query;
|
||||
|
||||
if (!id || !queue_type) {
|
||||
return res.status(400).send({ status: 'error', message: 'id and queue_type are required' });
|
||||
}
|
||||
|
||||
let queueItem;
|
||||
switch (queue_type) {
|
||||
case 'semi-urgent':
|
||||
queueItem = await SemiUrgentQueue.findOne({ where: { id } });
|
||||
break;
|
||||
case 'non-urgent':
|
||||
queueItem = await NonUrgentQueue.findOne({ where: { id } });
|
||||
break;
|
||||
default:
|
||||
return res.status(400).send({ status: 'error', message: 'invalid queue_type' });
|
||||
}
|
||||
|
||||
if (!queueItem) {
|
||||
return res.status(404).send({ status: 'error', message: 'No queue item found' });
|
||||
}
|
||||
|
||||
return { status: 'OK', queueItem };
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return { status: 'error' };
|
||||
}
|
||||
}
|
||||
|
||||
async function handler(req, res) {
|
||||
try {
|
||||
const result = await readQueueById(req);
|
||||
|
||||
return res.status(200).send(result);
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
return res.status(200).send({ status: 'error', message: 'list error' });
|
||||
}
|
||||
}
|
||||
|
||||
export default handler;
|
@@ -0,0 +1,77 @@
|
||||
import { NonUrgentQueue, SemiUrgentQueue } from './model';
|
||||
|
||||
async function list(req) {
|
||||
let output = {};
|
||||
|
||||
const {
|
||||
patient_name: name,
|
||||
patient_hkid: hkid,
|
||||
patient_age: age,
|
||||
patient_mobile: mobile,
|
||||
//
|
||||
bruisesScratchesMinorBurns,
|
||||
chestPain,
|
||||
headache,
|
||||
myMuiCheck,
|
||||
nauseaAndVomiting,
|
||||
runnyOrStuffyNose,
|
||||
soreThroat,
|
||||
} = req.body.values;
|
||||
|
||||
try {
|
||||
if (headache || chestPain || bruisesScratchesMinorBurns) {
|
||||
console.log('headache || chestPain || bruisesScratchesMinorBurns, classified to a SemiUrgentQueue');
|
||||
const result = await SemiUrgentQueue.create({
|
||||
name,
|
||||
hkid,
|
||||
mobile,
|
||||
age,
|
||||
description: '',
|
||||
bruisesScratchesMinorBurns,
|
||||
chestPain,
|
||||
headache,
|
||||
myMuiCheck,
|
||||
nauseaAndVomiting,
|
||||
runnyOrStuffyNose,
|
||||
soreThroat,
|
||||
});
|
||||
|
||||
output = { success: 'OK', queue: 'semi-urgent', result };
|
||||
} else {
|
||||
console.log('headache == false, classified to a NonUrgentQueue');
|
||||
const result = await NonUrgentQueue.create({
|
||||
name,
|
||||
hkid,
|
||||
mobile,
|
||||
age,
|
||||
description: '',
|
||||
bruisesScratchesMinorBurns,
|
||||
chestPain,
|
||||
headache,
|
||||
myMuiCheck,
|
||||
nauseaAndVomiting,
|
||||
runnyOrStuffyNose,
|
||||
soreThroat,
|
||||
});
|
||||
|
||||
output = { success: 'OK', queue: 'non-urgent', result };
|
||||
}
|
||||
} catch (error) {
|
||||
output = { message: 'error' };
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
async function handler(req, res) {
|
||||
try {
|
||||
const result = await list(req);
|
||||
|
||||
return res.status(200).send(result);
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
return res.status(200).send({ status: 'error', message: 'list error' });
|
||||
}
|
||||
}
|
||||
|
||||
export default handler;
|
@@ -0,0 +1,51 @@
|
||||
import { Op, Sequelize } from 'sequelize';
|
||||
import { NonUrgentQueue, SemiUrgentQueue } from './model';
|
||||
|
||||
async function search_queue(req) {
|
||||
try {
|
||||
let n_u_result = [];
|
||||
let s_u_result = [];
|
||||
|
||||
const { semi_urgent_case, non_urgent_case } = req.body;
|
||||
const criteria = ['hkid', 'mobile']
|
||||
.filter(key => req.body[key] !== '')
|
||||
.map(key => ({
|
||||
[key]: Sequelize.where(Sequelize.fn('LOWER', Sequelize.col(key)), 'LIKE', `%${req.body[key].toLowerCase()}%`),
|
||||
}));
|
||||
|
||||
if (non_urgent_case) {
|
||||
n_u_result = await NonUrgentQueue.findAll({ where: { [Op.or]: criteria } });
|
||||
// if (n_u_result === undefined) n_u_result = [];
|
||||
n_u_result.forEach(q => {
|
||||
q.dataValues.queue_type = 'non-urgent';
|
||||
});
|
||||
}
|
||||
|
||||
if (semi_urgent_case) {
|
||||
s_u_result = await SemiUrgentQueue.findAll({ where: { [Op.or]: criteria } });
|
||||
// if (s_u_result === undefined) s_u_result = [];
|
||||
s_u_result.forEach(q => {
|
||||
q.dataValues.queue_type = 'semi-urgent';
|
||||
});
|
||||
}
|
||||
|
||||
console.log({ s_u_result });
|
||||
return { status: 'OK', patient_queues: [...n_u_result, ...s_u_result] };
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return { status: 'ERROR' };
|
||||
}
|
||||
}
|
||||
|
||||
async function handler(req, res) {
|
||||
try {
|
||||
const result = await search_queue(req);
|
||||
|
||||
return res.status(200).send(result);
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
return res.status(200).send({ status: 'error', message: 'list error' });
|
||||
}
|
||||
}
|
||||
|
||||
export default handler;
|
@@ -0,0 +1,25 @@
|
||||
import { SemiUrgentQueue } from './model';
|
||||
|
||||
async function list() {
|
||||
try {
|
||||
const patient_queues = await SemiUrgentQueue.findAll();
|
||||
|
||||
return { status: 'OK', patient_queues };
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return { status: 'ERROR' };
|
||||
}
|
||||
}
|
||||
|
||||
async function handler(req, res) {
|
||||
try {
|
||||
const result = await list(req);
|
||||
|
||||
return res.status(200).send(result);
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
return res.status(200).send({ status: 'error', message: 'list error' });
|
||||
}
|
||||
}
|
||||
|
||||
export default handler;
|
@@ -0,0 +1,15 @@
|
||||
fetch("http://localhost/api/patient_queue/read_queue_item?queue_type=non-urgent&id=4", {
|
||||
"headers": {
|
||||
"sec-ch-ua": "\"Google Chrome\";v=\"129\", \"Not=A?Brand\";v=\"8\", \"Chromium\";v=\"129\"",
|
||||
"sec-ch-ua-mobile": "?1",
|
||||
"sec-ch-ua-platform": "\"Android\"",
|
||||
"Referer": "http://localhost/NonUrgentCaseEdit/1",
|
||||
"Referrer-Policy": "strict-origin-when-cross-origin"
|
||||
},
|
||||
"body": null,
|
||||
"method": "GET"
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => console.log(data))
|
||||
.catch(error => console.error('Error:', error));
|
||||
|
@@ -0,0 +1,23 @@
|
||||
fetch("http://localhost/api/patient_queue/register", {
|
||||
"headers": {
|
||||
"accept": "*/*",
|
||||
"accept-language": "en-US,en;q=0.9,zh-TW;q=0.8,zh-CN;q=0.7,zh;q=0.6",
|
||||
"cache-control": "no-cache",
|
||||
"content-type": "application/json",
|
||||
"pragma": "no-cache",
|
||||
"sec-ch-ua": "\"Google Chrome\";v=\"129\", \"Not=A?Brand\";v=\"8\", \"Chromium\";v=\"129\"",
|
||||
"sec-ch-ua-mobile": "?1",
|
||||
"sec-ch-ua-platform": "\"Android\"",
|
||||
"sec-fetch-dest": "empty",
|
||||
"sec-fetch-mode": "cors",
|
||||
"sec-fetch-site": "same-origin",
|
||||
"cookie": "pma_lang=en; phpMyAdmin=51ff7da1fa656cafa38dce7a6be8a79d",
|
||||
"Referer": "http://localhost/PatientRegister",
|
||||
"Referrer-Policy": "strict-origin-when-cross-origin"
|
||||
},
|
||||
"body": "{\"values\":{\"patient_name\":\"p1\",\"patient_hkid\":\"A123456(7)\",\"patient_age\":\"32\",\"patient_mobile\":\"91234567\",\"bruisesScratchesMinorBurns\":true,\"chestPain\":false,\"headache\":false,\"myMuiCheck\":false,\"nauseaAndVomiting\":false,\"runnyOrStuffyNose\":true,\"soreThroat\":false}}",
|
||||
"method": "POST"
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => console.log(data))
|
||||
.catch(error => console.error('Error:', error));
|
@@ -0,0 +1,23 @@
|
||||
fetch('http://localhost/api/patient_queue/search', {
|
||||
headers: {
|
||||
accept: '*/*',
|
||||
'accept-language': 'en-US,en;q=0.9,zh-TW;q=0.8,zh-CN;q=0.7,zh;q=0.6',
|
||||
'cache-control': 'no-cache',
|
||||
'content-type': 'application/json',
|
||||
pragma: 'no-cache',
|
||||
'sec-ch-ua': '"Google Chrome";v="129", "Not=A?Brand";v="8", "Chromium";v="129"',
|
||||
'sec-ch-ua-mobile': '?1',
|
||||
'sec-ch-ua-platform': '"Android"',
|
||||
'sec-fetch-dest': 'empty',
|
||||
'sec-fetch-mode': 'cors',
|
||||
'sec-fetch-site': 'same-origin',
|
||||
cookie: 'pma_lang=en',
|
||||
Referer: 'http://localhost/SearchCase',
|
||||
'Referrer-Policy': 'strict-origin-when-cross-origin',
|
||||
},
|
||||
body: '{"semi_urgent_case":true,"non_urgent_case":false,"hkid":"","mobile":"91234567"}',
|
||||
method: 'POST',
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => console.log(data))
|
||||
.catch(error => console.error('Error:', error));
|
@@ -0,0 +1,21 @@
|
||||
fetch("http://localhost/api/patient_queue/update_queue_item", {
|
||||
"headers": {
|
||||
"accept": "*/*",
|
||||
"accept-language": "en-US,en;q=0.9,zh-TW;q=0.8,zh-CN;q=0.7,zh;q=0.6",
|
||||
"content-type": "application/json",
|
||||
"sec-ch-ua": "\"Google Chrome\";v=\"129\", \"Not=A?Brand\";v=\"8\", \"Chromium\";v=\"129\"",
|
||||
"sec-ch-ua-mobile": "?1",
|
||||
"sec-ch-ua-platform": "\"Android\"",
|
||||
"sec-fetch-dest": "empty",
|
||||
"sec-fetch-mode": "cors",
|
||||
"sec-fetch-site": "same-origin",
|
||||
"cookie": "pma_lang=en; phpMyAdmin=51ff7da1fa656cafa38dce7a6be8a79d",
|
||||
"Referer": "http://localhost/NonUrgentCaseEdit/4",
|
||||
"Referrer-Policy": "strict-origin-when-cross-origin"
|
||||
},
|
||||
"body": "{\"id\":\"4\",\"queue_type\":\"non-urgent\",\"values\":{\"patient_name\":\"non-urgent-patient 3 update\",\"patient_hkid\":\"A123456(3)\",\"patient_mobile\":\"91234563\",\"patient_age\":13}}",
|
||||
"method": "POST"
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => console.log(data))
|
||||
.catch(error => console.error('Error:', error));
|
@@ -0,0 +1,89 @@
|
||||
import { NonUrgentQueue, SemiUrgentQueue } from './model';
|
||||
|
||||
async function updateQueueById(req, res) {
|
||||
try {
|
||||
const { id, queue_type } = req.body;
|
||||
console.log({ t: req.body });
|
||||
|
||||
if (!id || !queue_type) {
|
||||
return res.status(400).send({ status: 'error', message: 'id and queue_type are required' });
|
||||
}
|
||||
|
||||
const {
|
||||
patient_name: name,
|
||||
patient_hkid: hkid,
|
||||
patient_age: age,
|
||||
patient_mobile: mobile,
|
||||
bruisesScratchesMinorBurns,
|
||||
chestPain,
|
||||
headache,
|
||||
myMuiCheck,
|
||||
nauseaAndVomiting,
|
||||
runnyOrStuffyNose,
|
||||
soreThroat,
|
||||
} = req.body.values;
|
||||
|
||||
switch (queue_type) {
|
||||
case 'non-urgent':
|
||||
await NonUrgentQueue.update(
|
||||
{
|
||||
name,
|
||||
hkid,
|
||||
age,
|
||||
mobile,
|
||||
bruisesScratchesMinorBurns,
|
||||
chestPain,
|
||||
headache,
|
||||
myMuiCheck,
|
||||
nauseaAndVomiting,
|
||||
runnyOrStuffyNose,
|
||||
soreThroat,
|
||||
},
|
||||
{ where: { id } },
|
||||
);
|
||||
return { status: 'OK' };
|
||||
|
||||
case 'semi-urgent':
|
||||
await SemiUrgentQueue.update(
|
||||
{
|
||||
name,
|
||||
hkid,
|
||||
age,
|
||||
mobile,
|
||||
bruisesScratchesMinorBurns,
|
||||
chestPain,
|
||||
headache,
|
||||
myMuiCheck,
|
||||
nauseaAndVomiting,
|
||||
runnyOrStuffyNose,
|
||||
soreThroat,
|
||||
},
|
||||
{ where: { id } },
|
||||
);
|
||||
return { status: 'OK' };
|
||||
|
||||
default:
|
||||
return res.status(400).send({ status: 'error', message: 'invalid queue_type' });
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return { status: 'error' };
|
||||
}
|
||||
}
|
||||
|
||||
async function handler(req, res) {
|
||||
if (req.method === 'POST') {
|
||||
try {
|
||||
const result = await updateQueueById(req, res);
|
||||
|
||||
return res.status(200).send(result);
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
return res.status(200).send({ status: 'error', message: 'list error' });
|
||||
}
|
||||
} else {
|
||||
return res.status(405).send({ status: 'error', message: 'method not allowed' });
|
||||
}
|
||||
}
|
||||
|
||||
export default handler;
|
104
task1/project/003_src/client/pages/debug/index.js
Normal file
104
task1/project/003_src/client/pages/debug/index.js
Normal file
@@ -0,0 +1,104 @@
|
||||
import React from 'react';
|
||||
|
||||
import MailIcon from '@mui/icons-material/Mail';
|
||||
import InboxIcon from '@mui/icons-material/MoveToInbox';
|
||||
import { Box, Divider, Drawer, Link, List, ListItem, ListItemButton, ListItemIcon, ListItemText } from '@mui/material';
|
||||
import Head from 'next/head';
|
||||
|
||||
import { useFormik } from 'formik';
|
||||
import * as yup from 'yup';
|
||||
|
||||
const validationSchema = yup.object({
|
||||
// email: yup.string('Enter your email').email('Enter a valid email').required('Email is required'),
|
||||
// password: yup
|
||||
// .string('Enter your password')
|
||||
// .min(8, 'Password should be of minimum 8 characters length')
|
||||
// .required('Password is required'),
|
||||
});
|
||||
|
||||
export default function Home() {
|
||||
const [open, setOpen] = React.useState(false);
|
||||
|
||||
const toggleDrawer = newOpen => () => {
|
||||
setOpen(newOpen);
|
||||
};
|
||||
|
||||
const formik = useFormik({
|
||||
initialValues: {
|
||||
email: 'foobar@example.com',
|
||||
password: 'foobar',
|
||||
patient_name: 'default patient name',
|
||||
patient_hkid: 'A213456(7)',
|
||||
patient_age: 37,
|
||||
patient_mobile: '91234567',
|
||||
bruisesScratchesMinorBurns: false,
|
||||
chestPain: false,
|
||||
headache: false,
|
||||
myMuiCheck: false,
|
||||
nauseaAndVomiting: false,
|
||||
runnyOrStuffyNose: false,
|
||||
soreThroat: false,
|
||||
},
|
||||
validationSchema: validationSchema,
|
||||
onSubmit: values => {
|
||||
alert(JSON.stringify(values, null, 2));
|
||||
},
|
||||
});
|
||||
|
||||
const DrawerList = (
|
||||
<Box sx={{ width: 250 }} role='presentation' onClick={toggleDrawer(false)}>
|
||||
<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>
|
||||
</Box>
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
<title>dashboard - non-urgent case</title>
|
||||
<meta name='description' content='Generated by create next app' />
|
||||
<link rel='icon' href='/favicon.ico' />
|
||||
</Head>
|
||||
|
||||
<Box
|
||||
sx={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
minHeight: '90vh',
|
||||
}}
|
||||
>
|
||||
<Link href='/PatientRegister'>PatientRegister</Link>
|
||||
<Link href='/PatientQueueDisplay'>PatientQueueDisplay</Link>
|
||||
<Link href='/AdminLogin'>AdminLogin</Link>
|
||||
<Link href='/AdminHome'>AdminHome</Link>
|
||||
<Link href='/SemiUrgentCaseList'>SemiUrgentCaseList</Link>
|
||||
<Link href='/NonUrgentCaseList'>NonUrgentCaseList</Link>
|
||||
</Box>
|
||||
|
||||
<Drawer open={open} onClose={toggleDrawer(false)}>
|
||||
{DrawerList}
|
||||
</Drawer>
|
||||
</>
|
||||
);
|
||||
}
|
5
task1/project/003_src/client/pages/index.css.js
Normal file
5
task1/project/003_src/client/pages/index.css.js
Normal file
@@ -0,0 +1,5 @@
|
||||
export default () => `
|
||||
padding:0;
|
||||
margin:0;
|
||||
|
||||
`;
|
55
task1/project/003_src/client/pages/index.js
Normal file
55
task1/project/003_src/client/pages/index.js
Normal file
@@ -0,0 +1,55 @@
|
||||
import { Box, Button } from '@mui/material';
|
||||
import Head from 'next/head';
|
||||
import { useRouter } from 'next/router';
|
||||
import { useState } from 'react';
|
||||
|
||||
export default () => {
|
||||
const [changing_page, setChangingPage] = useState(false);
|
||||
const router = useRouter();
|
||||
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
<title>dashboard - non-urgent case</title>
|
||||
<meta name='description' content='Generated by create next app' />
|
||||
<link rel='icon' href='/favicon.ico' />
|
||||
</Head>
|
||||
|
||||
<Box
|
||||
sx={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
minHeight: '90vh',
|
||||
}}
|
||||
>
|
||||
<Box sx={{ display: 'flex', flexDirection: 'column', gap: '1rem' }}>
|
||||
<Box sx={{ fontWeight: 'bold', fontSize: '1.2rem' }}>Demo Patient Queue system</Box>
|
||||
<Button
|
||||
onClick={() => {
|
||||
setChangingPage(true);
|
||||
router.push('/PatientLanding');
|
||||
}}
|
||||
variant='contained'
|
||||
disableElevation
|
||||
disabled={changing_page}
|
||||
>
|
||||
I am patient
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => {
|
||||
setChangingPage(true);
|
||||
router.push('/AdminLogin');
|
||||
}}
|
||||
variant='contained'
|
||||
disableElevation
|
||||
disabled={changing_page}
|
||||
>
|
||||
I am admin
|
||||
</Button>
|
||||
</Box>
|
||||
</Box>
|
||||
</>
|
||||
);
|
||||
};
|
Reference in New Issue
Block a user