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

92 lines
2.9 KiB
TypeScript

import { useLocalSearchParams } from "expo-router";
import { useMemo, useState } from "react";
import { FlatList, useWindowDimensions, View } from "react-native";
import { useTranslation } from "react-i18next";
import { Chip, ChipRow } from "@/components/ui/Chip";
import { EmptyState } from "@/components/ui/EmptyState";
import { AppHeader } from "@/components/ui/Header";
import { ProductCard, GRID_CARD_GAP } from "@/components/ui/ProductCard";
import { Screen } from "@/components/ui/Screen";
import { SearchField } from "@/components/ui/SearchField";
import { products } from "@/lib/data/products";
import { categories } from "@/lib/routes";
import { gutter } from "@/lib/theme";
export default function ShopScreen() {
const { t } = useTranslation();
const params = useLocalSearchParams<{ q?: string; category?: string }>();
const [q, setQ] = useState(params.q ?? "");
const [category, setCategory] = useState(params.category ?? "");
const { width } = useWindowDimensions();
const cardWidth = (width - gutter * 2 - GRID_CARD_GAP) / 2;
const data = useMemo(() => {
return products.filter((p) => {
const catOk = !category || p.category === category;
const qOk =
!q ||
p.name.toLowerCase().includes(q.toLowerCase()) ||
p.brand.toLowerCase().includes(q.toLowerCase()) ||
p.description.toLowerCase().includes(q.toLowerCase());
return catOk && qOk;
});
}, [q, category]);
return (
<Screen>
<AppHeader
large
back
title="Explore products"
subtitle="Trusted medicines, vitamins and care essentials"
/>
<View style={{ paddingHorizontal: gutter, marginBottom: 12 }}>
<SearchField
value={q}
onChangeText={setQ}
onClear={() => setQ("")}
placeholder={t("common.search")}
/>
</View>
<ChipRow gutters={gutter}>
<Chip
label="All"
selected={!category}
onPress={() => setCategory("")}
/>
{categories.map((c) => (
<Chip
key={c.id}
label={t(c.labelKey)}
selected={category === c.id}
onPress={() => setCategory(c.id)}
icon={c.icon}
/>
))}
</ChipRow>
<FlatList
data={data}
numColumns={2}
keyExtractor={(i) => i.id}
showsVerticalScrollIndicator={false}
contentContainerStyle={{
paddingHorizontal: gutter,
paddingTop: 16,
paddingBottom: 40,
gap: GRID_CARD_GAP,
}}
columnWrapperStyle={{ gap: GRID_CARD_GAP }}
ListEmptyComponent={
<EmptyState
icon="search-outline"
title="No matches"
body="Try another medicine name, brand or category."
compact
/>
}
renderItem={({ item }) => <ProductCard product={item} width={cardWidth} />}
/>
</Screen>
);
}