Skip to content
Open
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
Empty file modified .husky/commit-msg
100755 → 100644
Empty file.
Empty file modified .husky/pre-commit
100755 → 100644
Empty file.
Empty file modified .husky/pre-push
100755 → 100644
Empty file.
13,551 changes: 13,551 additions & 0 deletions package-lock.json

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,35 @@ export class RemoteCreateForageUseCase implements CreateForageUseCase {
execute: CreateForageUseCase['execute'] = async ({ propertyId, forage }) => {
const url = this.url.replace(':propertyId', String(propertyId))

const body = {
...forage,

cultivation:
typeof forage.cultivation === 'object'
? forage.cultivation.label
: forage.cultivation,

area: forage.area ? Number(forage.area) : undefined,

averageCost: forage.averageCost
? Number(
String(forage.averageCost)
.replace('R$', '') // remove símbolo
.replace(/\./g, '') // remove separador de milhar (se houver)
.replace(',', '.') // troca vírgula por ponto
.trim()
)
: undefined,


usefulLife: forage.usefulLife ? Number(forage.usefulLife) : undefined,
}
console.log('Payload enviado para API:', body)

const { statusCode } = await this.httpClient.request({
url,
method: 'post',
body: forage,
body,
})

if (statusCode === HttpStatusCode.created) return
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,17 @@ export class RemoteGetForageUseCase implements GetForageUseCase {
const url = this.url.replace(':propertyId', String(propertyId))

const { statusCode, body } = await this.httpClient.request({
url: `${url}/${forageId}`,
url: `${url}/${forageId}/details`,
method: 'get',
})

if (statusCode === HttpStatusCode.ok && !!body) {
return {
type: body.type, // Ensure this property exists in the API response
area: body.area,
averageCost: body.averageCost,
cultivation: body.cultivation,
formation: new Date(body.formation),
formation: body.formation ? new Date(body.formation) : null, // <--- RETORNA Date OU null
cultivation: body.cultivation || '', // <--- RETORNA string OU string vazia
observation: body.observation,
ownershipType: body.ownershipType,
growthCycle: body.growthCycle,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,22 @@
import { format } from 'date-fns'
import { format } from 'date-fns';

import { type HttpClient, HttpStatusCode } from '@/core/data/protocols/http'
import { type HttpClient, HttpStatusCode } from '@/core/data/protocols/http';
import {
UnexpectedError,
NotFoundError,
ForbiddenError,
} from '@/core/domain/errors'
} from '@/core/domain/errors';

import type {
// CORREÇÃO APLICADA AQUI: Importação de ForageModel, ForageApiResponse e as enums
import {
ForageModel,
ForageApiResponse,
ForageGrowthCycle,
ForageModel,
ForageOwnershipType,
} from '../../domain/models/forages-model'
import type { GetForagesUseCase } from '../../domain/use-cases'
import type { ListApiResponse, MapApiProperties } from '@/core/domain/types'
} from '../../domain/models/forages-model';

import type { GetForagesUseCase } from '../../domain/use-cases';
import type { ListApiResponse, MapApiProperties } from '@/core/domain/types';

export class RemoteGetForagesUseCase implements GetForagesUseCase {
constructor(
Expand Down Expand Up @@ -42,56 +44,70 @@ export class RemoteGetForagesUseCase implements GetForagesUseCase {
ownershipType: 'ownershipType',
growthCycle: 'growthCycle',
usefulLife: 'usefulLife',
}
};

const url = this.url.replace(':propertyId', String(propertyId))
const url = this.url.replace(':propertyId', String(propertyId));

const { statusCode, body } = await this.httpClient.request({
url: `${url}/search`,
method: 'post',
url: `${url}`,
method: 'get',
filters,
pagination,
sort,
mapApiProperties,
})
});

if (statusCode === HttpStatusCode.ok && !!body) {
if (statusCode === HttpStatusCode.ok && body) {
const ownershipType: Record<ForageOwnershipType, string> = {
OWNED_LAND: 'Terra Própria',
LEASED_LAND: 'Terra Arrendada',
}
};

const growthCycle: Record<ForageGrowthCycle, string> = {
ANNUAL: 'Anual',
PERENNIAL: 'Perene',
}
};

const rawResources = Array.isArray(body)
? body
: Array.isArray(body.content)
? body.content
: [];

const resources = rawResources.map((item) => ({
id: item.id,
area: item.area,
averageCost: item.averageCost ?? 'Não informado',
cultivation: item.cultivation ?? 'Não informado',
formation: item.formation ? format(new Date(item.formation), 'dd/MM/yyyy') : 'Não informado',
observation: item.observation ?? 'Sem observação',
ownershipType: ownershipType[item.ownershipType as ForageOwnershipType] ?? 'Não informado',
growthCycle: growthCycle[item.growthCycle as ForageGrowthCycle] ?? 'Não informado',

usefulLife: item.usefulLife ?? 'Não informado',
}));

const totalPages =
body && body.pageable && body.pageable.pageSize && body.numberOfElements
? Math.ceil(body.numberOfElements / body.pageable.pageSize)
: 1; // Retorna 1 se a API não fornecer dados de paginação.

return {
resources: body.content.map((item) => ({
id: item.id,
area: item.area,
averageCost: item.averageCost,
cultivation: item.cultivation,
formation: format(new Date(item.formation), 'dd/MM/yyyy'),
observation: item.observation,
ownershipType: ownershipType[item.ownershipType],
growthCycle: growthCycle[item.growthCycle],
usefulLife: item.usefulLife,
})),
totalPages: Math.ceil(body.numberOfElements / body.pageable.pageSize),
}
resources,
totalPages,
};
}

if (statusCode === HttpStatusCode.notFound) {
throw new NotFoundError('Propriedades')
throw new NotFoundError('Propriedades');
}

if (statusCode === HttpStatusCode.forbidden) {
throw new ForbiddenError(
'Você não tem permissão para buscar propriedades'
)
);
}

