DiskManagementReviewAndSubmitDialog.hooks.ts186 lines · main
| 1 | import { useMemo } from 'react' |
| 2 | import { UseFormReturn } from 'react-hook-form' |
| 3 | |
| 4 | import { DiskStorageSchemaType } from '../DiskManagement.schema' |
| 5 | import { |
| 6 | calculateComputeSizePrice, |
| 7 | calculateDiskSizePrice, |
| 8 | calculateIOPSPrice, |
| 9 | calculateThroughputPrice, |
| 10 | getAvailableComputeOptions, |
| 11 | mapAddOnVariantIdToComputeSize, |
| 12 | } from '../DiskManagement.utils' |
| 13 | import { DiskType } from '../ui/DiskManagement.constants' |
| 14 | import { useProjectAddonsQuery } from '@/data/subscriptions/project-addons-query' |
| 15 | import { useSelectedOrganizationQuery } from '@/hooks/misc/useSelectedOrganization' |
| 16 | import { |
| 17 | useIsAwsNimbusCloudProvider, |
| 18 | useSelectedProjectQuery, |
| 19 | } from '@/hooks/misc/useSelectedProject' |
| 20 | |
| 21 | export function useDiskManagementReviewChanges( |
| 22 | form: UseFormReturn<DiskStorageSchemaType>, |
| 23 | numReplicas: number |
| 24 | ) { |
| 25 | const { data: project } = useSelectedProjectQuery() |
| 26 | const { data: org } = useSelectedOrganizationQuery() |
| 27 | const isAwsNimbus = useIsAwsNimbusCloudProvider() |
| 28 | const { data: addons } = useProjectAddonsQuery({ projectRef: project?.ref }) |
| 29 | |
| 30 | const isAwsK8sProject = project?.cloud_provider === 'AWS_K8S' |
| 31 | const planId = org?.plan.id ?? 'free' |
| 32 | |
| 33 | const availableAddons = useMemo(() => addons?.available_addons ?? [], [addons]) |
| 34 | const availableOptions = useMemo( |
| 35 | () => getAvailableComputeOptions(availableAddons, project?.cloud_provider), |
| 36 | [availableAddons, project?.cloud_provider] |
| 37 | ) |
| 38 | |
| 39 | // --- Prices --- |
| 40 | |
| 41 | const computeSizePrice = calculateComputeSizePrice({ |
| 42 | availableOptions, |
| 43 | oldComputeSize: form.formState.defaultValues?.computeSize || 'ci_micro', |
| 44 | newComputeSize: form.getValues('computeSize'), |
| 45 | plan: planId, |
| 46 | }) |
| 47 | const diskSizePrice = calculateDiskSizePrice({ |
| 48 | planId, |
| 49 | oldSize: form.formState.defaultValues?.totalSize || 0, |
| 50 | oldStorageType: form.formState.defaultValues?.storageType as DiskType, |
| 51 | newSize: form.getValues('totalSize'), |
| 52 | newStorageType: form.getValues('storageType') as DiskType, |
| 53 | numReplicas, |
| 54 | }) |
| 55 | const iopsPrice = calculateIOPSPrice({ |
| 56 | oldStorageType: form.formState.defaultValues?.storageType as DiskType, |
| 57 | oldProvisionedIOPS: form.formState.defaultValues?.provisionedIOPS || 0, |
| 58 | newStorageType: form.getValues('storageType') as DiskType, |
| 59 | newProvisionedIOPS: form.getValues('provisionedIOPS'), |
| 60 | numReplicas, |
| 61 | }) |
| 62 | const throughputPrice = calculateThroughputPrice({ |
| 63 | storageType: form.getValues('storageType') as DiskType, |
| 64 | newThroughput: form.getValues('throughput') || 0, |
| 65 | oldThroughput: form.formState.defaultValues?.throughput || 0, |
| 66 | numReplicas, |
| 67 | }) |
| 68 | |
| 69 | const totalBeforePrice = |
| 70 | Number(computeSizePrice.oldPrice) + |
| 71 | Number(diskSizePrice.oldPrice) + |
| 72 | Number(iopsPrice.oldPrice) + |
| 73 | Number(throughputPrice.oldPrice) |
| 74 | |
| 75 | const totalAfterPrice = |
| 76 | Number(computeSizePrice.newPrice) + |
| 77 | Number(diskSizePrice.newPrice) + |
| 78 | Number(iopsPrice.newPrice) + |
| 79 | Number(throughputPrice.newPrice) |
| 80 | |
| 81 | // --- Change flags --- |
| 82 | |
| 83 | const hasComputeChanges = |
| 84 | form.formState.defaultValues?.computeSize !== form.getValues('computeSize') |
| 85 | |
| 86 | const hasTotalSizeChanges = |
| 87 | !isAwsK8sProject && |
| 88 | !isAwsNimbus && |
| 89 | form.formState.defaultValues?.totalSize !== form.getValues('totalSize') |
| 90 | |
| 91 | const hasStorageTypeChanges = |
| 92 | !isAwsK8sProject && |
| 93 | !isAwsNimbus && |
| 94 | form.formState.defaultValues?.storageType !== form.getValues('storageType') |
| 95 | |
| 96 | const hasThroughputChanges = |
| 97 | !isAwsK8sProject && |
| 98 | !isAwsNimbus && |
| 99 | form.formState.defaultValues?.throughput !== form.getValues('throughput') |
| 100 | |
| 101 | const hasIOPSChanges = |
| 102 | !isAwsK8sProject && |
| 103 | !isAwsNimbus && |
| 104 | form.formState.defaultValues?.provisionedIOPS !== form.getValues('provisionedIOPS') |
| 105 | |
| 106 | const hasGrowthPercentChanges = |
| 107 | !isAwsK8sProject && |
| 108 | !isAwsNimbus && |
| 109 | form.formState.defaultValues?.growthPercent !== form.getValues('growthPercent') |
| 110 | |
| 111 | const hasMinIncrementChanges = |
| 112 | !isAwsK8sProject && |
| 113 | !isAwsNimbus && |
| 114 | form.formState.defaultValues?.minIncrementGb !== form.getValues('minIncrementGb') |
| 115 | |
| 116 | const hasMaxSizeChanges = |
| 117 | !isAwsK8sProject && |
| 118 | !isAwsNimbus && |
| 119 | form.formState.defaultValues?.maxSizeGb !== form.getValues('maxSizeGb') |
| 120 | |
| 121 | // --- Derived predicates --- |
| 122 | |
| 123 | const storageTypeBefore = (form.formState.defaultValues?.storageType ?? '') as DiskType |
| 124 | const storageTypeAfter = form.getValues('storageType') as DiskType |
| 125 | |
| 126 | // Show hero whenever any line-item price actually changes, not just compute |
| 127 | const anyBillableDiskChange = |
| 128 | Number(diskSizePrice.newPrice) !== Number(diskSizePrice.oldPrice) || |
| 129 | Number(iopsPrice.newPrice) !== Number(iopsPrice.oldPrice) || |
| 130 | Number(throughputPrice.newPrice) !== Number(throughputPrice.oldPrice) |
| 131 | |
| 132 | // Show cooldown warning whenever any disk attribute that enforces the 4-hour lock changes |
| 133 | const anyDiskAttributeChange = hasIOPSChanges || hasStorageTypeChanges || hasTotalSizeChanges |
| 134 | |
| 135 | // Show throughput row whenever either the before or after storage type is GP3 |
| 136 | // (covers GP3→IO2 where the throughput charge drops to zero) |
| 137 | const showThroughputRow = |
| 138 | !isAwsK8sProject && |
| 139 | !isAwsNimbus && |
| 140 | (storageTypeBefore === 'gp3' || storageTypeAfter === 'gp3') && |
| 141 | (hasThroughputChanges || hasStorageTypeChanges) |
| 142 | |
| 143 | const hasAnyBreakdownRows = |
| 144 | hasComputeChanges || |
| 145 | hasStorageTypeChanges || |
| 146 | hasIOPSChanges || |
| 147 | showThroughputRow || |
| 148 | hasTotalSizeChanges || |
| 149 | hasGrowthPercentChanges || |
| 150 | hasMinIncrementChanges || |
| 151 | hasMaxSizeChanges |
| 152 | |
| 153 | // --- Labels --- |
| 154 | |
| 155 | const oldComputeLabel = mapAddOnVariantIdToComputeSize( |
| 156 | form.formState.defaultValues?.computeSize ?? 'ci_nano' |
| 157 | ) |
| 158 | const newComputeLabel = mapAddOnVariantIdToComputeSize(form.getValues('computeSize')) |
| 159 | |
| 160 | return { |
| 161 | // prices |
| 162 | computeSizePrice, |
| 163 | diskSizePrice, |
| 164 | iopsPrice, |
| 165 | throughputPrice, |
| 166 | totalBeforePrice, |
| 167 | totalAfterPrice, |
| 168 | // change flags |
| 169 | hasComputeChanges, |
| 170 | hasTotalSizeChanges, |
| 171 | hasStorageTypeChanges, |
| 172 | hasThroughputChanges, |
| 173 | hasIOPSChanges, |
| 174 | hasGrowthPercentChanges, |
| 175 | hasMinIncrementChanges, |
| 176 | hasMaxSizeChanges, |
| 177 | // derived predicates |
| 178 | anyBillableDiskChange, |
| 179 | anyDiskAttributeChange, |
| 180 | showThroughputRow, |
| 181 | hasAnyBreakdownRows, |
| 182 | // labels |
| 183 | oldComputeLabel, |
| 184 | newComputeLabel, |
| 185 | } |
| 186 | } |