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 d40cb22ff4 Finalize profile, prescription, and checkout with shared UI modules.
Add payment/notification prefs, assisted pharmacist codes, Rx status journey, and mock payment intents so demo flows match the storefront brief.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-10 14:53:34 +03:00

254 lines
8.8 KiB
TypeScript

import { router } from "expo-router";
import { useMemo, useState } from "react";
import { Alert, ScrollView, View } from "react-native";
import { RxImagePager, RxStatusStepper } from "@/components/prescription";
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 { useNotificationStore } from "@/lib/stores/notificationStore";
import { usePrescriptionStore } from "@/lib/stores/prescriptionStore";
import { colors, gutter } 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 pushNotification = useNotificationStore((s) => s.push);
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([]);
pushNotification({
kind: "rx",
title: "Prescription submitted",
body: "A pharmacist will review your script shortly.",
href: routes.rxDetail(rx.id),
});
Alert.alert("Submitted", "Your prescription is under review.", [
{ text: "Track status", onPress: () => router.replace(routes.rxDetail(rx.id)) },
{ text: "Reminders", onPress: () => router.replace(routes.rxCalendar(rx.id)) },
...(toCart
? [{ text: "Cart", onPress: () => router.replace(routes.cart) }]
: [{ 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 }}
>
<Card elevated={false}>
<Text variant="label" color={colors.muted} style={{ marginBottom: 12 }}>
After submit
</Text>
<RxStatusStepper status="submitted" />
</Card>
<Card elevated={false}>
<Text variant="h3" style={{ marginBottom: 10 }}>
Prescription pages ({draftImages.length})
</Text>
{draftImages.length ? (
<RxImagePager
uris={draftImages}
size={104}
onLongPress={(_, index) => {
Alert.alert("Remove page?", `Page ${index + 1}`, [
{ text: "Cancel", style: "cancel" },
{
text: "Remove",
style: "destructive",
onPress: () =>
setDraftImages(draftImages.filter((_, i) => i !== index)),
},
]);
}}
/>
) : (
<>
<Text variant="bodySm" color={colors.muted}>
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>
);
}