"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.listEmployees = listEmployees; exports.inviteEmployee = inviteEmployee; exports.updateEmployeeRole = updateEmployeeRole; exports.deactivateEmployee = deactivateEmployee; exports.reactivateEmployee = reactivateEmployee; exports.removeEmployee = removeEmployee; const crypto_1 = __importDefault(require("crypto")); const prisma_1 = require("../lib/prisma"); const notificationService_1 = require("./notificationService"); const notificationLocalizationService_1 = require("./notificationLocalizationService"); const INVITE_TOKEN_TTL_MINUTES = 60 * 24 * 7; function ensureDashboardBasePath(baseUrl) { try { const url = new URL(baseUrl); const pathname = url.pathname.replace(/\/$/, ''); if (!pathname.endsWith('/dashboard')) url.pathname = `${pathname}/dashboard`; return url.toString().replace(/\/$/, ''); } catch { const trimmed = baseUrl.replace(/\/$/, ''); return trimmed.endsWith('/dashboard') ? trimmed : `${trimmed}/dashboard`; } } function buildInviteEmail(resetUrl, companyName, firstName, role, locale) { const greetingName = firstName.trim() || 'there'; if (locale === 'fr') { return { subject: `Vous avez ete invite chez ${companyName}`, html: `

Bonjour ${greetingName},

Vous avez ete invite a rejoindre ${companyName} sur RentalDriveGo en tant que ${role.toLowerCase()}.

Definir votre mot de passe

Ce lien d'invitation expire dans 7 jours.

RentalDriveGo

`, text: `Bonjour ${greetingName},\n\nVous avez ete invite a rejoindre ${companyName} sur RentalDriveGo en tant que ${role.toLowerCase()}.\n\nDefinissez votre mot de passe ici : ${resetUrl}\n\nCe lien d'invitation expire dans 7 jours.\n\nRentalDriveGo`, }; } if (locale === 'ar') { return { subject: `تمت دعوتك إلى ${companyName}`, html: `

مرحباً ${greetingName}،

تمت دعوتك للانضمام إلى ${companyName} على RentalDriveGo بصفتك ${role.toLowerCase()}.

عيّن كلمة المرور

تنتهي صلاحية رابط الدعوة هذا خلال 7 أيام.

RentalDriveGo

`, text: `مرحباً ${greetingName}،\n\nتمت دعوتك للانضمام إلى ${companyName} على RentalDriveGo بصفتك ${role.toLowerCase()}.\n\nعيّن كلمة المرور هنا: ${resetUrl}\n\nتنتهي صلاحية رابط الدعوة هذا خلال 7 أيام.\n\nRentalDriveGo`, }; } return { subject: `You have been invited to ${companyName}`, html: `

Hi ${greetingName},

You were invited to join ${companyName} on RentalDriveGo as a ${role.toLowerCase()}.

Set your password

This invitation link expires in 7 days.

RentalDriveGo

