Skip to content

Commit 84ca766

Browse files
committed
feat: add status field to delivery requests and shipments, and update date picker for time selection
1 parent 329e14b commit 84ca766

File tree

6 files changed

+54
-67
lines changed

6 files changed

+54
-67
lines changed

api/app.js

Lines changed: 0 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -33,18 +33,7 @@ app.use(
3333
"X-Requested-With",
3434
"x-request-timeout",
3535
"X-Request-Timeout",
36-
"Access-Control-Allow-Headers",
37-
"Access-Control-Allow-Origin",
38-
"Cache-Control",
39-
"Pragma",
40-
"X-HTTP-Method-Override",
41-
"X-Forwarded-For",
42-
"X-Real-IP",
43-
"User-Agent",
44-
"Referer",
4536
],
46-
exposedHeaders: ["Content-Length", "Content-Type"],
47-
maxAge: 86400, // 24 hours
4837
})
4938
);
5039

@@ -59,25 +48,6 @@ const publicLimiter = rateLimit({
5948

6049
app.use("/api", publicLimiter);
6150

62-
// Specific handler for deliveries preflight (must come before general options handler)
63-
app.options("/api/deliveries", (req, res) => {
64-
res.header("Access-Control-Allow-Origin", req.headers.origin || "*");
65-
res.header(
66-
"Access-Control-Allow-Methods",
67-
"GET,POST,PUT,DELETE,PATCH,OPTIONS"
68-
);
69-
res.header(
70-
"Access-Control-Allow-Headers",
71-
"Content-Type,Authorization,Accept,Origin,X-Requested-With,x-request-timeout,X-Request-Timeout,Access-Control-Allow-Headers,Access-Control-Allow-Origin,Cache-Control,Pragma,X-HTTP-Method-Override,X-Forwarded-For,X-Real-IP,User-Agent,Referer"
72-
);
73-
res.header("Access-Control-Allow-Credentials", "true");
74-
res.header("Access-Control-Max-Age", "86400");
75-
res.sendStatus(204); // Use 204 No Content for preflight
76-
});
77-
78-
// Handle preflight requests (general fallback)
79-
app.options("*", cors());
80-
8151
app.use("/api/auth", authRoutes);
8252
app.use("/api/deliveries", deliveryRoutes);
8353
app.use("/api/invoices", invoiceRoutes);

client/src/Admin/pages/CreateDelivery.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ interface DeliveryRequest {
4242
dateSent: string;
4343
deliveryDate: string;
4444
checkEmail: boolean;
45+
status: string; // Add status field
4546
}
4647

4748
interface DeliveryResponse {
@@ -76,6 +77,7 @@ interface ShipmentData {
7677
weight: number;
7778
value: number;
7879
}>;
80+
status: string;
7981
deliveryFee: number;
8082
currency: { code: string; symbol: string; name: string };
8183
checkEmail: boolean;
@@ -158,6 +160,7 @@ const CreateDelivery = () => {
158160
? new Date(data.deliveryDate).toISOString()
159161
: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000).toISOString(),
160162
checkEmail: Boolean(data.checkEmail),
163+
status: data.status || "Pending", // Include status from form
161164
};
162165
};
163166

@@ -181,7 +184,6 @@ const CreateDelivery = () => {
181184
method: "POST",
182185
headers: {
183186
Authorization: `Bearer ${token}`,
184-
"X-Request-Timeout": "60000", // Indicate we expect a longer processing time
185187
},
186188
data: requestData,
187189
});

