import { unwrap } from '@pipu/core'; import { useMutation, useQueryClient } from '@tanstack/react-query'; import { useState } from 'react'; import { useTranslation } from 'react-i18next'; import { useSession } from '../../app/session'; import { useErrorText } from '../../shared/lib/errors'; import { Button, Dialog, FormError } from '../../shared/ui/ui'; import s from '../../pages/page.module.css'; import { downloadUserArchive, MAX_ARCHIVE_BYTES, parseUserArchive, type UserArchive } from './transfer'; export function UserTransfer() { const { t } = useTranslation(['admin', 'common']); const session = useSession(); const queryClient = useQueryClient(); const errorText = useErrorText(); const [open, setOpen] = useState(false); const [archive, setArchive] = useState(null); const [fileError, setFileError] = useState(false); const [reading, setReading] = useState(false); const exporting = useMutation({ mutationFn: async () => downloadUserArchive(unwrap(await session.client.GET('/api/v1/admin/users/export'))), }); const importing = useMutation({ mutationFn: async () => unwrap(await session.client.POST('/api/v1/admin/users/import', { body: archive! })), onSuccess: () => { setArchive(null); void queryClient.invalidateQueries({ queryKey: ['admin-users'] }); }, }); const busy = importing.isPending || reading; const close = () => { if (!busy) { setOpen(false); setArchive(null); } }; const read = async (file: File | undefined) => { setArchive(null); setFileError(false); importing.reset(); if (!file) return; setReading(true); try { if (file.size > MAX_ARCHIVE_BYTES) throw new Error('size'); setArchive(parseUserArchive(await file.text())); } catch { setFileError(true); } finally { setReading(false); } }; return <> {exporting.error ? errorText(exporting.error) : null} {open && }>

{t('transfer.description')}

{t('transfer.sensitive')}

{archive &&

{t('transfer.preview', { count: archive.users.length })}

} {fileError ? t('transfer.invalid') : importing.error ? errorText(importing.error) : null} {importing.data &&

{t('transfer.result', { count: importing.data.created, skipped: importing.data.skipped.length })}

{importing.data.skipped.length > 0 &&

{importing.data.skipped.join(', ')}

}
}
} ; }