`, text: `Hi ${greetingName},\n\nYou were invited to join ${companyName} on RentalDriveGo as a ${role.toLowerCase()}.\n\nSet your password here: ${resetUrl}\n\nThis invitation link expires in 7 days.\n\nRentalDriveGo`, }; } async function listEmployees(companyId) { const employees = await prisma_1.prisma.employee.findMany({ where: { companyId }, orderBy: [{ role: 'asc' }, { createdAt: 'asc' }], }); return employees.map((employee) => ({ ...employee, lastActiveAt: null, invitationStatus: employee.passwordHash ? 'accepted' : 'pending', })); } async function inviteEmployee(companyId, inviterId, payload) { if (payload.role === 'OWNER') { throw Object.assign(new Error('Cannot invite a member with the OWNER role'), { statusCode: 400, code: 'invalid_role' }); } const existing = await prisma_1.prisma.employee.findFirst({ where: { companyId, email: payload.email } }); if (existing) { throw Object.assign(new Error('An employee with this email already exists in your team'), { statusCode: 409, code: 'employee_already_exists' }); } const company = await prisma_1.prisma.company.findUniqueOrThrow({ where: { id: companyId }, include: { brand: { select: { defaultLocale: true, displayName: true } } }, }); const rawToken = crypto_1.default.randomBytes(32).toString('hex'); const expiresAt = new Date(Date.now() + INVITE_TOKEN_TTL_MINUTES * 60 * 1000); const locale = (0, notificationLocalizationService_1.coerceNotificationLocale)(company.brand?.defaultLocale); const employee = await prisma_1.prisma.employee.create({ data: { companyId, clerkUserId: `local_member_${crypto_1.default.randomUUID()}`, firstName: payload.firstName, lastName: payload.lastName, email: payload.email, role: payload.role, isActive: true, preferredLanguage: locale, passwordResetToken: rawToken, passwordResetExpiresAt: expiresAt, }, }); const dashboardUrl = ensureDashboardBasePath(process.env.DASHBOARD_URL ?? process.env.NEXT_PUBLIC_DASHBOARD_URL ?? 'http://localhost:3000/dashboard'); const resetUrl = `${dashboardUrl}/reset-password?token=${rawToken}`; const message = buildInviteEmail(resetUrl, company.brand?.displayName ?? company.name, payload.firstName, payload.role, locale); await (0, notificationService_1.sendTransactionalEmail)({ to: payload.email, subject: message.subject, html: message.html, text: message.text, }); return { employee: { ...employee, lastActiveAt: null, invitationStatus: 'pending', }, invitationId: employee.id, invitedBy: inviterId, }; } async function updateEmployeeRole(companyId, requesterId, requesterRole, employeeId, payload) { const target = await prisma_1.prisma.employee.findFirstOrThrow({ where: { id: employeeId, companyId } }); if (requesterRole !== 'OWNER') throw Object.assign(new Error('Only the account owner can change team member roles'), { statusCode: 403, code: 'forbidden' }); if (target.role === 'OWNER') throw Object.assign(new Error('Cannot change the role of the account owner'), { statusCode: 400 }); if (payload.role === 'OWNER') throw Object.assign(new Error('Cannot assign the OWNER role via this endpoint'), { statusCode: 400 }); if (target.id === requesterId) throw Object.assign(new Error('You cannot change your own role'), { statusCode: 400 }); return prisma_1.prisma.employee.update({ where: { id: employeeId }, data: { role: payload.role } }); } async function deactivateEmployee(companyId, requesterRole, employeeId) { if (requesterRole !== 'OWNER') throw Object.assign(new Error('Only the account owner can deactivate team members'), { statusCode: 403 }); const target = await prisma_1.prisma.employee.findFirstOrThrow({ where: { id: employeeId, companyId } }); if (target.role === 'OWNER') throw Object.assign(new Error('Cannot deactivate the account owner'), { statusCode: 400 }); return prisma_1.prisma.employee.update({ where: { id: employeeId }, data: { isActive: false } }); } async function reactivateEmployee(companyId, requesterRole, employeeId) { if (requesterRole !== 'OWNER') throw Object.assign(new Error('Only the account owner can reactivate team members'), { statusCode: 403 }); await prisma_1.prisma.employee.findFirstOrThrow({ where: { id: employeeId, companyId } }); return prisma_1.prisma.employee.update({ where: { id: employeeId }, data: { isActive: true } }); } async function removeEmployee(companyId, requesterRole, employeeId) { if (requesterRole !== 'OWNER') throw Object.assign(new Error('Only the account owner can remove team members'), { statusCode: 403 }); const target = await prisma_1.prisma.employee.findFirstOrThrow({ where: { id: employeeId, companyId } }); if (target.role === 'OWNER') throw Object.assign(new Error('Cannot remove the account owner'), { statusCode: 400 }); await prisma_1.prisma.employee.delete({ where: { id: employeeId } }); return { success: true }; } //# sourceMappingURL=teamService.js.map