forked from VinokurovVE/tests
Testing: fetch servers by region
This commit is contained in:
6
frontend_reactjs/package-lock.json
generated
6
frontend_reactjs/package-lock.json
generated
@ -11,6 +11,7 @@
|
|||||||
"-": "^0.0.1",
|
"-": "^0.0.1",
|
||||||
"@emotion/react": "^11.11.4",
|
"@emotion/react": "^11.11.4",
|
||||||
"@emotion/styled": "^11.11.5",
|
"@emotion/styled": "^11.11.5",
|
||||||
|
"@fontsource/inter": "^5.0.19",
|
||||||
"@fontsource/open-sans": "^5.0.28",
|
"@fontsource/open-sans": "^5.0.28",
|
||||||
"@js-preview/docx": "^1.6.2",
|
"@js-preview/docx": "^1.6.2",
|
||||||
"@js-preview/excel": "^1.7.8",
|
"@js-preview/excel": "^1.7.8",
|
||||||
@ -2495,6 +2496,11 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.2.tgz",
|
"resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.2.tgz",
|
||||||
"integrity": "sha512-J4yDIIthosAsRZ5CPYP/jQvUAQtlZTTD/4suA08/FEnlxqW3sKS9iAhgsa9VYLZ6vDHn/ixJgIqRQPotoBjxIw=="
|
"integrity": "sha512-J4yDIIthosAsRZ5CPYP/jQvUAQtlZTTD/4suA08/FEnlxqW3sKS9iAhgsa9VYLZ6vDHn/ixJgIqRQPotoBjxIw=="
|
||||||
},
|
},
|
||||||
|
"node_modules/@fontsource/inter": {
|
||||||
|
"version": "5.0.19",
|
||||||
|
"resolved": "https://registry.npmjs.org/@fontsource/inter/-/inter-5.0.19.tgz",
|
||||||
|
"integrity": "sha512-tVU77yjKnsoUotrXGYbbYxmL9nbm/MSo3deZietmf8V2FEDlbi9fvkJHMrYbo7ZsOqR1AYBBqRYmemz4pSE5Mg=="
|
||||||
|
},
|
||||||
"node_modules/@fontsource/open-sans": {
|
"node_modules/@fontsource/open-sans": {
|
||||||
"version": "5.0.28",
|
"version": "5.0.28",
|
||||||
"resolved": "https://registry.npmjs.org/@fontsource/open-sans/-/open-sans-5.0.28.tgz",
|
"resolved": "https://registry.npmjs.org/@fontsource/open-sans/-/open-sans-5.0.28.tgz",
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
"-": "^0.0.1",
|
"-": "^0.0.1",
|
||||||
"@emotion/react": "^11.11.4",
|
"@emotion/react": "^11.11.4",
|
||||||
"@emotion/styled": "^11.11.5",
|
"@emotion/styled": "^11.11.5",
|
||||||
|
"@fontsource/inter": "^5.0.19",
|
||||||
"@fontsource/open-sans": "^5.0.28",
|
"@fontsource/open-sans": "^5.0.28",
|
||||||
"@js-preview/docx": "^1.6.2",
|
"@js-preview/docx": "^1.6.2",
|
||||||
"@js-preview/excel": "^1.7.8",
|
"@js-preview/excel": "^1.7.8",
|
||||||
|
@ -10,8 +10,42 @@ 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 } from '../store/auth';
|
import { logout, useAuthStore } from '../store/auth';
|
||||||
import { ListItem } from '@mui/material';
|
import { ListItem, Switch, styled } from '@mui/material';
|
||||||
|
import { setDarkMode, usePrefStore } from '../store/preferences';
|
||||||
|
|
||||||
|
const Android12Switch = styled(Switch)(({ theme }) => ({
|
||||||
|
padding: 8,
|
||||||
|
'& .MuiSwitch-track': {
|
||||||
|
borderRadius: 22 / 2,
|
||||||
|
'&::before, &::after': {
|
||||||
|
content: '""',
|
||||||
|
position: 'absolute',
|
||||||
|
top: '50%',
|
||||||
|
transform: 'translateY(-50%)',
|
||||||
|
width: 16,
|
||||||
|
height: 16,
|
||||||
|
},
|
||||||
|
'&::before': {
|
||||||
|
backgroundImage: `url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="16" width="16" viewBox="0 0 24 24"><path fill="${encodeURIComponent(
|
||||||
|
theme.palette.getContrastText(theme.palette.primary.main),
|
||||||
|
)}" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"/></svg>')`,
|
||||||
|
left: 12,
|
||||||
|
},
|
||||||
|
'&::after': {
|
||||||
|
backgroundImage: `url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="16" width="16" viewBox="0 0 24 24"><path fill="${encodeURIComponent(
|
||||||
|
theme.palette.getContrastText(theme.palette.primary.main),
|
||||||
|
)}" d="M19,13H5V11H19V13Z" /></svg>')`,
|
||||||
|
right: 12,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'& .MuiSwitch-thumb': {
|
||||||
|
boxShadow: 'none',
|
||||||
|
width: 16,
|
||||||
|
height: 16,
|
||||||
|
margin: 2,
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
export default function AccountMenu() {
|
export default function AccountMenu() {
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
@ -26,6 +60,9 @@ export default function AccountMenu() {
|
|||||||
const handleClose = () => {
|
const handleClose = () => {
|
||||||
setAnchorEl(null);
|
setAnchorEl(null);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const prefStore = usePrefStore()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<Box sx={{ display: 'flex', alignItems: 'center', textAlign: 'center' }}>
|
<Box sx={{ display: 'flex', alignItems: 'center', textAlign: 'center' }}>
|
||||||
@ -47,7 +84,6 @@ export default function AccountMenu() {
|
|||||||
id="account-menu"
|
id="account-menu"
|
||||||
open={open}
|
open={open}
|
||||||
onClose={handleClose}
|
onClose={handleClose}
|
||||||
onClick={handleClose}
|
|
||||||
PaperProps={{
|
PaperProps={{
|
||||||
elevation: 0,
|
elevation: 0,
|
||||||
sx: {
|
sx: {
|
||||||
@ -77,12 +113,25 @@ export default function AccountMenu() {
|
|||||||
transformOrigin={{ horizontal: 'right', vertical: 'top' }}
|
transformOrigin={{ horizontal: 'right', vertical: 'top' }}
|
||||||
anchorOrigin={{ horizontal: 'right', vertical: 'bottom' }}
|
anchorOrigin={{ horizontal: 'right', vertical: 'bottom' }}
|
||||||
>
|
>
|
||||||
|
<MenuItem onClick={() => {
|
||||||
|
console.log()
|
||||||
|
}}>
|
||||||
|
<Android12Switch
|
||||||
|
defaultChecked={prefStore.darkMode}
|
||||||
|
onChange={(e) => {
|
||||||
|
setDarkMode(e.target.checked)
|
||||||
|
}} />
|
||||||
|
Тема
|
||||||
|
</MenuItem>
|
||||||
|
|
||||||
|
|
||||||
<MenuItem onClick={handleClose}>
|
<MenuItem onClick={handleClose}>
|
||||||
<ListItemIcon>
|
<ListItemIcon>
|
||||||
<Settings fontSize="small" />
|
<Settings fontSize="small" />
|
||||||
</ListItemIcon>
|
</ListItemIcon>
|
||||||
Настройки
|
Настройки
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
|
|
||||||
<MenuItem
|
<MenuItem
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
logout()
|
logout()
|
||||||
|
@ -116,12 +116,12 @@ export function useReport(city_id?: number) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// API general
|
// API general (fuel)
|
||||||
|
|
||||||
export function useAddress(limit?: number, page?: number) {
|
export function useAddress(limit?: number, page?: number) {
|
||||||
const { data, error, isLoading } = useSWR(
|
const { data, error, isLoading } = useSWR(
|
||||||
`/general/address?limit=${limit || 10}&page=${page || 1}`,
|
`/general/address?limit=${limit || 10}&page=${page || 1}`,
|
||||||
(url) => fetcher(url, import.meta.env.VITE_API_FUEL_URL),
|
(url) => fetcher(url, BASE_URL.fuel),
|
||||||
{
|
{
|
||||||
revalidateOnFocus: false
|
revalidateOnFocus: false
|
||||||
}
|
}
|
||||||
@ -134,9 +134,41 @@ export function useAddress(limit?: number, page?: number) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function useRegions(limit?: number, page?: number, search?: string) {
|
||||||
|
const { data, error, isLoading } = useSWR(
|
||||||
|
`/general/regions?limit=${limit || 10}&page=${page || 1}${search ? `&search=${search}` : ''}`,
|
||||||
|
(url) => fetcher(url, BASE_URL.fuel),
|
||||||
|
{
|
||||||
|
revalidateOnFocus: false
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
return {
|
||||||
|
regions: data,
|
||||||
|
isLoading,
|
||||||
|
isError: error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useCities(limit?: number, page?: number, search?: string) {
|
||||||
|
const { data, error, isLoading } = useSWR(
|
||||||
|
`/general/cities?limit=${limit || 10}&page=${page || 1}${search ? `&search=${search}` : ''}`,
|
||||||
|
(url) => fetcher(url, BASE_URL.fuel),
|
||||||
|
{
|
||||||
|
revalidateOnFocus: false
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
return {
|
||||||
|
cities: data,
|
||||||
|
isLoading,
|
||||||
|
isError: error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export function useBoilers(limit?: number, page?: number, search?: string) {
|
export function useBoilers(limit?: number, page?: number, search?: string) {
|
||||||
const { data, error, isLoading } = useSWR(
|
const { data, error, isLoading } = useSWR(
|
||||||
`/general/boilers?limit=${limit || 10}&page=${page || 1}&search=${search || ""}`,
|
`/general/boilers?limit=${limit || 10}&page=${page || 1}${search ? `&search=${search}` : ''}`,
|
||||||
(url) => fetcher(url, BASE_URL.fuel),
|
(url) => fetcher(url, BASE_URL.fuel),
|
||||||
{
|
{
|
||||||
revalidateOnFocus: false
|
revalidateOnFocus: false
|
||||||
|
4
frontend_reactjs/src/interfaces/fuel.ts
Normal file
4
frontend_reactjs/src/interfaces/fuel.ts
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
export interface IRegion {
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
}
|
3
frontend_reactjs/src/interfaces/preferences.ts
Normal file
3
frontend_reactjs/src/interfaces/preferences.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export interface PreferencesState {
|
||||||
|
darkMode: boolean;
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
import "@fontsource/open-sans";
|
import "@fontsource/inter";
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import ReactDOM from 'react-dom/client'
|
import ReactDOM from 'react-dom/client'
|
||||||
import App from './App.tsx'
|
import App from './App.tsx'
|
||||||
@ -7,12 +7,13 @@ 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";
|
||||||
|
|
||||||
const theme = createTheme(
|
const theme = createTheme(
|
||||||
{
|
{
|
||||||
typography: {
|
typography: {
|
||||||
fontFamily: [
|
fontFamily: [
|
||||||
'Open Sans'
|
'Inter'
|
||||||
].join(',')
|
].join(',')
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
|
@ -1,21 +1,103 @@
|
|||||||
import { useEffect, useState } from "react"
|
import { Autocomplete, Box, Button, CircularProgress, Paper, TextField, Typography } from "@mui/material"
|
||||||
import { Button, Typography } from "@mui/material"
|
import { useBoilers, useCities, useRegions, useServers } from "../hooks/swrHooks"
|
||||||
import { useServers } from "../hooks/swrHooks"
|
import { Fragment, useEffect, useState } from "react"
|
||||||
|
import { IRegion } from "../interfaces/fuel"
|
||||||
|
import { DataGrid, GridColDef } from "@mui/x-data-grid"
|
||||||
|
|
||||||
export default function ApiTest() {
|
export default function ApiTest() {
|
||||||
const [state, setState] = useState<any>(null)
|
const [open, setOpen] = useState(false)
|
||||||
|
const [options, setOptions] = useState<any>([])
|
||||||
|
const [search, setSearch] = useState<any>(null)
|
||||||
|
const [debouncedSearch, setDebouncedSearch] = useState("")
|
||||||
|
const [selectedOption, setSelectedOption] = useState<IRegion | null>(null)
|
||||||
|
const { regions, isLoading } = useRegions(10, 1, debouncedSearch)
|
||||||
|
|
||||||
const { servers } = useServers(32, 0, 10)
|
useEffect(() => {
|
||||||
|
const handler = setTimeout(() => {
|
||||||
|
setDebouncedSearch(search)
|
||||||
|
}, 500)
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
clearTimeout(handler)
|
||||||
|
}
|
||||||
|
}, [search])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (regions) {
|
||||||
|
setOptions([...regions])
|
||||||
|
}
|
||||||
|
}, [regions])
|
||||||
|
|
||||||
|
const handleInputChange = (event: any, value: any) => {
|
||||||
|
setSearch(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleOptionChange = (event: any, value: any) => {
|
||||||
|
setSelectedOption(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
//const { boilers } = useBoilers(10, 1)
|
||||||
|
//const { cities } = useCities(10, 1)
|
||||||
|
const { servers, isLoading: serversLoading } = useServers(selectedOption?.id, 0, 10)
|
||||||
|
|
||||||
|
const serversColumns: GridColDef[] = [
|
||||||
|
{ field: 'id', headerName: 'ID', type: "number" },
|
||||||
|
{ field: 'name', headerName: 'Название', type: "string" },
|
||||||
|
]
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<Box sx={{ display: 'flex', flexDirection: 'column', gap: '16px', height: '100%' }}>
|
||||||
<Typography>
|
<Paper elevation={1}>
|
||||||
<Button onClick={() => {
|
<Box sx={{ display: 'flex', flexDirection: 'column', gap: '16px', height: '100%', p: '16px'}}>
|
||||||
|
<Typography variant='h6' fontWeight='600'>
|
||||||
}}>
|
Get servers
|
||||||
{servers && JSON.stringify(servers)}
|
|
||||||
</Button>
|
|
||||||
</Typography>
|
</Typography>
|
||||||
</>
|
|
||||||
|
<Autocomplete
|
||||||
|
open={open}
|
||||||
|
onOpen={() => {
|
||||||
|
setOpen(true)
|
||||||
|
}}
|
||||||
|
onClose={() => {
|
||||||
|
setOpen(false)
|
||||||
|
}}
|
||||||
|
onInputChange={handleInputChange}
|
||||||
|
onChange={handleOptionChange}
|
||||||
|
filterOptions={(x) => x}
|
||||||
|
isOptionEqualToValue={(option: any, value: any) => option.name === value.name}
|
||||||
|
getOptionLabel={(option: any) => option.name ? option.name : ""}
|
||||||
|
options={options}
|
||||||
|
loading={isLoading}
|
||||||
|
value={selectedOption}
|
||||||
|
renderInput={(params) => (
|
||||||
|
<TextField
|
||||||
|
{...params}
|
||||||
|
label="Район"
|
||||||
|
InputProps={{
|
||||||
|
...params.InputProps,
|
||||||
|
endAdornment: (
|
||||||
|
<Fragment>
|
||||||
|
{isLoading ? <CircularProgress color="inherit" size={20} /> : null}
|
||||||
|
{params.InputProps.endAdornment}
|
||||||
|
</Fragment>
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{serversLoading ?
|
||||||
|
<CircularProgress />
|
||||||
|
:
|
||||||
|
servers &&
|
||||||
|
<DataGrid
|
||||||
|
rowSelection={false}
|
||||||
|
rows={servers}
|
||||||
|
columns={serversColumns}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
</Box>
|
||||||
|
</Paper>
|
||||||
|
</Box>
|
||||||
)
|
)
|
||||||
}
|
}
|
@ -79,5 +79,5 @@ export {
|
|||||||
refreshToken,
|
refreshToken,
|
||||||
initAuth,
|
initAuth,
|
||||||
login,
|
login,
|
||||||
logout
|
logout,
|
||||||
}
|
}
|
21
frontend_reactjs/src/store/preferences.ts
Normal file
21
frontend_reactjs/src/store/preferences.ts
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
import { create } from 'zustand';
|
||||||
|
import { PreferencesState } from '../interfaces/preferences';
|
||||||
|
|
||||||
|
export const usePrefStore = create<PreferencesState>((set, get) => ({
|
||||||
|
darkMode: false
|
||||||
|
}));
|
||||||
|
|
||||||
|
const getDarkMode = () => {
|
||||||
|
const darkMode = localStorage.getItem('darkMode')
|
||||||
|
return darkMode
|
||||||
|
}
|
||||||
|
|
||||||
|
const setDarkMode = (darkMode: boolean) => {
|
||||||
|
localStorage.setItem('darkMode', JSON.stringify(darkMode))
|
||||||
|
usePrefStore.setState(() => ({ darkMode: darkMode }))
|
||||||
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
getDarkMode,
|
||||||
|
setDarkMode
|
||||||
|
}
|
@ -1148,6 +1148,11 @@
|
|||||||
resolved "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.2.tgz"
|
resolved "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.2.tgz"
|
||||||
integrity sha512-J4yDIIthosAsRZ5CPYP/jQvUAQtlZTTD/4suA08/FEnlxqW3sKS9iAhgsa9VYLZ6vDHn/ixJgIqRQPotoBjxIw==
|
integrity sha512-J4yDIIthosAsRZ5CPYP/jQvUAQtlZTTD/4suA08/FEnlxqW3sKS9iAhgsa9VYLZ6vDHn/ixJgIqRQPotoBjxIw==
|
||||||
|
|
||||||
|
"@fontsource/inter@^5.0.19":
|
||||||
|
version "5.0.19"
|
||||||
|
resolved "https://registry.npmjs.org/@fontsource/inter/-/inter-5.0.19.tgz"
|
||||||
|
integrity sha512-tVU77yjKnsoUotrXGYbbYxmL9nbm/MSo3deZietmf8V2FEDlbi9fvkJHMrYbo7ZsOqR1AYBBqRYmemz4pSE5Mg==
|
||||||
|
|
||||||
"@fontsource/open-sans@^5.0.28":
|
"@fontsource/open-sans@^5.0.28":
|
||||||
version "5.0.28"
|
version "5.0.28"
|
||||||
resolved "https://registry.npmjs.org/@fontsource/open-sans/-/open-sans-5.0.28.tgz"
|
resolved "https://registry.npmjs.org/@fontsource/open-sans/-/open-sans-5.0.28.tgz"
|
||||||
|
Reference in New Issue
Block a user