RocketChat/Rocket.Chat

View on GitHub
apps/meteor/client/hooks/useDownloadFromServiceWorker.ts

Summary

Maintainability
B
4 hrs
Test Coverage
import { Emitter } from '@rocket.chat/emitter';
import { useUniqueId } from '@rocket.chat/fuselage-hooks';
import { useCallback, useEffect } from 'react';
import { useTranslation } from 'react-i18next';

import { downloadAs } from '../lib/download';

const ee = new Emitter<Record<string, { result: ArrayBuffer; id: string }>>();

if ('serviceWorker' in navigator) {
    navigator.serviceWorker.addEventListener('message', (event) => {
        if (event.data.type === 'attachment-download-result') {
            const { result } = event.data as { result: ArrayBuffer; id: string };

            ee.emit(event.data.id, { result, id: event.data.id });
        }
    });
}

export const registerDownloadForUid = (uid: string, t: ReturnType<typeof useTranslation>['t'], title?: string) => {
    ee.once(uid, ({ result }) => {
        downloadAs({ data: [new Blob([result])] }, title ?? t('Download'));
    });
};

export const forAttachmentDownload = (uid: string, href: string, controller?: ServiceWorker | null) => {
    if (!controller) {
        controller = navigator?.serviceWorker?.controller;
    }

    if (!controller) {
        return;
    }

    controller?.postMessage({
        type: 'attachment-download',
        url: href,
        id: uid,
    });
};

export const useDownloadFromServiceWorker = (href: string, title?: string) => {
    const { controller } = navigator?.serviceWorker || {};

    const uid = useUniqueId();

    const { t } = useTranslation();

    useEffect(() => registerDownloadForUid(uid, t, title), [title, t, uid]);

    return {
        disabled: !controller,
        onContextMenu: useCallback((e) => e.preventDefault(), []),
        onClick: useCallback(
            (e: React.MouseEvent<HTMLElement, MouseEvent>) => {
                e.preventDefault();

                forAttachmentDownload(uid, href, controller);
            },
            [href, uid, controller],
        ),
    };
};