From dad13c9cfb2d4f685839bebd67ecc0713a30cb61 Mon Sep 17 00:00:00 2001 From: Indigo Tang Date: Sun, 6 Jul 2025 13:34:11 +0000 Subject: [PATCH] change sqlite user table column id to increment int ids --- src/app/[locale/owner/[ownerId]/toys/page.tsx | 103 ++++++++++++++++++ .../[locale]/admin/users/edit/[id]/page.tsx | 3 +- src/app/[locale]/admin/users/page.tsx | 2 +- .../[locale]/dashboard/messages/[id]/page.tsx | 22 ++-- src/app/[locale]/dashboard/messages/page.tsx | 4 +- src/app/[locale]/dashboard/my-toys/page.tsx | 2 +- .../dashboard/rental-history/page.tsx | 3 +- src/app/[locale]/dashboard/requests/page.tsx | 87 +++++++-------- src/app/actions/user.ts | 31 +++--- src/data/operations.ts | 6 +- src/lib/db.ts | 4 +- src/lib/mockData.ts | 26 ++--- src/types/index.ts | 10 +- 13 files changed, 200 insertions(+), 103 deletions(-) create mode 100644 src/app/[locale/owner/[ownerId]/toys/page.tsx diff --git a/src/app/[locale/owner/[ownerId]/toys/page.tsx b/src/app/[locale/owner/[ownerId]/toys/page.tsx new file mode 100644 index 0000000..16b661a --- /dev/null +++ b/src/app/[locale/owner/[ownerId]/toys/page.tsx @@ -0,0 +1,103 @@ + +import Link from 'next/link'; +import { Button } from '@/components/ui/button'; +import ToyList from '@/components/toys/ToyList'; +import { getToysByOwner, getOwnerProfile, getAllToys } from '@/data/operations'; +import { getI18n, getStaticParams as getLocaleStaticParams } from '@/locales/server'; +import { Home, UserCircle } from 'lucide-react'; +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; +import { ToyBrick } from 'lucide-react'; +import { Avatar, AvatarImage, AvatarFallback } from "@/components/ui/avatar"; + +interface OwnerToysPageProps { + params: { ownerId: string; locale: string }; +} + +export default async function OwnerToysPage({ params }: OwnerToysPageProps) { + const t = await getI18n(); + const ownerId = Number(params.ownerId); + const ownerToys = getToysByOwner(ownerId); + const ownerProfile = getOwnerProfile(ownerId); + + const ownerNameFromToys = ownerToys.length > 0 ? ownerToys[0].ownerName : undefined; + + let displayOwnerName = ownerProfile?.name || ownerNameFromToys || t('owner_toys.unknown_owner'); + + const pageTitle = displayOwnerName !== t('owner_toys.unknown_owner') + ? t('owner_toys.title_specific', { ownerName: displayOwnerName }) + : t('owner_toys.title_generic'); + + return ( +
+
+

{pageTitle}

+ + + +
+ + {ownerProfile && ( + + +
+ + + + {displayOwnerName ? displayOwnerName.split(' ').map(n => n[0]).join('').toUpperCase() : } + + +
+ + {t('owner_toys.about_owner', { ownerName: displayOwnerName })} + + {ownerNameFromToys && ownerNameFromToys !== displayOwnerName && ( + {t('toy_details.owner')}: {ownerNameFromToys} + )} +
+
+
+ +

{ownerProfile.bio}

+
+
+ )} + + {ownerToys.length > 0 ? ( + + ) : ( + + + + + {displayOwnerName !== t('owner_toys.unknown_owner') + ? t('owner_toys.no_toys_listed_by', { ownerName: displayOwnerName }) + : t('owner_toys.owner_not_found')} + + {displayOwnerName !== t('owner_toys.unknown_owner') && {t('home.explore_toys')}} + + + + + + + + )} +
+ ); +} + +export async function generateStaticParams() { + const localeParams = getLocaleStaticParams(); + const allToys = getAllToys(); + const ownerIds = Array.from(new Set(allToys.map(toy => toy.ownerId))); + const ownerParams = ownerIds.map(id => ({ ownerId: String(id) })); + + return localeParams.flatMap(lang => + ownerParams.map(owner => ({ ...lang, ...owner })) + ); +} diff --git a/src/app/[locale]/admin/users/edit/[id]/page.tsx b/src/app/[locale]/admin/users/edit/[id]/page.tsx index 34928d0..d0f18ca 100644 --- a/src/app/[locale]/admin/users/edit/[id]/page.tsx +++ b/src/app/[locale]/admin/users/edit/[id]/page.tsx @@ -13,7 +13,8 @@ interface EditUserPageProps { export default async function EditUserPage({ params }: EditUserPageProps) { const t = await getI18n(); - const userData = getUserById(params.id); + const userId = Number(params.id); + const userData = getUserById(userId); if (!userData) { return ( diff --git a/src/app/[locale]/admin/users/page.tsx b/src/app/[locale]/admin/users/page.tsx index 5fa3b60..d03ae3d 100644 --- a/src/app/[locale]/admin/users/page.tsx +++ b/src/app/[locale]/admin/users/page.tsx @@ -53,7 +53,7 @@ export default function AdminUserManagementPage() { }, [t, toast]); - const handleDeleteUser = async (userId: string) => { + const handleDeleteUser = async (userId: number) => { setIsDeleting(true); const result = await deleteUser(userId); if (result.success) { diff --git a/src/app/[locale]/dashboard/messages/[id]/page.tsx b/src/app/[locale]/dashboard/messages/[id]/page.tsx index da199a2..5cc23c5 100644 --- a/src/app/[locale]/dashboard/messages/[id]/page.tsx +++ b/src/app/[locale]/dashboard/messages/[id]/page.tsx @@ -17,20 +17,20 @@ import { ArrowLeft, Send, Loader2, AlertTriangle, ToyBrick } from 'lucide-react' import { useToast } from '@/hooks/use-toast'; import { format } from 'date-fns'; -// Assume current user is 'user1' for mock purposes -const currentUserId = 'user1'; -const currentUserProfiles: Record = { - 'user1': { name: 'Alice Wonderland', avatarInitial: 'AW', avatarUrl: 'https://placehold.co/40x40.png?text=AW' }, // Logged in user - 'user2': { name: 'Bob The Builder', avatarInitial: 'BT', avatarUrl: 'https://placehold.co/40x40.png?text=BT' }, - 'user3': { name: 'Carol Danvers', avatarInitial: 'CD', avatarUrl: 'https://placehold.co/40x40.png?text=CD' }, - 'user4': { name: 'Charlie Brown', avatarInitial: 'CB', avatarUrl: 'https://placehold.co/40x40.png?text=CB' }, - 'user5': { name: 'Diana Prince', avatarInitial: 'DP', avatarUrl: 'https://placehold.co/40x40.png?text=DP' }, - 'user6': { name: 'Edward Nigma', avatarInitial: 'EN', avatarUrl: 'https://placehold.co/40x40.png?text=EN' }, +// Assume current user is 'user1' (ID: 1) for mock purposes +const currentUserId = 1; +const currentUserProfiles: Record = { + 1: { name: 'Alice Wonderland', avatarInitial: 'AW', avatarUrl: 'https://placehold.co/40x40.png?text=AW' }, // Logged in user + 2: { name: 'Bob The Builder', avatarInitial: 'BT', avatarUrl: 'https://placehold.co/40x40.png?text=BT' }, + 3: { name: 'Carol Danvers', avatarInitial: 'CD', avatarUrl: 'https://placehold.co/40x40.png?text=CD' }, + 4: { name: 'Charlie Brown', avatarInitial: 'CB', avatarUrl: 'https://placehold.co/40x40.png?text=CB' }, + 5: { name: 'Diana Prince', avatarInitial: 'DP', avatarUrl: 'https://placehold.co/40x40.png?text=DP' }, + 6: { name: 'Edward Nigma', avatarInitial: 'EN', avatarUrl: 'https://placehold.co/40x40.png?text=EN' }, }; // Helper function to get the other participant in a conversation -const getOtherParticipant = (request: RentalRequest, currentUserId: string) => { +const getOtherParticipant = (request: RentalRequest, currentUserId: number) => { if (request.toy.ownerId === currentUserId) { return { id: request.requesterId, name: request.requesterName }; } @@ -238,5 +238,3 @@ export default function MessageDetailPage({ params }: { params: { id: string } } ); } - - \ No newline at end of file diff --git a/src/app/[locale]/dashboard/messages/page.tsx b/src/app/[locale]/dashboard/messages/page.tsx index ce0640c..dbf7584 100644 --- a/src/app/[locale]/dashboard/messages/page.tsx +++ b/src/app/[locale]/dashboard/messages/page.tsx @@ -9,10 +9,10 @@ import Link from "next/link"; import { MessageSquareQuote, ToyBrick } from "lucide-react"; import { format } from 'date-fns'; -const currentUserId = 'user1'; // Assume this is the logged-in user's ID +const currentUserId = 1; // Assume this is the logged-in user's ID // Helper function to get the other participant in a conversation -const getOtherParticipant = (request: RentalRequest, currentUserId: string) => { +const getOtherParticipant = (request: RentalRequest, currentUserId: number) => { if (request.toy.ownerId === currentUserId) { return { id: request.requesterId, name: request.requesterName }; } diff --git a/src/app/[locale]/dashboard/my-toys/page.tsx b/src/app/[locale]/dashboard/my-toys/page.tsx index 8bd71fe..c7e581b 100644 --- a/src/app/[locale]/dashboard/my-toys/page.tsx +++ b/src/app/[locale]/dashboard/my-toys/page.tsx @@ -10,7 +10,7 @@ import type { Toy } from "@/types"; import { Badge } from "@/components/ui/badge"; import { getI18n } from "@/locales/server"; -const currentUserId = 'user1'; +const currentUserId = 1; export default async function MyToysPage() { const t = await getI18n(); diff --git a/src/app/[locale]/dashboard/rental-history/page.tsx b/src/app/[locale]/dashboard/rental-history/page.tsx index a753792..b978840 100644 --- a/src/app/[locale]/dashboard/rental-history/page.tsx +++ b/src/app/[locale]/dashboard/rental-history/page.tsx @@ -11,7 +11,7 @@ import type { Locale } from "@/locales/server"; import { Badge } from "@/components/ui/badge"; import { format } from 'date-fns'; -const currentUserId = 'user1'; // Assume this is the logged-in user's ID +const currentUserId = 1; // Assume this is the logged-in user's ID export default async function RentalHistoryPage({ params }: { params: { locale: Locale } }) { const t = await getI18n(); @@ -112,4 +112,3 @@ function RentalHistoryItemCard({ item, t, locale }: RentalHistoryItemCardProps) ); } - diff --git a/src/app/[locale]/dashboard/requests/page.tsx b/src/app/[locale]/dashboard/requests/page.tsx index 4c676ef..fdcb132 100644 --- a/src/app/[locale]/dashboard/requests/page.tsx +++ b/src/app/[locale]/dashboard/requests/page.tsx @@ -4,55 +4,53 @@ import { ListOrdered, Check, X, MessageSquareText } 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"; import { getI18n } from "@/locales/server"; -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 []; + + const rentalRequests: RentalRequest[] = [ + { + id: 'req1', + toy: myToys[0], + requesterName: 'Charlie Brown', + requesterId: 4, + requestedDates: 'August 10, 2024 - August 17, 2024', + status: 'pending', + message: 'My son would love to play with these for his birthday week! We are very careful with toys and will ensure it is returned in perfect condition. Could we possibly pick it up on the 9th evening?', + dataAiHint: myToys[0]?.category.toLowerCase(), + }, + { + id: 'req2', + toy: myToys.length > 1 ? myToys[1] : myToys[0], + requesterName: 'Diana Prince', + requesterId: 5, + requestedDates: 'September 1, 2024 - September 5, 2024', + status: 'approved', + dataAiHint: (myToys.length > 1 ? myToys[1] : myToys[0])?.category.toLowerCase(), + }, + { + id: 'req3', + toy: myToys[0], + requesterName: 'Edward Nigma', + requesterId: 6, + requestedDates: 'July 20, 2024 - July 22, 2024', + status: 'declined', + message: 'Looking for a weekend rental.', + dataAiHint: myToys[0]?.category.toLowerCase(), + }, + ]; + return rentalRequests; } -const rentalRequests: RentalRequest[] = [ - { - id: 'req1', - toy: mockToys[0], - requesterName: 'Charlie Brown', - requesterId: 'user4', - requestedDates: 'August 10, 2024 - August 17, 2024', - status: 'pending', - message: 'My son would love to play with these for his birthday week! We are very careful with toys and will ensure it is returned in perfect condition. Could we possibly pick it up on the 9th evening?', - dataAiHint: mockToys[0]?.category.toLowerCase(), - }, - { - id: 'req2', - toy: mockToys[3], - requesterName: 'Diana Prince', - requesterId: 'user5', - requestedDates: 'September 1, 2024 - September 5, 2024', - status: 'approved', - dataAiHint: mockToys[3]?.category.toLowerCase(), - }, - { - id: 'req3', - toy: mockToys[0], - requesterName: 'Edward Nigma', - requesterId: 'user6', - requestedDates: 'July 20, 2024 - July 22, 2024', - status: 'declined', - message: 'Looking for a weekend rental.', - dataAiHint: mockToys[0]?.category.toLowerCase(), - }, -]; - -const currentUserToyRequests = rentalRequests.filter(req => req.toy.ownerId === 'user1'); +const currentUserToyRequests = getMockRequests(); export default async function RentalRequestsPage() { @@ -167,4 +165,3 @@ function RequestItemCard({ request, t }: RequestItemCardProps) { ); } - diff --git a/src/app/actions/user.ts b/src/app/actions/user.ts index 84d1ea5..f11a14e 100644 --- a/src/app/actions/user.ts +++ b/src/app/actions/user.ts @@ -3,7 +3,6 @@ import db from '@/lib/db'; import type { User } from '@/types'; -import { randomUUID } from 'crypto'; import { revalidatePath } from 'next/cache'; import { getAllUsers as dbGetAllUsers, getUserById } from '@/data/operations'; @@ -25,22 +24,22 @@ export async function registerUser(data: { name: string; nickname?: string; emai if (existingUser) { return { success: false, message: 'An account with this email already exists.' }; } - - const newUser: User = { - id: `user-${randomUUID()}`, - name, - nickname, - email, - role: role, - avatarUrl: '', - bio: '' - }; - + const stmt = db.prepare( - 'INSERT INTO users (id, name, nickname, email, role, avatarUrl, bio) VALUES (@id, @name, @nickname, @email, @role, @avatarUrl, @bio)' + 'INSERT INTO users (name, nickname, email, role, avatarUrl, bio) VALUES (@name, @nickname, @email, @role, @avatarUrl, @bio)' ); - stmt.run(newUser); + const info = stmt.run({ + name, + nickname: nickname ?? null, + email, + role: role, + avatarUrl: '', + bio: '' + }); + + const newUserId = info.lastInsertRowid as number; + const newUser = getUserById(newUserId); revalidatePath('/admin/users'); @@ -96,7 +95,7 @@ interface DeleteUserResult { message: string; } -export async function deleteUser(id: string): Promise { +export async function deleteUser(id: number): Promise { try { const user = getUserById(id); if (user && (user.email === 'user@example.com' || user.email === 'admin@example.com')) { @@ -143,7 +142,7 @@ export async function getUserByEmail(email: string): Promise { } interface UpdateProfileData { - id: string; + id: number; name: string; nickname?: string; avatarUrl?: string; diff --git a/src/data/operations.ts b/src/data/operations.ts index eb4173f..d103b81 100644 --- a/src/data/operations.ts +++ b/src/data/operations.ts @@ -39,7 +39,7 @@ export function getToyById(id: string): Toy | undefined { return toy ? parseToy(toy) : undefined; } -export function getToysByOwner(ownerId: string): Toy[] { +export function getToysByOwner(ownerId: number): Toy[] { const stmt = db.prepare(` SELECT t.*, u.name as ownerName, u.avatarUrl as ownerAvatarUrl FROM toys t @@ -93,7 +93,7 @@ export function updateToy(toyData: Omit[] = [ @@ -25,7 +25,7 @@ export const rawToys: Omit[] { 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' }) }, ], - ownerId: 'user1', + ownerId: 1, pricePerDay: 5, location: 'Springfield Gardens', }, @@ -38,7 +38,7 @@ export const rawToys: Omit[] unavailableRanges: [ { startDate: formatISO(addDays(today, 10), { representation: 'date' }), endDate: formatISO(addDays(today, 12), { representation: 'date' }) }, ], - ownerId: 'user2', + ownerId: 2, pricePerDay: 8, location: 'Willow Creek', }, @@ -49,7 +49,7 @@ export const rawToys: Omit[] category: 'Electronics', images: ['https://placehold.co/600x400.png?text=Kids+Tablet', 'https://placehold.co/600x400.png?text=Tablet+Screen'], unavailableRanges: [], - ownerId: 'user3', + ownerId: 3, pricePerDay: 7, location: 'Metro City', }, @@ -62,7 +62,7 @@ export const rawToys: Omit[] unavailableRanges: [ { startDate: formatISO(addDays(today, 20), { representation: 'date' }), endDate: formatISO(addDays(today, 25), { representation: 'date' }) }, ], - ownerId: 'user1', + ownerId: 1, pricePerDay: 3, location: 'Springfield Gardens', }, @@ -73,7 +73,7 @@ export const rawToys: Omit[] category: 'Musical', images: ['https://placehold.co/600x400.png?text=Kids+Guitar'], unavailableRanges: [], - ownerId: 'user2', + ownerId: 2, pricePerDay: 10, location: 'Willow Creek', }, @@ -84,7 +84,7 @@ export const rawToys: Omit[] category: 'Outdoor', images: ['https://placehold.co/600x400.png?text=Sports+Kit'], unavailableRanges: [], - ownerId: 'user3', + ownerId: 3, pricePerDay: 6, location: 'Metro City', } diff --git a/src/types/index.ts b/src/types/index.ts index 0094fe2..54bb2dc 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -1,7 +1,7 @@ export interface MessageEntry { id: string; - senderId: string; + senderId: number; senderName: string; text: string; timestamp: string; // ISO date string @@ -15,7 +15,7 @@ export interface Toy { images: string[]; unavailableRanges: { startDate: string; endDate: string }[]; ownerName: string; - ownerId: string; + ownerId: number; ownerAvatarUrl?: string; pricePerDay?: number; location?: string; @@ -23,7 +23,7 @@ export interface Toy { } export interface User { - id: string; + id: number; name: string; // This is now Full Name nickname?: string; email: string; @@ -40,7 +40,7 @@ export interface DailyAvailability { export interface RentalHistoryEntry { id:string; - userId: string; + userId: number; toy: Toy; rentalStartDate: string; rentalEndDate: string; @@ -53,7 +53,7 @@ export interface RentalRequest { id: string; toy: Toy; requesterName: string; - requesterId: string; + requesterId: number; requestedDates: string; status: 'pending' | 'approved' | 'declined'; message?: string;