diff --git a/frontend/src/menuAside.ts b/frontend/src/menuAside.ts
index 010d528..cd6344c 100644
--- a/frontend/src/menuAside.ts
+++ b/frontend/src/menuAside.ts
@@ -7,6 +7,11 @@ const menuAside: MenuAsideItem[] = [
icon: icon.mdiViewDashboardOutline,
label: 'Dashboard',
},
+ {
+ href: '/tables',
+ label: 'Table Management',
+ icon: icon.mdiTableChair,
+ },
{
href: '/users/users-list',
@@ -50,7 +55,7 @@ const menuAside: MenuAsideItem[] = [
},
{
href: '/tables/tables-list',
- label: 'Tables',
+ label: 'Table List',
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
icon: 'mdiSeat' in icon ? icon['mdiSeat' as keyof typeof icon] : icon.mdiTable ?? icon.mdiTable,
diff --git a/frontend/src/pages/reservations/reservations-new.tsx b/frontend/src/pages/reservations/reservations-new.tsx
index 50671d0..9bc8ba8 100644
--- a/frontend/src/pages/reservations/reservations-new.tsx
+++ b/frontend/src/pages/reservations/reservations-new.tsx
@@ -184,7 +184,7 @@ const ReservationsNew = () => {
// get from url params
- const { dateRangeStart, dateRangeEnd } = router.query
+ const { dateRangeStart, dateRangeEnd, tableId } = router.query
const handleSubmit = async (data) => {
@@ -206,11 +206,12 @@ const ReservationsNew = () => {
- dateRangeStart && dateRangeEnd ?
+ (dateRangeStart && dateRangeEnd) || tableId ?
{
...initialValues,
start_at: moment(dateRangeStart).format('YYYY-MM-DDTHH:mm'),
end_at: moment(dateRangeEnd).format('YYYY-MM-DDTHH:mm'),
+ table: tableId,
} : initialValues
}
diff --git a/frontend/src/pages/tables/index.tsx b/frontend/src/pages/tables/index.tsx
new file mode 100644
index 0000000..9582984
--- /dev/null
+++ b/frontend/src/pages/tables/index.tsx
@@ -0,0 +1,122 @@
+
+import { useState, useEffect } from 'react'
+import { useDispatch, useSelector } from 'react-redux'
+import type { ReactElement } from 'react'
+import { useRouter } from 'next/router'
+import Link from 'next/link'
+import Head from 'next/head'
+
+import { mdiTable } from '@mdi/js'
+import CardBox from '../../components/CardBox'
+import LayoutAuthenticated from '../../layouts/Authenticated'
+import SectionMain from '../../components/SectionMain'
+import SectionTitleLineWithButton from '../../components/SectionTitleLineWithButton'
+import { getPageTitle } from '../../config'
+import { fetchTables } from '../../stores/tables/tablesSlice'
+import { fetchReservations } from '../../stores/reservations/reservationsSlice'
+
+const TableStatus = {
+ Available: 'Available',
+ Reserved: 'Reserved',
+ Occupied: 'Occupied',
+}
+
+const TableCard = ({ table, status }) => {
+ const router = useRouter()
+
+ const getStatusColor = () => {
+ switch (status) {
+ case TableStatus.Available:
+ return 'bg-green-500'
+ case TableStatus.Reserved:
+ return 'bg-orange-500'
+ case TableStatus.Occupied:
+ return 'bg-red-500'
+ default:
+ return 'bg-gray-400'
+ }
+ }
+
+ const handleTableClick = () => {
+ if (status === TableStatus.Available) {
+ router.push(`/reservations/reservations-new?tableId=${table.id}`)
+ } else {
+ // Find reservation and show details, for now just log
+ console.log(`Table ${table.number} is ${status}`)
+ }
+ }
+
+ return (
+
+
Table {table.number}
+
{table.capacity} Seats
+
{status}
+
+ )
+}
+
+const TablesPage = () => {
+ const dispatch = useDispatch()
+ const router = useRouter()
+
+ const tables = useSelector((state) => state.tables.tables)
+ const reservations = useSelector((state) => state.reservations.reservations)
+
+ const [tableStatuses, setTableStatuses] = useState({})
+
+ useEffect(() => {
+ dispatch(fetchTables())
+ dispatch(fetchReservations())
+ }, [dispatch])
+
+ useEffect(() => {
+ const statuses = {}
+ const now = new Date()
+
+ tables.forEach((table) => {
+ const currentReservation = reservations.find(
+ (r) =>
+ r.tableId === table.id &&
+ new Date(r.startTime) <= now &&
+ new Date(r.endTime) > now,
+ )
+
+ if (currentReservation) {
+ if (currentReservation.status === 'Confirmed') {
+ statuses[table.id] = TableStatus.Occupied
+ } else {
+ statuses[table.id] = TableStatus.Reserved
+ }
+ } else {
+ statuses[table.id] = TableStatus.Available
+ }
+ })
+ setTableStatuses(statuses)
+ }, [tables, reservations])
+
+ return (
+ <>
+
+ {getPageTitle('Tables')}
+
+
+
+
+
+ {tables.map((table) => (
+
+ ))}
+
+
+ >
+ )
+}
+
+TablesPage.getLayout = function getLayout(page: ReactElement) {
+ return {page}
+}
+
+export default TablesPage
diff --git a/frontend/src/stores/reservations/reservationsSlice.ts b/frontend/src/stores/reservations/reservationsSlice.ts
index 36bf862..1f52b84 100644
--- a/frontend/src/stores/reservations/reservationsSlice.ts
+++ b/frontend/src/stores/reservations/reservationsSlice.ts
@@ -28,7 +28,7 @@ const initialState: MainState = {
},
}
-export const fetch = createAsyncThunk('reservations/fetch', async (data: any) => {
+export const fetchReservations = createAsyncThunk('reservations/fetch', async (data: any = {}) => {
const { id, query } = data
const result = await axios.get(
`reservations${
@@ -132,16 +132,16 @@ export const reservationsSlice = createSlice({
},
},
extraReducers: (builder) => {
- builder.addCase(fetch.pending, (state) => {
+ builder.addCase(fetchReservations.pending, (state) => {
state.loading = true
resetNotify(state);
})
- builder.addCase(fetch.rejected, (state, action) => {
+ builder.addCase(fetchReservations.rejected, (state, action) => {
state.loading = false
rejectNotify(state, action);
})
- builder.addCase(fetch.fulfilled, (state, action) => {
+ builder.addCase(fetchReservations.fulfilled, (state, action) => {
if (action.payload.rows && action.payload.count >= 0) {
state.reservations = action.payload.rows;
state.count = action.payload.count;
diff --git a/frontend/src/stores/tables/tablesSlice.ts b/frontend/src/stores/tables/tablesSlice.ts
index 4d6a929..8cc4f71 100644
--- a/frontend/src/stores/tables/tablesSlice.ts
+++ b/frontend/src/stores/tables/tablesSlice.ts
@@ -28,7 +28,7 @@ const initialState: MainState = {
},
}
-export const fetch = createAsyncThunk('tables/fetch', async (data: any) => {
+export const fetchTables = createAsyncThunk('tables/fetch', async (data: any = {}) => {
const { id, query } = data
const result = await axios.get(
`tables${
@@ -132,16 +132,16 @@ export const tablesSlice = createSlice({
},
},
extraReducers: (builder) => {
- builder.addCase(fetch.pending, (state) => {
+ builder.addCase(fetchTables.pending, (state) => {
state.loading = true
resetNotify(state);
})
- builder.addCase(fetch.rejected, (state, action) => {
+ builder.addCase(fetchTables.rejected, (state, action) => {
state.loading = false
rejectNotify(state, action);
})
- builder.addCase(fetch.fulfilled, (state, action) => {
+ builder.addCase(fetchTables.fulfilled, (state, action) => {
if (action.payload.rows && action.payload.count >= 0) {
state.tables = action.payload.rows;
state.count = action.payload.count;