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>
135 lines
4.6 KiB
TypeScript
135 lines
4.6 KiB
TypeScript
import { Ionicons } from "@expo/vector-icons";
|
|
import { router } from "expo-router";
|
|
import { useTranslation } from "react-i18next";
|
|
import { Pressable, ScrollView, View } from "react-native";
|
|
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 { routes } from "@/lib/routes";
|
|
import { useProfileModeStore } from "@/lib/stores/profileModeStore";
|
|
import { colors, gutter } from "@/lib/theme";
|
|
import { formatETB } from "@/lib/utils";
|
|
|
|
export default function ProfileSwitchScreen() {
|
|
const { t } = useTranslation();
|
|
const mode = useProfileModeStore((s) => s.mode);
|
|
const setMode = useProfileModeStore((s) => s.setMode);
|
|
const memberships = useProfileModeStore((s) => s.memberships);
|
|
const setActiveOrg = useProfileModeStore((s) => s.setActiveOrg);
|
|
const activeOrgId = useProfileModeStore((s) => s.activeOrgId);
|
|
|
|
return (
|
|
<Screen>
|
|
<AppHeader
|
|
title={t("common.switchProfile")}
|
|
subtitle="Personal shopping or organisation benefits"
|
|
/>
|
|
<ScrollView
|
|
contentContainerStyle={{
|
|
paddingHorizontal: gutter,
|
|
paddingBottom: 32,
|
|
gap: 12,
|
|
}}
|
|
>
|
|
<Pressable
|
|
onPress={() => {
|
|
setMode("personal");
|
|
setActiveOrg(null);
|
|
}}
|
|
style={cardStyle(mode === "personal")}
|
|
>
|
|
<View style={{ flexDirection: "row", alignItems: "center", gap: 12 }}>
|
|
<View
|
|
style={{
|
|
width: 44,
|
|
height: 44,
|
|
borderRadius: 14,
|
|
backgroundColor: colors.brandSoft,
|
|
alignItems: "center",
|
|
justifyContent: "center",
|
|
}}
|
|
>
|
|
<Ionicons name="person" size={20} color={colors.brandText} />
|
|
</View>
|
|
<View style={{ flex: 1 }}>
|
|
<Text variant="h3">{t("common.personal")}</Text>
|
|
<Text variant="caption" color={colors.muted} style={{ marginTop: 2 }}>
|
|
Retail shopping, loyalty points, family
|
|
</Text>
|
|
</View>
|
|
{mode === "personal" ? <Badge label="Active" tone="brand" /> : null}
|
|
</View>
|
|
</Pressable>
|
|
|
|
{memberships.map((m) => {
|
|
const active = mode === "corporate" && activeOrgId === m.orgId;
|
|
return (
|
|
<Pressable
|
|
key={m.orgId}
|
|
onPress={() => setActiveOrg(m.orgId)}
|
|
style={cardStyle(active)}
|
|
>
|
|
<View style={{ flexDirection: "row", alignItems: "center", gap: 12 }}>
|
|
<View
|
|
style={{
|
|
width: 44,
|
|
height: 44,
|
|
borderRadius: 14,
|
|
backgroundColor: colors.brandSoft,
|
|
alignItems: "center",
|
|
justifyContent: "center",
|
|
}}
|
|
>
|
|
<Ionicons name="business" size={20} color={colors.brandText} />
|
|
</View>
|
|
<View style={{ flex: 1 }}>
|
|
<Text variant="h3">{m.orgName}</Text>
|
|
<Text variant="caption" color={colors.muted} style={{ marginTop: 2 }}>
|
|
{m.planName}
|
|
</Text>
|
|
<Text variant="label" color={colors.brandText} style={{ marginTop: 6 }}>
|
|
{formatETB(m.remainingAllowance)} allowance left
|
|
</Text>
|
|
</View>
|
|
{active ? <Badge label="Active" tone="brand" /> : null}
|
|
</View>
|
|
</Pressable>
|
|
);
|
|
})}
|
|
|
|
{!memberships.length ? (
|
|
<Card elevated={false}>
|
|
<Text variant="body" color={colors.muted}>
|
|
No organisations yet. Join with a demo code from your HR team.
|
|
</Text>
|
|
<Button
|
|
title={t("common.joinOrg")}
|
|
onPress={() => router.push(routes.profileJoin)}
|
|
style={{ marginTop: 12 }}
|
|
/>
|
|
</Card>
|
|
) : (
|
|
<Button
|
|
title={t("common.joinOrg")}
|
|
variant="outline"
|
|
onPress={() => router.push(routes.profileJoin)}
|
|
/>
|
|
)}
|
|
</ScrollView>
|
|
</Screen>
|
|
);
|
|
}
|
|
|
|
function cardStyle(selected: boolean) {
|
|
return {
|
|
backgroundColor: colors.surface,
|
|
borderRadius: 20,
|
|
padding: 16,
|
|
borderWidth: selected ? 2 : 1,
|
|
borderColor: selected ? colors.brand : colors.line,
|
|
};
|
|
}
|