client/src/components/EditShipmentForm.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,7 @@ const EditShipmentForm: React.FC<ShipmentFormProps> = ({
353353
onChange={(newValue) =>
354354
setFormData((prev) => ({ ...prev, pickupDate: newValue }))
355355
}
356+
allowTimeSelection={true} // Allow both date and time selection
356357
/>
357358
</div>
358359

@@ -365,6 +366,7 @@ const EditShipmentForm: React.FC<ShipmentFormProps> = ({
365366
onChange={(newValue) =>
366367
setFormData((prev) => ({ ...prev, deliveryDate: newValue }))
367368
}
369+
allowTimeSelection={true} // Allow both date and time selection
368370
/>
369371
</div>
370372
</div>

client/src/components/ShipmentForm.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,7 @@ const ShipmentForm: React.FC<ShipmentFormProps> = ({
365365
onChange={(newValue) =>
366366
setFormData((prev) => ({ ...prev, pickupDate: newValue }))
367367
}
368+
allowTimeSelection={false} // Date-only for pickup
368369
/>
369370
</div>
370371

@@ -377,6 +378,7 @@ const ShipmentForm: React.FC<ShipmentFormProps> = ({
377378
onChange={(newValue) =>
378379
setFormData((prev) => ({ ...prev, deliveryDate: newValue }))
379380
}
381+
allowTimeSelection={false} // Date-only for delivery
380382
/>
381383
</div>
382384
</div>

client/src/components/date-time.tsx

Lines changed: 45 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,13 @@ import { CalendarIcon } from "lucide-react";
1010
interface DatePickerDemoProps {
1111
value: string; // ISO string from formData
1212
onChange: (value: string) => void; // callback to update formData
13+
allowTimeSelection?: boolean; // Make time selection optional
1314
}
1415

1516
export default function DatePickerDemo({
1617
value,
1718
onChange,
19+
allowTimeSelection = true, // Default to true for backward compatibility
1820
}: DatePickerDemoProps) {
1921
const today = new Date();
2022
const [date, setDate] = useState<Date | undefined>(
@@ -72,8 +74,16 @@ export default function DatePickerDemo({
7274
const handleDateSelect = (newDate: Date | undefined) => {
7375
if (!newDate) return;
7476
setDate(newDate);
75-
setTime(undefined);
7677

78+
if (!allowTimeSelection) {
79+
// If time selection is not allowed, use start of day
80+
const dateOnly = new Date(newDate);
81+
dateOnly.setHours(0, 0, 0, 0);
82+
onChange(dateOnly.toISOString());
83+
return;
84+
}
85+
86+
setTime(undefined);
7787
// Reset time in formData if time was previously set
7888
if (value) onChange("");
7989
};
@@ -91,11 +101,12 @@ export default function DatePickerDemo({
91101
<CalendarIcon className="mr-2 h-4 w-4" />
92102
{date ? (
93103
<span className="text-zinc-900 dark:text-white">
94-
{format(date, "PPP")} {time ? ` - ${time}` : ""}
104+
{format(date, "PPP")}{" "}
105+
{allowTimeSelection && time ? ` - ${time}` : ""}
95106
</span>
96107
) : (
97108
<span className="text-zinc-500 dark:text-zinc-400">
98-
Pick a date and time
109+
{allowTimeSelection ? "Pick a date and time" : "Pick a date"}
99110
</span>
100111
)}
101112
</Button>
@@ -113,37 +124,39 @@ export default function DatePickerDemo({
113124
className="p-2 sm:pe-5"
114125
disabled={[{ before: today }]}
115126
/>
116-
<div className="relative w-full max-sm:h-48 sm:w-40">
117-
<div className="absolute inset-0 py-4 max-sm:border-t border-zinc-200 dark:border-zinc-700">
118-
<ScrollArea className="h-full sm:border-s border-zinc-200 dark:border-zinc-700">
119-
<div className="space-y-3">
120-
<div className="flex h-5 shrink-0 items-center px-5">
121-
<p className="text-sm font-medium text-zinc-900 dark:text-white">
122-
{date ? format(date, "EEEE, d") : "Pick a date"}
123-
</p>
124-
</div>
125-
<div className="grid gap-1.5 px-5 max-sm:grid-cols-2">
126-
{timeSlots.map(({ time: timeSlot, available }) => (
127-
<Button
128-
key={timeSlot}
129-
variant={time === timeSlot ? "primary" : "outline"}
130-
size="sm"
131-
className={`w-full ${
132-
time === timeSlot
133-
? "bg-blue-600 text-white hover:bg-blue-700"
134-
: "bg-transparent border-zinc-300 dark:border-zinc-600 text-zinc-900 dark:text-white hover:bg-zinc-100 dark:hover:bg-zinc-700"
135-
}`}
136-
onClick={() => handleTimeSelect(timeSlot)}
137-
disabled={!available}
138-
>
139-
{timeSlot}
140-
</Button>
141-
))}
127+
{allowTimeSelection && (
128+
<div className="relative w-full max-sm:h-48 sm:w-40">
129+
<div className="absolute inset-0 py-4 max-sm:border-t border-zinc-200 dark:border-zinc-700">
130+
<ScrollArea className="h-full sm:border-s border-zinc-200 dark:border-zinc-700">
131+
<div className="space-y-3">
132+
<div className="flex h-5 shrink-0 items-center px-5">
133+
<p className="text-sm font-medium text-zinc-900 dark:text-white">
134+
{date ? format(date, "EEEE, d") : "Pick a date"}
135+
</p>
136+
</div>
137+
<div className="grid gap-1.5 px-5 max-sm:grid-cols-2">
138+
{timeSlots.map(({ time: timeSlot, available }) => (
139+
<Button
140+
key={timeSlot}
141+
variant={time === timeSlot ? "primary" : "outline"}
142+
size="sm"
143+
className={`w-full ${
144+
time === timeSlot
145+
? "bg-blue-600 text-white hover:bg-blue-700"
146+
: "bg-transparent border-zinc-300 dark:border-zinc-600 text-zinc-900 dark:text-white hover:bg-zinc-100 dark:hover:bg-zinc-700"
147+
}`}
148+
onClick={() => handleTimeSelect(timeSlot)}
149+
disabled={!available}
150+
>
151+
{timeSlot}
152+
</Button>
153+
))}
154+
</div>
142155
</div>
143-
</div>
144-
</ScrollArea>
156+
</ScrollArea>
157+
</div>
145158
</div>
146-
</div>
159+
)}
147160
</div>
148161
</PopoverContent>
149162
</Popover>

client/src/services/api.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ const tokenManager = {
3333
// --- Axios Instance ---
3434
export const api = axios.create({
3535
baseURL: BASE_URL,
36-
timeout: 60000, // Increased to 60 seconds for delivery creation with PDF/email
36+
timeout: 60000, // 60 seconds for delivery creation with PDF/email
3737
headers: {
3838
"Content-Type": "application/json",
3939
Accept: "application/json",
@@ -65,9 +65,7 @@ api.interceptors.request.use(
6565
config.headers?.set?.("Authorization", `Bearer ${token}`);
6666

6767
// Or fallback for older Axios (still safe)
68-
(config.headers as Record<string, string>)[
69-
"Authorization"
70-
] = `Bearer ${token}`;
68+
(config.headers as any)["Authorization"] = `Bearer ${token}`;
7169
}
7270
return config;
7371
},

0 commit comments

Comments
 (0)