summaryrefslogtreecommitdiff
path: root/client/src/components
diff options
context:
space:
mode:
Diffstat (limited to 'client/src/components')
-rw-r--r--client/src/components/Admin.tsx29
-rw-r--r--client/src/components/AdminLogin.tsx90
-rw-r--r--client/src/components/Dashboard.tsx60
-rw-r--r--client/src/components/GuestLogin.tsx14
-rw-r--r--client/src/components/Rsvp.tsx4
-rw-r--r--client/src/components/RsvpForm.tsx4
6 files changed, 190 insertions, 11 deletions
diff --git a/client/src/components/Admin.tsx b/client/src/components/Admin.tsx
new file mode 100644
index 0000000..6e772ab
--- /dev/null
+++ b/client/src/components/Admin.tsx
@@ -0,0 +1,29 @@
+import React from 'react';
+import { useMemo } from 'react';
+import { useLocation, Navigate, Outlet } from 'react-router-dom';
+import { useSelector } from 'react-redux';
+import CssBaseline from '@mui/material/CssBaseline';
+import NavBar from './NavBar';
+import { selectGuests } from '../slices/auth/adminSlice';
+
+const authenticate = () => {
+ const guests = useSelector(selectGuests);
+ return useMemo(() => ({ guests }), [guests]);
+};
+
+function Rsvp() {
+ const auth = authenticate();
+ const location = useLocation();
+
+ return auth?.guests ? (
+ <>
+ <CssBaseline />
+ <NavBar />
+ <Outlet context={auth?.guests} />
+ </>
+ ) : (
+ <Navigate to="/admin/login" state={{ from: location }} replace />
+ );
+}
+
+export default Rsvp;
diff --git a/client/src/components/AdminLogin.tsx b/client/src/components/AdminLogin.tsx
new file mode 100644
index 0000000..d9c1260
--- /dev/null
+++ b/client/src/components/AdminLogin.tsx
@@ -0,0 +1,90 @@
+import React from 'react';
+import { useNavigate } from 'react-router-dom';
+import { useDispatch } from 'react-redux';
+import { Button, Paper, TextField, Typography } from '@mui/material';
+import { useForm } from 'react-hook-form';
+import { setAdmin } from '../slices/auth/adminSlice';
+import { useLoginAdminMutation } from '../slices/api/adminSlice';
+import type { AdminLoginRequest } from '../slices/api/adminSlice';
+
+function GuestLogin() {
+ const dispatch = useDispatch();
+ const navigate = useNavigate();
+ const [login] = useLoginAdminMutation();
+
+ const {
+ register,
+ handleSubmit,
+ formState: { errors },
+ } = useForm<AdminLoginRequest>({
+ defaultValues: {
+ username: '',
+ password: '',
+ },
+ });
+
+ const onSubmit = async (data: AdminLoginRequest) => {
+ try {
+ dispatch(setAdmin(await login(data).unwrap()));
+ navigate('/dashboard');
+ } catch (e) {
+ console.log(e);
+ }
+ };
+
+ return (
+ <form
+ style={{
+ height: '100%',
+ width: '100%',
+ display: 'flex',
+ justifyContent: 'center',
+ alignItems: 'start',
+ }}
+ noValidate
+ onSubmit={handleSubmit(onSubmit)}
+ >
+ <Paper
+ elevation={3}
+ sx={{
+ '&:hover': { boxShadow: 8 },
+ width: { xs: '90%', md: 400 },
+ display: 'flex',
+ flexDirection: 'column',
+ justifyContent: 'center',
+ alignItems: 'center',
+ mt: 16,
+ p: 2,
+ borderRadius: '8px',
+ }}
+ >
+ <Typography variant="h6">Admin Login</Typography>
+ <TextField
+ label="Username"
+ variant="outlined"
+ margin="normal"
+ fullWidth
+ error={!!errors.username}
+ helperText={errors.username?.message}
+ required
+ {...register('username', { required: 'This field is required' })}
+ />
+ <TextField
+ label="Password"
+ variant="outlined"
+ margin="normal"
+ fullWidth
+ error={!!errors.password}
+ helperText={errors.password?.message}
+ required
+ {...register('password', { required: 'This field is required' })}
+ />
+ <Button type="submit" variant="contained" fullWidth sx={{ mt: 2 }}>
+ Log in
+ </Button>
+ </Paper>
+ </form>
+ );
+}
+
+export default GuestLogin;
diff --git a/client/src/components/Dashboard.tsx b/client/src/components/Dashboard.tsx
new file mode 100644
index 0000000..20758fc
--- /dev/null
+++ b/client/src/components/Dashboard.tsx
@@ -0,0 +1,60 @@
+import React, { useMemo } from 'react';
+import { useOutletContext } from 'react-router-dom';
+import {
+ MaterialReactTable,
+ useMaterialReactTable,
+ type MRT_ColumnDef,
+} from 'material-react-table';
+import type { Guest } from '../slices/api/adminSlice';
+
+function Dashboard() {
+ const guests: Guest[] = useOutletContext();
+ const columns = useMemo<MRT_ColumnDef<Guest>[]>(
+ () => [
+ {
+ accessorKey: 'firstName',
+ header: 'First Name',
+ size: 150,
+ },
+ {
+ accessorKey: 'lastName',
+ header: 'Last Name',
+ size: 150,
+ },
+ {
+ accessorKey: 'attendance',
+ header: 'Attendance',
+ size: 50,
+ },
+ {
+ accessorKey: 'email',
+ header: 'Email',
+ size: 150,
+ },
+ {
+ accessorKey: 'message',
+ header: 'Message',
+ size: 200,
+ },
+ {
+ accessorKey: 'partySize',
+ header: 'Party Size',
+ size: 50,
+ },
+ // {
+ // accessorKey: 'partyList',
+ // header: 'Party List',
+ // size: 150,
+ // },
+ ],
+ []
+ );
+ const table = useMaterialReactTable({
+ columns,
+ data: guests,
+ });
+
+ return <MaterialReactTable table={table} />;
+}
+
+export default Dashboard;
diff --git a/client/src/components/GuestLogin.tsx b/client/src/components/GuestLogin.tsx
index cca2179..0e47384 100644
--- a/client/src/components/GuestLogin.tsx
+++ b/client/src/components/GuestLogin.tsx
@@ -3,29 +3,29 @@ import { useNavigate } from 'react-router-dom';
import { useDispatch } from 'react-redux';
import { Button, Paper, TextField, Typography } from '@mui/material';
import { useForm } from 'react-hook-form';
-import { setCredentials } from '../slices/authSlice';
-import { useLoginMutation } from '../slices/apiSlice';
-import type { LoginRequest } from '../slices/apiSlice';
+import { setGuest } from '../slices/auth/guestSlice';
+import { useLoginGuestMutation } from '../slices/api/guestSlice';
+import type { GuestLoginRequest } from '../slices/api/guestSlice';
function GuestLogin() {
const dispatch = useDispatch();
const navigate = useNavigate();
- const [login] = useLoginMutation();
+ const [login] = useLoginGuestMutation();
const {
register,
handleSubmit,
formState: { errors },
- } = useForm<LoginRequest>({
+ } = useForm<GuestLoginRequest>({
defaultValues: {
firstName: '',
lastName: '',
},
});
- const onSubmit = async (data: LoginRequest) => {
+ const onSubmit = async (data: GuestLoginRequest) => {
try {
- dispatch(setCredentials(await login(data).unwrap()));
+ dispatch(setGuest(await login(data).unwrap()));
navigate('/rsvp');
} catch (e) {
console.log(e);
diff --git a/client/src/components/Rsvp.tsx b/client/src/components/Rsvp.tsx
index d3d9677..ab83cd7 100644
--- a/client/src/components/Rsvp.tsx
+++ b/client/src/components/Rsvp.tsx
@@ -4,10 +4,10 @@ import { useLocation, Navigate, Outlet } from 'react-router-dom';
import { useSelector } from 'react-redux';
import CssBaseline from '@mui/material/CssBaseline';
import NavBar from './NavBar';
-import { selectCurrentGuest } from '../slices/authSlice';
+import { selectGuest } from '../slices/auth/guestSlice';
const authenticate = () => {
- const guest = useSelector(selectCurrentGuest);
+ const guest = useSelector(selectGuest);
return useMemo(() => ({ guest }), [guest]);
};
diff --git a/client/src/components/RsvpForm.tsx b/client/src/components/RsvpForm.tsx
index 1e03227..d72b92d 100644
--- a/client/src/components/RsvpForm.tsx
+++ b/client/src/components/RsvpForm.tsx
@@ -16,8 +16,8 @@ import {
} from '@mui/material';
import MailIcon from '@mui/icons-material/Mail';
import { useForm, Controller, useFieldArray } from 'react-hook-form';
-import { useUpdateGuestMutation } from '../slices/apiSlice';
-import type { Guest } from '../slices/apiSlice';
+import { useUpdateGuestMutation } from '../slices/api/guestSlice';
+import type { Guest } from '../slices/api/guestSlice';
interface StatusProps {
isError: boolean;