diff --git a/rsconcept/frontend/src/App.tsx b/rsconcept/frontend/src/App.tsx index caeeeb48..c8456f01 100644 --- a/rsconcept/frontend/src/App.tsx +++ b/rsconcept/frontend/src/App.tsx @@ -12,12 +12,19 @@ import RegisterPage from './pages/RegisterPage'; import ManualsPage from './pages/ManualsPage'; import Footer from './components/Footer'; import RSFormCreatePage from './pages/RSFormCreatePage'; +import ToasterThemed from './components/ToasterThemed'; -function App() { +function App() { return (
+ } /> diff --git a/rsconcept/frontend/src/backendAPI.ts b/rsconcept/frontend/src/backendAPI.ts new file mode 100644 index 00000000..79d6ad4e --- /dev/null +++ b/rsconcept/frontend/src/backendAPI.ts @@ -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({ + title: 'Current user', + endpoint: `${config.url.AUTH}auth`, + request: request + }); +} + +export async function getProfile(request?: IFrontRequest) { + AxiosGet({ + 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({ + title: 'Active users list', + endpoint: `${config.url.AUTH}active-users`, + request: request + }); +} + +export async function getRSForms(request?: IFrontRequest) { + AxiosGet({ + 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({ + 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({endpoint, request, title}: IAxiosRequest) { + if (title) console.log(`[[${title}]] requested`); + if (request?.setLoading) request?.setLoading(true); + axios.get(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); + }); +} \ No newline at end of file diff --git a/rsconcept/frontend/src/components/ToasterThemed.tsx b/rsconcept/frontend/src/components/ToasterThemed.tsx new file mode 100644 index 00000000..bb5882f3 --- /dev/null +++ b/rsconcept/frontend/src/components/ToasterThemed.tsx @@ -0,0 +1,14 @@ +import { ToastContainer, ToastContainerProps } from 'react-toastify'; +import { useTheme } from '../context/ThemeContext'; + +function ToasterThemed({theme, ...props}: ToastContainerProps) { + const { darkMode } = useTheme(); + + return ( + + ); +} +export default ToasterThemed; \ No newline at end of file diff --git a/rsconcept/frontend/src/context/AuthContext.tsx b/rsconcept/frontend/src/context/AuthContext.tsx index a39426b1..dec48952 100644 --- a/rsconcept/frontend/src/context/AuthContext.tsx +++ b/rsconcept/frontend/src/context/AuthContext.tsx @@ -1,17 +1,15 @@ -import axios from 'axios'; import { createContext, useCallback, useContext, useEffect, useState } from 'react'; - -import { config } from '../constants'; import { ICurrentUser, IUserSignupData } from '../models'; import { ErrorInfo } from '../components/BackendError'; import useLocalStorage from '../hooks/useLocalStorage'; +import { getAuth, postLogin, postLogout, postSignup } from '../backendAPI'; interface IAuthContext { user: ICurrentUser | undefined - login: (username: string, password: string, onSuccess?: Function) => void - logout: (onSuccess?: Function) => void - signup: (data: IUserSignupData, onSuccess?: Function) => void + login: (username: string, password: string, onSuccess?: () => void) => void + logout: (onSuccess?: () => void) => void + signup: (data: IUserSignupData, onSuccess?: () => void) => void loading: boolean error: ErrorInfo setError: (error: ErrorInfo) => void @@ -38,74 +36,55 @@ export const AuthState = ({ children }: AuthStateProps) => { const loadCurrentUser = useCallback( async () => { - setError(undefined); - setLoading(true); - console.log('Current user requested'); - axios.get(`${config.url.AUTH}auth`) - .then(function (response) { - setLoading(false); - if (response.data.id) { - setUser(response.data); - } else { - setUser(undefined) + getAuth({ + onError: error => setUser(undefined), + onSucccess: response => { + if (response.data.id) { + setUser(response.data); + } else { + setUser(undefined) + } } - }) - .catch(function (error) { - setLoading(false); - setUser(undefined); - setError(error); }); }, [setUser] ); - async function login(uname: string, pw: string, onSuccess?: Function) { - setLoading(true); + async function login(uname: string, pw: string, onSuccess?: () => void) { setError(undefined); - axios.post(`${config.url.AUTH}login`, {username: uname, password: pw}) - .then(function (response) { - setLoading(false); - loadCurrentUser(); - if(onSuccess) { - onSuccess(); + postLogin({ + data: {username: uname, password: pw}, + showError: true, + setLoading: setLoading, + onError: error => setError(error), + onSucccess: response => { + loadCurrentUser(); + if(onSuccess) onSuccess(); } - }) - .catch(function (error) { - setLoading(false); - setError(error); }); } - async function logout(onSuccess?: Function) { - setLoading(true); + async function logout(onSuccess?: () => void) { setError(undefined); - axios.post(`${config.url.AUTH}logout`) - .then(function (response) { - setLoading(false); - loadCurrentUser(); - if(onSuccess) { - onSuccess(); + postLogout({ + showError: true, + onSucccess: response => { + loadCurrentUser(); + if(onSuccess) onSuccess(); } - }) - .catch(function (error) { - setLoading(false); - setError(error); }); } - async function signup(data: IUserSignupData, onSuccess?: Function) { - setLoading(true); + async function signup(data: IUserSignupData, onSuccess?: () => void) { setError(undefined); - axios.post(`${config.url.AUTH}signup`, data) - .then(function (response) { - setLoading(false); - loadCurrentUser(); - if(onSuccess) { - onSuccess(); + postSignup({ + data: data, + showError: true, + setLoading: setLoading, + onError: error => setError(error), + onSucccess: response => { + loadCurrentUser(); + if(onSuccess) onSuccess(); } - }) - .catch(function (error) { - setLoading(false); - setError(error); }); } diff --git a/rsconcept/frontend/src/context/RSFormContext.tsx b/rsconcept/frontend/src/context/RSFormContext.tsx index 379ac3ed..e2fcce45 100644 --- a/rsconcept/frontend/src/context/RSFormContext.tsx +++ b/rsconcept/frontend/src/context/RSFormContext.tsx @@ -3,8 +3,7 @@ import { IConstituenta, IRSForm } from '../models'; import { useRSFormDetails } from '../hooks/useRSFormDetails'; import { ErrorInfo } from '../components/BackendError'; import { useAuth } from './AuthContext'; -import axios from 'axios'; -import { config } from '../constants'; +import { BackendCallback, deleteRSForm, patchRSForm, postClaimRSForm } from '../backendAPI'; interface IRSFormContext { schema?: IRSForm @@ -17,9 +16,9 @@ interface IRSFormContext { setActive: (cst: IConstituenta) => void reload: () => void - upload: (data: any, callback: Function) => void - destroy: (callback: Function) => void - claim: (callback: Function) => void + upload: (data: any, callback?: BackendCallback) => void + destroy: (callback: BackendCallback) => void + claim: (callback: BackendCallback) => void } export const RSFormContext = createContext({ @@ -58,49 +57,34 @@ export const RSFormState = ({ id, children }: RSFormStateProps) => { } }, [schema]) - async function upload(data: any, callback?: Function) { - console.log(`Update rsform with ${data}`); - data['id'] = {id} + async function upload(data: any, callback?: BackendCallback) { setError(undefined); - setProcessing(true); - axios.patch(`${config.url.BASE}rsforms/${id}/`, data) - .then(function (response) { - setProcessing(false); - if (callback) callback(response.data); - }) - .catch(function (error) { - setProcessing(false); - setError(error); + patchRSForm(id, { + data: data, + showError: true, + setLoading: setProcessing, + onError: error => setError(error), + onSucccess: callback }); } - async function destroy(callback?: Function) { - console.log(`Deleting rsform ${id}`); + async function destroy(callback: BackendCallback) { setError(undefined); - setProcessing(true); - axios.delete(`${config.url.BASE}rsforms/${id}/`) - .then(function (response) { - setProcessing(false); - if (callback) callback(); - }) - .catch(function (error) { - setProcessing(false); - setError(error); + deleteRSForm(id, { + showError: true, + setLoading: setProcessing, + onError: error => setError(error), + onSucccess: callback }); } - async function claim(callback?: Function) { - console.log(`Claiming rsform ${id}`); + async function claim(callback: BackendCallback) { setError(undefined); - setProcessing(true); - axios.post(`${config.url.BASE}rsforms/${id}/claim/`) - .then(function (response) { - setProcessing(false); - if (callback) callback(); - }) - .catch(function (error) { - setProcessing(false); - setError(error); + postClaimRSForm(id, { + showError: true, + setLoading: setProcessing, + onError: error => setError(error), + onSucccess: callback }); } diff --git a/rsconcept/frontend/src/context/UsersContext.tsx b/rsconcept/frontend/src/context/UsersContext.tsx index 99a9e6b5..b319a605 100644 --- a/rsconcept/frontend/src/context/UsersContext.tsx +++ b/rsconcept/frontend/src/context/UsersContext.tsx @@ -1,22 +1,16 @@ -import axios from 'axios' import { createContext, useCallback, useContext, useEffect, useState } from 'react' import { IUserInfo } from '../models' -import { config } from '../constants' -import { ErrorInfo } from '../components/BackendError' +import { getActiveUsers } from '../backendAPI' interface IUsersContext { users: IUserInfo[] - error: ErrorInfo - loading: boolean reload: () => void getUserLabel: (userID?: number) => string } export const UsersContext = createContext({ users: [], - error: undefined, - loading: false, reload: () => {}, getUserLabel: () => '' }) @@ -27,8 +21,6 @@ interface UsersStateProps { export const UsersState = ({ children }: UsersStateProps) => { const [users, setUsers] = useState([]); - const [loading, setLoading] = useState(false); - const [error, setError] = useState(undefined); const getUserLabel = (userID?: number) => { const user = users.find(({id}) => id === userID); @@ -49,18 +41,12 @@ export const UsersState = ({ children }: UsersStateProps) => { const reload = useCallback( async () => { - setError(undefined); - setLoading(true); - console.log('Profile requested'); - axios.get(`${config.url.AUTH}active-users`) - .then(function (response) { - setLoading(false); - setUsers(response.data); - }) - .catch(function (error) { - setLoading(false); - setUsers([]); - setError(error); + getActiveUsers({ + showError: true, + onError: error => setUsers([]), + onSucccess: response => { + setUsers(response ? response.data : []); + } }); }, [setUsers] ); @@ -72,7 +58,6 @@ export const UsersState = ({ children }: UsersStateProps) => { return ( { children } diff --git a/rsconcept/frontend/src/hooks/useAPI.ts b/rsconcept/frontend/src/hooks/useAPI.ts deleted file mode 100644 index 5b6e7b8a..00000000 --- a/rsconcept/frontend/src/hooks/useAPI.ts +++ /dev/null @@ -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(`${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; \ No newline at end of file diff --git a/rsconcept/frontend/src/hooks/useNewRSForm.ts b/rsconcept/frontend/src/hooks/useNewRSForm.ts index 55583b44..2598e29f 100644 --- a/rsconcept/frontend/src/hooks/useNewRSForm.ts +++ b/rsconcept/frontend/src/hooks/useNewRSForm.ts @@ -1,33 +1,30 @@ -import axios from 'axios' import { useState } from 'react' -import { config } from '../constants' import { ErrorInfo } from '../components/BackendError'; +import { postNewRSForm } from '../backendAPI'; -function useNewRSForm({callback}: {callback: (newID: string) => void}) { +function useNewRSForm() { const [loading, setLoading] = useState(false); const [error, setError] = useState(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); - setLoading(true); if (file) { - data['file']=file; - data['fileName']=file.name; + data['file'] = file; + data['fileName'] = file.name; } - axios.post(`${config.url.BASE}rsforms/create-detailed/`, data) - .then(function (response) { - setLoading(false); - if(callback) { - callback(response.data.id); - } - }) - .catch(function (error) { - setLoading(false); - setError(error); + postNewRSForm({ + data: data, + showError: true, + setLoading: setLoading, + onError: error => setError(error), + onSucccess: response => onSuccess(response.data.id) }); } - return { createNew, error, setError, loading }; + return { createSchema, error, setError, loading }; } export default useNewRSForm; \ No newline at end of file diff --git a/rsconcept/frontend/src/hooks/useRSFormDetails.ts b/rsconcept/frontend/src/hooks/useRSFormDetails.ts index d48892f3..7a7502f9 100644 --- a/rsconcept/frontend/src/hooks/useRSFormDetails.ts +++ b/rsconcept/frontend/src/hooks/useRSFormDetails.ts @@ -1,8 +1,7 @@ -import axios from 'axios' -import { config } from '../constants'; import { useCallback, useEffect, useState } from 'react' import { IRSForm } from '../models' import { ErrorInfo } from '../components/BackendError'; +import { getRSFormDetails } from '../backendAPI'; export function useRSFormDetails({target}: {target?: string}) { const [schema, setSchema] = useState(); @@ -10,21 +9,16 @@ export function useRSFormDetails({target}: {target?: string}) { const [error, setError] = useState(undefined); const fetchData = useCallback(async () => { - console.log(`Requesting rsform ${target}`); setError(undefined); setSchema(undefined); if (!target) { return; } - setLoading(true); - axios.get(`${config.url.BASE}rsforms/${target}/details/`) - .then(function (response) { - setLoading(false); - setSchema(response.data); - }) - .catch(function (error) { - setLoading(false); - setError(error); + getRSFormDetails(target, { + showError: true, + setLoading: setLoading, + onError: error => setError(error), + onSucccess: response => setSchema(response.data) }); }, [target]); diff --git a/rsconcept/frontend/src/hooks/useRSForms.ts b/rsconcept/frontend/src/hooks/useRSForms.ts index 84935093..cc3d190a 100644 --- a/rsconcept/frontend/src/hooks/useRSForms.ts +++ b/rsconcept/frontend/src/hooks/useRSForms.ts @@ -1,32 +1,25 @@ -import axios from 'axios' -import { useEffect, useState } from 'react' +import { useCallback, useEffect, useState } from 'react' import { IRSForm } from '../models' -import { config } from '../constants' import { ErrorInfo } from '../components/BackendError'; +import { getRSForms } from '../backendAPI'; export function useRSForms() { const [rsforms, setRSForms] = useState([]); const [loading, setLoading] = useState(false); const [error, setError] = useState(undefined); - - async function fetchRSForms() { - setError(undefined); - setLoading(true); - console.log('RSForms requested'); - axios.get(`${config.url.BASE}rsforms/`) - .then(function (response) { - setLoading(false); - setRSForms(response.data); - }) - .catch(function (error) { - setLoading(false); - setError(error); + + const fetchData = useCallback(async () => { + getRSForms({ + showError: true, + setLoading: setLoading, + onError: error => setError(error), + onSucccess: response => setRSForms(response.data) }); - } + }, []); useEffect(() => { - fetchRSForms(); - }, []) + fetchData(); + }, [fetchData]) return { rsforms, error, loading }; } \ No newline at end of file diff --git a/rsconcept/frontend/src/hooks/useUserProfile.ts b/rsconcept/frontend/src/hooks/useUserProfile.ts index 7f4c406c..7128bfd2 100644 --- a/rsconcept/frontend/src/hooks/useUserProfile.ts +++ b/rsconcept/frontend/src/hooks/useUserProfile.ts @@ -1,8 +1,7 @@ -import axios from 'axios' import { useCallback, useEffect, useState } from 'react' import { IUserProfile } from '../models' -import { config } from '../constants' import { ErrorInfo } from '../components/BackendError' +import { getProfile } from '../backendAPI' export function useUserProfile() { @@ -13,17 +12,12 @@ export function useUserProfile() { const fetchUser = useCallback( async () => { setError(undefined); - setLoading(true); - console.log('Profile requested'); - axios.get(`${config.url.AUTH}profile`) - .then(function (response) { - setLoading(false); - setUser(response.data); - }) - .catch(function (error) { - setLoading(false); - setUser(undefined); - setError(error); + setUser(undefined); + getProfile({ + showError: true, + setLoading: setLoading, + onError: error => setError(error), + onSucccess: response => setUser(response.data) }); }, [setUser] ) diff --git a/rsconcept/frontend/src/index.tsx b/rsconcept/frontend/src/index.tsx index 691a7353..fc178f60 100644 --- a/rsconcept/frontend/src/index.tsx +++ b/rsconcept/frontend/src/index.tsx @@ -2,9 +2,10 @@ import React from 'react'; import axios from 'axios'; +import './index.css'; +import 'react-toastify/dist/ReactToastify.css'; import ReactDOM from 'react-dom/client'; import { BrowserRouter } from 'react-router-dom'; -import './index.css'; import App from './App'; import { AuthState } from './context/AuthContext'; import { ThemeState } from './context/ThemeContext'; diff --git a/rsconcept/frontend/src/pages/LoginPage.tsx b/rsconcept/frontend/src/pages/LoginPage.tsx index 90a1fb8c..ea56c2da 100644 --- a/rsconcept/frontend/src/pages/LoginPage.tsx +++ b/rsconcept/frontend/src/pages/LoginPage.tsx @@ -20,6 +20,7 @@ function LoginPage() { useEffect(() => { const name = new URLSearchParams(search).get('username'); setUsername(name || ''); + setPassword(''); }, [search]); useEffect(() => { @@ -37,7 +38,7 @@ function LoginPage() {
{ user ? : -
+ setPassword(event.target.value)} /> -
+
diff --git a/rsconcept/frontend/src/pages/RSFormCreatePage.tsx b/rsconcept/frontend/src/pages/RSFormCreatePage.tsx index 58785616..d76d7aef 100644 --- a/rsconcept/frontend/src/pages/RSFormCreatePage.tsx +++ b/rsconcept/frontend/src/pages/RSFormCreatePage.tsx @@ -11,6 +11,7 @@ import { useNavigate } from 'react-router-dom'; import TextArea from '../components/Common/TextArea'; import Checkbox from '../components/Common/Checkbox'; import FileInput from '../components/Common/FileInput'; +import { toast } from 'react-toastify'; function RSFormCreatePage() { const navigate = useNavigate(); @@ -29,8 +30,11 @@ function RSFormCreatePage() { } } - const onSuccess = (newID: string) => navigate(`/rsforms/${newID}`); - const { createNew, error, setError, loading } = useNewRSForm({callback: onSuccess}) + const onSuccess = (newID: string) => { + toast.success('Схема успешно создана'); + navigate(`/rsforms/${newID}`); + } + const { createSchema, error, setError, loading } = useNewRSForm() useEffect(() => { setError(undefined) @@ -45,7 +49,11 @@ function RSFormCreatePage() { 'comment': comment, 'is_common': common, }; - createNew({data: data, file: file}); + createSchema({ + data: data, + file: file, + onSuccess: onSuccess + }); } }; diff --git a/rsconcept/frontend/src/pages/RSFormPage/RSFormCard.tsx b/rsconcept/frontend/src/pages/RSFormPage/RSFormCard.tsx index 1e83808d..8c1ad3db 100644 --- a/rsconcept/frontend/src/pages/RSFormPage/RSFormCard.tsx +++ b/rsconcept/frontend/src/pages/RSFormPage/RSFormCard.tsx @@ -6,10 +6,10 @@ import TextInput from '../../components/Common/TextInput'; import { useRSForm } from '../../context/RSFormContext'; import { useCallback, useEffect, useState } from 'react'; 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 { useNavigate } from 'react-router-dom'; -import FileInput from '../../components/Common/FileInput'; +import { toast } from 'react-toastify'; function RSFormCard() { const navigate = useNavigate(); @@ -21,8 +21,6 @@ function RSFormCard() { const [alias, setAlias] = useState(''); const [comment, setComment] = useState(''); const [common, setCommon] = useState(false); - - const onSuccess = (data: any) => reload(); useEffect(() => { setTitle(schema!.title) @@ -40,28 +38,34 @@ function RSFormCard() { 'comment': comment, 'is_common': common, }; - upload(data, onSuccess); + upload(data, () => { + toast.success('Изменения сохранены'); + reload(); + }); } }; const handleDelete = useCallback(() => { if (window.confirm('Вы уверены, что хотите удалить данную схему?')) { - destroy(() => navigate('/rsforms?filter=owned')) + destroy(() => { + toast.success('Схема удалена'); + navigate('/rsforms?filter=owned'); + }); } }, [destroy, navigate]); const handleClaimOwner = useCallback(() => { if (window.confirm('Вы уверены, что хотите стать владельцем данной схемы?')) { - claim(() => reload()); + claim(() => { + toast.success('Вы стали владельцем схемы'); + reload(); + }); } }, [claim, reload]); - const handleUpload = useCallback(() => { - - }, []); - const handleDownload = useCallback(() => { - + // TODO: implement file download + toast.info('Загрузка в разработке'); }, []); return ( diff --git a/rsconcept/frontend/src/pages/RegisterPage.tsx b/rsconcept/frontend/src/pages/RegisterPage.tsx index d9133a18..1fcf8441 100644 --- a/rsconcept/frontend/src/pages/RegisterPage.tsx +++ b/rsconcept/frontend/src/pages/RegisterPage.tsx @@ -40,11 +40,11 @@ function RegisterPage() { }; return ( - <> +
{ success &&
- +
} { !success && user && } @@ -90,7 +90,7 @@ function RegisterPage() { { error && } } - +
); }