diff --git a/src/app/api/rooms/[id]/likes/route.ts b/src/app/api/rooms/[id]/likes/route.ts index 1f7ab12..1debd4f 100644 --- a/src/app/api/rooms/[id]/likes/route.ts +++ b/src/app/api/rooms/[id]/likes/route.ts @@ -1,54 +1,90 @@ import { NextRequest, NextResponse } from 'next/server'; import { db } from '@/lib/db'; +import { getSession } from '@/lib/auth'; -export async function GET(request: NextRequest, { params }: { params: { id: string } }) { +// GET - check if user liked a room and get total likes +export async function GET( + request: NextRequest, + { params }: { params: { id: string } } +) { try { const roomId = parseInt(params.id, 10); - if (isNaN(roomId)) { - return NextResponse.json({ error: 'Invalid room ID' }, { status: 400 }); + const session = await getSession(); + + // Get total likes + const { rows: countRows } = await db.query( + 'SELECT COUNT(*) as count FROM room_likes WHERE room_id = $1', + [roomId] + ); + const totalLikes = parseInt(countRows[0].count) || 0; + + // Check if current user liked this room + let likedByUser = false; + if (session) { + const { rows: likeRows } = await db.query( + 'SELECT 1 FROM room_likes WHERE room_id = $1 AND user_id = $2', + [roomId, session.id] + ); + likedByUser = likeRows.length > 0; } - const [countResult, userLikeResult] = await Promise.all([ - db.query('SELECT COUNT(*) AS count FROM room_likes WHERE room_id = $1', [roomId]), - db.query('SELECT 1 FROM room_likes WHERE room_id = $1 AND user_id = $2', [roomId, 1]), - ]); - - return NextResponse.json({ - count: parseInt(countResult.rows[0].count, 10), - user_liked: userLikeResult.rows.length > 0, - }); + return NextResponse.json({ totalLikes, likedByUser }); } catch (err: any) { - // Table may not exist yet — return safe defaults - return NextResponse.json({ count: 0, user_liked: false }); + return NextResponse.json({ error: err.message || 'Failed to get likes' }, { status: 500 }); } } -export async function POST(request: NextRequest, { params }: { params: { id: string } }) { +// POST - toggle like (add if not liked, remove if already liked) +export async function POST( + request: NextRequest, + { params }: { params: { id: string } } +) { try { - const roomId = parseInt(params.id, 10); - if (isNaN(roomId)) { - return NextResponse.json({ error: 'Invalid room ID' }, { status: 400 }); + const session = await getSession(); + if (!session) { + return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); } - // TODO: get user_id from session/auth instead of hardcoded - const userId = 1; + const roomId = parseInt(params.id, 10); - // Toggle: if already liked, unlike; otherwise like - const existing = await db.query( - 'SELECT id FROM room_likes WHERE room_id = $1 AND user_id = $2', - [roomId, userId] + // Check if already liked + const { rows: existing } = await db.query( + 'SELECT 1 FROM room_likes WHERE room_id = $1 AND user_id = $2', + [roomId, session.id] ); - if (existing.rows.length > 0) { - await db.query('DELETE FROM room_likes WHERE id = $1', [existing.rows[0].id]); + let liked: boolean; + if (existing.length > 0) { + // Unlike - remove the like + await db.query( + 'DELETE FROM room_likes WHERE room_id = $1 AND user_id = $2', + [roomId, session.id] + ); + liked = false; } else { - await db.query('INSERT INTO room_likes (room_id, user_id) VALUES ($1, $2)', [roomId, userId]); + // Like - add the like + await db.query( + 'INSERT INTO room_likes (room_id, user_id) VALUES ($1, $2)', + [roomId, session.id] + ); + liked = true; } - const countResult = await db.query('SELECT COUNT(*) AS count FROM room_likes WHERE room_id = $1', [roomId]); + // Get updated count + const { rows: countRows } = await db.query( + 'SELECT COUNT(*) as count FROM room_likes WHERE room_id = $1', + [roomId] + ); + const totalLikes = parseInt(countRows[0].count) || 0; - return NextResponse.json({ count: parseInt(countResult.rows[0].count, 10) }); + // Update the rooms table for quick access + await db.query( + 'UPDATE rooms SET likes_count = $1 WHERE id = $2', + [totalLikes, roomId] + ); + + return NextResponse.json({ liked, totalLikes }); } catch (err: any) { return NextResponse.json({ error: err.message || 'Failed to toggle like' }, { status: 500 }); } -} +} \ No newline at end of file diff --git a/src/app/rooms/page.tsx b/src/app/rooms/page.tsx index 82526d9..9faf9b7 100644 --- a/src/app/rooms/page.tsx +++ b/src/app/rooms/page.tsx @@ -3,6 +3,7 @@ import { useEffect, useState, useRef } from 'react'; import { formatDisplayDate } from '@/lib/date'; import RoomCalendar from '@/components/RoomCalendar'; +import LikeButton from '@/components/LikeButton'; interface Room { id: number; @@ -420,8 +421,11 @@ export default function RoomsPage() { {/* ─── Room Info ─── */}
{room.description}
+{room.description}
{/* ─── Amenity Icons ─── */} {room.amenities && room.amenities.length > 0 && ( diff --git a/src/components/LikeButton.tsx b/src/components/LikeButton.tsx new file mode 100644 index 0000000..e5dc3b9 --- /dev/null +++ b/src/components/LikeButton.tsx @@ -0,0 +1,89 @@ +'use client'; + +import { useEffect, useState } from 'react'; + +interface LikeButtonProps { + roomId: number; +} + +export default function LikeButton({ roomId }: LikeButtonProps) { + const [liked, setLiked] = useState(false); + const [totalLikes, setTotalLikes] = useState(0); + const [loading, setLoading] = useState(true); + + useEffect(() => { + fetch(`/api/rooms/${roomId}/likes`) + .then(res => res.json()) + .then(data => { + setLiked(data.likedByUser); + setTotalLikes(data.totalLikes); + setLoading(false); + }) + .catch(() => setLoading(false)); + }, [roomId]); + + const toggleLike = async () => { + try { + const res = await fetch(`/api/rooms/${roomId}/likes`, { method: 'POST' }); + if (res.ok) { + const data = await res.json(); + setLiked(data.liked); + setTotalLikes(data.totalLikes); + } + } catch (err) { + console.error('Failed to toggle like:', err); + } + }; + + if (loading) { + return ( +