feat(subscription): implement feature gating for subscription-based access in admin panel
This commit is contained in:
@@ -14,6 +14,7 @@ import PriceInput from '../components/ui/PriceInput';
|
||||
import ConfirmDialog from '../components/ui/ConfirmDialog';
|
||||
import PageHeader from '../components/ui/PageHeader';
|
||||
import SearchableSelect from '../components/ui/SearchableSelect';
|
||||
import FeatureGate from '../components/ui/FeatureGate';
|
||||
|
||||
const sectionSchema = z.object({ name: z.string().min(1, 'نام بخش الزامی است') });
|
||||
const itemSchema = z.object({
|
||||
@@ -27,7 +28,7 @@ type ItemForm = z.infer<typeof itemSchema>;
|
||||
const EMPTY_SECTIONS: ServiceSection[] = [];
|
||||
const EMPTY_ITEMS: ServiceItem[] = [];
|
||||
|
||||
export default function ClinicServicesPage() {
|
||||
function ClinicServicesPageInner() {
|
||||
const qc = useQueryClient();
|
||||
|
||||
const [selectedSection, setSelectedSection] = useState<ServiceSection | null>(null);
|
||||
@@ -409,3 +410,11 @@ export default function ClinicServicesPage() {
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default function ClinicServicesPage() {
|
||||
return (
|
||||
<FeatureGate feature="services">
|
||||
<ClinicServicesPageInner />
|
||||
</FeatureGate>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ import Pagination from '../components/ui/Pagination';
|
||||
import Modal from '../components/ui/Modal';
|
||||
import PageHeader from '../components/ui/PageHeader';
|
||||
import SearchableSelect from '../components/ui/SearchableSelect';
|
||||
import FeatureGate from '../components/ui/FeatureGate';
|
||||
|
||||
const sessionSchema = z.object({
|
||||
visit_price_rials: z.coerce.number().min(0),
|
||||
@@ -44,7 +45,7 @@ function calcFinalPrice(visitPrice: number, baseDiscount: number, suppDiscount:
|
||||
return Math.round(afterSupp) + servicesTotal;
|
||||
}
|
||||
|
||||
export default function MyPatientsPage() {
|
||||
function MyPatientsPageInner() {
|
||||
const qc = useQueryClient();
|
||||
const [selectedRecord, setSelectedRecord] = useState<PatientRecord | null>(null);
|
||||
const [page, setPage] = useState(1);
|
||||
@@ -543,3 +544,11 @@ function EditSessionModal({
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
export default function MyPatientsPage() {
|
||||
return (
|
||||
<FeatureGate feature="patient_records">
|
||||
<MyPatientsPageInner />
|
||||
</FeatureGate>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -15,6 +15,8 @@ import Modal from '../components/ui/Modal';
|
||||
import ConfirmDialog from '../components/ui/ConfirmDialog';
|
||||
import PageHeader from '../components/ui/PageHeader';
|
||||
import { useAuthStore } from '../stores/authStore';
|
||||
import { useSubscription } from '../hooks/useSubscription';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
// ── Default permissions & labels ──────────────────────────────────────────
|
||||
|
||||
@@ -143,6 +145,7 @@ export default function MySecretariesPage() {
|
||||
const { doctorUuid, dbUuid, primaryRole } = useAuthStore();
|
||||
|
||||
const isClinic = primaryRole === 'clinic';
|
||||
const { maxSecretaries } = useSubscription();
|
||||
|
||||
// for clinic: selected doctor to add secretary for
|
||||
const [selectedDoctorUuid, setSelectedDoctorUuid] = useState<string>('');
|
||||
@@ -309,10 +312,16 @@ export default function MySecretariesPage() {
|
||||
title="منشیان من"
|
||||
description="مدیریت منشیان و دسترسیهای آنها"
|
||||
action={
|
||||
<button className="btn primary sm" onClick={handleCreateOpen} disabled={isClinic && !selectedDoctorUuid}>
|
||||
<PlusIcon style={{ width: 16 }} />
|
||||
افزودن منشی
|
||||
</button>
|
||||
secretaries.length >= maxSecretaries ? (
|
||||
<Link to="/admin/subscription" className="btn sm" style={{ textDecoration: 'none', opacity: 0.8 }} title={`حداکثر ${maxSecretaries} منشی مجاز است`}>
|
||||
ارتقاء پنل برای افزودن منشی
|
||||
</Link>
|
||||
) : (
|
||||
<button className="btn primary sm" onClick={handleCreateOpen} disabled={isClinic && !selectedDoctorUuid}>
|
||||
<PlusIcon style={{ width: 16 }} />
|
||||
افزودن منشی
|
||||
</button>
|
||||
)
|
||||
}
|
||||
/>
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ import { formatRial, formatNumber, formatDateTime } from '../lib/utils';
|
||||
import Modal from '../components/ui/Modal';
|
||||
import Pagination from '../components/ui/Pagination';
|
||||
import PageHeader from '../components/ui/PageHeader';
|
||||
import FeatureGate from '../components/ui/FeatureGate';
|
||||
|
||||
const chargeSchema = z.object({
|
||||
amount_rials: z.coerce.number().min(10000, 'حداقل مبلغ ۱۰,۰۰۰ ریال است'),
|
||||
@@ -22,7 +23,7 @@ type ChargeForm = z.infer<typeof chargeSchema>;
|
||||
|
||||
const EMPTY_LOGS: SmsWalletLog[] = [];
|
||||
|
||||
export default function SmsWalletPage() {
|
||||
function SmsWalletPageInner() {
|
||||
const qc = useQueryClient();
|
||||
const [chargeOpen, setChargeOpen] = useState(false);
|
||||
const [gateway, setGateway] = useState<'mellat' | 'sep'>('mellat');
|
||||
@@ -433,3 +434,11 @@ export default function SmsWalletPage() {
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default function SmsWalletPage() {
|
||||
return (
|
||||
<FeatureGate feature="sms_panel">
|
||||
<SmsWalletPageInner />
|
||||
</FeatureGate>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user