doctors.busyStatus de Ocupação do Médico
Evento WebSocket para notificar em tempo real quando o status de ocupação de um médico muda. Este evento é emitido automaticamente pelo servidor quando um agendamento muda de status, propagando a notificação para todos os clientes conectados da mesma conta. O servidor faz broadcast do evento para todos os clientes da mesma accountId, permitindo que todos atualizem o status do médico simultaneamente. Este evento não é iniciado pelo frontend; é um evento unidirecional (servidor → clientes) usado exclusivamente para sincronização de UI em tempo real. O evento é emitido em dois contextos: quando um agendamento muda para "Em atendimento" (médico fica ocupado - isBusy: true) ou quando um agendamento é finalizado (médico fica livre - isBusy: false).
Access Token
Para realizar requisições GET, POST, PUT, DELETE e PATCH nos endpoints da API você precisa de uma chave de autorização. Chamamos essa chave de accessToken.
Para ter acesso ao accessToken, é necessário que o usuário master da licença efetue a liberação deste pela interface do ImageMais Clinic. O accessToken tem validade de 1 hora.
Headers
| Nome | Tipo | Obrig. | Descrição |
|---|---|---|---|
Authorization | string | Sim | Token de autenticação no formato Bearer {accessToken}. O token deve ser enviado durante o handshake de conexão WebSocket. |
AuthorizationOBRIGATÓRIOParâmetros
Este método não possui parâmetros.
Fluxo passo a passo: doctors.busy
Listener emite evento quando status de agendamento muda
Quando um agendamento muda de status, os listeners emitem o evento 'doctors.busy' com o novo status de ocupação:
// in-service-appointment.ts (médico fica ocupado)
@OnEvent('appointments.status.change')
async handleAppointmentsStatusChange(event: AppointmentStatusChangeEvent) {
if (event.action !== AppointmentStatusEnum.EM_ATENDIMENTO) return;
// ... atualiza médico no banco (isBusy: true) ...
// Emite evento de ocupado
this.eventEmitter.emit('doctors.busy', {
doctorId: event.doctorId ?? event.appointment.doctorId,
isBusy: true, // Médico fica ocupado
payload: event.payload,
});
}
// finish-appointment.ts (médico fica livre)
@OnEvent('appointments.status.change')
async handleAppointmentsStatusChange(event: AppointmentStatusChangeEvent) {
if (event.action !== AppointmentStatusEnum.FINALIZADO) return;
// ... atualiza médico no banco (isBusy: false) ...
// Emite evento de livre
this.eventEmitter.emit('doctors.busy', {
doctorId: event.doctorId ?? event.appointment.doctorId,
isBusy: false, // Médico fica livre
payload: event.payload,
});
}Listener propaga evento via WebSocket
O doctors.listener.ts escuta o evento interno e propaga via WebSocket para todos os clientes da conta:
// doctors.listener.ts
@OnEvent('doctors.busy')
async handleDoctorsBusy(data: {
doctorId: number;
isBusy: boolean;
payload: PayloadTokenDto;
}) {
try {
// Propaga via WebSocket para todos os clientes da conta
await this.gateway.notifyOnEvent(
'doctors.busy',
{
doctorId: data.doctorId,
isBusy: data.isBusy, // true (ocupado) ou false (livre)
},
data.payload,
);
this.logger.debug(
`medico ${data.doctorId} esta ${data.isBusy ? 'ocupado' : 'livre'}`,
);
} catch (error) {
this.logger.error(`Erro ao propagar evento doctors.busy:`, error);
}
}Gateway faz broadcast para todos da conta
O método `notifyOnEvent` envia o evento 'doctors.busy' para todos os sockets da mesma accountId:
// accounts.gateways.ts
async notifyOnEvent(
event: string,
data: any,
payload: PayloadTokenDto,
): Promise<any> {
if (this._events.includes(event)) {
// Envia para todos os clientes da mesma conta
this.server
.to(`${this.room}${payload.accountId}`)
.emit(event, data);
}
}
// this.room = 'orders.account.'
// Evento: 'doctors.busy' (está na lista de eventos permitidos - linha 104)
// Dados: objeto com doctorId (number) e isBusy (boolean)
// Todos os clientes conectados da mesma accountId recebem o eventoCliente recebe evento e atualiza status do médico
Os componentes Doctors.tsx e List.tsx escutam o evento e atualizam o status de ocupação do médico na lista:
// Doctors.tsx
socket.on(
'doctors.busy',
(data: { doctorId: number; isBusy: boolean }) => {
// Atualiza status do médico na lista
setAvailableDoctorsState((prev) =>
prev.map((doctor) =>
Number(doctor.id) === data.doctorId
? { ...doctor, isBusy: data.isBusy } // Atualiza apenas isBusy
: doctor
)
);
}
);
// List.tsx (mesmo comportamento)
socket.on(
'doctors.busy',
(data: { doctorId: number; isBusy: boolean }) => {
setListAvailableDoctors((prev) =>
prev.map((doctor) =>
Number(doctor.id) === data.doctorId
? { ...doctor, isBusy: data.isBusy }
: doctor
)
);
}
);
// Cleanup ao desmontar
return () => {
socket.off('doctors.busy');
};Request URL
ws://api-dev.imagemais.com{
"message": "Este evento é emitido automaticamente pelo servidor (não requer request body)"
}{
"message": "Este evento é emitido automaticamente pelo servidor (não requer request body)"
}Respostas
{
"doctorId": 1,
"isBusy": true
...{
"doctorId": 1,
"isBusy": true
}