pagination and filters addd for tjhe location data. front end start aligning to brand ui theme like font family and colors

This commit is contained in:
laxman h 2026-04-23 19:00:45 +05:30
parent d6426f705b
commit 837be9bce1
3 changed files with 83 additions and 2 deletions

View File

@ -78,6 +78,16 @@ export const getAreas = async (req: Request, res: Response) => {
]; ];
} }
const stateId = req.query.stateId as string;
const zoneId = req.query.zoneId as string;
const regionId = req.query.regionId as string;
const isActive = req.query.isActive as string;
if (stateId) where['$district.stateId$'] = stateId;
if (zoneId) where['$district.zoneId$'] = zoneId;
if (regionId) where['$district.regionId$'] = regionId;
if (isActive !== undefined) where.isActive = isActive === 'true';
const { count, rows: areas } = await db.Location.findAndCountAll({ const { count, rows: areas } = await db.Location.findAndCountAll({
where, where,
include: [ include: [

View File

@ -1,6 +1,6 @@
import { Request, Response } from 'express'; import { Request, Response } from 'express';
import db from '../../database/models/index.js'; import db from '../../database/models/index.js';
const { Application, Opportunity, ApplicationStatusHistory, ApplicationProgress, AuditLog, District, State, Region, Zone, SecurityDeposit, FddAssignment, FddReport, OnboardingDocument, Worknote, StageApprovalAction, DealerCode, Dealer, RequestParticipant, QuestionnaireResponse, QuestionnaireQuestion, QuestionnaireOption, User } = db; const { Application, Opportunity, ApplicationStatusHistory, ApplicationProgress, AuditLog, District, State, Region, Zone, SecurityDeposit, FddAssignment, FddReport, OnboardingDocument, Worknote, StageApprovalAction, DealerCode, Dealer, RequestParticipant, QuestionnaireResponse, QuestionnaireQuestion, QuestionnaireOption, Questionnaire, User } = db;
import { AUDIT_ACTIONS, APPLICATION_STAGES, APPLICATION_STATUS } from '../../common/config/constants.js'; import { AUDIT_ACTIONS, APPLICATION_STAGES, APPLICATION_STATUS } from '../../common/config/constants.js';
import { v4 as uuidv4 } from 'uuid'; import { v4 as uuidv4 } from 'uuid';
import { Op } from 'sequelize'; import { Op } from 'sequelize';
@ -1121,3 +1121,72 @@ export const updateApplication = async (req: AuthRequest, res: Response) => {
return res.status(500).json({ success: false, message: 'Internal server error' }); return res.status(500).json({ success: false, message: 'Internal server error' });
} }
}; };
export const exportApplicationResponses = async (req: AuthRequest, res: Response) => {
try {
const { applicationIds } = req.query;
if (!applicationIds) return res.status(400).json({ success: false, message: 'No applications selected' });
const ids = (applicationIds as string).split(',');
// 1. Fetch Applications with their identification details
const applications = await Application.findAll({
where: {
id: { [Op.in]: ids },
overallStatus: { [Op.ne]: APPLICATION_STATUS.QUESTIONNAIRE_PENDING }
},
attributes: ['id', 'applicationId', 'applicantName', 'preferredLocation', 'email', 'phone']
});
if (applications.length === 0 && ids.length > 0) {
return res.status(400).json({
success: false,
message: 'No applications found with completed questionnaires among the selected records.'
});
}
// 2. Fetch all unique questions involved in these applications
// For consistency, let's get all questions from the active questionnaire
const activeQuestionnaire = await Questionnaire.findOne({ where: { isActive: true }, order: [['version', 'DESC']] });
if (!activeQuestionnaire) return res.status(404).json({ success: false, message: 'Active questionnaire not found' });
const allQuestions = await QuestionnaireQuestion.findAll({
where: { questionnaireId: activeQuestionnaire.id },
order: [['order', 'ASC']]
});
// 3. Fetch all responses for these applications
const responses = await QuestionnaireResponse.findAll({
where: { applicationId: { [Op.in]: ids } },
attributes: ['applicationId', 'questionId', 'responseValue']
});
// 4. Map responses for quick lookup: applicationid -> questionid -> responseValue
const responsesMap: any = {};
responses.forEach((r: any) => {
if (!responsesMap[r.applicationId]) responsesMap[r.applicationId] = {};
responsesMap[r.applicationId][r.questionId] = r.responseValue;
});
// 5. Construct rows
const rows = applications.map((app: any) => {
const data: any = {
'Application ID': app.applicationId,
'Applicant Name': app.applicantName,
'Email': app.email,
'Phone': app.phone,
'Preferred Location': app.preferredLocation
};
allQuestions.forEach((q: any) => {
data[q.questionText] = responsesMap[app.id]?.[q.id] || 'Not Answered';
});
return data;
});
res.json({ success: true, data: rows });
} catch (error) {
console.error('Export error:', error);
res.status(500).json({ success: false, message: 'Error exporting data' });
}
};

View File

@ -5,7 +5,8 @@ import {
uploadDocuments, getApplicationDocuments, bulkShortlist, uploadDocuments, getApplicationDocuments, bulkShortlist,
assignArchitectureTeam, updateArchitectureStatus, generateDealerCodes, assignArchitectureTeam, updateArchitectureStatus, generateDealerCodes,
retriggerEvaluators, getDocumentConfigs, getDocumentConfigMetadata, retriggerEvaluators, getDocumentConfigs, getDocumentConfigMetadata,
createDocumentConfig, updateDocumentConfig, deleteDocumentConfig, updateApplication createDocumentConfig, updateDocumentConfig, deleteDocumentConfig, updateApplication,
exportApplicationResponses
} from './onboarding.controller.js'; } from './onboarding.controller.js';
import { authenticate } from '../../common/middleware/auth.js'; import { authenticate } from '../../common/middleware/auth.js';
@ -23,6 +24,7 @@ router.put('/document-configs/:id', updateDocumentConfig);
router.delete('/document-configs/:id', deleteDocumentConfig); router.delete('/document-configs/:id', deleteDocumentConfig);
router.get('/applications', getApplications); router.get('/applications', getApplications);
router.get('/applications/export-responses', exportApplicationResponses);
router.get('/document-configs/metadata', getDocumentConfigMetadata); router.get('/document-configs/metadata', getDocumentConfigMetadata);
router.get('/document-configs', getDocumentConfigs); router.get('/document-configs', getDocumentConfigs);
router.post('/applications/shortlist', bulkShortlist); // Existing route, updated to named import router.post('/applications/shortlist', bulkShortlist); // Existing route, updated to named import