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)/(tabs)/prescriptions.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

255 lines
9.1 KiB
TypeScript

import { router } from "expo-router";
import { useMemo, useState } from "react";
import { Alert, ScrollView, View } from "react-native";
import { useTranslation } from "react-i18next";
import { FamilyInviteCard } from "@/components/care";
import { RxCareCard } from "@/components/prescription";
import { Badge } from "@/components/ui/Badge";
import { Button } from "@/components/ui/Button";
import { Card, Section } from "@/components/ui/Card";
import { Chip } from "@/components/ui/Chip";
import { EmptyState } from "@/components/ui/EmptyState";
import { Screen, TAB_BAR_INSET } from "@/components/ui/Screen";
import { TabTopBar } from "@/components/ui/TabTopBar";
import { Text } from "@/components/ui/Text";
import { routes } from "@/lib/routes";
import { useFamilyStore } from "@/lib/stores/familyStore";
import {
usePrescriptionStore,
type Reminder,
type RxStatus,
} from "@/lib/stores/prescriptionStore";
import { colors, gutter } from "@/lib/theme";
type Filter = "all" | RxStatus;
export default function PrescriptionsTabScreen() {
const { t } = useTranslation();
const prescriptions = usePrescriptionStore((s) => s.prescriptions);
const reminders = usePrescriptionStore((s) => s.reminders);
const members = useFamilyStore((s) => s.members);
const inviteCode = useFamilyStore((s) => s.inviteCode);
const acceptInvite = useFamilyStore((s) => s.acceptInvite);
const removeMember = useFamilyStore((s) => s.removeMember);
const setActiveMember = useFamilyStore((s) => s.setActiveMember);
const activeMemberId = useFamilyStore((s) => s.activeMemberId);
const [expandedId, setExpandedId] = useState<string | null>(null);
const [filter, setFilter] = useState<Filter>("all");
const reminderByRx = useMemo(() => {
const map = new Map<string, Reminder>();
reminders.forEach((r) => map.set(r.prescriptionId, r));
return map;
}, [reminders]);
const activeReminderCount = reminders.filter((r) => r.enabled).length;
const needingSetup = prescriptions.filter((p) => !reminderByRx.get(p.id)?.enabled).length;
const queriedCount = prescriptions.filter((p) => p.status === "queried").length;
const visible = useMemo(
() =>
filter === "all"
? prescriptions
: prescriptions.filter((p) => p.status === filter),
[prescriptions, filter]
);
return (
<Screen>
<TabTopBar subtitle={t("common.prescriptions")} />
<ScrollView
showsVerticalScrollIndicator={false}
contentContainerStyle={{
paddingBottom: TAB_BAR_INSET + 24,
paddingHorizontal: gutter,
gap: 14,
}}
>
<View>
<Text variant="h1">{t("common.prescriptions")}</Text>
<Text variant="bodySm" color={colors.subtle} style={{ marginTop: 4 }}>
Manage Rx, dose calendars, and family care shares
</Text>
</View>
<View style={{ flexDirection: "row", gap: 10 }}>
<Card elevated={false} tone="brand" style={{ flex: 1 }}>
<Text variant="caption" color={colors.muted}>
Active reminders
</Text>
<Text variant="h1" style={{ marginTop: 2 }}>
{activeReminderCount}
</Text>
</Card>
<Card elevated={false} style={{ flex: 1 }}>
<Text variant="caption" color={colors.muted}>
Need setup
</Text>
<Text variant="h1" style={{ marginTop: 2 }}>
{needingSetup}
</Text>
</Card>
{queriedCount ? (
<Card elevated={false} style={{ flex: 1 }}>
<Text variant="caption" color={colors.muted}>
Need reply
</Text>
<Text variant="h1" style={{ marginTop: 2 }}>
{queriedCount}
</Text>
</Card>
) : null}
</View>
<Button
title={t("common.scanRx")}
icon="scan-outline"
onPress={() => router.push(routes.rxScan)}
/>
<ScrollView horizontal showsHorizontalScrollIndicator={false} contentContainerStyle={{ gap: 8 }}>
{(
[
["all", "All"],
["queried", "Queried"],
["under_review", "Review"],
["approved", "Approved"],
["filled", "Filled"],
] as [Filter, string][]
).map(([id, label]) => (
<Chip
key={id}
label={label}
selected={filter === id}
onPress={() => setFilter(id)}
size="sm"
/>
))}
</ScrollView>
<Section title="Your prescriptions">
{visible.length === 0 ? (
<EmptyState
compact
icon="document-text-outline"
title={filter === "all" ? "No prescriptions yet" : "Nothing in this filter"}
body={
filter === "all"
? "Scan or upload a prescription to start reminders."
: "Try another status filter."
}
actionTitle="Scan prescription"
onAction={() => router.push(routes.rxScan)}
/>
) : (
<View style={{ gap: 12 }}>
{visible.map((rx) => (
<RxCareCard
key={rx.id}
rx={rx}
reminder={reminderByRx.get(rx.id)}
expanded={expandedId === rx.id}
onToggleExpand={() =>
setExpandedId((cur) => (cur === rx.id ? null : rx.id))
}
/>
))}
</View>
)}
</Section>
<Section title={t("common.family")}>
<FamilyInviteCard
inviteCode={inviteCode}
onInvite={() => router.push(routes.familyInvite)}
/>
{members.length === 0 ? (
<Text variant="bodySm" color={colors.muted} style={{ marginTop: 8 }}>
No family members yet. Invite someone to share Rx care.
</Text>
) : (
<View style={{ gap: 10, marginTop: 4 }}>
{members.map((m) => {
const active = activeMemberId === m.id;
return (
<Card
key={m.id}
onPress={() => setActiveMember(active ? null : m.id)}
style={{
borderColor: active ? colors.brand : colors.line,
borderWidth: active ? 1.5 : 1,
}}
>
<View style={{ flexDirection: "row", gap: 12, alignItems: "center" }}>
<View
style={{
width: 42,
height: 42,
borderRadius: 21,
backgroundColor: colors.brandSoft,
alignItems: "center",
justifyContent: "center",
}}
>
<Text variant="label" color={colors.brandText}>
{m.name.slice(0, 1).toUpperCase()}
</Text>
</View>
<View style={{ flex: 1 }}>
<Text variant="h3">{m.name}</Text>
<Text variant="caption" color={colors.subtle} style={{ marginTop: 2 }}>
{m.relationship}
{m.phone ? ` · ${m.phone}` : ""}
{active ? " · Active for Rx" : ""}
</Text>
</View>
<Badge
label={m.status}
tone={m.status === "accepted" ? "brand" : "warn"}
/>
</View>
<View
style={{
flexDirection: "row",
flexWrap: "wrap",
gap: 8,
marginTop: 12,
}}
>
{m.status === "pending" ? (
<Button
title="Accept"
size="sm"
fullWidth={false}
onPress={() => acceptInvite(m.id)}
/>
) : null}
<Button
title="Remove"
size="sm"
variant="ghost"
fullWidth={false}
onPress={() =>
Alert.alert("Remove member?", m.name, [
{ text: "Cancel", style: "cancel" },
{
text: "Remove",
style: "destructive",
onPress: () => removeMember(m.id),
},
])
}
/>
</View>
</Card>
);
})}
</View>
)}
</Section>
</ScrollView>
</Screen>
);
}