toy availability change to assign date range for rental, toy page show c

This commit is contained in:
Indigo Tang 2025-06-09 09:20:54 +00:00
parent d45edc5f88
commit e52d2d2977
7 changed files with 86 additions and 121 deletions

View File

@ -3,15 +3,18 @@ import Image from 'next/image';
import { mockToys } from '@/lib/mockData'; import { mockToys } from '@/lib/mockData';
import type { Toy } from '@/types'; import type { Toy } from '@/types';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import AvailabilityCalendar from '@/components/toys/AvailabilityCalendar'; import { Calendar } from '@/components/ui/calendar'; // Using ShadCN calendar
import { ArrowLeft, CalendarDays, DollarSign, MapPin, ShoppingBag, UserCircle2 } from 'lucide-react'; import { ArrowLeft, DollarSign, MapPin, ShoppingBag, UserCircle2 } from 'lucide-react';
import Link from 'next/link'; import Link from 'next/link';
import { Badge } from '@/components/ui/badge'; import { Badge } from '@/components/ui/badge';
import { Separator } from '@/components/ui/separator'; import { Separator } from '@/components/ui/separator';
import { getI18n, getStaticParams as getLocaleStaticParams } from '@/locales/server'; // Renamed to avoid conflict import { getI18n, getStaticParams as getLocaleStaticParams } from '@/locales/server';
import type { Locale } from '@/locales/server';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { addDays, parseISO } from 'date-fns'; // For date manipulation
interface ToyPageProps { interface ToyPageProps {
params: { id: string, locale: string }; params: { id: string, locale: Locale };
} }
async function getToyById(id: string): Promise<Toy | undefined> { async function getToyById(id: string): Promise<Toy | undefined> {
@ -40,6 +43,17 @@ export default async function ToyPage({ params }: ToyPageProps) {
const placeholderHint = toy.category.toLowerCase() || "toy detail"; const placeholderHint = toy.category.toLowerCase() || "toy detail";
const disabledDates = toy.unavailableRanges.map(range => {
// react-day-picker expects Date objects for ranges
const from = parseISO(range.startDate);
const to = parseISO(range.endDate);
// If 'to' is inclusive, add a day for the range. react-day-picker's 'to' is exclusive for the visual range.
// However, for disabling, if a range is "2023-08-10" to "2023-08-12", all 3 days should be disabled.
// The `disabled` prop for DayPicker usually treats `to` as inclusive.
return { from, to };
});
return ( return (
<div className="container mx-auto py-8 px-4"> <div className="container mx-auto py-8 px-4">
<Link href={`/${params.locale}/`} className="inline-flex items-center text-primary hover:underline mb-6 group"> <Link href={`/${params.locale}/`} className="inline-flex items-center text-primary hover:underline mb-6 group">
@ -120,7 +134,22 @@ export default async function ToyPage({ params }: ToyPageProps) {
<Separator /> <Separator />
<AvailabilityCalendar availability={toy.availability} /> <Card className="shadow-md">
<CardHeader>
<CardTitle className="text-xl font-headline text-primary">{t('toy_details.availability_calendar_title')}</CardTitle>
</CardHeader>
<CardContent className="flex justify-center">
<Calendar
mode="single" // "single" is fine for display, range selection would be for booking
disabled={disabledDates} // Disable booked ranges
month={new Date()} // Show current month by default
className="rounded-md border"
/>
</CardContent>
<p className="text-xs text-muted-foreground mt-0 pb-4 text-center">
{t('toy_details.calendar_note')}
</p>
</Card>
<Button size="lg" className="w-full mt-6 transition-transform transform hover:scale-105"> <Button size="lg" className="w-full mt-6 transition-transform transform hover:scale-105">
<ShoppingBag className="mr-2 h-5 w-5" /> {t('toy_details.request_to_rent')} <ShoppingBag className="mr-2 h-5 w-5" /> {t('toy_details.request_to_rent')}
@ -132,7 +161,7 @@ export default async function ToyPage({ params }: ToyPageProps) {
} }
export function generateStaticParams() { export function generateStaticParams() {
const localeParams = getLocaleStaticParams(); // e.g. [{ locale: 'en' }, { locale: 'zh-TW' }] const localeParams = getLocaleStaticParams();
const toyParams = mockToys.map((toy) => ({ id: toy.id })); const toyParams = mockToys.map((toy) => ({ id: toy.id }));
return localeParams.flatMap(lang => return localeParams.flatMap(lang =>

View File

@ -9,7 +9,6 @@ import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label'; import { Label } from '@/components/ui/label';
import { Textarea } from '@/components/ui/textarea'; import { Textarea } from '@/components/ui/textarea';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import { Checkbox } from '@/components/ui/checkbox';
import { useToast } from '@/hooks/use-toast'; import { useToast } from '@/hooks/use-toast';
import { ToyBrick, Save, PlusCircle, Trash2 } from 'lucide-react'; import { ToyBrick, Save, PlusCircle, Trash2 } from 'lucide-react';
import type { Toy } from '@/types'; import type { Toy } from '@/types';
@ -30,9 +29,6 @@ const toyCategoryDefinitions = [
{ key: 'building_blocks', value: 'Building Blocks' }, { key: 'building_blocks', value: 'Building Blocks' },
]; ];
const daysOfWeek = ['monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday'] as const;
interface AddToyFormProps { interface AddToyFormProps {
initialData?: Partial<Toy>; initialData?: Partial<Toy>;
isEditMode?: boolean; isEditMode?: boolean;
@ -50,11 +46,8 @@ export default function AddToyForm({ initialData, isEditMode = false }: AddToyFo
const [pricePerDay, setPricePerDay] = useState(initialData?.pricePerDay?.toString() || '0'); const [pricePerDay, setPricePerDay] = useState(initialData?.pricePerDay?.toString() || '0');
const [location, setLocation] = useState(initialData?.location || ''); const [location, setLocation] = useState(initialData?.location || '');
const [images, setImages] = useState<string[]>(initialData?.images || ['']); const [images, setImages] = useState<string[]>(initialData?.images || ['']);
const [availability, setAvailability] = useState<Toy['availability']>( // unavailableRanges will be initialized as empty or from initialData, but not editable in this form version.
initialData?.availability || { const [unavailableRanges, setUnavailableRanges] = useState<Toy['unavailableRanges']>(initialData?.unavailableRanges || []);
monday: true, tuesday: true, wednesday: true, thursday: true, friday: true, saturday: false, sunday: false
}
);
const [isLoading, setIsLoading] = useState(false); const [isLoading, setIsLoading] = useState(false);
const handleImageChange = (index: number, value: string) => { const handleImageChange = (index: number, value: string) => {
@ -72,34 +65,34 @@ export default function AddToyForm({ initialData, isEditMode = false }: AddToyFo
} }
}; };
const handleAvailabilityChange = (day: keyof Toy['availability']) => {
setAvailability(prev => ({ ...prev, [day]: !prev[day] }));
};
const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => { const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault(); e.preventDefault();
setIsLoading(true); setIsLoading(true);
if (!name || !description || !category) { if (!name || !description || !category) {
toast({ title: "Missing Fields", description: "Please fill in all required fields.", variant: "destructive" }); // Translate toast({ title: "Missing Fields", description: "Please fill in all required fields.", variant: "destructive" });
setIsLoading(false); setIsLoading(false);
return; return;
} }
const toyData = { const toyData: Partial<Toy> = {
name, description, category, name, description, category,
pricePerDay: parseFloat(pricePerDay) || 0, pricePerDay: parseFloat(pricePerDay) || 0,
location, location,
images: images.filter(img => img.trim() !== ''), images: images.filter(img => img.trim() !== ''),
availability, unavailableRanges: initialData?.unavailableRanges || [], // Preserve existing, or empty for new
}; };
if (isEditMode && initialData?.id) {
toyData.id = initialData.id;
}
console.log("Submitting toy data:", toyData); console.log("Submitting toy data:", toyData);
await new Promise(resolve => setTimeout(resolve, 1500)); await new Promise(resolve => setTimeout(resolve, 1500));
toast({ toast({
title: isEditMode ? "Toy Updated!" : "Toy Added!", // Translate title: isEditMode ? t('add_toy_form.edit_title_toast') : t('add_toy_form.add_title_toast'),
description: `${name} has been successfully ${isEditMode ? 'updated' : 'listed'}.`, // Translate description: t('add_toy_form.success_description_toast', { toyName: name, action: isEditMode ? t('add_toy_form.updated_action_toast') : t('add_toy_form.listed_action_toast')})
}); });
router.push(`/${locale}/dashboard/my-toys`); router.push(`/${locale}/dashboard/my-toys`);
setIsLoading(false); setIsLoading(false);
@ -137,7 +130,7 @@ export default function AddToyForm({ initialData, isEditMode = false }: AddToyFo
<SelectContent> <SelectContent>
{toyCategoryDefinitions.map(catDef => ( {toyCategoryDefinitions.map(catDef => (
<SelectItem key={catDef.key} value={catDef.value}> <SelectItem key={catDef.key} value={catDef.value}>
{t(`toy_categories.${catDef.key}` as any)} {/* Use 'as any' if TS complains about template literal type */} {t(`toy_categories.${catDef.key}` as any)}
</SelectItem> </SelectItem>
))} ))}
</SelectContent> </SelectContent>
@ -180,23 +173,6 @@ export default function AddToyForm({ initialData, isEditMode = false }: AddToyFo
)} )}
</div> </div>
<div className="space-y-3">
<Label className="text-base">{t('add_toy_form.availability_label')}</Label>
<div className="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 gap-4">
{daysOfWeek.map(day => (
<div key={day} className="flex items-center space-x-2">
<Checkbox
id={`avail-${day}`}
checked={availability[day]}
onCheckedChange={() => handleAvailabilityChange(day as keyof Toy['availability'])}
disabled={isLoading}
/>
<Label htmlFor={`avail-${day}`} className="capitalize font-normal text-sm">{day}</Label>
</div>
))}
</div>
</div>
<CardFooter className="p-0 pt-6"> <CardFooter className="p-0 pt-6">
<Button type="submit" className="w-full" size="lg" disabled={isLoading}> <Button type="submit" className="w-full" size="lg" disabled={isLoading}>
{isLoading ? (isEditMode ? t('add_toy_form.saving_button') : t('add_toy_form.listing_button')) : ( {isLoading ? (isEditMode ? t('add_toy_form.saving_button') : t('add_toy_form.listing_button')) : (
@ -212,5 +188,3 @@ export default function AddToyForm({ initialData, isEditMode = false }: AddToyFo
</Card> </Card>
); );
} }

View File

@ -1,54 +0,0 @@
import type { Toy } from '@/types';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { CheckCircle2, XCircle } from 'lucide-react';
import { cn } from '@/lib/utils';
interface AvailabilityCalendarProps {
availability: Toy['availability'];
}
const daysOfWeek = [
{ key: 'monday', label: 'Mon' },
{ key: 'tuesday', label: 'Tue' },
{ key: 'wednesday', label: 'Wed' },
{ key: 'thursday', label: 'Thu' },
{ key: 'friday', label: 'Fri' },
{ key: 'saturday', label: 'Sat' },
{ key: 'sunday', label: 'Sun' },
] as const; // Use 'as const' for stricter typing of keys
export default function AvailabilityCalendar({ availability }: AvailabilityCalendarProps) {
return (
<Card className="shadow-md">
<CardHeader>
<CardTitle className="text-xl font-headline text-primary">Weekly Availability</CardTitle>
</CardHeader>
<CardContent>
<div className="grid grid-cols-3 sm:grid-cols-4 md:grid-cols-7 gap-2 text-center">
{daysOfWeek.map((day) => {
const isAvailable = availability[day.key];
return (
<div
key={day.key}
className={cn(
"p-3 rounded-md border flex flex-col items-center justify-center space-y-1",
isAvailable ? "bg-green-100 border-green-300" : "bg-red-100 border-red-300"
)}
>
<span className="font-medium text-sm text-foreground/80">{day.label}</span>
{isAvailable ? (
<CheckCircle2 className="h-6 w-6 text-green-600" />
) : (
<XCircle className="h-6 w-6 text-red-600" />
)}
</div>
);
})}
</div>
<p className="text-xs text-muted-foreground mt-4 text-center">
This calendar shows general weekly availability. Specific dates may vary.
</p>
</CardContent>
</Card>
);
}

View File

@ -1,4 +1,7 @@
import type { Toy, RentalHistoryEntry } from '@/types'; import type { Toy, RentalHistoryEntry } from '@/types';
import { addDays, formatISO } from 'date-fns';
const today = new Date();
export const mockToys: Toy[] = [ export const mockToys: Toy[] = [
{ {
@ -7,7 +10,10 @@ export const mockToys: Toy[] = [
description: 'A fantastic set of 100 colorful building blocks to spark creativity in young minds. Suitable for ages 3+.', description: 'A fantastic set of 100 colorful building blocks to spark creativity in young minds. Suitable for ages 3+.',
category: 'Educational', category: 'Educational',
images: ['https://placehold.co/600x400.png?text=Building+Blocks', 'https://placehold.co/600x400.png?text=Blocks+Close+Up'], images: ['https://placehold.co/600x400.png?text=Building+Blocks', 'https://placehold.co/600x400.png?text=Blocks+Close+Up'],
availability: { monday: true, tuesday: true, wednesday: false, thursday: true, friday: true, saturday: true, sunday: false }, unavailableRanges: [
{ startDate: formatISO(addDays(today, 5), { representation: 'date' }), endDate: formatISO(addDays(today, 7), { representation: 'date' }) },
{ startDate: formatISO(addDays(today, 15), { representation: 'date' }), endDate: formatISO(addDays(today, 16), { representation: 'date' }) },
],
ownerName: 'Alice Wonderland', ownerName: 'Alice Wonderland',
ownerId: 'user1', ownerId: 'user1',
pricePerDay: 5, pricePerDay: 5,
@ -20,7 +26,9 @@ export const mockToys: Toy[] = [
description: 'Zoom around with this super-fast remote control racing car. Features rechargeable batteries and durable design. Ages 6+.', description: 'Zoom around with this super-fast remote control racing car. Features rechargeable batteries and durable design. Ages 6+.',
category: 'Vehicles', category: 'Vehicles',
images: ['https://placehold.co/600x400.png?text=RC+Car', 'https://placehold.co/600x400.png?text=RC+Car+Controller'], images: ['https://placehold.co/600x400.png?text=RC+Car', 'https://placehold.co/600x400.png?text=RC+Car+Controller'],
availability: { monday: false, tuesday: true, wednesday: true, thursday: true, friday: true, saturday: true, sunday: true }, unavailableRanges: [
{ startDate: formatISO(addDays(today, 10), { representation: 'date' }), endDate: formatISO(addDays(today, 12), { representation: 'date' }) },
],
ownerName: 'Bob The Builder', ownerName: 'Bob The Builder',
ownerId: 'user2', ownerId: 'user2',
pricePerDay: 8, pricePerDay: 8,
@ -33,7 +41,7 @@ export const mockToys: Toy[] = [
description: 'An educational tablet for kids with games, stories, and learning activities. Parent-approved content. Ages 4-7.', description: 'An educational tablet for kids with games, stories, and learning activities. Parent-approved content. Ages 4-7.',
category: 'Electronics', category: 'Electronics',
images: ['https://placehold.co/600x400.png?text=Kids+Tablet', 'https://placehold.co/600x400.png?text=Tablet+Screen'], images: ['https://placehold.co/600x400.png?text=Kids+Tablet', 'https://placehold.co/600x400.png?text=Tablet+Screen'],
availability: { monday: true, tuesday: true, wednesday: true, thursday: true, friday: true, saturday: false, sunday: false }, unavailableRanges: [],
ownerName: 'Carol Danvers', ownerName: 'Carol Danvers',
ownerId: 'user3', ownerId: 'user3',
pricePerDay: 7, pricePerDay: 7,
@ -46,8 +54,10 @@ export const mockToys: Toy[] = [
description: 'A cuddly and soft large teddy bear, perfect for hugs and comfort. Hypoallergenic materials. All ages.', description: 'A cuddly and soft large teddy bear, perfect for hugs and comfort. Hypoallergenic materials. All ages.',
category: 'Plush Toys', category: 'Plush Toys',
images: ['https://placehold.co/600x400.png?text=Teddy+Bear'], images: ['https://placehold.co/600x400.png?text=Teddy+Bear'],
availability: { monday: true, tuesday: true, wednesday: true, thursday: true, friday: true, saturday: true, sunday: true }, unavailableRanges: [
ownerName: 'Alice Wonderland', // Changed owner for variety, was David Copperfield { startDate: formatISO(addDays(today, 20), { representation: 'date' }), endDate: formatISO(addDays(today, 25), { representation: 'date' }) },
],
ownerName: 'Alice Wonderland',
ownerId: 'user1', ownerId: 'user1',
pricePerDay: 3, pricePerDay: 3,
location: 'Springfield Gardens', location: 'Springfield Gardens',
@ -59,8 +69,8 @@ export const mockToys: Toy[] = [
description: 'A 3/4 size acoustic guitar, ideal for children starting their musical journey. Comes with a soft case and picks.', description: 'A 3/4 size acoustic guitar, ideal for children starting their musical journey. Comes with a soft case and picks.',
category: 'Musical', category: 'Musical',
images: ['https://placehold.co/600x400.png?text=Kids+Guitar'], images: ['https://placehold.co/600x400.png?text=Kids+Guitar'],
availability: { monday: true, tuesday: false, wednesday: true, thursday: false, friday: true, saturday: true, sunday: true }, unavailableRanges: [],
ownerName: 'Bob The Builder', // Changed owner, was Eve Adamson ownerName: 'Bob The Builder',
ownerId: 'user2', ownerId: 'user2',
pricePerDay: 10, pricePerDay: 10,
location: 'Willow Creek', location: 'Willow Creek',
@ -72,8 +82,8 @@ export const mockToys: Toy[] = [
description: 'Includes a frisbee, a jump rope, and a set of cones. Perfect for outdoor fun and activities.', description: 'Includes a frisbee, a jump rope, and a set of cones. Perfect for outdoor fun and activities.',
category: 'Outdoor', category: 'Outdoor',
images: ['https://placehold.co/600x400.png?text=Sports+Kit'], images: ['https://placehold.co/600x400.png?text=Sports+Kit'],
availability: { monday: true, tuesday: true, wednesday: true, thursday: true, friday: true, saturday: true, sunday: true }, unavailableRanges: [],
ownerName: 'Carol Danvers', // Changed owner, was Frank Castle ownerName: 'Carol Danvers',
ownerId: 'user3', ownerId: 'user3',
pricePerDay: 6, pricePerDay: 6,
location: 'Metro City', location: 'Metro City',
@ -85,7 +95,7 @@ export const mockRentalHistory: RentalHistoryEntry[] = [
{ {
id: 'hist1', id: 'hist1',
userId: 'user1', userId: 'user1',
toy: mockToys[2], // Interactive Learning Tablet from Carol Danvers (user3) toy: mockToys[2],
rentalStartDate: '2024-05-01', rentalStartDate: '2024-05-01',
rentalEndDate: '2024-05-07', rentalEndDate: '2024-05-07',
totalCost: mockToys[2].pricePerDay! * 7, totalCost: mockToys[2].pricePerDay! * 7,
@ -95,7 +105,7 @@ export const mockRentalHistory: RentalHistoryEntry[] = [
{ {
id: 'hist2', id: 'hist2',
userId: 'user1', userId: 'user1',
toy: mockToys[5], // Outdoor Sports Kit from Carol Danvers (user3) toy: mockToys[5],
rentalStartDate: '2024-06-10', rentalStartDate: '2024-06-10',
rentalEndDate: '2024-06-15', rentalEndDate: '2024-06-15',
totalCost: mockToys[5].pricePerDay! * 5, totalCost: mockToys[5].pricePerDay! * 5,
@ -104,8 +114,8 @@ export const mockRentalHistory: RentalHistoryEntry[] = [
}, },
{ {
id: 'hist3', id: 'hist3',
userId: 'user2', // Different user userId: 'user2',
toy: mockToys[0], // Building Blocks from Alice Wonderland (user1) toy: mockToys[0],
rentalStartDate: '2024-07-01', rentalStartDate: '2024-07-01',
rentalEndDate: '2024-07-10', rentalEndDate: '2024-07-10',
totalCost: mockToys[0].pricePerDay! * 10, totalCost: mockToys[0].pricePerDay! * 10,

View File

@ -45,6 +45,8 @@ export default {
'toy_details.price_free': 'Free', 'toy_details.price_free': 'Free',
'toy_details.price_per_day': '/day', 'toy_details.price_per_day': '/day',
'toy_details.request_to_rent': 'Request to Rent', 'toy_details.request_to_rent': 'Request to Rent',
'toy_details.availability_calendar_title': 'Availability Calendar',
'toy_details.calendar_note': 'Dates shown in gray or crossed out are unavailable.',
'dashboard.layout.loading': 'Loading Dashboard...', 'dashboard.layout.loading': 'Loading Dashboard...',
'dashboard.sidebar.user_dashboard': 'User Dashboard', 'dashboard.sidebar.user_dashboard': 'User Dashboard',
'dashboard.sidebar.toy_management': 'Toy Management', 'dashboard.sidebar.toy_management': 'Toy Management',
@ -131,6 +133,11 @@ export default {
'add_toy_form.list_button': 'List My Toy', 'add_toy_form.list_button': 'List My Toy',
'add_toy_form.saving_button': 'Saving Changes...', 'add_toy_form.saving_button': 'Saving Changes...',
'add_toy_form.listing_button': 'Listing Toy...', 'add_toy_form.listing_button': 'Listing Toy...',
'add_toy_form.edit_title_toast': 'Toy Updated!',
'add_toy_form.add_title_toast': 'Toy Added!',
'add_toy_form.success_description_toast': '{toyName} has been successfully {action}.',
'add_toy_form.updated_action_toast': 'updated',
'add_toy_form.listed_action_toast': 'listed',
'dashboard.rentals.title': 'My Rentals', 'dashboard.rentals.title': 'My Rentals',
'dashboard.rentals.description': 'Toys you are currently renting from others.', 'dashboard.rentals.description': 'Toys you are currently renting from others.',
'dashboard.rentals.no_rentals_title': 'No Active Rentals', 'dashboard.rentals.no_rentals_title': 'No Active Rentals',

View File

@ -45,6 +45,8 @@ export default {
'toy_details.price_free': '免費', 'toy_details.price_free': '免費',
'toy_details.price_per_day': '/天', 'toy_details.price_per_day': '/天',
'toy_details.request_to_rent': '請求租借', 'toy_details.request_to_rent': '請求租借',
'toy_details.availability_calendar_title': '可租借日曆',
'toy_details.calendar_note': '灰色或劃掉的日期表示不可租借。',
'dashboard.layout.loading': '正在載入儀表板...', 'dashboard.layout.loading': '正在載入儀表板...',
'dashboard.sidebar.user_dashboard': '使用者儀表板', 'dashboard.sidebar.user_dashboard': '使用者儀表板',
'dashboard.sidebar.toy_management': '玩具管理', 'dashboard.sidebar.toy_management': '玩具管理',
@ -131,6 +133,11 @@ export default {
'add_toy_form.list_button': '列出我的玩具', 'add_toy_form.list_button': '列出我的玩具',
'add_toy_form.saving_button': '儲存變更中...', 'add_toy_form.saving_button': '儲存變更中...',
'add_toy_form.listing_button': '列出玩具中...', 'add_toy_form.listing_button': '列出玩具中...',
'add_toy_form.edit_title_toast': '玩具已更新!',
'add_toy_form.add_title_toast': '玩具已新增!',
'add_toy_form.success_description_toast': '{toyName} 已成功 {action}。',
'add_toy_form.updated_action_toast': '更新',
'add_toy_form.listed_action_toast': '列出',
'dashboard.rentals.title': '我的租借', 'dashboard.rentals.title': '我的租借',
'dashboard.rentals.description': '您目前正在向他人租借的玩具。', 'dashboard.rentals.description': '您目前正在向他人租借的玩具。',
'dashboard.rentals.no_rentals_title': '沒有進行中的租借', 'dashboard.rentals.no_rentals_title': '沒有進行中的租借',

View File

@ -5,15 +5,7 @@ export interface Toy {
description: string; description: string;
category: string; category: string;
images: string[]; // Array of image URLs images: string[]; // Array of image URLs
availability: { unavailableRanges: { startDate: string; endDate: string }[]; // New field for booked/unavailable date ranges
monday: boolean;
tuesday: boolean;
wednesday: boolean;
thursday: boolean;
friday: boolean;
saturday: boolean;
sunday: boolean;
};
ownerName: string; // Simplified for now ownerName: string; // Simplified for now
ownerId: string; ownerId: string;
pricePerDay?: number; // Optional daily rental price pricePerDay?: number; // Optional daily rental price