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)/branches.tsx
kirukib 7310a349c5 Add Gishen mobile app with complete demo shopping and care flows.
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>
2026-08-07 01:21:32 +03:00

147 lines
5.1 KiB
TypeScript

import * as Location from "expo-location";
import { router } from "expo-router";
import { useMemo, useState } from "react";
import { Alert, Linking, 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 { AppHeader } from "@/components/ui/Header";
import { Screen } from "@/components/ui/Screen";
import { Text } from "@/components/ui/Text";
import { branches } from "@/lib/data/branches";
import { routes } from "@/lib/routes";
import { useLocationStore } from "@/lib/stores/locationStore";
import { colors, gutter } from "@/lib/theme";
function dist(a: { lat: number; lng: number }, b: { lat: number; lng: number }) {
const toRad = (d: number) => (d * Math.PI) / 180;
const R = 6371;
const dLat = toRad(b.lat - a.lat);
const dLng = toRad(b.lng - a.lng);
const x =
Math.sin(dLat / 2) ** 2 +
Math.cos(toRad(a.lat)) * Math.cos(toRad(b.lat)) * Math.sin(dLng / 2) ** 2;
return 2 * R * Math.asin(Math.sqrt(x));
}
export default function BranchesScreen() {
const { t } = useTranslation();
const setBranchId = useLocationStore((s) => s.setBranchId);
const setFulfillment = useLocationStore((s) => s.setFulfillment);
const setCoords = useLocationStore((s) => s.setCoords);
const branchId = useLocationStore((s) => s.branchId);
const [coords, setLocal] = useState<{ lat: number; lng: number } | null>(null);
const sorted = useMemo(() => {
if (!coords) return branches;
return [...branches].sort((a, b) => dist(coords, a) - dist(coords, b));
}, [coords]);
const useMyLocation = async () => {
const { status } = await Location.requestForegroundPermissionsAsync();
if (status !== "granted") {
Alert.alert("Location", "Permission denied");
return;
}
const pos = await Location.getCurrentPositionAsync({});
const c = { lat: pos.coords.latitude, lng: pos.coords.longitude };
setLocal(c);
setCoords(c.lat, c.lng);
};
return (
<Screen>
<AppHeader
title={t("common.branches")}
subtitle={`${branches.length} locations across Addis Ababa`}
/>
<ScrollView
contentContainerStyle={{
paddingHorizontal: gutter,
paddingBottom: 40,
gap: 12,
}}
>
<Button
title={t("common.useLocation")}
icon="navigate-outline"
onPress={useMyLocation}
/>
<Text variant="h3">{t("common.nearestBranch")}</Text>
{sorted.map((b, index) => {
const selected = branchId === b.id;
const km = coords ? dist(coords, b) : null;
return (
<Card
key={b.id}
style={{
borderWidth: selected ? 2 : 1,
borderColor: selected ? colors.brand : colors.line,
}}
>
<View style={{ flexDirection: "row", justifyContent: "space-between", gap: 10 }}>
<View style={{ flex: 1 }}>
<Text variant="h3">{b.name}</Text>
<Text variant="bodySm" color={colors.muted} style={{ marginTop: 4 }}>
{b.area}
</Text>
<Text variant="caption" color={colors.subtle} style={{ marginTop: 2 }}>
{b.hours}
{b.pickupAvailable ? " · Pickup" : ""}
</Text>
</View>
<View style={{ alignItems: "flex-end", gap: 6 }}>
{selected ? <Badge label="Selected" tone="brand" /> : null}
{index === 0 && coords ? <Badge label="Nearest" tone="info" /> : null}
{km != null ? (
<Text variant="label" color={colors.brandText}>
{km.toFixed(1)} km
</Text>
) : null}
</View>
</View>
<View style={{ flexDirection: "row", flexWrap: "wrap", gap: 8, marginTop: 14 }}>
<Button
title="Call"
size="md"
fullWidth={false}
variant="outline"
icon="call-outline"
onPress={() => Linking.openURL(`tel:${b.phone}`)}
/>
<Button
title="Maps"
size="md"
fullWidth={false}
variant="outline"
icon="map-outline"
onPress={() => Linking.openURL(b.mapsUrl)}
/>
<Button
title="Set pickup"
size="md"
fullWidth={false}
onPress={() => {
setBranchId(b.id);
setFulfillment("pickup");
Alert.alert("Pickup set", `${b.name} selected for checkout.`);
}}
/>
</View>
</Card>
);
})}
<Button
title="Go to checkout"
variant="ghost"
onPress={() => router.push(routes.checkout)}
/>
</ScrollView>
</Screen>
);
}