diff --git a/src/app/modules/general-cultivations/data/use-cases/general-cultivation-pests-use-cases/remote-create-general-cultivation-pest-use-case.ts b/src/app/modules/general-cultivations/data/use-cases/general-cultivation-pests-use-cases/remote-create-general-cultivation-pest-use-case.ts index 8963f6fa..ca2a9b99 100644 --- a/src/app/modules/general-cultivations/data/use-cases/general-cultivation-pests-use-cases/remote-create-general-cultivation-pest-use-case.ts +++ b/src/app/modules/general-cultivations/data/use-cases/general-cultivation-pests-use-cases/remote-create-general-cultivation-pest-use-case.ts @@ -30,7 +30,7 @@ export class RemoteCreateGeneralCultivationPestUseCase if (statusCode === HttpStatusCode.forbidden) { throw new ForbiddenError( - 'Você não tem permissão para criar uma praga geral de cultivo.' + 'Você não tem permissão para criar uma praga de cultivo geral.' ) } diff --git a/src/app/modules/general-cultivations/data/use-cases/general-cultivation-pests-use-cases/remote-delete-general-cultivation-pest-use-case.ts b/src/app/modules/general-cultivations/data/use-cases/general-cultivation-pests-use-cases/remote-delete-general-cultivation-pest-use-case.ts index 1738dbba..d12ac88f 100644 --- a/src/app/modules/general-cultivations/data/use-cases/general-cultivation-pests-use-cases/remote-delete-general-cultivation-pest-use-case.ts +++ b/src/app/modules/general-cultivations/data/use-cases/general-cultivation-pests-use-cases/remote-delete-general-cultivation-pest-use-case.ts @@ -29,7 +29,7 @@ export class RemoteDeleteGeneralCultivationPestUseCase if (statusCode === HttpStatusCode.forbidden) { throw new ForbiddenError( - 'Você não tem permissão para excluir uma praga geral de cultivo.' + 'Você não tem permissão para excluir uma praga de cultivo geral.' ) } diff --git a/src/app/modules/general-cultivations/data/use-cases/general-cultivation-pests-use-cases/remote-get-general-cultivation-pest-use-case.ts b/src/app/modules/general-cultivations/data/use-cases/general-cultivation-pests-use-cases/remote-get-general-cultivation-pest-use-case.ts index 1dbdabd4..ceb91f90 100644 --- a/src/app/modules/general-cultivations/data/use-cases/general-cultivation-pests-use-cases/remote-get-general-cultivation-pest-use-case.ts +++ b/src/app/modules/general-cultivations/data/use-cases/general-cultivation-pests-use-cases/remote-get-general-cultivation-pest-use-case.ts @@ -39,7 +39,7 @@ export class RemoteGetGeneralCultivationPestUseCase if (statusCode === HttpStatusCode.forbidden) { throw new ForbiddenError( - 'Você não tem permissão para buscar uma praga geral de cultivo.' + 'Você não tem permissão para buscar uma praga de cultivo geral.' ) } diff --git a/src/app/modules/general-cultivations/data/use-cases/general-cultivation-pests-use-cases/remote-get-general-cultivation-pests-use-case.ts b/src/app/modules/general-cultivations/data/use-cases/general-cultivation-pests-use-cases/remote-get-general-cultivation-pests-use-case.ts index f0c4eb42..e77aa148 100644 --- a/src/app/modules/general-cultivations/data/use-cases/general-cultivation-pests-use-cases/remote-get-general-cultivation-pests-use-case.ts +++ b/src/app/modules/general-cultivations/data/use-cases/general-cultivation-pests-use-cases/remote-get-general-cultivation-pests-use-case.ts @@ -64,7 +64,7 @@ export class RemoteGetGeneralCultivationPestsUseCase if (statusCode === HttpStatusCode.forbidden) { throw new ForbiddenError( - 'Você não tem permissão para buscar as pragas gerais de cultivo.' + 'Você não tem permissão para buscar as pragas de cultivo geral.' ) } diff --git a/src/app/modules/general-cultivations/data/use-cases/general-cultivation-pests-use-cases/remote-update-general-cultivation-pest-use-case.ts b/src/app/modules/general-cultivations/data/use-cases/general-cultivation-pests-use-cases/remote-update-general-cultivation-pest-use-case.ts index 251bba31..a6e611d4 100644 --- a/src/app/modules/general-cultivations/data/use-cases/general-cultivation-pests-use-cases/remote-update-general-cultivation-pest-use-case.ts +++ b/src/app/modules/general-cultivations/data/use-cases/general-cultivation-pests-use-cases/remote-update-general-cultivation-pest-use-case.ts @@ -30,7 +30,7 @@ export class RemoteUpdateGeneralCultivationPestUseCase if (statusCode === HttpStatusCode.forbidden) { throw new ForbiddenError( - 'Você não tem permissão para editar uma praga geral de cultivo.' + 'Você não tem permissão para editar uma praga de cultivo geral.' ) } diff --git a/src/app/modules/general-cultivations/domain/models/general-cultivation-pests-model.ts b/src/app/modules/general-cultivations/domain/models/general-cultivation-pests-model.ts index 59e03dad..cdee8c4e 100644 --- a/src/app/modules/general-cultivations/domain/models/general-cultivation-pests-model.ts +++ b/src/app/modules/general-cultivations/domain/models/general-cultivation-pests-model.ts @@ -12,7 +12,6 @@ export type GeneralCultivationPestModel = WithId<{ name: string }> -// todo: refactor to be consistent with Api response export type GeneralCultivationPestApiResponse = WithId<{ name: string }> diff --git a/src/app/modules/general-cultivations/mocks/handlers/general-cultivation-pests-handlers/get-general-cultivation-pest-handler.ts b/src/app/modules/general-cultivations/mocks/handlers/general-cultivation-pests-handlers/get-general-cultivation-pest-handler.ts index 751aacaf..94dec676 100644 --- a/src/app/modules/general-cultivations/mocks/handlers/general-cultivation-pests-handlers/get-general-cultivation-pest-handler.ts +++ b/src/app/modules/general-cultivations/mocks/handlers/general-cultivation-pests-handlers/get-general-cultivation-pest-handler.ts @@ -24,7 +24,8 @@ export const getGeneralCultivationPestHandler = httpWithMiddleware< } const generalCultivationPestsFound = generalCultivationPestsData.find( - (generalCultivation) => generalCultivation.id === Number(params.id) + (generalCultivationPest) => + generalCultivationPest.id === Number(params.id) ) if (!generalCultivationPestsFound) { diff --git a/src/app/modules/general-cultivations/mocks/handlers/general-cultivation-pests-handlers/get-general-cultivation-pests-handler.ts b/src/app/modules/general-cultivations/mocks/handlers/general-cultivation-pests-handlers/get-general-cultivation-pests-handler.ts index 208230b4..6709d266 100644 --- a/src/app/modules/general-cultivations/mocks/handlers/general-cultivation-pests-handlers/get-general-cultivation-pests-handler.ts +++ b/src/app/modules/general-cultivations/mocks/handlers/general-cultivation-pests-handlers/get-general-cultivation-pests-handler.ts @@ -37,10 +37,7 @@ export const getGeneralCultivationPestsHandler = httpWithMiddleware< ) } - let generalCultivationPests = generalCultivationPestsData.map((pest) => ({ - id: pest.id, - name: pest.name, - })) + let generalCultivationPests = generalCultivationPestsData if (filters) generalCultivationPests = filterData( diff --git a/src/app/modules/general-cultivations/presentation/components/general-cultivation-pest-data-table/general-cultivation-pest-data-table.hook.tsx b/src/app/modules/general-cultivations/presentation/components/general-cultivation-pest-data-table/general-cultivation-pest-data-table.hook.tsx new file mode 100644 index 00000000..de487283 --- /dev/null +++ b/src/app/modules/general-cultivations/presentation/components/general-cultivation-pest-data-table/general-cultivation-pest-data-table.hook.tsx @@ -0,0 +1,92 @@ +import { useMemo, useState } from 'react' + +import { MoreHorizontalIcon, PencilIcon, Trash2Icon } from 'lucide-react' + +import { DropdownMenu } from '@/core/presentation/components/ui' +import { useDebounce } from '@/core/presentation/hooks' + +import { useGeneralCultivationPestContext } from '../../hooks/general-cultivation-pest-context.hook' +import { useGeneralCultivationPestsQuery } from '../../hooks/queries/general-cultivation-pests-query.hook' + +import type { GeneralCultivationPestModel } from '../../../domain/models/general-cultivation-pests-model' +import type { GeneralCultivationPestSort } from '../../types/general-cultivation-pest-types' +import type { ColumnDef } from '@tanstack/react-table' + +export function useGeneralCultivationPestDataTable() { + const { + filters, + openEditGeneralCultivationPestForm, + openDeleteGeneralCultivationPestContainer, + } = useGeneralCultivationPestContext() + + const [page, setPage] = useState(1) + const [sort, setSort] = useState() + + const debouncedFilters = useDebounce({ value: filters }) + + const { isLoading, generalCultivationPests } = + useGeneralCultivationPestsQuery({ + filters: debouncedFilters, + page, + sort, + }) + + const columns = useMemo[]>( + () => [ + { + accessorKey: 'name', + header: 'Nome', + }, + { + id: 'row-actions', + header: '', + cell: ({ row }) => { + const { original: generalCultivationPest } = row + + return ( + + + + + + + openEditGeneralCultivationPestForm(generalCultivationPest) + } + > + Editar + + + + openDeleteGeneralCultivationPestContainer( + generalCultivationPest + ) + } + > + Excluir + + + + ) + }, + }, + ], + [ + openDeleteGeneralCultivationPestContainer, + openEditGeneralCultivationPestForm, + ] + ) + + return { + columns, + generalCultivationPests, + isLoading, + page, + sort, + setSort, + setPage, + } +} diff --git a/src/app/modules/general-cultivations/presentation/components/general-cultivation-pest-data-table/general-cultivation-pest-data-table.tsx b/src/app/modules/general-cultivations/presentation/components/general-cultivation-pest-data-table/general-cultivation-pest-data-table.tsx new file mode 100644 index 00000000..0d6e867f --- /dev/null +++ b/src/app/modules/general-cultivations/presentation/components/general-cultivation-pest-data-table/general-cultivation-pest-data-table.tsx @@ -0,0 +1,36 @@ +import { DataTable } from '@/core/presentation/components/ui' + +import { useGeneralCultivationPestDataTable } from './general-cultivation-pest-data-table.hook' + +import type { GeneralCultivationPestModel } from '../../../domain/models/general-cultivation-pests-model' + +export function GeneralCultivationPestDataTable() { + const { + columns, + generalCultivationPests, + isLoading, + page, + sort, + setSort, + setPage, + } = useGeneralCultivationPestDataTable() + + return ( + + columns={columns} + data={generalCultivationPests.resources} + totalPages={generalCultivationPests.totalPages} + pagination={{ + currentPage: page, + onPageChange: setPage, + }} + sorting={{ + currentSorting: sort, + onSorting: setSort, + }} + loading={isLoading} + /> + ) +} + +GeneralCultivationPestDataTable.displayName = 'GeneralCultivationPestDataTable' diff --git a/src/app/modules/general-cultivations/presentation/components/general-cultivation-pest-data-table/index.ts b/src/app/modules/general-cultivations/presentation/components/general-cultivation-pest-data-table/index.ts new file mode 100644 index 00000000..8470dff4 --- /dev/null +++ b/src/app/modules/general-cultivations/presentation/components/general-cultivation-pest-data-table/index.ts @@ -0,0 +1 @@ +export * from './general-cultivation-pest-data-table' diff --git a/src/app/modules/general-cultivations/presentation/components/general-cultivation-pest-delete-dialog/general-cultivation-pest-delete-dialog.tsx b/src/app/modules/general-cultivations/presentation/components/general-cultivation-pest-delete-dialog/general-cultivation-pest-delete-dialog.tsx new file mode 100644 index 00000000..0c94e091 --- /dev/null +++ b/src/app/modules/general-cultivations/presentation/components/general-cultivation-pest-delete-dialog/general-cultivation-pest-delete-dialog.tsx @@ -0,0 +1,84 @@ +import { useCallback } from 'react' + +import { useQueryClient, useMutation } from '@tanstack/react-query' +import toast from 'react-hot-toast' + +import { AlertDialog } from '@/core/presentation/components/ui' + +import { makeRemoteDeleteGeneralCultivationPestUseCase } from '../../../main/factories/use-cases/general-cultivation-pests-use-cases' +import { useGeneralCultivationPestContext } from '../../hooks/general-cultivation-pest-context.hook' + +export function GeneralCultivationPestDeleteDialog() { + const deleteGeneralCultivationPestUseCase = + makeRemoteDeleteGeneralCultivationPestUseCase() + + const { + selectedGeneralCultivationPest, + isOpenDeleteGeneralCultivationPestContainer, + closeDeleteGeneralCultivationPestContainer, + } = useGeneralCultivationPestContext() + + const queryClient = useQueryClient() + + const { mutateAsync: mutateHandleDeleteGeneralCultivationPest } = useMutation( + { + mutationFn: deleteGeneralCultivationPestUseCase.execute, + } + ) + + const handleDeleteGeneralCultivationPest = useCallback(async () => { + if (!selectedGeneralCultivationPest) { + toast.error('Erro ao remover praga de cultivo geral') + return + } + + try { + await mutateHandleDeleteGeneralCultivationPest({ + id: selectedGeneralCultivationPest.id, + }) + + queryClient.invalidateQueries({ + queryKey: ['general-cultivation-pests'], + exact: false, + }) + + toast.success('Praga de cultivo geral removida com sucesso') + } catch { + toast.error('Erro ao remover praga de cultivo geral') + } finally { + closeDeleteGeneralCultivationPestContainer() + } + }, [ + closeDeleteGeneralCultivationPestContainer, + mutateHandleDeleteGeneralCultivationPest, + queryClient, + selectedGeneralCultivationPest, + ]) + + return ( + + + + + {`Deseja remover a praga de cultivo geral ${selectedGeneralCultivationPest?.name}?`} + + + Não será possível desfazer essa ação! + + + + Cancelar + + Remover + + + + + ) +} + +GeneralCultivationPestDeleteDialog.displayName = + 'GeneralCultivationPestDeleteDialog' diff --git a/src/app/modules/general-cultivations/presentation/components/general-cultivation-pest-delete-dialog/index.ts b/src/app/modules/general-cultivations/presentation/components/general-cultivation-pest-delete-dialog/index.ts new file mode 100644 index 00000000..9b579cae --- /dev/null +++ b/src/app/modules/general-cultivations/presentation/components/general-cultivation-pest-delete-dialog/index.ts @@ -0,0 +1 @@ +export * from './general-cultivation-pest-delete-dialog' diff --git a/src/app/modules/general-cultivations/presentation/contexts/general-cultivation-pest-context.tsx b/src/app/modules/general-cultivations/presentation/contexts/general-cultivation-pest-context.tsx new file mode 100644 index 00000000..a5ab959a --- /dev/null +++ b/src/app/modules/general-cultivations/presentation/contexts/general-cultivation-pest-context.tsx @@ -0,0 +1,140 @@ +import { + createContext, + useCallback, + useMemo, + useState, + type PropsWithChildren, +} from 'react' + +import type { GeneralCultivationPestModel } from '../../domain/models/general-cultivation-pests-model' +import type { GeneralCultivationPestFilters } from '../types/general-cultivation-pest-types' + +type GeneralCultivationPestContextValue = { + filters: GeneralCultivationPestFilters + handleChangeFilters: (newFilters: GeneralCultivationPestFilters) => void + selectedGeneralCultivationPest?: GeneralCultivationPestModel + isOpenNewGeneralCultivationPestForm: boolean + isOpenEditGeneralCultivationPestForm: boolean + isOpenDeleteGeneralCultivationPestContainer: boolean + openNewGeneralCultivationPestForm: () => void + closeNewGeneralCultivationPestForm: () => void + openEditGeneralCultivationPestForm: ( + generalCultivationPest: GeneralCultivationPestModel + ) => void + closeEditGeneralCultivationPestForm: () => void + openDeleteGeneralCultivationPestContainer: ( + generalCultivationPest: GeneralCultivationPestModel + ) => void + closeDeleteGeneralCultivationPestContainer: () => void +} + +export const GeneralCultivationPestContext = createContext( + {} as GeneralCultivationPestContextValue +) + +export function GeneralCultivationPestProvider({ + children, +}: Readonly) { + const [filters, setFilters] = useState({}) + + const handleChangeFilters = useCallback( + (newFilters: GeneralCultivationPestFilters) => { + setFilters((prevState) => ({ + ...prevState, + ...newFilters, + })) + }, + [] + ) + + const [ + isOpenNewGeneralCultivationPestForm, + setIsOpenNewGeneralCultivationPestForm, + ] = useState(false) + + const [ + isOpenEditGeneralCultivationPestForm, + setIsOpenEditGeneralCultivationPestForm, + ] = useState(false) + + const [ + isOpenDeleteGeneralCultivationPestContainer, + setIsOpenDeleteGeneralCultivationPestContainer, + ] = useState(false) + + const [selectedGeneralCultivationPest, setSelectedGeneralCultivationPest] = + useState() + + const openNewGeneralCultivationPestForm = useCallback(() => { + setIsOpenNewGeneralCultivationPestForm(true) + }, []) + + const closeNewGeneralCultivationPestForm = useCallback(() => { + setIsOpenNewGeneralCultivationPestForm(false) + }, []) + + const openEditGeneralCultivationPestForm = useCallback( + (generalCultivationPest: GeneralCultivationPestModel) => { + setSelectedGeneralCultivationPest(generalCultivationPest) + setIsOpenEditGeneralCultivationPestForm(true) + }, + [] + ) + + const closeEditGeneralCultivationPestForm = useCallback(() => { + setSelectedGeneralCultivationPest(undefined) + setIsOpenEditGeneralCultivationPestForm(false) + }, []) + + const openDeleteGeneralCultivationPestContainer = useCallback( + (generalCultivationPest: GeneralCultivationPestModel) => { + setSelectedGeneralCultivationPest(generalCultivationPest) + setIsOpenDeleteGeneralCultivationPestContainer(true) + }, + [] + ) + + const closeDeleteGeneralCultivationPestContainer = useCallback(() => { + setSelectedGeneralCultivationPest(undefined) + setIsOpenDeleteGeneralCultivationPestContainer(false) + }, []) + + const providerValues = useMemo( + () => ({ + filters, + handleChangeFilters, + selectedGeneralCultivationPest, + isOpenNewGeneralCultivationPestForm, + isOpenEditGeneralCultivationPestForm, + isOpenDeleteGeneralCultivationPestContainer, + openNewGeneralCultivationPestForm, + closeNewGeneralCultivationPestForm, + openEditGeneralCultivationPestForm, + closeEditGeneralCultivationPestForm, + openDeleteGeneralCultivationPestContainer, + closeDeleteGeneralCultivationPestContainer, + }), + [ + filters, + handleChangeFilters, + selectedGeneralCultivationPest, + isOpenNewGeneralCultivationPestForm, + isOpenEditGeneralCultivationPestForm, + isOpenDeleteGeneralCultivationPestContainer, + openNewGeneralCultivationPestForm, + closeNewGeneralCultivationPestForm, + openEditGeneralCultivationPestForm, + closeEditGeneralCultivationPestForm, + openDeleteGeneralCultivationPestContainer, + closeDeleteGeneralCultivationPestContainer, + ] + ) + + return ( + + {children} + + ) +} + +GeneralCultivationPestProvider.displayName = 'GeneralCultivationPestProvider' diff --git a/src/app/modules/general-cultivations/presentation/forms/general-cultivation-pest-form/create-general-cultivation-pest-form.tsx b/src/app/modules/general-cultivations/presentation/forms/general-cultivation-pest-form/create-general-cultivation-pest-form.tsx new file mode 100644 index 00000000..2b93a928 --- /dev/null +++ b/src/app/modules/general-cultivations/presentation/forms/general-cultivation-pest-form/create-general-cultivation-pest-form.tsx @@ -0,0 +1,117 @@ +import { useCallback } from 'react' + +import { zodResolver } from '@hookform/resolvers/zod' +import { useMutation, useQueryClient } from '@tanstack/react-query' +import toast from 'react-hot-toast' + +import { + Button, + Form, + ScrollArea, + Sheet, +} from '@/core/presentation/components/ui' +import { useHookForm } from '@/core/presentation/hooks' + +import { makeRemoteCreateGeneralCultivationPestUseCase } from '../../../main/factories/use-cases/general-cultivation-pests-use-cases' +import { useGeneralCultivationPestContext } from '../../hooks/general-cultivation-pest-context.hook' +import { + generalCultivationPestFormSchema, + type GeneralCultivationPestFormSchema, +} from '../../validations/general-cultivation-pest-form-schema' + +import { GeneralCultivationPestFormInputs } from './general-cultivation-pest-form-inputs' +import { GENERAL_CULTIVATION_PEST_INITIAL_FORM_DATA } from './general-cultivation-pest-initial-form-data' + +export function CreateGeneralCultivationPestForm() { + const { + isOpenNewGeneralCultivationPestForm, + closeNewGeneralCultivationPestForm, + } = useGeneralCultivationPestContext() + + const createGeneralCultivationPestUseCase = + makeRemoteCreateGeneralCultivationPestUseCase() + + const queryClient = useQueryClient() + + const form = useHookForm({ + defaultValues: GENERAL_CULTIVATION_PEST_INITIAL_FORM_DATA, + resolver: zodResolver(generalCultivationPestFormSchema), + }) + + const { mutateAsync: mutateHandleCreateGeneralCultivationPest } = useMutation( + { + mutationFn: createGeneralCultivationPestUseCase.execute, + } + ) + + const handleCreateGeneralCultivationPest = useCallback( + async (data: GeneralCultivationPestFormSchema) => { + try { + await mutateHandleCreateGeneralCultivationPest({ + generalCultivationPest: { + ...data, + }, + }) + + queryClient.invalidateQueries({ + queryKey: ['general-cultivation-pests'], + exact: false, + }) + + toast.success('Praga de Cultivo Geral foi cadastrada com sucesso') + form.reset(GENERAL_CULTIVATION_PEST_INITIAL_FORM_DATA) + closeNewGeneralCultivationPestForm() + } catch { + toast.error('Erro ao cadastrar praga de cultivo geral') + } + }, + [ + closeNewGeneralCultivationPestForm, + form, + mutateHandleCreateGeneralCultivationPest, + queryClient, + ] + ) + + return ( + + + + Nova Praga de Cultivo Geral + + Preencha o formulário para criar uma nova Praga de Cultivo Geral. + + + + + +
+ + +
+
+ + + + +
+
+ ) +} + +CreateGeneralCultivationPestForm.displayName = + 'CreateGeneralCultivationPestForm' diff --git a/src/app/modules/general-cultivations/presentation/forms/general-cultivation-pest-form/edit-general-cultivation-pest-form.tsx b/src/app/modules/general-cultivations/presentation/forms/general-cultivation-pest-form/edit-general-cultivation-pest-form.tsx new file mode 100644 index 00000000..77f27f7e --- /dev/null +++ b/src/app/modules/general-cultivations/presentation/forms/general-cultivation-pest-form/edit-general-cultivation-pest-form.tsx @@ -0,0 +1,140 @@ +import { useCallback } from 'react' + +import { zodResolver } from '@hookform/resolvers/zod' +import { useMutation, useQueryClient } from '@tanstack/react-query' +import toast from 'react-hot-toast' + +import { + Button, + Form, + Loading, + ScrollArea, + Sheet, +} from '@/core/presentation/components/ui' +import { useHookForm } from '@/core/presentation/hooks' + +import { makeRemoteUpdateGeneralCultivationPestUseCase } from '../../../main/factories/use-cases/general-cultivation-pests-use-cases' +import { useGeneralCultivationPestContext } from '../../hooks/general-cultivation-pest-context.hook' +import { useGeneralCultivationPestQuery } from '../../hooks/queries/general-cultivation-pest-query.hook' +import { + generalCultivationPestFormSchema, + type GeneralCultivationPestFormSchema, +} from '../../validations/general-cultivation-pest-form-schema' + +import { GeneralCultivationPestFormInputs } from './general-cultivation-pest-form-inputs' +import { GENERAL_CULTIVATION_PEST_INITIAL_FORM_DATA } from './general-cultivation-pest-initial-form-data' + +export function EditGeneralCultivationPestForm() { + const { + isOpenEditGeneralCultivationPestForm, + closeEditGeneralCultivationPestForm, + selectedGeneralCultivationPest, + } = useGeneralCultivationPestContext() + + const { isLoading, generalCultivationPest } = useGeneralCultivationPestQuery({ + id: selectedGeneralCultivationPest!.id, + }) + + const updateGeneralCultivationPestUseCase = + makeRemoteUpdateGeneralCultivationPestUseCase() + + const queryClient = useQueryClient() + + const form = useHookForm({ + defaultValues: GENERAL_CULTIVATION_PEST_INITIAL_FORM_DATA, + ...(generalCultivationPest && { + values: { + ...generalCultivationPest, + }, + }), + resolver: zodResolver(generalCultivationPestFormSchema), + }) + + const { mutateAsync: mutateHandleUpdateGeneralCultivationPest } = useMutation( + { + mutationFn: updateGeneralCultivationPestUseCase.execute, + } + ) + + const handleUpdateGeneralCultivationPest = useCallback( + async (data: GeneralCultivationPestFormSchema) => { + try { + if (!selectedGeneralCultivationPest) { + toast.error('Erro ao atualizar Praga de Cultivo Geral') + return + } + + await mutateHandleUpdateGeneralCultivationPest({ + generalCultivationPest: { + name: data.name, + id: selectedGeneralCultivationPest.id, + }, + }) + + queryClient.invalidateQueries({ + queryKey: ['general-cultivation-pests'], + exact: false, + }) + + toast.success('Praga de Cultivo Geral foi editada com sucesso') + form.reset(GENERAL_CULTIVATION_PEST_INITIAL_FORM_DATA) + closeEditGeneralCultivationPestForm() + } catch { + toast.error('Erro ao salvar alterações') + } + }, + [ + closeEditGeneralCultivationPestForm, + form, + mutateHandleUpdateGeneralCultivationPest, + queryClient, + selectedGeneralCultivationPest, + ] + ) + + return ( + + + + {`Editar Praga de Cultivo Geral ${selectedGeneralCultivationPest?.name}`} + + Preencha o formulário para editar a Praga de Cultivo Geral. + + + + +
+ {isLoading ? ( +
+ +
+ ) : ( + + )} + +
+
+ + + + +
+
+ ) +} + +EditGeneralCultivationPestForm.displayName = 'EditGeneralCultivationPestForm' diff --git a/src/app/modules/general-cultivations/presentation/forms/general-cultivation-pest-form/general-cultivation-pest-form-inputs.tsx b/src/app/modules/general-cultivations/presentation/forms/general-cultivation-pest-form/general-cultivation-pest-form-inputs.tsx new file mode 100644 index 00000000..4fee8523 --- /dev/null +++ b/src/app/modules/general-cultivations/presentation/forms/general-cultivation-pest-form/general-cultivation-pest-form-inputs.tsx @@ -0,0 +1,33 @@ +import { useFormContext } from 'react-hook-form' + +import { Form, Input } from '@/core/presentation/components/ui' + +export function GeneralCultivationPestFormInputs() { + const form = useFormContext() + + return ( +
+ { + const { error } = fieldState + + return ( + + Nome* + + + + + + ) + }} + /> +
+ ) +} diff --git a/src/app/modules/general-cultivations/presentation/forms/general-cultivation-pest-form/general-cultivation-pest-form.tsx b/src/app/modules/general-cultivations/presentation/forms/general-cultivation-pest-form/general-cultivation-pest-form.tsx new file mode 100644 index 00000000..8c25801a --- /dev/null +++ b/src/app/modules/general-cultivations/presentation/forms/general-cultivation-pest-form/general-cultivation-pest-form.tsx @@ -0,0 +1,16 @@ +import { CreateGeneralCultivationPestForm } from './create-general-cultivation-pest-form' +import { EditGeneralCultivationPestForm } from './edit-general-cultivation-pest-form' + +type GeneralCultivationPestFormProps = { + readonly id?: number +} + +export function GeneralCultivationPestForm({ + id, +}: GeneralCultivationPestFormProps) { + if (id) { + return + } + + return +} diff --git a/src/app/modules/general-cultivations/presentation/forms/general-cultivation-pest-form/general-cultivation-pest-initial-form-data.ts b/src/app/modules/general-cultivations/presentation/forms/general-cultivation-pest-form/general-cultivation-pest-initial-form-data.ts new file mode 100644 index 00000000..a467023f --- /dev/null +++ b/src/app/modules/general-cultivations/presentation/forms/general-cultivation-pest-form/general-cultivation-pest-initial-form-data.ts @@ -0,0 +1,6 @@ +import type { GeneralCultivationPestFormSchema } from '../../validations/general-cultivation-pest-form-schema' + +export const GENERAL_CULTIVATION_PEST_INITIAL_FORM_DATA: GeneralCultivationPestFormSchema = + { + name: '', + } diff --git a/src/app/modules/general-cultivations/presentation/forms/general-cultivation-pest-form/index.ts b/src/app/modules/general-cultivations/presentation/forms/general-cultivation-pest-form/index.ts new file mode 100644 index 00000000..205feb8e --- /dev/null +++ b/src/app/modules/general-cultivations/presentation/forms/general-cultivation-pest-form/index.ts @@ -0,0 +1 @@ +export * from './general-cultivation-pest-form' diff --git a/src/app/modules/general-cultivations/presentation/hooks/general-cultivation-pest-context.hook.ts b/src/app/modules/general-cultivations/presentation/hooks/general-cultivation-pest-context.hook.ts new file mode 100644 index 00000000..6942ef69 --- /dev/null +++ b/src/app/modules/general-cultivations/presentation/hooks/general-cultivation-pest-context.hook.ts @@ -0,0 +1,15 @@ +import { useContext } from 'react' + +import { GeneralCultivationPestContext } from '../contexts/general-cultivation-pest-context' + +export function useGeneralCultivationPestContext() { + const context = useContext(GeneralCultivationPestContext) + + if (!context) { + throw new Error( + 'useGeneralCultivationPestContext should be used within ' + ) + } + + return context +} diff --git a/src/app/modules/general-cultivations/presentation/hooks/queries/all-general-cultivation-pests-query.hook.ts b/src/app/modules/general-cultivations/presentation/hooks/queries/all-general-cultivation-pests-query.hook.ts index bb90cef4..9ac4d9db 100644 --- a/src/app/modules/general-cultivations/presentation/hooks/queries/all-general-cultivation-pests-query.hook.ts +++ b/src/app/modules/general-cultivations/presentation/hooks/queries/all-general-cultivation-pests-query.hook.ts @@ -34,12 +34,12 @@ export function useAllGeneralCultivationPestsQuery({ filters }: Props) { useEffect(() => { if (isError) - toast.error(error?.message ?? 'Erro ao buscar pragas de cultivos gerais') + toast.error(error?.message ?? 'Erro ao buscar pragas de cultivo geral') }, [error, isError]) return { allGeneralCultivationPests: - data?.resources.map((resource) => toOption(resource, 'name')) ?? [], + data?.resources.map((resource) => toOption(resource, 'name', {})) ?? [], isLoading, refetchAllGeneralCultivationPests, } diff --git a/src/app/modules/general-cultivations/presentation/hooks/queries/general-cultivation-pest-query.hook.ts b/src/app/modules/general-cultivations/presentation/hooks/queries/general-cultivation-pest-query.hook.ts new file mode 100644 index 00000000..60835805 --- /dev/null +++ b/src/app/modules/general-cultivations/presentation/hooks/queries/general-cultivation-pest-query.hook.ts @@ -0,0 +1,40 @@ +import { useEffect } from 'react' + +import { useQuery } from '@tanstack/react-query' +import toast from 'react-hot-toast' + +import { makeRemoteGetGeneralCultivationPestUseCase } from '../../../main/factories/use-cases/general-cultivation-pests-use-cases' + +type Props = { + id: number +} + +export function useGeneralCultivationPestQuery({ id }: Props) { + const getGeneralCultivationPestUseCase = + makeRemoteGetGeneralCultivationPestUseCase() + + const { + data: generalCultivationPest, + isError, + error, + isLoading, + refetch: refetchGeneralCultivationPest, + } = useQuery({ + queryKey: ['general-cultivation-pest', id], + queryFn: () => + getGeneralCultivationPestUseCase.execute({ + id, + }), + }) + + useEffect(() => { + if (isError) + toast.error(error?.message ?? 'Erro ao buscar uma praga de cultivo geral') + }, [error, isError]) + + return { + generalCultivationPest, + isLoading, + refetchGeneralCultivationPest, + } +} diff --git a/src/app/modules/general-cultivations/presentation/hooks/queries/general-cultivation-pests-query.hook.ts b/src/app/modules/general-cultivations/presentation/hooks/queries/general-cultivation-pests-query.hook.ts new file mode 100644 index 00000000..7e53d061 --- /dev/null +++ b/src/app/modules/general-cultivations/presentation/hooks/queries/general-cultivation-pests-query.hook.ts @@ -0,0 +1,56 @@ +import { useEffect } from 'react' + +import { useQuery } from '@tanstack/react-query' +import toast from 'react-hot-toast' + +import { makeRemoteGetGeneralCultivationPestsUseCase } from '../../../main/factories/use-cases/general-cultivation-pests-use-cases' + +import type { + GeneralCultivationPestFilters, + GeneralCultivationPestSort, +} from '../../types/general-cultivation-pest-types' + +type Props = { + filters: GeneralCultivationPestFilters + page: number + sort?: GeneralCultivationPestSort +} + +export function useGeneralCultivationPestsQuery({ + filters, + page, + sort, +}: Props) { + const getGeneralCultivationPestsUseCase = + makeRemoteGetGeneralCultivationPestsUseCase() + + const { + data: generalCultivationPests, + isError, + error, + isLoading, + refetch: refetchGeneralCultivationPests, + } = useQuery({ + queryKey: ['general-cultivation-pests', { page, sort, filters }], + queryFn: () => + getGeneralCultivationPestsUseCase.execute({ + pagination: { page }, + sort, + filters, + }), + }) + + useEffect(() => { + if (isError) + toast.error(error?.message ?? 'Erro ao buscar pragas de cultivo geral') + }, [error, isError]) + + return { + generalCultivationPests: generalCultivationPests ?? { + resources: [], + totalPages: 1, + }, + isLoading, + refetchGeneralCultivationPests, + } +} diff --git a/src/app/modules/general-cultivations/presentation/screens/general-cultivation-pests-screen.tsx b/src/app/modules/general-cultivations/presentation/screens/general-cultivation-pests-screen.tsx new file mode 100644 index 00000000..5cc21899 --- /dev/null +++ b/src/app/modules/general-cultivations/presentation/screens/general-cultivation-pests-screen.tsx @@ -0,0 +1,66 @@ +import { Button, Input } from '@/core/presentation/components/ui' + +import { GeneralCultivationPestDataTable } from '../components/general-cultivation-pest-data-table' +import { GeneralCultivationPestDeleteDialog } from '../components/general-cultivation-pest-delete-dialog' +import { + GeneralCultivationPestContext, + GeneralCultivationPestProvider, +} from '../contexts/general-cultivation-pest-context' +import { GeneralCultivationPestForm } from '../forms/general-cultivation-pest-form' + +export function GeneralCultivationPestsScreen() { + return ( + + + {({ + selectedGeneralCultivationPest, + isOpenDeleteGeneralCultivationPestContainer, + isOpenNewGeneralCultivationPestForm, + isOpenEditGeneralCultivationPestForm, + filters, + handleChangeFilters, + openNewGeneralCultivationPestForm, + }) => ( +
+
+ + + { + handleChangeFilters({ + name: { value: target.value, type: 'LIKE' }, + }) + }} + placeholder="Procurar pragas" + /> +
+ + + {selectedGeneralCultivationPest && + isOpenDeleteGeneralCultivationPestContainer && ( + + )} + + {(isOpenNewGeneralCultivationPestForm || + isOpenEditGeneralCultivationPestForm) && ( + + )} +
+ )} +
+
+ ) +} + +GeneralCultivationPestsScreen.displayName = 'GeneralCultivationPestScreen' diff --git a/src/app/modules/general-cultivations/presentation/validations/general-cultivation-pest-form-schema.ts b/src/app/modules/general-cultivations/presentation/validations/general-cultivation-pest-form-schema.ts new file mode 100644 index 00000000..b6abe9b3 --- /dev/null +++ b/src/app/modules/general-cultivations/presentation/validations/general-cultivation-pest-form-schema.ts @@ -0,0 +1,11 @@ +import { z } from 'zod' + +export const generalCultivationPestFormSchema = z.object({ + name: z.string().min(1, { + message: 'Nome é obrigatório', + }), +}) + +export type GeneralCultivationPestFormSchema = z.infer< + typeof generalCultivationPestFormSchema +> diff --git a/src/app/pages/general-registrations-page.tsx b/src/app/pages/general-registrations-page.tsx index 1ee65e69..ec80f3d2 100644 --- a/src/app/pages/general-registrations-page.tsx +++ b/src/app/pages/general-registrations-page.tsx @@ -2,6 +2,7 @@ import { useCallback, useMemo, useState, type ReactNode } from 'react' import { Breadcrumb, ScrollArea, Tabs } from '@/core/presentation/components/ui' +import { GeneralCultivationPestsScreen } from '../modules/general-cultivations/presentation/screens/general-cultivation-pests-screen' import { GeneralCultivationsScreen } from '../modules/general-cultivations/presentation/screens/general-cultivations-screen' type Tab = @@ -34,6 +35,11 @@ export function GeneralRegistrationsPage() { name: 'Cultivos Gerais', component: , }, + { + key: 'general-cultivation-pests', + name: 'Pragas', + component: , + }, ], }, ],