1
0
forked from baron/baron-sso

fix(adminfront): prevent bulk import modal from unmounting when dropdown closes

Lifted the modal state out of the DropdownMenuContent to ensure the dialog does not unmount immediately when the dropdown item is clicked.
This commit is contained in:
2026-05-20 13:28:03 +09:00
parent 53dacda5d5
commit 11d535f4e3
2 changed files with 30 additions and 8 deletions

View File

@@ -146,6 +146,7 @@ function UserListPage() {
React.useState(""); React.useState("");
const [sortConfig, setSortConfig] = const [sortConfig, setSortConfig] =
React.useState<SortConfig<UserSortKey> | null>(null); React.useState<SortConfig<UserSortKey> | null>(null);
const [bulkUploadOpen, setBulkUploadOpen] = React.useState(false);
const limit = 1000; const limit = 1000;
const offset = (page - 1) * limit; const offset = (page - 1) * limit;
@@ -513,10 +514,16 @@ function UserListPage() {
{t("ui.admin.users.csv_template", "템플릿 다운로드")} {t("ui.admin.users.csv_template", "템플릿 다운로드")}
</DropdownMenuItem> </DropdownMenuItem>
<DropdownMenuSeparator /> <DropdownMenuSeparator />
<UserBulkUploadModal <DropdownMenuItem
variant="dropdown" onSelect={(e) => {
onSuccess={() => query.refetch()} e.preventDefault();
/> setBulkUploadOpen(true);
}}
className="cursor-pointer"
>
<Upload size={16} className="mr-2 opacity-50" />
{t("ui.admin.users.list.bulk_import", "일괄 등록 (CSV)")}
</DropdownMenuItem>
<DropdownMenuSeparator /> <DropdownMenuSeparator />
<DropdownMenuItem <DropdownMenuItem
onClick={() => handleExport(false)} onClick={() => handleExport(false)}
@@ -538,6 +545,12 @@ function UserListPage() {
</DropdownMenuItem> </DropdownMenuItem>
</DropdownMenuContent> </DropdownMenuContent>
</DropdownMenu> </DropdownMenu>
<UserBulkUploadModal
variant="custom"
open={bulkUploadOpen}
onOpenChange={setBulkUploadOpen}
onSuccess={() => query.refetch()}
/>
<Dialog> <Dialog>
<DialogTrigger asChild> <DialogTrigger asChild>
<Button variant="outline" size="icon" className="h-9 w-9"> <Button variant="outline" size="icon" className="h-9 w-9">

View File

@@ -43,7 +43,9 @@ import {
interface UserBulkUploadModalProps { interface UserBulkUploadModalProps {
onSuccess?: () => void; onSuccess?: () => void;
variant?: "button" | "dropdown"; variant?: "button" | "dropdown" | "custom";
open?: boolean;
onOpenChange?: (open: boolean) => void;
} }
function buildUserTenantPreviewRows( function buildUserTenantPreviewRows(
@@ -141,8 +143,15 @@ export const downloadUserTemplate = () => {
export function UserBulkUploadModal({ export function UserBulkUploadModal({
onSuccess, onSuccess,
variant = "button", variant = "button",
open: controlledOpen,
onOpenChange: controlledOnOpenChange,
}: UserBulkUploadModalProps) { }: UserBulkUploadModalProps) {
const [open, setOpen] = React.useState(false); const [localOpen, setLocalOpen] = React.useState(false);
const open = controlledOpen !== undefined ? controlledOpen : localOpen;
const setOpen = (val: boolean) => {
setLocalOpen(val);
controlledOnOpenChange?.(val);
};
const [file, setFile] = React.useState<File | null>(null); const [file, setFile] = React.useState<File | null>(null);
const [parsing, setParsing] = React.useState(false); const [parsing, setParsing] = React.useState(false);
const [previewData, setPreviewData] = React.useState<BulkUserItem[]>([]); const [previewData, setPreviewData] = React.useState<BulkUserItem[]>([]);
@@ -359,7 +368,7 @@ export function UserBulkUploadModal({
<Upload size={16} className="mr-2 opacity-50" /> <Upload size={16} className="mr-2 opacity-50" />
{t("ui.admin.users.list.bulk_import", "일괄 등록 (CSV)")} {t("ui.admin.users.list.bulk_import", "일괄 등록 (CSV)")}
</DropdownMenuItem> </DropdownMenuItem>
) : ( ) : variant === "custom" ? null : (
<DialogTrigger asChild> <DialogTrigger asChild>
<Button variant="outline" className="gap-2" {...triggerProps}> <Button variant="outline" className="gap-2" {...triggerProps}>
<Upload size={16} /> <Upload size={16} />
@@ -378,7 +387,7 @@ export function UserBulkUploadModal({
if (!val) reset(); if (!val) reset();
}} }}
> >
{variant !== "dropdown" && triggerNode} {variant !== "dropdown" && variant !== "custom" && triggerNode}
<DialogContent className="max-w-2xl"> <DialogContent className="max-w-2xl">
<DialogHeader> <DialogHeader>
<DialogTitle data-testid="bulk-upload-title"> <DialogTitle data-testid="bulk-upload-title">