// Copyright 2025 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only import type { MutableRefObject } from 'react'; import React, { useCallback, useEffect, useMemo, useRef, useState, } from 'react'; import type { LocalizerType } from '../types/Util'; import { useConfirmDiscard } from '../hooks/useConfirmDiscard'; import { Button, ButtonVariant } from './Button'; import type { HumanDonationAmount } from '../types/Donations'; import { ONE_TIME_DONATION_CONFIG_ID, type DonationWorkflow, type OneTimeDonationHumanAmounts, } from '../types/Donations'; import { brandHumanDonationAmount, parseCurrencyString, toHumanCurrencyString, toStripeDonationAmount, } from '../util/currency'; import { Input } from './Input'; import { PreferencesContent } from './Preferences'; import type { SubmitDonationType } from '../state/ducks/donations'; import { Select } from './Select'; export type PropsDataType = { i18n: LocalizerType; donationAmountsConfig: OneTimeDonationHumanAmounts | undefined; validCurrencies: ReadonlyArray; workflow: DonationWorkflow | undefined; }; type PropsHousekeepingType = { contentsRef: MutableRefObject; }; type PropsActionType = { clearWorkflow: () => void; submitDonation: (payload: SubmitDonationType) => void; onBack: () => void; }; export type PropsType = PropsDataType & PropsActionType & PropsHousekeepingType; export function PreferencesDonateFlow({ contentsRef, i18n, donationAmountsConfig, validCurrencies, workflow, clearWorkflow, submitDonation, onBack, }: PropsType): JSX.Element { const tryClose = useRef<() => void | undefined>(); const [confirmDiscardModal, confirmDiscardIf] = useConfirmDiscard({ i18n, name: 'PreferencesDonateFlow', tryClose, }); const [step, setStep] = useState<'amount' | 'paymentDetails'>('amount'); const [amount, setAmount] = useState(); const [currency, setCurrency] = useState(); const [cardExpirationMonth, setCardExpirationMonth] = useState(''); const [cardExpirationYear, setCardExpirationYear] = useState(''); const [cardNumber, setCardNumber] = useState(''); const [cardCvc, setCardCvc] = useState(''); const formattedCurrencyAmount = useMemo(() => { return toHumanCurrencyString({ amount, currency }); }, [amount, currency]); const handleAmountPickerResult = useCallback((result: AmountPickerResult) => { const { currency: pickedCurrency, amount: pickedAmount } = result; setAmount(pickedAmount); setCurrency(pickedCurrency); setStep('paymentDetails'); }, []); const handleDonateClicked = useCallback(() => { if (amount == null || currency == null) { return; } const paymentAmount = toStripeDonationAmount({ amount, currency }); submitDonation({ currencyType: currency, paymentAmount, paymentDetail: { expirationMonth: cardExpirationMonth, expirationYear: cardExpirationYear, number: cardNumber, cvc: cardCvc, }, }); }, [ amount, cardCvc, cardExpirationMonth, cardExpirationYear, cardNumber, currency, submitDonation, ]); const isDonateDisabled = workflow !== undefined; const onTryClose = useCallback(() => { const onDiscard = () => { // TODO: DESKTOP-8950 }; confirmDiscardIf(true, onDiscard); }, [confirmDiscardIf]); tryClose.current = onTryClose; let innerContent: JSX.Element; let handleBack: () => void; if (step === 'amount') { innerContent = ( ); // Dismiss DonateFlow and return to Donations home handleBack = () => onBack(); } else { innerContent = (
{workflow && (

Current Workflow

{JSON.stringify(workflow)}
)}
          {amount} {currency}
        
setCardNumber(value)} placeholder="0000000000000000" maxLengthCount={16} value={cardNumber} /> setCardExpirationMonth(value)} placeholder="MM" value={cardExpirationMonth} /> setCardExpirationYear(value)} placeholder="YY" value={cardExpirationYear} /> setCardCvc(value)} placeholder="123" value={cardCvc} />
); handleBack = () => { setStep('amount'); }; } const backButton = ( ); }