From 72de293c1689bbf6c0e872c9725e709b5d14153b Mon Sep 17 00:00:00 2001 From: Ellvius Date: Mon, 7 Apr 2025 17:15:28 +0530 Subject: [PATCH] search --- backend/controllers/userController.js | 49 +++ backend/routes/userRoutes.js | 2 + frontend/src/app/alumni/page.js | 6 +- frontend/src/app/alumni/search/page.js | 500 +++++++++-------------- frontend/src/components/Navbar/index.jsx | 1 + 5 files changed, 258 insertions(+), 300 deletions(-) diff --git a/backend/controllers/userController.js b/backend/controllers/userController.js index 609a602..940be76 100644 --- a/backend/controllers/userController.js +++ b/backend/controllers/userController.js @@ -1,4 +1,5 @@ const User = require('../models/user'); +const AlumniProfile = require('../models/alumni-profile'); const { Op } = require('sequelize'); const bcrypt = require('bcryptjs'); const { generateAuthToken } = require('../middleware/authMiddleware'); @@ -114,6 +115,54 @@ class UserController { } } + // Search Alumni Profiles +async searchProfiles(req, res) { + try { + const { name, graduationYear, company } = req.query; + console.log(req.query); + // Build the where clause based on search parameters + const whereClause = {}; + + if (name) { + whereClause[Op.or] = [ + { firstName: { [Op.iLike]: `%${name}%` } }, + { lastName: { [Op.iLike]: `%${name}%` } } + ]; + } + + if (graduationYear) { + whereClause.graduationYear = graduationYear; + } + + if (company) { + whereClause.company = { [Op.iLike]: `%${company}%` }; + } + + // Find alumni profiles that match the criteria + const alumni = await AlumniProfile.findAll({ + where: whereClause, + order: [['lastName', 'ASC'], ['firstName', 'ASC']], + attributes: [ + 'id', 'firstName', 'lastName', 'graduationYear', + 'degreeProgram', 'major', 'company', 'jobTitle', 'privacySettings','email','phone' + ] + }); + + // Only return public profiles unless user has admin role + const filteredAlumni = req.user?.role === 'admin' + ? alumni + : alumni.filter(profile => profile.privacySettings === 'public'); + + res.json({ + alumni: filteredAlumni, + total: filteredAlumni.length + }); + } catch (error) { + console.error('Error searching alumni profiles:', error); + res.status(500).json({ error: error.message }); + } +} + // Change user password async changePassword(req, res) { try { diff --git a/backend/routes/userRoutes.js b/backend/routes/userRoutes.js index f889573..9e27547 100644 --- a/backend/routes/userRoutes.js +++ b/backend/routes/userRoutes.js @@ -19,7 +19,9 @@ router.patch('/change-password', authenticateUser, userController.changePassword // Deactivate user account (PATCH for clarity) router.patch('/deactivate-account', authenticateUser, userController.deactivateAccount); +router.get('/search', userController.searchProfiles); // List all users (Admin only) router.get('/', authenticateUser, authorizeRoles('admin'), userController.listUsers); + module.exports = router; diff --git a/frontend/src/app/alumni/page.js b/frontend/src/app/alumni/page.js index a35363b..ef3434a 100644 --- a/frontend/src/app/alumni/page.js +++ b/frontend/src/app/alumni/page.js @@ -191,6 +191,10 @@ const AlumniDashboard = () => { router.push("/jobs/create"); } + const editJob = (jobId) =>{ + router.push(`/jobs/edit/${jobId}`); + } + // Use actual data if available, otherwise use fallback const displayUser = user ; const displayEvents = userEvents; @@ -396,7 +400,7 @@ const AlumniDashboard = () => { {displayJobs .filter(job => job.poster.id === displayUser.userId) .map(job => ( -
+
editJob(job.id)} key={job.id} className="border-b border-gray-100 pb-3 last:border-0 last:pb-0">

{job.jobTitle}

{job.companyName} • {job.location}

