381 lines
13 KiB
JavaScript
381 lines
13 KiB
JavaScript
import { readOnboardedPii } from '../services/cryptoPii.js';
|
|
import { toYmd, weekdayOf } from '../services/schedule.js';
|
|
|
|
export function userLanguages(user) {
|
|
const fromArray = (user?.languages || []).map((item) => String(item || '').trim()).filter(Boolean);
|
|
if (fromArray.length) return [...new Set(fromArray)];
|
|
if (user?.language) return [String(user.language).trim()].filter(Boolean);
|
|
return [];
|
|
}
|
|
|
|
export function toUserDto(user, extras = {}) {
|
|
if (!user) return null;
|
|
const role = user.role && typeof user.role === 'object' ? user.role : null;
|
|
const languages = userLanguages(user);
|
|
return {
|
|
id: String(user._id),
|
|
firstName: user.firstName,
|
|
lastName: user.lastName,
|
|
email: user.email,
|
|
phone: user.phone || '',
|
|
languages,
|
|
language: languages[0] || '',
|
|
specializations: Array.isArray(user.specializations) ? user.specializations : [],
|
|
availableSlots: Array.isArray(user.availableSlots) ? user.availableSlots : [],
|
|
availableStartWeekdays: Array.isArray(user.availableStartWeekdays) ? user.availableStartWeekdays : [],
|
|
maxCohorts: user.maxCohorts ?? null,
|
|
isActive: user.isActive,
|
|
lastLoginAt: user.lastLoginAt,
|
|
createdAt: user.createdAt,
|
|
updatedAt: user.updatedAt,
|
|
role: role
|
|
? {
|
|
id: String(role._id),
|
|
name: role.name,
|
|
systemKey: role.systemKey,
|
|
isSystem: role.isSystem,
|
|
}
|
|
: user.role
|
|
? { id: String(user.role) }
|
|
: null,
|
|
...extras,
|
|
};
|
|
}
|
|
|
|
export function toGoogleCalendarDto(user) {
|
|
const google = user?.google || {};
|
|
return {
|
|
connected: Boolean(google.refreshToken || google.accessToken),
|
|
email: google.email || '',
|
|
};
|
|
}
|
|
|
|
export function toAuthPayload(user) {
|
|
return toUserDto(user, { googleCalendar: toGoogleCalendarDto(user) });
|
|
}
|
|
|
|
export function toRoleDto(role, userCount = 0) {
|
|
return {
|
|
id: String(role._id),
|
|
name: role.name,
|
|
description: role.description || '',
|
|
systemKey: role.systemKey,
|
|
isSystem: role.isSystem,
|
|
permissions: (role.permissions || []).map((p) => ({
|
|
module: p.module,
|
|
actions: [...(p.actions || [])],
|
|
scope: p.scope || 'all',
|
|
})),
|
|
userCount,
|
|
createdAt: role.createdAt,
|
|
updatedAt: role.updatedAt,
|
|
};
|
|
}
|
|
|
|
export function toPatientDto(patient) {
|
|
const educator = patient.assignedEducator && typeof patient.assignedEducator === 'object'
|
|
? patient.assignedEducator
|
|
: null;
|
|
return {
|
|
id: String(patient._id),
|
|
sourcePatientId: patient.sourcePatientId,
|
|
name: patient.name,
|
|
mobile: patient.mobile || '',
|
|
age: patient.age,
|
|
gender: patient.gender || '',
|
|
lungCondition: patient.lungCondition || '',
|
|
otherHealthCondition: patient.otherHealthCondition || '',
|
|
sessionLanguage: patient.sessionLanguage || patient.language || '',
|
|
consentType: patient.consentType || '',
|
|
isNewOrOld: patient.isNewOrOld || '',
|
|
doctor: patient.doctor || {},
|
|
lastVisitDate: patient.lastVisitDate,
|
|
assignedEducator: educator
|
|
? {
|
|
id: String(educator._id),
|
|
firstName: educator.firstName,
|
|
lastName: educator.lastName,
|
|
email: educator.email,
|
|
}
|
|
: patient.assignedEducator
|
|
? { id: String(patient.assignedEducator) }
|
|
: null,
|
|
createdAt: patient.createdAt,
|
|
updatedAt: patient.updatedAt,
|
|
};
|
|
}
|
|
|
|
export function toSessionDto(session) {
|
|
if (!session) return null;
|
|
const s = typeof session.toObject === 'function' ? session.toObject() : session;
|
|
const patientId = s.patient && typeof s.patient === 'object' ? s.patient._id : s.patient;
|
|
return {
|
|
id: String(s._id),
|
|
sourceSessionId: s.sourceSessionId,
|
|
patientId: patientId ? String(patientId) : null,
|
|
visitDate: s.visitDate || null,
|
|
slot: s.slot || '',
|
|
sessionType: s.sessionType || '',
|
|
sessionReporting: s.sessionReporting || '',
|
|
zoomNotJoiningReason: s.zoomNotJoiningReason || '',
|
|
exercises: {
|
|
exercise: s.exercises?.exercise || '',
|
|
warmUp: s.exercises?.warmUp || '',
|
|
breathing: s.exercises?.breathing || '',
|
|
aerobic: s.exercises?.aerobic || '',
|
|
strengthening: s.exercises?.strengthening || '',
|
|
coolDown: s.exercises?.coolDown || '',
|
|
other: s.exercises?.other || '',
|
|
},
|
|
vitals: {
|
|
spo2Pre: s.vitals?.spo2Pre ?? null,
|
|
heartRatePre: s.vitals?.heartRatePre ?? null,
|
|
bpPre: s.vitals?.bpPre || '',
|
|
respPre: s.vitals?.respPre ?? null,
|
|
spo2Post: s.vitals?.spo2Post ?? null,
|
|
heartRatePost: s.vitals?.heartRatePost ?? null,
|
|
bpPost: s.vitals?.bpPost || '',
|
|
respPost: s.vitals?.respPost ?? null,
|
|
rpeRest: s.vitals?.rpeRest ?? null,
|
|
rpeActivity: s.vitals?.rpeActivity ?? null,
|
|
},
|
|
assessments: {
|
|
fev1: s.assessments?.fev1 ?? null,
|
|
fvc: s.assessments?.fvc ?? null,
|
|
sixMwt: s.assessments?.sixMwt ?? null,
|
|
eq5d3l: s.assessments?.eq5d3l ?? null,
|
|
sgrq: s.assessments?.sgrq ?? null,
|
|
sitToStand: s.assessments?.sitToStand ?? null,
|
|
o2Regular: s.assessments?.o2Regular ?? null,
|
|
o2WithExercise: s.assessments?.o2WithExercise ?? null,
|
|
},
|
|
employee: {
|
|
code: s.employee?.code || '',
|
|
uniqueId: s.employee?.uniqueId || '',
|
|
parentCode: s.employee?.parentCode || '',
|
|
name: s.employee?.name || '',
|
|
hq: s.employee?.hq || '',
|
|
region: s.employee?.region || '',
|
|
zone: s.employee?.zone || '',
|
|
},
|
|
sourceCreatedAt: s.sourceCreatedAt || null,
|
|
sourceModifiedAt: s.sourceModifiedAt || null,
|
|
createdAt: s.createdAt,
|
|
updatedAt: s.updatedAt,
|
|
};
|
|
}
|
|
|
|
export function toOnboardedPatientDto(item) {
|
|
if (!item) return null;
|
|
const pii = readOnboardedPii(item);
|
|
const by = item.onboardedBy && typeof item.onboardedBy === 'object'
|
|
? item.onboardedBy
|
|
: null;
|
|
return {
|
|
id: String(item._id),
|
|
sourcePatientId: item.sourcePatientId || '',
|
|
name: pii.name,
|
|
mobile: pii.mobile,
|
|
age: pii.age,
|
|
gender: pii.gender,
|
|
lungCondition: pii.lungCondition,
|
|
otherHealthCondition: pii.otherHealthCondition,
|
|
sessionLanguage: item.sessionLanguage || '',
|
|
diseaseType: item.diseaseType || '',
|
|
preferredWeekday: item.preferredWeekday ?? null,
|
|
sessionDate: item.sessionDate || null,
|
|
slot: item.slot || '',
|
|
matchingStatus: item.matchingStatus || 'unassigned',
|
|
rejectReason: item.rejectReason || '',
|
|
paymentStatus: item.paymentStatus || 'Unpaid',
|
|
hasScreenshot: Boolean(item.paymentScreenshot?.filename),
|
|
onboardedBy: by
|
|
? {
|
|
id: String(by._id),
|
|
firstName: by.firstName,
|
|
lastName: by.lastName,
|
|
email: by.email,
|
|
}
|
|
: item.onboardedBy
|
|
? { id: String(item.onboardedBy) }
|
|
: null,
|
|
assignedEducator: item.assignedEducator && typeof item.assignedEducator === 'object'
|
|
? {
|
|
id: String(item.assignedEducator._id),
|
|
firstName: item.assignedEducator.firstName,
|
|
lastName: item.assignedEducator.lastName,
|
|
}
|
|
: item.assignedEducator
|
|
? { id: String(item.assignedEducator) }
|
|
: null,
|
|
cohort: item.cohort && typeof item.cohort === 'object'
|
|
? { id: String(item.cohort._id), name: item.cohort.name, startDate: toYmd(item.cohort.startDate), slot: item.cohort.slot, language: item.cohort.language || '' }
|
|
: item.cohort
|
|
? { id: String(item.cohort) }
|
|
: null,
|
|
whatsappOptOut: Boolean(item.whatsappOptOut),
|
|
reviewStatus: item.reviewStatus || 'pending',
|
|
reviewedAt: item.reviewedAt || null,
|
|
reviewedBy: item.reviewedBy && typeof item.reviewedBy === 'object'
|
|
? {
|
|
id: String(item.reviewedBy._id),
|
|
firstName: item.reviewedBy.firstName,
|
|
lastName: item.reviewedBy.lastName,
|
|
}
|
|
: item.reviewedBy
|
|
? { id: String(item.reviewedBy) }
|
|
: null,
|
|
createdAt: item.createdAt,
|
|
updatedAt: item.updatedAt,
|
|
};
|
|
}
|
|
|
|
function userBrief(user) {
|
|
if (!user) return null;
|
|
if (typeof user === 'object') {
|
|
return {
|
|
id: String(user._id),
|
|
firstName: user.firstName,
|
|
lastName: user.lastName,
|
|
email: user.email,
|
|
};
|
|
}
|
|
return { id: String(user) };
|
|
}
|
|
|
|
export function toCohortDto(cohort) {
|
|
if (!cohort) return null;
|
|
const patients = Array.isArray(cohort.patients) ? cohort.patients : [];
|
|
return {
|
|
id: String(cohort._id),
|
|
name: cohort.name,
|
|
startDate: toYmd(cohort.startDate),
|
|
weekday: cohort.startDate ? weekdayOf(toYmd(cohort.startDate)) : null,
|
|
slot: cohort.slot || '',
|
|
language: cohort.language || '',
|
|
scheduleId: cohort.scheduleId || '',
|
|
diseaseType: cohort.diseaseType || '',
|
|
status: cohort.status || 'active',
|
|
needsReassignment: Boolean(cohort.needsReassignment),
|
|
durationMinutes: cohort.durationMinutes || 60,
|
|
virtualPrt: userBrief(cohort.virtualPrt),
|
|
patients: patients.map((p) => (
|
|
p && typeof p === 'object'
|
|
? { id: String(p._id), name: readOnboardedPii(p).name, mobile: readOnboardedPii(p).mobile, whatsappOptOut: Boolean(p.whatsappOptOut) }
|
|
: { id: String(p) }
|
|
)),
|
|
patientCount: patients.length,
|
|
whatsapp: {
|
|
status: cohort.whatsappStatus || '',
|
|
error: cohort.whatsappError || '',
|
|
inviteUrl: cohort.whatsappInviteUrl || '',
|
|
members: (cohort.whatsappMembers || []).map((row) => ({
|
|
patientId: String(row.patient?._id || row.patient),
|
|
status: row.status || '',
|
|
error: row.error || '',
|
|
})),
|
|
},
|
|
createdAt: cohort.createdAt,
|
|
updatedAt: cohort.updatedAt,
|
|
};
|
|
}
|
|
|
|
export function toHolidayDto(holiday) {
|
|
if (!holiday) return null;
|
|
return {
|
|
id: String(holiday._id),
|
|
date: holiday.date,
|
|
name: holiday.name,
|
|
languages: holiday.languages || [],
|
|
createdAt: holiday.createdAt,
|
|
updatedAt: holiday.updatedAt,
|
|
};
|
|
}
|
|
|
|
export function toLeaveDto(leave) {
|
|
if (!leave) return null;
|
|
return {
|
|
id: String(leave._id),
|
|
user: userBrief(leave.user),
|
|
startDate: leave.startDate,
|
|
endDate: leave.endDate,
|
|
reason: leave.reason || '',
|
|
status: leave.status || 'pending',
|
|
reviewedAt: leave.reviewedAt || null,
|
|
reviewedBy: userBrief(leave.reviewedBy),
|
|
createdAt: leave.createdAt,
|
|
updatedAt: leave.updatedAt,
|
|
};
|
|
}
|
|
|
|
export function toCohortSessionDto(session) {
|
|
if (!session) return null;
|
|
const cohort = session.cohort && typeof session.cohort === 'object' ? session.cohort : null;
|
|
return {
|
|
id: String(session._id),
|
|
index: session.index,
|
|
date: session.date,
|
|
slot: session.slot || cohort?.slot || '',
|
|
status: session.status || 'scheduled',
|
|
cancelReason: session.cancelReason || '',
|
|
meetUrl: session.meetUrl || '',
|
|
htmlLink: session.htmlLink || '',
|
|
googleEventId: session.googleEventId || '',
|
|
reminderSentAt: session.reminderSentAt || null,
|
|
coverPrt: userBrief(session.coverPrt),
|
|
cohort: cohort
|
|
? {
|
|
id: String(cohort._id),
|
|
name: cohort.name,
|
|
slot: cohort.slot || '',
|
|
language: cohort.language || '',
|
|
diseaseType: cohort.diseaseType || '',
|
|
status: cohort.status || '',
|
|
virtualPrt: userBrief(cohort.virtualPrt),
|
|
}
|
|
: session.cohort
|
|
? { id: String(session.cohort) }
|
|
: null,
|
|
records: (session.records || []).map((record) => ({
|
|
patient: record.patient && typeof record.patient === 'object'
|
|
? { id: String(record.patient._id), name: readOnboardedPii(record.patient).name, mobile: readOnboardedPii(record.patient).mobile }
|
|
: { id: String(record.patient) },
|
|
attended: Boolean(record.attended),
|
|
pre: { bp: record.pre?.bp || '', spo2: record.pre?.spo2 ?? null, pulse: record.pre?.pulse ?? null },
|
|
post: { bp: record.post?.bp || '', spo2: record.post?.spo2 ?? null, pulse: record.post?.pulse ?? null },
|
|
assessment: {
|
|
fev1: record.assessment?.fev1 || '',
|
|
fvc: record.assessment?.fvc || '',
|
|
sixMwt: record.assessment?.sixMwt || '',
|
|
eq5d3l: record.assessment?.eq5d3l || '',
|
|
sgrq: record.assessment?.sgrq || '',
|
|
sitToStand: record.assessment?.sitToStand || '',
|
|
rpeRest: record.assessment?.rpeRest || '',
|
|
rpeActivity: record.assessment?.rpeActivity || '',
|
|
o2Regular: record.assessment?.o2Regular || '',
|
|
o2WithExercise: record.assessment?.o2WithExercise || '',
|
|
},
|
|
})),
|
|
createdAt: session.createdAt,
|
|
updatedAt: session.updatedAt,
|
|
};
|
|
}
|
|
|
|
export function toReassignmentDto(event) {
|
|
if (!event) return null;
|
|
return {
|
|
id: String(event._id),
|
|
reason: event.reason || '',
|
|
status: event.status || 'open',
|
|
cohort: event.cohort && typeof event.cohort === 'object'
|
|
? { id: String(event.cohort._id), name: event.cohort.name, slot: event.cohort.slot || '', language: event.cohort.language || '' }
|
|
: event.cohort
|
|
? { id: String(event.cohort) }
|
|
: null,
|
|
fromPrt: userBrief(event.fromPrt),
|
|
toPrt: userBrief(event.toPrt),
|
|
createdAt: event.createdAt,
|
|
updatedAt: event.updatedAt,
|
|
};
|
|
}
|