From f2c955fd5106b282c668cda8086b4b3122d13e2d Mon Sep 17 00:00:00 2001 From: Piotr Gawron <p.gawron@atcomp.pl> Date: Wed, 30 Oct 2024 13:37:51 +0100 Subject: [PATCH] add spiner (fetch in memory and download from memory) --- CHANGELOG | 2 + .../DownloadSubmap.component.tsx | 42 +++++++++++++++---- src/redux/export/export.utils.ts | 26 ++++++++++++ 3 files changed, 61 insertions(+), 9 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 2f472f0f..a244f595 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,8 @@ minerva-front (18.0.2) stable; urgency=medium * Bug fix: Terms of Service modal is not hidden by Select project modal when login via ORCID (#305) + * Bug fix: when downloading map there was missing spinner indicating the + download is in progress (#297) -- Piotr Gawron <piotr.gawron@uni.lu> Wed, 30 Oct 2024 13:00:00 +0200 diff --git a/src/components/Map/Drawer/SubmapsDrawer/SubmapItem/DownloadSubmap/DownloadSubmap.component.tsx b/src/components/Map/Drawer/SubmapsDrawer/SubmapItem/DownloadSubmap/DownloadSubmap.component.tsx index 01587d62..31652812 100644 --- a/src/components/Map/Drawer/SubmapsDrawer/SubmapItem/DownloadSubmap/DownloadSubmap.component.tsx +++ b/src/components/Map/Drawer/SubmapsDrawer/SubmapItem/DownloadSubmap/DownloadSubmap.component.tsx @@ -2,18 +2,34 @@ import { formatsHandlersSelector } from '@/redux/configuration/configuration.sel import { Button } from '@/shared/Button'; import { useSelect } from 'downshift'; import { useSelector } from 'react-redux'; +import Image from 'next/image'; +import spinnerIcon from '@/assets/vectors/icons/spinner.svg'; +import { useState } from 'react'; +import { downloadFileFromUrl } from '@/redux/export/export.utils'; import { SUBMAP_DOWNLOAD_HANDLERS_NAMES } from './DownloadSubmap.constants'; import { useGetSubmapDownloadUrl } from './utils/useGetSubmapDownloadUrl'; -export const DownloadSubmap = (): JSX.Element => { +export const DownloadSubmap = (): React.ReactNode => { const formatsHandlers = useSelector(formatsHandlersSelector); const formatsHandlersItems = Object.entries(formatsHandlers); const getSubmapDownloadUrl = useGetSubmapDownloadUrl(); - const { isOpen, getToggleButtonProps, getMenuProps } = useSelect({ + const [isDownloading, setIsDownloading] = useState<boolean>(false); + + const { isOpen, getToggleButtonProps, getMenuProps, closeMenu } = useSelect({ items: formatsHandlersItems, }); + const downloadSubmap = (handler: string) => { + return function () { + closeMenu(); + setIsDownloading(true); + downloadFileFromUrl(getSubmapDownloadUrl({ handler })).finally(function () { + setIsDownloading(false); + }); + }; + }; + return ( <div className="relative"> <Button @@ -22,6 +38,15 @@ export const DownloadSubmap = (): JSX.Element => { className="mr-4" {...getToggleButtonProps()} > + {isDownloading && ( + <Image + src={spinnerIcon} + alt="spinner icon" + height={12} + width={12} + className="mr-5 animate-spin" + /> + )} Download </Button> <ul @@ -34,14 +59,13 @@ export const DownloadSubmap = (): JSX.Element => { {isOpen && formatsHandlersItems.map(([formatId, handler]) => ( <li key={formatId}> - <a - className="flex flex-col border-t px-4 py-2 shadow-sm" - href={getSubmapDownloadUrl({ handler })} - target="_blank" - download + <Button + variantStyles="ghost" + className="flex w-full flex-col border-t px-4 py-2 shadow-sm" + onClick={downloadSubmap(handler)} > - <span>{SUBMAP_DOWNLOAD_HANDLERS_NAMES[formatId]}</span> - </a> + {SUBMAP_DOWNLOAD_HANDLERS_NAMES[formatId]} + </Button> </li> ))} </ul> diff --git a/src/redux/export/export.utils.ts b/src/redux/export/export.utils.ts index 60cba1fd..921c3812 100644 --- a/src/redux/export/export.utils.ts +++ b/src/redux/export/export.utils.ts @@ -1,3 +1,5 @@ +import axios from 'axios'; + export const downloadFileFromBlob = (data: string, filename: string): void => { const url = window.URL.createObjectURL(new Blob([data])); const link = document.createElement('a'); @@ -7,3 +9,27 @@ export const downloadFileFromBlob = (data: string, filename: string): void => { link.click(); link.remove(); }; + +export const downloadFileFromUrl = async (url: string): Promise<void> => { + const genericAxios = axios.create(); + + const response = await genericAxios.get(url, { + withCredentials: true, + responseType: 'arraybuffer', + }); + + const content = Buffer.from(response.data, 'binary'); + + let filename = 'file.xml'; + if (response.headers && response.headers['content-type'] === 'application/zip') { + filename = 'file.zip'; + } + + const tmpUrl = window.URL.createObjectURL(new Blob([content], { type: 'application/zip' })); + const link = document.createElement('a'); + link.href = tmpUrl; + link.setAttribute('download', filename); + document.body.appendChild(link); + link.click(); + link.remove(); +}; -- GitLab