feat: add appointment date range filter

This commit is contained in:
Kailasdevdas
2026-05-13 14:20:51 +05:30
parent 988fbd28f1
commit 6889137164
3 changed files with 148 additions and 45 deletions
@@ -143,18 +143,51 @@ export const getAppointments = async (req, res) => {
const page = parseInt(req.query.page) || 1;
const limit = parseInt(req.query.limit) || 10;
const skip = (page - 1) * limit;
const { date, search } = req.query;
const { date, startDate, endDate, search } = req.query;
const where = {};
if (date) {
const hasSingleDate = date && date.trim() !== "";
const hasRange =
(startDate && startDate.trim() !== "") ||
(endDate && endDate.trim() !== "");
if (hasSingleDate) {
const start = new Date(date);
start.setHours(0, 0, 0, 0);
const end = new Date(date);
end.setDate(end.getDate() + 1);
where.date = { gte: start, lt: end };
end.setHours(23, 59, 59, 999);
where.date = {
gte: start,
lte: end,
};
}
if (search) {
if (!hasSingleDate && hasRange) {
const dateFilter = {};
if (startDate && startDate.trim() !== "") {
const start = new Date(startDate);
start.setHours(0, 0, 0, 0);
dateFilter.gte = start;
}
if (endDate && endDate.trim() !== "") {
const end = new Date(endDate);
end.setHours(23, 59, 59, 999);
dateFilter.lte = end;
}
where.date = dateFilter;
}
if (search && search.trim() !== "") {
where.OR = [
{ name: { contains: search, mode: "insensitive" } },
{ mobileNumber: { contains: search } },
@@ -165,24 +198,39 @@ export const getAppointments = async (req, res) => {
const [appointments, total] = await Promise.all([
prisma.appointment.findMany({
where,
include: { doctor: true, department: true },
orderBy: { createdAt: "desc" },
include: {
doctor: true,
department: true,
},
orderBy: {
createdAt: "desc",
},
skip,
take: limit,
}),
prisma.appointment.count({ where }),
prisma.appointment.count({
where,
}),
]);
res.status(200).json({
success: true,
data: appointments,
pagination: { total, page, limit, totalPages: Math.ceil(total / limit) },
pagination: {
total,
page,
limit,
totalPages: Math.ceil(total / limit),
},
});
} catch (error) {
console.error(error);
res
.status(500)
.json({ success: false, message: "Failed to fetch appointments" });
res.status(500).json({
success: false,
message: "Failed to fetch appointments",
});
}
};
+4
View File
@@ -4,12 +4,16 @@ export const getAppointmentsApi = async (
page = 1,
limit = 10,
date = "",
startDate = "",
endDate = "",
search = "",
) => {
const params = new URLSearchParams({
page: String(page),
limit: String(limit),
...(date && { date }),
...(startDate && { startDate }),
...(endDate && { endDate }),
...(search && { search }),
});
const res = await apiClient.get(`/appointments/getall?${params}`);
+54 -3
View File
@@ -40,7 +40,8 @@ export default function AppointmentPage() {
const [searchText, setSearchText] = useState("");
const [filterDoctor, setFilterDoctor] = useState("");
const [filterDate, setFilterDate] = useState("");
const [startDate, setStartDate] = useState("");
const [endDate, setEndDate] = useState("");
const [viewOpen, setViewOpen] = useState(false);
const [viewData, setViewData] = useState<any>(null);
@@ -56,6 +57,8 @@ export default function AppointmentPage() {
currentPage,
itemsPerPage,
filterDate,
startDate,
endDate,
searchText,
);
setAppointments(res?.data || []);
@@ -66,7 +69,7 @@ export default function AppointmentPage() {
} finally {
setLoading(false);
}
}, [currentPage, itemsPerPage, filterDate, searchText]);
}, [currentPage, itemsPerPage, filterDate, startDate, endDate, searchText]);
useEffect(() => {
fetchAll();
@@ -116,7 +119,11 @@ export default function AppointmentPage() {
<div className="flex flex-col md:flex-row md:justify-between md:items-center gap-4">
<h1 className="text-3xl font-bold">Appointments</h1>
<div className="flex flex-wrap gap-3">
<div className="flex flex-wrap gap-4 items-end">
<div className="flex flex-col gap-1">
<label className="text-xs font-medium text-muted-foreground">
Search
</label>
<Input
placeholder="Search name / phone..."
value={searchText}
@@ -126,7 +133,12 @@ export default function AppointmentPage() {
}}
className="w-[220px] text-base"
/>
</div>
<div className="flex flex-col gap-1">
<label className="text-xs font-medium text-muted-foreground">
Date
</label>
<Input
type="date"
value={filterDate}
@@ -135,8 +147,46 @@ export default function AppointmentPage() {
setCurrentPage(1);
}}
className="w-[160px] text-base"
disabled={!!startDate || !!endDate}
/>
</div>
<div className="flex flex-col gap-1">
<label className="text-xs font-medium text-muted-foreground">
From
</label>
<Input
type="date"
value={startDate}
onChange={(e) => {
setStartDate(e.target.value);
setCurrentPage(1);
}}
className="w-[160px] text-base"
disabled={!!filterDate}
/>
</div>
<div className="flex flex-col gap-1">
<label className="text-xs font-medium text-muted-foreground">
To
</label>
<Input
type="date"
value={endDate}
onChange={(e) => {
setEndDate(e.target.value);
setCurrentPage(1);
}}
className="w-[160px] text-base"
disabled={!!filterDate}
/>
</div>
<div className="flex flex-col gap-1">
<label className="text-xs font-medium text-muted-foreground">
Rows
</label>
<select
value={itemsPerPage}
onChange={(e) => {
@@ -149,6 +199,7 @@ export default function AppointmentPage() {
<option value={10}>10 / page</option>
<option value={20}>20 / page</option>
</select>
</div>
<Button
variant="outline"