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)/loyalty.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

168 lines
5.9 KiB
TypeScript

import { Share, ScrollView, View } from "react-native";
import { useTranslation } from "react-i18next";
import { Badge } from "@/components/ui/Badge";
import { Button } from "@/components/ui/Button";
import { Card, InfoRow, Section } from "@/components/ui/Card";
import { AppHeader } from "@/components/ui/Header";
import { Screen } from "@/components/ui/Screen";
import { Text } from "@/components/ui/Text";
import { DEMO_VOUCHER } from "@/lib/commerce";
import { useAuthStore } from "@/lib/stores/authStore";
import { useCartStore } from "@/lib/stores/cartStore";
import { colors, gutter } from "@/lib/theme";
import { router } from "expo-router";
import { routes } from "@/lib/routes";
import { Alert } from "react-native";
const tiers = [
{ id: "bronze", min: 0, perks: "1 pt per 10 ETB · Birthday surprise" },
{ id: "silver", min: 300, perks: "1.25x points · Free delivery over 800 ETB" },
{ id: "gold", min: 1000, perks: "1.5x points · Priority pharmacist consult" },
] as const;
export default function LoyaltyScreen() {
const { t } = useTranslation();
const user = useAuthStore((s) => s.user);
const ledger = useAuthStore((s) => s.ledger);
const redeemPoints = useAuthStore((s) => s.redeemPoints);
const setVoucher = useCartStore((s) => s.setVoucher);
const points = user?.points ?? 0;
const next = tiers.find((tier) => points < tier.min) ?? null;
const progress = next
? Math.min(1, points / next.min)
: 1;
return (
<Screen>
<AppHeader title={t("common.loyalty")} subtitle="Earn points on every paid order" />
<ScrollView contentContainerStyle={{ paddingHorizontal: gutter, paddingBottom: 40, gap: 14 }}>
<Card tone="brand" elevated={false}>
<View style={{ flexDirection: "row", justifyContent: "space-between" }}>
<View>
<Text variant="caption" color={colors.muted}>
Available points
</Text>
<Text variant="display" style={{ marginTop: 4 }}>
{points}
</Text>
</View>
<Badge label={(user?.tier ?? "bronze").toUpperCase()} solid />
</View>
<View
style={{
marginTop: 16,
height: 8,
borderRadius: 4,
backgroundColor: "rgba(16,20,16,0.12)",
overflow: "hidden",
}}
>
<View
style={{
width: `${Math.round(progress * 100)}%`,
height: "100%",
backgroundColor: colors.ink,
}}
/>
</View>
<Text variant="caption" color={colors.muted} style={{ marginTop: 8 }}>
{next
? `${next.min - points} pts to ${next.id}`
: "You've reached Gold — enjoy premium perks"}
</Text>
</Card>
<Section title="How tiers work">
<Card elevated={false}>
{tiers.map((tier, i) => (
<InfoRow
key={tier.id}
label={`${tier.id} · ${tier.min}+ pts`}
value={tier.perks}
last={i === tiers.length - 1}
/>
))}
</Card>
</Section>
<Card elevated={false}>
<Text variant="h3">Redeem rewards</Text>
<Text variant="bodySm" color={colors.muted} style={{ marginTop: 6 }}>
Redeem 100 points for a {DEMO_VOUCHER} voucher (10% off your next order).
</Text>
{user?.activeVoucher ? (
<Badge
label={`Active voucher: ${user.activeVoucher}`}
tone="brand"
style={{ marginTop: 12 }}
/>
) : null}
<Button
title="Redeem 100 pts"
style={{ marginTop: 14 }}
disabled={!user || user.isGuest || points < 100}
onPress={() => {
const ok = redeemPoints(100);
if (!ok) {
Alert.alert("Not enough points", "You need at least 100 points.");
return;
}
setVoucher(DEMO_VOUCHER);
Alert.alert(
"Voucher unlocked",
`${DEMO_VOUCHER} is ready in your cart / checkout.`,
[
{ text: "Go to cart", onPress: () => router.push(routes.cart) },
{ text: "OK" },
]
);
}}
/>
</Card>
<Card elevated={false}>
<Text variant="h3">{t("common.referral")}</Text>
<Text variant="priceLg" style={{ marginTop: 8 }}>
{user?.referralCode ?? "GISHEN-GUEST"}
</Text>
<Text variant="bodySm" color={colors.muted} style={{ marginTop: 6 }}>
Friends get 50 welcome points. You get 100 when they place their first order.
</Text>
<Button
title="Share code"
variant="outline"
icon="share-outline"
style={{ marginTop: 14 }}
onPress={() =>
Share.share({
message: `Join Gishen Pharmacy with my code ${user?.referralCode ?? ""}. Healthcare delivered to your doorstep.`,
})
}
/>
</Card>
<Section title="Points history">
<Card elevated={false}>
{ledger.length === 0 ? (
<Text variant="bodySm" color={colors.muted}>
Points from orders will appear here.
</Text>
) : (
ledger.map((entry, i) => (
<InfoRow
key={entry.id}
label={`${entry.label} · ${new Date(entry.at).toLocaleDateString()}`}
value={`${entry.delta > 0 ? "+" : ""}${entry.delta}`}
valueColor={entry.delta >= 0 ? colors.brandText : colors.danger}
last={i === ledger.length - 1}
/>
))
)}
</Card>
</Section>
</ScrollView>
</Screen>
);
}