Files
petfeed/src/components/profile/ProfileTabs.tsx
T

111 lines
4.0 KiB
TypeScript

"use client";
import { useState, useCallback } from "react";
import { Layers2 } from "lucide-react";
import { useQuery } from "@tanstack/react-query";
import { useTRPC } from "@/trpc/client";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { MilestoneCard } from "@/components/feed/MilestoneCard";
import { getMediaUrl } from "@/lib/media-url";
import type { PostCardPost } from "@/components/feed/PostCard";
interface ProfileTabsProps {
petId: string;
}
/**
* ProfileTabs — Posts (3-col photo grid) + Milestones (chronological list) (MILE-02).
*
* Posts tab: photo posts fetched via posts.byPetId; carousel posts get a Layers2 overlay.
* Milestones tab: milestone posts via milestones.listByPet rendered as MilestoneCard.
* Active tab has orange-500 underline (shadcn Tabs default with --primary: orange-500).
*/
export function ProfileTabs({ petId }: ProfileTabsProps) {
const trpc = useTRPC();
const [_activeTab, setActiveTab] = useState("posts");
const { data: postsData } = useQuery(
trpc.posts.byPetId.queryOptions({ petId, limit: 30 })
);
const { data: milestonesData } = useQuery(
trpc.milestones.listByPet.queryOptions({ petId, limit: 30 })
);
const posts = postsData?.posts ?? [];
const milestones = (milestonesData ?? []) as PostCardPost[];
const handleTabChange = useCallback((tab: string) => {
setActiveTab(tab);
}, []);
return (
<Tabs defaultValue="posts" onValueChange={handleTabChange}>
<TabsList className="w-full rounded-none border-b bg-transparent h-auto p-0">
<TabsTrigger
value="posts"
className="flex-1 rounded-none border-b-2 border-transparent data-[state=active]:border-orange-500 data-[state=active]:text-foreground data-[state=active]:shadow-none pb-2"
>
Posts
</TabsTrigger>
<TabsTrigger
value="milestones"
className="flex-1 rounded-none border-b-2 border-transparent data-[state=active]:border-orange-500 data-[state=active]:text-foreground data-[state=active]:shadow-none pb-2"
>
Milestones
</TabsTrigger>
</TabsList>
{/* Posts tab — 3-column photo grid */}
<TabsContent value="posts" className="mt-0">
{posts.length === 0 ? (
<p className="text-sm text-muted-foreground text-center py-10">
No posts yet
</p>
) : (
<div className="grid grid-cols-3 gap-0.5 mt-0.5">
{posts.map((post) => {
const firstImage = post.images?.[0];
const isCarousel = (post.images?.length ?? 0) > 1;
const mediaUrl = firstImage ? getMediaUrl(firstImage.storageKey) : null;
return (
<div key={post.id} className="relative aspect-square overflow-hidden bg-muted">
{mediaUrl ? (
// eslint-disable-next-line @next/next/no-img-element
<img
src={mediaUrl}
alt={post.caption ?? "Post"}
className="w-full h-full object-cover"
/>
) : (
<div className="w-full h-full bg-muted" />
)}
{isCarousel && (
<div className="absolute top-1.5 right-1.5">
<Layers2 className="h-4 w-4 text-white drop-shadow" aria-hidden="true" />
</div>
)}
</div>
);
})}
</div>
)}
</TabsContent>
{/* Milestones tab — chronological MilestoneCard list */}
<TabsContent value="milestones" className="mt-4 space-y-4">
{milestones.length === 0 ? (
<p className="text-sm text-muted-foreground text-center py-10">
No milestones yet
</p>
) : (
milestones.map((post) => (
<MilestoneCard key={post.id} post={post} />
))
)}
</TabsContent>
</Tabs>
);
}