import { useEffect, useState } from "react";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
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 type { ApiResponse } from "../lib/api";
import { api } from "../lib/api";
import { formatDate, digitsOnly, IRAN_MOBILE_RE, IRAN_NATIONAL_CODE_RE } from "../lib/utils";
import { useSubscription } from "../hooks/useSubscription";
import { useAuthStore } from "../stores/authStore";
import type { Secretary, SecretaryPermissions } from "../types";
// ── SVG icons (copied verbatim from clinic-pro-tauri) ───────────────────────
const PlusIcon = () => (
);
const EyeIcon = () => (
);
const EditIcon = () => (
);
const ChevronDown = ({ open }: { open: boolean }) => (
);
// ── Avatar (first-letter gradient fallback, like tauri) ─────────────────────
function Avatar({ name, size = 32 }: { name?: string; size?: number }) {
const firstLetter = (name?.trim().charAt(0) || "?").toUpperCase();
return (
{firstLetter}
);
}
// ── Permission sections (based on existing clinicpro pages) ─────────────────
const EMPTY_PERMISSIONS: SecretaryPermissions = {
appointments: { view: false, create: false, cancel: false, update_status: false },
patients: { view: false, create: false, update: false, delete: false },
payments: { view: false, create: false, update: false, delete: false },
insurances: { view: false, create: false, update: false, delete: false },
addresses: { view: false, create: false, update: false, delete: false },
clinic_info: { view: false, update: false },
inventory: { view: false, create: false, update: false, delete: false },
tags: { view: false, create: false, update: false, delete: false },
services: { view: false, create: false, update: false, delete: false },
staff: { view: false, create: false, update: false, delete: false },
discounts: { view: false, create: false, update: false, delete: false },
sms: { view: false, create: false, update: false, delete: false },
appointment_settings: { view: false, update: false },
clinic_doctors: { view: false, create: false, update: false, delete: false },
subscription: { view: false, create: false },
};
type PermSection = keyof SecretaryPermissions;
const PERMISSION_SECTIONS: {
key: PermSection;
title: string;
/** فقط برای مالکِ کلینیک نمایش داده میشود (پزشک مستقل نه toggle نه منو). */
clinicOnly?: boolean;
items: { key: string; label: string }[];
}[] = [
{
key: "appointments",
title: "مدیریت نوبتها",
items: [
{ key: "view", label: "مشاهده نوبتها" },
{ key: "create", label: "ایجاد نوبت" },
{ key: "cancel", label: "لغو نوبت" },
{ key: "update_status", label: "تغییر وضعیت نوبت" },
],
},
{
key: "patients",
title: "پرونده بیماران",
items: [
{ key: "view", label: "مشاهده بیماران" },
{ key: "create", label: "ایجاد بیمار" },
{ key: "update", label: "ویرایش بیمار" },
{ key: "delete", label: "حذف بیمار" },
],
},
{
key: "payments",
title: "مدیریت پرداختها",
items: [
{ key: "view", label: "مشاهده پرداختها" },
{ key: "create", label: "ثبت پرداخت" },
{ key: "update", label: "ویرایش پرداخت" },
{ key: "delete", label: "حذف پرداخت" },
],
},
{
key: "insurances",
title: "مدیریت بیمهها",
items: [
{ key: "view", label: "مشاهده بیمهها" },
{ key: "create", label: "ایجاد بیمه" },
{ key: "update", label: "ویرایش بیمه" },
{ key: "delete", label: "حذف بیمه" },
],
},
{
key: "addresses",
title: "آدرسها",
items: [
{ key: "view", label: "مشاهده آدرسها" },
{ key: "create", label: "ایجاد آدرس" },
{ key: "update", label: "ویرایش آدرس" },
{ key: "delete", label: "حذف آدرس" },
],
},
{
key: "clinic_info",
title: "اطلاعات کلینیک",
items: [
{ key: "view", label: "مشاهده اطلاعات" },
{ key: "update", label: "ویرایش اطلاعات" },
],
},
{
key: "inventory",
title: "انبار",
items: [
{ key: "view", label: "مشاهده انبار" },
{ key: "create", label: "ایجاد کالا/بسته" },
{ key: "update", label: "ویرایش انبار" },
{ key: "delete", label: "حذف از انبار" },
],
},
{
key: "tags",
title: "تگها",
items: [
{ key: "view", label: "مشاهده تگها" },
{ key: "create", label: "ایجاد تگ" },
{ key: "update", label: "ویرایش تگ" },
{ key: "delete", label: "حذف تگ" },
],
},
{
key: "services",
title: "خدمات و تعرفهها",
items: [
{ key: "view", label: "مشاهده خدمات" },
{ key: "create", label: "ایجاد خدمت" },
{ key: "update", label: "ویرایش خدمت" },
{ key: "delete", label: "حذف خدمت" },
],
},
{
key: "staff",
title: "پرسنل",
items: [
{ key: "view", label: "مشاهده پرسنل" },
{ key: "create", label: "افزودن پرسنل" },
{ key: "update", label: "ویرایش پرسنل" },
{ key: "delete", label: "حذف پرسنل" },
],
},
{
key: "discounts",
title: "تخفیفها",
items: [
{ key: "view", label: "مشاهده تخفیفها" },
{ key: "create", label: "ایجاد تخفیف" },
{ key: "update", label: "ویرایش تخفیف" },
{ key: "delete", label: "حذف تخفیف" },
],
},
{
key: "sms",
title: "پیامکها",
items: [
{ key: "view", label: "مشاهده پیامک/کیف پول" },
{ key: "create", label: "شارژ/ارسال" },
{ key: "update", label: "ویرایش تنظیمات" },
{ key: "delete", label: "حذف" },
],
},
{
key: "appointment_settings",
title: "تنظیمات نوبتدهی",
items: [
{ key: "view", label: "مشاهده تنظیمات" },
{ key: "update", label: "ویرایش تنظیمات" },
],
},
{
key: "clinic_doctors",
title: "مدیریت پزشکان کلینیک",
clinicOnly: true,
items: [
{ key: "view", label: "مشاهده پزشکان" },
{ key: "create", label: "افزودن پزشک" },
{ key: "update", label: "ویرایش پزشک" },
{ key: "delete", label: "حذف پزشک" },
],
},
{
key: "subscription",
title: "خرید اشتراک",
items: [
{ key: "view", label: "مشاهده اشتراک" },
{ key: "create", label: "خرید/فعالسازی اشتراک" },
],
},
];
function PermissionAccordions({
permissions,
onChange,
disabled,
isClinic,
}: {
permissions: SecretaryPermissions;
onChange: (section: PermSection, item: string, value: boolean) => void;
disabled?: boolean;
isClinic: boolean;
}) {
const [openKeys, setOpenKeys] = useState>(
new Set(["appointments", "patients"]),
);
const toggleOpen = (key: string) => {
setOpenKeys((prev) => {
const next = new Set(prev);
next.has(key) ? next.delete(key) : next.add(key);
return next;
});
};
// منابع clinicOnly (مثل مدیریت پزشکان کلینیک) فقط برای مالکِ کلینیک دیده میشوند.
const sections = PERMISSION_SECTIONS.filter((s) => !s.clinicOnly || isClinic);
return (
مجوزهای دسترسی
{sections.map((section) => {
const open = openKeys.has(section.key);
const sectionPerm = permissions[section.key] as Record
;
return (
{open && (
)}
);
})}
);
}
// ── Text field (tauri DefaultTextField look) ────────────────────────────────
function DefaultTextField({
placeholder,
value,
onChange,
disabled,
multiline,
rows,
numeric,
maxDigits,
}: {
placeholder?: string;
value: string;
onChange: (v: string) => void;
disabled?: boolean;
multiline?: boolean;
rows?: number;
/** فیلد فقطعددی: ارقام فارسی/عربی به لاتین تبدیل و غیررقم حذف میشود. */
numeric?: boolean;
maxDigits?: number;
}) {
const cls =
"w-full bg-[var(--bg)] dark:bg-[var(--surface)] rounded-[8px] border border-[var(--border-2)] dark:border-[var(--border)] " +
"text-[var(--text-2)] dark:text-[var(--text)] text-[16px] font-normal px-[12px] py-[12.5px] outline-none " +
"focus:border-[var(--primary)] disabled:opacity-70";
if (multiline) {
return (