mirror of
https://github.com/IRBorisov/ConceptPortal.git
synced 2025-06-26 13:00:39 +03:00
Refactor backend API calls and add toasts
This commit is contained in:
parent
eb045905d8
commit
484b1a9ea1
|
@ -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/>} />
|
||||||
|
|
||||||
|
|
179
rsconcept/frontend/src/backendAPI.ts
Normal file
179
rsconcept/frontend/src/backendAPI.ts
Normal 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);
|
||||||
|
});
|
||||||
|
}
|
14
rsconcept/frontend/src/components/ToasterThemed.tsx
Normal file
14
rsconcept/frontend/src/components/ToasterThemed.tsx
Normal 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;
|
|
@ -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`)
|
if (response.data.id) {
|
||||||
.then(function (response) {
|
setUser(response.data);
|
||||||
setLoading(false);
|
} else {
|
||||||
if (response.data.id) {
|
setUser(undefined)
|
||||||
setUser(response.data);
|
}
|
||||||
} else {
|
|
||||||
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,
|
||||||
loadCurrentUser();
|
setLoading: setLoading,
|
||||||
if(onSuccess) {
|
onError: error => setError(error),
|
||||||
onSuccess();
|
onSucccess: response => {
|
||||||
|
loadCurrentUser();
|
||||||
|
if(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,
|
||||||
loadCurrentUser();
|
setLoading: setLoading,
|
||||||
if(onSuccess) {
|
onError: error => setError(error),
|
||||||
onSuccess();
|
onSucccess: response => {
|
||||||
|
loadCurrentUser();
|
||||||
|
if(onSuccess) onSuccess();
|
||||||
}
|
}
|
||||||
})
|
|
||||||
.catch(function (error) {
|
|
||||||
setLoading(false);
|
|
||||||
setError(error);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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 }
|
||||||
|
|
|
@ -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;
|
|
|
@ -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;
|
|
@ -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]);
|
||||||
|
|
||||||
|
|
|
@ -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 };
|
||||||
}
|
}
|
|
@ -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);
|
setUser(undefined);
|
||||||
console.log('Profile requested');
|
getProfile({
|
||||||
axios.get<IUserProfile>(`${config.url.AUTH}profile`)
|
showError: true,
|
||||||
.then(function (response) {
|
setLoading: setLoading,
|
||||||
setLoading(false);
|
onError: error => setError(error),
|
||||||
setUser(response.data);
|
onSucccess: response => setUser(response.data)
|
||||||
})
|
|
||||||
.catch(function (error) {
|
|
||||||
setLoading(false);
|
|
||||||
setUser(undefined);
|
|
||||||
setError(error);
|
|
||||||
});
|
});
|
||||||
}, [setUser]
|
}, [setUser]
|
||||||
)
|
)
|
||||||
|
|
|
@ -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';
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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 (
|
||||||
|
|
|
@ -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>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user