diff --git a/src/api.js b/src/api.js index 0dc6500..9900b45 100644 --- a/src/api.js +++ b/src/api.js @@ -1 +1 @@ -export const API_BASE_URL = import.meta.env.VITE_API_URL; +export const API_BASE_URL = "http://localhost:8080/api"; \ No newline at end of file diff --git a/src/api/api.js b/src/api/api.js index fdea9c1..d4ba3c0 100644 --- a/src/api/api.js +++ b/src/api/api.js @@ -1,10 +1,9 @@ import axios from "axios"; const API = axios.create({ - baseURL: `${import.meta.env.VITE_API_URL}/api`, + baseURL: "http://localhost:8080/api", }); - /* ========================= Attach JWT token (if exists) ========================= */ @@ -48,6 +47,14 @@ export const getAvailableSlots = async (doctorId, date) => { return res.data; }; +export const getAllSlots = async (doctorId, date) => { + const res = await API.get(`/availability/doctor/${doctorId}/all`, { + params: { date }, + }); + return res.data; +}; + + export const saveAvailability = async ({ doctorId, date, times }) => { const res = await API.post("/availability", { doctorId, @@ -71,49 +78,65 @@ export const deleteAvailabilitySlot = async (id) => { APPOINTMENTS ========================= */ export const bookAppointment = async (data) => { - // POST /api/appointments/book const res = await API.post("/appointments/book", data); return res.data; }; export const getAppointmentTypes = async () => { - // GET /api/appointment-types const res = await API.get("/appointment-types"); return res.data; }; -// This matches your current backend controller: -// GET /api/appointments/user/success +// GET appointments for logged-in patient export const getUserAppointments = async () => { try { - const res = await API.get("/appointments/user/success"); - return res.data; + const response = await API.get("/appointments/user/success"); + return response.data; } catch (err) { - console.error("Error fetching appointments:", err); - return []; + console.error("Failed to fetch user appointments:", err); + throw err; } }; +export const rescheduleAppointment = async ({ appointmentId, newDate, newTime }) => { + const res = await API.put(`/appointments/reschedule/${appointmentId}`, { + bookingDate: newDate, + bookingTime: newTime, + }); + return res.data; +}; + /* ========================= ADMIN – APPOINTMENTS ========================= */ - -// This matches AdminAppointmentController: -// GET /api/admin/appointments export const getAllAppointments = async () => { const res = await API.get("/admin/appointments"); return res.data; }; -// This matches AdminAppointmentController: -// POST /api/admin/appointments/confirm/{id}?physicalLocation=... OR ?zoomLink=... -export const confirmAppointment = async (appointmentId, params) => { +export const updateAppointmentDate = async (appointmentId, bookingDate, bookingTime) => { + if (!appointmentId) throw new Error("Appointment ID is required"); + + const res = await API.put( + `/admin/appointments/update-date/${appointmentId}`, + { + bookingDate, + bookingTime + } + ); + + return res.data; +}; + +export const confirmAppointment = async (appointmentId, data) => { + if (!appointmentId) throw new Error("Appointment ID is required"); + + // Send data in JSON body const res = await API.post( `/admin/appointments/confirm/${appointmentId}`, - null, - { params } // axios will convert this to query string + data ); return res.data; }; - export default API; + diff --git a/src/components/PatientPortal/bookings/AdminConfirmAppointments.jsx b/src/components/PatientPortal/bookings/AdminConfirmAppointments.jsx index 721209a..46c3595 100644 --- a/src/components/PatientPortal/bookings/AdminConfirmAppointments.jsx +++ b/src/components/PatientPortal/bookings/AdminConfirmAppointments.jsx @@ -1,68 +1,219 @@ import React, { useEffect, useState } from "react"; -import { getAllAppointments, confirmAppointment } from "../../../api/api"; +import { + getAllAppointments, + confirmAppointment, + updateAppointmentDate, +} from "../../../api/api"; export default function AdminConfirmAppointments() { const [appointments, setAppointments] = useState([]); - const [input, setInput] = useState({}); + const [dates, setDates] = useState({}); + const [times, setTimes] = useState({}); + const [locations, setLocations] = useState({}); useEffect(() => { - load(); + loadAppointments(); }, []); - const load = async () => { - const data = await getAllAppointments(); - setAppointments(Array.isArray(data) ? data : []); + const loadAppointments = async () => { + try { + const data = await getAllAppointments(); + console.log("Appointments from backend:", data); + setAppointments(Array.isArray(data) ? data : []); + } catch (err) { + console.error("Failed to load appointments:", err); + } }; - const confirm = async (a) => { + const confirm = async (appointment) => { + const appointmentId = appointment.id || appointment.appointmentId; + if (!appointmentId) { + alert("Appointment ID is missing"); + return; + } + + const value = locations[appointmentId]; + if (!value) { + alert( + appointment.appointmentType === "Physical" + ? "Please enter a location" + : "Please enter a meeting link", + ); + return; + } + const params = - a.appointmentType === "Physical" - ? { physicalLocation: input[a.id] } - : { zoomLink: input[a.id] }; + appointment.appointmentType === "Physical" + ? { physicalLocation: value } + : { zoomLink: value }; + + try { + await confirmAppointment(appointmentId, params); + loadAppointments(); + setLocations((prev) => ({ ...prev, [appointmentId]: "" })); + } catch (err) { + console.error(err); + alert("Failed to confirm appointment. Check console for details."); + } + }; + + const updateDate = async (appointment) => { + const appointmentId = appointment.id || appointment.appointmentId; + + if (!appointmentId) { + alert("Appointment ID is missing"); + return; + } - await confirmAppointment(a.id, params); - load(); + const dateValue = dates[appointmentId]; + const timeValue = times[appointmentId]; + + if (!dateValue && !timeValue) { + alert("Please change date or time"); + return; + } + + try { + await updateAppointmentDate(appointmentId, dateValue, timeValue); + loadAppointments(); + + setDates((prev) => ({ ...prev, [appointmentId]: "" })); + setTimes((prev) => ({ ...prev, [appointmentId]: "" })); + } catch (err) { + console.error(err); + alert("Failed to update appointment. Check console for details."); + } }; return ( -
Doctor: {a.doctorName}
-Specialty: {a.specialty}
-Type: {a.appointmentType}
-Date: {a.bookingDate}
-Time: {a.bookingTime}
-Status: {a.appointmentStatus}
-Payment: {a.paymentStatus}
-Location / Link: {a.locationOrLink}
- - {a.appointmentStatus === "PENDING" && - a.paymentStatus === "SUCCESS" && ( - <> - - setInput({ ...input, [a.id]: e.target.value }) - } - /> - - > - )} -+ Doctor: {a.doctorName} +
+ ++ Specialty:{" "} + {a.specialty} +
+ ++ Type:{" "} + {a.appointmentType} +
+ ++ Status:{" "} + {a.appointmentStatus} +
+ ++ Payment:{" "} + {a.paymentStatus} +
+ ++ Location / Link:{" "} + {a.locationOrLink} +
+- Specialty: {selectedDoctor.specialty} -
+Consultation Fee: Rs. {selectedDoctor.consultationFee} diff --git a/src/components/PatientPortal/bookings/BookingForm.jsx b/src/components/PatientPortal/bookings/BookingForm.jsx index 7a4270d..5c5c18a 100644 --- a/src/components/PatientPortal/bookings/BookingForm.jsx +++ b/src/components/PatientPortal/bookings/BookingForm.jsx @@ -17,9 +17,8 @@ export default function BookingModal({ setShowModal, onBookingSuccess }) { const fetchTypes = async () => { try { const types = await getAppointmentTypes(); -setAppointmentTypes(types || []); -if (types?.length) setSelectedTypeId(types[0].id); - + setAppointmentTypes(types || []); + if (types?.length) setSelectedTypeId(types[0].id); } catch (err) { console.error("Failed to fetch appointment types:", err); } @@ -28,10 +27,15 @@ if (types?.length) setSelectedTypeId(types[0].id); }, []); const handleBooking = async () => { - if (!selectedDoctor || !date || !selectedTime || !reason || !selectedTypeId) { - return alert("Please fill all fields (including appointment type)"); -} - + if ( + !selectedDoctor || + !date || + !selectedTime || + !reason || + !selectedTypeId + ) { + return alert("Please fill all fields (including appointment type)"); + } const appointmentData = { doctorId: selectedDoctor.id, @@ -64,89 +68,131 @@ if (types?.length) setSelectedTypeId(types[0].id); alert("Appointment booked successfully! Click 'Pay Now' to pay."); } catch (err) { - console.log("BOOKING ERROR FULL:", err); - console.log("BOOKING ERROR DATA:", err.response?.data); - alert(err.response?.data?.error || err.response?.data?.message || "Error booking appointment"); -} - + console.log("BOOKING ERROR FULL:", err); + console.log("BOOKING ERROR DATA:", err.response?.data); + alert( + err.response?.data?.error || + err.response?.data?.message || + "Error booking appointment", + ); + } }; const handlePayNow = () => { - if (!appointmentId) return alert("Please book first!"); - - const fee = Number(selectedDoctor.consultationFee || 0).toFixed(2); - - window.location.href = - `${API_BASE}/api/payments/pay/${appointmentId}?amount=${fee}`; -}; + if (!appointmentId) return alert("Please book first!"); + const fee = Number(selectedDoctor.consultationFee || 0).toFixed(2); + window.location.href = `http://localhost:8080/api/payments/pay/${appointmentId}?amount=${fee}`; + }; return ( -