This repository has been archived on 2026-08-11. You can view files and clone it, but cannot push or open issues or pull requests.
Gishen-Mob/app/(root)/(screens)/prescription/review.tsx
kirukib 7310a349c5 Add Gishen mobile app with complete demo shopping and care flows.
Ship Expo Router screens, seeded stores, and polished UX so auth, shop, checkout, prescriptions, loyalty, family, and account processes work end-to-end offline.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-07 01:21:32 +03:00

223 lines
7.9 KiB
TypeScript

import { router } from "expo-router";
import { useMemo, useState } from "react";
import { Alert, Image, ScrollView, View } from "react-native";
import { Badge } from "@/components/ui/Badge";
import { Button } from "@/components/ui/Button";
import { Card } from "@/components/ui/Card";
import { Chip } from "@/components/ui/Chip";
import { Field } from "@/components/ui/Field";
import { AppHeader } from "@/components/ui/Header";
import { Screen } from "@/components/ui/Screen";
import { Text } from "@/components/ui/Text";
import { products } from "@/lib/data/products";
import { routes } from "@/lib/routes";
import { useAuthStore } from "@/lib/stores/authStore";
import { useCartStore } from "@/lib/stores/cartStore";
import { useFamilyStore } from "@/lib/stores/familyStore";
import { useLocationStore } from "@/lib/stores/locationStore";
import { usePrescriptionStore } from "@/lib/stores/prescriptionStore";
import { colors, gutter, radii } from "@/lib/theme";
function matchStatus(name: string): "ready" | "review" | "unavailable" {
const hit = products.find((p) =>
p.name.toLowerCase().includes(name.trim().toLowerCase())
);
if (!hit) return "review";
if (!hit.inStock) return "unavailable";
return "ready";
}
export default function RxReviewScreen() {
const draftImages = usePrescriptionStore((s) => s.draftImages);
const setDraftImages = usePrescriptionStore((s) => s.setDraftImages);
const addPrescription = usePrescriptionStore((s) => s.addPrescription);
const addProduct = useCartStore((s) => s.addProduct);
const setFulfillment = useLocationStore((s) => s.setFulfillment);
const user = useAuthStore((s) => s.user);
const members = useFamilyStore((s) => s.members);
const activeMemberId = useFamilyStore((s) => s.activeMemberId);
const activeMember = members.find((m) => m.id === activeMemberId);
const [patientName, setPatientName] = useState(
activeMember?.name || user?.name || ""
);
const [memberId, setMemberId] = useState<string | null>(activeMemberId);
const [medicineName, setMedicineName] = useState("Metformin 500mg");
const [daysSupply, setDaysSupply] = useState("30");
const [list, setList] = useState("Metformin 500mg, Vitamin B12");
const [notes, setNotes] = useState("");
const medicines = useMemo(() => {
return list
.split(",")
.map((s) => s.trim())
.filter(Boolean)
.map((name) => ({ name, status: matchStatus(name) }));
}, [list]);
const save = (toCart: boolean) => {
if (!draftImages.length) {
Alert.alert("Image required", "Scan or upload at least one prescription photo first.");
return;
}
if (!patientName.trim() || !medicineName.trim()) {
Alert.alert("Missing", "Patient and primary medicine are required.");
return;
}
const meds =
medicines.length > 0
? medicines
: [{ name: medicineName, status: matchStatus(medicineName) }];
const rx = addPrescription({
patientName: patientName.trim(),
memberId,
medicineName: medicineName.trim(),
medicines: meds,
imageUris: draftImages,
daysSupply: Number(daysSupply) || 30,
lastFilledAt: null,
notes: notes.trim(),
});
if (toCart) {
meds
.filter((m) => m.status === "ready")
.forEach((m) => {
const p = products.find((x) =>
x.name.toLowerCase().includes(m.name.toLowerCase().split(" ")[0])
);
if (p) addProduct(p);
});
setFulfillment("pickup");
}
setDraftImages([]);
Alert.alert("Saved", "Prescription submitted for pharmacist review", [
{ text: "Open details", onPress: () => router.replace(routes.rxDetail(rx.id)) },
{ text: "Reminders", onPress: () => router.replace(routes.rxCalendar(rx.id)) },
{ text: "List", onPress: () => router.replace(routes.rxList) },
]);
};
return (
<Screen>
<AppHeader title="Review prescription" subtitle="Confirm patient and medicines" />
<ScrollView contentContainerStyle={{ paddingHorizontal: gutter, paddingBottom: 40, gap: 14 }}>
{draftImages.length ? (
<ScrollView horizontal showsHorizontalScrollIndicator={false} contentContainerStyle={{ gap: 8 }}>
{draftImages.map((uri) => (
<Image
key={uri}
source={{ uri }}
style={{ width: 96, height: 96, borderRadius: radii.md, backgroundColor: colors.surfaceAlt }}
/>
))}
</ScrollView>
) : (
<Card tone="brand" elevated={false}>
<Text variant="h3">No images attached</Text>
<Text variant="bodySm" color={colors.muted} style={{ marginTop: 4 }}>
Go back to scan or upload a prescription photo.
</Text>
<Button
title="Scan / upload"
size="md"
style={{ marginTop: 12 }}
onPress={() => router.replace(routes.rxScan)}
/>
</Card>
)}
<Card elevated={false}>
<Text variant="h3" style={{ marginBottom: 10 }}>
Patient
</Text>
<View style={{ flexDirection: "row", flexWrap: "wrap", gap: 8, marginBottom: 12 }}>
<Chip
label={user?.name || "Me"}
selected={!memberId}
onPress={() => {
setMemberId(null);
setPatientName(user?.name || "");
}}
/>
{members
.filter((m) => m.status === "accepted")
.map((m) => (
<Chip
key={m.id}
label={m.name}
selected={memberId === m.id}
onPress={() => {
setMemberId(m.id);
setPatientName(m.name);
}}
/>
))}
</View>
<View style={{ gap: 12 }}>
<Field label="Patient name" value={patientName} onChangeText={setPatientName} />
<Field
label="Primary medicine"
value={medicineName}
onChangeText={setMedicineName}
hint="Used as the prescription title"
/>
<Field
label="All medicines (comma-separated)"
value={list}
onChangeText={setList}
placeholder="Metformin 500mg, Vitamin B12"
/>
<Field
label="Days supply"
value={daysSupply}
onChangeText={setDaysSupply}
keyboardType="number-pad"
/>
<Field
label="Notes for pharmacist"
value={notes}
onChangeText={setNotes}
placeholder="Allergies, instructions, preferred brand…"
/>
</View>
</Card>
<Card elevated={false}>
<Text variant="h3" style={{ marginBottom: 10 }}>
Availability preview
</Text>
{(medicines.length ? medicines : [{ name: medicineName || "—", status: "review" as const }]).map(
(m) => (
<View
key={m.name}
style={{
flexDirection: "row",
justifyContent: "space-between",
paddingVertical: 8,
borderBottomWidth: 1,
borderBottomColor: colors.line,
}}
>
<Text variant="bodyMedium">{m.name}</Text>
<Badge
label={m.status}
tone={
m.status === "ready" ? "brand" : m.status === "review" ? "warn" : "danger"
}
/>
</View>
)
)}
</Card>
<Button title="Submit for review" onPress={() => save(false)} />
<Button
title="Submit & add ready items to cart"
variant="soft"
onPress={() => save(true)}
/>
</ScrollView>
</Screen>
);
}