throw new UnexpectedError()
}
}
throw new UnexpectedError();
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,81 @@ import {

import type { UpdateForageUseCase } from '../../domain/use-cases'

// Tipos usados para sanitização
type SelectOption = {
label: string
value: number
}

type ForagePayload = {
id: number | string
cultivation: SelectOption
averageCost: string | number | undefined | null
formation: string | undefined | null // Adicionamos 'formation' aqui
[key: string]: any
}

// Função auxiliar para garantir o formato 'MM' ou 'DD' (com zero à esquerda se necessário)
const padTo2Digits = (num: number) => num.toString().padStart(2, '0')

export class RemoteUpdateForageUseCase implements UpdateForageUseCase {
constructor(
private readonly url: string,
private readonly httpClient: HttpClient
private readonly httpClient: HttpClient,
) {}

execute: UpdateForageUseCase['execute'] = async ({
propertyId,
forage: { id, ...forage },
forage,
}) => {
const { id, cultivation, averageCost, formation, ...restOfForage } = forage as ForagePayload

const sanitizedAverageCost = averageCost
? Number(
String(averageCost)
.replace('R$', '')
.replace(/\./g, '')
.replace(',', '.')
.trim()
)
: undefined

let sanitizedFormationDate: string | undefined

if (formation) {
try {
const date = new Date(formation)

// Verifica se a data é válida antes de tentar formatar
if (!isNaN(date.getTime())) {
const year = date.getFullYear()
// O método getMonth() retorna 0 para Janeiro, 11 para Dezembro.
const month = padTo2Digits(date.getMonth() + 1)
const day = padTo2Digits(date.getDate()+1)

// Formata como YYYY-MM-DD
sanitizedFormationDate = `${year}-${month}-${day}`
}
} catch (error) {
// Em caso de falha na criação da data, envia undefined ou a string original para debug
console.error('Erro ao parsear a data de formação:', formation, error)
sanitizedFormationDate = undefined
}
}

const bodyToSend = {
...restOfForage,
cultivation: cultivation.label,
averageCost: sanitizedAverageCost,
formation: sanitizedFormationDate,
}

const url = this.url.replace(':propertyId', String(propertyId))

const { statusCode } = await this.httpClient.request({
url: `${url}/${id}`,
method: 'patch',
body: forage,
body: bodyToSend,
})

if (statusCode === HttpStatusCode.noContent) return
Expand All @@ -31,7 +90,7 @@ export class RemoteUpdateForageUseCase implements UpdateForageUseCase {

if (statusCode === HttpStatusCode.forbidden) {
throw new ForbiddenError(
'Você não tem permissão para editar uma forrageira'
'Você não tem permissão para editar uma forrageira',
)
}

Expand Down
6 changes: 4 additions & 2 deletions src/app/modules/forages/domain/models/forages-model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,19 @@ export type ForageOwnershipType = 'OWNED_LAND' | 'LEASED_LAND'
export type ForageGrowthCycle = 'ANNUAL' | 'PERENNIAL'

export type ForageDetailsModel = {
cultivation: Option
type: any
cultivation: Option | ''
area: string
averageCost: string
usefulLife: string
formation: Date
formation: Date | null
ownershipType: ForageOwnershipType
growthCycle: ForageGrowthCycle
observation?: string
}

export type ForageDetailsApiResponse = {
type: any
cultivation: Option
area: string
averageCost: string
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { makeApiHttpClient } from '@/core/main/factories/http'
import { makeApiHttpClient } from '@/core/main/factories/http/api-http-client-factory'

import { RemoteCreateForageUseCase } from '../../../data/use-cases'

Expand All @@ -7,6 +7,6 @@ import type { CreateForageUseCase } from '../../../domain/use-cases'
export function makeRemoteCreateForageUseCase(): CreateForageUseCase {
return new RemoteCreateForageUseCase(
'properties/:propertyId/forages',
makeApiHttpClient()
makeApiHttpClient({ method:'post' })
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@ import type { DeleteForageUseCase } from '../../../domain/use-cases'
export function makeRemoteDeleteForageUseCase(): DeleteForageUseCase {
return new RemoteDeleteForageUseCase(
'properties/:propertyId/forages',
makeApiHttpClient()
makeApiHttpClient({method:'delete'})
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import type { GetForageUseCase } from '../../../domain/use-cases'
export function makeRemoteGetForageUseCase(): GetForageUseCase {
return new RemoteGetForageUseCase(
'properties/:propertyId/forages',
makeApiHttpClient<ForageDetailsModel, ForageDetailsApiResponse>()
makeApiHttpClient<ForageDetailsModel, ForageDetailsApiResponse>({
method:'get'
})
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,6 @@ export function makeRemoteGetForagesUseCase(): GetForagesUseCase {
ForageModel,
ForageApiResponse,
ListApiResponse<ForageApiResponse[]>
>()
>({method:'get'})
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@ import type { UpdateForageUseCase } from '../../../domain/use-cases'
export function makeRemoteUpdateForageUseCase(): UpdateForageUseCase {
return new RemoteUpdateForageUseCase(
'properties/:propertyId/forages',
makeApiHttpClient()
makeApiHttpClient({ method:'patch' })
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,12 @@ export const getForagesHandler = httpWithMiddleware<
if (filters) forages = filterData<ForageApiResponse>(filters, forages)
if (sort) forages = sortData<ForageApiResponse>(sort, forages)
const numberOfElements = forages.length
forages = paginateData<ForageApiResponse>({ page, perPage: rows }, forages)

if (page)
forages = paginateData<ForageApiResponse>(
{ page, perPage: rows },
forages
)

return HttpResponse.json(
{
Expand Down
Loading