feat: simplify all of this

This commit is contained in:
kemal committed 2026-03-31 13:21:20 +01:00
1 parent 5caf917f5b
commit b8ff33e8f1
5 files changed
+147

No files matched your search

@@ -38,11 +38,16 @@ import { RestoringState } from './RestoringState'
import { UpgradingState } from './UpgradingState'
import { CreateBranchModal } from '@/components/interfaces/BranchManagement/CreateBranchModal'
import { ProjectAPIDocs } from '@/components/interfaces/ProjectAPIDocs/ProjectAPIDocs'
import { BannerFreeMicroUpgrade } from '@/components/ui/BannerStack/Banners/BannerFreeMicroUpgrade'
import { useBannerStack } from '@/components/ui/BannerStack/BannerStackProvider'
import { ResourceExhaustionWarningBanner } from '@/components/ui/ResourceExhaustionWarningBanner/ResourceExhaustionWarningBanner'
import { useCustomContent } from '@/hooks/custom-content/useCustomContent'
import { useCheckEntitlements } from '@/hooks/misc/useCheckEntitlements'
import { useLocalStorageQuery } from '@/hooks/misc/useLocalStorage'
import { useSelectedOrganizationQuery } from '@/hooks/misc/useSelectedOrganization'
import { useSelectedProjectQuery } from '@/hooks/misc/useSelectedProject'
import { withAuth } from '@/hooks/misc/withAuth'
import { LOCAL_STORAGE_KEYS } from 'common'
import { PROJECT_STATUS } from '@/lib/constants'
import { buildStudioPageTitle } from '@/lib/page-title'
import { getPathnameWithoutQuery } from '@/lib/pathname.utils'
@@ -110,6 +115,16 @@ export const ProjectLayout = forwardRef<HTMLDivElement, PropsWithChildren<Projec
const router = useRouter()
const { data: selectedOrganization } = useSelectedOrganizationQuery()
const { data: selectedProject } = useSelectedProjectQuery()
const { addBanner, dismissBanner } = useBannerStack()
const { hasAccess: entitledUpdateCompute } = useCheckEntitlements(
'instances.compute_update_available_sizes'
)
const isEligibleForFreeUpgrade =
entitledUpdateCompute && selectedProject?.infra_compute_size === 'nano'
const [isFreeMicroUpgradeBannerDismissed] = useLocalStorageQuery(
LOCAL_STORAGE_KEYS.FREE_MICRO_UPGRADE_BANNER_DISMISSED(selectedProject?.ref ?? ''),
false
)
const { showSidebar } = useAppStateSnapshot()
const { setContent: setMobileSheetContent, registerOpenMenu } = useMobileSheet()
@@ -153,6 +168,19 @@ export const ProjectLayout = forwardRef<HTMLDivElement, PropsWithChildren<Projec
router.pathname.includes('/project/[ref]/logs')
const showPausedState = isPaused && !ignorePausedState
useEffect(() => {
if (isEligibleForFreeUpgrade && !isFreeMicroUpgradeBannerDismissed) {
addBanner({
id: 'free-micro-upgrade-banner',
isDismissed: false,
content: <BannerFreeMicroUpgrade />,
priority: 2,
})
} else {
dismissBanner('free-micro-upgrade-banner')
}
}, [isEligibleForFreeUpgrade, isFreeMicroUpgradeBannerDismissed, addBanner, dismissBanner])
useLayoutEffect(() => {
const unregister = registerOpenMenu(() => {
setMobileSheetContent(
@@ -5,6 +5,7 @@ const BANNER_ID = {
INDEX_ADVISOR: 'index-advisor-banner',
TABLE_EDITOR_QUEUE_OPERATIONS: 'table-editor-queue-operations-banner',
RLS_EVENT_TRIGGER: 'rls-event-trigger-banner',
FREE_MICRO_UPGRADE: 'free-micro-upgrade-banner',
} as const
export type BannerId = (typeof BANNER_ID)[keyof typeof BANNER_ID]
@@ -0,0 +1,92 @@
import { LOCAL_STORAGE_KEYS } from 'common'
import { useParams } from 'common/hooks'
import { useLocalStorageQuery } from 'hooks/misc/useLocalStorage'
import { useTrack } from 'lib/telemetry/track'
import Link from 'next/link'
import { Button } from 'ui'
import { ComputeBadge } from 'ui-patterns/ComputeBadge'
import { BannerCard } from '../BannerCard'
import { useBannerStack } from '../BannerStackProvider'
const ChevronsUpAnimated = () => (
<svg
width={10}
height={10}
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2.5"
strokeLinecap="round"
strokeLinejoin="round"
>
<polyline
points="17 18 12 13 7 18"
className="animate-chevron-up"
style={{ animationDelay: '0s' }}
/>
<polyline
points="17 11 12 6 7 11"
className="animate-chevron-up"
style={{ animationDelay: '0.3s' }}
/>
</svg>
)
export const BannerFreeMicroUpgrade = () => {
const { ref } = useParams()
const track = useTrack()
const { dismissBanner } = useBannerStack()
const [, setIsDismissed] = useLocalStorageQuery(
LOCAL_STORAGE_KEYS.FREE_MICRO_UPGRADE_BANNER_DISMISSED(ref ?? ''),
false
)
return (
<BannerCard
onDismiss={() => {
setIsDismissed(true)
dismissBanner('free-micro-upgrade-banner')
track('free_micro_upgrade_banner_dismissed')
}}
>
<div className="flex flex-col gap-y-4">
<div className="flex flex-col gap-y-2 items-start">
<div className="animate-badge-pulse">
<div className="relative inline-flex overflow-hidden rounded">
<ComputeBadge
infraComputeSize="nano"
icon={<ChevronsUpAnimated />}
className="text-brand-600 border-brand-500 bg-brand/10 gap-1"
/>
<span className="animate-badge-shimmer pointer-events-none absolute inset-0 bg-gradient-to-br from-transparent via-brand/20 to-transparent blur-md" />
</div>
</div>
</div>
<div className="flex flex-col gap-y-1 mb-2">
<p className="text-sm font-medium">Free upgrade to Micro available</p>
<p className="text-xs text-foreground-lighter text-balance">
Your Pro plan includes a free upgrade from Nano to Micro — double the memory at no extra
cost.
</p>
</div>
<div className="flex gap-2">
<Button
type="primary"
size="tiny"
asChild
onClick={() => {
setIsDismissed(true)
dismissBanner('free-micro-upgrade-banner')
track('free_micro_upgrade_banner_cta_clicked')
}}
>
<Link href={`/project/${ref}/settings/compute-and-disk?upgrade=micro`}>
Upgrade for free
</Link>
</Button>
</div>
</div>
</BannerCard>
)
}
@@ -116,6 +116,8 @@ export const LOCAL_STORAGE_KEYS = {
TABLE_EDITOR_QUEUE_OPERATIONS_BANNER_DISMISSED: (ref: string) =>
`table-editor-queue-operations-banner-dismissed-${ref}`,
FREE_MICRO_UPGRADE_BANNER_DISMISSED: (ref: string) =>
`free-micro-upgrade-banner-dismissed-${ref}`,
PRIVACY_NOTICE_ACKNOWLEDGED: 'privacy-notice-acknowledged-2026-03',
/**
+24
View File
@@ -2946,6 +2946,28 @@ export interface ComputeBadgeUpgradeClickedEvent {
groups: TelemetryGroups
}
/**
* User dismissed the free Micro upgrade banner.
*
* @group Events
* @source studio
*/
export interface FreeMicroUpgradeBannerDismissedEvent {
action: 'free_micro_upgrade_banner_dismissed'
groups: TelemetryGroups
}
/**
* User clicked the CTA on the free Micro upgrade banner.
*
* @group Events
* @source studio
*/
export interface FreeMicroUpgradeBannerCtaClickedEvent {
action: 'free_micro_upgrade_banner_cta_clicked'
groups: TelemetryGroups
}
/**
* User clicked the Navigate action in the storage explorer header.
*
@@ -3136,3 +3158,5 @@ export type TelemetryEvent =
| OrgMenuBackClickedEvent
| OrgMenuItemClickedEvent
| ComputeBadgeUpgradeClickedEvent
| FreeMicroUpgradeBannerDismissedEvent
| FreeMicroUpgradeBannerCtaClickedEvent