import { Fragment, useState, useEffect } from 'react' import { Dialog, Transition } from '@headlessui/react' import { IconX, IconCheck, IconInfoCircle } from '@tabler/icons-react' import type { CategoryWithStatus, SpecTier, SpecResource } from '../../types/collections' import { resolveTierResources } from '~/lib/collections' import { formatBytes } from '~/lib/util' import classNames from 'classnames' import DynamicIcon, { DynamicIconName } from './DynamicIcon' import StyledButton from './StyledButton' interface TierSelectionModalProps { isOpen: boolean onClose: () => void category: CategoryWithStatus | null selectedTierSlug?: string | null onSelectTier: (category: CategoryWithStatus, tier: SpecTier) => void } const TierSelectionModal: React.FC = ({ isOpen, onClose, category, selectedTierSlug, onSelectTier, }) => { // Local selection state - initialized from prop const [localSelectedSlug, setLocalSelectedSlug] = useState(null) // Reset local selection when modal opens or category changes useEffect(() => { if (isOpen && category) { setLocalSelectedSlug(selectedTierSlug || null) } }, [isOpen, category, selectedTierSlug]) if (!category) return null // Get all resources for a tier (including inherited resources) const getAllResourcesForTier = (tier: SpecTier): SpecResource[] => { return resolveTierResources(tier, category.tiers) } const getTierTotalSize = (tier: SpecTier): number => { return getAllResourcesForTier(tier).reduce((acc, r) => acc + r.size_mb * 1024 * 1024, 0) } const handleTierClick = (tier: SpecTier) => { // Toggle selection: if clicking the same tier, deselect it if (localSelectedSlug === tier.slug) { setLocalSelectedSlug(null) } else { setLocalSelectedSlug(tier.slug) } } const handleSubmit = () => { if (!localSelectedSlug) return const selectedTier = category.tiers.find(t => t.slug === localSelectedSlug) if (selectedTier) { onSelectTier(category, selectedTier) } onClose() } return (
{/* Header */}
{category.name}

{category.description}

{/* Content */}

Select a tier based on your storage capacity and needs. Higher tiers include all content from lower tiers.

{category.tiers.map((tier) => { const totalSize = getTierTotalSize(tier) const isSelected = localSelectedSlug === tier.slug const includedTierName = tier.includesTier ? category.tiers.find(t => t.slug === tier.includesTier)?.name : null // Only show this tier's own resources (not inherited) const ownResources = tier.resources const ownResourceCount = ownResources.length return (
handleTierClick(tier)} className={classNames( 'border-2 rounded-lg p-5 cursor-pointer transition-all', isSelected ? 'border-desert-green bg-desert-green/5 shadow-md' : 'border-border-subtle hover:border-desert-green/50 hover:shadow-sm' )} >

{tier.name}

{includedTierName && ( (includes {includedTierName}) )}

{tier.description}

{/* Resources preview - only show this tier's own resources */}

{includedTierName ? ( <> {ownResourceCount} additional {ownResourceCount === 1 ? 'resource' : 'resources'} (plus everything in {includedTierName}) ) : ( <>{ownResourceCount} {ownResourceCount === 1 ? 'resource' : 'resources'} included )}

{ownResources.map((resource, idx) => (
{resource.title} ({formatBytes(resource.size_mb * 1024 * 1024, 0)})
))}
{formatBytes(totalSize, 1)}
{isSelected && }
) })}
{/* Info note */}

You can change your selection at any time. Click Submit to confirm your choice.

{/* Footer */}
Submit
) } export default TierSelectionModal