mirror of
https://github.com/IRBorisov/ConceptPortal.git
synced 2025-06-26 04:50:36 +03:00
Implement trs file download
This commit is contained in:
parent
555784b0b1
commit
61d8a0e4aa
|
@ -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) {
|
export async function postClaimRSForm(target: string, request?: IFrontRequest) {
|
||||||
AxiosPost({
|
AxiosPost({
|
||||||
title: `Claim on RSForm id=${target}`,
|
title: `Claim on RSForm id=${target}`,
|
||||||
|
@ -141,6 +149,21 @@ function AxiosGet<ReturnType>({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) {
|
function AxiosPost({endpoint, request, title}: IAxiosRequest) {
|
||||||
if (title) console.log(`[[${title}]] posted`);
|
if (title) console.log(`[[${title}]] posted`);
|
||||||
if (request?.setLoading) request?.setLoading(true);
|
if (request?.setLoading) request?.setLoading(true);
|
||||||
|
|
|
@ -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 { IConstituenta, IRSForm } from '../models';
|
||||||
import { useRSFormDetails } from '../hooks/useRSFormDetails';
|
import { useRSFormDetails } from '../hooks/useRSFormDetails';
|
||||||
import { ErrorInfo } from '../components/BackendError';
|
import { ErrorInfo } from '../components/BackendError';
|
||||||
import { useAuth } from './AuthContext';
|
import { useAuth } from './AuthContext';
|
||||||
import { BackendCallback, deleteRSForm, patchRSForm, postClaimRSForm } from '../backendAPI';
|
import { BackendCallback, deleteRSForm, getTRSFile, patchRSForm, postClaimRSForm } from '../backendAPI';
|
||||||
|
|
||||||
interface IRSFormContext {
|
interface IRSFormContext {
|
||||||
schema?: IRSForm
|
schema?: IRSForm
|
||||||
|
@ -16,9 +16,10 @@ interface IRSFormContext {
|
||||||
|
|
||||||
setActive: (cst: IConstituenta | undefined) => void
|
setActive: (cst: IConstituenta | undefined) => void
|
||||||
reload: () => void
|
reload: () => void
|
||||||
upload: (data: any, callback?: BackendCallback) => void
|
update: (data: any, callback?: BackendCallback) => void
|
||||||
destroy: (callback: BackendCallback) => void
|
destroy: (callback: BackendCallback) => void
|
||||||
claim: (callback: BackendCallback) => void
|
claim: (callback: BackendCallback) => void
|
||||||
|
download: (callback: BackendCallback) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
export const RSFormContext = createContext<IRSFormContext>({
|
export const RSFormContext = createContext<IRSFormContext>({
|
||||||
|
@ -32,9 +33,10 @@ export const RSFormContext = createContext<IRSFormContext>({
|
||||||
|
|
||||||
setActive: () => {},
|
setActive: () => {},
|
||||||
reload: () => {},
|
reload: () => {},
|
||||||
upload: () => {},
|
update: () => {},
|
||||||
destroy: () => {},
|
destroy: () => {},
|
||||||
claim: () => {},
|
claim: () => {},
|
||||||
|
download: () => {},
|
||||||
})
|
})
|
||||||
|
|
||||||
interface RSFormStateProps {
|
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 isEditable = useMemo(() => (user?.id === schema?.owner || user?.is_staff || false), [user, schema]);
|
||||||
const isClaimable = useMemo(() => (user?.id !== schema?.owner || 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);
|
setError(undefined);
|
||||||
patchRSForm(id, {
|
patchRSForm(id, {
|
||||||
data: data,
|
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 (
|
return (
|
||||||
<RSFormContext.Provider value={{
|
<RSFormContext.Provider value={{
|
||||||
schema, error, loading, processing,
|
schema, error, loading, processing,
|
||||||
active, setActive,
|
active, setActive,
|
||||||
isEditable, isClaimable,
|
isEditable, isClaimable,
|
||||||
reload, upload, destroy, claim
|
reload, update, download, destroy, claim
|
||||||
}}>
|
}}>
|
||||||
{ children }
|
{ children }
|
||||||
</RSFormContext.Provider>
|
</RSFormContext.Provider>
|
||||||
|
|
|
@ -4,24 +4,29 @@ import SubmitButton from '../../components/Common/SubmitButton';
|
||||||
import TextArea from '../../components/Common/TextArea';
|
import TextArea from '../../components/Common/TextArea';
|
||||||
import TextInput from '../../components/Common/TextInput';
|
import TextInput from '../../components/Common/TextInput';
|
||||||
import { useRSForm } from '../../context/RSFormContext';
|
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 Button from '../../components/Common/Button';
|
||||||
import { CrownIcon, DownloadIcon, DumpBinIcon } from '../../components/Icons';
|
import { CrownIcon, DownloadIcon, DumpBinIcon } from '../../components/Icons';
|
||||||
import { useUsers } from '../../context/UsersContext';
|
import { useUsers } from '../../context/UsersContext';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
|
import { AxiosResponse } from 'axios';
|
||||||
|
|
||||||
function RSFormCard() {
|
function RSFormCard() {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const { getUserLabel } = useUsers();
|
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 [title, setTitle] = useState('');
|
||||||
const [alias, setAlias] = useState('');
|
const [alias, setAlias] = useState('');
|
||||||
const [comment, setComment] = useState('');
|
const [comment, setComment] = useState('');
|
||||||
const [common, setCommon] = useState(false);
|
const [common, setCommon] = useState(false);
|
||||||
|
|
||||||
|
const fileRef = useRef<HTMLAnchorElement | null>(null);
|
||||||
|
const [fileURL, setFileUrl] = useState<string>();
|
||||||
|
const [fileName, setFileName] = useState<string>();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setTitle(schema!.title)
|
setTitle(schema!.title)
|
||||||
setAlias(schema!.alias)
|
setAlias(schema!.alias)
|
||||||
|
@ -31,18 +36,16 @@ function RSFormCard() {
|
||||||
|
|
||||||
const handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {
|
const handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
if (!processing) {
|
const data = {
|
||||||
const data = {
|
'title': title,
|
||||||
'title': title,
|
'alias': alias,
|
||||||
'alias': alias,
|
'comment': comment,
|
||||||
'comment': comment,
|
'is_common': common,
|
||||||
'is_common': common,
|
};
|
||||||
};
|
update(data, () => {
|
||||||
upload(data, () => {
|
toast.success('Изменения сохранены');
|
||||||
toast.success('Изменения сохранены');
|
reload();
|
||||||
reload();
|
});
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleDelete = useCallback(() => {
|
const handleDelete = useCallback(() => {
|
||||||
|
@ -64,9 +67,17 @@ function RSFormCard() {
|
||||||
}, [claim, reload]);
|
}, [claim, reload]);
|
||||||
|
|
||||||
const handleDownload = useCallback(() => {
|
const handleDownload = useCallback(() => {
|
||||||
// TODO: implement file download
|
download((response: AxiosResponse) => {
|
||||||
toast.info('Загрузка в разработке');
|
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 (
|
return (
|
||||||
<form onSubmit={handleSubmit} className='flex-grow max-w-xl px-4 py-2 border'>
|
<form onSubmit={handleSubmit} className='flex-grow max-w-xl px-4 py-2 border'>
|
||||||
|
@ -95,24 +106,28 @@ function RSFormCard() {
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div className='flex items-center justify-between gap-1 py-2 mt-2'>
|
<div className='flex items-center justify-between gap-1 py-2 mt-2'>
|
||||||
<SubmitButton text='Сохранить изменения' loading={processing} disabled={!isEditable} />
|
<SubmitButton text='Сохранить изменения' loading={processing} disabled={!isEditable || processing} />
|
||||||
<div className='flex justify-end gap-1'>
|
<div className='flex justify-end gap-1'>
|
||||||
<Button
|
<Button
|
||||||
|
disabled={processing}
|
||||||
tooltip='Скачать TRS файл'
|
tooltip='Скачать TRS файл'
|
||||||
icon={<DownloadIcon />}
|
icon={<DownloadIcon />}
|
||||||
loading={processing}
|
loading={processing}
|
||||||
onClick={handleDownload}
|
onClick={handleDownload}
|
||||||
/>
|
/>
|
||||||
|
<a href={fileURL} download={fileName} className='hidden' ref={fileRef}>
|
||||||
|
<i aria-hidden="true"/>
|
||||||
|
</a>
|
||||||
<Button
|
<Button
|
||||||
tooltip={isClaimable ? 'Стать владельцем' : 'Вы уже являетесь владельцем' }
|
tooltip={isClaimable ? 'Стать владельцем' : 'Вы уже являетесь владельцем' }
|
||||||
disabled={!isClaimable}
|
disabled={!isClaimable || processing}
|
||||||
icon={<CrownIcon />}
|
icon={<CrownIcon />}
|
||||||
colorClass='text-green-400 dark:text-green-500'
|
colorClass='text-green-400 dark:text-green-500'
|
||||||
onClick={handleClaimOwner}
|
onClick={handleClaimOwner}
|
||||||
/>
|
/>
|
||||||
<Button
|
<Button
|
||||||
tooltip={ isEditable ? 'Удалить схему' : 'Вы не можете редактировать данную схему'}
|
tooltip={ isEditable ? 'Удалить схему' : 'Вы не можете редактировать данную схему'}
|
||||||
disabled={!isEditable}
|
disabled={!isEditable || processing}
|
||||||
icon={<DumpBinIcon />}
|
icon={<DumpBinIcon />}
|
||||||
colorClass='text-red-400 dark:text-red-600'
|
colorClass='text-red-400 dark:text-red-600'
|
||||||
loading={processing}
|
loading={processing}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user