diff --git a/src/components/PatientPortal/bookings/BookingForm.jsx b/src/components/PatientPortal/bookings/BookingForm.jsx
index 7a4270d..ef67280 100644
--- a/src/components/PatientPortal/bookings/BookingForm.jsx
+++ b/src/components/PatientPortal/bookings/BookingForm.jsx
@@ -3,6 +3,8 @@ import DoctorSelect from "./BookingDoctorSelect.jsx";
import TimeSlotPicker from "./SpecialTimeSlotPicker.jsx";
import { getAppointmentTypes, bookAppointment } from "../../../api/api.js";
+const API_BASE = import.meta.env.VITE_API_URL;
+
export default function BookingModal({ setShowModal, onBookingSuccess }) {
const [selectedDoctor, setSelectedDoctor] = useState(null);
const [date, setDate] = useState("");
diff --git a/src/components/PatientPortal/bookings/DoctorAvailabilityModal.jsx b/src/components/PatientPortal/bookings/DoctorAvailabilityModal.jsx
index fab34c0..a313f15 100644
--- a/src/components/PatientPortal/bookings/DoctorAvailabilityModal.jsx
+++ b/src/components/PatientPortal/bookings/DoctorAvailabilityModal.jsx
@@ -21,8 +21,31 @@ const generateSlots = () => {
return slots;
};
-// Helper to normalize backend time (remove seconds if present)
-const normalizeTime = (time) => time.slice(0, 5);
+// Helper to normalize backend time to HH:mm
+const normalizeTime = (time) => {
+ if (!time) return "";
+ if (Array.isArray(time)) {
+ const hours = String(time[0] ?? "0").padStart(2, "0");
+ const minutes = String(time[1] ?? "0").padStart(2, "0");
+ return `${hours}:${minutes}`;
+ }
+ if (typeof time !== "string") {
+ const raw = String(time);
+ const numericParts = raw.match(/\d+/g);
+ if (numericParts && numericParts.length >= 2) {
+ const hours = String(numericParts[0]).padStart(2, "0");
+ const minutes = String(numericParts[1]).padStart(2, "0");
+ return `${hours}:${minutes}`;
+ }
+ return raw;
+ }
+
+ const delimiter = time.includes(":") ? ":" : ",";
+ const parts = time.split(delimiter);
+ const hours = String(parts[0] ?? "0").padStart(2, "0");
+ const minutes = String(parts[1] ?? "0").padStart(2, "0");
+ return `${hours}:${minutes}`;
+};
export default function DoctorAvailabilityModal({ doctor, onClose }) {
const [date, setDate] = useState("");
diff --git a/src/components/PatientPortal/bookings/PaymentCancel.jsx b/src/components/PatientPortal/bookings/PaymentCancel.jsx
index 8329264..32df942 100644
--- a/src/components/PatientPortal/bookings/PaymentCancel.jsx
+++ b/src/components/PatientPortal/bookings/PaymentCancel.jsx
@@ -1,9 +1,8 @@
-
import { useEffect } from "react";
import { useNavigate } from "react-router-dom";
-export default function PaymentSuccess() {
+export default function PaymentCancel() {
const nav = useNavigate();
- useEffect(() => { nav("/patient/bookings"); }, []);
- return
❌ Payment Cancelled
;
+ useEffect(() => { nav("/patient-portal"); }, []);
+ return
❌ Payment Cancelled — redirecting...
;
}
diff --git a/src/components/PatientPortal/bookings/PaymentSuccess.jsx b/src/components/PatientPortal/bookings/PaymentSuccess.jsx
index 44a255e..43dbf00 100644
--- a/src/components/PatientPortal/bookings/PaymentSuccess.jsx
+++ b/src/components/PatientPortal/bookings/PaymentSuccess.jsx
@@ -3,6 +3,27 @@ import { useNavigate } from "react-router-dom";
export default function PaymentSuccess() {
const nav = useNavigate();
- useEffect(() => { nav("/patient/bookings"); }, []);
- return
✅ Payment Successful
;
+
+ useEffect(() => {
+ // The backend already marked it as SUCCESS before redirecting here.
+ const timer = setTimeout(() => {
+ nav("/patient-portal");
+ }, 2000);
+ return () => clearTimeout(timer);
+ }, [nav]);
+
+ return (
+
+
+
+
Payment Successful!
+
Your appointment has been confirmed.
+
Redirecting to your dashboard...
+
+
+ );
}
diff --git a/src/components/PatientPortal/bookings/SpecialTimeSlotPicker.jsx b/src/components/PatientPortal/bookings/SpecialTimeSlotPicker.jsx
index f30c893..0997c8d 100644
--- a/src/components/PatientPortal/bookings/SpecialTimeSlotPicker.jsx
+++ b/src/components/PatientPortal/bookings/SpecialTimeSlotPicker.jsx
@@ -1,6 +1,31 @@
import { useEffect, useState } from "react";
import { getAvailableSlots } from "../../../api/api";
+const normalizeTime = (time) => {
+ if (!time) return "";
+ if (Array.isArray(time)) {
+ const hours = String(time[0] ?? "0").padStart(2, "0");
+ const minutes = String(time[1] ?? "0").padStart(2, "0");
+ return `${hours}:${minutes}`;
+ }
+ if (typeof time !== "string") {
+ const raw = String(time);
+ const numericParts = raw.match(/\d+/g);
+ if (numericParts && numericParts.length >= 2) {
+ const hours = String(numericParts[0]).padStart(2, "0");
+ const minutes = String(numericParts[1]).padStart(2, "0");
+ return `${hours}:${minutes}`;
+ }
+ return raw;
+ }
+
+ const delimiter = time.includes(":") ? ":" : ",";
+ const parts = time.split(delimiter);
+ const hours = String(parts[0] ?? "0").padStart(2, "0");
+ const minutes = String(parts[1] ?? "0").padStart(2, "0");
+ return `${hours}:${minutes}`;
+};
+
export default function TimeSlotPicker({
doctorId,
date,
@@ -19,7 +44,7 @@ export default function TimeSlotPicker({
const data = await getAvailableSlots(doctorId, date);
// data = [{id, availableDate, availableTime}]
// map to string "HH:mm" for buttons
- setSlots(data.map((slot) => slot.availableTime.slice(0, 5)));
+ setSlots(data.map((slot) => normalizeTime(slot.availableTime)));
} catch (err) {
console.error(err);
} finally {
diff --git a/src/pages/DoctorViewPatient/DoctorViewComponents/DoctorNotesCard.jsx b/src/pages/DoctorViewPatient/DoctorViewComponents/DoctorNotesCard.jsx
index 984a34c..31d06c0 100644
--- a/src/pages/DoctorViewPatient/DoctorViewComponents/DoctorNotesCard.jsx
+++ b/src/pages/DoctorViewPatient/DoctorViewComponents/DoctorNotesCard.jsx
@@ -2,7 +2,7 @@ import { useMemo, useState, useEffect } from "react";
import { MessageSquare, Clock, User, Loader2, Plus } from "lucide-react";
import axios from "axios";
-const API_BASE = "http://localhost:8084";
+const API_BASE = "http://localhost:8080";
const DoctorNotesCard = ({ patientId }) => {
const [notes, setNotes] = useState([]);
diff --git a/src/pages/DoctorsPage/CriticalAlertPage.jsx b/src/pages/DoctorsPage/CriticalAlertPage.jsx
index 67d1671..747d660 100644
--- a/src/pages/DoctorsPage/CriticalAlertPage.jsx
+++ b/src/pages/DoctorsPage/CriticalAlertPage.jsx
@@ -2,7 +2,7 @@ import React, { useState, useEffect } from "react";
import AlertCard from "./componants/AlertCard";
import { AlertTriangle, RefreshCw, Shield } from "lucide-react";
-const API_BASE = "http://localhost:8084";
+const API_BASE = import.meta.env.VITE_API_URL;
/* ── JWT helpers ── */
const getToken = () => localStorage.getItem("token");
@@ -47,6 +47,30 @@ const fetchDoctorId = async () => {
return me?.id || me?.Id || null;
};
+const parseDateStr = (dateVal) => {
+ if (!dateVal) return 0;
+ if (Array.isArray(dateVal)) {
+ const [y, m, d, h = 0, min = 0, s = 0] = dateVal;
+ return new Date(y, m - 1, d, h, min, s).getTime();
+ }
+ return new Date(dateVal).getTime();
+};
+
+const formatAlertDate = (dateVal) => {
+ if (!dateVal) return "";
+ let d;
+ if (Array.isArray(dateVal)) {
+ const [y, m, day, h = 0, min = 0, s = 0] = dateVal;
+ d = new Date(y, m - 1, day, h, min, s);
+ } else {
+ d = new Date(dateVal);
+ }
+ return d.toLocaleString(undefined, {
+ year: "numeric", month: "short", day: "numeric",
+ hour: "2-digit", minute: "2-digit"
+ });
+};
+
function CriticalAlertPage() {
const [alerts, setAlerts] = useState([]);
const [loading, setLoading] = useState(true);
@@ -79,7 +103,9 @@ function CriticalAlertPage() {
if (!res.ok) throw new Error("Failed to load alerts");
const data = await res.json();
- setAlerts(Array.isArray(data) ? data : []);
+ const rawAlerts = Array.isArray(data) ? data : [];
+ rawAlerts.sort((a, b) => parseDateStr(b.recordedAt) - parseDateStr(a.recordedAt));
+ setAlerts(rawAlerts);
setLastRefresh(new Date());
} catch (e) {
setError(e.message || "Error loading alerts");
@@ -214,11 +240,7 @@ function CriticalAlertPage() {
normalRange={alert.normalRange}
severity={alert.severity}
room={alert.room}
- time={
- alert.recordedAt
- ? new Date(alert.recordedAt).toLocaleString()
- : ""
- }
+ time={formatAlertDate(alert.recordedAt)}
/>
))}
diff --git a/src/pages/DoctorsPage/DocDashboard.jsx b/src/pages/DoctorsPage/DocDashboard.jsx
index f320e55..98b9638 100644
--- a/src/pages/DoctorsPage/DocDashboard.jsx
+++ b/src/pages/DoctorsPage/DocDashboard.jsx
@@ -4,6 +4,7 @@ import ECGReaderPage from "./ECGReaderPage";
import ReportsPage from "./ReportsPage";
import DoctorMessagesPanel from "../../pages/DoctorViewPatient/DoctorViewComponents/DoctorMessagingDashboard";
+import AppointmentsCard from "../../components/PatientPortal/AppointmentsCard";
import { useNavigate } from "react-router-dom";
@@ -21,6 +22,7 @@ import {
TrendingUp,
Wifi,
MessageSquare, // NEW ICON for Messaging
+ Calendar, // NEW ICON for Appointments
} from "lucide-react";
/* ===================== Config ===================== */
@@ -405,6 +407,18 @@ function DocDashboard() {