feat(api): complete unified v2 mobile surface

This commit is contained in:
zouantchaw
2026-03-13 17:02:24 +01:00
parent 817a39e305
commit b455455a49
39 changed files with 7726 additions and 506 deletions

View File

@@ -1,32 +1,47 @@
import { Router } from 'express';
import { requireAuth, requirePolicy } from '../middleware/auth.js';
import {
getCoverageReport,
getClientDashboard,
getClientSession,
getCoverageStats,
getCurrentAttendanceStatus,
getCurrentBill,
getDailyOpsReport,
getPaymentChart,
getPaymentsSummary,
getPersonalInfo,
getPerformanceReport,
getProfileSectionsStatus,
getPrivacySettings,
getForecastReport,
getNoShowReport,
getOrderReorderPreview,
getReportSummary,
getSavings,
getStaffDashboard,
getStaffProfileCompletion,
getStaffSession,
getStaffShiftDetail,
listAttireChecklist,
listAssignedShifts,
listBusinessAccounts,
listBusinessTeamMembers,
listCancelledShifts,
listCertificates,
listCostCenters,
listCoreTeam,
listCoverageByDate,
listCompletedShifts,
listEmergencyContacts,
listFaqCategories,
listHubManagers,
listHubs,
listIndustries,
listInvoiceHistory,
listOpenShifts,
listTaxForms,
listTimeCardEntries,
listOrderItemsByDateRange,
listPaymentsHistory,
listPendingAssignments,
@@ -40,37 +55,55 @@ import {
listTodayShifts,
listVendorRoles,
listVendors,
searchFaqs,
getSpendBreakdown,
getSpendReport,
} from '../services/mobile-query-service.js';
const defaultQueryService = {
getClientDashboard,
getClientSession,
getCoverageReport,
getCoverageStats,
getCurrentAttendanceStatus,
getCurrentBill,
getDailyOpsReport,
getPaymentChart,
getPaymentsSummary,
getPersonalInfo,
getPerformanceReport,
getProfileSectionsStatus,
getPrivacySettings,
getForecastReport,
getNoShowReport,
getOrderReorderPreview,
getReportSummary,
getSavings,
getSpendBreakdown,
getSpendReport,
getStaffDashboard,
getStaffProfileCompletion,
getStaffSession,
getStaffShiftDetail,
listAttireChecklist,
listAssignedShifts,
listBusinessAccounts,
listBusinessTeamMembers,
listCancelledShifts,
listCertificates,
listCostCenters,
listCoreTeam,
listCoverageByDate,
listCompletedShifts,
listEmergencyContacts,
listFaqCategories,
listHubManagers,
listHubs,
listIndustries,
listInvoiceHistory,
listOpenShifts,
listTaxForms,
listTimeCardEntries,
listOrderItemsByDateRange,
listPaymentsHistory,
listPendingAssignments,
@@ -84,6 +117,7 @@ const defaultQueryService = {
listTodayShifts,
listVendorRoles,
listVendors,
searchFaqs,
};
function requireQueryParam(name, value) {
@@ -199,6 +233,15 @@ export function createMobileQueryRouter(queryService = defaultQueryService) {
}
});
router.get('/client/coverage/core-team', requireAuth, requirePolicy('coverage.read', 'coverage'), async (req, res, next) => {
try {
const items = await queryService.listCoreTeam(req.actor.uid);
return res.status(200).json({ items, requestId: req.requestId });
} catch (error) {
return next(error);
}
});
router.get('/client/hubs', requireAuth, requirePolicy('hubs.read', 'hub'), async (req, res, next) => {
try {
const items = await queryService.listHubs(req.actor.uid);
@@ -244,6 +287,15 @@ export function createMobileQueryRouter(queryService = defaultQueryService) {
}
});
router.get('/client/team-members', requireAuth, requirePolicy('hubs.read', 'hub'), async (req, res, next) => {
try {
const items = await queryService.listBusinessTeamMembers(req.actor.uid);
return res.status(200).json({ items, requestId: req.requestId });
} catch (error) {
return next(error);
}
});
router.get('/client/orders/view', requireAuth, requirePolicy('orders.read', 'order'), async (req, res, next) => {
try {
const items = await queryService.listOrderItemsByDateRange(req.actor.uid, req.query);
@@ -253,6 +305,78 @@ export function createMobileQueryRouter(queryService = defaultQueryService) {
}
});
router.get('/client/orders/:orderId/reorder-preview', requireAuth, requirePolicy('orders.read', 'order'), async (req, res, next) => {
try {
const data = await queryService.getOrderReorderPreview(req.actor.uid, req.params.orderId);
return res.status(200).json({ ...data, requestId: req.requestId });
} catch (error) {
return next(error);
}
});
router.get('/client/reports/summary', requireAuth, requirePolicy('reports.read', 'report'), async (req, res, next) => {
try {
const data = await queryService.getReportSummary(req.actor.uid, req.query);
return res.status(200).json({ ...data, requestId: req.requestId });
} catch (error) {
return next(error);
}
});
router.get('/client/reports/daily-ops', requireAuth, requirePolicy('reports.read', 'report'), async (req, res, next) => {
try {
const data = await queryService.getDailyOpsReport(req.actor.uid, { date: requireQueryParam('date', req.query.date) });
return res.status(200).json({ ...data, requestId: req.requestId });
} catch (error) {
return next(error);
}
});
router.get('/client/reports/spend', requireAuth, requirePolicy('reports.read', 'report'), async (req, res, next) => {
try {
const data = await queryService.getSpendReport(req.actor.uid, req.query);
return res.status(200).json({ ...data, requestId: req.requestId });
} catch (error) {
return next(error);
}
});
router.get('/client/reports/coverage', requireAuth, requirePolicy('reports.read', 'report'), async (req, res, next) => {
try {
const data = await queryService.getCoverageReport(req.actor.uid, req.query);
return res.status(200).json({ ...data, requestId: req.requestId });
} catch (error) {
return next(error);
}
});
router.get('/client/reports/forecast', requireAuth, requirePolicy('reports.read', 'report'), async (req, res, next) => {
try {
const data = await queryService.getForecastReport(req.actor.uid, req.query);
return res.status(200).json({ ...data, requestId: req.requestId });
} catch (error) {
return next(error);
}
});
router.get('/client/reports/performance', requireAuth, requirePolicy('reports.read', 'report'), async (req, res, next) => {
try {
const data = await queryService.getPerformanceReport(req.actor.uid, req.query);
return res.status(200).json({ ...data, requestId: req.requestId });
} catch (error) {
return next(error);
}
});
router.get('/client/reports/no-show', requireAuth, requirePolicy('reports.read', 'report'), async (req, res, next) => {
try {
const data = await queryService.getNoShowReport(req.actor.uid, req.query);
return res.status(200).json({ ...data, requestId: req.requestId });
} catch (error) {
return next(error);
}
});
router.get('/staff/session', requireAuth, requirePolicy('staff.session.read', 'session'), async (req, res, next) => {
try {
const data = await queryService.getStaffSession(req.actor.uid);
@@ -433,6 +557,33 @@ export function createMobileQueryRouter(queryService = defaultQueryService) {
}
});
router.get('/staff/profile/attire', requireAuth, requirePolicy('staff.profile.read', 'staff'), async (req, res, next) => {
try {
const items = await queryService.listAttireChecklist(req.actor.uid);
return res.status(200).json({ items, requestId: req.requestId });
} catch (error) {
return next(error);
}
});
router.get('/staff/profile/tax-forms', requireAuth, requirePolicy('staff.profile.read', 'staff'), async (req, res, next) => {
try {
const items = await queryService.listTaxForms(req.actor.uid);
return res.status(200).json({ items, requestId: req.requestId });
} catch (error) {
return next(error);
}
});
router.get('/staff/profile/emergency-contacts', requireAuth, requirePolicy('staff.profile.read', 'staff'), async (req, res, next) => {
try {
const items = await queryService.listEmergencyContacts(req.actor.uid);
return res.status(200).json({ items, requestId: req.requestId });
} catch (error) {
return next(error);
}
});
router.get('/staff/profile/certificates', requireAuth, requirePolicy('staff.profile.read', 'staff'), async (req, res, next) => {
try {
const items = await queryService.listCertificates(req.actor.uid);
@@ -460,5 +611,41 @@ export function createMobileQueryRouter(queryService = defaultQueryService) {
}
});
router.get('/staff/profile/time-card', requireAuth, requirePolicy('staff.profile.read', 'staff'), async (req, res, next) => {
try {
const items = await queryService.listTimeCardEntries(req.actor.uid, req.query);
return res.status(200).json({ items, requestId: req.requestId });
} catch (error) {
return next(error);
}
});
router.get('/staff/profile/privacy', requireAuth, requirePolicy('staff.profile.read', 'staff'), async (req, res, next) => {
try {
const data = await queryService.getPrivacySettings(req.actor.uid);
return res.status(200).json({ ...data, requestId: req.requestId });
} catch (error) {
return next(error);
}
});
router.get('/staff/faqs', async (req, res, next) => {
try {
const items = await queryService.listFaqCategories();
return res.status(200).json({ items, requestId: req.requestId });
} catch (error) {
return next(error);
}
});
router.get('/staff/faqs/search', async (req, res, next) => {
try {
const items = await queryService.searchFaqs(req.query.q || '');
return res.status(200).json({ items, requestId: req.requestId });
} catch (error) {
return next(error);
}
});
return router;
}