114 lines
5.1 KiB
TypeScript
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import React, { useEffect, useMemo, useState } from "react";
import {
View, Text, ScrollView,
ActivityIndicator, useColorScheme, TouchableOpacity,
} from "react-native";
import { SafeAreaView } from "react-native-safe-area-context";
import SearchBar from "../components/SearchBar";
import CollapsibleCategory, { CollapsibleCategoryProps } from "../components/CollapsibleCategory";
import { entriesApi } from "../services/api";
// Cycles through as many groups as the API returns
const PALETTE: Pick<CollapsibleCategoryProps, "icon" | "color" | "darkColor">[] = [
{ icon: "book-outline", color: "#3B7DD8", darkColor: "#5E9EF4" },
{ icon: "book-outline", color: "#2E9E6B", darkColor: "#4EC992" },
{ icon: "book-outline", color: "#9B4FB8", darkColor: "#C47CE0" },
{ icon: "book-outline", color: "#C4622D", darkColor: "#E07B45" },
{ icon: "book-outline", color: "#B8834F", darkColor: "#D4A574" },
{ icon: "book-outline", color: "#2E7D9E", darkColor: "#4EA8C9" },
];
export default function AllFeed() {
const dark = useColorScheme() === "dark";
const [groups, setGroups] = useState<string[]>([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState("");
const [query, setQuery] = useState("");
const loadGroups = () => {
setLoading(true);
setError("");
entriesApi.getGroups()
.then(setGroups)
.catch(() => setError("Couldn't load groups."))
.finally(() => setLoading(false));
};
useEffect(() => { loadGroups(); }, []);
const visibleGroups = useMemo(() => {
if (!query.trim()) return groups;
const lower = query.toLowerCase();
return groups.filter((g) => g.toLowerCase().includes(lower));
}, [query, groups]);
return (
<SafeAreaView className={`flex-1 ${dark ? "bg-obsidian-200" : "bg-parchment-50"}`}>
{/* Header */}
<View className={`border-b ${dark ? "border-border-dark" : "border-border-light"}`}>
<View className="px-4 pt-2 pb-1">
<Text className={`text-2xl font-display font-bold ${dark ? "text-ink-dark" : "text-ink-light"}`}>
Discover
</Text>
<Text className={`text-xs mt-0.5 font-sans ${dark ? "text-muted-dark" : "text-muted-light"}`}>
{loading ? "Loading…" : `${groups.length} groups`}
</Text>
</View>
<SearchBar placeholder="Search groups…" onSearch={setQuery} />
</View>
{/* States */}
{loading ? (
<View className="flex-1 items-center justify-center">
<ActivityIndicator color={dark ? "#E07B45" : "#C4622D"} />
</View>
) : error ? (
<View className="flex-1 items-center justify-center px-8">
<Text className="text-4xl mb-3"></Text>
<Text className={`text-sm font-sans text-center mb-4 ${dark ? "text-muted-dark" : "text-muted-light"}`}>
{error}
</Text>
<TouchableOpacity
onPress={loadGroups}
className="px-5 py-2.5 rounded-xl"
style={{ backgroundColor: dark ? "#E07B45" : "#C4622D" }}
>
<Text className="text-sm font-sans font-semibold text-white">Retry</Text>
</TouchableOpacity>
</View>
) : (
<ScrollView
contentContainerStyle={{ paddingTop: 16, paddingBottom: 40 }}
showsVerticalScrollIndicator={false}
keyboardDismissMode="on-drag"
>
{visibleGroups.length === 0 ? (
<View className="items-center mt-16 px-8">
<Text className="text-4xl mb-3">🔍</Text>
<Text className={`text-base font-sans font-semibold text-center ${dark ? "text-ink-dark" : "text-ink-light"}`}>
No groups match "{query}"
</Text>
<Text className={`text-sm font-sans text-center mt-1 ${dark ? "text-muted-dark" : "text-muted-light"}`}>
Try a different search term.
</Text>
</View>
) : (
visibleGroups.map((groupName, index) => (
<CollapsibleCategory
key={groupName}
id={groupName}
label={groupName}
groupName={groupName}
defaultOpen={index === 0}
{...PALETTE[index % PALETTE.length]}
/>
))
)}
</ScrollView>
)}
</SafeAreaView>
);
}