Yaltopia-Tickets-App/app/notifications/index.tsx
2026-03-11 22:48:53 +03:00

135 lines
4.0 KiB
TypeScript

import React, { useCallback, useEffect, useState } from "react";
import { View, ActivityIndicator, FlatList, RefreshControl } from "react-native";
import { Text } from "@/components/ui/text";
import { Card, CardContent } from "@/components/ui/card";
import { ScreenWrapper } from "@/components/ScreenWrapper";
import { StandardHeader } from "@/components/StandardHeader";
import { api } from "@/lib/api";
import { EmptyState } from "@/components/EmptyState";
type NotificationItem = {
id: string;
title?: string;
body?: string;
message?: string;
createdAt?: string;
read?: boolean;
};
export default function NotificationsScreen() {
const [items, setItems] = useState<NotificationItem[]>([]);
const [loading, setLoading] = useState(true);
const [refreshing, setRefreshing] = useState(false);
const [page, setPage] = useState(1);
const [hasMore, setHasMore] = useState(true);
const [loadingMore, setLoadingMore] = useState(false);
const fetchNotifications = useCallback(
async (pageNum: number, mode: "initial" | "refresh" | "more") => {
try {
if (mode === "initial") setLoading(true);
if (mode === "refresh") setRefreshing(true);
if (mode === "more") setLoadingMore(true);
const res = await (api as any).notifications.getAll({
query: { page: pageNum, limit: 20 },
});
const next = (res?.data ?? []) as NotificationItem[];
if (mode === "more") {
setItems((prev) => [...prev, ...next]);
} else {
setItems(next);
}
setHasMore(Boolean(res?.meta?.hasNextPage));
setPage(pageNum);
} catch (e) {
setHasMore(false);
} finally {
setLoading(false);
setRefreshing(false);
setLoadingMore(false);
}
},
[],
);
useEffect(() => {
fetchNotifications(1, "initial");
}, [fetchNotifications]);
const onRefresh = () => fetchNotifications(1, "refresh");
const onEndReached = () => {
if (!loading && !loadingMore && hasMore) fetchNotifications(page + 1, "more");
};
const renderItem = ({ item }: { item: NotificationItem }) => {
const message = item.body ?? item.message ?? "";
const time = item.createdAt
? new Date(item.createdAt).toLocaleString()
: "";
return (
<Card className="mb-2">
<CardContent className="py-3">
<Text className="font-semibold text-foreground">
{item.title ?? "Notification"}
</Text>
{message ? (
<Text className="text-muted-foreground mt-1 text-sm">{message}</Text>
) : null}
{time ? (
<Text className="text-muted-foreground mt-1 text-xs">{time}</Text>
) : null}
</CardContent>
</Card>
);
};
return (
<ScreenWrapper className="bg-background">
<StandardHeader
showBack
title="Notifications"
rightAction="notificationsSettings"
/>
{loading ? (
<View className="flex-1 items-center justify-center">
<ActivityIndicator />
</View>
) : (
<FlatList
data={items}
keyExtractor={(i) => i.id}
renderItem={renderItem}
contentContainerStyle={{ padding: 16, paddingBottom: 32 }}
onEndReached={onEndReached}
onEndReachedThreshold={0.4}
refreshControl={
<RefreshControl refreshing={refreshing} onRefresh={onRefresh} />
}
ListEmptyComponent={
<View className="px-[16px] py-6">
<EmptyState
title="No notifications"
description="You don't have any notifications yet."
hint="Pull to refresh to check for new notifications."
previewLines={3}
/>
</View>
}
ListFooterComponent={
loadingMore ? (
<View className="py-4">
<ActivityIndicator />
</View>
) : null
}
/>
)}
</ScreenWrapper>
);
}