<commit_before>import { useEffect, useRef, useState } from 'react';
import * as React from 'react';
import { c } from 'ttag';
import { validateEmail, validatePhone } from '@proton/shared/lib/api/core/validate';
import { getApiErrorMessage } from '@proton/shared/lib/api/helpers/apiErrorHelper';
import { emailValidator, requiredValidator } from '@proton/shared/lib/helpers/formValidators';
import { noop } from '@proton/shared/lib/helpers/function';

import {
    Button,
    Challenge,
    useModals,
    useLoading,
    useApi,
    Tabs,
    useFormErrors,
    ConfirmModal,
    PhoneInput,
    InputFieldTwo,
    captureChallengeMessage,
    ChallengeResult,
    ChallengeRef,
} from '@proton/components';

import { SignupModel, SIGNUP_STEPS } from './interfaces';
import Loader from './Loader';

const { RECOVERY_EMAIL, RECOVERY_PHONE } = SIGNUP_STEPS;

interface Props {
    model: SignupModel;
    onChange: (model: Partial<SignupModel>) => void;
    onSubmit: (payload?: ChallengeResult) => void;
    onSkip: (payload?: ChallengeResult) => void;
    defaultCountry?: string;
    hasChallenge?: boolean;
}

const RecoveryForm = ({ model, hasChallenge, onChange, onSubmit, onSkip, defaultCountry }: Props) => {
    const api = useApi();
    const formRef = useRef<HTMLFormElement>(null);
    const [challengeLoading, setChallengeLoading] = useState(hasChallenge);
    const { createModal } = useModals();
    const challengeRefRecovery = useRef<ChallengeRef>();
    const [loading, withLoading] = useLoading();
    const [phoneError, setPhoneError] = useState('');
    const [emailError, setEmailError] = useState('');

    const { validator, onFormSubmit } = useFormErrors();

    const getOnChange = (field: keyof SignupModel) => (value: string) => onChange({ [field]: value });

    const setRecoveryPhone = getOnChange('recoveryPhone');
    const setRecoveryEmail = getOnChange('recoveryEmail');

    const handleSkip = async () => {
        await new Promise<void>((resolve, reject) => {
            createModal(
                <ConfirmModal title={c('Title').t`Warning`} onConfirm={resolve} onClose={reject} mode="alert">
                    {c('Info')
                        .t`You did not set a recovery method so account recovery is impossible if you forget your password. Proceed without recovery method?`}
                </ConfirmModal>
            );
        });
        const payload = await challengeRefRecovery.current?.getChallenge();
        return onSkip(payload);
    };

    const handleSubmit = async () => {
        if (loading || !onFormSubmit()) {
            return;
        }

        const payload = await challengeRefRecovery.current?.getChallenge();

        if (model.step === RECOVERY_EMAIL) {
            try {
                await api(validateEmail(model.recoveryEmail));
                return onSubmit(payload);
            } catch (error) {
                setEmailError(getApiErrorMessage(error) || c('Error').t`Can't validate email, try again later`);
                throw error;
            }
        }

        if (model.step === RECOVERY_PHONE) {
            try {
                await api(validatePhone(model.recoveryPhone));
                return onSubmit(payload);
            } catch (error) {
                setPhoneError(getApiErrorMessage(error) || c('Error').t`Can't validate phone, try again later`);
                throw error;
            }
        }
    };

    useEffect(() => {
        if (model.step === RECOVERY_EMAIL && !challengeLoading) {
            // Special focus management for challenge
            challengeRefRecovery.current?.focus('#recovery-email');
        }
    }, [model.step, challengeLoading]);

    const innerChallenge = model.step === RECOVERY_EMAIL && (
        <InputFieldTwo
            id="recovery-email"
            bigger
            label={c('Label').t`Recovery email`}
            error={validator(
                model.step === RECOVERY_EMAIL
                    ? [requiredValidator(model.recoveryEmail), emailValidator(model.recoveryEmail), emailError]
                    : []
            )}
            autoFocus
            disableChange={loading}
            type="email"
            value={model.recoveryEmail}
            onValue={(value: string) => {
                setEmailError('');
                setRecoveryEmail(value);
            }}
            onKeyDown={({ key }: React.KeyboardEvent<HTMLInputElement>) => {
                if (key === 'Enter') {
                    withLoading(handleSubmit()).catch(noop);
                }
            }}
        />
    );

    return (
        <>
            {model.step === RECOVERY_EMAIL && challengeLoading ? (
                <div className="text-center">
                    <Loader />
                </div>
            ) : null}
            <form
                name="recoveryForm"
                onSubmit={(e) => {
                    e.preventDefault();
                    withLoading(handleSubmit()).catch(noop);
                }}
                style={
                    model.step === RECOVERY_EMAIL && challengeLoading
                        ? {
                              position: 'absolute',
                              top: '-1000px',
                              left: '-1000px',
                          }
                        : undefined
                }
                ref={formRef}
                method="post"
                autoComplete="off"
                noValidate
            >
                <Tabs
                    value={model.step === RECOVERY_EMAIL ? 0 : model.step === RECOVERY_PHONE ? 1 : 0}
                    tabs={[
                        {
                            title: c('Label').t`Email`,
                            content: (
                                <>
                                    <div className="mb1-75">
                                        {c('Info')
                                            .t`We will send you a recovery link to this email address if you forget your password or get locked out of your account.`}
                                    </div>
                                </>
                            ),
                        },
                        {
                            title: c('Label').t`Phone`,
                            content: (
                                <>
                                    <div className="mb1-75">
                                        {c('Info')
                                            .t`We will send a code to this phone number if you forget your password or get locked out of your account.`}
                                    </div>
                                    <InputFieldTwo
                                        as={PhoneInput}
                                        id="recovery-phone"
                                        bigger
                                        label={c('Label').t`Recovery phone`}
                                        error={validator(
                                            model.step === RECOVERY_PHONE
                                                ? [requiredValidator(model.recoveryPhone), phoneError]
                                                : []
                                        )}
                                        disableChange={loading}
                                        autoFocus
                                        defaultCountry={defaultCountry}
                                        value={model.recoveryPhone}
                                        onChange={(value: string) => {
                                            setPhoneError('');<commit_msg>Add copy for recovery methods trust<commit_after>import { useEffect, useRef, useState } from 'react';
import * as React from 'react';
import { c } from 'ttag';
import { validateEmail, validatePhone } from '@proton/shared/lib/api/core/validate';
import { getApiErrorMessage } from '@proton/shared/lib/api/helpers/apiErrorHelper';
import { emailValidator, requiredValidator } from '@proton/shared/lib/helpers/formValidators';
import { noop } from '@proton/shared/lib/helpers/function';

import {
    Button,
    Challenge,
    useModals,
    useLoading,
    useApi,
    Tabs,
    useFormErrors,
    ConfirmModal,
    PhoneInput,
    InputFieldTwo,
    captureChallengeMessage,
    ChallengeResult,
    ChallengeRef,
} from '@proton/components';

import { SignupModel, SIGNUP_STEPS } from './interfaces';
import Loader from './Loader';

const { RECOVERY_EMAIL, RECOVERY_PHONE } = SIGNUP_STEPS;

interface Props {
    model: SignupModel;
    onChange: (model: Partial<SignupModel>) => void;
    onSubmit: (payload?: ChallengeResult) => void;
    onSkip: (payload?: ChallengeResult) => void;
    defaultCountry?: string;
    hasChallenge?: boolean;
}

const RecoveryForm = ({ model, hasChallenge, onChange, onSubmit, onSkip, defaultCountry }: Props) => {
    const api = useApi();
    const formRef = useRef<HTMLFormElement>(null);
    const [challengeLoading, setChallengeLoading] = useState(hasChallenge);
    const { createModal } = useModals();
    const challengeRefRecovery = useRef<ChallengeRef>();
    const [loading, withLoading] = useLoading();
    const [phoneError, setPhoneError] = useState('');
    const [emailError, setEmailError] = useState('');

    const { validator, onFormSubmit } = useFormErrors();

    const getOnChange = (field: keyof SignupModel) => (value: string) => onChange({ [field]: value });

    const setRecoveryPhone = getOnChange('recoveryPhone');
    const setRecoveryEmail = getOnChange('recoveryEmail');

    const handleSkip = async () => {
        await new Promise<void>((resolve, reject) => {
            createModal(
                <ConfirmModal title={c('Title').t`Warning`} onConfirm={resolve} onClose={reject} mode="alert">
                    {c('Info')
                        .t`You did not set a recovery method so account recovery is impossible if you forget your password. Proceed without recovery method?`}
                </ConfirmModal>
            );
        });
        const payload = await challengeRefRecovery.current?.getChallenge();
        return onSkip(payload);
    };

    const handleSubmit = async () => {
        if (loading || !onFormSubmit()) {
            return;
        }

        const payload = await challengeRefRecovery.current?.getChallenge();

        if (model.step === RECOVERY_EMAIL) {
            try {
                await api(validateEmail(model.recoveryEmail));
                return onSubmit(payload);
            } catch (error) {
                setEmailError(getApiErrorMessage(error) || c('Error').t`Can't validate email, try again later`);
                throw error;
            }
        }

        if (model.step === RECOVERY_PHONE) {
            try {
                await api(validatePhone(model.recoveryPhone));
                return onSubmit(payload);
            } catch (error) {
                setPhoneError(getApiErrorMessage(error) || c('Error').t`Can't validate phone, try again later`);
                throw error;
            }
        }
    };

    useEffect(() => {
        if (model.step === RECOVERY_EMAIL && !challengeLoading) {
            // Special focus management for challenge
            challengeRefRecovery.current?.focus('#recovery-email');
        }
    }, [model.step, challengeLoading]);

    const innerChallenge = model.step === RECOVERY_EMAIL && (
        <InputFieldTwo
            id="recovery-email"
            bigger
            label={c('Label').t`Recovery email`}
            error={validator(
                model.step === RECOVERY_EMAIL
                    ? [requiredValidator(model.recoveryEmail), emailValidator(model.recoveryEmail), emailError]
                    : []
            )}
            autoFocus
            disableChange={loading}
            type="email"
            value={model.recoveryEmail}
            onValue={(value: string) => {
                setEmailError('');
                setRecoveryEmail(value);
            }}
            onKeyDown={({ key }: React.KeyboardEvent<HTMLInputElement>) => {
                if (key === 'Enter') {
                    withLoading(handleSubmit()).catch(noop);
                }
            }}
        />
    );

    return (
        <>
            {model.step === RECOVERY_EMAIL && challengeLoading ? (
                <div className="text-center">
                    <Loader />
                </div>
            ) : null}
            <form
                name="recoveryForm"
                onSubmit={(e) => {
                    e.preventDefault();
                    withLoading(handleSubmit()).catch(noop);
                }}
                style={
                    model.step === RECOVERY_EMAIL && challengeLoading
                        ? {
                              position: 'absolute',
                              top: '-1000px',
                              left: '-1000px',
                          }
                        : undefined
                }
                ref={formRef}
                method="post"
                autoComplete="off"
                noValidate
            >
                <Tabs
                    value={model.step === RECOVERY_EMAIL ? 0 : model.step === RECOVERY_PHONE ? 1 : 0}
                    tabs={[
                        {
                            title: c('Label').t`Email`,
                            content: (
                                <>
                                    <div className="mb1-75">
                                        {c('Info')
                                            .t`We will send you a recovery link to this email address if you forget your password or get locked out of your account.`}
                                        <br />
                                        {c('Info').t`This email address will only be used for recovery purposes.`}
                                    </div>
                                </>
                            ),
                        },
                        {
                            title: c('Label').t`Phone`,
                            content: (
                                <>
                                    <div className="mb1-75">
                                        {c('Info')
                                            .t`We will send a code to this phone number if you forget your password or get locked out of your account.`}
                                        <br />
                                        {c('Info').t`This phone number will only be used for recovery purposes.`}
                                    </div>
                                    <InputFieldTwo
                                        as={PhoneInput}
                                        id="recovery-phone"
                                        bigger
                                        label={c('Label').t`Recovery phone`}
                                        error={validator(
                                            model.step === RECOVERY_PHONE
                                                ? [requiredValidator(model.recoveryPhone), phoneError]
                                                : []
                                        )}
                                        disableChange={loading}
                                        autoFocus
                                        defaultCountry={defaultCountry}
                                        value={model.recoveryPhone}
                                        onChange={(value: string) => {
                                            setPhoneError('');
{'fraction_non_alphanumeric': 0.10365195300095269, 'fraction_numerical': 0.0021594156875198475, 'mean_word_length': 1.2754335260115608, 'pattern_counts': {'":': 0, '<': 49, '<?xml version=': 0, '>': 73, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 68, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3221457', 'n_tokens_mistral': 3690, 'n_tokens_neox': 3541, 'n_words': 800}