From 61d8a0e4aaecd90af3c70510858448111f9d6444 Mon Sep 17 00:00:00 2001 From: IRBorisov <8611739+IRBorisov@users.noreply.github.com> Date: Sun, 16 Jul 2023 22:25:23 +0300 Subject: [PATCH] Implement trs file download --- rsconcept/frontend/src/backendAPI.ts | 23 ++++++++ .../frontend/src/context/RSFormContext.tsx | 24 ++++++-- .../src/pages/RSFormPage/RSFormCard.tsx | 55 ++++++++++++------- 3 files changed, 76 insertions(+), 26 deletions(-) diff --git a/rsconcept/frontend/src/backendAPI.ts b/rsconcept/frontend/src/backendAPI.ts index f8cad1b3..5336adf6 100644 --- a/rsconcept/frontend/src/backendAPI.ts +++ b/rsconcept/frontend/src/backendAPI.ts @@ -117,6 +117,14 @@ export async function deleteRSForm(target: string, request?: IFrontRequest) { }); } +export async function getTRSFile(target: string, request?: IFrontRequest) { + AxiosGetBlob({ + title: `RSForm TRS file for id=${target}`, + endpoint: `${config.url.BASE}rsforms/${target}/export-trs/`, + request: request + }); +} + export async function postClaimRSForm(target: string, request?: IFrontRequest) { AxiosPost({ title: `Claim on RSForm id=${target}`, @@ -141,6 +149,21 @@ function AxiosGet({endpoint, request, title}: IAxiosRequest) { }); } +function AxiosGetBlob({endpoint, request, title}: IAxiosRequest) { + if (title) console.log(`[[${title}]] requested`); + if (request?.setLoading) request?.setLoading(true); + axios.get(endpoint, {responseType: 'blob'}) + .then(function (response) { + if (request?.setLoading) request?.setLoading(false); + if (request?.onSucccess) request.onSucccess(response); + }) + .catch(function (error) { + if (request?.setLoading) request?.setLoading(false); + if (request?.showError) toast.error(error.message); + if (request?.onError) request.onError(error); + }); +} + function AxiosPost({endpoint, request, title}: IAxiosRequest) { if (title) console.log(`[[${title}]] posted`); if (request?.setLoading) request?.setLoading(true); diff --git a/rsconcept/frontend/src/context/RSFormContext.tsx b/rsconcept/frontend/src/context/RSFormContext.tsx index 32b3af5e..4c6229d9 100644 --- a/rsconcept/frontend/src/context/RSFormContext.tsx +++ b/rsconcept/frontend/src/context/RSFormContext.tsx @@ -1,9 +1,9 @@ -import { createContext, useState, useContext, useMemo, useEffect } from 'react'; +import { createContext, useState, useContext, useMemo } from 'react'; import { IConstituenta, IRSForm } from '../models'; import { useRSFormDetails } from '../hooks/useRSFormDetails'; import { ErrorInfo } from '../components/BackendError'; import { useAuth } from './AuthContext'; -import { BackendCallback, deleteRSForm, patchRSForm, postClaimRSForm } from '../backendAPI'; +import { BackendCallback, deleteRSForm, getTRSFile, patchRSForm, postClaimRSForm } from '../backendAPI'; interface IRSFormContext { schema?: IRSForm @@ -16,9 +16,10 @@ interface IRSFormContext { setActive: (cst: IConstituenta | undefined) => void reload: () => void - upload: (data: any, callback?: BackendCallback) => void + update: (data: any, callback?: BackendCallback) => void destroy: (callback: BackendCallback) => void claim: (callback: BackendCallback) => void + download: (callback: BackendCallback) => void } export const RSFormContext = createContext({ @@ -32,9 +33,10 @@ export const RSFormContext = createContext({ setActive: () => {}, reload: () => {}, - upload: () => {}, + update: () => {}, destroy: () => {}, claim: () => {}, + download: () => {}, }) interface RSFormStateProps { @@ -51,7 +53,7 @@ export const RSFormState = ({ id, children }: RSFormStateProps) => { const isEditable = useMemo(() => (user?.id === schema?.owner || user?.is_staff || false), [user, schema]); const isClaimable = useMemo(() => (user?.id !== schema?.owner || false), [user, schema]); - async function upload(data: any, callback?: BackendCallback) { + async function update(data: any, callback?: BackendCallback) { setError(undefined); patchRSForm(id, { data: data, @@ -82,12 +84,22 @@ export const RSFormState = ({ id, children }: RSFormStateProps) => { }); } + async function download(callback: BackendCallback) { + setError(undefined); + getTRSFile(id, { + showError: true, + setLoading: setProcessing, + onError: error => setError(error), + onSucccess: callback + }); + } + return ( { children } diff --git a/rsconcept/frontend/src/pages/RSFormPage/RSFormCard.tsx b/rsconcept/frontend/src/pages/RSFormPage/RSFormCard.tsx index 11eab76f..6bdaacea 100644 --- a/rsconcept/frontend/src/pages/RSFormPage/RSFormCard.tsx +++ b/rsconcept/frontend/src/pages/RSFormPage/RSFormCard.tsx @@ -4,24 +4,29 @@ import SubmitButton from '../../components/Common/SubmitButton'; import TextArea from '../../components/Common/TextArea'; import TextInput from '../../components/Common/TextInput'; import { useRSForm } from '../../context/RSFormContext'; -import { useCallback, useEffect, useState } from 'react'; +import { useCallback, useEffect, useRef, useState } from 'react'; import Button from '../../components/Common/Button'; import { CrownIcon, DownloadIcon, DumpBinIcon } from '../../components/Icons'; import { useUsers } from '../../context/UsersContext'; import { useNavigate } from 'react-router-dom'; import { toast } from 'react-toastify'; +import { AxiosResponse } from 'axios'; function RSFormCard() { const navigate = useNavigate(); const intl = useIntl(); const { getUserLabel } = useUsers(); - const { schema, upload, reload, isEditable, isClaimable, processing, destroy, claim } = useRSForm(); + const { schema, update, download, reload, isEditable, isClaimable, processing, destroy, claim } = useRSForm(); const [title, setTitle] = useState(''); const [alias, setAlias] = useState(''); const [comment, setComment] = useState(''); const [common, setCommon] = useState(false); + const fileRef = useRef(null); + const [fileURL, setFileUrl] = useState(); + const [fileName, setFileName] = useState(); + useEffect(() => { setTitle(schema!.title) setAlias(schema!.alias) @@ -31,18 +36,16 @@ function RSFormCard() { const handleSubmit = (event: React.FormEvent) => { event.preventDefault(); - if (!processing) { - const data = { - 'title': title, - 'alias': alias, - 'comment': comment, - 'is_common': common, - }; - upload(data, () => { - toast.success('Изменения сохранены'); - reload(); - }); - } + const data = { + 'title': title, + 'alias': alias, + 'comment': comment, + 'is_common': common, + }; + update(data, () => { + toast.success('Изменения сохранены'); + reload(); + }); }; const handleDelete = useCallback(() => { @@ -64,9 +67,17 @@ function RSFormCard() { }, [claim, reload]); const handleDownload = useCallback(() => { - // TODO: implement file download - toast.info('Загрузка в разработке'); - }, []); + download((response: AxiosResponse) => { + try { + setFileName((schema?.alias || 'Schema') + '.trs') + setFileUrl(URL.createObjectURL(new Blob([response.data]))); + fileRef.current?.click(); + if (fileURL) URL.revokeObjectURL(fileURL); + } catch (error: any) { + toast.error(error.message); + } + }); + }, [download, schema?.alias, fileURL]); return (
@@ -95,24 +106,28 @@ function RSFormCard() { />
- +