Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions src/api/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,16 @@ export const getDoctorAppointments = async (doctorId) => {
}
};

export const verifyPaymentSuccess = async (orderId) => {
try {
const res = await API.get(`/payments/success/${orderId}`);
return res.data;
} catch (err) {
console.error("Error verifying payment:", err);
return null;
}
};

/* =========================
ADMIN – APPOINTMENTS
========================= */
Expand Down
37 changes: 10 additions & 27 deletions src/components/PatientPortal/AppointmentsCard.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { useEffect, useState } from "react";
import { Activity, Video, User } from "lucide-react";
import BookingModal from "../../components/PatientPortal/bookings/BookingPage";
import AppointmentsTable from "../../components/PatientPortal/bookings/AppointmentsTable";
import { getUserAppointments, getDoctorAppointments, confirmAppointmentDoctor } from "../../api/api.js";

const AppointmentsCard = ({ isDoctorView = false, doctorId = null }) => {
Expand Down Expand Up @@ -117,6 +118,15 @@ const AppointmentsCard = ({ isDoctorView = false, doctorId = null }) => {
{/* Body */}
{loading ? (
<p className="text-sm text-gray-500">Loading appointments...</p>
) : isDoctorView ? (
<div className="mt-4 -mx-4 sm:mx-0">
<AppointmentsTable
appointments={appointments}
isAdminView={false}
isDoctorView={true}
refreshData={fetchAppointments}
/>
</div>
) : appointments.length === 0 ? (
<p className="text-sm text-gray-500">No appointments found.</p>
) : (
Expand Down Expand Up @@ -163,33 +173,6 @@ const AppointmentsCard = ({ isDoctorView = false, doctorId = null }) => {
</a>
</div>
)}

{/* Doctor Confirmation Input */}
{isDoctorView &&
apt.appointmentStatus === "PENDING" &&
apt.paymentStatus === "SUCCESS" && (
<div className="mt-3 flex flex-col gap-2 relative z-10">
<input
type="text"
className="border border-gray-300 rounded px-2 py-1 text-sm w-full"
placeholder={
apt.appointmentType === "Physical"
? "Enter location"
: "Enter meeting link (Zoom, Meet)"
}
value={links[apt.appointmentId] || ""}
onChange={(e) =>
handleLinkChange(apt.appointmentId, e.target.value)
}
/>
<button
onClick={() => handleConfirm(apt)}
className="bg-green-600 hover:bg-green-700 text-white px-3 py-1.5 rounded-md text-xs w-fit transition-colors"
>
Confirm & Send Link
</button>
</div>
)}
</div>
</div>
);
Expand Down
83 changes: 32 additions & 51 deletions src/components/PatientPortal/bookings/AdminConfirmAppointments.jsx
Original file line number Diff line number Diff line change
@@ -1,68 +1,49 @@
import React, { useEffect, useState } from "react";
import { getAllAppointments, confirmAppointment } from "../../../api/api";
import { getAllAppointments } from "../../../api/api";
import AppointmentsTable from "./AppointmentsTable";

export default function AdminConfirmAppointments() {
const [appointments, setAppointments] = useState([]);
const [input, setInput] = useState({});
const [loading, setLoading] = useState(true);

useEffect(() => {
load();
}, []);

const load = async () => {
const data = await getAllAppointments();
setAppointments(Array.isArray(data) ? data : []);
};

const confirm = async (a) => {
const params =
a.appointmentType === "Physical"
? { physicalLocation: input[a.id] }
: { zoomLink: input[a.id] };

await confirmAppointment(a.id, params);
load();
setLoading(true);
try {
const data = await getAllAppointments();
setAppointments(Array.isArray(data) ? data : []);
} catch (e) {
console.error(e);
setAppointments([]);
} finally {
setLoading(false);
}
};

return (
<div className="p-6">
<h1 className="text-2xl font-bold mb-4">Admin Confirm Appointments</h1>

{appointments.map((a) => (
<div key={a.id} className="border p-4 mb-4 rounded shadow">
<p><b>Doctor:</b> {a.doctorName}</p>
<p><b>Specialty:</b> {a.specialty}</p>
<p><b>Type:</b> {a.appointmentType}</p>
<p><b>Date:</b> {a.bookingDate}</p>
<p><b>Time:</b> {a.bookingTime}</p>
<p><b>Status:</b> {a.appointmentStatus}</p>
<p><b>Payment:</b> {a.paymentStatus}</p>
<p><b>Location / Link:</b> {a.locationOrLink}</p>

{a.appointmentStatus === "PENDING" &&
a.paymentStatus === "SUCCESS" && (
<>
<input
className="border p-2 w-full my-2"
placeholder={
a.appointmentType === "Physical"
? "Enter location"
: "Enter meeting link"
}
onChange={(e) =>
setInput({ ...input, [a.id]: e.target.value })
}
/>
<button
className="bg-green-600 text-white px-4 py-2 rounded"
onClick={() => confirm(a)}
>
Confirm
</button>
</>
)}
<div className="p-6 bg-[#F0F6FF] min-h-[calc(100vh-80px)]">
<div className="mb-6">
<h1 className="text-2xl font-bold text-gray-900">Admin Confirm Appointments</h1>
<p className="text-sm text-gray-500 mt-1">
Review all system bookings across all doctors and manually set locations or meeting links.
</p>
</div>

{loading ? (
<p className="text-gray-500">Loading system appointments...</p>
) : (
<div className="bg-white rounded-xl shadow-lg border border-gray-100 p-1">
<AppointmentsTable
appointments={appointments}
isAdminView={true}
isDoctorView={false}
refreshData={load}
/>
</div>
))}
)}
</div>
);
}
Loading
Loading