1 import { type FC, useState } from 'react';
2 import { useSelector } from 'react-redux';
4 import { useFormik } from 'formik';
5 import { c } from 'ttag';
7 import { useNotifications } from '@proton/components';
8 import { usePassCore } from '@proton/pass/components/Core/PassCoreProvider';
9 import { ExportForm } from '@proton/pass/components/Export/ExportForm';
10 import { usePasswordUnlock } from '@proton/pass/components/Lock/PasswordUnlockProvider';
11 import { type ExportFormValues, ExportFormat } from '@proton/pass/lib/export/types';
12 import { validateExportForm } from '@proton/pass/lib/validation/export';
13 import { selectExtraPasswordEnabled } from '@proton/pass/store/selectors';
14 import type { MaybePromise } from '@proton/pass/types';
15 import { download } from '@proton/pass/utils/dom/download';
16 import { throwError } from '@proton/pass/utils/fp/throw';
17 import { logger } from '@proton/pass/utils/logger';
18 import { BRAND_NAME, PASS_APP_NAME } from '@proton/shared/lib/constants';
21 /** Optional assertion function that will be triggered
22 * immediately before an export request */
23 onConfirm: (password: string) => MaybePromise<void>;
26 export const Exporter: FC<Props> = ({ onConfirm }) => {
27 const { exportData } = usePassCore();
28 const { createNotification } = useNotifications();
30 const initialValues: ExportFormValues = { format: ExportFormat.PGP, passphrase: '' };
31 const [loading, setLoading] = useState(false);
33 const confirmPassword = usePasswordUnlock();
34 const hasExtraPassword = useSelector(selectExtraPasswordEnabled);
36 const form = useFormik<ExportFormValues>({
37 initialValues: initialValues,
38 initialErrors: validateExportForm(initialValues),
39 validateOnChange: true,
40 validateOnMount: true,
41 validate: validateExportForm,
42 onSubmit: async (values) => {
46 await confirmPassword({
47 message: hasExtraPassword
48 ? c('Info').t`Please confirm your extra password in order to export your ${PASS_APP_NAME} data`
50 .t`Please confirm your ${BRAND_NAME} password in order to export your ${PASS_APP_NAME} data`,
51 onSubmit: (password) => onConfirm(password),
52 onError: () => throwError({ name: 'AuthConfirmInvalidError' }),
53 onAbort: () => throwError({ name: 'AuthConfirmAbortError' }),
56 download(await exportData(values));
58 form.resetForm({ values: { ...form.values, passphrase: '' } });
59 void form.validateForm();
61 createNotification({ type: 'success', text: c('Info').t`Successfully exported all your items` });
63 const notification = (() => {
64 if (error instanceof Error) {
66 case 'AuthConfirmInvalidError':
68 .t`Authentication failed. Confirm your ${BRAND_NAME} password in order to proceed with the export`;
69 case 'AuthConfirmAbortError':
74 return c('Warning').t`An error occurred while exporting your data`;
77 logger.warn(`[Settings::Exporter] export failed`, error);
78 if (notification) createNotification({ type: 'error', text: notification });
85 return <ExportForm form={form} loading={loading} />;