diff --git a/app/api/pharmacy/order/route.ts b/app/api/pharmacy/order/route.ts
new file mode 100644
index 0000000..7bc78f1
--- /dev/null
+++ b/app/api/pharmacy/order/route.ts
@@ -0,0 +1,131 @@
+import { prisma } from "@/app/utils/db";
+import { requireUser } from "@/lib/requireUser";
+import { NextResponse } from "next/server";
+
+export async function POST(request: Request) {
+ try {
+ const user = await requireUser("PHARMACY");
+
+ if (!user || user.role !== "PHARMACY" || !user.pharmacy) {
+ return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
+ }
+
+ const body = await request.json();
+ const { prescriptionId, items } = body;
+
+ if (!prescriptionId || !items || items.length === 0) {
+ return NextResponse.json(
+ { error: "Missing required fields" },
+ { status: 400 }
+ );
+ }
+
+ // Verify prescription exists and belongs to a patient
+ const prescription = await prisma.prescription.findUnique({
+ where: { id: prescriptionId },
+ include: { Patient: true },
+ });
+
+ if (!prescription) {
+ return NextResponse.json(
+ { error: "Prescription not found" },
+ { status: 404 }
+ );
+ }
+
+ // Calculate total amount
+ const totalAmount = items.reduce(
+ (total: number, item: { price: number; quantity: number }) =>
+ total + item.price * item.quantity,
+ 0
+ );
+
+ // Create the order
+ const order = await prisma.order.create({
+ data: {
+ pharmacyId: user.pharmacy.id,
+ patientId: prescription.Patient.id,
+ prescriptionId: prescription.id,
+ totalAmount,
+ items: {
+ create: items.map(
+ (item: { name: string; price: number; quantity: number }) => ({
+ name: item.name,
+ price: item.price,
+ quantity: item.quantity,
+ })
+ ),
+ },
+ },
+ include: {
+ items: true,
+ Patient: true,
+ pharmacy: true,
+ },
+ });
+
+ return NextResponse.json(order, { status: 201 });
+ } catch (error) {
+ console.error("[ORDERS_POST]", error);
+ return NextResponse.json(
+ { error: "Internal server error" },
+ { status: 500 }
+ );
+ }
+}
+
+export async function GET(request: Request) {
+ try {
+ const user = await requireUser("PHARMACY");
+
+ if (!user || !["PHARMACY", "ADMIN"].includes(user.role)) {
+ return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
+ }
+
+ const { searchParams } = new URL(request.url);
+ const pharmacyId = searchParams.get("pharmacyId");
+ const patientId = searchParams.get("patientId");
+
+ let where = {};
+
+ if (user.role === "PHARMACY" && user.pharmacy) {
+ where = { pharmacyId: user.pharmacy.id };
+ } else if (pharmacyId) {
+ where = { pharmacyId };
+ }
+
+ if (patientId) {
+ where = { ...where, patientId };
+ }
+
+ const orders = await prisma.order.findMany({
+ where,
+ include: {
+ items: true,
+ Patient: {
+ include: {
+ user: {
+ select: {
+ email: true,
+ phone: true,
+ },
+ },
+ },
+ },
+ pharmacy: true,
+ prescription: true,
+ },
+ orderBy: {
+ createdAt: "desc",
+ },
+ });
+
+ return NextResponse.json(orders);
+ } catch (error) {
+ console.error("[ORDERS_GET]", error);
+ return NextResponse.json(
+ { error: "Internal server error" },
+ { status: 500 }
+ );
+ }
+}
diff --git a/app/dashboardNew/patient/page.tsx b/app/dashboardNew/patient/page.tsx
deleted file mode 100644
index d8c6884..0000000
--- a/app/dashboardNew/patient/page.tsx
+++ /dev/null
@@ -1,281 +0,0 @@
-import { prisma } from "@/app/utils/db";
-import { signOut } from "@/lib/auth";
-import { requireUser } from "@/lib/requireUser";
-import { redirect } from "next/navigation";
-import Link from "next/link";
-
-export default async function PatientDashboard() {
- const user = await requireUser("PATIENT");
-
- // Fetch complete patient data with all relations
- const patient = await prisma.patient.findUnique({
- where: {
- userId: user.id,
- },
- include: {
- geoLocation: true,
- prescriptions: {
- orderBy: {
- createdAt: "desc",
- },
- take: 5, // Only get the 5 most recent prescriptions
- },
- subscriptions: {
- include: {
- medicine: {
- include: {
- pharmacy: true,
- },
- },
- },
- orderBy: {
- nextDelivery: "asc",
- },
- },
- orders: {
- include: {
- medicines: {
- include: {
- medicine: true,
- },
- },
- pharmacy: true,
- payment: true,
- delivery: true,
- },
- orderBy: {
- createdAt: "desc",
- },
- take: 5, // Only get the 5 most recent orders
- },
- },
- });
-
- if (!patient) {
- redirect("/auth/complete-profile");
- }
-
- return (
-
- {/* Header Section */}
-
-
-
Welcome, {patient.fullName}
-
-
-
-
- {/* Personal Information Card */}
-
-
Personal Information
-
-
-
Date of Birth
-
{new Date(patient.dateOfBirth).toLocaleDateString()}
-
-
-
Gender
-
{patient.gender || "Not specified"}
-
-
-
-
-
- {/* Address Card */}
-
-
Address
-
-
{patient.streetAddress}
-
- {patient.city}, {patient.stateProvince} {patient.postalCode}
-
-
{patient.country}
- {patient.geoLocation && (
-
- Location coordinates: {patient.geoLocation.latitude.toFixed(4)},{" "}
- {patient.geoLocation.longitude.toFixed(4)}
-
- )}
-
-
-
- {/* Medical Information Card */}
-
-
Medical Information
-
-
-
Medical Conditions
-
- {patient.medicalConditions || "None reported"}
-
-
-
-
Allergies
-
- {patient.allergies || "None reported"}
-
-
-
-
-
- {/* Recent Prescriptions Card */}
-
-
-
Recent Prescriptions
-
- View All
-
-
- {patient.prescriptions.length > 0 ? (
-
- {patient.prescriptions.map((prescription) => (
-
- ))}
-
- ) : (
-
No prescriptions found
- )}
-
-
- {/* Active Subscriptions Card */}
-
-
-
Active Subscriptions
-
- View All
-
-
- {patient.subscriptions.length > 0 ? (
-
- {patient.subscriptions.map((subscription) => (
-
-
-
-
- {subscription.medicine.name} -{" "}
- {subscription.medicine.pharmacy.name}
-
-
{subscription.frequency} day delivery frequency
-
-
-
- Next delivery:{" "}
- {new Date(subscription.nextDelivery).toLocaleDateString()}
-
-
- {subscription.medicine.pharmacy.city}
-
-
-
-
- ))}
-
- ) : (
-
No active subscriptions
- )}
-
-
- {/* Recent Orders Card */}
-
-
-
Recent Orders
-
- View All
-
-
- {patient.orders.length > 0 ? (
-
- {patient.orders.map((order) => (
-
-
-
-
- Order #{order.id.slice(-6).toUpperCase()}
-
-
- {order.pharmacy.name} -{" "}
- {new Date(order.createdAt).toLocaleDateString()}
-
-
- {order.medicines.slice(0, 2).map((item) => (
-
- {item.quantity}x {item.medicine.name}
-
- ))}
- {order.medicines.length > 2 && (
-
- +{order.medicines.length - 2} more items
-
- )}
-
-
-
-
- ${order.totalAmount.toFixed(2)}
-
-
- Status: {order.delivery ? "Shipped" : "Processing"}
-
- {order.delivery?.trackingId && (
-
- Track #{order.delivery.trackingId}
-
- )}
-
-
-
- ))}
-
- ) : (
-
No recent orders
- )}
-
-
- );
-}
diff --git a/app/layout.tsx b/app/layout.tsx
index b3963b0..8e583ca 100644
--- a/app/layout.tsx
+++ b/app/layout.tsx
@@ -1,33 +1,27 @@
-import type React from "react"
-import type { Metadata } from "next"
-import { Inter } from "next/font/google"
-import "./globals.css"
-import { ThemeProvider } from "@/components/theme-provider"
+import type React from "react";
+import type { Metadata } from "next";
+import { Inter } from "next/font/google";
+import "./globals.css";
+import { ThemeProvider } from "@/components/theme-provider";
-const inter = Inter({ subsets: ["latin"] })
+const inter = Inter({ subsets: ["latin"] });
export const metadata: Metadata = {
title: "Medi-Link",
description: "Bridging Patients & Pharmacies Effortlessly",
- generator: 'v0.dev'
-}
+ generator: "v0.dev",
+};
export default function RootLayout({
children,
}: Readonly<{
- children: React.ReactNode
+ children: React.ReactNode;
}>) {
return (
-
-
- {children}
-
-
+ {children}
- )
+ );
}
-
-
-import './globals.css'
\ No newline at end of file
+import "./globals.css";
diff --git a/app/login/page.tsx b/app/login/page.tsx
index 555cff6..addfa41 100644
--- a/app/login/page.tsx
+++ b/app/login/page.tsx
@@ -50,9 +50,7 @@ export default function LoginPage() {
// Redirect based on the role from session
router.push(
- session.user.role === "PHARMACY"
- ? "/dashboardNew/pharmacy"
- : "/dashboardNew/patient"
+ session.user.role === "PHARMACY" ? "/site/pharmacy" : "/site/patient"
);
} catch (error) {
toast({
diff --git a/app/pharmacy/orders/page.tsx b/app/pharmacy/orders/page.tsx
index 4265ea7..c66da24 100644
--- a/app/pharmacy/orders/page.tsx
+++ b/app/pharmacy/orders/page.tsx
@@ -1,46 +1,25 @@
-"use client"
+"use client";
-import { useEffect, useState } from "react"
-import { useRouter } from "next/navigation"
-import Image from "next/image"
-import { Search, Filter } from "lucide-react"
-import { Button } from "@/components/ui/button"
-import { Input } from "@/components/ui/input"
-import PharmacySidebar from "@/components/pharmacy-sidebar"
-import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
+import { useEffect, useState } from "react";
+import { useRouter } from "next/navigation";
+import Image from "next/image";
+import { Search, Filter } from "lucide-react";
+import { Button } from "@/components/ui/button";
+import { Input } from "@/components/ui/input";
+import PharmacySidebar from "@/components/pharmacy-sidebar";
+import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
type Order = {
- id: number
- name: string
- date: string
- avatar: string
- status: "pending" | "accepted" | "completed"
-}
+ id: number;
+ name: string;
+ date: string;
+ avatar: string;
+ status: "pending" | "accepted" | "completed";
+};
export default function PharmacyOrdersPage() {
- const [user, setUser] = useState(null)
- const router = useRouter()
-
- useEffect(() => {
- // Check if user is logged in
- const userData = localStorage.getItem("user")
- if (!userData) {
- router.push("/login")
- return
- }
-
- const parsedUser = JSON.parse(userData)
- if (parsedUser.type !== "pharmacy") {
- router.push("/login")
- return
- }
-
- setUser(parsedUser)
- }, [router])
-
- if (!user) {
- return null // Loading state
- }
+ const [user, setUser] = useState(null);
+ const router = useRouter();
return (
@@ -100,53 +79,67 @@ export default function PharmacyOrdersPage() {
- {[...pendingOrders, ...acceptedOrders, ...completedOrders].map((order) => (
-
-
-
-
-
+ {[...pendingOrders, ...acceptedOrders, ...completedOrders].map(
+ (order) => (
+
+
+
+
+
+
+
+
{order.name}
+
+ {order.date}
+
+
-
-
{order.name}
-
{order.date}
-
-
-
-
-
+
-
- ))}
+ )
+ )}
{pendingOrders.map((order) => (
-
+
@@ -164,10 +157,17 @@ export default function PharmacyOrdersPage() {
-
+
Order Info
-
+
Pending
@@ -178,7 +178,10 @@ export default function PharmacyOrdersPage() {
{acceptedOrders.map((order) => (
-
+
@@ -196,10 +199,17 @@ export default function PharmacyOrdersPage() {
-
+
Order Info
-
+
Accepted
@@ -210,7 +220,10 @@ export default function PharmacyOrdersPage() {
{completedOrders.map((order) => (
-
+
@@ -228,10 +241,17 @@ export default function PharmacyOrdersPage() {
-
+
Order Info
-
+
Completed
@@ -244,7 +264,7 @@ export default function PharmacyOrdersPage() {
- )
+ );
}
const pendingOrders: Order[] = [
@@ -262,7 +282,7 @@ const pendingOrders: Order[] = [
avatar: "/placeholder.svg?height=64&width=64",
status: "pending",
},
-]
+];
const acceptedOrders: Order[] = [
{
@@ -279,7 +299,7 @@ const acceptedOrders: Order[] = [
avatar: "/placeholder.svg?height=64&width=64",
status: "accepted",
},
-]
+];
const completedOrders: Order[] = [
{
@@ -296,5 +316,4 @@ const completedOrders: Order[] = [
avatar: "/placeholder.svg?height=64&width=64",
status: "completed",
},
-]
-
+];
diff --git a/app/site/components/pharmacy/OrderForm.tsx b/app/site/components/pharmacy/OrderForm.tsx
new file mode 100644
index 0000000..dc69df4
--- /dev/null
+++ b/app/site/components/pharmacy/OrderForm.tsx
@@ -0,0 +1,175 @@
+"use client";
+
+import { useState } from "react";
+import { useRouter } from "next/navigation";
+import { Button } from "@/components/ui/button";
+import { Input } from "@/components/ui/input";
+import { toast } from "sonner";
+
+interface OrderItem {
+ name: string;
+ price: string;
+ quantity: string;
+}
+
+export function OrderForm({ prescription }: { prescription: string }) {
+ const router = useRouter();
+ const [items, setItems] = useState
([
+ { name: "", price: "", quantity: "1" },
+ ]);
+ const [isSubmitting, setIsSubmitting] = useState(false);
+
+ // Calculate total amount by parsing the string values
+ const totalAmount = items.reduce((sum, item) => {
+ const price = parseFloat(item.price) || 0;
+ const quantity = parseInt(item.quantity) || 0;
+ return sum + price * quantity;
+ }, 0);
+
+ const handleAddItem = () => {
+ setItems([...items, { name: "", price: "", quantity: "1" }]);
+ };
+
+ const handleRemoveItem = (index: number) => {
+ if (items.length > 1) {
+ const newItems = [...items];
+ newItems.splice(index, 1);
+ setItems(newItems);
+ }
+ };
+
+ const handleItemChange = (
+ index: number,
+ field: keyof OrderItem,
+ value: string
+ ) => {
+ const newItems = [...items];
+ newItems[index] = { ...newItems[index], [field]: value };
+ setItems(newItems);
+ };
+
+ const handleSubmit = async (e: React.FormEvent) => {
+ e.preventDefault();
+ setIsSubmitting(true);
+
+ // Convert string values to numbers before submitting
+ const itemsToSubmit = items.map((item) => ({
+ ...item,
+ price: parseFloat(item.price) || 0,
+ quantity: parseInt(item.quantity) || 1,
+ }));
+
+ const createOrderPromise = new Promise(async (resolve, reject) => {
+ try {
+ const response = await fetch("/api/pharmacy/order", {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ },
+ body: JSON.stringify({
+ prescriptionId: prescription,
+ items: itemsToSubmit, // Use the converted items
+ }),
+ });
+
+ if (!response.ok) {
+ throw new Error("Failed to create order");
+ }
+
+ const data = await response.json();
+ resolve(data);
+ router.push("/pharmacy/orders");
+ } catch (error) {
+ console.error("Error creating order:", error);
+ reject(error);
+ } finally {
+ setIsSubmitting(false);
+ }
+ });
+
+ toast.promise(createOrderPromise, {
+ loading: "Creating order...",
+ success: (data: any) => {
+ return `Order #${data.id} has been created successfully`;
+ },
+ error: "Failed to create order. Please try again.",
+ });
+ };
+
+ return (
+
+ );
+}
diff --git a/app/site/patient/page.tsx b/app/site/patient/page.tsx
new file mode 100644
index 0000000..ce64610
--- /dev/null
+++ b/app/site/patient/page.tsx
@@ -0,0 +1,31 @@
+import { prisma } from "@/app/utils/db";
+import { signOut } from "@/lib/auth";
+import { requireUser } from "@/lib/requireUser";
+import { redirect } from "next/navigation";
+import Link from "next/link";
+
+export default async function PatientDashboard() {
+ const user = await requireUser("PATIENT");
+
+ // Fetch complete patient data with all relations
+ const patient = await prisma.patient.findUnique({
+ where: {
+ userId: user.id,
+ },
+ include: {
+ geoLocation: true,
+ prescriptions: {
+ orderBy: {
+ createdAt: "desc",
+ },
+ take: 5, // Only get the 5 most recent prescriptions
+ },
+ },
+ });
+
+ if (!patient) {
+ redirect("/auth/complete-profile");
+ }
+
+ return This is patient header
;
+}
diff --git a/app/dashboardNew/pharmacy/page.tsx b/app/site/pharmacy/page.tsx
similarity index 82%
rename from app/dashboardNew/pharmacy/page.tsx
rename to app/site/pharmacy/page.tsx
index 36fc160..2f99c28 100644
--- a/app/dashboardNew/pharmacy/page.tsx
+++ b/app/site/pharmacy/page.tsx
@@ -2,7 +2,7 @@ import { signOut } from "@/lib/auth";
import { requireUser } from "@/lib/requireUser";
export default async function PharmacyDashboard() {
- const user = await requireUser("PHARMACY"); // Note: You're requiring PHARMACY role but component is named PatientDashboard
+ const user = await requireUser("PHARMACY");
return (
diff --git a/app/site/pharmacy/prescriptions/[prescriptionId]/page.tsx b/app/site/pharmacy/prescriptions/[prescriptionId]/page.tsx
new file mode 100644
index 0000000..2fc933b
--- /dev/null
+++ b/app/site/pharmacy/prescriptions/[prescriptionId]/page.tsx
@@ -0,0 +1,21 @@
+import { OrderForm } from "@/app/site/components/pharmacy/OrderForm";
+import { requireUser } from "@/lib/requireUser";
+
+export default async function ReviewOrder({
+ params,
+}: {
+ params: Promise<{ prescriptionId: string }>;
+}) {
+ const user = await requireUser("PHARMACY");
+
+ const { prescriptionId } = await params;
+
+ return (
+
+
Hello {user.pharmacy?.id}
+ Hello {user.id}
+ This is prescription {prescriptionId}
+
+
+ );
+}
diff --git a/middleware.ts b/middleware.ts
index 6fbca47..f10c48c 100644
--- a/middleware.ts
+++ b/middleware.ts
@@ -6,11 +6,11 @@ import { requireUser } from "./lib/requireUser";
// Define the protected routes and their allowed roles
const protectedRoutes = [
{
- path: "/dashboardNew/patient",
+ path: "/site/patient",
roles: ["PATIENT"],
},
{
- path: "/dashboardNew/pharmacy",
+ path: "/site/pharmacy",
roles: ["PHARMACY"],
},
{
diff --git a/prisma/schema.prisma b/prisma/schema.prisma
index b45d621..26d252b 100644
--- a/prisma/schema.prisma
+++ b/prisma/schema.prisma
@@ -20,7 +20,6 @@ model User {
sessions Session[]
authenticator Authenticator[]
- // Profile relations (only one will be populated based on role)
patient Patient?
pharmacy Pharmacy?
}
@@ -31,7 +30,6 @@ enum Role {
ADMIN
}
-// Authentication models (unchanged from your current schema)
model Account {
id String @id @default(auto()) @map("_id") @db.ObjectId
userId String @db.ObjectId
@@ -102,9 +100,9 @@ model Patient {
}
model Pharmacy {
- id String @id @default(auto()) @map("_id") @db.ObjectId
- userId String @unique @db.ObjectId
- user User @relation(fields: [userId], references: [id])
+ id String @id @default(auto()) @map("_id") @db.ObjectId
+ userId String @unique @db.ObjectId
+ user User @relation(fields: [userId], references: [id])
name String
phone String
streetAddress String
@@ -112,57 +110,49 @@ model Pharmacy {
stateProvince String
postalCode String
country String
- geoLocation GeoLocation? @relation(fields: [geoLocationId], references: [id])
- geoLocationId String? @db.ObjectId
- medicines Medicine[]
+ geoLocation GeoLocation? @relation(fields: [geoLocationId], references: [id])
+ geoLocationId String? @db.ObjectId
orders Order[]
- licenseNumber String @unique
+ licenseNumber String @unique
licenseFile String?
- verified Boolean @default(false)
+ verified Boolean @default(false)
+ Prescription Prescription[]
}
model Prescription {
- id String @id @default(auto()) @map("_id") @db.ObjectId
- PharmacistId String @db.ObjectId
- Patient Patient @relation(fields: [PharmacistId], references: [id])
- fileUrl String // URL to the uploaded prescription image/file
- createdAt DateTime @default(now())
-}
-
-model Medicine {
- id String @id @default(auto()) @map("_id") @db.ObjectId
- pharmacyId String @db.ObjectId
- pharmacy Pharmacy @relation(fields: [pharmacyId], references: [id])
- name String
- price Float
- stock Int
- createdAt DateTime @default(now())
- updatedAt DateTime @updatedAt
- OrderMedicine OrderMedicine[]
- Subscription Subscription[]
+ id String @id @default(auto()) @map("_id") @db.ObjectId
+ patientId String @db.ObjectId
+ patient Patient @relation(fields: [patientId], references: [id])
+ fileUrl String // URL to the uploaded prescription image/file
+ createdAt DateTime @default(now())
+ pharmacyId String @db.ObjectId
+ pharmacy Pharmacy @relation(fields: [pharmacyId], references: [id])
+ Order Order[]
}
model Order {
- id String @id @default(auto()) @map("_id") @db.ObjectId
- PharmacistId String @db.ObjectId
- Patient Patient @relation(fields: [PharmacistId], references: [id])
- pharmacyId String @db.ObjectId
- pharmacy Pharmacy @relation(fields: [pharmacyId], references: [id])
- medicines OrderMedicine[]
- totalAmount Float
- payment Payment?
- delivery Delivery?
- createdAt DateTime @default(now())
- updatedAt DateTime @updatedAt
-}
-
-model OrderMedicine {
- id String @id @default(auto()) @map("_id") @db.ObjectId
- orderId String @db.ObjectId
- order Order @relation(fields: [orderId], references: [id])
- medicineId String @db.ObjectId
- medicine Medicine @relation(fields: [medicineId], references: [id])
- quantity Int
+ id String @id @default(auto()) @map("_id") @db.ObjectId
+ pharmacyId String @db.ObjectId
+ pharmacy Pharmacy @relation(fields: [pharmacyId], references: [id])
+ items OrderItem[]
+ totalAmount Float
+ payment Payment?
+ delivery Delivery?
+ createdAt DateTime @default(now())
+ updatedAt DateTime @updatedAt
+ Patient Patient? @relation(fields: [patientId], references: [id])
+ patientId String? @db.ObjectId
+ prescriptionId String @db.ObjectId
+ prescription Prescription @relation(fields: [prescriptionId], references: [id])
+}
+
+model OrderItem {
+ id String @id @default(auto()) @map("_id") @db.ObjectId
+ orderId String @db.ObjectId
+ order Order @relation(fields: [orderId], references: [id])
+ name String
+ price Float
+ quantity Int
}
model Payment {
@@ -177,9 +167,7 @@ model Subscription {
id String @id @default(auto()) @map("_id") @db.ObjectId
PharmacistId String @db.ObjectId
Patient Patient @relation(fields: [PharmacistId], references: [id])
- medicineId String @db.ObjectId
- medicine Medicine @relation(fields: [medicineId], references: [id])
- frequency Int // Days between each delivery
+ frequency Int
nextDelivery DateTime
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt