import express from "express"; import fetch from "node-fetch"; import bcrypt from "bcryptjs"; import { User } from "../models/User.js"; import { requireAuth } from "../middleware/auth.js"; const router = express.Router(); // GET /api/profiles/me router.get("/me", requireAuth, async (req, res) => { const user = await User.findById(req.user.id).select("-password -__v"); if (!user) return res.status(404).json({ error: "User not found" }); res.json({ email: user.email, role: user.role, profile: user.profile, }); }); // NEW: GET any profile by its ID router.get("/:id", async (req, res) => { try { const user = await User.findById(req.params.id).select("-password -__v"); if (!user) return res.status(404).json({ error: "Profile not found" }); return res.json({ email: user.email, role: user.role, profile: user.profile, }); } catch (err) { return res.status(500).json({ error: err.message }); } }); // POST /api/profiles (create or update profile) // – normal user: only name/address/password // – pro user: full profile (field, rate, address, lat, lon, published) router.post("/", requireAuth, async (req, res) => { try { const user = await User.findById(req.user.id); if (req.user.role === "pro") { const { firstName, lastName, phone, field, rate, address, description, picture, published, } = req.body; // pure publish toggle? if ( req.body.hasOwnProperty("published") && Object.keys(req.body).length === 1 ) { // disallow publishing unless all fields are set if (published) { const pf = (await User.findById(req.user.id)).profile; if ( !pf.firstName || !pf.lastName || !pf.phone || !pf.field || pf.rate == null || !pf.address || !pf.description || // ← require description !pf.picture // ← require picture ) { return res.status(400).json({ error: "Complete firstName, lastName, phone, field, rate, address, description & picture before publishing.", }); } } user.profile.published = !!published; await user.save(); return res.json({ success: true }); } // full update → geocode + persist all fields const geoRes = await fetch( `https://maps.googleapis.com/maps/api/geocode/json` + `?address=${encodeURIComponent(address)}` + `&key=${process.env.GOOGLE_PLACES_API_KEY}` ); const geoData = await geoRes.json(); console.log( "🗺️ geoData.results:", JSON.stringify(geoData.results, null, 2) ); if (geoData.status !== "OK" || !geoData.results.length) { return res.status(400).json({ error: "Invalid address" }); } // prefer a true city‐level result, then region, then country, then anything const place = geoData.results.find((r) => r.types.includes("locality")) || geoData.results.find((r) => r.types.includes("administrative_area_level_2") ) || geoData.results.find((r) => r.types.includes("administrative_area_level_1") ) || geoData.results[0]; const { lat, lng } = place.geometry.location; // first try the locality component const cityComp = place.address_components.find((c) => c.types.includes("locality") ); let rawCity; if (cityComp) { rawCity = cityComp.long_name; } else { // use the penultimate segment of formatted_address, e.g. // ["Hlavná","Old Town","Košice","Slovakia"] → "Košice" const parts = (place.formatted_address || "") .split(",") .map((s) => s.trim()); rawCity = parts.length > 1 ? parts[parts.length - 2] : parts[0]; } // normalize: strip accents + lowercase const city = rawCity .normalize("NFD") .replace(/[\u0300-\u036f]/g, "") .toLowerCase(); // now persist everything user.profile.firstName = firstName; user.profile.lastName = lastName; user.profile.phone = phone; user.profile.field = field; user.profile.rate = rate; user.profile.address = address; user.profile.description = description; // ← save description user.profile.picture = picture; // ← save picture user.profile.city = city; user.profile.location = { type: "Point", coordinates: [lng, lat], }; user.profile.published = !!published; } else { // ─── Normal user profile update ────────────────────────────────────── // Allow them to save firstName, lastName, phone, and (optionally) password const { firstName, lastName, phone, password } = req.body; const u = await User.findById(req.user.id); if (!u) return res.status(404).json({ error: "User not found" }); if (firstName !== undefined) u.profile.firstName = firstName; if (lastName !== undefined) u.profile.lastName = lastName; if (phone !== undefined) u.profile.phone = phone; // if they submitted a new password, hash + save it if (password) { u.password = await bcrypt.hash(password, 10); } await u.save(); return res.json({ success: true, profile: u.profile }); } await user.save(); res.json({ success: true }); } catch (err) { res.status(500).json({ error: err.message }); } }); // DELETE /api/profiles/me → unpublish pro or delete normal account router.delete("/me", requireAuth, async (req, res) => { try { // Delete the entire user account await User.findByIdAndDelete(req.user.id); return res.json({ success: true }); } catch (err) { res.status(500).json({ error: err.message }); } }); export default router;