forked from VinokurovVE/tests
Cleanup
This commit is contained in:
9
frontend_reactjs/package-lock.json
generated
9
frontend_reactjs/package-lock.json
generated
@ -29,7 +29,6 @@
|
|||||||
"react-hook-form": "^7.52.0",
|
"react-hook-form": "^7.52.0",
|
||||||
"react-router-dom": "^6.23.1",
|
"react-router-dom": "^6.23.1",
|
||||||
"swr": "^2.2.5",
|
"swr": "^2.2.5",
|
||||||
"zod": "^3.23.8",
|
|
||||||
"zustand": "^4.5.2"
|
"zustand": "^4.5.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@ -9927,14 +9926,6 @@
|
|||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/zod": {
|
|
||||||
"version": "3.23.8",
|
|
||||||
"resolved": "https://registry.npmjs.org/zod/-/zod-3.23.8.tgz",
|
|
||||||
"integrity": "sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==",
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/colinhacks"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/zustand": {
|
"node_modules/zustand": {
|
||||||
"version": "4.5.2",
|
"version": "4.5.2",
|
||||||
"resolved": "https://registry.npmjs.org/zustand/-/zustand-4.5.2.tgz",
|
"resolved": "https://registry.npmjs.org/zustand/-/zustand-4.5.2.tgz",
|
||||||
|
@ -31,7 +31,6 @@
|
|||||||
"react-hook-form": "^7.52.0",
|
"react-hook-form": "^7.52.0",
|
||||||
"react-router-dom": "^6.23.1",
|
"react-router-dom": "^6.23.1",
|
||||||
"swr": "^2.2.5",
|
"swr": "^2.2.5",
|
||||||
"zod": "^3.23.8",
|
|
||||||
"zustand": "^4.5.2"
|
"zustand": "^4.5.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { BrowserRouter as Router, Route, Routes, Navigate, redirect } from "react-router-dom"
|
import { BrowserRouter as Router, Route, Routes, Navigate } from "react-router-dom"
|
||||||
import Main from "./pages/Main"
|
import Main from "./pages/Main"
|
||||||
import Users from "./pages/Users"
|
import Users from "./pages/Users"
|
||||||
import Roles from "./pages/Roles"
|
import Roles from "./pages/Roles"
|
||||||
@ -10,7 +10,7 @@ import ApiTest from "./pages/ApiTest"
|
|||||||
import SignUp from "./pages/auth/SignUp"
|
import SignUp from "./pages/auth/SignUp"
|
||||||
import { initAuth, useAuthStore } from "./store/auth"
|
import { initAuth, useAuthStore } from "./store/auth"
|
||||||
import { useEffect, useState } from "react"
|
import { useEffect, useState } from "react"
|
||||||
import { Box, CircularProgress, Container } from "@mui/material"
|
import { Box, CircularProgress } from "@mui/material"
|
||||||
import Documents from "./pages/Documents"
|
import Documents from "./pages/Documents"
|
||||||
import Reports from "./pages/Reports"
|
import Reports from "./pages/Reports"
|
||||||
|
|
||||||
|
@ -4,14 +4,13 @@ import Avatar from '@mui/material/Avatar';
|
|||||||
import Menu from '@mui/material/Menu';
|
import Menu from '@mui/material/Menu';
|
||||||
import MenuItem from '@mui/material/MenuItem';
|
import MenuItem from '@mui/material/MenuItem';
|
||||||
import ListItemIcon from '@mui/material/ListItemIcon';
|
import ListItemIcon from '@mui/material/ListItemIcon';
|
||||||
import Divider from '@mui/material/Divider';
|
|
||||||
import IconButton from '@mui/material/IconButton';
|
import IconButton from '@mui/material/IconButton';
|
||||||
import Tooltip from '@mui/material/Tooltip';
|
import Tooltip from '@mui/material/Tooltip';
|
||||||
import Settings from '@mui/icons-material/Settings';
|
import Settings from '@mui/icons-material/Settings';
|
||||||
import Logout from '@mui/icons-material/Logout';
|
import Logout from '@mui/icons-material/Logout';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
import { logout, useAuthStore } from '../store/auth';
|
import { logout } from '../store/auth';
|
||||||
import { ListItem, Switch, styled } from '@mui/material';
|
import { ListItemText, Switch, styled } from '@mui/material';
|
||||||
import { setDarkMode, usePrefStore } from '../store/preferences';
|
import { setDarkMode, usePrefStore } from '../store/preferences';
|
||||||
|
|
||||||
const Android12Switch = styled(Switch)(({ theme }) => ({
|
const Android12Switch = styled(Switch)(({ theme }) => ({
|
||||||
@ -79,36 +78,39 @@ export default function AccountMenu() {
|
|||||||
</IconButton>
|
</IconButton>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Menu
|
<Menu
|
||||||
anchorEl={anchorEl}
|
anchorEl={anchorEl}
|
||||||
id="account-menu"
|
id="account-menu"
|
||||||
open={open}
|
open={open}
|
||||||
onClose={handleClose}
|
onClose={handleClose}
|
||||||
PaperProps={{
|
slotProps={{
|
||||||
elevation: 0,
|
paper: {
|
||||||
sx: {
|
elevation: 0,
|
||||||
overflow: 'visible',
|
sx: {
|
||||||
filter: 'drop-shadow(0px 2px 8px rgba(0,0,0,0.32))',
|
overflow: 'visible',
|
||||||
mt: 1.5,
|
filter: 'drop-shadow(0px 2px 8px rgba(0,0,0,0.32))',
|
||||||
'& .MuiAvatar-root': {
|
mt: 1.5,
|
||||||
width: 32,
|
'& .MuiAvatar-root': {
|
||||||
height: 32,
|
width: 32,
|
||||||
ml: -0.5,
|
height: 32,
|
||||||
mr: 1,
|
ml: -0.5,
|
||||||
|
mr: 1,
|
||||||
|
},
|
||||||
|
'&::before': {
|
||||||
|
content: '""',
|
||||||
|
display: 'block',
|
||||||
|
position: 'absolute',
|
||||||
|
top: 0,
|
||||||
|
right: 14,
|
||||||
|
width: 10,
|
||||||
|
height: 10,
|
||||||
|
bgcolor: 'background.paper',
|
||||||
|
transform: 'translateY(-50%) rotate(45deg)',
|
||||||
|
zIndex: 0,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
'&::before': {
|
}
|
||||||
content: '""',
|
|
||||||
display: 'block',
|
|
||||||
position: 'absolute',
|
|
||||||
top: 0,
|
|
||||||
right: 14,
|
|
||||||
width: 10,
|
|
||||||
height: 10,
|
|
||||||
bgcolor: 'background.paper',
|
|
||||||
transform: 'translateY(-50%) rotate(45deg)',
|
|
||||||
zIndex: 0,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}}
|
}}
|
||||||
transformOrigin={{ horizontal: 'right', vertical: 'top' }}
|
transformOrigin={{ horizontal: 'right', vertical: 'top' }}
|
||||||
anchorOrigin={{ horizontal: 'right', vertical: 'bottom' }}
|
anchorOrigin={{ horizontal: 'right', vertical: 'bottom' }}
|
||||||
@ -116,12 +118,16 @@ export default function AccountMenu() {
|
|||||||
<MenuItem onClick={() => {
|
<MenuItem onClick={() => {
|
||||||
console.log()
|
console.log()
|
||||||
}}>
|
}}>
|
||||||
<Android12Switch
|
<ListItemIcon>
|
||||||
defaultChecked={prefStore.darkMode}
|
<Android12Switch
|
||||||
onChange={(e) => {
|
defaultChecked={prefStore.darkMode}
|
||||||
setDarkMode(e.target.checked)
|
onChange={(e) => {
|
||||||
}} />
|
setDarkMode(e.target.checked)
|
||||||
Тема
|
}} />
|
||||||
|
</ListItemIcon>
|
||||||
|
<ListItemText>
|
||||||
|
Тема: {prefStore.darkMode ? "темная" : "светлая"}
|
||||||
|
</ListItemText>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,21 +1,21 @@
|
|||||||
import { useState, useEffect, useMemo } from 'react';
|
import { useState, useEffect, useMemo } from 'react'
|
||||||
import axiosInstance from '../http/axiosInstance';
|
import axiosInstance from '../http/axiosInstance'
|
||||||
export function useDataFetching<T>(url: string, initData: T): T {
|
export function useDataFetching<T>(url: string, initData: T): T {
|
||||||
const [data, setData] = useState<T>(initData);
|
const [data, setData] = useState<T>(initData)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const fetchData = async () => {
|
const fetchData = async () => {
|
||||||
const response = await axiosInstance.get(url);
|
const response = await axiosInstance.get(url)
|
||||||
const result = await response.data;
|
const result = await response.data
|
||||||
setData(result);
|
setData(result)
|
||||||
};
|
}
|
||||||
|
|
||||||
fetchData();
|
fetchData()
|
||||||
}, [url]);
|
}, [url])
|
||||||
console.log(data)
|
console.log(data)
|
||||||
// Memoize the data value
|
// Memoize the data value
|
||||||
const memoizedData = useMemo<T>(() => data, [data]);
|
const memoizedData = useMemo<T>(() => data, [data])
|
||||||
return memoizedData;
|
return memoizedData
|
||||||
};
|
}
|
||||||
|
|
||||||
export default useDataFetching;
|
export default useDataFetching;
|
@ -1,6 +1,6 @@
|
|||||||
import { useDocuments, useDownload, useFolders } from '../hooks/swrHooks'
|
import { useDocuments, useDownload, useFolders } from '../hooks/swrHooks'
|
||||||
import { IDocument, IDocumentFolder } from '../interfaces/documents'
|
import { IDocument, IDocumentFolder } from '../interfaces/documents'
|
||||||
import { Box, Breadcrumbs, Button, Card, CardActionArea, CircularProgress, Divider, IconButton, Input, InputLabel, LinearProgress, Link, List, ListItem, ListItemButton, SxProps } from '@mui/material'
|
import { Box, Breadcrumbs, Button, CircularProgress, Divider, IconButton, Link, List, ListItemButton, SxProps } from '@mui/material'
|
||||||
import { Cancel, Close, Download, Folder, InsertDriveFile, Upload, UploadFile } from '@mui/icons-material'
|
import { Cancel, Close, Download, Folder, InsertDriveFile, Upload, UploadFile } from '@mui/icons-material'
|
||||||
import React, { useEffect, useRef, useState } from 'react'
|
import React, { useEffect, useRef, useState } from 'react'
|
||||||
import DocumentService from '../services/DocumentService'
|
import DocumentService from '../services/DocumentService'
|
||||||
@ -29,7 +29,7 @@ const FileItemStyle: SxProps = {
|
|||||||
padding: '8px'
|
padding: '8px'
|
||||||
}
|
}
|
||||||
|
|
||||||
function ItemFolder({ folder, index, handleFolderClick, ...props }: FolderProps) {
|
function ItemFolder({ folder, handleFolderClick, ...props }: FolderProps) {
|
||||||
return (
|
return (
|
||||||
<ListItemButton
|
<ListItemButton
|
||||||
onClick={() => handleFolderClick(folder)}
|
onClick={() => handleFolderClick(folder)}
|
||||||
@ -118,6 +118,7 @@ export default function FolderViewer() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const handleDocumentClick = async (doc: IDocument, index: number) => {
|
const handleDocumentClick = async (doc: IDocument, index: number) => {
|
||||||
|
console.log(doc)
|
||||||
setCurrentFileNo(index)
|
setCurrentFileNo(index)
|
||||||
setFileViewerModal(true)
|
setFileViewerModal(true)
|
||||||
}
|
}
|
||||||
@ -139,7 +140,7 @@ export default function FolderViewer() {
|
|||||||
setDragOver(true)
|
setDragOver(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleDragLeave = (e: React.DragEvent) => {
|
const handleDragLeave = () => {
|
||||||
setDragOver(false)
|
setDragOver(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -159,11 +160,11 @@ export default function FolderViewer() {
|
|||||||
setIsUploading(true)
|
setIsUploading(true)
|
||||||
if (filesToUpload.length > 0 && currentFolder && currentFolder.id) {
|
if (filesToUpload.length > 0 && currentFolder && currentFolder.id) {
|
||||||
const formData = new FormData()
|
const formData = new FormData()
|
||||||
for (let file of filesToUpload) {
|
for (const file of filesToUpload) {
|
||||||
formData.append('files', file)
|
formData.append('files', file)
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const response = await DocumentService.uploadFiles(currentFolder.id, formData, setUploadProgress);
|
await DocumentService.uploadFiles(currentFolder.id, formData, setUploadProgress);
|
||||||
setIsUploading(false);
|
setIsUploading(false);
|
||||||
setFilesToUpload([]);
|
setFilesToUpload([]);
|
||||||
mutate(`/info/documents/${currentFolder.id}`);
|
mutate(`/info/documents/${currentFolder.id}`);
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { memo, useEffect, useMemo, useState } from "react";
|
import { useEffect, useMemo, useState } from "react";
|
||||||
import UserService from "../services/UserService";
|
import UserService from "../services/UserService";
|
||||||
|
|
||||||
export default function useUserData<T>(token: string, initData: T): T {
|
export default function useUserData<T>(token: string, initData: T): T {
|
||||||
|
@ -2,7 +2,7 @@ import { SubmitHandler, useForm } from 'react-hook-form';
|
|||||||
import { AxiosResponse } from 'axios';
|
import { AxiosResponse } from 'axios';
|
||||||
import { ApiResponse } from '../../interfaces/auth';
|
import { ApiResponse } from '../../interfaces/auth';
|
||||||
import RoleService from '../../services/RoleService';
|
import RoleService from '../../services/RoleService';
|
||||||
import { Box, Button, MenuItem, Modal, Select, TextField, Typography } from '@mui/material';
|
import { Box, Button, Modal, Select, TextField, Typography } from '@mui/material';
|
||||||
import { ICompany } from '../../interfaces/documents';
|
import { ICompany } from '../../interfaces/documents';
|
||||||
import { useCompanies } from '../../hooks/swrHooks';
|
import { useCompanies } from '../../hooks/swrHooks';
|
||||||
|
|
||||||
@ -12,7 +12,7 @@ interface Props {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const style = {
|
const style = {
|
||||||
position: 'absolute' as 'absolute',
|
position: 'absolute',
|
||||||
top: '50%',
|
top: '50%',
|
||||||
left: '50%',
|
left: '50%',
|
||||||
transform: 'translate(-50%, -50%)',
|
transform: 'translate(-50%, -50%)',
|
||||||
|
@ -11,7 +11,7 @@ interface Props {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const style = {
|
const style = {
|
||||||
position: 'absolute' as 'absolute',
|
position: 'absolute',
|
||||||
top: '50%',
|
top: '50%',
|
||||||
left: '50%',
|
left: '50%',
|
||||||
transform: 'translate(-50%, -50%)',
|
transform: 'translate(-50%, -50%)',
|
||||||
|
@ -11,7 +11,7 @@ interface Props {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const style = {
|
const style = {
|
||||||
position: 'absolute' as 'absolute',
|
position: 'absolute',
|
||||||
top: '50%',
|
top: '50%',
|
||||||
left: '50%',
|
left: '50%',
|
||||||
transform: 'translate(-50%, -50%)',
|
transform: 'translate(-50%, -50%)',
|
||||||
@ -53,7 +53,6 @@ export default function CreateRoleModal({
|
|||||||
aria-describedby="modal-modal-description"
|
aria-describedby="modal-modal-description"
|
||||||
>
|
>
|
||||||
<form onSubmit={handleSubmit(onSubmit)}>
|
<form onSubmit={handleSubmit(onSubmit)}>
|
||||||
|
|
||||||
<Box sx={style}>
|
<Box sx={style}>
|
||||||
<Typography variant="h6" component="h6" gutterBottom>
|
<Typography variant="h6" component="h6" gutterBottom>
|
||||||
Создание роли
|
Создание роли
|
||||||
|
@ -11,7 +11,7 @@ interface Props {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const style = {
|
const style = {
|
||||||
position: 'absolute' as 'absolute',
|
position: 'absolute',
|
||||||
top: '50%',
|
top: '50%',
|
||||||
left: '50%',
|
left: '50%',
|
||||||
transform: 'translate(-50%, -50%)',
|
transform: 'translate(-50%, -50%)',
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
import React, { useEffect, useRef, useState } from 'react'
|
import { useEffect, useRef } from 'react'
|
||||||
import { AppBar, Box, Button, CircularProgress, Dialog, IconButton, Toolbar, Typography } from '@mui/material';
|
import { AppBar, Box, Button, CircularProgress, Dialog, IconButton, Toolbar, Typography } from '@mui/material';
|
||||||
import { ChevronLeft, ChevronRight, Close, Warning } from '@mui/icons-material';
|
import { ChevronLeft, ChevronRight, Close, Warning } from '@mui/icons-material';
|
||||||
import { useDownload, useFileType } from '../../hooks/swrHooks';
|
import { useDownload, useFileType } from '../../hooks/swrHooks';
|
||||||
import { fileTypeFromBlob } from 'file-type/core';
|
|
||||||
|
|
||||||
import jsPreviewExcel from "@js-preview/excel"
|
import jsPreviewExcel from "@js-preview/excel"
|
||||||
import '@js-preview/excel/lib/index.css'
|
import '@js-preview/excel/lib/index.css'
|
||||||
@ -11,11 +10,12 @@ import jsPreviewDocx from "@js-preview/docx"
|
|||||||
import '@js-preview/docx/lib/index.css'
|
import '@js-preview/docx/lib/index.css'
|
||||||
|
|
||||||
import jsPreviewPdf from '@js-preview/pdf'
|
import jsPreviewPdf from '@js-preview/pdf'
|
||||||
|
import { IDocument } from '../../interfaces/documents';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
open: boolean;
|
open: boolean;
|
||||||
setOpen: (state: boolean) => void;
|
setOpen: (state: boolean) => void;
|
||||||
docs: any;
|
docs: IDocument[];
|
||||||
currentFileNo: number;
|
currentFileNo: number;
|
||||||
setCurrentFileNo: (state: number) => void;
|
setCurrentFileNo: (state: number) => void;
|
||||||
}
|
}
|
||||||
@ -29,13 +29,10 @@ function PdfViewer({
|
|||||||
}: ViewerProps) {
|
}: ViewerProps) {
|
||||||
const previewContainerRef = useRef(null)
|
const previewContainerRef = useRef(null)
|
||||||
|
|
||||||
const [loadingPreview, setLoadingPreview] = useState(false)
|
|
||||||
|
|
||||||
const pdfPreviewer = jsPreviewPdf
|
const pdfPreviewer = jsPreviewPdf
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (previewContainerRef && previewContainerRef.current) {
|
if (previewContainerRef && previewContainerRef.current) {
|
||||||
setLoadingPreview(true);
|
|
||||||
pdfPreviewer.init(previewContainerRef.current)
|
pdfPreviewer.init(previewContainerRef.current)
|
||||||
.preview(url)
|
.preview(url)
|
||||||
}
|
}
|
||||||
@ -60,11 +57,8 @@ function DocxViewer({
|
|||||||
}: ViewerProps) {
|
}: ViewerProps) {
|
||||||
const previewContainerRef = useRef(null)
|
const previewContainerRef = useRef(null)
|
||||||
|
|
||||||
const [loadingPreview, setLoadingPreview] = useState(false)
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (previewContainerRef && previewContainerRef.current) {
|
if (previewContainerRef && previewContainerRef.current) {
|
||||||
setLoadingPreview(true);
|
|
||||||
jsPreviewDocx.init(previewContainerRef.current, {
|
jsPreviewDocx.init(previewContainerRef.current, {
|
||||||
breakPages: true,
|
breakPages: true,
|
||||||
inWrapper: true,
|
inWrapper: true,
|
||||||
@ -93,11 +87,8 @@ function ExcelViewer({
|
|||||||
}: ViewerProps) {
|
}: ViewerProps) {
|
||||||
const previewContainerRef = useRef(null)
|
const previewContainerRef = useRef(null)
|
||||||
|
|
||||||
const [loadingPreview, setLoadingPreview] = useState(false)
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (previewContainerRef && previewContainerRef.current) {
|
if (previewContainerRef && previewContainerRef.current) {
|
||||||
setLoadingPreview(true);
|
|
||||||
jsPreviewExcel.init(previewContainerRef.current)
|
jsPreviewExcel.init(previewContainerRef.current)
|
||||||
.preview(url)
|
.preview(url)
|
||||||
}
|
}
|
||||||
@ -145,7 +136,7 @@ export default function FileViewer({
|
|||||||
currentFileNo,
|
currentFileNo,
|
||||||
setCurrentFileNo
|
setCurrentFileNo
|
||||||
}: Props) {
|
}: Props) {
|
||||||
const { file, isError, isLoading: fileIsLoading } = useDownload(currentFileNo >= 0 ? docs[currentFileNo]?.document_folder_id : null, currentFileNo >= 0 ? docs[currentFileNo]?.id : null)
|
const { file, isLoading: fileIsLoading } = useDownload(currentFileNo >= 0 ? docs[currentFileNo]?.document_folder_id : null, currentFileNo >= 0 ? docs[currentFileNo]?.id : null)
|
||||||
|
|
||||||
const { fileType, isLoading: fileTypeIsLoading } = useFileType(currentFileNo >= 0 ? docs[currentFileNo]?.name : null, currentFileNo >= 0 ? file : null)
|
const { fileType, isLoading: fileTypeIsLoading } = useFileType(currentFileNo >= 0 ? docs[currentFileNo]?.name : null, currentFileNo >= 0 ? file : null)
|
||||||
|
|
||||||
|
@ -83,10 +83,10 @@ export function useDownload(folder_id?: number | null, id?: number | null) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useFileType(fileName?: string, file?: Blob) {
|
export function useFileType(fileName?: string | null, file?: Blob | null) {
|
||||||
const { data, error, isLoading } = useSWR(
|
const { data, error, isLoading } = useSWR(
|
||||||
fileName && file ? `/filetype/${fileName}` : null,
|
fileName && file ? `/filetype/${fileName}` : null,
|
||||||
file ? (key: string) => fileTypeFromBlob(file) : null,
|
file ? () => fileTypeFromBlob(file) : null,
|
||||||
{
|
{
|
||||||
revalidateOnFocus: false
|
revalidateOnFocus: false
|
||||||
}
|
}
|
||||||
@ -134,7 +134,7 @@ export function useAddress(limit?: number, page?: number) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useRegions(limit?: number, page?: number, search?: string) {
|
export function useRegions(limit?: number, page?: number, search?: string | null) {
|
||||||
const { data, error, isLoading } = useSWR(
|
const { data, error, isLoading } = useSWR(
|
||||||
`/general/regions?limit=${limit || 10}&page=${page || 1}${search ? `&search=${search}` : ''}`,
|
`/general/regions?limit=${limit || 10}&page=${page || 1}${search ? `&search=${search}` : ''}`,
|
||||||
(url) => fetcher(url, BASE_URL.fuel),
|
(url) => fetcher(url, BASE_URL.fuel),
|
||||||
|
@ -19,7 +19,7 @@ export interface UserCreds extends User {
|
|||||||
export interface AuthState {
|
export interface AuthState {
|
||||||
isAuthenticated: boolean;
|
isAuthenticated: boolean;
|
||||||
token: string | null;
|
token: string | null;
|
||||||
userData: UserData | {};
|
userData: UserData | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface LoginFormData {
|
export interface LoginFormData {
|
||||||
@ -32,8 +32,8 @@ export interface LoginFormData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface ApiResponse {
|
export interface ApiResponse {
|
||||||
access_token: any;
|
access_token: string;
|
||||||
data: any;
|
data: JSON;
|
||||||
status: number;
|
status: number;
|
||||||
statusText: string;
|
statusText: string;
|
||||||
}
|
}
|
@ -2,3 +2,17 @@ export interface IRegion {
|
|||||||
id: number;
|
id: number;
|
||||||
name: string;
|
name: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ICity {
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IBoiler {
|
||||||
|
id: string;
|
||||||
|
id_object: string;
|
||||||
|
boiler_name: string;
|
||||||
|
boiler_code: string;
|
||||||
|
id_city: number;
|
||||||
|
activity: boolean;
|
||||||
|
}
|
@ -4,6 +4,12 @@ export interface IServer {
|
|||||||
region_id: number;
|
region_id: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface IServersInfo extends IServer {
|
||||||
|
servers_count: number;
|
||||||
|
IPs_count: number;
|
||||||
|
status: string;
|
||||||
|
}
|
||||||
|
|
||||||
export interface IServerIP {
|
export interface IServerIP {
|
||||||
name: string;
|
name: string;
|
||||||
is_actual: boolean;
|
is_actual: boolean;
|
||||||
|
@ -9,17 +9,14 @@ import List from '@mui/material/List';
|
|||||||
import Typography from '@mui/material/Typography';
|
import Typography from '@mui/material/Typography';
|
||||||
import Divider from '@mui/material/Divider';
|
import Divider from '@mui/material/Divider';
|
||||||
import IconButton from '@mui/material/IconButton';
|
import IconButton from '@mui/material/IconButton';
|
||||||
import Badge from '@mui/material/Badge';
|
|
||||||
import Container from '@mui/material/Container';
|
import Container from '@mui/material/Container';
|
||||||
import MenuIcon from '@mui/icons-material/Menu';
|
import MenuIcon from '@mui/icons-material/Menu';
|
||||||
import ChevronLeftIcon from '@mui/icons-material/ChevronLeft';
|
import { Api, Assignment, Home, People, Shield, Storage, } from '@mui/icons-material';
|
||||||
import NotificationsIcon from '@mui/icons-material/Notifications';
|
import { ListItem, ListItemButton, ListItemIcon, ListItemText, } from '@mui/material';
|
||||||
import { AccountCircle, Api, Assignment, ExitToApp, Home, People, Print, Report, Schedule, SendAndArchive, Settings, Shield, Storage, Tablet } from '@mui/icons-material';
|
|
||||||
import { ListItem, ListItemButton, ListItemIcon, ListItemText, colors } from '@mui/material';
|
|
||||||
import { Outlet, useNavigate } from 'react-router-dom';
|
import { Outlet, useNavigate } from 'react-router-dom';
|
||||||
import { UserData } from '../interfaces/auth';
|
import { UserData } from '../interfaces/auth';
|
||||||
import { getUserData, useAuthStore } from '../store/auth';
|
import { getUserData, useAuthStore } from '../store/auth';
|
||||||
import { Theme, useTheme } from '@emotion/react';
|
import { useTheme } from '@emotion/react';
|
||||||
import AccountMenu from '../components/AccountMenu';
|
import AccountMenu from '../components/AccountMenu';
|
||||||
|
|
||||||
const drawerWidth: number = 240;
|
const drawerWidth: number = 240;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
// Layout for dashboard with responsive drawer
|
// Layout for dashboard with responsive drawer
|
||||||
|
|
||||||
import { Link, NavLink, Navigate, Outlet, useLocation, useNavigate } from "react-router-dom"
|
import { Outlet, useLocation, useNavigate } from "react-router-dom"
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import AppBar from '@mui/material/AppBar';
|
import AppBar from '@mui/material/AppBar';
|
||||||
import Box from '@mui/material/Box';
|
import Box from '@mui/material/Box';
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import "@fontsource/inter";
|
import "@fontsource/inter";
|
||||||
import React from 'react'
|
import React, { useEffect } from 'react'
|
||||||
import ReactDOM from 'react-dom/client'
|
import ReactDOM from 'react-dom/client'
|
||||||
import App from './App.tsx'
|
import App from './App.tsx'
|
||||||
import './index.css'
|
import './index.css'
|
||||||
@ -7,9 +7,9 @@ import { registerSW } from 'virtual:pwa-register'
|
|||||||
import { ThemeProvider } from '@emotion/react'
|
import { ThemeProvider } from '@emotion/react'
|
||||||
import { createTheme } from '@mui/material'
|
import { createTheme } from '@mui/material'
|
||||||
import { ruRU } from '@mui/material/locale'
|
import { ruRU } from '@mui/material/locale'
|
||||||
import { usePrefStore } from "./store/preferences.ts";
|
import { getDarkMode, usePrefStore } from "./store/preferences.ts";
|
||||||
|
|
||||||
const theme = createTheme(
|
const darkTheme = createTheme(
|
||||||
{
|
{
|
||||||
typography: {
|
typography: {
|
||||||
fontFamily: [
|
fontFamily: [
|
||||||
@ -29,6 +29,34 @@ const theme = createTheme(
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
palette: {
|
palette: {
|
||||||
|
mode: "dark",
|
||||||
|
primary: { main: '#1976d2' },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ruRU,
|
||||||
|
);
|
||||||
|
|
||||||
|
const lightTheme = createTheme(
|
||||||
|
{
|
||||||
|
typography: {
|
||||||
|
fontFamily: [
|
||||||
|
'Inter'
|
||||||
|
].join(',')
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
MuiButtonBase: {
|
||||||
|
defaultProps: {
|
||||||
|
//disableRipple: true,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
MuiButtonGroup: {
|
||||||
|
defaultProps: {
|
||||||
|
//disableRipple: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
palette: {
|
||||||
|
mode: "light",
|
||||||
primary: { main: '#1976d2' },
|
primary: { main: '#1976d2' },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -46,10 +74,22 @@ const updateSW = registerSW({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
|
function ThemedApp() {
|
||||||
<React.StrictMode>
|
const prefStore = usePrefStore()
|
||||||
<ThemeProvider theme={theme}>
|
|
||||||
|
useEffect(() => {
|
||||||
|
getDarkMode()
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ThemeProvider theme={prefStore.darkMode ? darkTheme : lightTheme}>
|
||||||
<App />
|
<App />
|
||||||
</ThemeProvider>
|
</ThemeProvider>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
|
||||||
|
<React.StrictMode>
|
||||||
|
<ThemedApp />
|
||||||
</React.StrictMode>,
|
</React.StrictMode>,
|
||||||
)
|
)
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
import { Autocomplete, Box, Button, CircularProgress, Paper, TextField, Typography } from "@mui/material"
|
import { Autocomplete, Box, CircularProgress, Paper, TextField, Typography } from "@mui/material"
|
||||||
import { useBoilers, useCities, useRegions, useServers } from "../hooks/swrHooks"
|
import { useBoilers, useRegions, useServers } from "../hooks/swrHooks"
|
||||||
import { Fragment, useEffect, useState } from "react"
|
import { Fragment, useEffect, useState } from "react"
|
||||||
import { IRegion } from "../interfaces/fuel"
|
import { IBoiler, IRegion } from "../interfaces/fuel"
|
||||||
import { DataGrid, GridColDef } from "@mui/x-data-grid"
|
import { DataGrid, GridColDef } from "@mui/x-data-grid"
|
||||||
|
|
||||||
export default function ApiTest() {
|
export default function ApiTest() {
|
||||||
const [open, setOpen] = useState(false)
|
const [open, setOpen] = useState(false)
|
||||||
const [options, setOptions] = useState<any>([])
|
const [options, setOptions] = useState<IRegion[]>([])
|
||||||
const [search, setSearch] = useState<any>(null)
|
const [search, setSearch] = useState<string | null>(null)
|
||||||
const [debouncedSearch, setDebouncedSearch] = useState("")
|
const [debouncedSearch, setDebouncedSearch] = useState<string | null>("")
|
||||||
const [selectedOption, setSelectedOption] = useState<IRegion | null>(null)
|
const [selectedOption, setSelectedOption] = useState<IRegion | null>(null)
|
||||||
const { regions, isLoading } = useRegions(10, 1, debouncedSearch)
|
const { regions, isLoading } = useRegions(10, 1, debouncedSearch)
|
||||||
|
|
||||||
@ -28,15 +28,34 @@ export default function ApiTest() {
|
|||||||
}
|
}
|
||||||
}, [regions])
|
}, [regions])
|
||||||
|
|
||||||
const handleInputChange = (event: any, value: any) => {
|
const handleInputChange = (value: string) => {
|
||||||
setSearch(value)
|
setSearch(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleOptionChange = (event: any, value: any) => {
|
const handleOptionChange = (value: IRegion | null) => {
|
||||||
setSelectedOption(value)
|
setSelectedOption(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
//const { boilers } = useBoilers(10, 1)
|
const [boilersPage, setBoilersPage] = useState(1)
|
||||||
|
const [boilerSearch, setBoilerSearch] = useState("")
|
||||||
|
const [debouncedBoilerSearch, setDebouncedBoilerSearch] = useState("")
|
||||||
|
const { boilers } = useBoilers(10, boilersPage, debouncedBoilerSearch)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const handler = setTimeout(() => {
|
||||||
|
setDebouncedBoilerSearch(boilerSearch)
|
||||||
|
}, 500)
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
clearTimeout(handler)
|
||||||
|
}
|
||||||
|
}, [boilerSearch])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setBoilersPage(1)
|
||||||
|
setBoilerSearch("")
|
||||||
|
}, [])
|
||||||
|
|
||||||
//const { cities } = useCities(10, 1)
|
//const { cities } = useCities(10, 1)
|
||||||
const { servers, isLoading: serversLoading } = useServers(selectedOption?.id, 0, 10)
|
const { servers, isLoading: serversLoading } = useServers(selectedOption?.id, 0, 10)
|
||||||
|
|
||||||
@ -45,12 +64,20 @@ export default function ApiTest() {
|
|||||||
{ field: 'name', headerName: 'Название', type: "string" },
|
{ field: 'name', headerName: 'Название', type: "string" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
const boilersColumns: GridColDef[] = [
|
||||||
|
{ field: 'id', headerName: 'ID', type: "number" },
|
||||||
|
{ field: 'boiler_name', headerName: 'Название', type: "string" },
|
||||||
|
{ field: 'boiler_code', headerName: 'Код', type: "string" },
|
||||||
|
{ field: 'id_city', headerName: 'Город', type: "string" },
|
||||||
|
{ field: 'activity', headerName: 'Активен', type: "boolean" },
|
||||||
|
]
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box sx={{ display: 'flex', flexDirection: 'column', gap: '16px', height: '100%' }}>
|
<Box sx={{ display: 'flex', flexDirection: 'column', gap: '16px', height: '100%' }}>
|
||||||
<Paper elevation={1}>
|
<Paper elevation={1}>
|
||||||
<Box sx={{ display: 'flex', flexDirection: 'column', gap: '16px', height: '100%', p: '16px'}}>
|
<Box sx={{ display: 'flex', flexDirection: 'column', gap: '16px', height: '100%', p: '16px' }}>
|
||||||
<Typography variant='h6' fontWeight='600'>
|
<Typography variant='h6' fontWeight='600'>
|
||||||
Get servers
|
Servers
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
<Autocomplete
|
<Autocomplete
|
||||||
@ -61,11 +88,11 @@ export default function ApiTest() {
|
|||||||
onClose={() => {
|
onClose={() => {
|
||||||
setOpen(false)
|
setOpen(false)
|
||||||
}}
|
}}
|
||||||
onInputChange={handleInputChange}
|
onInputChange={(_, value) => handleInputChange(value)}
|
||||||
onChange={handleOptionChange}
|
onChange={(_, value) => handleOptionChange(value)}
|
||||||
filterOptions={(x) => x}
|
filterOptions={(x) => x}
|
||||||
isOptionEqualToValue={(option: any, value: any) => option.name === value.name}
|
isOptionEqualToValue={(option: IRegion, value: IRegion) => option.name === value.name}
|
||||||
getOptionLabel={(option: any) => option.name ? option.name : ""}
|
getOptionLabel={(option: IRegion) => option.name ? option.name : ""}
|
||||||
options={options}
|
options={options}
|
||||||
loading={isLoading}
|
loading={isLoading}
|
||||||
value={selectedOption}
|
value={selectedOption}
|
||||||
@ -98,6 +125,24 @@ export default function ApiTest() {
|
|||||||
}
|
}
|
||||||
</Box>
|
</Box>
|
||||||
</Paper>
|
</Paper>
|
||||||
|
|
||||||
|
<Paper elevation={1}>
|
||||||
|
<Box sx={{ display: 'flex', flexDirection: 'column', gap: '16px', height: '100%', p: '16px' }}>
|
||||||
|
<Typography variant='h6' fontWeight='600'>
|
||||||
|
Boilers
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
{boilers &&
|
||||||
|
<DataGrid
|
||||||
|
rows={boilers.map((boiler: IBoiler) => {
|
||||||
|
return { ...boiler, id: boiler.id_object }
|
||||||
|
})}
|
||||||
|
columns={boilersColumns}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
|
||||||
|
</Box>
|
||||||
|
</Paper>
|
||||||
</Box>
|
</Box>
|
||||||
)
|
)
|
||||||
}
|
}
|
@ -1,37 +1,6 @@
|
|||||||
import { GridColDef } from '@mui/x-data-grid'
|
|
||||||
import FolderViewer from '../components/FolderViewer'
|
import FolderViewer from '../components/FolderViewer'
|
||||||
|
|
||||||
export default function Documents() {
|
export default function Documents() {
|
||||||
const organizationColumns: GridColDef[] = [
|
|
||||||
{ field: 'id', headerName: 'ID', type: "number", width: 90 },
|
|
||||||
{ field: 'id_1c', headerName: 'ID 1C', type: "string", width: 90 },
|
|
||||||
{ field: 'name', headerName: 'Наименование', type: "string", width: 90 },
|
|
||||||
{ field: 'full_name', headerName: 'Полное наименование', type: "string", width: 90 },
|
|
||||||
{ field: 'inn', headerName: 'ИНН', type: "string", width: 70 },
|
|
||||||
{ field: 'ogrn', headerName: 'ОГРН', width: 130 },
|
|
||||||
{ field: 'kpp', headerName: 'КПП', width: 130 },
|
|
||||||
{ field: 'okopf', headerName: 'ОКОПФ', width: 90 },
|
|
||||||
{ field: 'legal_address', headerName: 'Юридический адрес', width: 90 },
|
|
||||||
{ field: 'actual_address', headerName: 'Фактический адрес', width: 90 },
|
|
||||||
{ field: 'mail_address', headerName: 'Почтовый адрес', type: "string", width: 90 },
|
|
||||||
{ field: 'id_budget', headerName: 'Активен', type: "number", width: 90 },
|
|
||||||
{ field: 'fio_dir', headerName: 'Активен', type: "string", width: 90 },
|
|
||||||
{ field: 'phone', headerName: 'Телефон', type: "string", width: 90 },
|
|
||||||
{ field: 'email', headerName: 'Email', type: "string", width: 90 },
|
|
||||||
{ field: 'comment', headerName: 'Комментарий', type: "string", width: 90 },
|
|
||||||
{ field: 'id_bank', headerName: 'Банк', type: "string", width: 90 },
|
|
||||||
{ field: 'active', headerName: 'Активен', type: "boolean", width: 90 },
|
|
||||||
];
|
|
||||||
|
|
||||||
const bankColumns: GridColDef[] = [
|
|
||||||
{ field: 'id', headerName: 'ID', type: "number", width: 90 },
|
|
||||||
{ field: 'id_1c', headerName: 'ID 1C', type: "string", width: 90 },
|
|
||||||
{ field: 'name', headerName: 'Наименование', type: "string", width: 90 },
|
|
||||||
{ field: 'bik', headerName: 'БИК', type: "string", width: 90 },
|
|
||||||
{ field: 'corschet', headerName: 'Кор. счет', type: "string", width: 70 },
|
|
||||||
{ field: 'activ', headerName: 'Активен', type: "boolean", width: 130 },
|
|
||||||
];
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<FolderViewer />
|
<FolderViewer />
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import { Error } from "@mui/icons-material";
|
import { Error } from "@mui/icons-material";
|
||||||
import { Box, Typography, colors } from "@mui/material";
|
import { Box, Typography } from "@mui/material";
|
||||||
import { red } from "@mui/material/colors";
|
|
||||||
|
|
||||||
export default function NotFound() {
|
export default function NotFound() {
|
||||||
return (
|
return (
|
||||||
|
@ -1,18 +1,15 @@
|
|||||||
import { useEffect, useState } from "react"
|
import { useState } from "react"
|
||||||
import { Box, Button, Typography } from "@mui/material"
|
import { Box, Button } from "@mui/material"
|
||||||
import axiosInstance from "../http/axiosInstance"
|
import axiosInstance from "../http/axiosInstance"
|
||||||
import { DataGrid } from "@mui/x-data-grid"
|
import { DataGrid } from "@mui/x-data-grid"
|
||||||
|
|
||||||
export default function Reports() {
|
export default function Reports() {
|
||||||
const [state, setState] = useState<any>(null)
|
const [state, setState] = useState(null)
|
||||||
const [exportData, setExportData] = useState<any>(null)
|
|
||||||
|
|
||||||
const fetch = async () => {
|
const fetch = async () => {
|
||||||
await axiosInstance.get(`/info/reports/0?to_export=true`, {
|
await axiosInstance.get(`/info/reports/0?to_export=true`, {
|
||||||
responseType: 'blob',
|
responseType: 'blob',
|
||||||
}).then(response => {
|
}).then(response => {
|
||||||
setExportData(response.data)
|
|
||||||
|
|
||||||
const url = window.URL.createObjectURL(response.data)
|
const url = window.URL.createObjectURL(response.data)
|
||||||
const link = document.createElement('a')
|
const link = document.createElement('a')
|
||||||
link.href = url
|
link.href = url
|
||||||
@ -71,7 +68,7 @@ export default function Reports() {
|
|||||||
disableRowSelectionOnClick
|
disableRowSelectionOnClick
|
||||||
|
|
||||||
processRowUpdate={(updatedRow, originalRow) => {
|
processRowUpdate={(updatedRow, originalRow) => {
|
||||||
console.log(updatedRow)
|
console.log(updatedRow, originalRow)
|
||||||
return updatedRow
|
return updatedRow
|
||||||
}}
|
}}
|
||||||
|
|
||||||
|
@ -49,7 +49,7 @@ export default function Roles() {
|
|||||||
disableRowSelectionOnClick
|
disableRowSelectionOnClick
|
||||||
|
|
||||||
processRowUpdate={(updatedRow, originalRow) => {
|
processRowUpdate={(updatedRow, originalRow) => {
|
||||||
console.log(updatedRow)
|
console.log(updatedRow, originalRow)
|
||||||
return updatedRow
|
return updatedRow
|
||||||
}}
|
}}
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ export default function Settings() {
|
|||||||
{
|
{
|
||||||
field: 'role_id',
|
field: 'role_id',
|
||||||
headerName: 'Роль',
|
headerName: 'Роль',
|
||||||
valueGetter: (value, row) => {
|
valueGetter: (value) => {
|
||||||
if (roles) {
|
if (roles) {
|
||||||
const roleName = roles.find((role: IRole) => role.id === value).name
|
const roleName = roles.find((role: IRole) => role.id === value).name
|
||||||
return roleName
|
return roleName
|
||||||
@ -70,7 +70,7 @@ export default function Settings() {
|
|||||||
disableRowSelectionOnClick
|
disableRowSelectionOnClick
|
||||||
|
|
||||||
processRowUpdate={(updatedRow, originalRow) => {
|
processRowUpdate={(updatedRow, originalRow) => {
|
||||||
console.log(updatedRow)
|
console.log(updatedRow, originalRow)
|
||||||
return updatedRow
|
return updatedRow
|
||||||
}}
|
}}
|
||||||
|
|
||||||
|
@ -65,7 +65,7 @@ export default function Users() {
|
|||||||
disableRowSelectionOnClick
|
disableRowSelectionOnClick
|
||||||
|
|
||||||
processRowUpdate={(updatedRow, originalRow) => {
|
processRowUpdate={(updatedRow, originalRow) => {
|
||||||
console.log(updatedRow)
|
console.log(updatedRow, originalRow)
|
||||||
return updatedRow
|
return updatedRow
|
||||||
}}
|
}}
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ const config: AxiosRequestConfig = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default class AuthService {
|
export default class AuthService {
|
||||||
static async login(data: any) {
|
static async login(data: FormData) {
|
||||||
return await axiosInstance.post(`/auth/login`, data, config)
|
return await axiosInstance.post(`/auth/login`, data, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,11 +100,11 @@ export default class DocumentService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Upload Files
|
// Upload Files
|
||||||
static async uploadFiles(folder_id: number, files: any, setUploadProgress?: any) {
|
static async uploadFiles(folder_id: number, files: FormData, setUploadProgress?: (value: number) => void) {
|
||||||
return await axiosInstance.post(`/info/documents/upload/${folder_id}`, files, {
|
return await axiosInstance.post(`/info/documents/upload/${folder_id}`, files, {
|
||||||
onUploadProgress: (progressEvent: AxiosProgressEvent) => {
|
onUploadProgress: (progressEvent: AxiosProgressEvent) => {
|
||||||
const percentCompleted = progressEvent.progress
|
const percentCompleted = progressEvent.progress
|
||||||
setUploadProgress?.(percentCompleted)
|
setUploadProgress?.(percentCompleted || 0)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -127,7 +127,7 @@ export default class DocumentService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Convert Phones
|
// Convert Phones
|
||||||
static async convertPhones(data: any) {
|
static async convertPhones(data: FormData) {
|
||||||
return await axiosInstance.post(`/info/other/phones/`, data)
|
return await axiosInstance.post(`/info/other/phones/`, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import axios, { AxiosRequestConfig } from "axios";
|
import { AxiosRequestConfig } from "axios";
|
||||||
import axiosInstance from "../http/axiosInstance";
|
import axiosInstance from "../http/axiosInstance";
|
||||||
import { IHardware, IServer, IServerIP, IStorage } from "../interfaces/servers";
|
import { IHardware, IServer, IServerIP, IStorage } from "../interfaces/servers";
|
||||||
import { BASE_URL } from "../constants";
|
import { BASE_URL } from "../constants";
|
||||||
|
@ -2,13 +2,14 @@ import { AxiosRequestConfig } from "axios";
|
|||||||
import axiosInstance from "../http/axiosInstance";
|
import axiosInstance from "../http/axiosInstance";
|
||||||
import { UserCreds, UserData } from "../interfaces/auth";
|
import { UserCreds, UserData } from "../interfaces/auth";
|
||||||
import { BASE_URL } from "../constants";
|
import { BASE_URL } from "../constants";
|
||||||
|
import { IUserCreate } from "../interfaces/user";
|
||||||
|
|
||||||
const config: AxiosRequestConfig = {
|
const config: AxiosRequestConfig = {
|
||||||
baseURL: BASE_URL.auth
|
baseURL: BASE_URL.auth
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class UserService {
|
export default class UserService {
|
||||||
static async createUser(data: any) {
|
static async createUser(data: IUserCreate) {
|
||||||
return await axiosInstance.post(`/auth/user`, data, config)
|
return await axiosInstance.post(`/auth/user`, data, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,10 +3,10 @@ import { TOKEN_AUTH_KEY, TOKEN_EXPIRY_DURATION, TOKEN_ISSUED_DATE_KEY, USER_DATA
|
|||||||
import { AuthState } from '../interfaces/auth';
|
import { AuthState } from '../interfaces/auth';
|
||||||
import AuthService from '../services/AuthService';
|
import AuthService from '../services/AuthService';
|
||||||
|
|
||||||
export const useAuthStore = create<AuthState>((set, get) => ({
|
export const useAuthStore = create<AuthState>(() => ({
|
||||||
isAuthenticated: false,
|
isAuthenticated: false,
|
||||||
token: null,
|
token: null,
|
||||||
userData: {},
|
userData: null,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const login = (token: string) => {
|
const login = (token: string) => {
|
||||||
@ -20,7 +20,7 @@ const logout = () => {
|
|||||||
localStorage.removeItem(TOKEN_AUTH_KEY);
|
localStorage.removeItem(TOKEN_AUTH_KEY);
|
||||||
localStorage.removeItem(USER_DATA_KEY);
|
localStorage.removeItem(USER_DATA_KEY);
|
||||||
localStorage.removeItem(TOKEN_ISSUED_DATE_KEY);
|
localStorage.removeItem(TOKEN_ISSUED_DATE_KEY);
|
||||||
useAuthStore.setState(() => ({ isAuthenticated: false, token: null, userData: {} }));
|
useAuthStore.setState(() => ({ isAuthenticated: false, token: null, userData: null }));
|
||||||
}
|
}
|
||||||
|
|
||||||
const initAuth = async () => {
|
const initAuth = async () => {
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
import { create } from 'zustand';
|
import { create } from 'zustand';
|
||||||
import { PreferencesState } from '../interfaces/preferences';
|
import { PreferencesState } from '../interfaces/preferences';
|
||||||
|
|
||||||
export const usePrefStore = create<PreferencesState>((set, get) => ({
|
export const usePrefStore = create<PreferencesState>(() => ({
|
||||||
darkMode: false
|
darkMode: false
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const getDarkMode = () => {
|
const getDarkMode = () => {
|
||||||
const darkMode = localStorage.getItem('darkMode')
|
const darkMode = localStorage.getItem('darkMode')
|
||||||
|
usePrefStore.setState(() => ({ darkMode: darkMode?.toLowerCase() === "true" ? true : false }))
|
||||||
return darkMode
|
return darkMode
|
||||||
}
|
}
|
||||||
|
|
||||||
|
1
frontend_reactjs/tsconfig.node.tsbuildinfo
Normal file
1
frontend_reactjs/tsconfig.node.tsbuildinfo
Normal file
File diff suppressed because one or more lines are too long
2
frontend_reactjs/vite.config.d.ts
vendored
Normal file
2
frontend_reactjs/vite.config.d.ts
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
declare const _default: import("vite").UserConfig;
|
||||||
|
export default _default;
|
82
frontend_reactjs/vite.config.js
Normal file
82
frontend_reactjs/vite.config.js
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
import { defineConfig } from 'vite';
|
||||||
|
import react from '@vitejs/plugin-react-swc';
|
||||||
|
import { VitePWA } from "vite-plugin-pwa";
|
||||||
|
import { nodePolyfills } from 'vite-plugin-node-polyfills';
|
||||||
|
// https://vitejs.dev/config/
|
||||||
|
export default defineConfig({
|
||||||
|
plugins: [
|
||||||
|
nodePolyfills(),
|
||||||
|
react(),
|
||||||
|
VitePWA({
|
||||||
|
registerType: 'autoUpdate',
|
||||||
|
workbox: {
|
||||||
|
globPatterns: ["**/*"],
|
||||||
|
runtimeCaching: [
|
||||||
|
{
|
||||||
|
urlPattern: function (_a) {
|
||||||
|
var request = _a.request;
|
||||||
|
return request.mode === 'navigate';
|
||||||
|
},
|
||||||
|
handler: 'NetworkFirst',
|
||||||
|
options: {
|
||||||
|
cacheName: 'html-cache',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
urlPattern: /\.(?:js|css)$/,
|
||||||
|
handler: 'StaleWhileRevalidate',
|
||||||
|
options: {
|
||||||
|
cacheName: 'static-resources',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
urlPattern: /\.(?:png|jpg|jpeg|svg|gif)$/,
|
||||||
|
handler: 'CacheFirst',
|
||||||
|
options: {
|
||||||
|
cacheName: 'image-cache',
|
||||||
|
expiration: {
|
||||||
|
maxEntries: 50,
|
||||||
|
maxAgeSeconds: 30 * 24 * 60 * 60, // 30 days
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
includeAssets: [
|
||||||
|
"**/*",
|
||||||
|
],
|
||||||
|
manifest: {
|
||||||
|
"theme_color": "#f69435",
|
||||||
|
"background_color": "#f69435",
|
||||||
|
"display": "standalone",
|
||||||
|
"scope": "/",
|
||||||
|
"start_url": "/",
|
||||||
|
"short_name": "Vite PWA",
|
||||||
|
"description": "Vite PWA Boilerplate",
|
||||||
|
"name": "Vite PWA Boilerplate",
|
||||||
|
"icons": [
|
||||||
|
{
|
||||||
|
"src": "/icon-192x192.png",
|
||||||
|
"sizes": "192x192",
|
||||||
|
"type": "image/png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "/icon-256x256.png",
|
||||||
|
"sizes": "256x256",
|
||||||
|
"type": "image/png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "/icon-384x384.png",
|
||||||
|
"sizes": "384x384",
|
||||||
|
"type": "image/png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "/icon-512x512.png",
|
||||||
|
"sizes": "512x512",
|
||||||
|
"type": "image/png"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
});
|
@ -5349,11 +5349,6 @@ yocto-queue@^0.1.0:
|
|||||||
resolved "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz"
|
resolved "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz"
|
||||||
integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==
|
integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==
|
||||||
|
|
||||||
zod@^3.23.8:
|
|
||||||
version "3.23.8"
|
|
||||||
resolved "https://registry.npmjs.org/zod/-/zod-3.23.8.tgz"
|
|
||||||
integrity sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==
|
|
||||||
|
|
||||||
zustand@^4.5.2:
|
zustand@^4.5.2:
|
||||||
version "4.5.2"
|
version "4.5.2"
|
||||||
resolved "https://registry.npmjs.org/zustand/-/zustand-4.5.2.tgz"
|
resolved "https://registry.npmjs.org/zustand/-/zustand-4.5.2.tgz"
|
||||||
|
Reference in New Issue
Block a user