Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 23 additions & 58 deletions src/modules/appointments/schemas/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import { AppointmentType } from '@prisma/client';
import { AppointmentStatus, AppointmentType } from '@prisma/client';
import z from 'zod';

import { AppError } from '@app/errors/app-client';

export const appointmentParamId = z.object({
patientId: z.string().uuid(),
});
Expand All @@ -12,58 +10,25 @@ export const appointmentParamsSchema = z.object({
appointmentId: z.coerce.number().int(),
});

export const appointmentQuerySchema = z
.object({
name: z.string().optional(),
page: z.coerce.number().default(1),
items_per_page: z.coerce.number().max(500).default(10),
appointment_type: z
.union([z.nativeEnum(AppointmentType), z.literal('')])
.transform(val => (val === '' ? undefined : val))
.optional(),
start_date: z.preprocess(
val => {
if (typeof val === 'string' && val.trim() === '') return undefined;

if (typeof val === 'string' && !/^\d{4}-\d{2}-\d{2}$/.test(val)) {
throw new AppError(
'Data de início inválida. Use o formato YYYY-MM-DD',
);
}
return typeof val === 'string' ? new Date(val) : val;
},
z
.date({
invalid_type_error:
'Data de início inválida. Use o formato YYYY-MM-DD',
})
.optional(),
),
end_date: z.preprocess(
val => {
if (typeof val === 'string' && val.trim() === '') return undefined;

if (typeof val === 'string' && !/^\d{4}-\d{2}-\d{2}$/.test(val)) {
throw new AppError('Data de fim inválida. Use o formato YYYY-MM-DD');
}
return typeof val === 'string' ? new Date(val) : val;
},
z
.date({
invalid_type_error: 'Data de fim inválida. Use o formato YYYY-MM-DD',
})
.optional(),
),
})
.refine(
data => {
if (data.start_date && data.end_date) {
return data.start_date <= data.end_date;
}
return true;
},
{
message: 'A data de início não pode ser maior que a data de fim',
path: ['start_date'],
},
);
export const appointmentQuerySchema = z.object({
name: z.string().optional(),
appointment_type: z
.union([z.nativeEnum(AppointmentType), z.literal('')])
.transform(val => (val === '' ? undefined : val))
.optional(),
status: z
.union([z.nativeEnum(AppointmentStatus), z.literal('')])
.transform(val => (val === '' ? undefined : val))
.optional(),
scheduled_date: z.preprocess(val => {
if (typeof val === 'string' && /^\d{4}-\d{2}-\d{2}$/.test(val)) {
return new Date(`${val}T00:00:00.000Z`);
}
if (val === '' || val === null || val === undefined) {
return undefined;
}
throw new Error('Data inválida. Use o formato YYYY-MM-DD.');
}, z.date().optional()),
page: z.coerce.number().default(1),
items_per_page: z.coerce.number().max(500).default(10),
});
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { AppointmentType } from '@prisma/client';
import { AppointmentStatus, AppointmentType } from '@prisma/client';

import { IAppointment, IPaginateRequest } from '@shared/entities';
import { AppointmentRepository } from '@shared/repositories/implementations/appointment-repository';
import { validatePaginationParams } from '@shared/utils';
import { FindAndCountAll } from '@shared/utils/format-paginate';

type IGetAllAppointmentsParams = IPaginateRequest & {
end_date?: Date;
start_date?: Date;
scheduled_date?: Date;
appointment_type?: AppointmentType;
status?: AppointmentStatus;
};

export class GetAllAppointmentsService {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,15 @@ export class GetAppointmentService {
this.patientRepository = patientRepository;
}

async execute(queryId: number, patientId: string) {
async execute(appointmentId: number, patientId: string) {
const patient = await this.patientRepository.findById(patientId);

if (!patient) {
throw new AppError(PATIENT_NOT_FOUND, 404);
}

const appointment = await this.appointmentRepository.findById(queryId);
const appointment =
await this.appointmentRepository.findById(appointmentId);

if (patientId !== appointment?.patient_id) {
throw new AppError(APPOINTMENT_NOT_FOUND, 404);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { AppointmentType } from '@prisma/client';
import { AppointmentStatus, AppointmentType } from '@prisma/client';

import { AppError } from '@app/errors/app-client';
import { PATIENT_NOT_FOUND } from '@shared/constants/messages';
Expand All @@ -12,9 +12,9 @@ import { FindAndCountAll } from '@shared/utils/format-paginate';

type IGetAppointmentsByPatientParams = Omit<IPaginateRequest, 'name'> & {
patient_id: string;
end_date?: Date;
start_date?: Date;
scheduled_date?: Date;
appointment_type?: AppointmentType;
status?: AppointmentStatus;
};

export class GetAppointmentsByPatientService {
Expand Down
10 changes: 5 additions & 5 deletions src/shared/entities/entities.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { AppointmentType, Status } from '@prisma/client';
import { AppointmentStatus, AppointmentType, Status } from '@prisma/client';

export interface FindEntitiesAndCountParams {
name?: string;
Expand All @@ -14,16 +14,16 @@ export interface FindEntitiesAndCountResult<T> {
export interface FindAppointmentsAndCountParams
extends Omit<FindEntitiesAndCountParams, 'name'> {
patient_id: string;
scheduled_date?: Date;
appointment_type?: AppointmentType;
start_date?: Date;
end_date?: Date;
status?: AppointmentStatus;
}

export interface FindAllAppointmentsAndCountParams
extends FindEntitiesAndCountParams {
scheduled_date?: Date;
appointment_type?: AppointmentType;
start_date?: Date;
end_date?: Date;
status?: AppointmentStatus;
}

export interface FindAllPatientsAndCountParams
Expand Down
27 changes: 17 additions & 10 deletions src/shared/repositories/implementations/appointment-repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,18 @@ export class AppointmentRepository implements IAppointmentRepository {
async findAllAppointments(
params: FindAllAppointmentsAndCountParams,
): Promise<FindEntitiesAndCountResult<IAppointment>> {
const { name, skip, take, appointment_type, start_date, end_date } = params;
const { name, skip, take, appointment_type, scheduled_date, status } =
params;

const where: Prisma.AppointmentWhereInput = {
...(appointment_type && { appointment_type }),
scheduled_date: {
...(start_date && { gte: start_date }),
...(end_date && { lte: end_date }),
},
...(scheduled_date && {
scheduled_date: {
gte: scheduled_date,
lt: new Date(scheduled_date.getTime() + 24 * 60 * 60 * 1000), // Adiciona 1 dia
},
}),
...(status && { status }),
patient: {
...(name && { name: { contains: name } }),
},
Expand Down Expand Up @@ -51,16 +55,19 @@ export class AppointmentRepository implements IAppointmentRepository {
async findAndCountAll(
params: FindAppointmentsAndCountParams,
): Promise<FindEntitiesAndCountResult<IAppointment>> {
const { patient_id, skip, take, appointment_type, start_date, end_date } =
const { patient_id, skip, take, appointment_type, scheduled_date, status } =
params;

const where: Prisma.AppointmentWhereInput = {
patient_id: patient_id,
...(appointment_type && { appointment_type }),
scheduled_date: {
...(start_date && { gte: start_date }),
...(end_date && { lte: end_date }),
},
...(scheduled_date && {
scheduled_date: {
gte: scheduled_date,
lt: new Date(scheduled_date.getTime() + 24 * 60 * 60 * 1000), // Adiciona 1 dia
},
}),
...(status && { status }),
};

const count = await prisma.appointment.count({
Expand Down
Loading