RocketChat/Rocket.Chat

View on GitHub
apps/meteor/client/views/room/webdav/SaveToWebdavModal.tsx

Summary

Maintainability
A
3 hrs
Test Coverage
import type { MessageAttachment, IWebdavAccount } from '@rocket.chat/core-typings';
import type { SelectOption } from '@rocket.chat/fuselage';
import { Modal, Box, Button, FieldGroup, Field, FieldLabel, FieldRow, FieldError, Select, Throbber } from '@rocket.chat/fuselage';
import { useUniqueId } from '@rocket.chat/fuselage-hooks';
import { useMethod, useSetting, useToastMessageDispatch, useTranslation } from '@rocket.chat/ui-contexts';
import type { ReactElement } from 'react';
import React, { useState, useMemo, useEffect, useRef } from 'react';
import { useForm, Controller } from 'react-hook-form';

import { useWebDAVAccountIntegrationsQuery } from '../../../hooks/webdav/useWebDAVAccountIntegrationsQuery';
import { getWebdavServerName } from '../../../lib/getWebdavServerName';

type SaveToWebdavModalProps = {
    onClose: () => void;
    data: {
        attachment: MessageAttachment;
        url: string;
    };
};

const SaveToWebdavModal = ({ onClose, data }: SaveToWebdavModalProps): ReactElement => {
    const t = useTranslation();
    const [isLoading, setIsLoading] = useState(false);
    const dispatchToastMessage = useToastMessageDispatch();
    const uploadFileToWebdav = useMethod('uploadFileToWebdav');
    const fileRequest = useRef<XMLHttpRequest | null>(null);
    const accountIdField = useUniqueId();

    const {
        control,
        handleSubmit,
        formState: { errors },
    } = useForm<{ accountId: string }>();

    const enabled = useSetting<boolean>('Webdav_Integration_Enabled', false);

    const { data: value } = useWebDAVAccountIntegrationsQuery({ enabled });

    const accountsOptions: SelectOption[] = useMemo(() => {
        return value?.map(({ _id, ...current }) => [_id, getWebdavServerName(current)]) ?? [];
    }, [value]);

    useEffect(() => fileRequest.current?.abort, []);

    const handleSaveFile = ({ accountId }: { accountId: IWebdavAccount['_id'] }): void => {
        setIsLoading(true);

        const {
            url,
            attachment: { title },
        } = data;

        fileRequest.current = new XMLHttpRequest();
        fileRequest.current.open('GET', url, true);
        fileRequest.current.responseType = 'arraybuffer';
        fileRequest.current.onload = async (): Promise<void> => {
            const arrayBuffer = fileRequest.current?.response;
            if (arrayBuffer) {
                const fileData = new Uint8Array(arrayBuffer);

                try {
                    if (!title) {
                        throw new Error('File name is required');
                    }
                    const response = await uploadFileToWebdav(accountId, fileData, title);
                    if (!response.success) {
                        throw new Error(response.message ? t(response.message) : 'Error uploading file');
                    }
                    return dispatchToastMessage({ type: 'success', message: t('File_uploaded') });
                } catch (error) {
                    return dispatchToastMessage({ type: 'error', message: error });
                } finally {
                    setIsLoading(false);
                    onClose();
                }
            }
        };
        fileRequest.current.send(null);
    };

    return (
        <Modal wrapperFunction={(props) => <Box is='form' onSubmit={handleSubmit(handleSaveFile)} {...props} />}>
            <Modal.Header>
                <Modal.Title>{t('Save_To_Webdav')}</Modal.Title>
                <Modal.Close title={t('Close')} onClick={onClose} />
            </Modal.Header>
            <Modal.Content>
                {isLoading && (
                    <Box alignItems='center' display='flex' justifyContent='center' minHeight='x32'>
                        <Throbber />
                    </Box>
                )}
                {!isLoading && (
                    <FieldGroup>
                        <Field>
                            <FieldLabel>{t('Select_a_webdav_server')}</FieldLabel>
                            <FieldRow>
                                <Controller
                                    name='accountId'
                                    control={control}
                                    rules={{ required: true }}
                                    render={({ field }): ReactElement => (
                                        <Select {...field} options={accountsOptions} id={accountIdField} placeholder={t('Select_an_option')} />
                                    )}
                                />
                            </FieldRow>
                            {errors.accountId && <FieldError>{t('Field_required')}</FieldError>}
                        </Field>
                    </FieldGroup>
                )}
            </Modal.Content>
            <Modal.Footer>
                <Modal.FooterControllers>
                    <Button onClick={onClose}>{t('Cancel')}</Button>
                    <Button primary type='submit' loading={isLoading}>
                        {t('Save_To_Webdav')}
                    </Button>
                </Modal.FooterControllers>
            </Modal.Footer>
        </Modal>
    );
};
export default SaveToWebdavModal;