Status function change to auto update
This commit is contained in:
@@ -1,7 +1,6 @@
|
|||||||
import { Formik, Form } from "formik";
|
import { Formik, Form } from "formik";
|
||||||
import * as yup from "yup";
|
import * as yup from "yup";
|
||||||
import { Button, Radio } from "@nextui-org/react";
|
import { Button } from "@nextui-org/react";
|
||||||
import { NextUIFormikRadioGroup } from "../components/NextUIFormikRadioButton";
|
|
||||||
import { NextUIFormikDatePicker } from "../components/NextUIFormikDatePicker";
|
import { NextUIFormikDatePicker } from "../components/NextUIFormikDatePicker";
|
||||||
import NextUIFormikInput from "../components/NextUIFormikInput";
|
import NextUIFormikInput from "../components/NextUIFormikInput";
|
||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
@@ -18,14 +17,15 @@ const validationSchema = yup.object().shape({
|
|||||||
status: yup.string().trim().required()
|
status: yup.string().trim().required()
|
||||||
});
|
});
|
||||||
|
|
||||||
const initialValues: any = {
|
const initialValues = {
|
||||||
date: "",
|
date: "",
|
||||||
time: "",
|
time: "",
|
||||||
location: "",
|
location: "",
|
||||||
postalCode: "",
|
postalCode: "",
|
||||||
status: ""
|
status: "Up coming" // Set the default status
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
export default function CreateSchedulePage() {
|
export default function CreateSchedulePage() {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
@@ -55,14 +55,9 @@ export default function CreateSchedulePage() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
data.dateTime = dateTime.toISOString();
|
data.dateTime = dateTime.toISOString();
|
||||||
|
|
||||||
data.location = data.location.trim();
|
data.location = data.location.trim();
|
||||||
|
data.postalCode = data.postalCode.trim();
|
||||||
if (typeof data.postalCode === 'string') {
|
data.status = "Up coming"; // Set status to "Up coming" explicitly
|
||||||
data.postalCode = data.postalCode.trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
data.status = data.status.trim();
|
|
||||||
|
|
||||||
console.log("Data to be sent:", data);
|
console.log("Data to be sent:", data);
|
||||||
|
|
||||||
@@ -74,8 +69,8 @@ export default function CreateSchedulePage() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="w-full h-full pb-12 pt-10">
|
<div className="w-full h-full pb-12 pt-20">
|
||||||
<div className="w-[400px] mx-auto p-6 bg-red-50 dark:bg-primary-950 border border-primary-100 rounded-2xl">
|
<div className="w-[410px] mx-auto p-6 bg-red-50 dark:bg-primary-950 border border-primary-100 rounded-2xl">
|
||||||
<div>
|
<div>
|
||||||
<Button
|
<Button
|
||||||
isIconOnly
|
isIconOnly
|
||||||
@@ -94,7 +89,7 @@ export default function CreateSchedulePage() {
|
|||||||
onSubmit={handleSubmit}
|
onSubmit={handleSubmit}
|
||||||
>
|
>
|
||||||
{({ isValid, dirty }) => (
|
{({ isValid, dirty }) => (
|
||||||
<Form className="flex flex-col gap-4 pt-5 items-center justify-center">
|
<Form className="flex flex-col gap-4 pt-5 ">
|
||||||
<div className="flex flex-col gap-5 w-[360px]">
|
<div className="flex flex-col gap-5 w-[360px]">
|
||||||
<NextUIFormikDatePicker
|
<NextUIFormikDatePicker
|
||||||
label="Date"
|
label="Date"
|
||||||
@@ -120,15 +115,6 @@ export default function CreateSchedulePage() {
|
|||||||
placeholder="123456"
|
placeholder="123456"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<NextUIFormikRadioGroup
|
|
||||||
label="Status"
|
|
||||||
name="status"
|
|
||||||
className="flex gap-2"
|
|
||||||
>
|
|
||||||
<Radio value="Up coming">Up coming</Radio>
|
|
||||||
<Radio value="On going">On going</Radio>
|
|
||||||
<Radio value="Ended">Ended</Radio>
|
|
||||||
</NextUIFormikRadioGroup>
|
|
||||||
<Button
|
<Button
|
||||||
type="submit"
|
type="submit"
|
||||||
color="primary"
|
color="primary"
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
import { useState, useEffect } from "react";
|
import { useState, useEffect } from "react";
|
||||||
import { Formik, Form } from "formik";
|
import { Formik, Form } from "formik";
|
||||||
import * as yup from "yup";
|
import * as yup from "yup";
|
||||||
import { Button, Radio } from "@nextui-org/react";
|
import { Button } from "@nextui-org/react";
|
||||||
import { NextUIFormikRadioGroup } from "../components/NextUIFormikRadioButton";
|
|
||||||
import { NextUIFormikDatePicker } from "../components/NextUIFormikDatePicker";
|
import { NextUIFormikDatePicker } from "../components/NextUIFormikDatePicker";
|
||||||
import NextUIFormikInput from "../components/NextUIFormikInput";
|
import NextUIFormikInput from "../components/NextUIFormikInput";
|
||||||
import { useNavigate, useParams } from "react-router-dom";
|
import { useNavigate, useParams } from "react-router-dom";
|
||||||
@@ -29,7 +28,6 @@ export default function EditSchedulePage() {
|
|||||||
time: "",
|
time: "",
|
||||||
location: "",
|
location: "",
|
||||||
postalCode: "",
|
postalCode: "",
|
||||||
status: ""
|
|
||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -78,10 +76,6 @@ export default function EditSchedulePage() {
|
|||||||
data.postalCode = data.postalCode.trim();
|
data.postalCode = data.postalCode.trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
data.status = data.status.trim();
|
|
||||||
|
|
||||||
console.log("Data to be sent:", data);
|
|
||||||
|
|
||||||
instance.put(`/schedule/${id}`, data)
|
instance.put(`/schedule/${id}`, data)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
console.log(res.data);
|
console.log(res.data);
|
||||||
@@ -93,8 +87,8 @@ export default function EditSchedulePage() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="w-full h-full pb-12 pt-10">
|
<div className="w-full h-full pb-12 pt-20">
|
||||||
<div className="w-[400px] mx-auto p-6 bg-red-50 dark:bg-primary-950 border border-primary-100 rounded-2xl">
|
<div className="w-[410px] mx-auto p-6 bg-red-50 dark:bg-primary-950 border border-primary-100 rounded-2xl">
|
||||||
<div>
|
<div>
|
||||||
<Button
|
<Button
|
||||||
isIconOnly
|
isIconOnly
|
||||||
@@ -114,7 +108,7 @@ export default function EditSchedulePage() {
|
|||||||
onSubmit={handleSubmit}
|
onSubmit={handleSubmit}
|
||||||
>
|
>
|
||||||
{({ isValid, dirty }) => (
|
{({ isValid, dirty }) => (
|
||||||
<Form className="flex flex-col gap-4 pt-5 items-center justify-center">
|
<Form className="flex flex-col gap-4 pt-4">
|
||||||
<div className="flex flex-col gap-5 w-[360px]">
|
<div className="flex flex-col gap-5 w-[360px]">
|
||||||
<NextUIFormikDatePicker
|
<NextUIFormikDatePicker
|
||||||
label="Date"
|
label="Date"
|
||||||
@@ -140,17 +134,6 @@ export default function EditSchedulePage() {
|
|||||||
placeholder="123456"
|
placeholder="123456"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
|
||||||
<NextUIFormikRadioGroup
|
|
||||||
label="Status"
|
|
||||||
name="status"
|
|
||||||
className="flex gap-2"
|
|
||||||
>
|
|
||||||
<Radio value="Up coming">Up coming</Radio>
|
|
||||||
<Radio value="On going">On going</Radio>
|
|
||||||
<Radio value="Ended">Ended</Radio>
|
|
||||||
</NextUIFormikRadioGroup>
|
|
||||||
</div>
|
|
||||||
<Button
|
<Button
|
||||||
type="submit"
|
type="submit"
|
||||||
color="primary"
|
color="primary"
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { useEffect, useState } from 'react';
|
|||||||
import instance from "../security/http";
|
import instance from "../security/http";
|
||||||
import { PencilSquareIcon, PlusIcon, TrashDeleteIcon } from "../icons";
|
import { PencilSquareIcon, PlusIcon, TrashDeleteIcon } from "../icons";
|
||||||
import { Table, TableHeader, TableColumn, TableBody, TableRow, TableCell, Button, Modal, ModalContent, ModalHeader, ModalBody, ModalFooter, useDisclosure, SortDescriptor, Link as NextUILink } from "@nextui-org/react";
|
import { Table, TableHeader, TableColumn, TableBody, TableRow, TableCell, Button, Modal, ModalContent, ModalHeader, ModalBody, ModalFooter, useDisclosure, SortDescriptor, Link as NextUILink } from "@nextui-org/react";
|
||||||
|
import dayjs from 'dayjs';
|
||||||
|
|
||||||
interface Schedule {
|
interface Schedule {
|
||||||
id: number;
|
id: number;
|
||||||
@@ -12,6 +13,12 @@ interface Schedule {
|
|||||||
status: string;
|
status: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const determineStatus = (dateTime: string): string => {
|
||||||
|
const now = dayjs();
|
||||||
|
const scheduleDateTime = dayjs(dateTime);
|
||||||
|
return scheduleDateTime.isAfter(now) ? "Up coming" : "Ended";
|
||||||
|
};
|
||||||
|
|
||||||
export default function ManageSchedulePage() {
|
export default function ManageSchedulePage() {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const [scheduleList, setScheduleList] = useState<Schedule[]>([]);
|
const [scheduleList, setScheduleList] = useState<Schedule[]>([]);
|
||||||
@@ -25,33 +32,63 @@ export default function ManageSchedulePage() {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
instance.get("/schedule")
|
instance.get("/schedule")
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
const schedules = res.data.map((schedule: Schedule) => ({
|
const schedules: Schedule[] = res.data.map((schedule: Schedule) => ({
|
||||||
...schedule,
|
...schedule,
|
||||||
dateTime: new Date(schedule.dateTime), // Convert to Date object
|
dateTime: new Date(schedule.dateTime),
|
||||||
|
status: determineStatus(schedule.dateTime),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
setScheduleList(schedules);
|
setScheduleList(schedules);
|
||||||
|
|
||||||
|
// Update status in the database
|
||||||
|
schedules.forEach((schedule: Schedule) => {
|
||||||
|
instance.patch(`/schedule/${schedule.id}/status`)
|
||||||
|
.catch((err) => {
|
||||||
|
console.error(`Error updating status for schedule ${schedule.id}:`, err.response ? err.response.data : err.message);
|
||||||
|
});
|
||||||
|
});
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.error("Error fetching schedules:", err);
|
console.error("Error fetching schedules:", err.response ? err.response.data : err.message);
|
||||||
});
|
});
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const interval = setInterval(() => {
|
||||||
|
setScheduleList(prevSchedules =>
|
||||||
|
prevSchedules.map((schedule: Schedule) => ({
|
||||||
|
...schedule,
|
||||||
|
status: determineStatus(schedule.dateTime),
|
||||||
|
}))
|
||||||
|
);
|
||||||
|
|
||||||
|
// Optionally update status in the database
|
||||||
|
scheduleList.forEach((schedule: Schedule) => {
|
||||||
|
instance.patch(`/schedule/${schedule.id}/status`)
|
||||||
|
.catch((err) => {
|
||||||
|
console.error(`Error updating status for schedule ${schedule.id}:`, err.response ? err.response.data : err.message);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}, 60000);
|
||||||
|
|
||||||
|
return () => clearInterval(interval);
|
||||||
|
}, [scheduleList]);
|
||||||
|
|
||||||
const handleEdit = (id: number) => {
|
const handleEdit = (id: number) => {
|
||||||
navigate(`edit-schedule/${id}`);
|
navigate(`edit-schedule/${id}`);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const deleteSchedule = () => {
|
const deleteSchedule = () => {
|
||||||
if (scheduleIdToDelete !== null) {
|
if (scheduleIdToDelete !== null) {
|
||||||
instance.delete(`/schedule/${scheduleIdToDelete}`)
|
instance.delete(`/schedule/${scheduleIdToDelete}`)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
console.log(res.data);
|
console.log(res.data);
|
||||||
setScheduleList((prev) => prev.filter(schedule => schedule.id !== scheduleIdToDelete));
|
setScheduleList(prev => prev.filter((schedule: Schedule) => schedule.id !== scheduleIdToDelete));
|
||||||
onOpenChange();
|
onOpenChange();
|
||||||
setScheduleIdToDelete(null);
|
setScheduleIdToDelete(null);
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.error("Error deleting schedule:", err);
|
console.error("Error deleting schedule:", err.response ? err.response.data : err.message);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -59,7 +96,7 @@ export default function ManageSchedulePage() {
|
|||||||
const sortScheduleList = (list: Schedule[], descriptor: SortDescriptor) => {
|
const sortScheduleList = (list: Schedule[], descriptor: SortDescriptor) => {
|
||||||
const { column, direction } = descriptor;
|
const { column, direction } = descriptor;
|
||||||
|
|
||||||
const sortedList = [...list].sort((a, b) => {
|
const sortedList = [...list].sort((a: Schedule, b: Schedule) => {
|
||||||
switch (column) {
|
switch (column) {
|
||||||
case "dateTime":
|
case "dateTime":
|
||||||
const dateA = new Date(a.dateTime);
|
const dateA = new Date(a.dateTime);
|
||||||
@@ -121,7 +158,7 @@ export default function ManageSchedulePage() {
|
|||||||
<TableColumn>Action</TableColumn>
|
<TableColumn>Action</TableColumn>
|
||||||
</TableHeader>
|
</TableHeader>
|
||||||
<TableBody>
|
<TableBody>
|
||||||
{sortedScheduleList.map((schedule) => (
|
{sortedScheduleList.map((schedule: Schedule) => (
|
||||||
<TableRow key={schedule.id}>
|
<TableRow key={schedule.id}>
|
||||||
<TableCell>{((schedule.dateTime as unknown) as Date).toLocaleDateString()}</TableCell>
|
<TableCell>{((schedule.dateTime as unknown) as Date).toLocaleDateString()}</TableCell>
|
||||||
<TableCell>{((schedule.dateTime as unknown) as Date).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" })}</TableCell>
|
<TableCell>{((schedule.dateTime as unknown) as Date).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" })}</TableCell>
|
||||||
@@ -171,6 +208,5 @@ export default function ManageSchedulePage() {
|
|||||||
</ModalContent>
|
</ModalContent>
|
||||||
</Modal>
|
</Modal>
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,22 +1,32 @@
|
|||||||
module.exports = (sequelize, DataTypes) => {
|
const { DataTypes } = require("sequelize");
|
||||||
const Schedule = sequelize.define("Schedule", {
|
|
||||||
dateTime: {
|
module.exports = (sequelize) => {
|
||||||
type: DataTypes.DATE,
|
const Schedule = sequelize.define(
|
||||||
allowNull: false
|
"Schedule",
|
||||||
|
{
|
||||||
|
id: {
|
||||||
|
type: DataTypes.UUID,
|
||||||
|
defaultValue: DataTypes.UUIDV4,
|
||||||
|
allowNull: false,
|
||||||
|
primaryKey: true,
|
||||||
|
},
|
||||||
|
dateTime: {
|
||||||
|
type: DataTypes.DATE,
|
||||||
|
allowNull: false
|
||||||
|
},
|
||||||
|
location: {
|
||||||
|
type: DataTypes.TEXT,
|
||||||
|
allowNull: false
|
||||||
|
},
|
||||||
|
postalCode: {
|
||||||
|
type: DataTypes.INTEGER(6),
|
||||||
|
allowNull: false
|
||||||
|
},
|
||||||
|
status: {
|
||||||
|
type: DataTypes.TEXT,
|
||||||
|
allowNull: false
|
||||||
|
},
|
||||||
},
|
},
|
||||||
location: {
|
|
||||||
type: DataTypes.TEXT,
|
|
||||||
allowNull: false
|
|
||||||
},
|
|
||||||
postalCode: {
|
|
||||||
type: DataTypes.INTEGER(6),
|
|
||||||
allowNull: false
|
|
||||||
},
|
|
||||||
status: {
|
|
||||||
type: DataTypes.TEXT,
|
|
||||||
allowNull: false
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
tableName: "schedule"
|
tableName: "schedule"
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
"axios": "^1.7.2",
|
"axios": "^1.7.2",
|
||||||
"bad-words": "^3.0.4",
|
"bad-words": "^3.0.4",
|
||||||
"cors": "^2.8.5",
|
"cors": "^2.8.5",
|
||||||
|
"dayjs": "^1.11.12",
|
||||||
"dotenv": "^16.4.5",
|
"dotenv": "^16.4.5",
|
||||||
"express": "^4.19.2",
|
"express": "^4.19.2",
|
||||||
"jsonwebtoken": "^9.0.2",
|
"jsonwebtoken": "^9.0.2",
|
||||||
|
|||||||
8
server/pnpm-lock.yaml
generated
8
server/pnpm-lock.yaml
generated
@@ -20,6 +20,9 @@ importers:
|
|||||||
cors:
|
cors:
|
||||||
specifier: ^2.8.5
|
specifier: ^2.8.5
|
||||||
version: 2.8.5
|
version: 2.8.5
|
||||||
|
dayjs:
|
||||||
|
specifier: ^1.11.12
|
||||||
|
version: 1.11.12
|
||||||
dotenv:
|
dotenv:
|
||||||
specifier: ^16.4.5
|
specifier: ^16.4.5
|
||||||
version: 16.4.5
|
version: 16.4.5
|
||||||
@@ -327,6 +330,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==}
|
resolution: {integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==}
|
||||||
engines: {node: '>= 0.10'}
|
engines: {node: '>= 0.10'}
|
||||||
|
|
||||||
|
dayjs@1.11.12:
|
||||||
|
resolution: {integrity: sha512-Rt2g+nTbLlDWZTwwrIXjy9MeiZmSDI375FvZs72ngxx8PDC6YXOeR3q5LAuPzjZQxhiWdRKac7RKV+YyQYfYIg==}
|
||||||
|
|
||||||
debug@2.6.9:
|
debug@2.6.9:
|
||||||
resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==}
|
resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@@ -1229,6 +1235,8 @@ snapshots:
|
|||||||
object-assign: 4.1.1
|
object-assign: 4.1.1
|
||||||
vary: 1.1.2
|
vary: 1.1.2
|
||||||
|
|
||||||
|
dayjs@1.11.12: {}
|
||||||
|
|
||||||
debug@2.6.9:
|
debug@2.6.9:
|
||||||
dependencies:
|
dependencies:
|
||||||
ms: 2.0.0
|
ms: 2.0.0
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ const router = express.Router();
|
|||||||
const { Schedule } = require('../models');
|
const { Schedule } = require('../models');
|
||||||
const { Op } = require("sequelize");
|
const { Op } = require("sequelize");
|
||||||
const yup = require("yup");
|
const yup = require("yup");
|
||||||
|
const dayjs = require('dayjs');
|
||||||
|
|
||||||
router.post("/", async (req, res) => {
|
router.post("/", async (req, res) => {
|
||||||
let data = req.body;
|
let data = req.body;
|
||||||
@@ -104,5 +105,27 @@ router.delete("/:id", async (req, res) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
router.patch("/:id/status", async (req, res) => {
|
||||||
|
try {
|
||||||
|
const { id } = req.params;
|
||||||
|
const schedule = await Schedule.findByPk(id);
|
||||||
|
|
||||||
|
if (!schedule) {
|
||||||
|
return res.status(404).json({ message: 'Schedule not found' });
|
||||||
|
}
|
||||||
|
|
||||||
|
const now = dayjs();
|
||||||
|
const scheduleDateTime = dayjs(schedule.dateTime);
|
||||||
|
|
||||||
|
const newStatus = scheduleDateTime.isAfter(now) ? "Up coming" : "Ended";
|
||||||
|
schedule.status = newStatus;
|
||||||
|
|
||||||
|
await schedule.save();
|
||||||
|
res.status(200).json(schedule);
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error updating status:", error); // Log the error
|
||||||
|
res.status(500).json({ message: error.message });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
module.exports = router;
|
module.exports = router;
|
||||||
Reference in New Issue
Block a user