From 5c26d191e5484fb9a3b31cc882c3c567ba9630ae Mon Sep 17 00:00:00 2001 From: casulit Date: Tue, 5 Nov 2024 11:39:56 +0800 Subject: [PATCH] feat: Add user favorites functionality with create and delete endpoints --- schema.sql | 9 ++++++++ server.ts | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+) diff --git a/schema.sql b/schema.sql index 050804a..001e539 100644 --- a/schema.sql +++ b/schema.sql @@ -133,6 +133,15 @@ CREATE TABLE Listing ( updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); +-- Table to store user favorites +CREATE TABLE User_Favorites ( + id SERIAL PRIMARY KEY, + user_id INT NOT NULL REFERENCES "User"(user_id) ON DELETE CASCADE, + property_id BIGINT NOT NULL REFERENCES Property(id) ON DELETE CASCADE, + added_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + UNIQUE(user_id, property_id) +); + -- Price history tracking CREATE TABLE Price_Change_Log ( id SERIAL PRIMARY KEY, diff --git a/server.ts b/server.ts index b78692e..ad998db 100644 --- a/server.ts +++ b/server.ts @@ -526,6 +526,73 @@ app.get("/api/properties/cities", async (c: Context) => { }); }); +app.post("/api/properties/favorites/:propertyId", async (c: Context) => { + using client = await dbPool.connect(); + const propertyId = c.req.param("propertyId"); + const { userId } = await c.req.json(); + + if (!propertyId || !userId) { + return c.json({ error: "Property ID and User ID are required" }, 400); + } + + // First check if favorite already exists + const existingFavorite = await client.queryObject({ + args: [userId, propertyId], + text: ` + SELECT id, user_id, property_id, added_at + FROM User_Favorites + WHERE user_id = $1 AND property_id = $2 + `, + }); + + if (existingFavorite?.rowCount && existingFavorite.rowCount > 0) { + return c.json({ + data: existingFavorite.rows[0], + }); + } + + // Create new favorite if it doesn't exist + const result = await client.queryObject({ + args: [userId, propertyId], + text: ` + INSERT INTO User_Favorites (user_id, property_id) + VALUES ($1, $2) + RETURNING id, user_id, property_id, added_at + `, + }); + + return c.json({ + data: result.rows[0], + }); +}); + +app.delete("/api/properties/favorites/:propertyId", async (c: Context) => { + using client = await dbPool.connect(); + const propertyId = c.req.param("propertyId"); + const { userId } = await c.req.json(); + + if (!propertyId || !userId) { + return c.json({ error: "Property ID and User ID are required" }, 400); + } + + const result = await client.queryObject({ + args: [userId, propertyId], + text: ` + DELETE FROM User_Favorites + WHERE user_id = $1 AND property_id = $2 + RETURNING id + `, + }); + + if (result.rowCount === 0) { + return c.json({ error: "Favorite not found" }, 404); + } + + return c.json({ + data: { success: true }, + }); +}); + app.patch("/api/properties/:id/generate-ai-description", async (c: Context) => { using client = await dbPool.connect(); const id = c.req.param("id");