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>
108 lines
3.9 KiB
TypeScript
108 lines
3.9 KiB
TypeScript
import { router } from "expo-router";
|
|
import { Image, ScrollView, View } from "react-native";
|
|
import { useTranslation } from "react-i18next";
|
|
import { Badge } from "@/components/ui/Badge";
|
|
import { Card } from "@/components/ui/Card";
|
|
import { EmptyState } from "@/components/ui/EmptyState";
|
|
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);
|
|
|
|
return (
|
|
<Screen>
|
|
<AppHeader title={t("common.orders")} subtitle="Track delivery and pickup status" />
|
|
<ScrollView contentContainerStyle={{ paddingHorizontal: gutter, paddingBottom: 40 }}>
|
|
{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)}
|
|
/>
|
|
) : (
|
|
<View style={{ gap: 12 }}>
|
|
{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.fulfillment === "pickup" ? "Pickup" : "Delivery"} · {o.areaLabel}
|
|
</Text>
|
|
<Text variant="caption" color={colors.subtle} style={{ marginTop: 4 }}>
|
|
{new Date(o.createdAt).toLocaleString()} · {o.paymentMethod}
|
|
</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>
|
|
))}
|
|
</View>
|
|
)}
|
|
</ScrollView>
|
|
</Screen>
|
|
);
|
|
}
|