actions half done
This commit is contained in:
189
apps/Frontend/src/components/claims/claim-view-modal.tsx
Normal file
189
apps/Frontend/src/components/claims/claim-view-modal.tsx
Normal file
@@ -0,0 +1,189 @@
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogDescription,
|
||||
} from "@/components/ui/dialog";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { ClaimUncheckedCreateInputObjectSchema } from "@repo/db/usedSchemas";
|
||||
import React from "react";
|
||||
import { z } from "zod";
|
||||
|
||||
//creating types out of schema auto generated.
|
||||
type Claim = z.infer<typeof ClaimUncheckedCreateInputObjectSchema>;
|
||||
|
||||
type ClaimWithServiceLines = Claim & {
|
||||
serviceLines: {
|
||||
id: number;
|
||||
claimId: number;
|
||||
procedureCode: string;
|
||||
procedureDate: Date;
|
||||
oralCavityArea: string | null;
|
||||
toothNumber: string | null;
|
||||
toothSurface: string | null;
|
||||
billedAmount: number;
|
||||
}[];
|
||||
};
|
||||
|
||||
type ClaimViewModalProps = {
|
||||
isOpen: boolean;
|
||||
onOpenChange: (open: boolean) => void;
|
||||
onClose: () => void;
|
||||
claim: ClaimWithServiceLines | null;
|
||||
onEditClaim: (claim: ClaimWithServiceLines) => void;
|
||||
};
|
||||
|
||||
export default function ClaimViewModal({
|
||||
isOpen,
|
||||
onOpenChange,
|
||||
onClose,
|
||||
claim,
|
||||
onEditClaim,
|
||||
}: ClaimViewModalProps) {
|
||||
return (
|
||||
<Dialog open={isOpen} onOpenChange={onOpenChange}>
|
||||
<DialogContent className="sm:max-w-[700px] max-h-[90vh] overflow-y-auto">
|
||||
|
||||
<DialogHeader>
|
||||
<DialogTitle>Claim Details</DialogTitle>
|
||||
<DialogDescription>
|
||||
Detailed view of the selected claim.
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
|
||||
{claim && (
|
||||
<div className="space-y-4">
|
||||
<div className="flex items-center space-x-4">
|
||||
<div className="h-16 w-16 rounded-full bg-blue-600 text-white flex items-center justify-center text-xl font-medium">
|
||||
{claim.patientName.charAt(0)}
|
||||
</div>
|
||||
<div>
|
||||
<h3 className="text-xl font-semibold">{claim.patientName}</h3>
|
||||
<p className="text-gray-500">
|
||||
Claim ID: {claim.id?.toString().padStart(4, "0")}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4 pt-4">
|
||||
<div>
|
||||
<h4 className="font-medium text-gray-900">Basic Information</h4>
|
||||
<div className="mt-2 space-y-2">
|
||||
<p>
|
||||
<span className="text-gray-500">Member ID:</span>{" "}
|
||||
{claim.memberId}
|
||||
</p>
|
||||
<p>
|
||||
<span className="text-gray-500">Date of Birth:</span>{" "}
|
||||
{new Date(claim.dateOfBirth).toLocaleDateString()}
|
||||
</p>
|
||||
<p>
|
||||
<span className="text-gray-500">Service Date:</span>{" "}
|
||||
{new Date(claim.serviceDate).toLocaleDateString()}
|
||||
</p>
|
||||
<p>
|
||||
<span className="text-gray-500">Status:</span>{" "}
|
||||
<span
|
||||
className={`font-medium ${
|
||||
claim.status === "APPROVED"
|
||||
? "text-green-600"
|
||||
: claim.status === "CANCELLED"
|
||||
? "text-red-600"
|
||||
: claim.status === "REVIEW"
|
||||
? "text-yellow-600"
|
||||
: "text-gray-600"
|
||||
}`}
|
||||
>
|
||||
{claim?.status
|
||||
? claim.status.charAt(0).toUpperCase() +
|
||||
claim.status.slice(1).toLowerCase()
|
||||
: "Unknown"}
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h4 className="font-medium text-gray-900">Insurance</h4>
|
||||
<div className="mt-2 space-y-2">
|
||||
<p>
|
||||
<span className="text-gray-500">Provider:</span>{" "}
|
||||
{claim.insuranceProvider || "N/A"}
|
||||
</p>
|
||||
<p>
|
||||
<span className="text-gray-500">Remarks:</span>{" "}
|
||||
{claim.remarks || "N/A"}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h4 className="font-medium text-gray-900 pt-4">Service Lines</h4>
|
||||
<div className="mt-2 space-y-3">
|
||||
{claim.serviceLines.length > 0 ? (
|
||||
claim.serviceLines.map((line, index) => (
|
||||
<div
|
||||
key={line.id}
|
||||
className="border p-3 rounded-md bg-gray-50"
|
||||
>
|
||||
<p>
|
||||
<span className="text-gray-500">Procedure Code:</span>{" "}
|
||||
{line.procedureCode}
|
||||
</p>
|
||||
<p>
|
||||
<span className="text-gray-500">Procedure Date:</span>{" "}
|
||||
{new Date(line.procedureDate).toLocaleDateString()}
|
||||
</p>
|
||||
{line.oralCavityArea && (
|
||||
<p>
|
||||
<span className="text-gray-500">
|
||||
Oral Cavity Area:
|
||||
</span>{" "}
|
||||
{line.oralCavityArea}
|
||||
</p>
|
||||
)}
|
||||
{line.toothNumber && (
|
||||
<p>
|
||||
<span className="text-gray-500">Tooth Number:</span>{" "}
|
||||
{line.toothNumber}
|
||||
</p>
|
||||
)}
|
||||
{line.toothSurface && (
|
||||
<p>
|
||||
<span className="text-gray-500">Tooth Surface:</span>{" "}
|
||||
{line.toothSurface}
|
||||
</p>
|
||||
)}
|
||||
<p>
|
||||
<span className="text-gray-500">Billed Amount:</span> $
|
||||
{line.billedAmount.toFixed(2)}
|
||||
</p>
|
||||
</div>
|
||||
))
|
||||
) : (
|
||||
<p className="text-gray-500">No service lines available.</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex justify-end space-x-2 pt-4">
|
||||
<Button variant="outline" onClick={() => onOpenChange(false)}>
|
||||
Close
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => {
|
||||
onOpenChange(false);
|
||||
onEditClaim(claim);
|
||||
}}
|
||||
>
|
||||
Edit Claim
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
@@ -41,6 +41,7 @@ import { Avatar, AvatarFallback } from "@/components/ui/avatar";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { formatDateToHumanReadable } from "@/utils/dateUtils";
|
||||
import { Card, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import ClaimViewModal from "./claim-view-modal";
|
||||
|
||||
//creating types out of schema auto generated.
|
||||
type Claim = z.infer<typeof ClaimUncheckedCreateInputObjectSchema>;
|
||||
@@ -99,9 +100,9 @@ export default function ClaimsRecentTable({
|
||||
const claimsPerPage = 5;
|
||||
const offset = (currentPage - 1) * claimsPerPage;
|
||||
|
||||
const [currentClaim, setCurrentClaim] = useState<Claim | undefined>(
|
||||
undefined
|
||||
);
|
||||
const [currentClaim, setCurrentClaim] = useState<
|
||||
ClaimWithServiceLines | undefined
|
||||
>(undefined);
|
||||
const [selectedClaimId, setSelectedClaimId] = useState<number | null>(null);
|
||||
|
||||
const handleSelectClaim = (claim: Claim) => {
|
||||
@@ -170,17 +171,17 @@ export default function ClaimsRecentTable({
|
||||
},
|
||||
});
|
||||
|
||||
const handleEditClaim = (claim: Claim) => {
|
||||
const handleEditClaim = (claim: ClaimWithServiceLines) => {
|
||||
setCurrentClaim(claim);
|
||||
setIsEditClaimOpen(true);
|
||||
};
|
||||
|
||||
const handleViewClaim = (claim: Claim) => {
|
||||
const handleViewClaim = (claim: ClaimWithServiceLines) => {
|
||||
setCurrentClaim(claim);
|
||||
setIsViewClaimOpen(true);
|
||||
};
|
||||
|
||||
const handleDeleteClaim = (claim: Claim) => {
|
||||
const handleDeleteClaim = (claim: ClaimWithServiceLines) => {
|
||||
setCurrentClaim(claim);
|
||||
setIsDeleteClaimOpen(true);
|
||||
};
|
||||
@@ -464,6 +465,16 @@ export default function ClaimsRecentTable({
|
||||
entityName={currentClaim?.patientName}
|
||||
/>
|
||||
|
||||
{isViewClaimOpen && currentClaim && (
|
||||
<ClaimViewModal
|
||||
isOpen={isViewClaimOpen}
|
||||
onClose={() => setIsViewClaimOpen(false)}
|
||||
onOpenChange={(open) => setIsViewClaimOpen(open)}
|
||||
onEditClaim={(claim) => handleEditClaim(claim)}
|
||||
claim={currentClaim}
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* Pagination */}
|
||||
{totalPages > 1 && (
|
||||
<div className="bg-white px-4 py-3 border-t border-gray-200">
|
||||
|
||||
Reference in New Issue
Block a user