Dissolve/frontend/src/pages/MyDissolvesPage.tsx
2026-07-15 20:36:02 +05:30

104 lines
4.3 KiB
TypeScript

import { useEffect, useState } from 'react';
import { useQueryClient } from '@tanstack/react-query';
import { toast } from 'sonner';
import { AnimatePresence, motion } from 'framer-motion';
import { format, formatDistanceToNow } from 'date-fns';
import { Loader2, Inbox, Smile, Meh, Frown } from 'lucide-react';
import { useApi } from '@/hooks/useApi';
import { MyPostCard } from '@/components/MyPostCard';
import type { PostSummary } from '@/types';
export default function MyDissolvesPage() {
const queryClient = useQueryClient();
const { useGetMyPosts, useGetSummaries, useClearSummaries } = useApi();
const { data: myPostsData, isLoading: isLoadingPosts } = useGetMyPosts();
const { data: summariesData, isLoading: isLoadingSummaries } = useGetSummaries();
const clearSummariesMutation = useClearSummaries(queryClient);
const [shownSummaries, setShownSummaries] = useState<Set<string>>(new Set());
useEffect(() => {
const unseenSummaries = summariesData?.summaries.filter(s => !shownSummaries.has(s.id)) ?? [];
if (unseenSummaries.length > 0) {
const idsToShow = new Set<string>();
unseenSummaries.forEach(summary => {
toast(`Your feeling of '${summary.emotion_tag}' was held by ${summary.hold_count} people before it dissolved.`);
idsToShow.add(summary.id);
});
setShownSummaries(prev => new Set([...prev, ...idsToShow]));
// Here we can decide if we want to clear from DB after showing.
// For this implementation, we will not automatically clear, but allow user to see in a list.
}
}, [summariesData, shownSummaries]);
const activePosts = myPostsData?.posts ?? [];
const pastSummaries = summariesData?.summaries ?? [];
const getHoldIcon = (count: number) => {
if (count > 50) return <Smile className="h-6 w-6 text-green-500" />;
if (count > 10) return <Meh className="h-6 w-6 text-yellow-500" />;
return <Frown className="h-6 w-6 text-red-500" />;
}
return (
<div className="max-w-4xl mx-auto space-y-12">
<section>
<h1 className="text-2xl font-medium text-ink mb-6">Active Dissolves</h1>
{isLoadingPosts ? (
<div className="flex justify-center p-8"><Loader2 className="h-8 w-8 animate-spin text-muted" /></div>
) : activePosts.length === 0 ? (
<div className="text-center py-10 px-6 bg-surface-soft rounded-lg">
<p className="text-muted">You have no active feelings dissolving right now.</p>
</div>
) : (
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
<AnimatePresence>
{activePosts.map(post => <MyPostCard key={post.id} post={post} />)}
</AnimatePresence>
</div>
)}
</section>
<section>
<h1 className="text-2xl font-medium text-ink mb-6">Past Dissolves</h1>
{isLoadingSummaries ? (
<div className="flex justify-center p-8"><Loader2 className="h-8 w-8 animate-spin text-muted" /></div>
) : pastSummaries.length === 0 ? (
<div className="text-center py-10 px-6 bg-surface-soft rounded-lg">
<Inbox className="mx-auto h-12 w-12 text-muted-soft"/>
<p className="mt-4 text-muted">Summaries of your past feelings will appear here once they dissolve.</p>
</div>
) : (
<div className="space-y-3">
{pastSummaries.map((summary: PostSummary) => (
<motion.div
key={summary.id}
initial={{ opacity: 0, y: -10 }}
animate={{ opacity: 1, y: 0 }}
className="flex items-center justify-between p-4 bg-surface-soft rounded-lg"
>
<div className="flex items-center gap-4">
{getHoldIcon(summary.hold_count)}
<div>
<p className="font-medium text-ink">
Your feeling of <span className="font-bold">{summary.emotion_tag}</span> was held by {summary.hold_count} people.
</p>
<p className="text-sm text-muted-soft">
Dissolved {formatDistanceToNow(new Date(summary.dissolved_at), { addSuffix: true })}
</p>
</div>
</div>
</motion.div>
))}
</div>
)}
</section>
</div>
);
}