diff --git a/frontend/app/(app)/messages/page.tsx b/frontend/app/(app)/messages/page.tsx
new file mode 100644
index 0000000..0ab9e5a
--- /dev/null
+++ b/frontend/app/(app)/messages/page.tsx
@@ -0,0 +1,10 @@
+import { MessagesView } from "@/components/messages/messages-view";
+import { SidebarInset } from "@/components/ui/sidebar";
+
+export default function MessagesPage() {
+ return (
+
+
+
+ );
+}
diff --git a/frontend/app/(app)/prescriptions/page.tsx b/frontend/app/(app)/prescriptions/page.tsx
new file mode 100644
index 0000000..cc4c1cd
--- /dev/null
+++ b/frontend/app/(app)/prescriptions/page.tsx
@@ -0,0 +1,10 @@
+import { PrescriptionsView } from "@/components/prescriptions/prescriptions-view";
+import { SidebarInset } from "@/components/ui/sidebar";
+
+export default function PrescriptionsPage() {
+ return (
+
+
+
+ );
+}
diff --git a/frontend/components/appointments/appointments-view.tsx b/frontend/components/appointments/appointments-view.tsx
index f71e6ba..39b1303 100644
--- a/frontend/components/appointments/appointments-view.tsx
+++ b/frontend/components/appointments/appointments-view.tsx
@@ -1,12 +1,20 @@
"use client";
-import { CalendarClock, Clock, Plus, Stethoscope, Users } from "lucide-react";
+import {
+ CalendarClock,
+ CalendarDays,
+ Clock,
+ Plus,
+ Stethoscope,
+ Users,
+} from "lucide-react";
import { type ReactNode, useState } from "react";
import {
AddAppointmentDialog,
type NewAppointment,
} from "@/components/appointments/add-appointment-dialog";
+import { CalendarDialog } from "@/components/appointments/calendar-dialog";
import { Avatar, AvatarFallback } from "@/components/ui/avatar";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
@@ -17,7 +25,7 @@ import { Card } from "@/components/ui/card";
type ApptStatus = "confirmed" | "checked-in" | "completed" | "cancelled";
-type Appointment = {
+export type Appointment = {
time: string;
name: string;
initials: string;
@@ -171,7 +179,7 @@ function ApptRow({ appt }: { appt: Appointment }) {
);
}
-function ScheduleList({ items }: { items: Appointment[] }) {
+export function ScheduleList({ items }: { items: Appointment[] }) {
return (
{items.map((appt) => (
@@ -205,6 +213,7 @@ function Section({
export function AppointmentsView() {
const [addOpen, setAddOpen] = useState(false);
+ const [calendarOpen, setCalendarOpen] = useState(false);
const [schedule, setSchedule] = useState
(today);
// Insert a new (mock) appointment into today's schedule, kept time-sorted.
@@ -227,14 +236,25 @@ export function AppointmentsView() {
Today's clinic schedule and what's coming up. Sample data.
-
+
+
+
+
@@ -258,6 +278,12 @@ export function AppointmentsView() {
onOpenChange={setAddOpen}
open={addOpen}
/>
+
+
);
}
diff --git a/frontend/components/appointments/calendar-dialog.tsx b/frontend/components/appointments/calendar-dialog.tsx
new file mode 100644
index 0000000..2c71c1e
--- /dev/null
+++ b/frontend/components/appointments/calendar-dialog.tsx
@@ -0,0 +1,99 @@
+"use client";
+
+import { useState } from "react";
+
+import {
+ type Appointment,
+ ScheduleList,
+} from "@/components/appointments/appointments-view";
+import { Calendar } from "@/components/ui/calendar";
+import {
+ Dialog,
+ DialogDescription,
+ DialogHeader,
+ DialogPanel,
+ DialogPopup,
+ DialogTitle,
+} from "@/components/ui/dialog";
+
+// The mock schedule all belongs to this day (matches "Wednesday, June 5" in the
+// Appointments view). Month is zero-based, so 5 = June.
+const SCHEDULE_DATE = new Date(2026, 5, 5);
+
+const sameDay = (a: Date, b: Date) =>
+ a.getFullYear() === b.getFullYear() &&
+ a.getMonth() === b.getMonth() &&
+ a.getDate() === b.getDate();
+
+const fullDate = (d: Date) =>
+ d.toLocaleDateString("en-US", {
+ weekday: "long",
+ month: "long",
+ day: "numeric",
+ });
+
+// A month-grid calendar (à la Google Calendar) shown in a dialog. The day that
+// owns the mock schedule is ringed; selecting it lists those appointments, while
+// any other day shows an empty note. Mock-only — there's no per-date backend.
+export function CalendarDialog({
+ open,
+ onOpenChange,
+ schedule,
+}: {
+ open: boolean;
+ onOpenChange: (open: boolean) => void;
+ schedule: Appointment[];
+}) {
+ const [selected, setSelected] = useState(SCHEDULE_DATE);
+
+ const dayItems = sameDay(selected, SCHEDULE_DATE) ? schedule : [];
+
+ return (
+
+ );
+}
diff --git a/frontend/components/messages/messages-view.tsx b/frontend/components/messages/messages-view.tsx
new file mode 100644
index 0000000..3feecf8
--- /dev/null
+++ b/frontend/components/messages/messages-view.tsx
@@ -0,0 +1,226 @@
+"use client";
+
+import { Mail, SendHorizonal } from "lucide-react";
+import { useState } from "react";
+
+import { Avatar, AvatarFallback } from "@/components/ui/avatar";
+import { Button } from "@/components/ui/button";
+import {
+ Empty,
+ EmptyDescription,
+ EmptyHeader,
+ EmptyMedia,
+ EmptyTitle,
+} from "@/components/ui/empty";
+import { Textarea } from "@/components/ui/textarea";
+import { notify } from "@/lib/toast";
+import { cn } from "@/lib/utils";
+
+// All messages here are mock/placeholder data — there is no messaging backend.
+// They illustrate the email-style inbox layout (left list, right reading pane).
+
+type Message = {
+ id: string;
+ sender: string;
+ initials: string;
+ subject: string;
+ preview: string;
+ body: string[];
+ time: string;
+ read: boolean;
+};
+
+const seed: Message[] = [
+ {
+ id: "1",
+ sender: "Dr. Stein",
+ initials: "DS",
+ subject: "Lab results ready",
+ preview: "The lab results for Amina Yusuf are now available…",
+ body: [
+ "Hi,",
+ "The lab results for Amina Yusuf (file #10293) are now available for your review. The lipid panel and HbA1c both came back within the expected range.",
+ "Let me know if you'd like to adjust her current plan before the follow-up.",
+ "— Dr. Stein",
+ ],
+ time: "10:24",
+ read: false,
+ },
+ {
+ id: "2",
+ sender: "Dr. Okafor",
+ initials: "DO",
+ subject: "Re: Daniel Mensah intake",
+ preview: "Thanks for sending the intake notes over. I've…",
+ body: [
+ "Thanks for sending the intake notes over.",
+ "I've added him to tomorrow's schedule at 10:00. Could you confirm whether his prior records were imported?",
+ "— Dr. Okafor",
+ ],
+ time: "09:12",
+ read: false,
+ },
+ {
+ id: "3",
+ sender: "Care team",
+ initials: "CT",
+ subject: "Vaccination stock update",
+ preview: "A reminder that the seasonal vaccine stock has…",
+ body: [
+ "A reminder that the seasonal vaccine stock has been replenished.",
+ "Slots are open across the week — please direct eligible patients to the front desk to book.",
+ ],
+ time: "Yesterday",
+ read: true,
+ },
+ {
+ id: "4",
+ sender: "Reception",
+ initials: "RC",
+ subject: "Schedule change for Friday",
+ preview: "Two afternoon appointments were rescheduled…",
+ body: [
+ "Two afternoon appointments on Friday were rescheduled to next Monday at the patients' request.",
+ "The updated times are reflected in the schedule.",
+ ],
+ time: "Mon",
+ read: true,
+ },
+];
+
+export function MessagesView() {
+ const [messages, setMessages] = useState(seed);
+ const [selectedId, setSelectedId] = useState(null);
+ const [reply, setReply] = useState("");
+
+ const selected = messages.find((m) => m.id === selectedId) ?? null;
+
+ const open = (id: string) => {
+ setSelectedId(id);
+ setReply("");
+ setMessages((prev) =>
+ prev.map((m) => (m.id === id ? { ...m, read: true } : m)),
+ );
+ };
+
+ const send = () => {
+ if (!(reply.trim() && selected)) return;
+ notify.success("Reply sent", `To ${selected.sender}`);
+ setReply("");
+ };
+
+ return (
+
+ {/* Left: inbox list */}
+
+
+ {/* Right: reading pane or empty state */}
+
+ {selected ? (
+
+
+
+ {selected.subject}
+
+
+
+ {selected.initials}
+
+
+
+ {selected.sender}
+
+
+ to me · {selected.time}
+
+
+
+
+
+
+
+ {selected.body.map((para) => (
+
{para}
+ ))}
+
+
+
+
+
+ ) : (
+
+
+
+
+
+
+ No message selected
+
+ Choose a message from the inbox to read it here.
+
+
+
+
+ )}
+
+
+ );
+}
diff --git a/frontend/components/notes/notes-editor.tsx b/frontend/components/notes/notes-editor.tsx
index 28d8216..68cba19 100644
--- a/frontend/components/notes/notes-editor.tsx
+++ b/frontend/components/notes/notes-editor.tsx
@@ -19,6 +19,7 @@ import {
import { type ReactNode, useReducer, useState } from "react";
import { Button } from "@/components/ui/button";
+import { ConfirmDialog } from "@/components/ui/confirm-dialog";
import { Input } from "@/components/ui/input";
import {
Toolbar,
@@ -77,6 +78,7 @@ export function NotesEditor({
onDelete?: () => void;
}) {
const [title, setTitle] = useState(note.title);
+ const [confirmOpen, setConfirmOpen] = useState(false);
// Force a re-render on every editor transaction so the toolbar reflects the
// current formatting/undo state.
const [, bump] = useReducer((n: number) => n + 1, 0);
@@ -119,7 +121,7 @@ export function NotesEditor({
{onDelete && (