Skip to content

Commit 5ba226b

Browse files
committed
feat!: improve translation, zustand, API performance
1 parent 082a9ee commit 5ba226b

40 files changed

Lines changed: 1254 additions & 1230 deletions

src/app/WithSystemCheck.tsx

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,20 @@ import { Construction } from "lucide-react";
44
import { ComponentType, useCallback, useEffect, useMemo, useState } from "react";
55
import { Loading } from "@/app/components/Loading";
66
import { useTranslations } from 'next-intl';
7-
8-
// Define the system status type
9-
type SystemStatus = 'checking' | 'active' | 'inactive';
7+
import { SystemStatus } from "@/model/system";
108

119
let globalSystemStatus: SystemStatus | null = null;
1210
let lastFetchTime = 0;
1311
const CACHE_DURATION = 30000; // 30 seconds
1412

13+
type ExtendedSystemStatus = SystemStatus | 'checking';
1514
const WithSystemCheck = <P extends object>(
1615
WrappedComponent: ComponentType<P>
1716
): ComponentType<P> => {
1817

1918
return function WithSystemCheckComponent(props: P) {
2019
const t = useTranslations();
21-
const [systemStatus, setSystemStatus] = useState<SystemStatus>(() => {
20+
const [systemStatus, setSystemStatus] = useState<ExtendedSystemStatus>(() => {
2221
const now = Date.now();
2322
if (globalSystemStatus && (now - lastFetchTime) < CACHE_DURATION) {
2423
return globalSystemStatus;

src/app/admin/logout/page.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ const Page = () => {
99
const authStore = useAuthStore();
1010
useEffect(() => {
1111
authStore.signOut();
12-
router.push('/');
12+
router.push('/', { scroll: true })
1313
}, []);
1414

1515
return (

src/app/admin/manage/database/page.tsx

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ export default function ManagePage() {
2222

2323
fetch('/api/manage/db/delete', {
2424
method: 'POST',
25-
credentials: 'include', })
25+
credentials: 'include',
26+
})
2627
.then(() => setMessage('Database deleted'))
2728
.catch((error) => setMessage(error))
2829
}
@@ -34,7 +35,8 @@ export default function ManagePage() {
3435

3536
fetch('/api/manage/db/prepare', {
3637
method: 'POST',
37-
credentials: 'include', })
38+
credentials: 'include',
39+
})
3840
.then(() => setMessage('Database prepared'))
3941
.catch((error) => {
4042
console.error('Error preparing database', error);
@@ -44,7 +46,8 @@ export default function ManagePage() {
4446

4547
const getSystemStatus = () => {
4648
fetch('/api/manage/system/status', {
47-
credentials: 'include', })
49+
credentials: 'include',
50+
})
4851
.then(async response => {
4952
const data = await response.json();
5053
if (!response.ok) {
@@ -67,7 +70,8 @@ export default function ManagePage() {
6770
const updateSystemStatus = (status: SystemStatus) => {
6871
fetch(`/api/manage/system/status/${status}`, {
6972
method: 'POST',
70-
credentials: 'include', })
73+
credentials: 'include',
74+
})
7175
.then(() => {
7276
setMessage(`System ${status}`)
7377
setStatus(status)
@@ -77,7 +81,6 @@ export default function ManagePage() {
7781
setMessage(error)
7882
})
7983
}
80-
8184
return (
8285
<div>
8386
<Heading title={t('admin.manage.database.title')} description={message}

src/app/admin/prepare/pizza/page.tsx

Lines changed: 24 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ const PizzaMakerStation = () => {
4646

4747
// Fetch orders and calculate upcoming pizzas
4848
const fetchOrders = async () => {
49-
const response = await fetch('/api/order', { credentials: 'include',});
49+
const response = await fetch('/api/order', { credentials: 'include', });
5050
const data = await response.json();
5151

5252
if (!response.ok) {
@@ -116,7 +116,7 @@ const PizzaMakerStation = () => {
116116
return;
117117
}
118118

119-
// Add to recently made list for visual feedback
119+
// Add to a recently made list for visual feedback
120120
setRecentlyMade([...recentlyMade, pizzaType.name]);
121121
setTimeout(() => {
122122
setRecentlyMade(prev => prev.filter(name => name !== pizzaType.name));
@@ -134,38 +134,36 @@ const PizzaMakerStation = () => {
134134

135135
return (
136136
<div>
137-
{/* TODO: add missing translations*/}
138-
<Heading title={t('admin.prepare.title')} description={"Tap when pizza is ready for oven"}
137+
<Heading title={t('admin.prepare.title')} description={t('admin.prepare.subtitle')}
139138
icon={<Clock className="w-10 h-10 text-gray-900"/>}/>
140139

141140

142141
<div className="flex flex-col md:flex-row gap-5">
143142
<div className="bg-white p-4 md:p-8 rounded-2xl w-full md:w-1/3">
144-
<div className="flex flex-wrap gap-2">
145-
<div className="flex flex-col gap-2">
146-
{orders.map(order => (
147-
<>
148-
{order.items
149-
.filter(item => item.status === ITEM_STATUSES.PREPPING)
150-
.map((item, index) => (
151-
<span key={`${order._id.toString()}-${item.item.name}-${index}`}
152-
className={`border px-3 py-1 rounded-lg text-sm ${item.status !== ITEM_STATUSES.PREPPING ? 'bg-green-50 border-green-100 text-gray-400' : ''}`}>
143+
<div className="flex flex-col gap-2 max-h-[15rem] md:max-h-fit overflow-y-scroll ">
144+
{orders.map(order => (
145+
<>
146+
{order.items
147+
.filter(item => item.status === ITEM_STATUSES.PREPPING)
148+
.map((item, index) => (
149+
<div
150+
key={`${order._id.toString()}-${item.item._id.toString()}-${item.status}-${index}`}
151+
className={`border px-3 py-1 rounded-lg text-sm flex items-center justify-between ${item.status !== ITEM_STATUSES.PREPPING ? 'bg-green-50 border-green-100 text-gray-400' : ''}`}>
153152
{item.item.name} <span
154-
className="bg-gray-100 py-0.5 px-1 rounded-2xl">{order.timeslot}</span>
155-
</span>)
156-
)}
157-
</>
158-
))}
159-
</div>
160-
{upcomingPizzas.size === 0 && (
161-
<span className="text-gray-400">{t('admin.prepare.no_open_orders')} 🎉</span>
162-
)}
153+
className="bg-gray-100 py-0.5 px-1 rounded-2xl">{order.timeslot}</span>
154+
</div>)
155+
)}
156+
</>
157+
))}
163158
</div>
159+
{upcomingPizzas.size === 0 && (
160+
<span className="text-gray-400">{t('admin.prepare.no_open_orders')} 🎉</span>
161+
)}
164162
</div>
165163

166164
{/* Pizza buttons grid */}
167165
<div>
168-
<div className="grid grid-cols-2 md:grid-cols-3 gap-4 md:gap-6">
166+
<div className="grid grid-cols-1 md:grid-cols-3 gap-4 md:gap-6">
169167
{items.map(pizza => {
170168
const pendingCount = upcomingPizzas.get(pizza.name) ?? 0;
171169
const isRecent = recentlyMade.includes(pizza.name);
@@ -174,7 +172,7 @@ const PizzaMakerStation = () => {
174172
<button
175173
key={pizza.id}
176174
className={`
177-
aspect-4/3 ${pizza.color} bg-opacity-90 rounded-3xl p-6 md:p-4
175+
aspect-4/3 ${pizza.color} bg-opacity-90 rounded-3xl p-3 md:p-4
178176
shadow-2xl transform transition-all duration-200
179177
${pendingCount > 0 ? 'hover:scale-105 active:scale-95 cursor-pointer' : 'opacity-50 cursor-not-allowed'}
180178
${isRecent ? 'ring-4 ring-green-400 ring-opacity-75' : ''}
@@ -190,9 +188,9 @@ const PizzaMakerStation = () => {
190188
className="text-sm text-black opacity-75 mt-1">{pizza.dietary}</span>
191189
)}
192190
{pendingCount > 0 && (
193-
<div className="mt-4 bg-white bg-opacity-25 rounded-full px-4 py-2">
191+
<div className="mt-4 bg-white bg-opacity-25 rounded-2xl px-4 py-2">
194192
<span
195-
className="text-xl font-bold text-black">{pendingCount} needed</span>
193+
className="text-lg font-medium text-black">{pendingCount} needed</span>
196194
</div>
197195
)}
198196
{isRecent && (
Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,15 @@
11
import dbConnect from "@/lib/dbConnect";
2-
import { getSystemStatus } from "@/lib/system";
2+
import { getSystemStatus } from "@/lib/serverAuth";
33

4-
// Thanks to https://medium.com/phantom3/next-js-14-build-prerender-error-fix-f3c51de2fe1d
54
export const dynamic = "force-dynamic";
65
export const fetchCache = "force-no-store";
76

7+
const conn = await dbConnect();
88

99
/**
1010
* Set the system status
1111
* @constructor
1212
*/
1313
export async function GET(request: Request) {
14-
await dbConnect();
1514
return Response.json({ status: await getSystemStatus() })
1615
}

src/app/api/order/[id]/cancel/route.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import dbConnect from "@/lib/dbConnect";
22
import mongoose from "mongoose";
33
import { ORDER_STATUSES, OrderModel } from "@/model/order";
44
import { NextRequest } from "next/server";
5+
import { ObjectId } from "bson";
56

67
/**
78
* Allow user to cancel an order.
@@ -16,7 +17,7 @@ export async function PUT(request: NextRequest, { params }: { params: Promise<{
1617
const { id } = await params
1718

1819
// Check if the ID is valid and ObjectId
19-
if (!id || !mongoose.isValidObjectId(id)) {
20+
if (!id || !ObjectId.isValid(id)) {
2021
return new Response(`
2122
The ID is not valid.
2223
Please provide a valid ID.

src/app/api/order/[id]/pay/route.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,13 @@ import dbConnect from "@/lib/dbConnect";
33
import { requireAuth } from "@/lib/serverAuth";
44
import { OrderModel } from "@/model/order";
55
import { NextRequest, NextResponse } from "next/server";
6+
import { ObjectId } from "bson";
67

78
/**
89
* Retrieve whether order is paid or not
910
* @constructor
1011
* @param request
12+
* @param params
1113
*/
1214
export async function GET(request: NextRequest, { params }: { params: Promise<{ id: string }> }) {
1315
await dbConnect();
@@ -16,7 +18,7 @@ export async function GET(request: NextRequest, { params }: { params: Promise<{
1618
const { id } = await params
1719

1820
// Check if the ID is valid and ObjectId
19-
if (!id || !mongoose.isValidObjectId(id)) {
21+
if (!id || !ObjectId.isValid(id)) {
2022
return NextResponse.json({
2123
message: 'The ID is not valid.'
2224
}, { status: 400 })
@@ -42,22 +44,22 @@ export async function GET(request: NextRequest, { params }: { params: Promise<{
4244
* @param params
4345
*/
4446
export async function PUT(request: NextRequest, { params }: { params: Promise<{ id: string }> }) {
45-
await dbConnect();
46-
await requireAuth();
47-
4847
// Get the ID from the URL
4948
const { id } = await params
5049

5150
// Get the order details from the request body
5251
const { isPaid } = await request.json()
5352

5453
// Check if the ID is valid and ObjectId
55-
if (!id || !mongoose.isValidObjectId(id)) {
54+
if (!id || !ObjectId.isValid(id)) {
5655
return NextResponse.json({
5756
message: 'The ID is not valid.'
5857
}, { status: 400 })
5958
}
6059

60+
await dbConnect();
61+
await requireAuth();
62+
6163

6264
try {
6365
// Find the order by ID

src/app/api/order/[id]/route.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import dbConnect from "@/lib/dbConnect";
2-
import mongoose from "mongoose";
32
import { OrderModel } from "@/model/order";
43
import { NextRequest } from "next/server";
4+
import { ObjectId } from "bson";
55

66

77
export async function GET(request: NextRequest, { params }: { params: Promise<{ id: string }> }) {
@@ -11,7 +11,7 @@ export async function GET(request: NextRequest, { params }: { params: Promise<{
1111
const { id } = await params
1212

1313
// Check if the ID is valid and ObjectId
14-
if (!id || !mongoose.isValidObjectId(id)) {
14+
if (!id || !ObjectId.isValid(id)) {
1515
return new Response(`
1616
The ID is not valid.
1717
Please provide a valid ID.

src/app/api/order/batch/route.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import dbConnect from "@/lib/dbConnect";
2+
import mongoose from "mongoose";
3+
import { OrderModel, OrderStatus } from "@/model/order";
4+
import { NextRequest } from "next/server";
5+
6+
7+
export async function POST(request: NextRequest) {
8+
await dbConnect();
9+
10+
// Get IDs
11+
const { orderIds } = await request.json() as { orderIds: string[] }
12+
13+
// Check if the ID is valid and ObjectId
14+
if (!orderIds || orderIds.some(orderId => !mongoose.isValidObjectId(orderId))) {
15+
return new Response(`
16+
The ID are not valid.
17+
`, { status: 400 });
18+
}
19+
20+
// Batch fetch all order statuses in a single database query
21+
const orders = await OrderModel.find({
22+
_id: { $in: orderIds }
23+
}).select('_id status').lean();
24+
25+
const statusMap = orders.reduce((acc: { [id: string]: OrderStatus }, order) => {
26+
acc[order._id.toString()] = order.status;
27+
return acc;
28+
}, {});
29+
30+
return Response.json(statusMap);
31+
}

0 commit comments

Comments
 (0)