diff --git a/frontend/src/app/alumni/search/page.js b/frontend/src/app/alumni/search/page.js index 80e8123..4bb1e27 100644 --- a/frontend/src/app/alumni/search/page.js +++ b/frontend/src/app/alumni/search/page.js @@ -1,323 +1,225 @@ "use client"; -import React, { useState } from 'react'; -import { Search, Filter, MapPin, Briefcase, GraduationCap, ChevronDown, ChevronUp, X } from 'lucide-react'; -import Footer from '@/components/footer'; -const AlumniSearchPage = () => { - const [searchTerm, setSearchTerm] = useState(''); - const [industryFilter, setIndustryFilter] = useState(''); - const [locationFilter, setLocationFilter] = useState(''); - const [graduationYearFilter, setGraduationYearFilter] = useState(''); - const [showFilters, setShowFilters] = useState(false); - const [selectedAlumni, setSelectedAlumni] = useState(null); +import React, { useState, useEffect } from "react"; +import { useRouter } from "next/navigation"; +import axios from "axios"; +import Link from "next/link"; +import Image from "next/image"; +import Footer from "@/components/footer"; +import Navbar from "@/components/Navbar"; - // Sample alumni data - const alumniData = [ - { - id: 1, - name: 'Alex Johnson', - gradYear: 2018, - major: 'Computer Science', - industry: 'Technology', - company: 'Google', - position: 'Software Engineer', - location: 'San Francisco, CA', - profileImg: '/api/placeholder/100/100', - bio: 'Full-stack developer with expertise in React and Node.js. Passionate about creating user-friendly applications and mentoring new developers.', - skills: ['JavaScript', 'React', 'Node.js', 'Cloud Computing', 'System Design'], - openToMentoring: true - }, - { - id: 2, - name: 'Sarah Miller', - gradYear: 2020, - major: 'Business Administration', - industry: 'Finance', - company: 'Morgan Stanley', - position: 'Investment Analyst', - location: 'New York, NY', - profileImg: '/api/placeholder/100/100', - bio: 'Investment professional focused on emerging markets. Completed MBA in 2022. Previously worked in consulting.', - skills: ['Financial Analysis', 'Investment Management', 'Market Research', 'Strategic Planning'], - openToMentoring: true - }, - { - id: 3, - name: 'David Chen', - gradYear: 2015, - major: 'Biomedical Engineering', - industry: 'Healthcare', - company: 'Johnson & Johnson', - position: 'Product Manager', - location: 'Boston, MA', - profileImg: '/api/placeholder/100/100', - bio: 'Product manager with background in biomedical engineering. Working on innovative medical devices and healthcare technology solutions.', - skills: ['Product Management', 'Medical Devices', 'Regulatory Compliance', 'R&D'], - openToMentoring: false - }, - { - id: 4, - name: 'Priya Patel', - gradYear: 2019, - major: 'Marketing', - industry: 'Media', - company: 'Netflix', - position: 'Marketing Strategist', - location: 'Los Angeles, CA', - profileImg: '/api/placeholder/100/100', - bio: 'Digital marketing specialist with focus on content strategy and audience engagement. Previously at Disney and Meta.', - skills: ['Digital Marketing', 'Content Strategy', 'Brand Development', 'Analytics'], - openToMentoring: true - } - ]; - - const industries = ['Technology', 'Finance', 'Healthcare', 'Media', 'Education', 'Manufacturing']; - const locations = ['San Francisco, CA', 'New York, NY', 'Boston, MA', 'Los Angeles, CA', 'Chicago, IL', 'Seattle, WA']; - const graduationYears = [2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023]; - - // Filter alumni based on search and filters - const filteredAlumni = alumniData.filter(alumni => { - const matchesSearch = searchTerm === '' || - alumni.name.toLowerCase().includes(searchTerm.toLowerCase()) || - alumni.company.toLowerCase().includes(searchTerm.toLowerCase()) || - alumni.position.toLowerCase().includes(searchTerm.toLowerCase()); - - const matchesIndustry = industryFilter === '' || alumni.industry === industryFilter; - const matchesLocation = locationFilter === '' || alumni.location === locationFilter; - const matchesGradYear = graduationYearFilter === '' || alumni.gradYear.toString() === graduationYearFilter; - - return matchesSearch && matchesIndustry && matchesLocation && matchesGradYear; +export default function AlumniSearch() { + const [searchParams, setSearchParams] = useState({ + name: "", + graduationYear: "", + company: "" }); - - const resetFilters = () => { - setIndustryFilter(''); - setLocationFilter(''); - setGraduationYearFilter(''); + + const [results, setResults] = useState([]); + const [isLoading, setIsLoading] = useState(false); + const [error, setError] = useState(""); + const [totalResults, setTotalResults] = useState(0); + + const router = useRouter(); + + const handleSearch = async (e) => { + if (e) e.preventDefault(); + setError(""); + setIsLoading(true); + + try { + // Filter out empty search parameters + const queryParams = Object.entries(searchParams) + .filter(([_, value]) => value !== "") + .map(([key, value]) => `${key}=${encodeURIComponent(value)}`) + .join("&"); + + const { data } = await axios.get(`http://localhost:5000/api/users/search?${queryParams}`); + + setResults(data.alumni || []); + setTotalResults(data.total || data.alumni?.length || 0); + } catch (err) { + setError(err.response?.data?.error || "Failed to search alumni"); + console.error(err); + setResults([]); + } finally { + setIsLoading(false); + } }; - + + const handleInputChange = (e) => { + const { name, value } = e.target; + setSearchParams(prev => ({ + ...prev, + [name]: value + })); + }; + + const clearSearch = () => { + setSearchParams({ + name: "", + graduationYear: "", + company: "" + }); + setResults([]); + }; + + // Handle graduation year range for dropdown (last 30 years) + const currentYear = new Date().getFullYear(); + const graduationYears = []; + for (let year = currentYear; year >= currentYear - 30; year--) { + graduationYears.push(year); + } + return ( -
-
-

Find Alumni

- - {/* Search Bar */} -
-
- + <> + +
+
+ {/*
+

Alumni Directory

+
+
+ + + + + + + +
+ GradLink
- setSearchTerm(e.target.value)} - /> -
+
*/} - {/* Filters Toggle */} -
- +
+

Search Alumni

- {/* Filters Container */} - {showFilters && ( -
-
- {/* Industry Filter */} -
- - -
- - {/* Location Filter */} -
- - -
- - {/* Graduation Year Filter */} -
- - -
+ {error && ( +
+ {error} +
+ )} + +
+
+
+ + +
+ +
+ + +
+ +
+ +
+
+ +
+ - {/* Reset Filters Button */} -
- )} -
- - {/* Results Count */} -
- Found {filteredAlumni.length} alumni -
- - {/* Alumni List */} -
- {filteredAlumni.map(alumni => ( -
setSelectedAlumni(alumni)} - > -
-
- {alumni.name} -
-

{alumni.name}

-

{alumni.position}

-

{alumni.company}

-
-
- -
-
- - {alumni.industry} -
-
- - {alumni.location} -
-
- - {alumni.major}, Class of {alumni.gradYear} -
-
- - {alumni.openToMentoring && ( -
- - Open to Mentoring - -
- )} -
-
- ))} +
- {/* No Results */} - {filteredAlumni.length === 0 && ( -
-

No alumni match your search criteria

- + {/* Results Section */} +
+
+

+ {results.length > 0 ? `${totalResults} Alumni Found` : "Alumni Directory"} +

- )} - - {/* Alumni Detail Modal */} - {selectedAlumni && ( -
-
-
-
-
- {selectedAlumni.name} -
-

{selectedAlumni.name}

-

{selectedAlumni.position} at {selectedAlumni.company}

-

{selectedAlumni.location}

+ + {isLoading ? ( +
+
+

Searching for alumni...

+
+ ) : results.length > 0 ? ( +
+ {results.map((alumni) => ( +
+ +
+
+ {alumni.firstName.charAt(0)}{alumni.lastName.charAt(0)} +
+
+
+

{alumni.firstName} {alumni.lastName}

+ Class of {alumni.graduationYear} +
+

{alumni.degreeProgram} in {alumni.major}

+ {alumni.company && alumni.jobTitle && ( +

{alumni.jobTitle} at {alumni.company}

+ )} + {alumni.email && alumni.phone && ( +

{alumni.phone}, {alumni.email}

+ )} +
-
- -
- -
-

About

-

{selectedAlumni.bio}

-
- -
-

Education

-

{selectedAlumni.major}, Class of {selectedAlumni.gradYear}

-
- -
-

Skills

-
- {selectedAlumni.skills.map(skill => ( - - {skill} - - ))} -
-
- -
- {selectedAlumni.openToMentoring && ( - - )} - +
+ ))} +
+ ) : ( +
+
+ + +
+

No alumni found

+

Try adjusting your search criteria

-
- )} + )} +
-
+