feat(professionals): send FCM push notifications on status changes

Same events that trigger email (approve, deny, deactivate, setPending, upsert)
now also call tryPush() to send a silent FCM push to the professional's device.
NotificationsModule added to ProfessionalsModule imports.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Lizandro Guarnizo
2026-06-30 08:57:47 -05:00
co-authored by Claude Sonnet 4.6
parent 1f3efb50da
commit 749a1e860d
2 changed files with 23 additions and 2 deletions
@@ -2,9 +2,10 @@ import { Module } from '@nestjs/common';
import { ProfessionalsService } from './professionals.service';
import { ProfessionalsController } from './professionals.controller';
import { AuthModule } from '../auth/auth.module';
import { NotificationsModule } from '../notifications/notifications.module';
@Module({
imports: [AuthModule],
imports: [AuthModule, NotificationsModule],
providers: [ProfessionalsService],
controllers: [ProfessionalsController],
exports: [ProfessionalsService],
@@ -1,10 +1,24 @@
import { Injectable, NotFoundException, BadRequestException, ForbiddenException } from '@nestjs/common';
import { PrismaService } from '../prisma/prisma.service';
import { MailService } from '../mail/mail.service';
import { NotificationsService } from '../notifications/notifications.service';
@Injectable()
export class ProfessionalsService {
constructor(private prisma: PrismaService, private mail: MailService) {}
constructor(
private prisma: PrismaService,
private mail: MailService,
private notifications: NotificationsService,
) {}
private async tryPush(userId: string, title: string, body: string) {
try {
const u = await this.prisma.users.findUnique({
where: { id: userId }, select: { fcm_token: true },
});
if (u?.fcm_token) await this.notifications.send(u.fcm_token, title, body);
} catch (_) {}
}
async findAllActive(page = 1, limit = 20, city?: string) {
const skip = (page - 1) * limit;
@@ -76,6 +90,7 @@ export class ProfessionalsService {
const prof = await this.prisma.professionals.create({ data: { user_id: userId, is_active: false, ...data } });
const u = await this.prisma.users.findUnique({ where: { id: userId }, select: { name: true, email: true } });
if (u?.email) this.mail.sendProfessionalSubmitted(u.name || 'Usuario', u.email, data.profession || '').catch(() => {});
this.tryPush(userId, 'Solicitud recibida', 'Hemos recibido tu solicitud profesional. Te avisaremos cuando sea revisada.');
return prof;
}
@@ -87,6 +102,7 @@ export class ProfessionalsService {
this.prisma.users.update({ where: { id: userId }, data: { pro_state: 1 } }),
]);
if (user.email) this.mail.sendProfessionalSubmitted(user.name || 'Usuario', user.email, data.profession || '').catch(() => {});
this.tryPush(userId, 'Solicitud recibida', 'Hemos recibido tu solicitud profesional. Te avisaremos cuando sea revisada.');
return this.prisma.professionals.findUnique({ where: { user_id: userId } });
}
@@ -165,6 +181,7 @@ export class ProfessionalsService {
]);
const u = await this.prisma.users.findUnique({ where: { id: prof.user_id }, select: { name: true, email: true } });
if (u?.email) this.mail.sendStatusChanged(u.name || 'Profesional', u.email, 'approved').catch(() => {});
this.tryPush(prof.user_id, '¡Solicitud aprobada! 🎉', 'Tu perfil profesional ha sido aprobado en ProsApp.');
return { message: 'Profesional aprobado' };
}
@@ -178,6 +195,7 @@ export class ProfessionalsService {
]);
const u = await this.prisma.users.findUnique({ where: { id: prof.user_id }, select: { name: true, email: true } });
if (u?.email) this.mail.sendStatusChanged(u.name || 'Profesional', u.email, 'rejected').catch(() => {});
this.tryPush(prof.user_id, 'Actualización de tu solicitud', 'Tu solicitud profesional fue rechazada. Puedes volver a intentarlo.');
return { message: 'Solicitud rechazada' };
}
@@ -196,6 +214,7 @@ export class ProfessionalsService {
]);
const u = await this.prisma.users.findUnique({ where: { id: prof.user_id }, select: { name: true, email: true } });
if (u?.email) this.mail.sendStatusChanged(u.name || 'Profesional', u.email, 'deactivated').catch(() => {});
this.tryPush(prof.user_id, 'Cuenta desactivada', 'Tu cuenta profesional ha sido desactivada.');
return { message: 'Profesional desactivado' };
}
@@ -208,6 +227,7 @@ export class ProfessionalsService {
]);
const u = await this.prisma.users.findUnique({ where: { id: prof.user_id }, select: { name: true, email: true } });
if (u?.email) this.mail.sendStatusChanged(u.name || 'Profesional', u.email, 'pending').catch(() => {});
this.tryPush(prof.user_id, 'Solicitud en revisión', 'Tu solicitud está siendo revisada por el equipo de ProsApp.');
return { message: 'Profesional puesto en revisión' };
}