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>
137 lines
5.2 KiB
TypeScript
137 lines
5.2 KiB
TypeScript
import { router } from "expo-router";
|
|
import { useState } from "react";
|
|
import { Alert, 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 { Field } from "@/components/ui/Field";
|
|
import { AppHeader } from "@/components/ui/Header";
|
|
import { Screen } from "@/components/ui/Screen";
|
|
import { Text } from "@/components/ui/Text";
|
|
import { useAddressStore } from "@/lib/stores/addressStore";
|
|
import { useLocationStore } from "@/lib/stores/locationStore";
|
|
import { colors, gutter } from "@/lib/theme";
|
|
|
|
export default function AddressesScreen() {
|
|
const { t } = useTranslation();
|
|
const addresses = useAddressStore((s) => s.addresses);
|
|
const add = useAddressStore((s) => s.add);
|
|
const remove = useAddressStore((s) => s.remove);
|
|
const setDefault = useAddressStore((s) => s.setDefault);
|
|
const setAreaLabel = useLocationStore((s) => s.setAreaLabel);
|
|
|
|
const [label, setLabel] = useState("Home");
|
|
const [area, setArea] = useState("Bole, Addis Ababa");
|
|
const [street, setStreet] = useState("");
|
|
const [landmark, setLandmark] = useState("");
|
|
const [showForm, setShowForm] = useState(false);
|
|
|
|
return (
|
|
<Screen>
|
|
<AppHeader title={t("common.addresses")} subtitle="Saved delivery locations" />
|
|
<ScrollView contentContainerStyle={{ paddingHorizontal: gutter, paddingBottom: 40, gap: 12 }}>
|
|
{addresses.map((a) => (
|
|
<Card key={a.id}>
|
|
<View style={{ flexDirection: "row", justifyContent: "space-between", gap: 12 }}>
|
|
<View style={{ flex: 1 }}>
|
|
<Text variant="h3">{a.label}</Text>
|
|
<Text variant="bodySm" color={colors.muted} style={{ marginTop: 4 }}>
|
|
{a.street}
|
|
</Text>
|
|
<Text variant="caption" color={colors.subtle} style={{ marginTop: 2 }}>
|
|
{a.area}
|
|
{a.landmark ? ` · ${a.landmark}` : ""}
|
|
</Text>
|
|
</View>
|
|
{a.isDefault ? <Badge label="Default" tone="brand" /> : null}
|
|
</View>
|
|
<View style={{ flexDirection: "row", flexWrap: "wrap", gap: 8, marginTop: 12 }}>
|
|
{!a.isDefault ? (
|
|
<Button
|
|
title="Set default"
|
|
size="sm"
|
|
variant="outline"
|
|
fullWidth={false}
|
|
onPress={() => {
|
|
setDefault(a.id);
|
|
setAreaLabel(a.area);
|
|
}}
|
|
/>
|
|
) : (
|
|
<Button
|
|
title="Use for checkout"
|
|
size="sm"
|
|
fullWidth={false}
|
|
onPress={() => {
|
|
setAreaLabel(a.area);
|
|
router.push("/(root)/(tabs)/cart");
|
|
}}
|
|
/>
|
|
)}
|
|
<Button
|
|
title="Remove"
|
|
size="sm"
|
|
variant="ghost"
|
|
fullWidth={false}
|
|
onPress={() =>
|
|
Alert.alert("Remove address?", a.label, [
|
|
{ text: "Cancel", style: "cancel" },
|
|
{ text: "Remove", style: "destructive", onPress: () => remove(a.id) },
|
|
])
|
|
}
|
|
/>
|
|
</View>
|
|
</Card>
|
|
))}
|
|
|
|
{!showForm ? (
|
|
<Button title="Add address" icon="add" onPress={() => setShowForm(true)} />
|
|
) : (
|
|
<Card elevated={false}>
|
|
<Text variant="h3" style={{ marginBottom: 12 }}>
|
|
New address
|
|
</Text>
|
|
<View style={{ gap: 12 }}>
|
|
<Field label="Label" value={label} onChangeText={setLabel} placeholder="Home, Office…" />
|
|
<Field label="Area" value={area} onChangeText={setArea} placeholder="Bole, Addis Ababa" />
|
|
<Field
|
|
label="Street / building"
|
|
value={street}
|
|
onChangeText={setStreet}
|
|
placeholder="Street, building, apt"
|
|
/>
|
|
<Field
|
|
label="Landmark (optional)"
|
|
value={landmark}
|
|
onChangeText={setLandmark}
|
|
placeholder="Near Edna Mall"
|
|
/>
|
|
<Button
|
|
title="Save address"
|
|
onPress={() => {
|
|
if (!street.trim() || !area.trim()) {
|
|
Alert.alert("Missing info", "Area and street are required.");
|
|
return;
|
|
}
|
|
add({
|
|
label: label.trim() || "Address",
|
|
area: area.trim(),
|
|
street: street.trim(),
|
|
landmark: landmark.trim() || undefined,
|
|
isDefault: addresses.length === 0,
|
|
});
|
|
setStreet("");
|
|
setLandmark("");
|
|
setShowForm(false);
|
|
}}
|
|
/>
|
|
<Button title="Cancel" variant="ghost" onPress={() => setShowForm(false)} />
|
|
</View>
|
|
</Card>
|
|
)}
|
|
</ScrollView>
|
|
</Screen>
|
|
);
|
|
}
|