| @@ -83,15 +83,13 @@ | ||
| 83 | 83 | }; |
| 84 | 84 | |
| 85 | 85 | // Main Component |
| 86 | 86 | const AdditionalServices: React.FC = () => { |
| 87 | + // Module-availability gate. Evaluated up front; the actual early | |
| 88 | + // return runs AFTER every hook below so React's hook-order | |
| 89 | + // invariant holds (rules-of-hooks). | |
| 87 | 90 | const moduleAvailable = isModuleAvailable(); |
| 88 | 91 | |
| 89 | - // Show premium upgrade content if module is not available | |
| 90 | - if (!moduleAvailable) { | |
| 91 | - return <PremiumUpgradeCard />; | |
| 92 | - } | |
| 93 | - | |
| 94 | 92 | const [searchTerm, setSearchTerm] = useState(""); |
| 95 | 93 | const [statusFilter, setStatusFilter] = useState("all"); |
| 96 | 94 | const [sortBy, setSortBy] = useState("name"); |
| 97 | 95 | const [sortOrder, setSortOrder] = useState<"asc" | "desc">("asc"); |
| @@ -179,8 +177,9 @@ | ||
| 179 | 177 | }, |
| 180 | 178 | enabled: isModuleAvailable(), |
| 181 | 179 | }); |
| 182 | 180 | |
| 181 | + // eslint-disable-next-line react-hooks/exhaustive-deps | |
| 183 | 182 | const services = data?.data || []; |
| 184 | 183 | const total = data?.total || 0; |
| 185 | 184 | const totalPages = Math.ceil(total / 10); |
| 186 | 185 | |
| @@ -325,8 +324,15 @@ | ||
| 325 | 324 | }, |
| 326 | 325 | { key: "draft", label: __("Draft"), count: statusCounts.draft ?? 0 }, |
| 327 | 326 | { key: "trash", label: __("Trash"), count: statusCounts.trash ?? 0 }, |
| 328 | 327 | ]; |
| 328 | + | |
| 329 | + // Module-availability gate runs here so every hook above runs on | |
| 330 | + // every render — see rules-of-hooks. The PremiumUpgradeCard render | |
| 331 | + // matches what used to be above the hooks. | |
| 332 | + if (!moduleAvailable) { | |
| 333 | + return <PremiumUpgradeCard />; | |
| 334 | + } | |
| 329 | 335 | |
| 330 | 336 | return ( |
| 331 | 337 | <div className="space-y-3"> |
| 332 | 338 | <PageHeader |