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";
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";
type Props = { brandId: string };
@@ -197,6 +197,10 @@ export default function AbandonedCartDashboard({ brandId }: Props) {
function CartDetailModal({ cart, onClose }: { cart: AbandonedCart | null; onClose: () => void }) {
const dialogRef = useRef<HTMLDialogElement>(null);
const onCloseEvent = useEffectEvent(() => {
onClose();
});
useEffect(() => {
const dialog = dialogRef.current;
if (!dialog) return;
@@ -204,13 +208,13 @@ function CartDetailModal({ cart, onClose }: { cart: AbandonedCart | null; onClos
if (!cart && dialog.open) dialog.close();
const onCancel = (e: Event) => {
e.preventDefault();
onClose();
onCloseEvent();
};
dialog.addEventListener("cancel", onCancel);
return () => {
dialog.removeEventListener("cancel", onCancel);
};
}, [cart, onClose]);
}, [cart]);
if (!cart) return null;
+2 -2
View File
@@ -152,7 +152,7 @@ export default function BrandSelector({
<li>
<button
type="button"
aria-selected={!activeBrand}
aria-pressed={!activeBrand}
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"
style={{
@@ -185,7 +185,7 @@ export default function BrandSelector({
<li key={b.id}>
<button
type="button"
aria-selected={isActive}
aria-pressed={isActive}
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"
style={{
+1 -1
View File
@@ -370,7 +370,7 @@ function CommandPaletteDialog({ onClose }: { onClose: () => void }) {
<li key={entry.id} className="list-none">
<button
type="button"
aria-selected={isSelected}
aria-current={isSelected ? "true" : undefined}
onClick={() => navigate(entry.href)}
onMouseEnter={() => setSelected(i)}
style={{
+7 -3
View File
@@ -1,6 +1,6 @@
"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 { createPortal } from "react-dom";
@@ -140,19 +140,23 @@ export default function ProductFormModal({
// parent's React state stays in sync with the native close behavior.
const dialogRef = useRef<HTMLDialogElement>(null);
const onCloseEvent = useEffectEvent(() => {
onClose();
});
useEffect(() => {
const dialog = dialogRef.current;
if (!dialog) return;
if (!dialog.open) dialog.showModal();
const onCancel = (e: Event) => {
e.preventDefault();
onClose();
onCloseEvent();
};
dialog.addEventListener("cancel", onCancel);
return () => {
dialog.removeEventListener("cancel", onCancel);
};
}, [open, onClose]);
}, [open]);
const handleFile = useCallback(
async (file: File) => {
+7 -3
View File
@@ -1,6 +1,6 @@
"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 Image from "next/image";
import { useRouter } from "next/navigation";
@@ -390,6 +390,10 @@ function TableView({
init();
}, []);
const onDeleteCancelEvent = useEffectEvent(() => {
onDeleteCancel();
});
useEffect(() => {
if (!deleteConfirm) return;
const dialog = popupDialogRef.current;
@@ -397,13 +401,13 @@ function TableView({
if (!dialog.open) dialog.showModal();
const onCancel = (e: Event) => {
e.preventDefault();
onDeleteCancel();
onDeleteCancelEvent();
};
dialog.addEventListener("cancel", onCancel);
return () => {
dialog.removeEventListener("cancel", onCancel);
};
}, [deleteConfirm, onDeleteCancel]);
}, [deleteConfirm]);
// Track the previous deleteConfirm value so we can adjust menuPos
// inline during render when the prop changes — avoids a stale frame