diff --git a/metrics/sonar-metrics.py b/metrics/sonar-metrics.py index 11d83283..3456d3f3 100755 --- a/metrics/sonar-metrics.py +++ b/metrics/sonar-metrics.py @@ -27,7 +27,7 @@ def generate_metrics(): repository_version = sys.argv[2] underlined_repo_name = repository_name[:16] + \ repository_name[16:].replace('-', "_") - url = f'{base_url}{repository_name}&metricKeys={",".join(metrics)}&ps=500' + url = f'{base_url}{repository_name}&metricKeys={",".join(metrics)}' with urllib.request.urlopen(url) as res: data = json.load(res) date = datetime.now() diff --git a/src/components/action-buttons/approve-button-homologation/index.tsx b/src/components/action-buttons/approve-button-homologation/index.tsx index 359d38d5..3c170441 100644 --- a/src/components/action-buttons/approve-button-homologation/index.tsx +++ b/src/components/action-buttons/approve-button-homologation/index.tsx @@ -209,7 +209,6 @@ export function ApproveButton({ label="Adicionar Alerta" icon={} variant="outline" - disabled color="primary" tooltipProps={{ placement: 'bottom', diff --git a/src/components/side-bar/index.tsx b/src/components/side-bar/index.tsx index b0f4ab6c..91786eae 100644 --- a/src/components/side-bar/index.tsx +++ b/src/components/side-bar/index.tsx @@ -48,7 +48,7 @@ export const SideBar = memo(() => { label="Notificações" pathname="/notificacoes" icon={AiOutlineBell} - allowedUsersPath={['ADMIN', 'BASIC']} + allowedUsersPath={['ADMIN', 'BASIC', 'USER']} /> diff --git a/src/components/side-bar/sidebar-notification/index.tsx b/src/components/side-bar/sidebar-notification/index.tsx index b237c04c..7ef022d9 100644 --- a/src/components/side-bar/sidebar-notification/index.tsx +++ b/src/components/side-bar/sidebar-notification/index.tsx @@ -67,7 +67,7 @@ export const SideBarNotification = memo( style={{ opacity: filteredNotifications?.length === 0 || - user.profile === 'USER' + user.profile !== 'BASIC' ? 0 : 1, }} diff --git a/src/config/routes/Routes.tsx b/src/config/routes/Routes.tsx index 085d8144..cce5fc95 100644 --- a/src/config/routes/Routes.tsx +++ b/src/config/routes/Routes.tsx @@ -20,7 +20,6 @@ import { RegistrarAgendamento } from '@/pages/agendamento_externo/index'; import { AgendamentosAbertos } from '@/pages/agendamentos_abertos'; import { DefaultLayoutOpen } from '@/components/layout/default-layout-open'; import { Notificacoes } from '@/pages/notificacoes'; -import { NotificacaoAdmin } from '@/pages/notificacoes/notificacoes_admin'; export function Router() { return ( @@ -158,14 +157,6 @@ export function Router() { } /> - - - - } - /> {/* ROTAS PUBLICAS */} } /> diff --git a/src/features/alerts/api/detele-alerts.tsx b/src/features/alerts/api/detele-alerts.tsx new file mode 100644 index 00000000..93523410 --- /dev/null +++ b/src/features/alerts/api/detele-alerts.tsx @@ -0,0 +1,53 @@ +import { useMutation, useQueryClient } from '@tanstack/react-query'; +import { api } from '@/config/lib/axios'; +import { ALERT_ENDPOINT } from '@/features/alerts/constants/requests'; +import { toast } from '@/utils/toast'; +import { ALERTS_CACHE_KEYS } from '@/features/alerts/constants/cache'; +import { + DeleteAlertParams, + DeleteAlertsParams, +} from '@/features/alerts/api/types'; + +function deleteAlert({ alertId }: DeleteAlertParams) { + return api.delete(`${ALERT_ENDPOINT}/notifications/${alertId}`); +} + +function deleteAlerts({ alertsIds }: DeleteAlertsParams) { + return api.delete( + `${ALERT_ENDPOINT}/notifications/delete-alerts/${alertsIds}` + ); +} + +export function useDeleteAlert() { + const queryClient = useQueryClient(); + + return useMutation(deleteAlert, { + onSuccess() { + toast.success('Alerta removido com sucesso!'); + + queryClient.invalidateQueries([ALERTS_CACHE_KEYS.allAlerts]); + }, + onError() { + toast.error( + 'Não foi possível remover o alerta. Tente novamente mais tarde!' + ); + }, + }); +} + +export function useDeleteAlerts() { + const queryClient = useQueryClient(); + + return useMutation(deleteAlerts, { + onSuccess() { + toast.success('Alerta removidos com sucesso!'); + + queryClient.invalidateQueries([ALERTS_CACHE_KEYS.allAlerts]); + }, + onError() { + toast.error( + 'Não foi possível remover os alerta. Tente novamente mais tarde!' + ); + }, + }); +} diff --git a/src/features/alerts/components/alert-item-manager/alert-item-manager.spec.tsx b/src/features/alerts/components/alert-item-manager/alert-item-manager.spec.tsx deleted file mode 100644 index 4fae7a11..00000000 --- a/src/features/alerts/components/alert-item-manager/alert-item-manager.spec.tsx +++ /dev/null @@ -1,98 +0,0 @@ -import { - screen, - render, - waitFor, - act, - fireEvent, -} from '@testing-library/react'; -import { vi } from 'vitest'; -import { AlertItemManager } from '.'; -import { Alert } from '../../type'; - -const mockedNotification: Alert = { - id: '1', - sourceEmail: 'email@gmail.com', - sourceName: 'name', - targetName: 'targetName', - targetEmail: 'email1@gmail.com', - message: 'message', - status: 'unsolved', - pendency: 'pending', - read: false, - createdAt: new Date(), -}; - -const mockedNotificationSolved = { - ...mockedNotification, - status: 'solved', - read: true, -}; - -const mockedNotificationPending = { - ...mockedNotification, - status: 'pending', - read: true, -}; - -const mockedOnDelete = vi.fn(() => {}); - -describe('AlertItemManager', () => { - it('should render correctly', async () => { - render( - - ); - - const targetNameResult = screen.getByText(mockedNotification.targetName); - expect(targetNameResult).toBeInTheDocument(); - }); - - it('should render correctly status pending', async () => { - render( - - ); - - const targetNameResult = screen.getByText( - mockedNotificationPending.targetName - ); - expect(targetNameResult).toBeInTheDocument(); - }); - - it('should render correctly status solved', async () => { - render( - - ); - - const targetNameResult = screen.queryByText( - mockedNotificationSolved.targetName - ); - expect(targetNameResult).toBeInTheDocument(); - }); - - it('should be able to delete a alert', async () => { - const { queryByLabelText } = render( - - ); - - const button = queryByLabelText('Alerta'); - if (button) { - fireEvent.click(button); - expect(mockedOnDelete).toHaveBeenCalledWith(); - } - }); -}); diff --git a/src/features/alerts/components/alert-modal/index.tsx b/src/features/alerts/components/alert-modal/index.tsx index f168c4da..bde6fbf5 100644 --- a/src/features/alerts/components/alert-modal/index.tsx +++ b/src/features/alerts/components/alert-modal/index.tsx @@ -30,8 +30,6 @@ export function AlertModal({ const [filterBasicUsers, setFilterBasicUsers] = useState(users || []); const { user } = useAuth(); - const userAuth = useAuth(); - const handleSubmit = useCallback( async ({ target, message }: AlertPayload) => { const { label, value } = target; @@ -64,14 +62,10 @@ export function AlertModal({ useEffect(() => { if (users) { - const filteredUsers = users.filter( - (user) => - (user.profile === 'BASIC' || user.profile === 'ADMIN') && - user.email !== userAuth.user?.email - ); + const filteredUsers = users.filter((user) => user.profile === 'BASIC'); setFilterBasicUsers(filteredUsers); } - }, [users, userAuth.user?.email]); + }, [users]); return ( diff --git a/src/features/homologations/components/issue-open-edit-form/index.tsx b/src/features/homologations/components/issue-open-edit-form/index.tsx index f45e68f8..613d163b 100644 --- a/src/features/homologations/components/issue-open-edit-form/index.tsx +++ b/src/features/homologations/components/issue-open-edit-form/index.tsx @@ -438,7 +438,6 @@ export function UpdateExternIssueForm() { label="Adicionar Alerta" icon={} variant="outline" - disabled color="primary" tooltipProps={{ placement: 'bottom', diff --git a/src/features/issues/components/issue-item/index.tsx b/src/features/issues/components/issue-item/index.tsx index b1975518..dc28f465 100644 --- a/src/features/issues/components/issue-item/index.tsx +++ b/src/features/issues/components/issue-item/index.tsx @@ -1,7 +1,6 @@ import { Badge, Box, - Button, HStack, Spacer, Tag, @@ -15,32 +14,19 @@ import { useGetAllCities } from '@/features/cities/api/get-all-cities'; import { DeleteButton } from '@/components/action-buttons/delete-button'; import { ItemActions } from '@/components/list-item/list-item-actions'; import { Permission } from '@/components/permission'; -import { useGetAllSchedules } from '@/features/schedules/api/get-all-schedules'; interface IssueItemProps { issue: Issue; onDelete: (issueId: string) => void; isDeleting: boolean; - onOpen?: () => void; } -export function IssueItem({ - issue, - onDelete, - isDeleting, - onOpen, -}: IssueItemProps) { +export function IssueItem({ issue, onDelete, isDeleting }: IssueItemProps) { const { data: cities } = useGetAllCities(0); const city = cities?.find((city) => { return city?.id === issue?.city_id; }); - const { data: schedules } = useGetAllSchedules(); - - const isIssueScheduled = schedules?.some( - (schedule) => schedule.issue.id === issue.id - ); - return ( @@ -121,12 +107,6 @@ export function IssueItem({ }} > - {!isIssueScheduled ? ( - - ) : ( - (null as any) - )} - onDelete(issue.id)} label="atendimento" diff --git a/src/features/issues/components/issue-item/issue-item.spec.tsx b/src/features/issues/components/issue-item/issue-item.spec.tsx index 6c928252..eba4361c 100644 --- a/src/features/issues/components/issue-item/issue-item.spec.tsx +++ b/src/features/issues/components/issue-item/issue-item.spec.tsx @@ -51,7 +51,7 @@ describe('IssueItem', () => { expect(name[0]).toBeInTheDocument(); }); - it.todo('should be able to delete a item', async () => { + it('should be able to delete a item', async () => { const { queryByLabelText } = render( const errMessage = err?.response?.data?.message ?? 'Não foi possível carregar as notificações. Tente novamente mais tarde!'; - // toast.error(errMessage); + toast.error(errMessage); return [] as GetAllNotificationsResponse; }); diff --git a/src/features/reports/api/get-report.ts b/src/features/reports/api/get-report.ts new file mode 100644 index 00000000..c8d328d1 --- /dev/null +++ b/src/features/reports/api/get-report.ts @@ -0,0 +1,38 @@ +import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; +import { api } from '@/config/lib/axios'; +import { REPORT_ENDPOINT } from '@/features/reports/constants/requests'; +import { GetReportParams, GetReportResponse } from '@/features/reports/types'; +import { toast } from '@/utils/toast'; +import { REPORT_CACHE_KEYS } from '@/features/reports/constants/cache'; + +const getReport = async ({ startDate, endDate }: GetReportParams) => + api + .get( + `${REPORT_ENDPOINT}/report/?startDate=${startDate}&endDate=${endDate}` + ) + .then((response) => { + return response.data; + }) + .catch((error) => { + toast.error( + 'Não foi possível carregar o relatório. Tente novamente mais tarde!' + ); + return error; + }); + +// Set this with mutation +export const useGetReport = ({ + onSuccessCallBack, +}: { + onSuccessCallBack?: () => void; +}) => { + const queryClient = useQueryClient(); + + return useMutation(getReport, { + onSuccess() { + queryClient.invalidateQueries([REPORT_CACHE_KEYS.reportsCache]); + + onSuccessCallBack?.(); + }, + }); +}; diff --git a/src/features/reports/constants/cache.ts b/src/features/reports/constants/cache.ts new file mode 100644 index 00000000..72e31e18 --- /dev/null +++ b/src/features/reports/constants/cache.ts @@ -0,0 +1,3 @@ +export enum REPORT_CACHE_KEYS { + reportsCache = 'report-cache', +} diff --git a/src/features/reports/constants/requests.ts b/src/features/reports/constants/requests.ts new file mode 100644 index 00000000..960f2cb3 --- /dev/null +++ b/src/features/reports/constants/requests.ts @@ -0,0 +1,2 @@ +export const REPORT_ENDPOINT = + import.meta.env.VITE_PUBLIC_DETALHADOR_CHAMADOS_URL ?? ''; diff --git a/src/features/reports/types.ts b/src/features/reports/types.ts new file mode 100644 index 00000000..fcd90442 --- /dev/null +++ b/src/features/reports/types.ts @@ -0,0 +1,9 @@ +export interface GetReportParams { + startDate: string | null; + endDate: string | null; +} + +export interface GetReportResponse { + type: string; + data: ArrayBuffer; +} diff --git a/src/features/schedules/components/schedule-form/index.tsx b/src/features/schedules/components/schedule-form/index.tsx index 602d79d4..d9e98480 100644 --- a/src/features/schedules/components/schedule-form/index.tsx +++ b/src/features/schedules/components/schedule-form/index.tsx @@ -79,8 +79,9 @@ export function ScheduleForm({ applicant_phone={issue?.phone ?? ''} city={city?.name ?? ''} problem={ - issue?.problem_types.map((problem) => problem.name).join(' - ') ?? - '' + issue?.problem_category.problem_types + .map((problem) => problem.name) + .join(' - ') ?? '' } category={issue?.problem_category.name ?? ''} workstation={workstation ?? ''} diff --git a/src/features/schedules/components/schedule-form/schedule-form.spec.tsx b/src/features/schedules/components/schedule-form/schedule-form.spec.tsx deleted file mode 100644 index 3ebebc90..00000000 --- a/src/features/schedules/components/schedule-form/schedule-form.spec.tsx +++ /dev/null @@ -1,31 +0,0 @@ -import { ChakraProvider } from '@chakra-ui/react'; -import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; -import { render } from '@testing-library/react'; -import { BrowserRouter } from 'react-router-dom'; -import { vi } from 'vitest'; -import { theme } from '@/styles/theme'; -import { ScheduleForm } from '.'; -import { AuthProvider } from '@/contexts/AuthContext'; - -const queryClient = new QueryClient(); - -const mockSubmit = vi.fn(); - -describe('ScheduleForm Component', () => { - it('form inputs should be in the page', () => { - const { queryByText } = render( - - - - - - - - - - ); - - const btn = queryByText('Agendar Serviço'); - expect(btn).toBeInTheDocument(); - }); -}); diff --git a/src/features/schedules/components/schedule-table-item/index.tsx b/src/features/schedules/components/schedule-table-item/index.tsx index e74fd531..7b9ce0f0 100644 --- a/src/features/schedules/components/schedule-table-item/index.tsx +++ b/src/features/schedules/components/schedule-table-item/index.tsx @@ -7,14 +7,12 @@ interface ScheduleTableItemProps { schedule: Schedule | ScheduleOpen; selectedSchedules: (Schedule | ScheduleOpen)[]; setSelectedSchedules: Dispatch>; - workstation: Workstation | any; } export function ScheduleTableItem({ schedule, selectedSchedules, setSelectedSchedules, - workstation, }: ScheduleTableItemProps) { const isChecked = useMemo(() => { return selectedSchedules.findIndex((i) => i.id === schedule.id) !== -1; @@ -43,11 +41,9 @@ export function ScheduleTableItem({ onChange={handleCheckToggle} /> - {formatDate(schedule?.dateTime ?? '')} - {`${workstation?.name} - ${workstation?.city.name}`} {currentStatus ?? ''} {schedule?.issue?.requester ?? ''} - {workstation.phone} + {formatDate(schedule?.dateTime ?? '')} {schedule?.issue?.phone ?? ''} {schedule?.description ?? ''} diff --git a/src/features/schedules/components/schedule-table-item/schedule-table-item.spec.tsx b/src/features/schedules/components/schedule-table-item/schedule-table-item.spec.tsx deleted file mode 100644 index 9760079d..00000000 --- a/src/features/schedules/components/schedule-table-item/schedule-table-item.spec.tsx +++ /dev/null @@ -1,82 +0,0 @@ -import { ChakraProvider, Table } from '@chakra-ui/react'; -import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; -import { render, screen } from '@testing-library/react'; -import { BrowserRouter } from 'react-router-dom'; -import { vi } from 'vitest'; -import { AuthProvider } from '@/contexts/AuthContext'; -import { ScheduleTableItem } from '@/features/schedules/components/schedule-table-item'; -import { theme } from '@/styles/theme'; -import { Schedule, ScheduleStatus } from '@/features/schedules/types'; - -const schedule: Schedule = { - id: '1', - dateTime: 'string', - description: 'string', - status: ScheduleStatus.PENDENT, - alerts: [], - issue: { - id: '1', - requester: 'Mockerson', - phone: '61988554474', - city_id: '123', - workstation_id: '123', - email: 'mcok@email.com', - date: new Date(), - problem_category: { - id: '1', - name: 'Category Mock', - description: 'Category Mock', - problem_types: [ - { - id: '1', - name: 'Type Mock', - }, - ], - }, - problem_types: [ - { - id: '1', - name: 'Type Mock', - }, - ], - }, -}; - -const workstation = { - id: '1', - name: 'mockStation', - city: { id: '2', name: 'Goiás', state: 'Goiânia' }, - phone: '9999999999', - ip: '127.0.0.0', - gateway: 'mockGate', - is_regional: true, -}; - -const selectedSchedules: Schedule[] = []; - -const setSelectedSchedules = vi.fn(); - -describe('Schedule-table-item', () => { - it('should render correctly', () => { - render( - - - - - - -
-
-
-
-
- ); - - expect(screen.getByText('string')).toBeInTheDocument(); - }); -}); diff --git a/src/features/tutorials/components/tutorial-delete-form/tutorial-delete-form.spec.tsx b/src/features/tutorials/components/tutorial-delete-form/tutorial-delete-form.spec.tsx deleted file mode 100644 index e6790b9f..00000000 --- a/src/features/tutorials/components/tutorial-delete-form/tutorial-delete-form.spec.tsx +++ /dev/null @@ -1,48 +0,0 @@ -import { - screen, - render, - waitFor, - act, - fireEvent, - queryByText, -} from '@testing-library/react'; -import { vi } from 'vitest'; -import { BrowserRouter } from 'react-router-dom'; -import { ChakraProvider } from '@chakra-ui/react'; -import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; -import { DeleteTutorialForm } from '@/features/tutorials/components/tutorial-delete-form'; -import { AuthProvider } from '@/contexts/AuthContext'; -import { theme } from '@/styles/theme'; - -const mockedTutorial: string[] = ['1']; - -describe('TutorialDeleteForm', () => { - const queryClient = new QueryClient(); - const onClose = vi.fn(); - const onClear = vi.fn(); - const onDelete = vi.fn(); - - it('should have the correct button', async () => { - const { queryByText } = render( - - - - - - - - - - ); - - const btn = queryByText('Confirmar'); - if (btn) { - expect(btn).toBeInTheDocument(); - } - }); -}); diff --git a/src/features/tutorials/components/tutorial-form/index.tsx b/src/features/tutorials/components/tutorial-form/index.tsx index 0369dbda..cdf6a44f 100644 --- a/src/features/tutorials/components/tutorial-form/index.tsx +++ b/src/features/tutorials/components/tutorial-form/index.tsx @@ -130,7 +130,6 @@ export function TutorialForm({ id="fileinput" label="" type="file" - aria-label="Arquivo" {...register('file', { required: !isEditing, })} diff --git a/src/features/tutorials/components/tutorial-form/tutorial-form.spec.tsx b/src/features/tutorials/components/tutorial-form/tutorial-form.spec.tsx deleted file mode 100644 index 4c262d5c..00000000 --- a/src/features/tutorials/components/tutorial-form/tutorial-form.spec.tsx +++ /dev/null @@ -1,83 +0,0 @@ -import { - screen, - render, - waitFor, - act, - fireEvent, -} from '@testing-library/react'; -import { vi } from 'vitest'; -import { BrowserRouter } from 'react-router-dom'; -import { ChakraProvider } from '@chakra-ui/react'; -import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; -import { TutorialForm } from '@/features/tutorials/components/tutorial-form'; -import { Tutorial } from '@/features/tutorials/api/types'; -import { AuthProvider } from '@/contexts/AuthContext'; -import { theme } from '@/styles/theme'; - -const mockedTutorial: Tutorial = { - id: '1', - name: 'Criar ponto de rede', - filename: 'tutorial.pdf', - data: { - type: 'Buffer', - data: [1, 2, 3], - }, - category: { - id: '1', - name: 'Category 1', - }, -}; - -describe('TutorialForm', () => { - const queryClient = new QueryClient(); - - it('should have the correct data', () => { - render( - - - - - {}} - isSubmitting={false} - /> - - - - - ); - - expect(screen.getByLabelText('Nome do tutorial')).toHaveValue( - 'Criar ponto de rede' - ); - }); - - it('renders the form with initial values', () => { - const selectedTutorial = { - ...mockedTutorial, - }; - - render( - - - - - {}} - isSubmitting={false} - /> - - - - - ); - - expect(screen.getByLabelText('Nome do tutorial')).toHaveValue( - 'Criar ponto de rede' - ); - expect(screen.getByLabelText('Categoria')).toBeInTheDocument(); - expect(screen.getByLabelText('Arquivo')).toBeInTheDocument(); - }); -}); diff --git a/src/features/tutorials/components/tutorial-item-manager/tutorial-item-manager.spec.tsx b/src/features/tutorials/components/tutorial-item-manager/tutorial-item-manager.spec.tsx deleted file mode 100644 index bbda2d39..00000000 --- a/src/features/tutorials/components/tutorial-item-manager/tutorial-item-manager.spec.tsx +++ /dev/null @@ -1,79 +0,0 @@ -import { fireEvent, render } from '@testing-library/react'; -import { vi } from 'vitest'; -import { TutorialItemManager } from '@/features/tutorials/components/tutorial-item-manager'; -import { Tutorial } from '@/features/tutorials/api/types'; - -const mockedTutorial: Tutorial = { - id: '1', - name: 'Tutorial REDES', - filename: 'redes.pdf', - data: { - type: 'Buffer', - data: [1, 2, 3], - }, - category: { - id: '1', - name: 'Computadores 1', - }, -}; -const mockedOnEditFunction = vi.fn(() => {}); -const mockedOnDeleteFunction = vi.fn((tutorialId: string) => tutorialId); -const mockedOnCheckedFunction = vi.fn((tutorialId: string) => tutorialId); - -describe('TutorialItemManager', () => { - it('should render tutorial name and category', async () => { - const { findAllByText } = render( - - ); - - const tutorialName = await findAllByText(mockedTutorial.name); - expect(tutorialName[0]).toBeInTheDocument(); - - const tutorialCategory = await findAllByText(mockedTutorial.category.name); - expect(tutorialCategory[0]).toBeInTheDocument(); - }); - - it('should be able to delete a tutorial', async () => { - const { queryByLabelText } = render( - - ); - - const deleteButton = queryByLabelText(`Excluir ${mockedTutorial.name}`); - if (deleteButton) { - expect(deleteButton).toBeInTheDocument(); - } - }); - - it('should be able to edit a category', async () => { - const { queryByLabelText } = render( - - ); - - const EditButton = await queryByLabelText(`Editar ${mockedTutorial.name}`); - if (EditButton) { - fireEvent.click(EditButton); - expect(mockedOnEditFunction).toHaveBeenCalled(); - } - }); -}); diff --git a/src/features/users/components/user-form/user-form.spec.tsx b/src/features/users/components/user-form/user-form.spec.tsx deleted file mode 100644 index 67eed80b..00000000 --- a/src/features/users/components/user-form/user-form.spec.tsx +++ /dev/null @@ -1,64 +0,0 @@ -import { ChakraProvider } from '@chakra-ui/react'; -import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; -import { BrowserRouter } from 'react-router-dom'; -import { vi } from 'vitest'; -import { render } from '@testing-library/react'; -import { theme } from '@/styles/theme'; -import { UserForm } from '.'; -import { AuthProvider } from '@/contexts/AuthContext'; -import { User } from '../../api/types'; - -const queryClient = new QueryClient(); -const mockSubmit = vi.fn(); - -const mockUser: User = { - name: 'teste', - id: '1', - email: 'teste@gmail.com', - username: 'teste', - position: 'tech', - profile: 'USER', - cpf: '7338229104', - createdAt: '1710', - updatedAt: '1710', -}; - -describe('UserForm Component', () => { - it('should display save button', () => { - const { queryByText } = render( - - - - - - - - - - ); - - const btn = queryByText('Salvar'); - expect(btn).toBeInTheDocument(); - }); - - it('form inputs should be in the page', () => { - const { queryByLabelText } = render( - - - - - - - - - - ); - - const nameInput = queryByLabelText('Nome Completo'); - expect(nameInput).toBeInTheDocument(); - }); -}); diff --git a/src/pages/agendamentos_abertos/agendamentos_abertos.spec.tsx b/src/pages/agendamentos_abertos/agendamentos_abertos.spec.tsx deleted file mode 100644 index dadc45ec..00000000 --- a/src/pages/agendamentos_abertos/agendamentos_abertos.spec.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import { ChakraProvider } from '@chakra-ui/react'; -import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; -import { fireEvent, queryByText, render, screen } from '@testing-library/react'; -import { BrowserRouter } from 'react-router-dom'; -import { vi } from 'vitest'; -import { theme } from '@/styles/theme'; -import { AgendamentosAbertos } from './index'; -import { AuthProvider } from '@/contexts/AuthContext'; - -// eslint-disable-next-line import/no-extraneous-dependencies -import 'intersection-observer'; - -describe('Agendamento Aberto Page', () => { - const queryClient = new QueryClient(); - - it('should have a page external', async () => { - render( - - - - - - - - - - ); - - const pageTitle = screen.getByText('Agendamentos Abertos'); - expect(pageTitle).toBeInTheDocument(); - }); -}); diff --git a/src/pages/agendamentos_abertos/index.tsx b/src/pages/agendamentos_abertos/index.tsx index 0cee43c9..3e86da84 100644 --- a/src/pages/agendamentos_abertos/index.tsx +++ b/src/pages/agendamentos_abertos/index.tsx @@ -1,50 +1,22 @@ import { HStack, useDisclosure, Button } from '@chakra-ui/react'; import { useCallback, useState } from 'react'; -import { useNavigate } from 'react-router-dom'; +import { Link } from 'react-router-dom'; import { RefreshButton } from '@/components/action-buttons/refresh-button'; import { PageHeader } from '@/components/page-header'; -import { - useGetAllSchedules, - useGetAllSchedulesOpen, -} from '@/features/schedules/api/get-all-schedules'; +import { useGetAllSchedules } from '@/features/schedules/api/get-all-schedules'; import { ListView } from '@/components/list'; -import { - Schedule, - ScheduleStatus, - ScheduleOpen, -} from '@/features/schedules/types'; +import { Schedule, ScheduleStatus } from '@/features/schedules/types'; import { ScheduleItem } from '@/features/schedules/components/schedule-item'; import { useDeleteSchedule } from '@/features/schedules/api/delete-schedule'; import { ScheduleEditModal } from '@/features/schedules/components/schedule-edit-modal'; export function AgendamentosAbertos() { const { isOpen, onOpen, onClose } = useDisclosure(); - const [scheduleToEdit, setScheduleToEdit] = useState< - ScheduleOpen | Schedule - >(); + const [scheduleToEdit, setScheduleToEdit] = useState(); - const { - refetch: refetchSchedulesOpen, - data: schedulesOpen, - isLoading: isLoadingSchedulesOpen, - } = useGetAllSchedulesOpen(); - const { - refetch: refetchSchedules, - data: schedules, - isLoading: isLoadingSchedules, - } = useGetAllSchedules(); + const { data: schedules, isLoading, refetch } = useGetAllSchedules(); - const isLoading = isLoadingSchedulesOpen || isLoadingSchedules; - - const refetch = useCallback(async () => { - refetchSchedulesOpen(); - refetchSchedules(); - }, [refetchSchedulesOpen, refetchSchedules]); - - const allSchedules = - schedules && schedulesOpen ? [...schedules, ...schedulesOpen] : []; - - const filteredSchedules = allSchedules?.filter( + const filteredSchedules = schedules?.filter( (schedule) => schedule.status !== ('RESOLVIDO' as ScheduleStatus) ); @@ -72,7 +44,7 @@ export function AgendamentosAbertos() { }, [onClose]); const renderScheduleItem = useCallback( - (schedule: ScheduleOpen | Schedule) => ( + (schedule: Schedule) => ( - + - + items={ filteredSchedules && filteredSchedules.length > 0 ? filteredSchedules diff --git a/src/pages/chamados/chamados.spec.tsx b/src/pages/chamados/chamados.spec.tsx index 8ff725b0..ebd857f1 100644 --- a/src/pages/chamados/chamados.spec.tsx +++ b/src/pages/chamados/chamados.spec.tsx @@ -98,166 +98,109 @@ describe('sortIssues', () => { expect(sortedIssues).toEqual([]); }); - it('should sort the issues in descending order based on the date', () => { - const issues: Issue[] = [ - { - id: '1', - date: new Date('2021-09-01'), - requester: '', - phone: '', - city_id: '', - workstation_id: '', - email: '', - problem_category: { - id: '', - name: '', - description: '', - problem_types: [], - }, - problem_types: [], - }, - { - id: '2', - date: new Date('2021-08-15'), - requester: '', - phone: '', - city_id: '', - workstation_id: '', - email: '', - problem_category: { - id: '', - name: '', - description: '', - problem_types: [], - }, - problem_types: [], - }, - { - id: '3', - date: new Date('2021-08-30'), - requester: '', - phone: '', - city_id: '', - workstation_id: '', - email: '', - problem_category: { - id: '', - name: '', - description: '', - problem_types: [], - }, - problem_types: [], - }, - ]; - - const sortedIssues = sortIssues(issues); - - expect(sortedIssues).toEqual([ - { - id: '1', - date: new Date('2021-09-01'), - requester: '', - phone: '', - city_id: '', - workstation_id: '', - email: '', - problem_category: { - id: '', - name: '', - description: '', - problem_types: [], - }, - problem_types: [], - }, - { - id: '3', - date: new Date('2021-08-30'), - requester: '', - phone: '', - city_id: '', - workstation_id: '', - email: '', - problem_category: { - id: '', - name: '', - description: '', - problem_types: [], - }, - problem_types: [], - }, - { - id: '2', - date: new Date('2021-08-15'), - requester: '', - phone: '', - city_id: '', - workstation_id: '', - email: '', - problem_category: { - id: '', - name: '', - description: '', - problem_types: [], - }, - problem_types: [], - }, - ]); - }); - - it('should return the same array when the issues are already sorted', () => { - const issues: Issue[] = [ - { - id: '1', - date: new Date('2021-09-01'), - requester: '', - phone: '', - city_id: '', - workstation_id: '', - email: '', - problem_category: { - id: '', - name: '', - description: '', - problem_types: [], - }, - problem_types: [], - }, - { - id: '2', - date: new Date('2021-08-30'), - requester: '', - phone: '', - city_id: '', - workstation_id: '', - email: '', - problem_category: { - id: '', - name: '', - description: '', - problem_types: [], - }, - problem_types: [], - }, - { - id: '3', - date: new Date('2021-08-15'), - requester: '', - phone: '', - city_id: '', - workstation_id: '', - email: '', - problem_category: { - id: '', - name: '', - description: '', - problem_types: [], - }, - problem_types: [], - }, - ]; - - const sortedIssues = sortIssues(issues); - - expect(sortedIssues).toEqual(issues); - }); + // it('should sort issues in descending order based on the date property', () => { + // const issues: Issue[] = [ + // { + // id: '1', + // requester: 'Mockerson', + // phone: '61988554474', + // city_id: '123', + // workstation_id: '123', + // email: 'mockerson@mock.com', + // date: new Date(), + // problem_category: { + // id: '123', + // name: 'mockCategory', + // description: 'mockDesc', + // problem_types: [], + // }, + // problem_types: [], + // }, + // { + // id: '2', + // requester: 'Mockerson', + // phone: '61988554474', + // city_id: '123', + // workstation_id: '123', + // email: 'mockerson@mock.com', + // date: new Date(), + // problem_category: { + // id: '123', + // name: 'mockCategory', + // description: 'mockDesc', + // problem_types: [], + // }, + // problem_types: [], + // }, + // { + // id: '3', + // requester: 'Mockerson', + // phone: '61988554474', + // city_id: '123', + // workstation_id: '123', + // email: 'mockerson@mock.com', + // date: new Date(), + // problem_category: { + // id: '123', + // name: 'mockCategory', + // description: 'mockDesc', + // problem_types: [], + // }, + // problem_types: [], + // }, + // ]; + + // const sortedIssues = sortIssues(issues); + + // expect(sortedIssues).toEqual([ + // { + // id: '3', + // requester: 'Mockerson', + // phone: '61988554474', + // city_id: '123', + // workstation_id: '123', + // email: 'mockerson@mock.com', + // date: '2023-06-16T15:30:45.500Z', + // problem_category: { + // id: '123', + // name: 'mockCategory', + // description: 'mockDesc', + // problem_types: [], + // }, + // problem_types: [], + // }, + // { + // id: '1', + // requester: 'Mockerson', + // phone: '61988554474', + // city_id: '123', + // workstation_id: '123', + // email: 'mockerson@mock.com', + // date: '2023-06-15T15:30:45.500Z', + // problem_category: { + // id: '123', + // name: 'mockCategory', + // description: 'mockDesc', + // problem_types: [], + // }, + // problem_types: [], + // }, + // { + // id: '2', + // requester: 'Mockerson', + // phone: '61988554474', + // city_id: '123', + // workstation_id: '123', + // email: 'mockerson@mock.com', + // date: '2023-06-14T15:30:45.500Z', + // problem_category: { + // id: '123', + // name: 'mockCategory', + // description: 'mockDesc', + // problem_types: [], + // }, + // problem_types: [], + // }, + // ]); + // }); }); diff --git a/src/pages/chamados/index.tsx b/src/pages/chamados/index.tsx index 8ca311f7..33331c04 100644 --- a/src/pages/chamados/index.tsx +++ b/src/pages/chamados/index.tsx @@ -9,18 +9,20 @@ import { useDisclosure, } from '@chakra-ui/react'; import { Link } from 'react-router-dom'; -import { useCallback, useState } from 'react'; +import { useCallback, useEffect, useState } from 'react'; import { TiFilter } from 'react-icons/ti'; import { IoClose } from 'react-icons/io5'; import { RefreshButton } from '@/components/action-buttons/refresh-button'; import { PageHeader } from '@/components/page-header'; import { useGetAllIssues } from '@/features/issues/api/get-all-issues'; +import { useGetReport } from '@/features/reports/api/get-report'; import { Issue } from '@/features/issues/types'; import { Permission } from '@/components/permission'; import { ListView } from '@/components/list'; import { IssueItem } from '@/features/issues/components/issue-item'; import { useDeleteIssue } from '@/features/issues/api/delete-issue'; import { ScheduleModal } from '@/features/schedules/components/schedule-modal'; +import { toast } from '@/utils/toast'; export function sortIssues(issues: Issue[] | undefined): Issue[] { if (!issues) { @@ -41,8 +43,14 @@ export function Chamados() { isLoading: isLoadingIssues, refetch, } = useGetAllIssues(); - const { mutate: deleteIssue, isLoading: isRemovingIssue } = useDeleteIssue(); + const { + isLoading: isLoadingReport, + data: report, + mutate: getReport, + } = useGetReport({ + onSuccessCallBack: () => {}, + }); const onDelete = useCallback( (issueId: string) => { @@ -103,6 +111,41 @@ export function Chamados() { setEndDate(null); }, []); + const handleExport = useCallback(async () => { + if (!startDate || !endDate) { + toast.warning('Selecione um período para exportar o relatório'); + return; + } + + // Wait for report to be generated + await getReport({ + startDate, + endDate, + }); + + // Reset filter + clearFilter(); + }, [startDate, endDate, getReport, clearFilter]); + + useEffect(() => { + if (!isLoadingReport && report) { + const reportData = report.data; + const byteArray = new Uint8Array(reportData); + const blob = new Blob([byteArray], { type: 'application/pdf' }); + const fileUrl = URL.createObjectURL(blob); + const link = document.createElement('a'); + link.href = fileUrl; + link.download = `RELATÓRIO-${new Date().toLocaleString('pr-br', { + timeZone: 'America/Sao_Paulo', + })}.pdf`; + link.click(); + + URL.revokeObjectURL(fileUrl); + + console.log('Relatório gerado com sucesso!'); + } + }, [isLoadingReport, report]); + let filteredIssues = issues; if (isFiltering) { @@ -122,6 +165,9 @@ export function Chamados() { + diff --git a/src/pages/cidades/index.tsx b/src/pages/cidades/index.tsx index c27868b4..2a5a6f60 100644 --- a/src/pages/cidades/index.tsx +++ b/src/pages/cidades/index.tsx @@ -57,17 +57,13 @@ export function Cities() { let i = 0; setAux(i); const interval = setInterval(() => { - const fetchData = async () => { - await refetch?.(); - if (i >= 3) { - setAux(0); - clearInterval(interval); - } - i += 1; - setAux(i); - }; - - fetchData(); + refetch?.(); + if (i >= 3) { + setAux(i - i); + clearInterval(interval); + } + i += 1; + setAux(i); }, 1000); return () => clearInterval(interval); }, [modalClosed, refetch]); diff --git a/src/pages/exportacao_agendamentos/exportacao-agendamentos.spec.tsx b/src/pages/exportacao_agendamentos/exportacao-agendamentos.spec.tsx deleted file mode 100644 index e661b00c..00000000 --- a/src/pages/exportacao_agendamentos/exportacao-agendamentos.spec.tsx +++ /dev/null @@ -1,53 +0,0 @@ -import { vi } from 'vitest'; -import { fireEvent, render, screen } from '@testing-library/react'; -import { BrowserRouter } from 'react-router-dom'; -import { ChakraProvider } from '@chakra-ui/react'; -import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; -import jsPDF from 'jspdf'; -import { ScheduleExport } from '@/pages/exportacao_agendamentos'; -import { AuthProvider } from '@/contexts/AuthContext'; -import { theme } from '@/styles/theme'; -import 'jspdf-autotable'; - -const mockfunction = vi.fn(() => 'mocked function'); -vi.mock('jspdf'); -vi.mock('jspdf-autotable'); - -const queryClient = new QueryClient(); - -describe('ScheduleExport Page', () => { - it('should be in the page', async () => { - const { queryByText } = render( - - - - - - - - - - ); - - const btn = await queryByText('Exportar'); - expect(btn).toBeInTheDocument(); - }); - it('should call handleExportSchedules function when export button is clicked', () => { - const { getByText } = render( - - - - - - - - - - ); - const exportButton = getByText('Exportar'); - if (exportButton) { - fireEvent.click(exportButton); - expect(jsPDF).toHaveBeenCalled(); - } - }); -}); diff --git a/src/pages/exportacao_agendamentos/index.tsx b/src/pages/exportacao_agendamentos/index.tsx index fa9bf78f..14a3fb64 100644 --- a/src/pages/exportacao_agendamentos/index.tsx +++ b/src/pages/exportacao_agendamentos/index.tsx @@ -18,60 +18,37 @@ import { useGetAllSchedules } from '@/features/schedules/api/get-all-schedules'; import { ScheduleTableItem } from '@/features/schedules/components/schedule-table-item'; import { Schedule } from '@/features/schedules/types'; import { formatDate } from '@/utils/format-date'; -import { useGetAllWorkstations } from '@/features/workstations/api/get-all-workstations'; export function ScheduleExport() { const { data: schedules, refetch } = useGetAllSchedules(); const [selectedSchedules, setSelectedSchedules] = useState([]); - const { data: workstations } = useGetAllWorkstations(); - function handleExportSchedules() { // eslint-disable-next-line new-cap - const doc = new jsPDF('landscape'); + const doc = new jsPDF(); const tableColumn = [ - 'Data', - 'Posto de Trabalho', 'Status', 'Solicitante', - 'Telefone do Posto', - 'Telefone do Solicitante', + 'Data', + 'Telefone', 'Descrição', ]; const tableRows: string[][] = []; selectedSchedules.forEach((schedule) => { - const workstation = workstations?.find((workstation) => { - return workstation?.id === schedule?.issue.workstation_id; - }); - const ticketData: string[] | any = [ - formatDate(schedule.dateTime), - `${workstation?.name} - ${workstation?.city.name}`, + const ticketData = [ schedule.status, schedule.issue.requester, - workstation?.phone, + formatDate(schedule.dateTime), schedule.issue.phone, schedule.description, ]; tableRows.push(ticketData); }); - /* Cria a tabela e altera as margens do documento */ - (doc as any).autoTable(tableColumn, tableRows, { - startY: 20, - margin: 10, - columnStyles: { - 1: { cellWidth: 40 }, // Define o tamanho das colunas - 2: { cellWidth: 30 }, - 3: { cellWidth: 40 }, - 4: { cellWidth: 30 }, - 5: { cellWidth: 30 }, - 6: { minCellWidth: 40 }, - }, - }); - - doc.text('Lista de agendamentos', 10, 15); + (doc as any).autoTable(tableColumn, tableRows, { startY: 20 }); + doc.text('Lista de agendamentos', 14, 15); doc.save(`agendamentos.pdf`); } @@ -92,12 +69,10 @@ export function ScheduleExport() { - Data - Posto de Trabalho Status Solicitante - Telefone do Posto - Telefone do Solicitante + Data + Telefone Descrição @@ -108,9 +83,6 @@ export function ScheduleExport() { schedule={schedule} selectedSchedules={selectedSchedules} setSelectedSchedules={setSelectedSchedules} - workstation={workstations?.find((workstation) => { - return workstation?.id === schedule?.issue.workstation_id; - })} /> ))} diff --git a/src/pages/gerenciar-tutorial/gerenciar-tutoriais.spec.tsx b/src/pages/gerenciar-tutorial/gerenciar-tutoriais.spec.tsx deleted file mode 100644 index a6ffd5b7..00000000 --- a/src/pages/gerenciar-tutorial/gerenciar-tutoriais.spec.tsx +++ /dev/null @@ -1,206 +0,0 @@ -import { ChakraProvider } from '@chakra-ui/react'; -import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; -import { fireEvent, render, screen } from '@testing-library/react'; -import { BrowserRouter } from 'react-router-dom'; -import { vi } from 'vitest'; -import { AuthProvider } from '@/contexts/AuthContext'; -import { GerenciarTutoriais } from '@/pages/gerenciar-tutorial'; -import { theme } from '@/styles/theme'; -import { - getAllTutorials, - GetAllTutorialsResponse, -} from '@/features/tutorials/api/get-all-tutorials'; - -// eslint-disable-next-line import/no-extraneous-dependencies -import 'intersection-observer'; -import { Tutorial } from '@/features/tutorials/api/types'; - -describe('Manage-Tutorial Page', () => { - const queryClient = new QueryClient(); - let tutorials: GetAllTutorialsResponse; - - beforeAll(async () => { - tutorials = await getAllTutorials(); - }); - - it('should have a page external', async () => { - render( - - - - - - - - - - ); - - const pageTitle = screen.getByText('Gerenciar tutoriais'); - expect(pageTitle).toBeInTheDocument(); - }); - - it('should have an input for searching tutorials', async () => { - render( - - - - - - - - - - ); - - const searchInput = screen.getByPlaceholderText('Pesquisar tutoriais'); - expect(searchInput).toBeInTheDocument(); - }); - - it('should display a list of tutorials', async () => { - render( - - - - - - - - - - ); - - tutorials.forEach(async (tutorial: Tutorial) => { - const tutorialName = screen.getByText(tutorial.name); - expect(tutorialName).toBeInTheDocument(); - }); - }); - - it('should have a select for filtering tutorials by category', async () => { - render( - - - - - - - - - - ); - - const selectElement = screen.getByLabelText('Filtrar por categoria'); - expect(selectElement).toBeInTheDocument(); - }); - - it('should have a button to create a new tutorial', async () => { - const { queryByText } = render( - - - - - - - - - - ); - - const btn = await queryByText('Criar Tutorial'); - if (btn) { - expect(btn).toBeInTheDocument(); - } - }); - - it('should have a button to delete selected tutorials', async () => { - const { queryByText } = render( - - - - - - - - - - ); - - const btn = await queryByText('Excluir tutoriais'); - if (btn) { - expect(btn).toBeInTheDocument(); - } - }); - - it('should have a button to delete selected tutorials', async () => { - const { queryByText } = render( - - - - - - - - - - ); - - const btn = await queryByText('Excluir tutoriais'); - if (btn) { - expect(btn).toBeInTheDocument(); - } - }); - - it('should display a refresh button', async () => { - const { findByRole } = render( - - - - - - - - - - ); - - const button = await findByRole('button', { name: 'Atualizar Dados' }); - expect(button).toBeInTheDocument(); - }); - it('it should not call "Selecionar tutoriais"', () => { - const handleSelectMock = vi.fn(); - render( - - - - - - - - - - ); - - expect(handleSelectMock).not.toHaveBeenCalled(); - }); - it('it should not call "limpar"', () => { - const resetSelectedTutorialsMock = vi.fn(); - render( - - - - - - - - - - ); - - // Tem que chamar duas vezes o botão "Selecionar tutoriais" - fireEvent.click(screen.getByText('Selecionar tutoriais')); - - fireEvent.click(screen.getByText('Selecionar tutoriais')); - - expect(resetSelectedTutorialsMock).not.toHaveBeenCalled(); - }); -}); diff --git a/src/pages/gerenciar-tutorial/index.tsx b/src/pages/gerenciar-tutorial/index.tsx index eda1f2c6..ee56d709 100644 --- a/src/pages/gerenciar-tutorial/index.tsx +++ b/src/pages/gerenciar-tutorial/index.tsx @@ -225,7 +225,7 @@ export function GerenciarTutoriais() {