fix: render secretary modal via portal Modal component (centered card)
The custom inline overlay was mounted inside the SettingsLayout grid, so the fixed positioning resolved against a transformed ancestor and the modal rendered top-aligned and full-width. Use the shared Modal (portal to body) for a correctly centered card; keep the tauri-styled form body + permission accordions as its children.
This commit is contained in:
@@ -4,6 +4,7 @@ import { Link } from "react-router-dom";
|
||||
import { toast } from "sonner";
|
||||
import SettingsLayout from "../components/layout/SettingsLayout";
|
||||
import ConfirmDialog from "../components/ui/ConfirmDialog";
|
||||
import Modal from "../components/ui/Modal";
|
||||
import SearchableSelect from "../components/ui/SearchableSelect";
|
||||
import type { ApiResponse } from "../lib/api";
|
||||
import { api } from "../lib/api";
|
||||
@@ -21,16 +22,6 @@ const PlusIcon = () => (
|
||||
</svg>
|
||||
);
|
||||
|
||||
const CloseModalIcon = () => (
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="17" height="17" viewBox="0 0 17 17" fill="none">
|
||||
<path
|
||||
d="M12.5947 4.20135C12.533 4.13954 12.4597 4.09051 12.3791 4.05706C12.2984 4.0236 12.212 4.00638 12.1247 4.00638C12.0374 4.00638 11.9509 4.0236 11.8703 4.05706C11.7896 4.09051 11.7164 4.13954 11.6547 4.20135L8.39468 7.45468L5.13468 4.19468C5.07296 4.13296 4.99969 4.084 4.91904 4.0506C4.8384 4.01719 4.75197 4 4.66468 4C4.57739 4 4.49096 4.01719 4.41032 4.0506C4.32968 4.084 4.2564 4.13296 4.19468 4.19468C4.13296 4.2564 4.084 4.32968 4.0506 4.41032C4.01719 4.49096 4 4.57739 4 4.66468C4 4.75197 4.01719 4.8384 4.0506 4.91904C4.084 4.99969 4.13296 5.07296 4.19468 5.13468L7.45468 8.39468L4.19468 11.6547C4.13296 11.7164 4.084 11.7897 4.0506 11.8703C4.01719 11.951 4 12.0374 4 12.1247C4 12.212 4.01719 12.2984 4.0506 12.379C4.084 12.4597 4.13296 12.533 4.19468 12.5947C4.2564 12.6564 4.32968 12.7054 4.41032 12.7388C4.49096 12.7722 4.57739 12.7894 4.66468 12.7894C4.75197 12.7894 4.8384 12.7722 4.91904 12.7388C4.99969 12.7054 5.07296 12.6564 5.13468 12.5947L8.39468 9.33468L11.6547 12.5947C11.7164 12.6564 11.7897 12.7054 11.8703 12.7388C11.951 12.7722 12.0374 12.7894 12.1247 12.7894C12.212 12.7894 12.2984 12.7722 12.379 12.7388C12.4597 12.7054 12.533 12.6564 12.5947 12.5947C12.6564 12.533 12.7054 12.4597 12.7388 12.379C12.7722 12.2984 12.7894 12.212 12.7894 12.1247C12.7894 12.0374 12.7722 11.951 12.7388 11.8703C12.7054 11.7897 12.6564 11.7164 12.5947 11.6547L9.33468 8.39468L12.5947 5.13468C12.848 4.88135 12.848 4.45468 12.5947 4.20135Z"
|
||||
fill="#7E7E7E"
|
||||
className="dark:[fill:#FAFAFA]"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
|
||||
const EyeIcon = () => (
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20" fill="none">
|
||||
<path d="M12.9833 9.99993C12.9833 11.6499 11.6499 12.9833 9.99993 12.9833C8.34993 12.9833 7.0166 11.6499 7.0166 9.99993C7.0166 8.34993 8.34993 7.0166 9.99993 7.0166C11.6499 7.0166 12.9833 8.34993 12.9833 9.99993Z" stroke="#616161" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
|
||||
@@ -336,8 +327,6 @@ function SecretaryModal({
|
||||
}
|
||||
}, [open, mode, data]);
|
||||
|
||||
if (!open) return null;
|
||||
|
||||
const disabled = mode === "view";
|
||||
const title =
|
||||
mode === "add"
|
||||
@@ -372,83 +361,69 @@ function SecretaryModal({
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
className="fixed inset-0 z-[1300] flex items-center justify-center bg-black/50"
|
||||
onClick={onClose}
|
||||
>
|
||||
<div
|
||||
dir="rtl"
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
className="pt-[24px] md:pt-[22px] lg:pt-[20px] pb-[34px] px-[16px] bg-[#FAFAFA] dark:bg-[#222433]
|
||||
shadow-[0px_1px_24.8px_0px_rgba(204,204,204,0.18)] dark:shadow-[0px_4px_25px_10px_#1F1D2B]
|
||||
w-full h-full sm:w-fit sm:h-fit rounded-none sm:rounded-[8px] overflow-y-auto max-h-[90vh]"
|
||||
>
|
||||
<div className="flex items-center justify-between">
|
||||
<p className="text-[#525252] dark:text-[#D7D8ED] text-[16px] md:text-[18px] lg:text-[20px] font-bold">
|
||||
{title}
|
||||
</p>
|
||||
<button onClick={onClose} className="p-1 cursor-pointer">
|
||||
<CloseModalIcon />
|
||||
<Modal
|
||||
open={open}
|
||||
onClose={onClose}
|
||||
title={title}
|
||||
size="lg"
|
||||
footer={
|
||||
<>
|
||||
<button
|
||||
onClick={onClose}
|
||||
className="border border-[#5559CE] dark:border-transparent dark:bg-[#C7CEF4] text-[#5559CE] dark:text-[#222433]
|
||||
h-[40px] md:h-[44px] lg:h-[48px] py-[11px] px-[48px] rounded-[4px] cursor-pointer"
|
||||
>
|
||||
{mode === "view" ? "بستن" : "انصراف"}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col justify-start items-start gap-[24px] min-w-fit sm:min-w-[520px] lg:min-w-[620px] mt-[24px] mx-0 sm:mx-[52px]">
|
||||
{/* اطلاعات پایه */}
|
||||
<div className="w-full">
|
||||
<p className="text-[#525252] dark:text-[#D7D8ED] text-[16px] font-bold mb-[16px]">
|
||||
اطلاعات پایه
|
||||
</p>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-[16px]">
|
||||
<div className="flex w-full flex-col items-start justify-start gap-[12px]">
|
||||
<p className="text-[#525252] dark:text-[#D7D8ED] text-[14px] font-medium">نام</p>
|
||||
<DefaultTextField placeholder="نام" value={form.name} onChange={(v) => setField("name", v)} disabled={disabled} />
|
||||
</div>
|
||||
<div className="flex w-full flex-col items-start justify-start gap-[12px]">
|
||||
<p className="text-[#525252] dark:text-[#D7D8ED] text-[14px] font-medium">نام خانوادگی</p>
|
||||
<DefaultTextField placeholder="نام خانوادگی" value={form.family} onChange={(v) => setField("family", v)} disabled={disabled} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="w-full grid grid-cols-1 md:grid-cols-2 gap-[16px]">
|
||||
<div className="flex w-full flex-col items-start justify-start gap-[12px]">
|
||||
<p className="text-[#525252] dark:text-[#D7D8ED] text-[14px] font-medium">شماره موبایل</p>
|
||||
<DefaultTextField placeholder="09121234567" value={form.telephone} onChange={(v) => setField("telephone", v)} disabled={disabled || mode === "edit"} />
|
||||
</div>
|
||||
<div className="flex w-full flex-col items-start justify-start gap-[12px]">
|
||||
<p className="text-[#525252] dark:text-[#D7D8ED] text-[14px] font-medium">کد ملی</p>
|
||||
<DefaultTextField placeholder="کد ملی" value={form.national_code} onChange={(v) => setField("national_code", v)} disabled={disabled} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex w-full flex-col items-start justify-start gap-[12px]">
|
||||
<p className="text-[#525252] dark:text-[#D7D8ED] text-[14px] font-medium">آدرس</p>
|
||||
<DefaultTextField placeholder="آدرس" value={form.address} onChange={(v) => setField("address", v)} disabled={disabled} multiline rows={2} />
|
||||
</div>
|
||||
|
||||
<PermissionAccordions permissions={form.permission} onChange={setPermission} disabled={disabled} />
|
||||
|
||||
<div className="flex items-center justify-center gap-[16px] mt-[24px] md:mt-[20px] lg:mt-[16px] w-full">
|
||||
{mode !== "view" && (
|
||||
<button
|
||||
onClick={onClose}
|
||||
className="border border-[#5559CE] dark:border-transparent dark:bg-[#C7CEF4] text-[#5559CE] dark:text-[#222433]
|
||||
h-[40px] md:h-[44px] lg:h-[48px] py-[11px] px-[48px] rounded-[4px] cursor-pointer"
|
||||
onClick={handleSubmit}
|
||||
disabled={saving}
|
||||
className="bg-[#5559CE] text-[#EFEFEF] rounded-[4px] h-[40px] md:h-[44px] lg:h-[48px] py-[11px] px-[48px] cursor-pointer disabled:opacity-60"
|
||||
>
|
||||
{mode === "view" ? "بستن" : "انصراف"}
|
||||
{saving ? "در حال ذخیره..." : "ذخیره"}
|
||||
</button>
|
||||
{mode !== "view" && (
|
||||
<button
|
||||
onClick={handleSubmit}
|
||||
disabled={saving}
|
||||
className="bg-[#5559CE] text-[#EFEFEF] rounded-[4px] h-[40px] md:h-[44px] lg:h-[48px] py-[11px] px-[48px] cursor-pointer disabled:opacity-60"
|
||||
>
|
||||
{saving ? "در حال ذخیره..." : "ذخیره"}
|
||||
</button>
|
||||
)}
|
||||
)}
|
||||
</>
|
||||
}
|
||||
>
|
||||
<div dir="rtl" className="flex flex-col justify-start items-start gap-[24px] w-full">
|
||||
{/* اطلاعات پایه */}
|
||||
<div className="w-full">
|
||||
<p className="text-[#525252] dark:text-[#D7D8ED] text-[16px] font-bold mb-[16px]">
|
||||
اطلاعات پایه
|
||||
</p>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-[16px]">
|
||||
<div className="flex w-full flex-col items-start justify-start gap-[12px]">
|
||||
<p className="text-[#525252] dark:text-[#D7D8ED] text-[14px] font-medium">نام</p>
|
||||
<DefaultTextField placeholder="نام" value={form.name} onChange={(v) => setField("name", v)} disabled={disabled} />
|
||||
</div>
|
||||
<div className="flex w-full flex-col items-start justify-start gap-[12px]">
|
||||
<p className="text-[#525252] dark:text-[#D7D8ED] text-[14px] font-medium">نام خانوادگی</p>
|
||||
<DefaultTextField placeholder="نام خانوادگی" value={form.family} onChange={(v) => setField("family", v)} disabled={disabled} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="w-full grid grid-cols-1 md:grid-cols-2 gap-[16px]">
|
||||
<div className="flex w-full flex-col items-start justify-start gap-[12px]">
|
||||
<p className="text-[#525252] dark:text-[#D7D8ED] text-[14px] font-medium">شماره موبایل</p>
|
||||
<DefaultTextField placeholder="09121234567" value={form.telephone} onChange={(v) => setField("telephone", v)} disabled={disabled || mode === "edit"} />
|
||||
</div>
|
||||
<div className="flex w-full flex-col items-start justify-start gap-[12px]">
|
||||
<p className="text-[#525252] dark:text-[#D7D8ED] text-[14px] font-medium">کد ملی</p>
|
||||
<DefaultTextField placeholder="کد ملی" value={form.national_code} onChange={(v) => setField("national_code", v)} disabled={disabled} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex w-full flex-col items-start justify-start gap-[12px]">
|
||||
<p className="text-[#525252] dark:text-[#D7D8ED] text-[14px] font-medium">آدرس</p>
|
||||
<DefaultTextField placeholder="آدرس" value={form.address} onChange={(v) => setField("address", v)} disabled={disabled} multiline rows={2} />
|
||||
</div>
|
||||
|
||||
<PermissionAccordions permissions={form.permission} onChange={setPermission} disabled={disabled} />
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user