1- const Job = require ( '../models/jobs' ) ; // Import the Job model
1+ const Job = require ( '../models/jobs' ) ;
22const JobPositionCategory = require ( '../models/jobPositionCategory' ) ;
3- // Controller to fetch all jobs with pagination, search, and filtering
3+
4+ /* ============================================================
5+ INTERNAL: MAIN PAGINATION + FILTERING LOGIC
6+ ============================================================ */
47const paginationForJobs = async ( req , res ) => {
58 const { page = 1 , limit = 18 , search = '' , category = '' , position = '' } = req . query ;
69
710 try {
8- // Validate query parameters
9- const pageNumber = Math . max ( 1 , parseInt ( page , 10 ) ) ; // Ensure page is at least 1
10- const limitNumber = Math . max ( 1 , parseInt ( limit , 10 ) ) ; // Ensure limit is at least 1
11+ const pageNumber = Math . max ( 1 , parseInt ( page , 10 ) ) ;
12+ const limitNumber = Math . max ( 1 , parseInt ( limit , 10 ) ) ;
1113
12- // Build query conditions
1314 const conditions = [ ] ;
14- const [ allCategories , allPositions ] = await Promise . all ( [
15- JobPositionCategory . distinct ( 'category' ) ,
16- JobPositionCategory . distinct ( 'position' ) ,
17- ] ) ;
1815
19- if ( search ) {
20- const searchString = String ( search ) ;
16+ /* ----------------------------
17+ SEARCH FILTER
18+ ---------------------------- */
19+ if ( search && search . trim ( ) !== '' ) {
20+ const searchString = search . trim ( ) ;
2121 conditions . push ( {
2222 $or : [
2323 { title : { $regex : new RegExp ( searchString , 'i' ) } } ,
2424 { description : { $regex : new RegExp ( searchString , 'i' ) } } ,
2525 ] ,
2626 } ) ;
27- } // Case-insensitive search
28-
29- if ( position ) conditions . push ( { title : { $in : [ position ] } } ) ;
27+ }
3028
31- if ( category ) conditions . push ( { category : { $in : [ category ] } } ) ;
29+ /* ----------------------------
30+ POSITION FILTER (only if non-empty)
31+ ---------------------------- */
32+ if ( position && position . trim ( ) !== '' ) {
33+ conditions . push ( { title : { $in : [ position . trim ( ) ] } } ) ;
34+ }
3235
33- if ( allCategories . length ) conditions . push ( { category : { $in : allCategories } } ) ;
34- if ( allPositions . length ) conditions . push ( { title : { $in : allPositions } } ) ;
35- // Final query
36+ /* ----------------------------
37+ MULTI-CATEGORY FILTER (only if non-empty)
38+ ---------------------------- */
39+ if ( category && category . trim ( ) !== '' ) {
40+ const categoryList = category . split ( ',' ) . map ( ( c ) => c . trim ( ) ) ;
41+ conditions . push ( { category : { $in : categoryList } } ) ;
42+ }
3643
3744 const query = conditions . length ? { $and : conditions } : { } ;
45+
3846 const totalJobs = await Job . countDocuments ( query ) ;
47+ const totalPages = Math . ceil ( totalJobs / limitNumber ) ;
3948
40- const totalPages = Math . ceil ( totalJobs / limitNumber ) ; // was 20
49+ const pageNum = pageNumber > totalPages ? 1 : pageNumber ;
4150
42- let pageNum ;
43- if ( pageNumber > totalPages ) pageNum = 1 ;
44- else pageNum = pageNumber ;
45- // Fetch paginated results
4651 const jobs = await Job . find ( query )
4752 . skip ( ( pageNum - 1 ) * limitNumber )
4853 . limit ( limitNumber ) ;
4954
50- // Prepare response
5155 res . json ( {
5256 jobs,
5357 pagination : {
5458 totalJobs,
55- totalPages : Math . ceil ( totalJobs / limitNumber ) ,
56- currentPage : pageNumber ,
59+ totalPages,
60+ currentPage : pageNum ,
5761 limit : limitNumber ,
58- hasNextPage : pageNumber < Math . ceil ( totalJobs / limitNumber ) ,
59- hasPreviousPage : pageNumber > 1 ,
62+ hasNextPage : pageNum < totalPages ,
63+ hasPreviousPage : pageNum > 1 ,
6064 } ,
6165 } ) ;
6266 } catch ( error ) {
63- res . status ( 500 ) . json ( { error : 'Failed to fetch Jobs/Summaries' , details : error . message } ) ;
67+ res . status ( 500 ) . json ( {
68+ error : 'Failed to fetch Jobs' ,
69+ details : error . message ,
70+ } ) ;
6471 }
6572} ;
6673
67- // Controller to fetch all jobs with pagination, search, and filtering
68- const getJobs = ( req , res ) => paginationForJobs ( req , res , false ) ;
74+ /* ============================================================
75+ EXPORT: GET JOBS WITH PAGINATION
76+ ============================================================ */
77+ const getJobs = ( req , res ) => paginationForJobs ( req , res ) ;
6978
70- // Controller to fetch job summaries with pagination, search, filtering, and sorting
79+ /* ============================================================
80+ JOB SUMMARIES
81+ ============================================================ */
7182const getJobSummaries = async ( req , res ) => {
7283 const { search = '' , category = '' , position = '' } = req . query ;
7384
7485 try {
75- // Build query conditions
7686 const conditions = [ ] ;
77- const [ allCategories , allPositions ] = await Promise . all ( [
78- JobPositionCategory . distinct ( 'category' ) ,
79- JobPositionCategory . distinct ( 'position' ) ,
80- ] ) ;
8187
82- if ( search ) {
83- const searchString = String ( search ) ;
88+ if ( search && search . trim ( ) !== '' ) {
89+ const searchString = search . trim ( ) ;
8490 conditions . push ( {
8591 $or : [
8692 { title : { $regex : new RegExp ( searchString , 'i' ) } } ,
8793 { description : { $regex : new RegExp ( searchString , 'i' ) } } ,
8894 ] ,
8995 } ) ;
90- } // Case-insensitive search
91-
92- if ( position ) conditions . push ( { title : { $in : [ position ] } } ) ;
96+ }
9397
94- if ( category ) conditions . push ( { category : { $in : [ category ] } } ) ;
98+ if ( position && position . trim ( ) !== '' ) {
99+ conditions . push ( { title : { $in : [ position . trim ( ) ] } } ) ;
100+ }
95101
96- if ( allCategories . length ) conditions . push ( { category : { $in : allCategories } } ) ;
97- if ( allPositions . length ) conditions . push ( { title : { $in : allPositions } } ) ;
98- // Final query
102+ if ( category && category . trim ( ) !== '' ) {
103+ const categoryList = category . split ( ',' ) . map ( ( c ) => c . trim ( ) ) ;
104+ conditions . push ( { category : { $in : categoryList } } ) ;
105+ }
99106
100107 const query = conditions . length ? { $and : conditions } : { } ;
101108
102- // Sorting logic
103109 const sortCriteria = {
104110 displayOrder : 1 ,
105111 featured : - 1 ,
106112 datePosted : - 1 ,
107113 title : 1 ,
108114 } ;
109115
110- // Fetch the total number of jobs matching the query for pagination
111116 const totalJobs = await Job . countDocuments ( query ) ;
112117 const jobs = await Job . find ( query )
113118 . select ( 'title category location description datePosted featured jobDetailsLink' )
114119 . sort ( sortCriteria ) ;
115120
116- res . json ( {
117- jobs,
118- totalJobs,
119- } ) ;
121+ res . json ( { jobs, totalJobs } ) ;
120122 } catch ( error ) {
121- res . status ( 500 ) . json ( { error : 'Failed to fetch job summaries' , details : error . message } ) ;
123+ res . status ( 500 ) . json ( {
124+ error : 'Failed to fetch job summaries' ,
125+ details : error . message ,
126+ } ) ;
122127 }
123128} ;
124129
125- // Controller to fetch job title suggestions for a dropdown
130+ /* ============================================================
131+ OTHER CONTROLLERS
132+ ============================================================ */
126133const getJobTitleSuggestions = async ( req , res ) => {
127134 const { query = '' } = req . query ;
128-
129135 try {
130- const suggestions = await Job . find ( { title : { $regex : query , $options : 'i' } } ) . distinct (
131- ' title' ,
132- ) ;
136+ const suggestions = await Job . find ( {
137+ title : { $regex : query , $options : 'i' } ,
138+ } ) . distinct ( 'title' ) ;
133139
134140 res . json ( { suggestions } ) ;
135141 } catch ( error ) {
136- res
137- . status ( 500 )
138- . json ( { error : 'Failed to fetch job title suggestions' , details : error . message } ) ;
142+ res . status ( 500 ) . json ( { error : 'Failed to fetch job title suggestions' } ) ;
139143 }
140144} ;
141145
142146const resetJobsFilters = async ( req , res ) => {
143147 const { page = 1 , limit = 18 } = req . query ;
144148
145149 try {
146- // Validate pagination parameters
147150 const pageNumber = Math . max ( 1 , parseInt ( page , 10 ) ) ;
148151 const limitNumber = Math . max ( 1 , parseInt ( limit , 10 ) ) ;
149152
150- // Sorting logic
151153 const sortCriteria = {
152154 displayOrder : 1 ,
153155 featured : - 1 ,
154156 datePosted : - 1 ,
155157 title : 1 ,
156158 } ;
157- // Fetch all jobs without filtering
159+
158160 const totalJobs = await Job . countDocuments ( { } ) ;
159161 const jobs = await Job . find ( { } )
160162 . sort ( sortCriteria )
161163 . skip ( ( pageNumber - 1 ) * limitNumber )
162164 . limit ( limitNumber ) ;
163165
164- // Respond with all jobs and pagination metadata
165166 res . json ( {
166167 jobs,
167168 pagination : {
@@ -174,64 +175,50 @@ const resetJobsFilters = async (req, res) => {
174175 } ,
175176 } ) ;
176177 } catch ( error ) {
177- res
178- . status ( 500 )
179- . json ( { error : 'Failed to reset filters or reload jobs' , details : error . message } ) ;
178+ res . status ( 500 ) . json ( { error : 'Failed to reset filters' , details : error . message } ) ;
180179 }
181180} ;
182181
183182const getCategories = async ( req , res ) => {
184183 try {
185- // const categories = await Job.distinct('category', {});
186184 const categories = await JobPositionCategory . distinct ( 'category' , { } ) ;
187- // Sort categories alphabetically
188185 categories . sort ( ( a , b ) => a . localeCompare ( b ) ) ;
189-
190186 res . status ( 200 ) . json ( { categories } ) ;
191- } catch ( error ) {
187+ } catch {
192188 res . status ( 500 ) . json ( { message : 'Failed to fetch categories' } ) ;
193189 }
194190} ;
191+
195192const getPositions = async ( req , res ) => {
196193 try {
197194 const positions = await JobPositionCategory . distinct ( 'position' , { } ) ;
198-
199- // Sort categories alphabetically
200195 positions . sort ( ( a , b ) => a . localeCompare ( b ) ) ;
201-
202196 res . status ( 200 ) . json ( { positions } ) ;
203- } catch ( error ) {
197+ } catch {
204198 res . status ( 500 ) . json ( { message : 'Failed to fetch positions' } ) ;
205199 }
206200} ;
207201
208- // Controller to fetch job details by ID
209202const getJobById = async ( req , res ) => {
210203 const { id } = req . params ;
211-
212204 try {
213205 const job = await Job . findById ( id ) ;
214- if ( ! job ) {
215- return res . status ( 404 ) . json ( { error : 'Job not found' } ) ;
216- }
206+ if ( ! job ) return res . status ( 404 ) . json ( { error : 'Job not found' } ) ;
217207 res . json ( job ) ;
218208 } catch ( error ) {
219209 res . status ( 500 ) . json ( { error : 'Failed to fetch job' , details : error . message } ) ;
220210 }
221211} ;
222212
223- // Controller to create a new job
224213const createJob = async ( req , res ) => {
225214 const { title, category, description, imageUrl, location, applyLink, jobDetailsLink } = req . body ;
226215
227216 try {
228- // Find the highest displayOrder value currently in use
229217 const highestOrderJob = await Job . findOne ( ) . sort ( { displayOrder : - 1 } ) . limit ( 1 ) ;
230218 const newDisplayOrder = highestOrderJob ? highestOrderJob . displayOrder + 1 : 0 ;
231219
232220 const newJob = new Job ( {
233221 title,
234- // summaries,
235222 category,
236223 description,
237224 imageUrl,
@@ -248,47 +235,37 @@ const createJob = async (req, res) => {
248235 }
249236} ;
250237
251- // Controller to update an existing job by ID
252238const updateJob = async ( req , res ) => {
253239 const { id } = req . params ;
254240
255241 try {
256242 const updatedJob = await Job . findByIdAndUpdate ( id , req . body , { new : true } ) ;
257- if ( ! updatedJob ) {
258- return res . status ( 404 ) . json ( { error : 'Job not found' } ) ;
259- }
243+ if ( ! updatedJob ) return res . status ( 404 ) . json ( { error : 'Job not found' } ) ;
260244 res . json ( updatedJob ) ;
261245 } catch ( error ) {
262246 res . status ( 500 ) . json ( { error : 'Failed to update job' , details : error . message } ) ;
263247 }
264248} ;
265249
266- // Controller to delete a job by ID
267250const deleteJob = async ( req , res ) => {
268251 const { id } = req . params ;
269252
270253 try {
271254 const deletedJob = await Job . findByIdAndDelete ( id ) ;
272- if ( ! deletedJob ) {
273- return res . status ( 404 ) . json ( { error : 'Job not found' } ) ;
274- }
255+ if ( ! deletedJob ) return res . status ( 404 ) . json ( { error : 'Job not found' } ) ;
275256 res . json ( { message : 'Job deleted successfully' } ) ;
276257 } catch ( error ) {
277258 res . status ( 500 ) . json ( { error : 'Failed to delete job' , details : error . message } ) ;
278259 }
279260} ;
280261
281- // Controller to reorder jobs
282262const reorderJobs = async ( req , res ) => {
283263 const { jobIds } = req . body ;
284264
285265 try {
286- // Validate input
287- if ( ! Array . isArray ( jobIds ) || jobIds . length === 0 ) {
266+ if ( ! Array . isArray ( jobIds ) || jobIds . length === 0 )
288267 return res . status ( 400 ) . json ( { error : 'Invalid job order data' } ) ;
289- }
290268
291- // Update the order of each job
292269 const updateOperations = jobIds . map ( ( jobId , index ) => ( {
293270 updateOne : {
294271 filter : { _id : jobId } ,
@@ -298,7 +275,6 @@ const reorderJobs = async (req, res) => {
298275
299276 await Job . bulkWrite ( updateOperations ) ;
300277
301- // Fetch and return the updated jobs
302278 const jobs = await Job . find ( { _id : { $in : jobIds } } ) . sort ( { displayOrder : 1 } ) ;
303279
304280 res . json ( {
@@ -311,7 +287,6 @@ const reorderJobs = async (req, res) => {
311287 }
312288} ;
313289
314- // Export controllers as a plain object
315290module . exports = {
316291 getJobs,
317292 getJobTitleSuggestions,
0 commit comments