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>
112 lines
3.6 KiB
TypeScript
112 lines
3.6 KiB
TypeScript
import { router, useLocalSearchParams } from "expo-router";
|
|
import { useMemo, useState } from "react";
|
|
import { FlatList, Pressable, 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 { ProductRow } from "@/components/ui/ProductCard";
|
|
import { Screen } from "@/components/ui/Screen";
|
|
import { SearchField } from "@/components/ui/SearchField";
|
|
import { Text } from "@/components/ui/Text";
|
|
import { products, searchProducts } from "@/lib/data/products";
|
|
import { categories, routes } from "@/lib/routes";
|
|
import { colors, gutter } from "@/lib/theme";
|
|
|
|
const recent = ["Panadol", "Metformin", "Vitamin C", "Cough syrup", "Glucose meter"];
|
|
|
|
export default function SearchScreen() {
|
|
const { t } = useTranslation();
|
|
const params = useLocalSearchParams<{ q?: string }>();
|
|
const [q, setQ] = useState(params.q ?? "");
|
|
|
|
const results = useMemo(() => (q.trim() ? searchProducts(q) : []), [q]);
|
|
|
|
return (
|
|
<Screen>
|
|
<AppHeader title="Search" />
|
|
<View style={{ paddingHorizontal: gutter }}>
|
|
<SearchField
|
|
value={q}
|
|
onChangeText={setQ}
|
|
onClear={() => setQ("")}
|
|
autoFocus
|
|
placeholder={t("common.search")}
|
|
/>
|
|
</View>
|
|
|
|
{!q.trim() ? (
|
|
<View style={{ paddingHorizontal: gutter, paddingTop: 20 }}>
|
|
<Text variant="h3">Recent searches</Text>
|
|
<View style={{ marginTop: 12, gap: 10 }}>
|
|
{recent.map((term) => (
|
|
<Pressable
|
|
key={term}
|
|
onPress={() => setQ(term)}
|
|
style={{ flexDirection: "row", alignItems: "center", gap: 10 }}
|
|
>
|
|
<Text variant="body" color={colors.muted}>
|
|
{term}
|
|
</Text>
|
|
</Pressable>
|
|
))}
|
|
</View>
|
|
|
|
<Text variant="h3" style={{ marginTop: 28, marginBottom: 12 }}>
|
|
Browse by category
|
|
</Text>
|
|
<ChipRow gutters={0}>
|
|
{categories.map((c) => (
|
|
<Chip
|
|
key={c.id}
|
|
label={t(c.labelKey)}
|
|
icon={c.icon}
|
|
onPress={() =>
|
|
router.push({ pathname: routes.shop, params: { category: c.id } })
|
|
}
|
|
/>
|
|
))}
|
|
</ChipRow>
|
|
|
|
<Text variant="h3" style={{ marginTop: 28, marginBottom: 12 }}>
|
|
Popular right now
|
|
</Text>
|
|
<View style={{ gap: 10 }}>
|
|
{products
|
|
.filter((p) => p.badge === "bestseller")
|
|
.slice(0, 4)
|
|
.map((p) => (
|
|
<ProductRow key={p.id} product={p} />
|
|
))}
|
|
</View>
|
|
</View>
|
|
) : (
|
|
<FlatList
|
|
data={results}
|
|
keyExtractor={(i) => i.id}
|
|
contentContainerStyle={{
|
|
paddingHorizontal: gutter,
|
|
paddingTop: 16,
|
|
paddingBottom: 40,
|
|
gap: 10,
|
|
}}
|
|
ListEmptyComponent={
|
|
<EmptyState
|
|
icon="search-outline"
|
|
title="Nothing found"
|
|
body="Try a brand name, symptom or category."
|
|
compact
|
|
/>
|
|
}
|
|
ListHeaderComponent={
|
|
<Text variant="caption" color={colors.subtle} style={{ marginBottom: 8 }}>
|
|
{results.length} result{results.length === 1 ? "" : "s"}
|
|
</Text>
|
|
}
|
|
renderItem={({ item }) => <ProductRow product={item} />}
|
|
/>
|
|
)}
|
|
</Screen>
|
|
);
|
|
}
|