diff --git a/src/components/ApprovalStatusWidget.tsx b/src/components/ApprovalStatusWidget.tsx
new file mode 100644
index 0000000..45d7ba5
--- /dev/null
+++ b/src/components/ApprovalStatusWidget.tsx
@@ -0,0 +1,110 @@
+import { ClockIcon, CheckCircleIcon, XCircleIcon } from "./icons/StatusIcons";
+
+interface ApprovalRole {
+ id: string;
+ name: string;
+ avatar?: string;
+}
+
+interface ApprovalStatusWidgetProps {
+ required: ApprovalRole[];
+ given: ApprovalRole[];
+ pending: ApprovalRole[];
+}
+
+export function ApprovalStatusWidget({
+ required,
+ given,
+ pending,
+}: ApprovalStatusWidgetProps) {
+ const getInitial = (name: string): string => {
+ return name.charAt(0).toUpperCase();
+ };
+
+ const renderRole = (
+ role: ApprovalRole,
+ status: "pending" | "approved" | "rejected"
+ ) => {
+ const statusConfig = {
+ pending: { icon: ClockIcon, label: "Pending" },
+ approved: { icon: CheckCircleIcon, label: "Approved" },
+ rejected: { icon: XCircleIcon, label: "Rejected" },
+ };
+
+ const { icon: IconComponent, label } = statusConfig[status];
+
+ return (
+
+
+ {role.avatar ? (
+

+ ) : (
+
+ {getInitial(role.name)}
+
+ )}
+
+
+
+
+
+
+ {label}
+
+
+ );
+ };
+
+ return (
+
+ {required.length > 0 && (
+
+
+ Required Approvals
+
+
+ {required.map((role) => renderRole(role, "approved"))}
+
+
+ )}
+
+ {given.length > 0 && (
+
+
+ Given Approvals
+
+
+ {given.map((role) => renderRole(role, "approved"))}
+
+
+ )}
+
+ {pending.length > 0 && (
+
+
+ Pending Approvals
+
+
+ {pending.map((role) => renderRole(role, "pending"))}
+
+
+ )}
+
+ {required.length === 0 && given.length === 0 && pending.length === 0 && (
+
+
No approvals to display
+
+ )}
+
+ );
+}
diff --git a/src/components/icons/StatusIcons.tsx b/src/components/icons/StatusIcons.tsx
index 0bedc1c..855091f 100644
--- a/src/components/icons/StatusIcons.tsx
+++ b/src/components/icons/StatusIcons.tsx
@@ -21,3 +21,9 @@ export const TrashIcon = () => (
);
+
+export const XCircleIcon = () => (
+
+);
diff --git a/src/pages/MyDisputesPage.tsx b/src/pages/MyDisputesPage.tsx
new file mode 100644
index 0000000..ca61d7e
--- /dev/null
+++ b/src/pages/MyDisputesPage.tsx
@@ -0,0 +1,219 @@
+import { useState, useMemo } from "react";
+import { useNavigate } from "react-router-dom";
+import { useApiQuery } from "../hooks/useApiQuery";
+import { EscrowStatusBadge } from "../components/ui/EscrowStatusBadge";
+
+interface Dispute {
+ id: string;
+ petName: string;
+ opponentName: string;
+ status: string;
+ createdAt: string;
+}
+
+interface DisputesResponse {
+ disputes: Dispute[];
+ total: number;
+ page: number;
+ pageSize: number;
+}
+
+const ITEMS_PER_PAGE = 10;
+
+export default function MyDisputesPage() {
+ const navigate = useNavigate();
+ const [currentPage, setCurrentPage] = useState(1);
+
+ const { data, isLoading, isError } = useApiQuery(
+ ["disputes", currentPage],
+ () =>
+ fetch(`/api/disputes?page=${currentPage}&pageSize=${ITEMS_PER_PAGE}`).then(
+ (res) => res.json()
+ )
+ );
+
+ const disputes = data?.disputes || [];
+ const total = data?.total || 0;
+ const totalPages = Math.ceil(total / ITEMS_PER_PAGE);
+
+ const formatDate = (dateString: string): string => {
+ const date = new Date(dateString);
+ return date.toLocaleDateString("en-US", {
+ year: "numeric",
+ month: "short",
+ day: "numeric",
+ });
+ };
+
+ if (isLoading) {
+ return (
+
+
+
+ My Disputes
+
+
+ {Array.from({ length: 5 }).map((_, i) => (
+
+ ))}
+
+
+
+ );
+ }
+
+ if (isError || !data) {
+ return (
+
+
+
+ My Disputes
+
+
+
+ Failed to load disputes. Please try again.
+
+
+
+
+ );
+ }
+
+ return (
+
+
+
+ My Disputes
+
+
+ {total} dispute{total !== 1 ? "s" : ""}
+
+
+ {disputes.length === 0 ? (
+
+
+
+ No disputes yet
+
+
+ Active disputes will appear here
+
+
+ ) : (
+ <>
+
+ {disputes.map((dispute) => (
+
+ ))}
+
+
+ {totalPages > 1 && (
+
+
+
+
+ {Array.from({ length: totalPages }).map((_, i) => {
+ const page = i + 1;
+ const isCurrentPage = page === currentPage;
+ if (
+ page === 1 ||
+ page === totalPages ||
+ (page >= currentPage - 1 && page <= currentPage + 1)
+ ) {
+ return (
+
+ );
+ } else if (
+ (page === 2 && currentPage > 3) ||
+ (page === totalPages - 1 && currentPage < totalPages - 2)
+ ) {
+ return (
+
+ ...
+
+ );
+ }
+ })}
+
+
+
+
+ )}
+ >
+ )}
+
+
+ );
+}