Skip to content
Draft
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"use client";

import { useState, useMemo, useCallback, ReactNode } from "react";
import { useState, useMemo, useCallback, useEffect, useRef, ReactNode } from "react";
import { Check } from "lucide-react";
import { useTranslations } from "next-intl";
import { Input } from "@/components/input";
Expand Down Expand Up @@ -72,6 +72,17 @@ export function SelectModal({
}: SelectModalProps) {
const t = useTranslations("selectModal");
const [searchQuery, setSearchQuery] = useState("");
// Guard against rapid double-clicks: once a selection fires, ignore any
// subsequent clicks until the dialog has closed and re-opened.
const isSelectingRef = useRef(false);

// Reset the guard whenever the modal opens so it's ready for the next session.
useEffect(() => {
if (isOpen) {
isSelectingRef.current = false;
}
}, [isOpen]);
Comment on lines +79 to +84

const effectiveSearchPlaceholder = searchPlaceholder ?? t("searchByName");

const filteredOptions = useMemo(() => {
Expand Down Expand Up @@ -109,6 +120,12 @@ export function SelectModal({

const handleSelect = useCallback(
(option: SelectOption) => {
// Prevent a rapid double-click from triggering the handler twice (single-select only).
// For multi-select we must allow multiple item clicks while the modal remains open.
if (!multiSelect) {
if (isSelectingRef.current) return;
isSelectingRef.current = true;
Comment on lines +123 to +127
}
onSelect(option);
if (!multiSelect) {
setSearchQuery("");
Expand Down
Loading