Implement add toy and edit toy functions to sqlite database
This commit is contained in:
parent
a6ccc6a5f4
commit
0b22c28dfa
|
|
@ -1,5 +1,6 @@
|
|||
|
||||
import AddToyForm from '@/components/toys/AddToyForm';
|
||||
import { mockToys } from '@/lib/mockData';
|
||||
import { getToyById } from '@/data/operations';
|
||||
import type { Toy } from '@/types';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import Link from 'next/link';
|
||||
|
|
@ -9,14 +10,8 @@ interface EditToyPageProps {
|
|||
params: { id: string };
|
||||
}
|
||||
|
||||
// Server Component to fetch toy data (mocked for now)
|
||||
async function getToyForEdit(id: string): Promise<Partial<Toy> | undefined> {
|
||||
await new Promise(resolve => setTimeout(resolve, 100)); // Simulate fetch
|
||||
return mockToys.find(toy => toy.id === id);
|
||||
}
|
||||
|
||||
export default async function EditToyPage({ params }: EditToyPageProps) {
|
||||
const toyData = await getToyForEdit(params.id);
|
||||
const toyData = getToyById(params.id);
|
||||
|
||||
if (!toyData) {
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -1,20 +1,18 @@
|
|||
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import ToyCard from "@/components/toys/ToyCard";
|
||||
import { mockToys } from "@/lib/mockData"; // Using all toys for now, filter by ownerId in real app
|
||||
import { getToysByOwner } from "@/data/operations";
|
||||
import Link from "next/link";
|
||||
import { PlusCircle, Edit3, Trash2, Eye } from "lucide-react";
|
||||
import { PlusCircle, Edit3, Trash2, Eye, ToyBrick as ToyBrickIcon } from "lucide-react";
|
||||
import Image from "next/image";
|
||||
import type { Toy } from "@/types";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
|
||||
// Assume this is the logged-in user's ID
|
||||
const currentUserId = 'user1';
|
||||
const currentUserId = 1;
|
||||
|
||||
// Filter toys by current user
|
||||
const userToys = mockToys.filter(toy => toy.ownerId === currentUserId);
|
||||
export default async function MyToysPage() {
|
||||
const userToys = getToysByOwner(currentUserId);
|
||||
|
||||
export default function MyToysPage() {
|
||||
return (
|
||||
<div className="space-y-8">
|
||||
<div className="flex justify-between items-center">
|
||||
|
|
@ -33,7 +31,7 @@ export default function MyToysPage() {
|
|||
{userToys.length === 0 ? (
|
||||
<Card className="text-center py-12 shadow-md">
|
||||
<CardHeader>
|
||||
<ToyBrick className="h-16 w-16 mx-auto text-muted-foreground mb-4" />
|
||||
<ToyBrickIcon className="h-16 w-16 mx-auto text-muted-foreground mb-4" />
|
||||
<CardTitle>No Toys Listed Yet</CardTitle>
|
||||
<CardDescription>Share your first toy and spread the joy!</CardDescription>
|
||||
</CardHeader>
|
||||
|
|
@ -99,14 +97,14 @@ function ListedToyItem({ toy }: ListedToyItemProps) {
|
|||
</div>
|
||||
</div>
|
||||
<p className="text-muted-foreground mt-2 text-sm line-clamp-2">{toy.description}</p>
|
||||
<div className="mt-4 text-sm">
|
||||
<div className="mt-4 text-sm space-y-1">
|
||||
<div>
|
||||
<span className="font-semibold">Price: </span>
|
||||
{toy.pricePerDay !== undefined ? (toy.pricePerDay > 0 ? `$${toy.pricePerDay}/day` : 'Free') : 'Not set'}
|
||||
</div>
|
||||
{/* Could add more stats like number of rentals, views etc. here */}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,16 +1,21 @@
|
|||
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import Link from "next/link";
|
||||
import { ToyBrick, PlusCircle, ListOrdered, User, ShoppingBag } from "lucide-react";
|
||||
import { getToysByOwner } from "@/data/operations";
|
||||
|
||||
const currentUserId = 1; // Mock logged-in user ID
|
||||
|
||||
export default async function DashboardOverviewPage() {
|
||||
const userToys = getToysByOwner(currentUserId);
|
||||
|
||||
// Mock data for dashboard overview
|
||||
const userStats = {
|
||||
listedToys: 3,
|
||||
activeRentals: 1, // Toys I'm renting
|
||||
pendingRequests: 2, // Requests for my toys
|
||||
listedToys: userToys.length, // Real data from DB
|
||||
activeRentals: 1, // Mock data
|
||||
pendingRequests: 2, // Mock data
|
||||
};
|
||||
|
||||
export default function DashboardOverviewPage() {
|
||||
return (
|
||||
<div className="space-y-8">
|
||||
<Card className="shadow-lg">
|
||||
|
|
|
|||
|
|
@ -1,20 +1,24 @@
|
|||
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import { ShoppingBag, ToyBrick } from "lucide-react";
|
||||
import Link from "next/link";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import Image from "next/image";
|
||||
import type { Toy } from "@/types";
|
||||
import { mockToys } from "@/lib/mockData"; // Using all toys for now
|
||||
|
||||
// Mock data: toys rented by the current user
|
||||
// In a real app, this would come from a database query based on rental records
|
||||
const rentedToys: (Toy & { rentalEndDate?: string, dataAiHint?: string })[] = [
|
||||
{ ...mockToys[1], rentalEndDate: "2024-08-15", dataAiHint: mockToys[1]?.category.toLowerCase() }, // Remote Control Car
|
||||
{ ...mockToys[4], rentalEndDate: "2024-09-01", dataAiHint: mockToys[4]?.category.toLowerCase() }, // Beginner Guitar
|
||||
];
|
||||
|
||||
import { getAllToys } from "@/data/operations";
|
||||
|
||||
export default function MyRentalsPage() {
|
||||
const allToys = getAllToys();
|
||||
// Mock data: toys rented by the current user
|
||||
// In a real app, this would come from a database query based on rental records
|
||||
const rentedToys: (Toy & { rentalEndDate?: string })[] = [];
|
||||
if (allToys.length > 1) {
|
||||
rentedToys.push({ ...allToys[1], rentalEndDate: "2024-12-15" });
|
||||
}
|
||||
if (allToys.length > 4) {
|
||||
rentedToys.push({ ...allToys[4], rentalEndDate: "2025-01-01" });
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="space-y-8">
|
||||
<div>
|
||||
|
|
@ -50,7 +54,7 @@ export default function MyRentalsPage() {
|
|||
}
|
||||
|
||||
interface RentalItemCardProps {
|
||||
toy: Toy & { rentalEndDate?: string, dataAiHint?: string };
|
||||
toy: Toy & { rentalEndDate?: string };
|
||||
}
|
||||
|
||||
function RentalItemCard({ toy }: RentalItemCardProps) {
|
||||
|
|
|
|||
|
|
@ -1,58 +1,55 @@
|
|||
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import { ListOrdered, Check, X } from "lucide-react";
|
||||
import Link from "next/link";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import Image from "next/image";
|
||||
import type { Toy } from "@/types";
|
||||
import { mockToys } from "@/lib/mockData";
|
||||
import type { Toy, RentalRequest } from "@/types";
|
||||
import { getAllToys } from "@/data/operations";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
|
||||
interface RentalRequest {
|
||||
id: string;
|
||||
toy: Toy;
|
||||
requesterName: string;
|
||||
requesterId: string;
|
||||
requestedDates: string; // e.g., "Aug 5, 2024 - Aug 10, 2024"
|
||||
status: 'pending' | 'approved' | 'declined';
|
||||
message?: string;
|
||||
dataAiHint?: string;
|
||||
}
|
||||
// This is still mock data. In a real app, this would come from the database.
|
||||
function getMockRequests(): RentalRequest[] {
|
||||
const allToys = getAllToys();
|
||||
const myToys = allToys.filter(t => t.ownerId === 1);
|
||||
|
||||
if (myToys.length === 0) return [];
|
||||
|
||||
// Mock data: rental requests for the current user's toys
|
||||
const rentalRequests: RentalRequest[] = [
|
||||
{
|
||||
id: 'req1',
|
||||
toy: mockToys[0], // Colorful Building Blocks Set (owned by user1)
|
||||
toy: myToys[0],
|
||||
requesterName: 'Charlie Brown',
|
||||
requesterId: 'user4',
|
||||
requesterId: 4,
|
||||
requestedDates: 'August 10, 2024 - August 17, 2024',
|
||||
status: 'pending',
|
||||
message: 'My son would love to play with these for his birthday week!',
|
||||
dataAiHint: mockToys[0]?.category.toLowerCase(),
|
||||
dataAiHint: myToys[0]?.category.toLowerCase(),
|
||||
},
|
||||
{
|
||||
id: 'req2',
|
||||
toy: mockToys[3], // Plush Teddy Bear (owned by user1)
|
||||
toy: myToys.length > 1 ? myToys[1] : myToys[0],
|
||||
requesterName: 'Diana Prince',
|
||||
requesterId: 'user5',
|
||||
requesterId: 5,
|
||||
requestedDates: 'September 1, 2024 - September 5, 2024',
|
||||
status: 'approved',
|
||||
dataAiHint: mockToys[3]?.category.toLowerCase(),
|
||||
dataAiHint: (myToys.length > 1 ? myToys[1] : myToys[0])?.category.toLowerCase(),
|
||||
},
|
||||
{
|
||||
id: 'req3',
|
||||
toy: mockToys[0],
|
||||
toy: myToys[0],
|
||||
requesterName: 'Edward Nigma',
|
||||
requesterId: 'user6',
|
||||
requesterId: 6,
|
||||
requestedDates: 'July 20, 2024 - July 22, 2024',
|
||||
status: 'declined',
|
||||
message: 'Looking for a weekend rental.',
|
||||
dataAiHint: mockToys[0]?.category.toLowerCase(),
|
||||
dataAiHint: myToys[0]?.category.toLowerCase(),
|
||||
},
|
||||
];
|
||||
return rentalRequests;
|
||||
}
|
||||
|
||||
// Assuming current user is user1 for whom these requests are relevant
|
||||
const currentUserToyRequests = rentalRequests.filter(req => req.toy.ownerId === 'user1');
|
||||
const currentUserToyRequests = getMockRequests();
|
||||
|
||||
|
||||
export default function RentalRequestsPage() {
|
||||
|
|
|
|||
|
|
@ -1,10 +1,28 @@
|
|||
|
||||
import ToyList from '@/components/toys/ToyList';
|
||||
import { mockToys } from '@/lib/mockData';
|
||||
import { getAllToys } from '@/data/operations';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import Link from 'next/link';
|
||||
import { PlusCircle } from 'lucide-react';
|
||||
|
||||
export default function HomePage() {
|
||||
export default async function HomePage() {
|
||||
const toys = getAllToys();
|
||||
const t = (key: string, params?: any) => {
|
||||
// Basic mock t function for non-localized pages
|
||||
const keyParts = key.split('.');
|
||||
let text = keyParts.pop() || key;
|
||||
text = text.replace(/_/g, ' ');
|
||||
text = text.charAt(0).toUpperCase() + text.slice(1);
|
||||
|
||||
if (params) {
|
||||
Object.keys(params).forEach(pKey => {
|
||||
text = text.replace(`{${pKey}}`, params[pKey]);
|
||||
})
|
||||
}
|
||||
|
||||
return text;
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="space-y-8">
|
||||
<section className="text-center py-12 bg-gradient-to-r from-primary/10 via-background to-accent/10 rounded-lg shadow">
|
||||
|
|
@ -33,7 +51,7 @@ export default function HomePage() {
|
|||
<h2 className="text-3xl font-bold font-headline text-center mb-8 text-primary">
|
||||
Available Toys
|
||||
</h2>
|
||||
<ToyList toys={mockToys.map(toy => ({...toy, dataAiHint: toy.category.toLowerCase()}))} />
|
||||
<ToyList toys={toys} t={t} />
|
||||
</section>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,26 +1,24 @@
|
|||
|
||||
import Image from 'next/image';
|
||||
import { mockToys } from '@/lib/mockData';
|
||||
import { getToyById, getAllToys } from '@/data/operations';
|
||||
import type { Toy } from '@/types';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import AvailabilityCalendar from '@/components/toys/AvailabilityCalendar';
|
||||
import { ArrowLeft, CalendarDays, DollarSign, MapPin, ShoppingBag, UserCircle2 } from 'lucide-react';
|
||||
import { Calendar } from '@/components/ui/calendar';
|
||||
import { ArrowLeft, DollarSign, MapPin, ShoppingBag, UserCircle2 } from 'lucide-react';
|
||||
import Link from 'next/link';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { Separator } from '@/components/ui/separator';
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
import { addDays, parseISO } from 'date-fns';
|
||||
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar';
|
||||
|
||||
|
||||
interface ToyPageProps {
|
||||
params: { id: string };
|
||||
}
|
||||
|
||||
// Server Component to fetch toy data (mocked for now)
|
||||
async function getToyById(id: string): Promise<Toy | undefined> {
|
||||
// In a real app, this would fetch from a database
|
||||
await new Promise(resolve => setTimeout(resolve, 200)); // Simulate network delay
|
||||
return mockToys.find(toy => toy.id === id);
|
||||
}
|
||||
|
||||
export default async function ToyPage({ params }: ToyPageProps) {
|
||||
const toy = await getToyById(params.id);
|
||||
const toy = getToyById(params.id);
|
||||
|
||||
if (!toy) {
|
||||
return (
|
||||
|
|
@ -39,6 +37,12 @@ export default async function ToyPage({ params }: ToyPageProps) {
|
|||
|
||||
const placeholderHint = toy.category.toLowerCase() || "toy detail";
|
||||
|
||||
const disabledDates = toy.unavailableRanges.map(range => {
|
||||
const from = parseISO(range.startDate);
|
||||
const to = parseISO(range.endDate);
|
||||
return { from, to };
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="container mx-auto py-8 px-4">
|
||||
<Link href="/" className="inline-flex items-center text-primary hover:underline mb-6 group">
|
||||
|
|
@ -47,7 +51,6 @@ export default async function ToyPage({ params }: ToyPageProps) {
|
|||
</Link>
|
||||
|
||||
<div className="grid md:grid-cols-2 gap-8 lg:gap-12 items-start">
|
||||
{/* Image Gallery Section */}
|
||||
<div className="space-y-4">
|
||||
<div className="aspect-video relative w-full rounded-lg overflow-hidden shadow-lg">
|
||||
<Image
|
||||
|
|
@ -76,7 +79,6 @@ export default async function ToyPage({ params }: ToyPageProps) {
|
|||
)}
|
||||
</div>
|
||||
|
||||
{/* Toy Details Section */}
|
||||
<div className="space-y-6">
|
||||
<Badge variant="secondary" className="text-sm">{toy.category}</Badge>
|
||||
<h1 className="text-4xl font-bold font-headline text-primary">{toy.name}</h1>
|
||||
|
|
@ -88,11 +90,18 @@ export default async function ToyPage({ params }: ToyPageProps) {
|
|||
<Separator />
|
||||
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4 text-sm">
|
||||
<div className="flex items-center">
|
||||
<UserCircle2 className="h-5 w-5 mr-2 text-accent" />
|
||||
<div className="flex items-center gap-2">
|
||||
<Link href={`/owner/${toy.ownerId}/toys`} className="flex-shrink-0">
|
||||
<Avatar className="h-8 w-8">
|
||||
<AvatarImage src={toy.ownerAvatarUrl} alt={toy.ownerName} data-ai-hint="owner avatar" />
|
||||
<AvatarFallback>{toy.ownerName.split(' ').map(n => n[0]).join('').toUpperCase()}</AvatarFallback>
|
||||
</Avatar>
|
||||
</Link>
|
||||
<div>
|
||||
<span className="font-medium text-muted-foreground">Owner: </span>
|
||||
<span className="text-foreground">{toy.ownerName}</span>
|
||||
<Link href={`/owner/${toy.ownerId}/toys`} className="text-foreground hover:underline">
|
||||
{toy.ownerName}
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
{toy.location && (
|
||||
|
|
@ -109,7 +118,9 @@ export default async function ToyPage({ params }: ToyPageProps) {
|
|||
<DollarSign className="h-5 w-5 mr-2 text-accent" />
|
||||
<div>
|
||||
<span className="font-medium text-muted-foreground">Price: </span>
|
||||
<span className="text-foreground font-semibold">{toy.pricePerDay > 0 ? `$${toy.pricePerDay}/day` : 'Free'}</span>
|
||||
<span className="text-foreground font-semibold">
|
||||
{toy.pricePerDay > 0 ? `$${toy.pricePerDay}/day` : 'Free'}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
|
@ -117,7 +128,22 @@ export default async function ToyPage({ params }: ToyPageProps) {
|
|||
|
||||
<Separator />
|
||||
|
||||
<AvailabilityCalendar availability={toy.availability} />
|
||||
<Card className="shadow-md">
|
||||
<CardHeader>
|
||||
<CardTitle className="text-xl font-headline text-primary">Availability Calendar</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="flex justify-center">
|
||||
<Calendar
|
||||
mode="single"
|
||||
disabled={disabledDates}
|
||||
month={new Date()}
|
||||
className="rounded-md border"
|
||||
/>
|
||||
</CardContent>
|
||||
<p className="text-xs text-muted-foreground mt-0 pb-4 text-center">
|
||||
Dates shown in gray or crossed out are unavailable.
|
||||
</p>
|
||||
</Card>
|
||||
|
||||
<Button size="lg" className="w-full mt-6 transition-transform transform hover:scale-105">
|
||||
<ShoppingBag className="mr-2 h-5 w-5" /> Request to Rent
|
||||
|
|
@ -130,7 +156,8 @@ export default async function ToyPage({ params }: ToyPageProps) {
|
|||
|
||||
// Generate static paths for all toys
|
||||
export async function generateStaticParams() {
|
||||
return mockToys.map((toy) => ({
|
||||
const toys = getAllToys();
|
||||
return toys.map((toy) => ({
|
||||
id: toy.id,
|
||||
}));
|
||||
}
|
||||
|
|
|
|||
BIN
toyshare.db
BIN
toyshare.db
Binary file not shown.
BIN
toyshare.db-shm
BIN
toyshare.db-shm
Binary file not shown.
BIN
toyshare.db-wal
BIN
toyshare.db-wal
Binary file not shown.
Loading…
Reference in New Issue