import { ReactElement, useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react' import { BZZ, DAI, Duration, PostageBatch, RedundancyLevel, Size, Utils } from '@ethersphere/bee-js' import './InitialModal.scss' import { CustomDropdown } from '../CustomDropdown/CustomDropdown' import { Button } from '../Button/Button' import { calculateStampCapacityMetrics, fmFetchCost, getUsableStamps, handleCreateDrive } from '../../utils/bee' import { getExpiryDateByLifetime, safeSetState } from '../../utils/common' import { erasureCodeMarks } from '../../constants/common' import { desiredLifetimeOptions } from '../../constants/stamps' import { Context as SettingsContext } from '../../../../providers/Settings' import { Context as BeeContext } from '../../../../providers/Bee' import { FMSlider } from '../Slider/Slider' import { Context as FMContext } from '../../../../providers/FileManager' import { ADMIN_STAMP_LABEL } from '@solarpunkltd/file-manager-lib' import { ProgressBar } from '../ProgressBar/ProgressBar' import { Tooltip } from '../Tooltip/Tooltip' import { TOOLTIPS } from '../../constants/tooltips' interface InitialModalProps { resetState: boolean handleVisibility: (isVisible: boolean) => void handleShowError: (flag: boolean) => void setIsCreationInProgress: (isCreating: boolean) => void } const minMarkValue = Math.min(...erasureCodeMarks.map(mark => mark.value)) const maxMarkValue = Math.max(...erasureCodeMarks.map(mark => mark.value)) const BATCH_ID_PLACEHOLDER = 'Choose a saved Drive, or leave blank to create a new one' const createBatchIdOptions = (stamps: PostageBatch[]) => [ { label: BATCH_ID_PLACEHOLDER, value: -1 }, ...stamps.map((stamp, index) => { const batchId = stamp.batchID.toHex().slice(0, 8) const label = `${batchId}${stamp.label ? ` - ${stamp.label}` : ''}` return { label, value: index, } }), ] export function InitialModal({ resetState, setIsCreationInProgress, handleVisibility, handleShowError, }: InitialModalProps): ReactElement { const [isCreateEnabled, setIsCreateEnabled] = useState(false) const [isBalanceSufficient, setIsBalanceSufficient] = useState(true) const [isxDaiBalanceSufficient, setIsxDaiBalanceSufficient] = useState(true) const [capacity, setCapacity] = useState(0) const [lifetimeIndex, setLifetimeIndex] = useState(0) const [validityEndDate, setValidityEndDate] = useState(new Date()) const [erasureCodeLevel, setErasureCodeLevel] = useState(RedundancyLevel.OFF) const [cost, setCost] = useState('0') const [usableStamps, setUsableStamps] = useState([]) const [selectedBatch, setSelectedBatch] = useState(null) const [selectedBatchIndex, setSelectedBatchIndex] = useState(-1) const { walletBalance } = useContext(BeeContext) const { beeApi } = useContext(SettingsContext) const { fm } = useContext(FMContext) const currentFetch = useRef | null>(null) const isMountedRef = useRef(true) useEffect(() => { return () => { isMountedRef.current = false } }, []) const createAdminDrive = useCallback(async () => { setIsCreationInProgress?.(true) handleVisibility(false) await handleCreateDrive( beeApi, fm, Size.fromBytes(capacity), Duration.fromEndDate(validityEndDate), ADMIN_STAMP_LABEL, false, erasureCodeLevel, true, resetState, selectedBatch, () => { handleVisibility(false) setIsCreationInProgress(false) }, // onSuccess () => { handleShowError(true) setIsCreationInProgress(false) }, // onError ) }, [ beeApi, fm, capacity, validityEndDate, erasureCodeLevel, selectedBatch, handleVisibility, handleShowError, setIsCreationInProgress, resetState, ]) useEffect(() => { const getStamps = async () => { const stamps = (await getUsableStamps(beeApi)).filter(s => { const { capacityPct } = calculateStampCapacityMetrics(s) return capacityPct < 100 }) safeSetState(isMountedRef, setUsableStamps)([...stamps]) } if (beeApi) { getStamps() } }, [beeApi]) useEffect(() => { const newSizes = Array.from(Utils.getStampEffectiveBytesBreakpoints(false, erasureCodeLevel).values()) setCapacity(newSizes[2]) }, [erasureCodeLevel]) useEffect(() => { if (validityEndDate.getTime() > new Date().getTime()) { fmFetchCost( capacity, validityEndDate, false, erasureCodeLevel, beeApi, (cost: BZZ) => { setIsBalanceSufficient(true) setIsxDaiBalanceSufficient(true) if ((walletBalance && cost.gte(walletBalance.bzzBalance)) || !walletBalance) { safeSetState(isMountedRef, setIsBalanceSufficient)(false) } const zeroDAI = DAI.fromDecimalString('0') if ((walletBalance && zeroDAI.eq(walletBalance.nativeTokenBalance)) || !walletBalance) { safeSetState(isMountedRef, setIsxDaiBalanceSufficient)(false) } safeSetState(isMountedRef, setCost)(cost.toSignificantDigits(2)) }, currentFetch, ) if (lifetimeIndex >= 0) { setIsCreateEnabled(true) } } else { setCost('0') setIsCreateEnabled(false) } // eslint-disable-next-line react-hooks/exhaustive-deps }, [validityEndDate, beeApi, capacity, lifetimeIndex, walletBalance]) useEffect(() => { setValidityEndDate(getExpiryDateByLifetime(lifetimeIndex)) }, [lifetimeIndex]) useEffect(() => { if (selectedBatchIndex >= 0 && selectedBatchIndex < usableStamps.length) { setSelectedBatch(usableStamps[selectedBatchIndex]) } else { setSelectedBatch(null) } }, [usableStamps, selectedBatchIndex]) const { capacityPct, usedSize, totalSize } = useMemo( () => calculateStampCapacityMetrics(selectedBatch), [selectedBatch], ) const initText = resetState ? 'Resetting' : 'Initializing' const createText = resetState ? 'Reset' : 'Create' return (
Welcome to your Swarm File Manager
{initText} the File Manager
{usableStamps.length > 0 && (
{/*
*/} { setSelectedBatchIndex(index) if (index === -1) { setSelectedBatch(null) } }} placeholder={BATCH_ID_PLACEHOLDER} /> {selectedBatch && (
Capacity {usedSize} / {totalSize}
Expiry date: {selectedBatch.duration.toEndDate().toLocaleDateString()}
)}
)} {!selectedBatch && (
setErasureCodeLevel(value)} minValue={minMarkValue} maxValue={maxMarkValue} step={1} />
Estimated Cost:
{cost} BZZ {isBalanceSufficient ? '' : '(Insufficient balance)'} {isxDaiBalanceSufficient ? '' : ' (Insufficient xDAI balance)'}
(Based on current network conditions)
)}
) }