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-router-dom": "^6.23.1",
|
||||
"swr": "^2.2.5",
|
||||
"zod": "^3.23.8",
|
||||
"zustand": "^4.5.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
@ -9927,14 +9926,6 @@
|
||||
"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": {
|
||||
"version": "4.5.2",
|
||||
"resolved": "https://registry.npmjs.org/zustand/-/zustand-4.5.2.tgz",
|
||||
|
@ -31,7 +31,6 @@
|
||||
"react-hook-form": "^7.52.0",
|
||||
"react-router-dom": "^6.23.1",
|
||||
"swr": "^2.2.5",
|
||||
"zod": "^3.23.8",
|
||||
"zustand": "^4.5.2"
|
||||
},
|
||||
"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 Users from "./pages/Users"
|
||||
import Roles from "./pages/Roles"
|
||||
@ -10,7 +10,7 @@ import ApiTest from "./pages/ApiTest"
|
||||
import SignUp from "./pages/auth/SignUp"
|
||||
import { initAuth, useAuthStore } from "./store/auth"
|
||||
import { useEffect, useState } from "react"
|
||||
import { Box, CircularProgress, Container } from "@mui/material"
|
||||
import { Box, CircularProgress } from "@mui/material"
|
||||
import Documents from "./pages/Documents"
|
||||
import Reports from "./pages/Reports"
|
||||
|
||||
|
@ -4,14 +4,13 @@ import Avatar from '@mui/material/Avatar';
|
||||
import Menu from '@mui/material/Menu';
|
||||
import MenuItem from '@mui/material/MenuItem';
|
||||
import ListItemIcon from '@mui/material/ListItemIcon';
|
||||
import Divider from '@mui/material/Divider';
|
||||
import IconButton from '@mui/material/IconButton';
|
||||
import Tooltip from '@mui/material/Tooltip';
|
||||
import Settings from '@mui/icons-material/Settings';
|
||||
import Logout from '@mui/icons-material/Logout';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { logout, useAuthStore } from '../store/auth';
|
||||
import { ListItem, Switch, styled } from '@mui/material';
|
||||
import { logout } from '../store/auth';
|
||||
import { ListItemText, Switch, styled } from '@mui/material';
|
||||
import { setDarkMode, usePrefStore } from '../store/preferences';
|
||||
|
||||
const Android12Switch = styled(Switch)(({ theme }) => ({
|
||||
@ -79,36 +78,39 @@ export default function AccountMenu() {
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
</Box>
|
||||
|
||||
<Menu
|
||||
anchorEl={anchorEl}
|
||||
id="account-menu"
|
||||
open={open}
|
||||
onClose={handleClose}
|
||||
PaperProps={{
|
||||
elevation: 0,
|
||||
sx: {
|
||||
overflow: 'visible',
|
||||
filter: 'drop-shadow(0px 2px 8px rgba(0,0,0,0.32))',
|
||||
mt: 1.5,
|
||||
'& .MuiAvatar-root': {
|
||||
width: 32,
|
||||
height: 32,
|
||||
ml: -0.5,
|
||||
mr: 1,
|
||||
slotProps={{
|
||||
paper: {
|
||||
elevation: 0,
|
||||
sx: {
|
||||
overflow: 'visible',
|
||||
filter: 'drop-shadow(0px 2px 8px rgba(0,0,0,0.32))',
|
||||
mt: 1.5,
|
||||
'& .MuiAvatar-root': {
|
||||
width: 32,
|
||||
height: 32,
|
||||
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' }}
|
||||
anchorOrigin={{ horizontal: 'right', vertical: 'bottom' }}
|
||||
@ -116,12 +118,16 @@ export default function AccountMenu() {
|
||||
<MenuItem onClick={() => {
|
||||
console.log()
|
||||
}}>
|
||||
<Android12Switch
|
||||
defaultChecked={prefStore.darkMode}
|
||||
onChange={(e) => {
|
||||
setDarkMode(e.target.checked)
|
||||
}} />
|
||||
Тема
|
||||
<ListItemIcon>
|
||||
<Android12Switch
|
||||
defaultChecked={prefStore.darkMode}
|
||||
onChange={(e) => {
|
||||
setDarkMode(e.target.checked)
|
||||
}} />
|
||||
</ListItemIcon>
|
||||
<ListItemText>
|
||||
Тема: {prefStore.darkMode ? "темная" : "светлая"}
|
||||
</ListItemText>
|
||||
</MenuItem>
|
||||
|
||||
|
||||
|
@ -1,21 +1,21 @@
|
||||
import { useState, useEffect, useMemo } from 'react';
|
||||
import axiosInstance from '../http/axiosInstance';
|
||||
import { useState, useEffect, useMemo } from 'react'
|
||||
import axiosInstance from '../http/axiosInstance'
|
||||
export function useDataFetching<T>(url: string, initData: T): T {
|
||||
const [data, setData] = useState<T>(initData);
|
||||
const [data, setData] = useState<T>(initData)
|
||||
|
||||
useEffect(() => {
|
||||
const fetchData = async () => {
|
||||
const response = await axiosInstance.get(url);
|
||||
const result = await response.data;
|
||||
setData(result);
|
||||
};
|
||||
const response = await axiosInstance.get(url)
|
||||
const result = await response.data
|
||||
setData(result)
|
||||
}
|
||||
|
||||
fetchData();
|
||||
}, [url]);
|
||||
fetchData()
|
||||
}, [url])
|
||||
console.log(data)
|
||||
// Memoize the data value
|
||||
const memoizedData = useMemo<T>(() => data, [data]);
|
||||
return memoizedData;
|
||||
};
|
||||
const memoizedData = useMemo<T>(() => data, [data])
|
||||
return memoizedData
|
||||
}
|
||||
|
||||
export default useDataFetching;
|
@ -1,6 +1,6 @@
|
||||
import { useDocuments, useDownload, useFolders } from '../hooks/swrHooks'
|
||||
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 React, { useEffect, useRef, useState } from 'react'
|
||||
import DocumentService from '../services/DocumentService'
|
||||
@ -29,7 +29,7 @@ const FileItemStyle: SxProps = {
|
||||
padding: '8px'
|
||||
}
|
||||
|
||||
function ItemFolder({ folder, index, handleFolderClick, ...props }: FolderProps) {
|
||||
function ItemFolder({ folder, handleFolderClick, ...props }: FolderProps) {
|
||||
return (
|
||||
<ListItemButton
|
||||
onClick={() => handleFolderClick(folder)}
|
||||
@ -118,6 +118,7 @@ export default function FolderViewer() {
|
||||
}
|
||||
|
||||
const handleDocumentClick = async (doc: IDocument, index: number) => {
|
||||
console.log(doc)
|
||||
setCurrentFileNo(index)
|
||||
setFileViewerModal(true)
|
||||
}
|
||||
@ -139,7 +140,7 @@ export default function FolderViewer() {
|
||||
setDragOver(true)
|
||||
}
|
||||
|
||||
const handleDragLeave = (e: React.DragEvent) => {
|
||||
const handleDragLeave = () => {
|
||||
setDragOver(false)
|
||||
}
|
||||
|
||||
@ -159,11 +160,11 @@ export default function FolderViewer() {
|
||||
setIsUploading(true)
|
||||
if (filesToUpload.length > 0 && currentFolder && currentFolder.id) {
|
||||
const formData = new FormData()
|
||||
for (let file of filesToUpload) {
|
||||
for (const file of filesToUpload) {
|
||||
formData.append('files', file)
|
||||
}
|
||||
try {
|
||||
const response = await DocumentService.uploadFiles(currentFolder.id, formData, setUploadProgress);
|
||||
await DocumentService.uploadFiles(currentFolder.id, formData, setUploadProgress);
|
||||
setIsUploading(false);
|
||||
setFilesToUpload([]);
|
||||
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";
|
||||
|
||||
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 { ApiResponse } from '../../interfaces/auth';
|
||||
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 { useCompanies } from '../../hooks/swrHooks';
|
||||
|
||||
@ -12,7 +12,7 @@ interface Props {
|
||||
}
|
||||
|
||||
const style = {
|
||||
position: 'absolute' as 'absolute',
|
||||
position: 'absolute',
|
||||
top: '50%',
|
||||
left: '50%',
|
||||
transform: 'translate(-50%, -50%)',
|
||||
@ -93,7 +93,7 @@ export default function CreateCompanyModal({
|
||||
/>
|
||||
|
||||
{companies}
|
||||
|
||||
|
||||
<Select
|
||||
label="owner_id"
|
||||
{...register('owner_id', { required: '' })}
|
||||
|
@ -11,7 +11,7 @@ interface Props {
|
||||
}
|
||||
|
||||
const style = {
|
||||
position: 'absolute' as 'absolute',
|
||||
position: 'absolute',
|
||||
top: '50%',
|
||||
left: '50%',
|
||||
transform: 'translate(-50%, -50%)',
|
||||
|
@ -11,7 +11,7 @@ interface Props {
|
||||
}
|
||||
|
||||
const style = {
|
||||
position: 'absolute' as 'absolute',
|
||||
position: 'absolute',
|
||||
top: '50%',
|
||||
left: '50%',
|
||||
transform: 'translate(-50%, -50%)',
|
||||
@ -53,7 +53,6 @@ export default function CreateRoleModal({
|
||||
aria-describedby="modal-modal-description"
|
||||
>
|
||||
<form onSubmit={handleSubmit(onSubmit)}>
|
||||
|
||||
<Box sx={style}>
|
||||
<Typography variant="h6" component="h6" gutterBottom>
|
||||
Создание роли
|
||||
|
@ -11,7 +11,7 @@ interface Props {
|
||||
}
|
||||
|
||||
const style = {
|
||||
position: 'absolute' as 'absolute',
|
||||
position: 'absolute',
|
||||
top: '50%',
|
||||
left: '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 { ChevronLeft, ChevronRight, Close, Warning } from '@mui/icons-material';
|
||||
import { useDownload, useFileType } from '../../hooks/swrHooks';
|
||||
import { fileTypeFromBlob } from 'file-type/core';
|
||||
|
||||
import jsPreviewExcel from "@js-preview/excel"
|
||||
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 jsPreviewPdf from '@js-preview/pdf'
|
||||
import { IDocument } from '../../interfaces/documents';
|
||||
|
||||
interface Props {
|
||||
open: boolean;
|
||||
setOpen: (state: boolean) => void;
|
||||
docs: any;
|
||||
docs: IDocument[];
|
||||
currentFileNo: number;
|
||||
setCurrentFileNo: (state: number) => void;
|
||||
}
|
||||
@ -29,13 +29,10 @@ function PdfViewer({
|
||||
}: ViewerProps) {
|
||||
const previewContainerRef = useRef(null)
|
||||
|
||||
const [loadingPreview, setLoadingPreview] = useState(false)
|
||||
|
||||
const pdfPreviewer = jsPreviewPdf
|
||||
|
||||
useEffect(() => {
|
||||
if (previewContainerRef && previewContainerRef.current) {
|
||||
setLoadingPreview(true);
|
||||
pdfPreviewer.init(previewContainerRef.current)
|
||||
.preview(url)
|
||||
}
|
||||
@ -60,11 +57,8 @@ function DocxViewer({
|
||||
}: ViewerProps) {
|
||||
const previewContainerRef = useRef(null)
|
||||
|
||||
const [loadingPreview, setLoadingPreview] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
if (previewContainerRef && previewContainerRef.current) {
|
||||
setLoadingPreview(true);
|
||||
jsPreviewDocx.init(previewContainerRef.current, {
|
||||
breakPages: true,
|
||||
inWrapper: true,
|
||||
@ -93,11 +87,8 @@ function ExcelViewer({
|
||||
}: ViewerProps) {
|
||||
const previewContainerRef = useRef(null)
|
||||
|
||||
const [loadingPreview, setLoadingPreview] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
if (previewContainerRef && previewContainerRef.current) {
|
||||
setLoadingPreview(true);
|
||||
jsPreviewExcel.init(previewContainerRef.current)
|
||||
.preview(url)
|
||||
}
|
||||
@ -145,7 +136,7 @@ export default function FileViewer({
|
||||
currentFileNo,
|
||||
setCurrentFileNo
|
||||
}: 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)
|
||||
|
||||
|
@ -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(
|
||||
fileName && file ? `/filetype/${fileName}` : null,
|
||||
file ? (key: string) => fileTypeFromBlob(file) : null,
|
||||
file ? () => fileTypeFromBlob(file) : null,
|
||||
{
|
||||
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(
|
||||
`/general/regions?limit=${limit || 10}&page=${page || 1}${search ? `&search=${search}` : ''}`,
|
||||
(url) => fetcher(url, BASE_URL.fuel),
|
||||
|
@ -19,7 +19,7 @@ export interface UserCreds extends User {
|
||||
export interface AuthState {
|
||||
isAuthenticated: boolean;
|
||||
token: string | null;
|
||||
userData: UserData | {};
|
||||
userData: UserData | null;
|
||||
}
|
||||
|
||||
export interface LoginFormData {
|
||||
@ -32,8 +32,8 @@ export interface LoginFormData {
|
||||
}
|
||||
|
||||
export interface ApiResponse {
|
||||
access_token: any;
|
||||
data: any;
|
||||
access_token: string;
|
||||
data: JSON;
|
||||
status: number;
|
||||
statusText: string;
|
||||
}
|
@ -1,4 +1,18 @@
|
||||
export interface IRegion {
|
||||
id: number;
|
||||
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;
|
||||
}
|
||||
|
||||
export interface IServersInfo extends IServer {
|
||||
servers_count: number;
|
||||
IPs_count: number;
|
||||
status: string;
|
||||
}
|
||||
|
||||
export interface IServerIP {
|
||||
name: string;
|
||||
is_actual: boolean;
|
||||
|
@ -9,17 +9,14 @@ import List from '@mui/material/List';
|
||||
import Typography from '@mui/material/Typography';
|
||||
import Divider from '@mui/material/Divider';
|
||||
import IconButton from '@mui/material/IconButton';
|
||||
import Badge from '@mui/material/Badge';
|
||||
import Container from '@mui/material/Container';
|
||||
import MenuIcon from '@mui/icons-material/Menu';
|
||||
import ChevronLeftIcon from '@mui/icons-material/ChevronLeft';
|
||||
import NotificationsIcon from '@mui/icons-material/Notifications';
|
||||
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 { Api, Assignment, Home, People, Shield, Storage, } from '@mui/icons-material';
|
||||
import { ListItem, ListItemButton, ListItemIcon, ListItemText, } from '@mui/material';
|
||||
import { Outlet, useNavigate } from 'react-router-dom';
|
||||
import { UserData } from '../interfaces/auth';
|
||||
import { getUserData, useAuthStore } from '../store/auth';
|
||||
import { Theme, useTheme } from '@emotion/react';
|
||||
import { useTheme } from '@emotion/react';
|
||||
import AccountMenu from '../components/AccountMenu';
|
||||
|
||||
const drawerWidth: number = 240;
|
||||
|
@ -1,6 +1,6 @@
|
||||
// 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 AppBar from '@mui/material/AppBar';
|
||||
import Box from '@mui/material/Box';
|
||||
|
@ -1,5 +1,5 @@
|
||||
import "@fontsource/inter";
|
||||
import React from 'react'
|
||||
import React, { useEffect } from 'react'
|
||||
import ReactDOM from 'react-dom/client'
|
||||
import App from './App.tsx'
|
||||
import './index.css'
|
||||
@ -7,9 +7,9 @@ import { registerSW } from 'virtual:pwa-register'
|
||||
import { ThemeProvider } from '@emotion/react'
|
||||
import { createTheme } from '@mui/material'
|
||||
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: {
|
||||
fontFamily: [
|
||||
@ -29,6 +29,34 @@ const theme = createTheme(
|
||||
}
|
||||
},
|
||||
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' },
|
||||
},
|
||||
},
|
||||
@ -46,10 +74,22 @@ const updateSW = registerSW({
|
||||
},
|
||||
});
|
||||
|
||||
ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
|
||||
<React.StrictMode>
|
||||
<ThemeProvider theme={theme}>
|
||||
function ThemedApp() {
|
||||
const prefStore = usePrefStore()
|
||||
|
||||
useEffect(() => {
|
||||
getDarkMode()
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<ThemeProvider theme={prefStore.darkMode ? darkTheme : lightTheme}>
|
||||
<App />
|
||||
</ThemeProvider>
|
||||
)
|
||||
}
|
||||
|
||||
ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
|
||||
<React.StrictMode>
|
||||
<ThemedApp />
|
||||
</React.StrictMode>,
|
||||
)
|
||||
|
@ -1,14 +1,14 @@
|
||||
import { Autocomplete, Box, Button, CircularProgress, Paper, TextField, Typography } from "@mui/material"
|
||||
import { useBoilers, useCities, useRegions, useServers } from "../hooks/swrHooks"
|
||||
import { Autocomplete, Box, CircularProgress, Paper, TextField, Typography } from "@mui/material"
|
||||
import { useBoilers, useRegions, useServers } from "../hooks/swrHooks"
|
||||
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"
|
||||
|
||||
export default function ApiTest() {
|
||||
const [open, setOpen] = useState(false)
|
||||
const [options, setOptions] = useState<any>([])
|
||||
const [search, setSearch] = useState<any>(null)
|
||||
const [debouncedSearch, setDebouncedSearch] = useState("")
|
||||
const [options, setOptions] = useState<IRegion[]>([])
|
||||
const [search, setSearch] = useState<string | null>(null)
|
||||
const [debouncedSearch, setDebouncedSearch] = useState<string | null>("")
|
||||
const [selectedOption, setSelectedOption] = useState<IRegion | null>(null)
|
||||
const { regions, isLoading } = useRegions(10, 1, debouncedSearch)
|
||||
|
||||
@ -28,15 +28,34 @@ export default function ApiTest() {
|
||||
}
|
||||
}, [regions])
|
||||
|
||||
const handleInputChange = (event: any, value: any) => {
|
||||
const handleInputChange = (value: string) => {
|
||||
setSearch(value)
|
||||
}
|
||||
|
||||
const handleOptionChange = (event: any, value: any) => {
|
||||
const handleOptionChange = (value: IRegion | null) => {
|
||||
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 { servers, isLoading: serversLoading } = useServers(selectedOption?.id, 0, 10)
|
||||
|
||||
@ -45,12 +64,20 @@ export default function ApiTest() {
|
||||
{ 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 (
|
||||
<Box sx={{ display: 'flex', flexDirection: 'column', gap: '16px', height: '100%' }}>
|
||||
<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'>
|
||||
Get servers
|
||||
Servers
|
||||
</Typography>
|
||||
|
||||
<Autocomplete
|
||||
@ -61,11 +88,11 @@ export default function ApiTest() {
|
||||
onClose={() => {
|
||||
setOpen(false)
|
||||
}}
|
||||
onInputChange={handleInputChange}
|
||||
onChange={handleOptionChange}
|
||||
onInputChange={(_, value) => handleInputChange(value)}
|
||||
onChange={(_, value) => handleOptionChange(value)}
|
||||
filterOptions={(x) => x}
|
||||
isOptionEqualToValue={(option: any, value: any) => option.name === value.name}
|
||||
getOptionLabel={(option: any) => option.name ? option.name : ""}
|
||||
isOptionEqualToValue={(option: IRegion, value: IRegion) => option.name === value.name}
|
||||
getOptionLabel={(option: IRegion) => option.name ? option.name : ""}
|
||||
options={options}
|
||||
loading={isLoading}
|
||||
value={selectedOption}
|
||||
@ -98,6 +125,24 @@ export default function ApiTest() {
|
||||
}
|
||||
</Box>
|
||||
</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>
|
||||
)
|
||||
}
|
@ -1,37 +1,6 @@
|
||||
import { GridColDef } from '@mui/x-data-grid'
|
||||
import FolderViewer from '../components/FolderViewer'
|
||||
|
||||
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 (
|
||||
<div>
|
||||
<FolderViewer />
|
||||
|
@ -1,6 +1,5 @@
|
||||
import { Error } from "@mui/icons-material";
|
||||
import { Box, Typography, colors } from "@mui/material";
|
||||
import { red } from "@mui/material/colors";
|
||||
import { Box, Typography } from "@mui/material";
|
||||
|
||||
export default function NotFound() {
|
||||
return (
|
||||
|
@ -1,18 +1,15 @@
|
||||
import { useEffect, useState } from "react"
|
||||
import { Box, Button, Typography } from "@mui/material"
|
||||
import { useState } from "react"
|
||||
import { Box, Button } from "@mui/material"
|
||||
import axiosInstance from "../http/axiosInstance"
|
||||
import { DataGrid } from "@mui/x-data-grid"
|
||||
|
||||
export default function Reports() {
|
||||
const [state, setState] = useState<any>(null)
|
||||
const [exportData, setExportData] = useState<any>(null)
|
||||
const [state, setState] = useState(null)
|
||||
|
||||
const fetch = async () => {
|
||||
await axiosInstance.get(`/info/reports/0?to_export=true`, {
|
||||
responseType: 'blob',
|
||||
}).then(response => {
|
||||
setExportData(response.data)
|
||||
|
||||
const url = window.URL.createObjectURL(response.data)
|
||||
const link = document.createElement('a')
|
||||
link.href = url
|
||||
@ -71,7 +68,7 @@ export default function Reports() {
|
||||
disableRowSelectionOnClick
|
||||
|
||||
processRowUpdate={(updatedRow, originalRow) => {
|
||||
console.log(updatedRow)
|
||||
console.log(updatedRow, originalRow)
|
||||
return updatedRow
|
||||
}}
|
||||
|
||||
|
@ -49,7 +49,7 @@ export default function Roles() {
|
||||
disableRowSelectionOnClick
|
||||
|
||||
processRowUpdate={(updatedRow, originalRow) => {
|
||||
console.log(updatedRow)
|
||||
console.log(updatedRow, originalRow)
|
||||
return updatedRow
|
||||
}}
|
||||
|
||||
|
@ -23,7 +23,7 @@ export default function Settings() {
|
||||
{
|
||||
field: 'role_id',
|
||||
headerName: 'Роль',
|
||||
valueGetter: (value, row) => {
|
||||
valueGetter: (value) => {
|
||||
if (roles) {
|
||||
const roleName = roles.find((role: IRole) => role.id === value).name
|
||||
return roleName
|
||||
@ -70,7 +70,7 @@ export default function Settings() {
|
||||
disableRowSelectionOnClick
|
||||
|
||||
processRowUpdate={(updatedRow, originalRow) => {
|
||||
console.log(updatedRow)
|
||||
console.log(updatedRow, originalRow)
|
||||
return updatedRow
|
||||
}}
|
||||
|
||||
|
@ -65,7 +65,7 @@ export default function Users() {
|
||||
disableRowSelectionOnClick
|
||||
|
||||
processRowUpdate={(updatedRow, originalRow) => {
|
||||
console.log(updatedRow)
|
||||
console.log(updatedRow, originalRow)
|
||||
return updatedRow
|
||||
}}
|
||||
|
||||
|
@ -10,7 +10,7 @@ const config: AxiosRequestConfig = {
|
||||
}
|
||||
|
||||
export default class AuthService {
|
||||
static async login(data: any) {
|
||||
static async login(data: FormData) {
|
||||
return await axiosInstance.post(`/auth/login`, data, config)
|
||||
}
|
||||
|
||||
|
@ -100,11 +100,11 @@ export default class DocumentService {
|
||||
}
|
||||
|
||||
// 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, {
|
||||
onUploadProgress: (progressEvent: AxiosProgressEvent) => {
|
||||
const percentCompleted = progressEvent.progress
|
||||
setUploadProgress?.(percentCompleted)
|
||||
setUploadProgress?.(percentCompleted || 0)
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -127,7 +127,7 @@ export default class DocumentService {
|
||||
}
|
||||
|
||||
// Convert Phones
|
||||
static async convertPhones(data: any) {
|
||||
static async convertPhones(data: FormData) {
|
||||
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 { IHardware, IServer, IServerIP, IStorage } from "../interfaces/servers";
|
||||
import { BASE_URL } from "../constants";
|
||||
|
@ -2,13 +2,14 @@ import { AxiosRequestConfig } from "axios";
|
||||
import axiosInstance from "../http/axiosInstance";
|
||||
import { UserCreds, UserData } from "../interfaces/auth";
|
||||
import { BASE_URL } from "../constants";
|
||||
import { IUserCreate } from "../interfaces/user";
|
||||
|
||||
const config: AxiosRequestConfig = {
|
||||
baseURL: BASE_URL.auth
|
||||
}
|
||||
|
||||
export default class UserService {
|
||||
static async createUser(data: any) {
|
||||
static async createUser(data: IUserCreate) {
|
||||
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 AuthService from '../services/AuthService';
|
||||
|
||||
export const useAuthStore = create<AuthState>((set, get) => ({
|
||||
export const useAuthStore = create<AuthState>(() => ({
|
||||
isAuthenticated: false,
|
||||
token: null,
|
||||
userData: {},
|
||||
userData: null,
|
||||
}));
|
||||
|
||||
const login = (token: string) => {
|
||||
@ -20,7 +20,7 @@ const logout = () => {
|
||||
localStorage.removeItem(TOKEN_AUTH_KEY);
|
||||
localStorage.removeItem(USER_DATA_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 () => {
|
||||
|
@ -1,12 +1,13 @@
|
||||
import { create } from 'zustand';
|
||||
import { PreferencesState } from '../interfaces/preferences';
|
||||
|
||||
export const usePrefStore = create<PreferencesState>((set, get) => ({
|
||||
export const usePrefStore = create<PreferencesState>(() => ({
|
||||
darkMode: false
|
||||
}));
|
||||
|
||||
const getDarkMode = () => {
|
||||
const darkMode = localStorage.getItem('darkMode')
|
||||
usePrefStore.setState(() => ({ darkMode: darkMode?.toLowerCase() === "true" ? true : false }))
|
||||
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"
|
||||
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:
|
||||
version "4.5.2"
|
||||
resolved "https://registry.npmjs.org/zustand/-/zustand-4.5.2.tgz"
|
||||
|
Reference in New Issue
Block a user