owner toy list show personal description and owner avator icon

This commit is contained in:
Indigo Tang 2025-06-09 04:13:27 +00:00
parent 362e8adf57
commit f522dd88a1
3 changed files with 77 additions and 27 deletions

View File

@ -1,17 +1,39 @@
import Link from 'next/link'; import Link from 'next/link';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import ToyList from '@/components/toys/ToyList'; import ToyList from '@/components/toys/ToyList';
import { mockToys } from '@/lib/mockData'; import { mockToys } from '@/lib/mockData';
import type { Toy } from '@/types'; import type { Toy } from '@/types';
import { getI18n, getStaticParams as getLocaleStaticParams } from '@/locales/server'; import { getI18n, getStaticParams as getLocaleStaticParams } from '@/locales/server';
import { ArrowLeft, Home } from 'lucide-react'; import { Home, UserCircle } from 'lucide-react';
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
import { ToyBrick } from 'lucide-react'; import { ToyBrick } from 'lucide-react';
import { Avatar, AvatarImage, AvatarFallback } from "@/components/ui/avatar";
interface OwnerToysPageProps { interface OwnerToysPageProps {
params: { ownerId: string; locale: string }; params: { ownerId: string; locale: string };
} }
// Mock owner profiles - can be expanded or moved to a data file later
const mockOwnerProfiles: Record<string, { avatarUrl: string; bio: string; name?: string }> = {
'user1': { // Alice Wonderland
name: 'Alice W.', // Can be different from toy.ownerName for display
avatarUrl: 'https://placehold.co/100x100.png?text=AW',
bio: "Lover of imaginative play and sharing joy. I have a collection of classic storybooks and dress-up costumes that my kids have outgrown but still have lots of life left in them!"
},
'user2': { // Bob The Builder
name: 'Bob T.B.',
avatarUrl: 'https://placehold.co/100x100.png?text=BT',
bio: "Can we fix it? Yes, we can! Sharing my collection of construction toys, tools, and playsets. Always happy to help another budding builder."
},
'user3': { // Carol Danvers
name: 'Captain C.',
avatarUrl: 'https://placehold.co/100x100.png?text=CD',
bio: "Higher, further, faster. Sharing toys that inspire adventure, courage, and exploration. My collection includes superhero action figures and space-themed playsets."
}
};
async function getOwnerToys(ownerId: string): Promise<Toy[]> { async function getOwnerToys(ownerId: string): Promise<Toy[]> {
await new Promise(resolve => setTimeout(resolve, 100)); // Simulate fetch await new Promise(resolve => setTimeout(resolve, 100)); // Simulate fetch
return mockToys.filter(toy => toy.ownerId === ownerId); return mockToys.filter(toy => toy.ownerId === ownerId);
@ -21,34 +43,54 @@ export default async function OwnerToysPage({ params }: OwnerToysPageProps) {
const t = await getI18n(); const t = await getI18n();
const ownerToys = await getOwnerToys(params.ownerId); const ownerToys = await getOwnerToys(params.ownerId);
let ownerName: string | undefined; const ownerProfile = mockOwnerProfiles[params.ownerId];
if (ownerToys.length > 0) { const ownerNameFromToys = ownerToys.length > 0 ? ownerToys[0].ownerName : undefined;
ownerName = ownerToys[0].ownerName;
} else {
// Attempt to find owner name even if they have no toys, if we had a user list
// For now, we rely on toys or show a generic message if ownerId itself is unknown
const ownerFromAnyToy = mockToys.find(toy => toy.ownerId === params.ownerId);
if (ownerFromAnyToy) {
ownerName = ownerFromAnyToy.ownerName;
}
}
const pageTitle = ownerName let displayOwnerName = ownerProfile?.name || ownerNameFromToys || t('owner_toys.unknown_owner');
? t('owner_toys.title', { ownerName })
: t('owner_toys.owner_not_found'); const pageTitle = displayOwnerName !== t('owner_toys.unknown_owner')
? t('owner_toys.title_specific', { ownerName: displayOwnerName })
: t('owner_toys.title_generic');
return ( return (
<div className="space-y-8"> <div className="space-y-8">
<div className="flex justify-between items-center"> <div className="flex flex-col sm:flex-row justify-between items-start sm:items-center gap-4">
<h1 className="text-3xl font-bold font-headline text-primary">{pageTitle}</h1> <h1 className="text-3xl font-bold font-headline text-primary">{pageTitle}</h1>
<Link href="/" passHref> <Link href={`/${params.locale}/`} passHref>
<Button variant="outline"> <Button variant="outline" className="w-full sm:w-auto">
<Home className="mr-2 h-4 w-4" /> <Home className="mr-2 h-4 w-4" />
{t('owner_toys.back_to_home')} {t('owner_toys.back_to_home')}
</Button> </Button>
</Link> </Link>
</div> </div>
{ownerProfile && (
<Card className="mb-8 shadow-lg border-accent/30">
<CardHeader>
<div className="flex flex-col sm:flex-row items-center gap-4">
<Avatar className="h-20 w-20 sm:h-24 sm:w-24 border-2 border-accent">
<AvatarImage src={ownerProfile.avatarUrl} alt={displayOwnerName} data-ai-hint="owner avatar" />
<AvatarFallback className="text-3xl bg-muted">
{displayOwnerName ? displayOwnerName.split(' ').map(n => n[0]).join('').toUpperCase() : <UserCircle />}
</AvatarFallback>
</Avatar>
<div className="text-center sm:text-left">
<CardTitle className="text-2xl font-headline text-accent">
{t('owner_toys.about_owner', { ownerName: displayOwnerName })}
</CardTitle>
{/* Display the original ownerName from toy data if it's different and available */}
{ownerNameFromToys && ownerNameFromToys !== displayOwnerName && (
<CardDescription>{t('toy_details.owner')}: {ownerNameFromToys}</CardDescription>
)}
</div>
</div>
</CardHeader>
<CardContent>
<p className="text-foreground/80 leading-relaxed">{ownerProfile.bio}</p>
</CardContent>
</Card>
)}
{ownerToys.length > 0 ? ( {ownerToys.length > 0 ? (
<ToyList toys={ownerToys.map(toy => ({...toy, dataAiHint: toy.category.toLowerCase()}))} /> <ToyList toys={ownerToys.map(toy => ({...toy, dataAiHint: toy.category.toLowerCase()}))} />
) : ( ) : (
@ -56,12 +98,14 @@ export default async function OwnerToysPage({ params }: OwnerToysPageProps) {
<CardHeader> <CardHeader>
<ToyBrick className="h-16 w-16 mx-auto text-muted-foreground mb-4" /> <ToyBrick className="h-16 w-16 mx-auto text-muted-foreground mb-4" />
<CardTitle> <CardTitle>
{ownerName ? t('owner_toys.no_toys_listed_by', { ownerName }) : t('owner_toys.owner_not_found')} {displayOwnerName !== t('owner_toys.unknown_owner')
? t('owner_toys.no_toys_listed_by', { ownerName: displayOwnerName })
: t('owner_toys.owner_not_found')}
</CardTitle> </CardTitle>
{ownerName && <CardDescription>{t('home.explore_toys')}</CardDescription>} {displayOwnerName !== t('owner_toys.unknown_owner') && <CardDescription>{t('home.explore_toys')}</CardDescription>}
</CardHeader> </CardHeader>
<CardContent> <CardContent>
<Link href="/" passHref> <Link href={`/${params.locale}/`} passHref>
<Button size="lg"> <Button size="lg">
{t('home.explore_toys')} {t('home.explore_toys')}
</Button> </Button>
@ -74,7 +118,7 @@ export default async function OwnerToysPage({ params }: OwnerToysPageProps) {
} }
export async function generateStaticParams() { export async function generateStaticParams() {
const localeParams = getLocaleStaticParams(); // e.g. [{ locale: 'en' }, { locale: 'zh-TW' }] const localeParams = getLocaleStaticParams();
const ownerIds = Array.from(new Set(mockToys.map(toy => toy.ownerId))); const ownerIds = Array.from(new Set(mockToys.map(toy => toy.ownerId)));
const ownerParams = ownerIds.map(id => ({ ownerId: id })); const ownerParams = ownerIds.map(id => ({ ownerId: id }));

View File

@ -151,11 +151,14 @@ export default {
'dashboard.requests.status_pending': 'Pending', 'dashboard.requests.status_pending': 'Pending',
'dashboard.requests.status_approved': 'Approved', 'dashboard.requests.status_approved': 'Approved',
'dashboard.requests.status_declined': 'Declined', 'dashboard.requests.status_declined': 'Declined',
'owner_toys.title': "{ownerName}'s Shared Toys", 'owner_toys.title_specific': "{ownerName}'s Toy Collection",
'owner_toys.title_generic': "Owner's Toy Collection",
'owner_toys.about_owner': "About {ownerName}",
'owner_toys.no_toys_listed_by': '{ownerName} has not listed any toys yet.', 'owner_toys.no_toys_listed_by': '{ownerName} has not listed any toys yet.',
'owner_toys.owner_not_found': 'Owner not found or has no toys listed.', 'owner_toys.owner_not_found': 'Owner profile not found or they have no toys listed.',
'owner_toys.back_to_home': 'Back to Home', 'owner_toys.back_to_home': 'Back to Home',
'owner_toys.unknown_owner': 'Unknown Owner', 'owner_toys.unknown_owner': 'Unknown Owner',
'owner_toys.unknown_owner_simple': 'This Owner',
'toy_categories.educational': 'Educational', 'toy_categories.educational': 'Educational',
'toy_categories.vehicles': 'Vehicles', 'toy_categories.vehicles': 'Vehicles',
'toy_categories.electronics': 'Electronics', 'toy_categories.electronics': 'Electronics',

View File

@ -151,11 +151,14 @@ export default {
'dashboard.requests.status_pending': '待處理', 'dashboard.requests.status_pending': '待處理',
'dashboard.requests.status_approved': '已批准', 'dashboard.requests.status_approved': '已批准',
'dashboard.requests.status_declined': '已拒絕', 'dashboard.requests.status_declined': '已拒絕',
'owner_toys.title': '{ownerName} 分享的玩具', 'owner_toys.title_specific': "{ownerName}的玩具收藏",
'owner_toys.title_generic': "擁有者的玩具收藏",
'owner_toys.about_owner': "關於 {ownerName}",
'owner_toys.no_toys_listed_by': '{ownerName} 目前沒有列出任何玩具。', 'owner_toys.no_toys_listed_by': '{ownerName} 目前沒有列出任何玩具。',
'owner_toys.owner_not_found': '找不到擁有者或該擁有者沒有列出任何玩具。', 'owner_toys.owner_not_found': '找不到擁有者資訊或該擁有者沒有列出任何玩具。',
'owner_toys.back_to_home': '返回首頁', 'owner_toys.back_to_home': '返回首頁',
'owner_toys.unknown_owner': '未知擁有者', 'owner_toys.unknown_owner': '未知擁有者',
'owner_toys.unknown_owner_simple': '此擁有者',
'toy_categories.educational': '教育類', 'toy_categories.educational': '教育類',
'toy_categories.vehicles': '交通工具', 'toy_categories.vehicles': '交通工具',
'toy_categories.electronics': '電子玩具', 'toy_categories.electronics': '電子玩具',