Refactor backend API calls and add toasts

This commit is contained in:
IRBorisov 2023-07-15 17:57:25 +03:00
parent eb045905d8
commit 484b1a9ea1
16 changed files with 343 additions and 231 deletions

View File

@ -12,12 +12,19 @@ import RegisterPage from './pages/RegisterPage';
import ManualsPage from './pages/ManualsPage'; import ManualsPage from './pages/ManualsPage';
import Footer from './components/Footer'; import Footer from './components/Footer';
import RSFormCreatePage from './pages/RSFormCreatePage'; import RSFormCreatePage from './pages/RSFormCreatePage';
import ToasterThemed from './components/ToasterThemed';
function App() { function App() {
return ( return (
<div className='antialiased bg-gray-50 dark:bg-gray-800'> <div className='antialiased bg-gray-50 dark:bg-gray-800'>
<Navigation /> <Navigation />
<main className='min-h-[calc(100vh-107px)] px-2 h-fit'> <main className='min-h-[calc(100vh-107px)] px-2 h-fit'>
<ToasterThemed
className='mt-[4rem]'
autoClose={3000}
draggable={false}
limit={5}
/>
<Routes> <Routes>
<Route path='/' element={ <HomePage/>} /> <Route path='/' element={ <HomePage/>} />

View File

@ -0,0 +1,179 @@
import axios, { AxiosResponse } from 'axios'
import { config } from './constants'
import { ErrorInfo } from './components/BackendError'
import { toast } from 'react-toastify'
import { ICurrentUser, IRSForm, IUserInfo, IUserProfile } from './models'
export type BackendCallback = (response: AxiosResponse) => void;
export interface IFrontRequest {
onSucccess?: BackendCallback
onError?: (error: ErrorInfo) => void
setLoading?: (loading: boolean) => void
showError?: boolean
data?: any
}
interface IAxiosRequest {
endpoint: string
request?: IFrontRequest
title?: string
}
// ================= Export API ==============
export async function postLogin(request?: IFrontRequest) {
AxiosPost({
title: 'Login',
endpoint: `${config.url.AUTH}login`,
request: request
});
}
export async function getAuth(request?: IFrontRequest) {
AxiosGet<ICurrentUser>({
title: 'Current user',
endpoint: `${config.url.AUTH}auth`,
request: request
});
}
export async function getProfile(request?: IFrontRequest) {
AxiosGet<IUserProfile>({
title: 'Current user profile',
endpoint: `${config.url.AUTH}profile`,
request: request
});
}
export async function postLogout(request?: IFrontRequest) {
AxiosPost({
title: 'Logout',
endpoint: `${config.url.AUTH}logout`,
request: request
});
};
export async function postSignup(request?: IFrontRequest) {
AxiosPost({
title: 'Register user',
endpoint: `${config.url.AUTH}signup`,
request: request
});
}
export async function getActiveUsers(request?: IFrontRequest) {
AxiosGet<IUserInfo>({
title: 'Active users list',
endpoint: `${config.url.AUTH}active-users`,
request: request
});
}
export async function getRSForms(request?: IFrontRequest) {
AxiosGet<IRSForm[]>({
title: `RSForms list`,
endpoint: `${config.url.BASE}rsforms/`,
request: request
});
}
export async function postNewRSForm(request?: IFrontRequest) {
AxiosPost({
title: `New RSForm`,
endpoint: `${config.url.BASE}rsforms/create-detailed/`,
request: request
});
}
export async function getRSFormDetails(target: string, request?: IFrontRequest) {
AxiosGet<IRSForm>({
title: `RSForm details for id=${target}`,
endpoint: `${config.url.BASE}rsforms/${target}/details/`,
request: request
});
}
export async function patchRSForm(target: string, request?: IFrontRequest) {
AxiosPatch({
title: `RSForm id=${target}`,
endpoint: `${config.url.BASE}rsforms/${target}/`,
request: request
});
}
export async function deleteRSForm(target: string, request?: IFrontRequest) {
AxiosDelete({
title: `RSForm id=${target}`,
endpoint: `${config.url.BASE}rsforms/${target}/`,
request: request
});
}
export async function postClaimRSForm(target: string, request?: IFrontRequest) {
AxiosPost({
title: `Claim on RSForm id=${target}`,
endpoint: `${config.url.BASE}rsforms/${target}/claim/`,
request: request
});
}
// ====== Helper functions ===========
function AxiosGet<ReturnType>({endpoint, request, title}: IAxiosRequest) {
if (title) console.log(`[[${title}]] requested`);
if (request?.setLoading) request?.setLoading(true);
axios.get<ReturnType>(endpoint)
.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);
axios.post(endpoint, request?.data)
.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 AxiosDelete({endpoint, request, title}: IAxiosRequest) {
if (title) console.log(`[[${title}]] is being deleted`);
if (request?.setLoading) request?.setLoading(true);
axios.delete(endpoint)
.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 AxiosPatch({endpoint, request, title}: IAxiosRequest) {
if (title) console.log(`[[${title}]] is being patrially updated`);
if (request?.setLoading) request?.setLoading(true);
axios.patch(endpoint, request?.data)
.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);
});
}

View File

@ -0,0 +1,14 @@
import { ToastContainer, ToastContainerProps } from 'react-toastify';
import { useTheme } from '../context/ThemeContext';
function ToasterThemed({theme, ...props}: ToastContainerProps) {
const { darkMode } = useTheme();
return (
<ToastContainer
theme={ darkMode ? 'dark' : 'light'}
{...props}
/>
);
}
export default ToasterThemed;

View File

@ -1,17 +1,15 @@
import axios from 'axios';
import { createContext, useCallback, useContext, useEffect, useState } from 'react'; import { createContext, useCallback, useContext, useEffect, useState } from 'react';
import { config } from '../constants';
import { ICurrentUser, IUserSignupData } from '../models'; import { ICurrentUser, IUserSignupData } from '../models';
import { ErrorInfo } from '../components/BackendError'; import { ErrorInfo } from '../components/BackendError';
import useLocalStorage from '../hooks/useLocalStorage'; import useLocalStorage from '../hooks/useLocalStorage';
import { getAuth, postLogin, postLogout, postSignup } from '../backendAPI';
interface IAuthContext { interface IAuthContext {
user: ICurrentUser | undefined user: ICurrentUser | undefined
login: (username: string, password: string, onSuccess?: Function) => void login: (username: string, password: string, onSuccess?: () => void) => void
logout: (onSuccess?: Function) => void logout: (onSuccess?: () => void) => void
signup: (data: IUserSignupData, onSuccess?: Function) => void signup: (data: IUserSignupData, onSuccess?: () => void) => void
loading: boolean loading: boolean
error: ErrorInfo error: ErrorInfo
setError: (error: ErrorInfo) => void setError: (error: ErrorInfo) => void
@ -38,74 +36,55 @@ export const AuthState = ({ children }: AuthStateProps) => {
const loadCurrentUser = useCallback( const loadCurrentUser = useCallback(
async () => { async () => {
setError(undefined); getAuth({
setLoading(true); onError: error => setUser(undefined),
console.log('Current user requested'); onSucccess: response => {
axios.get<ICurrentUser>(`${config.url.AUTH}auth`)
.then(function (response) {
setLoading(false);
if (response.data.id) { if (response.data.id) {
setUser(response.data); setUser(response.data);
} else { } else {
setUser(undefined) setUser(undefined)
} }
}) }
.catch(function (error) {
setLoading(false);
setUser(undefined);
setError(error);
}); });
}, [setUser] }, [setUser]
); );
async function login(uname: string, pw: string, onSuccess?: Function) { async function login(uname: string, pw: string, onSuccess?: () => void) {
setLoading(true);
setError(undefined); setError(undefined);
axios.post(`${config.url.AUTH}login`, {username: uname, password: pw}) postLogin({
.then(function (response) { data: {username: uname, password: pw},
setLoading(false); showError: true,
setLoading: setLoading,
onError: error => setError(error),
onSucccess: response => {
loadCurrentUser(); loadCurrentUser();
if(onSuccess) { if(onSuccess) onSuccess();
onSuccess();
} }
})
.catch(function (error) {
setLoading(false);
setError(error);
}); });
} }
async function logout(onSuccess?: Function) { async function logout(onSuccess?: () => void) {
setLoading(true);
setError(undefined); setError(undefined);
axios.post(`${config.url.AUTH}logout`) postLogout({
.then(function (response) { showError: true,
setLoading(false); onSucccess: response => {
loadCurrentUser(); loadCurrentUser();
if(onSuccess) { if(onSuccess) onSuccess();
onSuccess();
} }
})
.catch(function (error) {
setLoading(false);
setError(error);
}); });
} }
async function signup(data: IUserSignupData, onSuccess?: Function) { async function signup(data: IUserSignupData, onSuccess?: () => void) {
setLoading(true);
setError(undefined); setError(undefined);
axios.post(`${config.url.AUTH}signup`, data) postSignup({
.then(function (response) { data: data,
setLoading(false); showError: true,
setLoading: setLoading,
onError: error => setError(error),
onSucccess: response => {
loadCurrentUser(); loadCurrentUser();
if(onSuccess) { if(onSuccess) onSuccess();
onSuccess();
} }
})
.catch(function (error) {
setLoading(false);
setError(error);
}); });
} }

View File

@ -3,8 +3,7 @@ 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 axios from 'axios'; import { BackendCallback, deleteRSForm, patchRSForm, postClaimRSForm } from '../backendAPI';
import { config } from '../constants';
interface IRSFormContext { interface IRSFormContext {
schema?: IRSForm schema?: IRSForm
@ -17,9 +16,9 @@ interface IRSFormContext {
setActive: (cst: IConstituenta) => void setActive: (cst: IConstituenta) => void
reload: () => void reload: () => void
upload: (data: any, callback: Function) => void upload: (data: any, callback?: BackendCallback) => void
destroy: (callback: Function) => void destroy: (callback: BackendCallback) => void
claim: (callback: Function) => void claim: (callback: BackendCallback) => void
} }
export const RSFormContext = createContext<IRSFormContext>({ export const RSFormContext = createContext<IRSFormContext>({
@ -58,49 +57,34 @@ export const RSFormState = ({ id, children }: RSFormStateProps) => {
} }
}, [schema]) }, [schema])
async function upload(data: any, callback?: Function) { async function upload(data: any, callback?: BackendCallback) {
console.log(`Update rsform with ${data}`);
data['id'] = {id}
setError(undefined); setError(undefined);
setProcessing(true); patchRSForm(id, {
axios.patch(`${config.url.BASE}rsforms/${id}/`, data) data: data,
.then(function (response) { showError: true,
setProcessing(false); setLoading: setProcessing,
if (callback) callback(response.data); onError: error => setError(error),
}) onSucccess: callback
.catch(function (error) {
setProcessing(false);
setError(error);
}); });
} }
async function destroy(callback?: Function) { async function destroy(callback: BackendCallback) {
console.log(`Deleting rsform ${id}`);
setError(undefined); setError(undefined);
setProcessing(true); deleteRSForm(id, {
axios.delete(`${config.url.BASE}rsforms/${id}/`) showError: true,
.then(function (response) { setLoading: setProcessing,
setProcessing(false); onError: error => setError(error),
if (callback) callback(); onSucccess: callback
})
.catch(function (error) {
setProcessing(false);
setError(error);
}); });
} }
async function claim(callback?: Function) { async function claim(callback: BackendCallback) {
console.log(`Claiming rsform ${id}`);
setError(undefined); setError(undefined);
setProcessing(true); postClaimRSForm(id, {
axios.post(`${config.url.BASE}rsforms/${id}/claim/`) showError: true,
.then(function (response) { setLoading: setProcessing,
setProcessing(false); onError: error => setError(error),
if (callback) callback(); onSucccess: callback
})
.catch(function (error) {
setProcessing(false);
setError(error);
}); });
} }

View File

@ -1,22 +1,16 @@
import axios from 'axios'
import { createContext, useCallback, useContext, useEffect, useState } from 'react' import { createContext, useCallback, useContext, useEffect, useState } from 'react'
import { IUserInfo } from '../models' import { IUserInfo } from '../models'
import { config } from '../constants' import { getActiveUsers } from '../backendAPI'
import { ErrorInfo } from '../components/BackendError'
interface IUsersContext { interface IUsersContext {
users: IUserInfo[] users: IUserInfo[]
error: ErrorInfo
loading: boolean
reload: () => void reload: () => void
getUserLabel: (userID?: number) => string getUserLabel: (userID?: number) => string
} }
export const UsersContext = createContext<IUsersContext>({ export const UsersContext = createContext<IUsersContext>({
users: [], users: [],
error: undefined,
loading: false,
reload: () => {}, reload: () => {},
getUserLabel: () => '' getUserLabel: () => ''
}) })
@ -27,8 +21,6 @@ interface UsersStateProps {
export const UsersState = ({ children }: UsersStateProps) => { export const UsersState = ({ children }: UsersStateProps) => {
const [users, setUsers] = useState<IUserInfo[]>([]); const [users, setUsers] = useState<IUserInfo[]>([]);
const [loading, setLoading] = useState(false);
const [error, setError] = useState<ErrorInfo>(undefined);
const getUserLabel = (userID?: number) => { const getUserLabel = (userID?: number) => {
const user = users.find(({id}) => id === userID); const user = users.find(({id}) => id === userID);
@ -49,18 +41,12 @@ export const UsersState = ({ children }: UsersStateProps) => {
const reload = useCallback( const reload = useCallback(
async () => { async () => {
setError(undefined); getActiveUsers({
setLoading(true); showError: true,
console.log('Profile requested'); onError: error => setUsers([]),
axios.get<IUserInfo[]>(`${config.url.AUTH}active-users`) onSucccess: response => {
.then(function (response) { setUsers(response ? response.data : []);
setLoading(false); }
setUsers(response.data);
})
.catch(function (error) {
setLoading(false);
setUsers([]);
setError(error);
}); });
}, [setUsers] }, [setUsers]
); );
@ -72,7 +58,6 @@ export const UsersState = ({ children }: UsersStateProps) => {
return ( return (
<UsersContext.Provider value={{ <UsersContext.Provider value={{
users, users,
error, loading,
reload, getUserLabel reload, getUserLabel
}}> }}>
{ children } { children }

View File

@ -1,29 +0,0 @@
import axios from 'axios'
import { IUserProfile } from '../models'
import { config } from '../constants'
import { ErrorInfo } from '../components/BackendError'
function useAPI() {
async function getProfile(
args?: {onSucccess: Function, onError: Function}) {
// setError(undefined);
// setLoading(true);
// console.log('Profile requested');
// axios.get<IUserProfile>(`${config.url.AUTH}profile`)
// .then(function (response) {
// setLoading(false);
// return response.data;
// })
// .catch(function (error) {
// setLoading(false);
// setError(error);
// return undefined;
// });
}
return {
getProfile
};
}
export default useAPI;

View File

@ -1,33 +1,30 @@
import axios from 'axios'
import { useState } from 'react' import { useState } from 'react'
import { config } from '../constants'
import { ErrorInfo } from '../components/BackendError'; import { ErrorInfo } from '../components/BackendError';
import { postNewRSForm } from '../backendAPI';
function useNewRSForm({callback}: {callback: (newID: string) => void}) { function useNewRSForm() {
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const [error, setError] = useState<ErrorInfo>(undefined); const [error, setError] = useState<ErrorInfo>(undefined);
async function createNew({data, file}: {data: any, file?: File}) { async function createSchema({data, file, onSuccess}: {
data: any, file?: File,
onSuccess: (newID: string) => void
}) {
setError(undefined); setError(undefined);
setLoading(true);
if (file) { if (file) {
data['file']=file; data['file'] = file;
data['fileName']=file.name; data['fileName'] = file.name;
} }
axios.post(`${config.url.BASE}rsforms/create-detailed/`, data) postNewRSForm({
.then(function (response) { data: data,
setLoading(false); showError: true,
if(callback) { setLoading: setLoading,
callback(response.data.id); onError: error => setError(error),
} onSucccess: response => onSuccess(response.data.id)
})
.catch(function (error) {
setLoading(false);
setError(error);
}); });
} }
return { createNew, error, setError, loading }; return { createSchema, error, setError, loading };
} }
export default useNewRSForm; export default useNewRSForm;

View File

@ -1,8 +1,7 @@
import axios from 'axios'
import { config } from '../constants';
import { useCallback, useEffect, useState } from 'react' import { useCallback, useEffect, useState } from 'react'
import { IRSForm } from '../models' import { IRSForm } from '../models'
import { ErrorInfo } from '../components/BackendError'; import { ErrorInfo } from '../components/BackendError';
import { getRSFormDetails } from '../backendAPI';
export function useRSFormDetails({target}: {target?: string}) { export function useRSFormDetails({target}: {target?: string}) {
const [schema, setSchema] = useState<IRSForm | undefined>(); const [schema, setSchema] = useState<IRSForm | undefined>();
@ -10,21 +9,16 @@ export function useRSFormDetails({target}: {target?: string}) {
const [error, setError] = useState<ErrorInfo>(undefined); const [error, setError] = useState<ErrorInfo>(undefined);
const fetchData = useCallback(async () => { const fetchData = useCallback(async () => {
console.log(`Requesting rsform ${target}`);
setError(undefined); setError(undefined);
setSchema(undefined); setSchema(undefined);
if (!target) { if (!target) {
return; return;
} }
setLoading(true); getRSFormDetails(target, {
axios.get<IRSForm>(`${config.url.BASE}rsforms/${target}/details/`) showError: true,
.then(function (response) { setLoading: setLoading,
setLoading(false); onError: error => setError(error),
setSchema(response.data); onSucccess: response => setSchema(response.data)
})
.catch(function (error) {
setLoading(false);
setError(error);
}); });
}, [target]); }, [target]);

View File

@ -1,32 +1,25 @@
import axios from 'axios' import { useCallback, useEffect, useState } from 'react'
import { useEffect, useState } from 'react'
import { IRSForm } from '../models' import { IRSForm } from '../models'
import { config } from '../constants'
import { ErrorInfo } from '../components/BackendError'; import { ErrorInfo } from '../components/BackendError';
import { getRSForms } from '../backendAPI';
export function useRSForms() { export function useRSForms() {
const [rsforms, setRSForms] = useState<IRSForm[]>([]); const [rsforms, setRSForms] = useState<IRSForm[]>([]);
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const [error, setError] = useState<ErrorInfo>(undefined); const [error, setError] = useState<ErrorInfo>(undefined);
async function fetchRSForms() { const fetchData = useCallback(async () => {
setError(undefined); getRSForms({
setLoading(true); showError: true,
console.log('RSForms requested'); setLoading: setLoading,
axios.get<IRSForm[]>(`${config.url.BASE}rsforms/`) onError: error => setError(error),
.then(function (response) { onSucccess: response => setRSForms(response.data)
setLoading(false);
setRSForms(response.data);
})
.catch(function (error) {
setLoading(false);
setError(error);
}); });
} }, []);
useEffect(() => { useEffect(() => {
fetchRSForms(); fetchData();
}, []) }, [fetchData])
return { rsforms, error, loading }; return { rsforms, error, loading };
} }

View File

@ -1,8 +1,7 @@
import axios from 'axios'
import { useCallback, useEffect, useState } from 'react' import { useCallback, useEffect, useState } from 'react'
import { IUserProfile } from '../models' import { IUserProfile } from '../models'
import { config } from '../constants'
import { ErrorInfo } from '../components/BackendError' import { ErrorInfo } from '../components/BackendError'
import { getProfile } from '../backendAPI'
export function useUserProfile() { export function useUserProfile() {
@ -13,17 +12,12 @@ export function useUserProfile() {
const fetchUser = useCallback( const fetchUser = useCallback(
async () => { async () => {
setError(undefined); setError(undefined);
setLoading(true);
console.log('Profile requested');
axios.get<IUserProfile>(`${config.url.AUTH}profile`)
.then(function (response) {
setLoading(false);
setUser(response.data);
})
.catch(function (error) {
setLoading(false);
setUser(undefined); setUser(undefined);
setError(error); getProfile({
showError: true,
setLoading: setLoading,
onError: error => setError(error),
onSucccess: response => setUser(response.data)
}); });
}, [setUser] }, [setUser]
) )

View File

@ -2,9 +2,10 @@
import React from 'react'; import React from 'react';
import axios from 'axios'; import axios from 'axios';
import './index.css';
import 'react-toastify/dist/ReactToastify.css';
import ReactDOM from 'react-dom/client'; import ReactDOM from 'react-dom/client';
import { BrowserRouter } from 'react-router-dom'; import { BrowserRouter } from 'react-router-dom';
import './index.css';
import App from './App'; import App from './App';
import { AuthState } from './context/AuthContext'; import { AuthState } from './context/AuthContext';
import { ThemeState } from './context/ThemeContext'; import { ThemeState } from './context/ThemeContext';

View File

@ -20,6 +20,7 @@ function LoginPage() {
useEffect(() => { useEffect(() => {
const name = new URLSearchParams(search).get('username'); const name = new URLSearchParams(search).get('username');
setUsername(name || ''); setUsername(name || '');
setPassword('');
}, [search]); }, [search]);
useEffect(() => { useEffect(() => {
@ -37,7 +38,7 @@ function LoginPage() {
<div className='container py-2'> { user ? <div className='container py-2'> { user ?
<InfoMessage message={`Вы вошли в систему как ${user.username}`} /> <InfoMessage message={`Вы вошли в систему как ${user.username}`} />
: :
<Form title='Ввод данных пользователя' onSubmit={handleSubmit} widthClass='max-w-sm'> <Form title='Ввод данных пользователя' onSubmit={handleSubmit} widthClass='w-[20rem]'>
<TextInput id='username' <TextInput id='username'
label='Имя пользователя' label='Имя пользователя'
required required
@ -49,10 +50,11 @@ function LoginPage() {
label='Пароль' label='Пароль'
required required
type='password' type='password'
value={password}
onChange={event => setPassword(event.target.value)} onChange={event => setPassword(event.target.value)}
/> />
<div className='flex items-center justify-between mt-4 mb-2'> <div className='flex items-center justify-between mt-4'>
<SubmitButton text='Вход' loading={loading}/> <SubmitButton text='Вход' loading={loading}/>
<TextURL text='Восстановить пароль...' href='restore-password' /> <TextURL text='Восстановить пароль...' href='restore-password' />
</div> </div>

View File

@ -11,6 +11,7 @@ import { useNavigate } from 'react-router-dom';
import TextArea from '../components/Common/TextArea'; import TextArea from '../components/Common/TextArea';
import Checkbox from '../components/Common/Checkbox'; import Checkbox from '../components/Common/Checkbox';
import FileInput from '../components/Common/FileInput'; import FileInput from '../components/Common/FileInput';
import { toast } from 'react-toastify';
function RSFormCreatePage() { function RSFormCreatePage() {
const navigate = useNavigate(); const navigate = useNavigate();
@ -29,8 +30,11 @@ function RSFormCreatePage() {
} }
} }
const onSuccess = (newID: string) => navigate(`/rsforms/${newID}`); const onSuccess = (newID: string) => {
const { createNew, error, setError, loading } = useNewRSForm({callback: onSuccess}) toast.success('Схема успешно создана');
navigate(`/rsforms/${newID}`);
}
const { createSchema, error, setError, loading } = useNewRSForm()
useEffect(() => { useEffect(() => {
setError(undefined) setError(undefined)
@ -45,7 +49,11 @@ function RSFormCreatePage() {
'comment': comment, 'comment': comment,
'is_common': common, 'is_common': common,
}; };
createNew({data: data, file: file}); createSchema({
data: data,
file: file,
onSuccess: onSuccess
});
} }
}; };

View File

@ -6,10 +6,10 @@ 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, useState } from 'react';
import Button from '../../components/Common/Button'; import Button from '../../components/Common/Button';
import { CrownIcon, DownloadIcon, DumpBinIcon, UploadIcon } 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 FileInput from '../../components/Common/FileInput'; import { toast } from 'react-toastify';
function RSFormCard() { function RSFormCard() {
const navigate = useNavigate(); const navigate = useNavigate();
@ -22,8 +22,6 @@ function RSFormCard() {
const [comment, setComment] = useState(''); const [comment, setComment] = useState('');
const [common, setCommon] = useState(false); const [common, setCommon] = useState(false);
const onSuccess = (data: any) => reload();
useEffect(() => { useEffect(() => {
setTitle(schema!.title) setTitle(schema!.title)
setAlias(schema!.alias) setAlias(schema!.alias)
@ -40,28 +38,34 @@ function RSFormCard() {
'comment': comment, 'comment': comment,
'is_common': common, 'is_common': common,
}; };
upload(data, onSuccess); upload(data, () => {
toast.success('Изменения сохранены');
reload();
});
} }
}; };
const handleDelete = useCallback(() => { const handleDelete = useCallback(() => {
if (window.confirm('Вы уверены, что хотите удалить данную схему?')) { if (window.confirm('Вы уверены, что хотите удалить данную схему?')) {
destroy(() => navigate('/rsforms?filter=owned')) destroy(() => {
toast.success('Схема удалена');
navigate('/rsforms?filter=owned');
});
} }
}, [destroy, navigate]); }, [destroy, navigate]);
const handleClaimOwner = useCallback(() => { const handleClaimOwner = useCallback(() => {
if (window.confirm('Вы уверены, что хотите стать владельцем данной схемы?')) { if (window.confirm('Вы уверены, что хотите стать владельцем данной схемы?')) {
claim(() => reload()); claim(() => {
toast.success('Вы стали владельцем схемы');
reload();
});
} }
}, [claim, reload]); }, [claim, reload]);
const handleUpload = useCallback(() => {
}, []);
const handleDownload = useCallback(() => { const handleDownload = useCallback(() => {
// TODO: implement file download
toast.info('Загрузка в разработке');
}, []); }, []);
return ( return (

View File

@ -40,11 +40,11 @@ function RegisterPage() {
}; };
return ( return (
<> <div className='container py-2'>
{ success && { success &&
<div className='flex flex-col items-center'> <div className='flex flex-col items-center'>
<InfoMessage message={`Вы успешно зарегистрировали пользователя ${username}`}/> <InfoMessage message={`Вы успешно зарегистрировали пользователя ${username}`}/>
<TextURL text='Войти в аккаунт' href={`login?username=${username}`}/> <TextURL text='Войти в аккаунт' href={`/login?username=${username}`}/>
</div>} </div>}
{ !success && user && { !success && user &&
<InfoMessage message={`Вы вошли в систему как ${user.username}. Если хотите зарегистрировать нового пользователя, выйдите из системы (меню в правом верхнем углу экрана)`} /> } <InfoMessage message={`Вы вошли в систему как ${user.username}. Если хотите зарегистрировать нового пользователя, выйдите из системы (меню в правом верхнем углу экрана)`} /> }
@ -90,7 +90,7 @@ function RegisterPage() {
{ error && <BackendError error={error} />} { error && <BackendError error={error} />}
</Form> </Form>
} }
</> </div>
); );
} }