chrysopedia/frontend/src/components/ConfirmModal.tsx
jlightner 4969935c76 feat: Added ConfirmModal component, Edit As button with write-mode conf…
- "frontend/src/components/ConfirmModal.tsx"
- "frontend/src/components/ConfirmModal.module.css"
- "frontend/src/api/auth.ts"
- "frontend/src/context/AuthContext.tsx"
- "frontend/src/pages/AdminUsers.tsx"
- "frontend/src/pages/AdminUsers.module.css"
- "frontend/src/components/ImpersonationBanner.tsx"
- "frontend/src/components/ImpersonationBanner.module.css"

GSD-Task: S07/T02
2026-04-04 06:27:38 +00:00

66 lines
1.6 KiB
TypeScript

import { useEffect, useCallback } from "react";
import styles from "./ConfirmModal.module.css";
interface ConfirmModalProps {
open: boolean;
title: string;
message: string;
confirmLabel?: string;
cancelLabel?: string;
onConfirm: () => void;
onCancel: () => void;
variant?: "warning" | "danger";
}
export default function ConfirmModal({
open,
title,
message,
confirmLabel = "Confirm",
cancelLabel = "Cancel",
onConfirm,
onCancel,
variant = "warning",
}: ConfirmModalProps) {
const handleKeyDown = useCallback(
(e: KeyboardEvent) => {
if (e.key === "Escape") onCancel();
},
[onCancel],
);
useEffect(() => {
if (!open) return;
document.addEventListener("keydown", handleKeyDown);
return () => document.removeEventListener("keydown", handleKeyDown);
}, [open, handleKeyDown]);
if (!open) return null;
return (
<div
className={styles.backdrop}
onClick={onCancel}
role="dialog"
aria-modal="true"
aria-label={title}
>
<div className={styles.card} onClick={(e) => e.stopPropagation()}>
<h2 className={styles.title}>{title}</h2>
<p className={styles.message}>{message}</p>
<div className={styles.actions}>
<button className={styles.cancelBtn} onClick={onCancel}>
{cancelLabel}
</button>
<button
className={styles.confirmBtn}
data-variant={variant}
onClick={onConfirm}
>
{confirmLabel}
</button>
</div>
</div>
</div>
);
}