useOrganizationRestrictions.ts94 lines · main
| 1 | import type { ReactNode } from 'react' |
| 2 | |
| 3 | import { useIsFeatureEnabled } from './useIsFeatureEnabled' |
| 4 | import { RESTRICTION_MESSAGES } from '@/components/interfaces/Organization/restriction.constants' |
| 5 | import { useOverdueInvoicesQuery } from '@/data/invoices/invoices-overdue-query' |
| 6 | import { useOrganizationsQuery } from '@/data/organizations/organizations-query' |
| 7 | import { useSelectedOrganizationQuery } from '@/hooks/misc/useSelectedOrganization' |
| 8 | |
| 9 | export type WarningBannerProps = { |
| 10 | variant: 'danger' | 'warning' | 'note' |
| 11 | title: string |
| 12 | description: ReactNode |
| 13 | } |
| 14 | |
| 15 | /** |
| 16 | * Compute billing-related restriction banners for the currently selected organization. |
| 17 | * |
| 18 | * The hook examines billing feature availability, overdue invoices, organization billing data, |
| 19 | * and restriction status to produce an ordered list of warning/danger banner props. |
| 20 | * |
| 21 | * @returns An object containing: |
| 22 | * - `warnings`: an array of `WarningBannerProps` to display for the selected organization (may be empty). |
| 23 | * - `org`: the selected organization data (may be `undefined`). |
| 24 | */ |
| 25 | export function useOrganizationRestrictions() { |
| 26 | const { data: org } = useSelectedOrganizationQuery() |
| 27 | |
| 28 | const { data: overdueInvoices } = useOverdueInvoicesQuery() |
| 29 | const { data: organizations } = useOrganizationsQuery() |
| 30 | |
| 31 | const warnings: WarningBannerProps[] = [] |
| 32 | |
| 33 | const billingEnabled = useIsFeatureEnabled('billing:all') |
| 34 | if (!billingEnabled) { |
| 35 | return { warnings, org } |
| 36 | } |
| 37 | |
| 38 | const overdueInvoicesFromOtherOrgs = overdueInvoices?.filter( |
| 39 | (invoice) => invoice.organization_id !== org?.id |
| 40 | ) |
| 41 | const thisOrgHasOverdueInvoices = overdueInvoices?.filter( |
| 42 | (invoice) => invoice.organization_id === org?.id |
| 43 | ) |
| 44 | |
| 45 | if (thisOrgHasOverdueInvoices?.length) { |
| 46 | warnings.push({ |
| 47 | variant: 'danger', |
| 48 | title: RESTRICTION_MESSAGES.OVERDUE_INVOICES.title, |
| 49 | description: RESTRICTION_MESSAGES.OVERDUE_INVOICES.description(org?.slug ?? 'default'), |
| 50 | }) |
| 51 | } |
| 52 | |
| 53 | if (overdueInvoicesFromOtherOrgs?.length) { |
| 54 | const otherOrgSlug = organizations?.find( |
| 55 | (o) => o.id === overdueInvoicesFromOtherOrgs[0].organization_id |
| 56 | )?.slug |
| 57 | warnings.push({ |
| 58 | variant: 'danger', |
| 59 | title: RESTRICTION_MESSAGES.OVERDUE_INVOICES_FROM_OTHER_ORGS.title, |
| 60 | description: RESTRICTION_MESSAGES.OVERDUE_INVOICES_FROM_OTHER_ORGS.description( |
| 61 | otherOrgSlug ?? org?.slug ?? 'default' |
| 62 | ), |
| 63 | }) |
| 64 | } |
| 65 | |
| 66 | if (org?.restriction_status === 'grace_period') { |
| 67 | warnings.push({ |
| 68 | variant: 'warning', |
| 69 | title: RESTRICTION_MESSAGES.GRACE_PERIOD.title, |
| 70 | description: RESTRICTION_MESSAGES.GRACE_PERIOD.description( |
| 71 | org?.restriction_data?.['grace_period_end'] ?? '', |
| 72 | org.slug |
| 73 | ), |
| 74 | }) |
| 75 | } |
| 76 | |
| 77 | if (org?.restriction_status === 'grace_period_over') { |
| 78 | warnings.push({ |
| 79 | variant: 'warning', |
| 80 | title: RESTRICTION_MESSAGES.GRACE_PERIOD_OVER.title, |
| 81 | description: RESTRICTION_MESSAGES.GRACE_PERIOD_OVER.description(org.slug), |
| 82 | }) |
| 83 | } |
| 84 | |
| 85 | if (org?.restriction_status === 'restricted') { |
| 86 | warnings.push({ |
| 87 | variant: 'danger', |
| 88 | title: RESTRICTION_MESSAGES.RESTRICTED.title, |
| 89 | description: RESTRICTION_MESSAGES.RESTRICTED.description(org.slug), |
| 90 | }) |
| 91 | } |
| 92 | |
| 93 | return { warnings, org } |
| 94 | } |