mirror of
https://github.com/supabase/supabase.git
synced 2026-06-14 14:08:31 +08:00
98 lines
3.4 KiB
TypeScript
98 lines
3.4 KiB
TypeScript
import { useQueries, useQuery } from '@tanstack/react-query'
|
|
import { LOCAL_STORAGE_KEYS, useFlag } from 'common'
|
|
import { useCallback, useMemo } from 'react'
|
|
|
|
import { getRelevantIncidentIds, shouldShowBanner } from './StatusPageBanner.utils'
|
|
import { useOrganizationsQuery } from '@/data/organizations/organizations-query'
|
|
import { incidentBannerQueryOptions } from '@/data/platform/incident-banner-query'
|
|
import { projectKeys } from '@/data/projects/keys'
|
|
import {
|
|
getOrganizationProjects,
|
|
type OrgProject,
|
|
} from '@/data/projects/org-projects-infinite-query'
|
|
import { useLocalStorageQuery } from '@/hooks/misc/useLocalStorage'
|
|
|
|
export type StatusPageBannerData = { title: string; dismiss?: () => void }
|
|
|
|
export function useStatusPageBannerVisibility(): StatusPageBannerData | null {
|
|
const showIncidentBannerOverride =
|
|
useFlag('ongoingIncident') || process.env.NEXT_PUBLIC_ONGOING_INCIDENT === 'true'
|
|
|
|
const { data: incidentBannerData } = useQuery(incidentBannerQueryOptions())
|
|
|
|
const bannerItems = incidentBannerData?.incidents ?? []
|
|
const incidents = bannerItems.map((i) => ({ id: i.id, cache: i.metadata }))
|
|
const hasActiveIncidents = incidents.length > 0
|
|
|
|
const { data: organizations } = useOrganizationsQuery({
|
|
enabled: !showIncidentBannerOverride && hasActiveIncidents,
|
|
})
|
|
|
|
const orgProjectsQueries = useQueries({
|
|
queries: (organizations ?? []).map((org) => ({
|
|
queryKey: projectKeys.bannerProjectsByOrg(org.slug),
|
|
queryFn: () => getOrganizationProjects({ slug: org.slug, limit: 100 }),
|
|
staleTime: 5 * 60 * 1000,
|
|
enabled: !showIncidentBannerOverride && hasActiveIncidents,
|
|
})),
|
|
})
|
|
|
|
const isProjectsFetched =
|
|
organizations !== undefined &&
|
|
(organizations.length === 0 || orgProjectsQueries.every((q) => q.isFetched))
|
|
|
|
const allProjects = orgProjectsQueries.flatMap((q) => q.data?.projects ?? [])
|
|
const hasProjects = allProjects.length > 0
|
|
const userRegions = useMemo(
|
|
() =>
|
|
new Set(
|
|
allProjects.flatMap((project: OrgProject) => project.databases.map((db) => db.region))
|
|
),
|
|
[allProjects]
|
|
)
|
|
const hasUnknownRegions = orgProjectsQueries.some(
|
|
(q) => q.isError || (q.data !== undefined && q.data.pagination.count > q.data.projects.length)
|
|
)
|
|
|
|
const [dismissedIds, setDismissedIds, { isSuccess: isDismissedLoaded }] = useLocalStorageQuery<
|
|
Array<string>
|
|
>(LOCAL_STORAGE_KEYS.INCIDENT_BANNER_DISMISSED_IDS, [])
|
|
|
|
const dismiss = useCallback(() => {
|
|
const activeIncidentIds = new Set(incidents.map((i) => i.id))
|
|
const relevantIds = getRelevantIncidentIds({
|
|
incidents,
|
|
hasProjects,
|
|
userRegions,
|
|
hasUnknownRegions,
|
|
})
|
|
setDismissedIds((prev) => [
|
|
...new Set([...prev.filter((id) => activeIncidentIds.has(id)), ...relevantIds]),
|
|
])
|
|
}, [incidents, hasProjects, userRegions, hasUnknownRegions, setDismissedIds])
|
|
|
|
if (showIncidentBannerOverride) return { title: 'We are investigating a technical issue' }
|
|
|
|
if (!hasActiveIncidents || !isProjectsFetched) return null
|
|
|
|
const dismissedIdSet = new Set(dismissedIds)
|
|
const undismissedIncidents = incidents.filter((i) => !dismissedIdSet.has(i.id))
|
|
|
|
if (
|
|
!isDismissedLoaded ||
|
|
!shouldShowBanner({
|
|
incidents: undismissedIncidents,
|
|
hasProjects,
|
|
userRegions,
|
|
hasUnknownRegions,
|
|
})
|
|
)
|
|
return null
|
|
|
|
const title = hasProjects
|
|
? 'We are investigating a technical issue'
|
|
: 'Project creation may be impacted in some regions'
|
|
|
|
return { title, dismiss }
|
|
}
|