fix: react-doctor exhaustive-deps 3→0, prefer-use-effect-event 3→0 (useEffectEvent for modal cancel handlers), role-supports-aria-props 3→0 (aria-pressed/aria-current on buttons)

This commit is contained in:
Nora
2026-06-26 05:53:17 -06:00
parent e3cdc6deb9
commit ed5afe4b21
8 changed files with 45 additions and 21 deletions
@@ -1,6 +1,6 @@
"use client"; "use client";
import { useState, useCallback, useEffect, useRef } from "react"; import { useState, useCallback, useEffect, useRef, useEffectEvent } from "react";
import { getAbandonedCarts, manuallyCloseAbandonedCart, resendAbandonedCartEmail, type AbandonedCart } from "@/actions/email-automation/abandoned-cart"; import { getAbandonedCarts, manuallyCloseAbandonedCart, resendAbandonedCartEmail, type AbandonedCart } from "@/actions/email-automation/abandoned-cart";
type Props = { brandId: string }; type Props = { brandId: string };
@@ -197,6 +197,10 @@ export default function AbandonedCartDashboard({ brandId }: Props) {
function CartDetailModal({ cart, onClose }: { cart: AbandonedCart | null; onClose: () => void }) { function CartDetailModal({ cart, onClose }: { cart: AbandonedCart | null; onClose: () => void }) {
const dialogRef = useRef<HTMLDialogElement>(null); const dialogRef = useRef<HTMLDialogElement>(null);
const onCloseEvent = useEffectEvent(() => {
onClose();
});
useEffect(() => { useEffect(() => {
const dialog = dialogRef.current; const dialog = dialogRef.current;
if (!dialog) return; if (!dialog) return;
@@ -204,13 +208,13 @@ function CartDetailModal({ cart, onClose }: { cart: AbandonedCart | null; onClos
if (!cart && dialog.open) dialog.close(); if (!cart && dialog.open) dialog.close();
const onCancel = (e: Event) => { const onCancel = (e: Event) => {
e.preventDefault(); e.preventDefault();
onClose(); onCloseEvent();
}; };
dialog.addEventListener("cancel", onCancel); dialog.addEventListener("cancel", onCancel);
return () => { return () => {
dialog.removeEventListener("cancel", onCancel); dialog.removeEventListener("cancel", onCancel);
}; };
}, [cart, onClose]); }, [cart]);
if (!cart) return null; if (!cart) return null;
+2 -2
View File
@@ -152,7 +152,7 @@ export default function BrandSelector({
<li> <li>
<button <button
type="button" type="button"
aria-selected={!activeBrand} aria-pressed={!activeBrand}
onClick={() => selectBrand(null)} onClick={() => selectBrand(null)}
className="w-full flex items-center gap-2 px-3 py-2 text-xs text-left transition-colors hover:bg-white/5" className="w-full flex items-center gap-2 px-3 py-2 text-xs text-left transition-colors hover:bg-white/5"
style={{ style={{
@@ -185,7 +185,7 @@ export default function BrandSelector({
<li key={b.id}> <li key={b.id}>
<button <button
type="button" type="button"
aria-selected={isActive} aria-pressed={isActive}
onClick={() => selectBrand(b.id)} onClick={() => selectBrand(b.id)}
className="w-full flex items-center gap-2 px-3 py-2 text-xs text-left transition-colors hover:bg-white/5" className="w-full flex items-center gap-2 px-3 py-2 text-xs text-left transition-colors hover:bg-white/5"
style={{ style={{
+1 -1
View File
@@ -370,7 +370,7 @@ function CommandPaletteDialog({ onClose }: { onClose: () => void }) {
<li key={entry.id} className="list-none"> <li key={entry.id} className="list-none">
<button <button
type="button" type="button"
aria-selected={isSelected} aria-current={isSelected ? "true" : undefined}
onClick={() => navigate(entry.href)} onClick={() => navigate(entry.href)}
onMouseEnter={() => setSelected(i)} onMouseEnter={() => setSelected(i)}
style={{ style={{
+7 -3
View File
@@ -1,6 +1,6 @@
"use client"; "use client";
import { useCallback, useEffect, useRef, useState, useSyncExternalStore } from "react"; import { useCallback, useEffect, useRef, useState, useSyncExternalStore, useEffectEvent } from "react";
import Image from "next/image"; import Image from "next/image";
import { createPortal } from "react-dom"; import { createPortal } from "react-dom";
@@ -140,19 +140,23 @@ export default function ProductFormModal({
// parent's React state stays in sync with the native close behavior. // parent's React state stays in sync with the native close behavior.
const dialogRef = useRef<HTMLDialogElement>(null); const dialogRef = useRef<HTMLDialogElement>(null);
const onCloseEvent = useEffectEvent(() => {
onClose();
});
useEffect(() => { useEffect(() => {
const dialog = dialogRef.current; const dialog = dialogRef.current;
if (!dialog) return; if (!dialog) return;
if (!dialog.open) dialog.showModal(); if (!dialog.open) dialog.showModal();
const onCancel = (e: Event) => { const onCancel = (e: Event) => {
e.preventDefault(); e.preventDefault();
onClose(); onCloseEvent();
}; };
dialog.addEventListener("cancel", onCancel); dialog.addEventListener("cancel", onCancel);
return () => { return () => {
dialog.removeEventListener("cancel", onCancel); dialog.removeEventListener("cancel", onCancel);
}; };
}, [open, onClose]); }, [open]);
const handleFile = useCallback( const handleFile = useCallback(
async (file: File) => { async (file: File) => {
+7 -3
View File
@@ -1,6 +1,6 @@
"use client"; "use client";
import { useState, useCallback, useTransition, useEffect, useRef } from "react"; import { useState, useCallback, useTransition, useEffect, useRef, useEffectEvent } from "react";
import { createPortal } from "react-dom"; import { createPortal } from "react-dom";
import Image from "next/image"; import Image from "next/image";
import { useRouter } from "next/navigation"; import { useRouter } from "next/navigation";
@@ -390,6 +390,10 @@ function TableView({
init(); init();
}, []); }, []);
const onDeleteCancelEvent = useEffectEvent(() => {
onDeleteCancel();
});
useEffect(() => { useEffect(() => {
if (!deleteConfirm) return; if (!deleteConfirm) return;
const dialog = popupDialogRef.current; const dialog = popupDialogRef.current;
@@ -397,13 +401,13 @@ function TableView({
if (!dialog.open) dialog.showModal(); if (!dialog.open) dialog.showModal();
const onCancel = (e: Event) => { const onCancel = (e: Event) => {
e.preventDefault(); e.preventDefault();
onDeleteCancel(); onDeleteCancelEvent();
}; };
dialog.addEventListener("cancel", onCancel); dialog.addEventListener("cancel", onCancel);
return () => { return () => {
dialog.removeEventListener("cancel", onCancel); dialog.removeEventListener("cancel", onCancel);
}; };
}, [deleteConfirm, onDeleteCancel]); }, [deleteConfirm]);
// Track the previous deleteConfirm value so we can adjust menuPos // Track the previous deleteConfirm value so we can adjust menuPos
// inline during render when the prop changes — avoids a stale frame // inline during render when the prop changes — avoids a stale frame
@@ -1,6 +1,6 @@
"use client"; "use client";
import { useState, useEffect, useRef } from "react"; import { useState, useEffect, useRef, useEffectEvent } from "react";
import Image from "next/image"; import Image from "next/image";
import { LotDetail } from "@/actions/route-trace/lots"; import { LotDetail } from "@/actions/route-trace/lots";
@@ -91,16 +91,20 @@ export default function StickerPreviewModal({ lot, onClose }: { lot: LotDetail;
}; };
}, []); }, []);
const onCloseEvent = useEffectEvent(() => {
onClose();
});
useEffect(() => { useEffect(() => {
const dialog = dialogRef.current; const dialog = dialogRef.current;
if (!dialog) return; if (!dialog) return;
const handleCancel = (e: Event) => { const handleCancel = (e: Event) => {
e.preventDefault(); e.preventDefault();
onClose(); onCloseEvent();
}; };
dialog.addEventListener("cancel", handleCancel); dialog.addEventListener("cancel", handleCancel);
return () => dialog.removeEventListener("cancel", handleCancel); return () => dialog.removeEventListener("cancel", handleCancel);
}, [onClose]); }, []);
const handleBackdropClick = (e: React.MouseEvent) => { const handleBackdropClick = (e: React.MouseEvent) => {
const dialog = dialogRef.current; const dialog = dialogRef.current;
+7 -3
View File
@@ -1,6 +1,6 @@
"use client"; "use client";
import { useState, useEffect, useRef } from "react"; import { useState, useEffect, useRef, useEffectEvent } from "react";
import { type WholesaleOrder, recordWholesaleDeposit } from "@/actions/wholesale"; import { type WholesaleOrder, recordWholesaleDeposit } from "@/actions/wholesale";
type Props = { type Props = {
@@ -26,16 +26,20 @@ export default function DepositModal({ order, onClose, onFulfilled }: Props) {
}; };
}, []); }, []);
const onCloseEvent = useEffectEvent(() => {
onClose();
});
useEffect(() => { useEffect(() => {
const dialog = dialogRef.current; const dialog = dialogRef.current;
if (!dialog) return; if (!dialog) return;
const handleCancel = (e: Event) => { const handleCancel = (e: Event) => {
e.preventDefault(); e.preventDefault();
onClose(); onCloseEvent();
}; };
dialog.addEventListener("cancel", handleCancel); dialog.addEventListener("cancel", handleCancel);
return () => dialog.removeEventListener("cancel", handleCancel); return () => dialog.removeEventListener("cancel", handleCancel);
}, [onClose]); }, []);
const handleBackdropClick = (e: React.MouseEvent) => { const handleBackdropClick = (e: React.MouseEvent) => {
const dialog = dialogRef.current; const dialog = dialogRef.current;
@@ -1,6 +1,6 @@
"use client"; "use client";
import { useEffect, useRef } from "react"; import { useEffect, useRef, useEffectEvent } from "react";
import { type WholesaleOrder } from "@/actions/wholesale"; import { type WholesaleOrder } from "@/actions/wholesale";
type Props = { type Props = {
@@ -38,16 +38,20 @@ export default function OrderDetailsModal({ order, onClose, onFulfill, onRecordD
}; };
}, []); }, []);
const onCloseEvent = useEffectEvent(() => {
onClose();
});
useEffect(() => { useEffect(() => {
const dialog = dialogRef.current; const dialog = dialogRef.current;
if (!dialog) return; if (!dialog) return;
const handleCancel = (e: Event) => { const handleCancel = (e: Event) => {
e.preventDefault(); e.preventDefault();
onClose(); onCloseEvent();
}; };
dialog.addEventListener("cancel", handleCancel); dialog.addEventListener("cancel", handleCancel);
return () => dialog.removeEventListener("cancel", handleCancel); return () => dialog.removeEventListener("cancel", handleCancel);
}, [onClose]); }, []);
const handleBackdropClick = (e: React.MouseEvent) => { const handleBackdropClick = (e: React.MouseEvent) => {
const dialog = dialogRef.current; const dialog = dialogRef.current;