feat(queryKey) : queryKey applied with one approach

This commit is contained in:
2025-09-05 01:50:15 +05:30
parent 2652cc71a1
commit 22c344cd9e
8 changed files with 99 additions and 64 deletions

View File

@@ -51,6 +51,17 @@ interface ClaimsRecentTableProps {
patientId?: number; patientId?: number;
} }
// 🔑 exported base key
export const QK_CLAIMS_BASE = ["claims-recent"] as const;
// helper for specific pages/patient scope
export const qkClaimsRecent = (opts: {
patientId?: number | null;
page: number;
}) =>
opts.patientId
? ([...QK_CLAIMS_BASE, "patient", opts.patientId, opts.page] as const)
: ([...QK_CLAIMS_BASE, "global", opts.page] as const);
export default function ClaimsRecentTable({ export default function ClaimsRecentTable({
allowEdit, allowEdit,
allowView, allowView,
@@ -89,17 +100,17 @@ export default function ClaimsRecentTable({
setCurrentPage(1); setCurrentPage(1);
}, [patientId]); }, [patientId]);
const getClaimsQueryKey = () => const queryKey = qkClaimsRecent({
patientId patientId: patientId ?? undefined,
? ["claims-recent", "patient", patientId, currentPage] page: currentPage,
: ["claims-recent", "global", currentPage]; });
const { const {
data: claimsData, data: claimsData,
isLoading, isLoading,
isError, isError,
} = useQuery<ClaimApiResponse, Error>({ } = useQuery<ClaimApiResponse, Error>({
queryKey: getClaimsQueryKey(), queryKey,
queryFn: async () => { queryFn: async () => {
const endpoint = patientId const endpoint = patientId
@@ -134,9 +145,7 @@ export default function ClaimsRecentTable({
description: "Claim updated successfully!", description: "Claim updated successfully!",
variant: "default", variant: "default",
}); });
queryClient.invalidateQueries({ queryClient.invalidateQueries({ queryKey: QK_CLAIMS_BASE });
queryKey: getClaimsQueryKey(),
});
}, },
onError: (error) => { onError: (error) => {
toast({ toast({
@@ -154,9 +163,7 @@ export default function ClaimsRecentTable({
}, },
onSuccess: () => { onSuccess: () => {
setIsDeleteClaimOpen(false); setIsDeleteClaimOpen(false);
queryClient.invalidateQueries({ queryClient.invalidateQueries({ queryKey: QK_CLAIMS_BASE });
queryKey: getClaimsQueryKey(),
});
toast({ toast({
title: "Success", title: "Success",
description: "Claim deleted successfully!", description: "Claim deleted successfully!",

View File

@@ -56,6 +56,12 @@ interface PatientTableProps {
onSearchChange?: (searchTerm: string) => void; onSearchChange?: (searchTerm: string) => void;
} }
// 🔑 exported base key
export const QK_PATIENTS_BASE = ["patients"] as const;
// helper (optional) mirrors your current key structure
export const qkPatients = (page: number, search: string) =>
[...QK_PATIENTS_BASE, { page, search }] as const;
export function PatientTable({ export function PatientTable({
allowEdit, allowEdit,
allowView, allowView,
@@ -101,18 +107,14 @@ export function PatientTable({
} }
}; };
const searchKeyPart = debouncedSearchCriteria?.searchTerm || "recent";
const { const {
data: patientsData, data: patientsData,
isLoading, isLoading,
isError, isError,
} = useQuery<PatientApiResponse, Error>({ } = useQuery<PatientApiResponse, Error>({
queryKey: [ queryKey: qkPatients(currentPage, searchKeyPart),
"patients",
{
page: currentPage,
search: debouncedSearchCriteria?.searchTerm || "recent",
},
],
queryFn: async () => { queryFn: async () => {
const trimmedTerm = debouncedSearchCriteria?.searchTerm?.trim(); const trimmedTerm = debouncedSearchCriteria?.searchTerm?.trim();
const isSearch = trimmedTerm && trimmedTerm.length > 0; const isSearch = trimmedTerm && trimmedTerm.length > 0;
@@ -176,17 +178,11 @@ export function PatientTable({
const res = await apiRequest("PUT", `/api/patients/${id}`, patient); const res = await apiRequest("PUT", `/api/patients/${id}`, patient);
return res.json(); return res.json();
}, },
onSuccess: () => { onSuccess: async () => {
setIsAddPatientOpen(false); setIsAddPatientOpen(false);
queryClient.invalidateQueries({
queryKey: [ // this query every page,
"patients", await queryClient.invalidateQueries({ queryKey: QK_PATIENTS_BASE });
{
page: currentPage,
search: debouncedSearchCriteria?.searchTerm || "recent",
},
],
});
toast({ toast({
title: "Success", title: "Success",
description: "Patient updated successfully!", description: "Patient updated successfully!",
@@ -207,17 +203,10 @@ export function PatientTable({
const res = await apiRequest("DELETE", `/api/patients/${id}`); const res = await apiRequest("DELETE", `/api/patients/${id}`);
return; return;
}, },
onSuccess: () => { onSuccess: async () => {
setIsDeletePatientOpen(false); setIsDeletePatientOpen(false);
queryClient.invalidateQueries({ await queryClient.invalidateQueries({ queryKey: QK_PATIENTS_BASE });
queryKey: [
"patients",
{
page: currentPage,
search: debouncedSearchCriteria?.searchTerm || "recent",
},
],
});
toast({ toast({
title: "Success", title: "Success",
description: "Patient deleted successfully!", description: "Patient deleted successfully!",

View File

@@ -3,9 +3,9 @@ import * as React from "react";
import { Card, CardContent } from "@/components/ui/card"; import { Card, CardContent } from "@/components/ui/card";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { Upload, Image as ImageIcon, X, Plus, Minus } from "lucide-react"; import { Upload, Image as ImageIcon, X, Plus } from "lucide-react";
import { useMutation } from "@tanstack/react-query"; import { useMutation } from "@tanstack/react-query";
import { apiRequest } from "@/lib/queryClient"; import { apiRequest, queryClient } from "@/lib/queryClient";
import { toast } from "@/hooks/use-toast"; import { toast } from "@/hooks/use-toast";
import { import {
@@ -14,7 +14,8 @@ import {
flexRender, flexRender,
ColumnDef, ColumnDef,
} from "@tanstack/react-table"; } from "@tanstack/react-table";
import { convertOCRDate } from "@/utils/dateUtils"; import { QK_PAYMENTS_RECENT_BASE } from "@/components/payments/payments-recent-table";
import { QK_PATIENTS_BASE } from "@/components/patients/patient-table";
// ---------------- Types ---------------- // ---------------- Types ----------------
@@ -211,6 +212,20 @@ export default function PaymentOCRBlock() {
if (!res.ok) throw new Error("Failed to save OCR payments"); if (!res.ok) throw new Error("Failed to save OCR payments");
toast({ title: "Saved", description: "OCR rows saved successfully" }); toast({ title: "Saved", description: "OCR rows saved successfully" });
// 🔄 REFRESH both tables (all pages/filters)
await Promise.all([
queryClient.invalidateQueries({ queryKey: QK_PAYMENTS_RECENT_BASE }), // all recent payments
queryClient.invalidateQueries({ queryKey: QK_PATIENTS_BASE }), // recent patients list
]);
// ✅ CLEAR UI: remove files and table rows
setUploadedImages([]);
setRows([]);
setColumns([]);
setError(null);
setIsDragging(false);
if (fileInputRef.current) fileInputRef.current.value = "";
} catch (err: any) { } catch (err: any) {
toast({ toast({
title: "Error", title: "Error",

View File

@@ -58,6 +58,22 @@ interface PaymentsRecentTableProps {
patientId?: number; patientId?: number;
} }
// 🔑 exported base key (so others can invalidate all pages/filters)
export const QK_PAYMENTS_RECENT_BASE = ["payments-recent"] as const;
// 🔑 exported helper for specific pages/scopes
export const qkPaymentsRecent = (opts: {
patientId?: number | null;
page: number;
}) =>
opts.patientId
? ([
...QK_PAYMENTS_RECENT_BASE,
"patient",
opts.patientId,
opts.page,
] as const)
: ([...QK_PAYMENTS_RECENT_BASE, "global", opts.page] as const);
export default function PaymentsRecentTable({ export default function PaymentsRecentTable({
allowEdit, allowEdit,
allowDelete, allowDelete,
@@ -94,17 +110,17 @@ export default function PaymentsRecentTable({
} }
}; };
const getPaymentsQueryKey = () => const queryKey = qkPaymentsRecent({
patientId patientId: patientId ?? undefined,
? ["payments-recent", "patient", patientId, currentPage] page: currentPage,
: ["payments-recent", "global", currentPage]; });
const { const {
data: paymentsData, data: paymentsData,
isLoading, isLoading,
isError, isError,
} = useQuery<PaymentApiResponse>({ } = useQuery<PaymentApiResponse>({
queryKey: getPaymentsQueryKey(), queryKey,
queryFn: async () => { queryFn: async () => {
const endpoint = patientId const endpoint = patientId
? `/api/payments/patient/${patientId}?limit=${paymentsPerPage}&offset=${offset}` ? `/api/payments/patient/${patientId}?limit=${paymentsPerPage}&offset=${offset}`
@@ -141,8 +157,9 @@ export default function PaymentsRecentTable({
description: "Payment updated successfully!", description: "Payment updated successfully!",
}); });
queryClient.invalidateQueries({ // 🔄 refresh this table page
queryKey: getPaymentsQueryKey(), await queryClient.invalidateQueries({
queryKey: QK_PAYMENTS_RECENT_BASE,
}); });
// Fetch updated payment and set into local state // Fetch updated payment and set into local state
@@ -193,8 +210,8 @@ export default function PaymentsRecentTable({
description: "Payment Status updated successfully!", description: "Payment Status updated successfully!",
}); });
queryClient.invalidateQueries({ await queryClient.invalidateQueries({
queryKey: getPaymentsQueryKey(), queryKey: QK_PAYMENTS_RECENT_BASE,
}); });
// Fetch updated payment and set into local state // Fetch updated payment and set into local state
@@ -233,12 +250,14 @@ export default function PaymentsRecentTable({
} }
return response.json(); return response.json();
}, },
onSuccess: () => { onSuccess: async () => {
toast({ toast({
title: "Success", title: "Success",
description: "Payment updated successfully!", description: "Payment updated successfully!",
}); });
queryClient.invalidateQueries({ queryKey: getPaymentsQueryKey() }); await queryClient.invalidateQueries({
queryKey: QK_PAYMENTS_RECENT_BASE,
});
}, },
onError: (error: any) => { onError: (error: any) => {
toast({ toast({
@@ -271,10 +290,10 @@ export default function PaymentsRecentTable({
return; return;
}, },
onSuccess: () => { onSuccess: async () => {
setIsDeletePaymentOpen(false); setIsDeletePaymentOpen(false);
queryClient.invalidateQueries({ await queryClient.invalidateQueries({
queryKey: getPaymentsQueryKey(), queryKey: QK_PAYMENTS_RECENT_BASE,
}); });
toast({ toast({
title: "Deleted", title: "Deleted",

View File

@@ -20,7 +20,9 @@ import {
} from "@/redux/slices/seleniumClaimSubmitTaskSlice"; } from "@/redux/slices/seleniumClaimSubmitTaskSlice";
import { SeleniumTaskBanner } from "@/components/ui/selenium-task-banner"; import { SeleniumTaskBanner } from "@/components/ui/selenium-task-banner";
import { formatLocalDate } from "@/utils/dateUtils"; import { formatLocalDate } from "@/utils/dateUtils";
import ClaimsRecentTable from "@/components/claims/claims-recent-table"; import ClaimsRecentTable, {
QK_CLAIMS_BASE,
} from "@/components/claims/claims-recent-table";
import ClaimsOfPatientModal from "@/components/claims/claims-of-patient-table"; import ClaimsOfPatientModal from "@/components/claims/claims-of-patient-table";
import { import {
Claim, Claim,
@@ -128,10 +130,7 @@ export default function ClaimsPage() {
return res.json(); return res.json();
}, },
onSuccess: () => { onSuccess: () => {
queryClient.invalidateQueries({ queryClient.invalidateQueries({ queryKey: QK_CLAIMS_BASE });
queryKey: ["claims-recent"],
exact: false,
});
toast({ toast({
title: "Claim created successfully", title: "Claim created successfully",

View File

@@ -29,11 +29,14 @@ import {
Patient, Patient,
UpdateAppointment, UpdateAppointment,
} from "@repo/db/types"; } from "@repo/db/types";
import { QK_PATIENTS_BASE } from "@/components/patients/patient-table";
// Type for the ref to access modal methods // Type for the ref to access modal methods
type AddPatientModalRef = { type AddPatientModalRef = {
shouldSchedule: boolean; shouldSchedule: boolean;
shouldClaim: boolean;
navigateToSchedule: (patientId: number) => void; navigateToSchedule: (patientId: number) => void;
navigateToClaim: (patientId: number) => void;
}; };
export default function Dashboard() { export default function Dashboard() {
@@ -84,7 +87,8 @@ export default function Dashboard() {
}, },
onSuccess: (newPatient) => { onSuccess: (newPatient) => {
setIsAddPatientOpen(false); setIsAddPatientOpen(false);
queryClient.invalidateQueries({ queryKey: ["patients"] });
queryClient.invalidateQueries({ queryKey: QK_PATIENTS_BASE });
toast({ toast({
title: "Success", title: "Success",
description: "Patient added successfully!", description: "Patient added successfully!",

View File

@@ -24,6 +24,7 @@ import { SeleniumTaskBanner } from "@/components/ui/selenium-task-banner";
import { formatLocalDate, parseLocalDate } from "@/utils/dateUtils"; import { formatLocalDate, parseLocalDate } from "@/utils/dateUtils";
import { InsertPatient, Patient } from "@repo/db/types"; import { InsertPatient, Patient } from "@repo/db/types";
import { DateInput } from "@/components/ui/dateInput"; import { DateInput } from "@/components/ui/dateInput";
import { QK_PATIENTS_BASE } from "@/components/patients/patient-table";
export default function InsuranceEligibilityPage() { export default function InsuranceEligibilityPage() {
const { user } = useAuth(); const { user } = useAuth();
@@ -77,7 +78,7 @@ export default function InsuranceEligibilityPage() {
return res.json(); return res.json();
}, },
onSuccess: () => { onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ["patients"] }); queryClient.invalidateQueries({ queryKey: QK_PATIENTS_BASE });
toast({ toast({
title: "Success", title: "Success",
description: "Patient added successfully!", description: "Patient added successfully!",

View File

@@ -1,6 +1,6 @@
import { useState, useRef } from "react"; import { useState, useRef } from "react";
import { useMutation } from "@tanstack/react-query"; import { useMutation } from "@tanstack/react-query";
import { PatientTable } from "@/components/patients/patient-table"; import { PatientTable, qkPatients } from "@/components/patients/patient-table";
import { AddPatientModal } from "@/components/patients/add-patient-modal"; import { AddPatientModal } from "@/components/patients/add-patient-modal";
import { FileUploadZone } from "@/components/file-upload/file-upload-zone"; import { FileUploadZone } from "@/components/file-upload/file-upload-zone";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
@@ -18,6 +18,7 @@ import { useAuth } from "@/hooks/use-auth";
import useExtractPdfData from "@/hooks/use-extractPdfData"; import useExtractPdfData from "@/hooks/use-extractPdfData";
import { useLocation } from "wouter"; import { useLocation } from "wouter";
import { InsertPatient, Patient } from "@repo/db/types"; import { InsertPatient, Patient } from "@repo/db/types";
import { QK_PATIENTS_BASE } from "@/components/patients/patient-table";
// Type for the ref to access modal methods // Type for the ref to access modal methods
type AddPatientModalRef = { type AddPatientModalRef = {
@@ -52,7 +53,7 @@ export default function PatientsPage() {
}, },
onSuccess: (newPatient) => { onSuccess: (newPatient) => {
setIsAddPatientOpen(false); setIsAddPatientOpen(false);
queryClient.invalidateQueries({ queryKey: ["patients"] }); queryClient.invalidateQueries({ queryKey: QK_PATIENTS_BASE });
toast({ toast({
title: "Success", title: "Success",
description: "Patient added successfully!", description: "Patient added successfully!",