Replace the profile tab with prescription management (inline reminders and family invite), add a shared tab top bar, separate notifications from orders, and support any-branch guest checkout with GSH codes. Co-authored-by: Cursor <cursoragent@cursor.com>
156 lines
5.2 KiB
TypeScript
156 lines
5.2 KiB
TypeScript
import { router } from "expo-router";
|
|
import { useState } from "react";
|
|
import { Alert, Image, ScrollView, View } from "react-native";
|
|
import { useTranslation } from "react-i18next";
|
|
import { Badge } from "@/components/ui/Badge";
|
|
import { Button } from "@/components/ui/Button";
|
|
import { Card } from "@/components/ui/Card";
|
|
import { EmptyState } from "@/components/ui/EmptyState";
|
|
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 { useOrdersStore } from "@/lib/stores/ordersStore";
|
|
import { colors, gutter, radii } from "@/lib/theme";
|
|
import { formatETB } from "@/lib/utils";
|
|
import { routes } from "@/lib/routes";
|
|
|
|
const toneFor = {
|
|
requested: "neutral",
|
|
confirmed: "info",
|
|
paid: "brand",
|
|
dispatched: "warn",
|
|
delivered: "brand",
|
|
completed: "brand",
|
|
cancelled: "danger",
|
|
} as const;
|
|
|
|
export default function OrdersScreen() {
|
|
const { t } = useTranslation();
|
|
const orders = useOrdersStore((s) => s.orders);
|
|
const getByPickupCode = useOrdersStore((s) => s.getByPickupCode);
|
|
const [lookup, setLookup] = useState("");
|
|
|
|
const findByCode = () => {
|
|
const order = getByPickupCode(lookup);
|
|
if (!order) {
|
|
Alert.alert(
|
|
"Code not found",
|
|
"Check the GSH-XXXX code from checkout. Demo sample: GSH-GUEST"
|
|
);
|
|
return;
|
|
}
|
|
router.push(routes.orderDetail(order.id));
|
|
};
|
|
|
|
return (
|
|
<Screen>
|
|
<AppHeader
|
|
title={t("common.orders")}
|
|
subtitle="Order history — not the same as notifications"
|
|
/>
|
|
<ScrollView
|
|
contentContainerStyle={{
|
|
paddingHorizontal: gutter,
|
|
paddingBottom: 40,
|
|
gap: 12,
|
|
}}
|
|
>
|
|
<Card elevated={false}>
|
|
<Text variant="h3">Find with pickup code</Text>
|
|
<Text variant="caption" color={colors.muted} style={{ marginTop: 4 }}>
|
|
Guests can open an order by entering the quick code from checkout.
|
|
</Text>
|
|
<View style={{ marginTop: 12, gap: 10 }}>
|
|
<Field
|
|
label="Pickup code"
|
|
value={lookup}
|
|
onChangeText={setLookup}
|
|
autoCapitalize="characters"
|
|
placeholder="GSH-GUEST"
|
|
icon="key-outline"
|
|
/>
|
|
<Button title="Look up order" variant="outline" onPress={findByCode} />
|
|
</View>
|
|
</Card>
|
|
|
|
{orders.length === 0 ? (
|
|
<EmptyState
|
|
icon="receipt-outline"
|
|
title="No orders yet"
|
|
body="Your purchases will show up here."
|
|
actionTitle="Start shopping"
|
|
onAction={() => router.push(routes.shop)}
|
|
/>
|
|
) : (
|
|
orders.map((o) => (
|
|
<Card key={o.id} onPress={() => router.push(routes.orderDetail(o.id))}>
|
|
<View style={{ flexDirection: "row", justifyContent: "space-between", gap: 12 }}>
|
|
<View style={{ flex: 1 }}>
|
|
<Text variant="h3">
|
|
{o.anyBranch
|
|
? "Any-branch pickup"
|
|
: o.fulfillment === "pickup"
|
|
? "Pickup"
|
|
: "Delivery"}{" "}
|
|
· {o.areaLabel}
|
|
</Text>
|
|
<Text variant="caption" color={colors.subtle} style={{ marginTop: 4 }}>
|
|
{new Date(o.createdAt).toLocaleString()} · {o.paymentMethod}
|
|
{o.pickupCode ? ` · ${o.pickupCode}` : ""}
|
|
</Text>
|
|
</View>
|
|
<Badge label={o.status} tone={toneFor[o.status]} />
|
|
</View>
|
|
|
|
<View style={{ flexDirection: "row", gap: 8, marginTop: 12 }}>
|
|
{o.items.slice(0, 3).map((item) => (
|
|
<Image
|
|
key={item.productId}
|
|
source={{ uri: item.image }}
|
|
style={{
|
|
width: 44,
|
|
height: 44,
|
|
borderRadius: radii.sm,
|
|
backgroundColor: colors.surfaceAlt,
|
|
}}
|
|
resizeMode="contain"
|
|
/>
|
|
))}
|
|
{o.items.length > 3 ? (
|
|
<View
|
|
style={{
|
|
width: 44,
|
|
height: 44,
|
|
borderRadius: radii.sm,
|
|
backgroundColor: colors.surfaceAlt,
|
|
alignItems: "center",
|
|
justifyContent: "center",
|
|
}}
|
|
>
|
|
<Text variant="micro">+{o.items.length - 3}</Text>
|
|
</View>
|
|
) : null}
|
|
</View>
|
|
|
|
<View
|
|
style={{
|
|
marginTop: 12,
|
|
flexDirection: "row",
|
|
justifyContent: "space-between",
|
|
alignItems: "center",
|
|
}}
|
|
>
|
|
<Text variant="price">{formatETB(o.total)}</Text>
|
|
<Text variant="label" color={colors.brandText}>
|
|
View details
|
|
</Text>
|
|
</View>
|
|
</Card>
|
|
))
|
|
)}
|
|
</ScrollView>
|
|
</Screen>
|
|
);
|
|
}
|