diff --git a/package-lock.json b/package-lock.json index bee4696..67359f7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,6 +18,7 @@ "react": "^19.2.4", "react-dom": "^19.2.4", "react-hook-form": "^7.72.1", + "react-hot-toast": "^2.6.0", "react-router-dom": "^7.14.1", "zod": "^4.3.6", "zustand": "^5.0.12" @@ -1658,7 +1659,6 @@ "version": "3.2.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", - "devOptional": true, "license": "MIT" }, "node_modules/debug": { @@ -2228,6 +2228,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/goober": { + "version": "2.1.19", + "resolved": "https://registry.npmjs.org/goober/-/goober-2.1.19.tgz", + "integrity": "sha512-U7veizMqxyKlM58+Z5j2ngJBH/r9siDmxpvNxSw0PylF6WQvrASJEZrxh1hidRBJc2jqoBVSyOban5u8m+6Rxg==", + "license": "MIT", + "peerDependencies": { + "csstype": "^3.0.10" + } + }, "node_modules/gopd": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", @@ -3063,6 +3072,23 @@ "react": "^16.8.0 || ^17 || ^18 || ^19" } }, + "node_modules/react-hot-toast": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/react-hot-toast/-/react-hot-toast-2.6.0.tgz", + "integrity": "sha512-bH+2EBMZ4sdyou/DPrfgIouFpcRLCJ+HoCA32UoAYHn6T3Ur5yfcDCeSr5mwldl6pFOsiocmrXMuoCJ1vV8bWg==", + "license": "MIT", + "dependencies": { + "csstype": "^3.1.3", + "goober": "^2.1.16" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "react": ">=16", + "react-dom": ">=16" + } + }, "node_modules/react-router": { "version": "7.14.1", "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.14.1.tgz", diff --git a/package.json b/package.json index 9d50695..8ed03d3 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,7 @@ "react": "^19.2.4", "react-dom": "^19.2.4", "react-hook-form": "^7.72.1", + "react-hot-toast": "^2.6.0", "react-router-dom": "^7.14.1", "zod": "^4.3.6", "zustand": "^5.0.12" diff --git a/src/App.tsx b/src/App.tsx index 1b7c9d3..6a52748 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,17 +1,19 @@ -import { useIsFetching, useIsMutating } from '@tanstack/react-query' +// import { useIsFetching, useIsMutating } from '@tanstack/react-query' import { RouterProvider } from 'react-router-dom' import { useEffect } from 'react' -import { Loader } from './shared/components/Loader' +// import { Loader } from './shared/components/Loader' import { router } from './router' import { useAuthStore } from './store/authStore' import { getMe, refreshToken } from './features/auth/api/auth.api' +import { Toaster } from 'react-hot-toast' const App = () => { - const isFetching = useIsFetching() - const isMutating = useIsMutating() + + // const isFetching = useIsFetching() + // const isMutating = useIsMutating() const { setAuth, setAccessToken, accessToken } = useAuthStore() - const isLoading = isFetching > 0 || isMutating > 0 + // const isLoading = isFetching > 0 || isMutating > 0 useEffect(() => { const initAuth = async () => { @@ -69,7 +71,8 @@ const App = () => { return ( <> - {isLoading && } + + {/* {isLoading && } */} ) diff --git a/src/features/cases/api/case-api.ts b/src/features/cases/api/case-api.ts index 8a8be19..8146d6a 100644 --- a/src/features/cases/api/case-api.ts +++ b/src/features/cases/api/case-api.ts @@ -22,13 +22,12 @@ const withTotalPages = ( // ── Get All Cases (paginated) ───────────────────────────────────── export const getCases = async ( - organizationId: string, page: number = 1, pageSize: number = 10 ): Promise>> => { const response = await AxiosInstance.get>>( '/Case/getAll', - { params: { organizationId, page, pageSize } } + { params: { page, pageSize } } ); return withTotalPages(response.data); }; diff --git a/src/features/cases/components/CaseDetailsModal.tsx b/src/features/cases/components/CaseDetailsModal.tsx index c29ffb7..c097bd4 100644 --- a/src/features/cases/components/CaseDetailsModal.tsx +++ b/src/features/cases/components/CaseDetailsModal.tsx @@ -1,8 +1,8 @@ import '../styles/case-details-modal.css'; -import type { GetCaseDto } from '../types/case.types'; +import type { CaseDto } from '../types/case.types'; interface Props { - caseItem: GetCaseDto; + caseItem: CaseDto; onEdit: () => void; onClose: () => void; } @@ -86,10 +86,10 @@ export default function CaseDetailsModal({ caseItem, onEdit, onClose }: Props) {
Petitioners
{caseItem.petitioners?.length > 0 ? (
- {caseItem.petitioners.map((name) => ( - + {caseItem.petitioners.map(p => ( + - {name} + {p.name} ))}
diff --git a/src/features/cases/components/case-list/CaseList.tsx b/src/features/cases/components/case-list/CaseList.tsx index e8c5b7a..88ec4af 100644 --- a/src/features/cases/components/case-list/CaseList.tsx +++ b/src/features/cases/components/case-list/CaseList.tsx @@ -1,5 +1,4 @@ import { useState, useCallback } from 'react'; - import CasePageHeader from './CasePageHeader'; import CaseStatsBar from './CaseStatsBar'; import CaseFilterTabs from './CaseFilterTabs'; @@ -8,7 +7,6 @@ import CaseTable from './CaseTable'; import CaseDrawer from '../case-drawer/CaseDrawer'; import CreateCaseModal from '../create-case/CreateCaseModal'; import CaseDetailsModal from '../CaseDetailsModal'; - import { useGetAllCases, useSearchCases, useDeleteCase } from '../../hooks/useCases'; import { useCaseModal } from '../../hooks/useCaseModal'; import type { CaseDto, SearchParams } from '../../types/case.types'; // ✅ CaseDto only, no GetCaseDto diff --git a/src/features/cases/hooks/useCases.ts b/src/features/cases/hooks/useCases.ts index b1e3d7b..35b2aef 100644 --- a/src/features/cases/hooks/useCases.ts +++ b/src/features/cases/hooks/useCases.ts @@ -4,25 +4,22 @@ import { createCase, deleteCase, getCases, searchCases } from '../api/case-api'; import { usePetitioners } from '../../petitioners/hooks/usePetitioners'; import { useGetDepartments } from '../../departments/hooks/useDepartments'; import { useGetCourts } from '../../courts/hooks/useCourts'; -import { useAuthStore } from '../../../store/authStore'; +import { toastService } from '../../../lib/toast.service' + // ── Query Key Factory ───────────────────────────────────────────── export const caseKeys = { all: () => ['cases'] as const, - list: (orgId: string, page: number, size: number) => ['cases', 'list', orgId, page, size] as const, + list: (page: number, size: number) => ['cases', 'list', page, size] as const, search: (params: SearchParams) => ['cases', 'search', params] as const, }; // ── Cases ───────────────────────────────────────────────────────── export const useGetAllCases = (page: number = 1, pageSize: number = 10) => { - const { user } = useAuthStore(); - const orgId = user?.organizationId ?? ''; - return useQuery({ - queryKey: caseKeys.list(orgId, page, pageSize), - queryFn: () => getCases(orgId, page, pageSize), - enabled: !!orgId, + queryKey: caseKeys.list(page, pageSize), + queryFn: () => getCases(page, pageSize), }); }; @@ -37,14 +34,19 @@ export const useSearchCases = (params: SearchParams) => { export const useCreateCase = () => { const qc = useQueryClient(); - const { user } = useAuthStore(); + // const { user } = useAuthStore(); return useMutation({ mutationFn: (data: CreateCaseDto) => createCase({ ...data, - organizationId: user?.organizationId ?? data.organizationId, }), - onSuccess: () => qc.invalidateQueries({ queryKey: caseKeys.all() }), + onSuccess: (response) => { + toastService.success(response.message); + qc.invalidateQueries({ queryKey: caseKeys.all() }); + }, + onError: (error: unknown) => { + toastService.error(error); + } }); }; diff --git a/src/features/documents/hooks/useDocuments.ts b/src/features/documents/hooks/useDocuments.ts index b5e506c..1628d8b 100644 --- a/src/features/documents/hooks/useDocuments.ts +++ b/src/features/documents/hooks/useDocuments.ts @@ -1,6 +1,7 @@ import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query' import { documentsApi } from '../api/documents' import type { UploadDocumentDto } from '../types' +import { toastService } from '../../../lib/toast.service' const DOCUMENT_KEYS = { byCase: (caseId: string) => ['documents', 'case', caseId], @@ -29,17 +30,15 @@ export function useUploadDocument(caseId: string) { return useMutation({ mutationFn: (dto: UploadDocumentDto) => documentsApi.upload(dto), onSuccess: (response) => { - alert(response?.message); - + toastService.success(response.message); queryClient.invalidateQueries({ queryKey: DOCUMENT_KEYS.byCase(caseId), }); }, - - onError: (error: any) => { - alert(error.message); - }, - }); + onError: (error: unknown) => { + toastService.error(error); + } + }) } export function useDeleteDocument(caseId: string) { @@ -47,10 +46,14 @@ export function useDeleteDocument(caseId: string) { return useMutation({ mutationFn: (id: string) => documentsApi.delete(id), - onSuccess: () => { + onSuccess: (response) => { + toastService.success(response.message); queryClient.invalidateQueries({ queryKey: DOCUMENT_KEYS.byCase(caseId), }) }, + onError: (error: unknown) => { + toastService.error(error); + } }) } \ No newline at end of file diff --git a/src/features/followup/hooks/useFollowups.ts b/src/features/followup/hooks/useFollowups.ts index 2237577..4f4416e 100644 --- a/src/features/followup/hooks/useFollowups.ts +++ b/src/features/followup/hooks/useFollowups.ts @@ -1,8 +1,7 @@ -// hooks/useFollowups.ts - import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query' import { followupApi } from '../api/followupApi' import type { CreateFollowUpDto, UpdateFollowUpDto, FollowUpPageParams } from '../types/followup.types' +import { toastService } from '../../../lib/toast.service' export const followupKeys = { all: ['followups'] as const, @@ -30,9 +29,13 @@ export const useCreateFollowUp = () => { const qc = useQueryClient() return useMutation({ mutationFn: (data: CreateFollowUpDto) => followupApi.create(data), - onSuccess: () => { + onSuccess: (response) => { + toastService.success(response.message); qc.invalidateQueries({ queryKey: followupKeys.all }) }, + onError: (error: unknown) => { + toastService.error(error); + } }) } @@ -50,8 +53,12 @@ export const useDeleteFollowUp = () => { const qc = useQueryClient() return useMutation({ mutationFn: (id: string) => followupApi.delete(id), - onSuccess: () => { + onSuccess: (response) => { + toastService.success(response.message); qc.invalidateQueries({ queryKey: followupKeys.all }) }, - }) + onError: (error: unknown) => { + toastService.error(error); + } + }); } \ No newline at end of file diff --git a/src/lib/toast.service.ts b/src/lib/toast.service.ts new file mode 100644 index 0000000..a91ad3e --- /dev/null +++ b/src/lib/toast.service.ts @@ -0,0 +1,29 @@ +import toast from 'react-hot-toast'; +import axios from 'axios'; + +const success = (message: string) => + toast.success(message, { + style: { + background: '#22c55e', + color: '#fff', + fontWeight: '500', + }, + iconTheme: { primary: '#fff', secondary: '#22c55e' }, + }); + +const error = (error: unknown) => { + const msg = axios.isAxiosError(error) + ? error.response?.data?.message ?? 'Something went wrong' + : 'Something went wrong'; + + toast.error(msg, { + style: { + background: '#ef4444', + color: '#fff', + fontWeight: '500', + }, + iconTheme: { primary: '#fff', secondary: '#ef4444' }, + }); +}; + +export const toastService = { success, error }; \ No newline at end of file