import jwt from "jsonwebtoken"; import Member from "../../models/member.js"; import { connectDB } from "../../utils/mongoose.js"; export default defineEventHandler(async (event) => { await connectDB(); // Check if user is authenticated const token = getCookie(event, "auth-token"); let isAuthenticated = false; let currentMemberId = null; if (token) { try { const decoded = jwt.verify(token, process.env.JWT_SECRET); currentMemberId = decoded.memberId; isAuthenticated = true; } catch (err) { // Invalid token, treat as public isAuthenticated = false; } } const query = getQuery(event); const search = query.search || ""; const circle = query.circle || ""; const tags = query.tags ? query.tags.split(",") : []; // Build query const dbQuery = { showInDirectory: true, status: "active", }; // Filter by circle if specified if (circle) { dbQuery.circle = circle; } // Search by name or bio if (search) { dbQuery.$or = [ { name: { $regex: search, $options: "i" } }, { bio: { $regex: search, $options: "i" } }, ]; } // Filter by tags (search in offering.tags or lookingFor.tags) if (tags.length > 0) { dbQuery.$or = [ { "offering.tags": { $in: tags } }, { "lookingFor.tags": { $in: tags } }, ]; // If search is also present, combine with AND if (search) { dbQuery.$and = [ { $or: [ { name: { $regex: search, $options: "i" } }, { bio: { $regex: search, $options: "i" } }, ], }, { $or: [ { "offering.tags": { $in: tags } }, { "lookingFor.tags": { $in: tags } }, ], }, ]; delete dbQuery.$or; } } try { const members = await Member.find(dbQuery) .select( "name pronouns timeZone avatar studio bio location socialLinks offering lookingFor privacy circle createdAt", ) .sort({ createdAt: -1 }) .lean(); // Filter fields based on privacy settings const filteredMembers = members.map((member) => { const privacy = member.privacy || {}; const filtered = { _id: member._id, name: member.name, circle: member.circle, createdAt: member.createdAt, }; // Helper function to check if field should be visible const isVisible = (field) => { const privacySetting = privacy[field] || "members"; if (privacySetting === "public") return true; if (privacySetting === "members" && isAuthenticated) return true; if (privacySetting === "private") return false; return false; }; // Add fields based on privacy settings if (isVisible("avatar")) filtered.avatar = member.avatar; if (isVisible("pronouns")) filtered.pronouns = member.pronouns; if (isVisible("timeZone")) filtered.timeZone = member.timeZone; if (isVisible("studio")) filtered.studio = member.studio; if (isVisible("bio")) filtered.bio = member.bio; if (isVisible("location")) filtered.location = member.location; if (isVisible("socialLinks")) filtered.socialLinks = member.socialLinks; if (isVisible("offering")) filtered.offering = member.offering; if (isVisible("lookingFor")) filtered.lookingFor = member.lookingFor; return filtered; }); // Get unique tags for filter options (from both offering and lookingFor) const allTags = members .flatMap((m) => [ ...(m.offering?.tags || []), ...(m.lookingFor?.tags || []), ]) .filter((tag, index, self) => self.indexOf(tag) === index) .sort(); return { members: filteredMembers, totalCount: filteredMembers.length, filters: { availableTags: allTags, }, }; } catch (error) { console.error("Directory fetch error:", error); throw createError({ statusCode: 500, message: "Failed to fetch member directory", }); } });