fuel; nest api
This commit is contained in:
@ -1,49 +1,117 @@
|
||||
import { useEffect, useState } from 'react'
|
||||
import { Combobox, CompoundButton, Option, Text } from '@fluentui/react-components'
|
||||
import { Dropdown, Option, Spinner } from '@fluentui/react-components'
|
||||
import useSWR from 'swr'
|
||||
import axios from 'axios'
|
||||
import { AgGridReact, CustomCellRendererProps } from 'ag-grid-react'
|
||||
import { AllCommunityModule, ModuleRegistry } from 'ag-grid-community'
|
||||
import FuelRenderer from './FuelRenderer'
|
||||
import { useSearchParams } from 'react-router-dom'
|
||||
import { ICity, IRegion } from '../../../interfaces/fuel'
|
||||
import BoilersCard from './BoilersCard'
|
||||
|
||||
ModuleRegistry.registerModules([AllCommunityModule])
|
||||
|
||||
function Boilers() {
|
||||
const [, setBoilersPage] = useState(1)
|
||||
const [boilerSearch, setBoilerSearch] = useState("")
|
||||
const [, setDebouncedBoilerSearch] = useState("")
|
||||
// const { boilers } = useBoilers(10, boilersPage, debouncedBoilerSearch)
|
||||
const [searchParams, setSearchParams] = useSearchParams();
|
||||
|
||||
const { data: regions } = useSWR('/general/regions', () => axios.get('/general/regions', {
|
||||
baseURL: import.meta.env.VITE_API_NEST_URL
|
||||
}).then(res => res.data))
|
||||
const [regionId, setRegionId] = useState<number | undefined>(
|
||||
searchParams.get("region_id") ? Number(searchParams.get("region_id")) : undefined
|
||||
);
|
||||
|
||||
const [regionId, setRegionId] = useState<number | undefined>(undefined)
|
||||
const [cityId, setCityId] = useState<number | undefined>(
|
||||
searchParams.get("city_id") ? Number(searchParams.get("city_id")) : undefined
|
||||
)
|
||||
|
||||
const { data: cities } = useSWR(regionId ? `/general/cities?region_id=${regionId}` : null, () => axios.get(`/general/cities?region_id=${regionId}`, {
|
||||
baseURL: import.meta.env.VITE_API_NEST_URL
|
||||
}).then(res => res.data))
|
||||
// Load regions
|
||||
const { data: regions, isLoading: regionsLoading } = useSWR("/general/regions", () =>
|
||||
axios
|
||||
.get("/general/regions", { baseURL: import.meta.env.VITE_API_NEST_URL })
|
||||
.then((res) => res.data)
|
||||
);
|
||||
|
||||
const [cityId, setCityId] = useState<number | undefined>(undefined)
|
||||
// Load cities when regionId exists
|
||||
const { data: cities, isLoading: citiesLoading } = useSWR(
|
||||
regionId ? `/general/cities?region_id=${regionId}` : null,
|
||||
() =>
|
||||
axios
|
||||
.get(`/general/cities?region_id=${regionId}`, {
|
||||
baseURL: import.meta.env.VITE_API_NEST_URL,
|
||||
})
|
||||
.then((res) => res.data)
|
||||
);
|
||||
|
||||
const { data: boilers, isLoading: boilersLoading } = useSWR(cityId !== undefined ? `/fuel/boilers?city_id=${cityId}&offset=0&limit=100` : null, () => axios.get(`/fuel/boilers?city_id=${cityId}&offset=0&limit=100`, {
|
||||
baseURL: import.meta.env.VITE_API_NEST_URL
|
||||
}).then(res => res.data))
|
||||
// Load boilers when cityId exists
|
||||
const { data: boilers, isLoading: boilersLoading } = useSWR(
|
||||
cityId ? `/fuel/boilers?city_id=${cityId}&offset=0&limit=100` : null,
|
||||
() =>
|
||||
axios
|
||||
.get(`/fuel/boilers?city_id=${cityId}&offset=0&limit=100`, {
|
||||
baseURL: import.meta.env.VITE_API_NEST_URL,
|
||||
})
|
||||
.then((res) => res.data)
|
||||
);
|
||||
|
||||
//
|
||||
// Sync regionId → URL
|
||||
//
|
||||
useEffect(() => {
|
||||
if (!regionId) return;
|
||||
|
||||
setSearchParams((prev) => {
|
||||
const params = new URLSearchParams(prev);
|
||||
params.set("region_id", regionId.toString());
|
||||
params.delete("city_id"); // reset city when region changes
|
||||
return params;
|
||||
});
|
||||
|
||||
}, [regionId]);
|
||||
|
||||
//
|
||||
// Sync cityId → URL
|
||||
//
|
||||
useEffect(() => {
|
||||
if (!cityId) return;
|
||||
|
||||
setSearchParams((prev) => {
|
||||
const params = new URLSearchParams(prev);
|
||||
params.set("city_id", cityId.toString());
|
||||
return params;
|
||||
});
|
||||
}, [cityId]);
|
||||
|
||||
//
|
||||
// Utility: get display values
|
||||
//
|
||||
const selectedRegion = regions?.find((r: IRegion) => r.id === regionId);
|
||||
const selectedCity = cities?.find((c: ICity) => c.id === cityId);
|
||||
|
||||
useEffect(() => {
|
||||
const handler = setTimeout(() => {
|
||||
setDebouncedBoilerSearch(boilerSearch)
|
||||
}, 500)
|
||||
const paramCityId = searchParams.get("city_id");
|
||||
|
||||
return () => {
|
||||
clearTimeout(handler)
|
||||
if (!paramCityId) return;
|
||||
|
||||
const id = Number(paramCityId);
|
||||
|
||||
// If cityId not yet set OR mismatched with URL
|
||||
if (cities && !cityId && cities.some((c: ICity) => c.id === id)) {
|
||||
setCityId(id);
|
||||
}
|
||||
}, [boilerSearch])
|
||||
}, [cities])
|
||||
|
||||
useEffect(() => {
|
||||
setBoilersPage(1)
|
||||
setBoilerSearch("")
|
||||
}, [])
|
||||
const paramRegionId = searchParams.get("region_id");
|
||||
if (!paramRegionId) return;
|
||||
|
||||
const id = Number(paramRegionId);
|
||||
|
||||
if (regions && !regionId && regions.some((r: IRegion) => r.id === id)) {
|
||||
setRegionId(id);
|
||||
}
|
||||
}, [regions]);
|
||||
|
||||
useEffect(() => {
|
||||
setCityId(undefined); // clear stale value before SWR runs
|
||||
}, [regionId]);
|
||||
|
||||
return (
|
||||
<div style={{
|
||||
@ -58,42 +126,51 @@ function Boilers() {
|
||||
</Portal> */}
|
||||
|
||||
<div style={{ display: 'flex', gap: '1rem' }}>
|
||||
<Combobox
|
||||
placeholder="Выберите регион"
|
||||
clearable
|
||||
onOptionSelect={(_, data) => {
|
||||
if (data.optionValue) {
|
||||
setRegionId(Number(data.optionValue))
|
||||
} else {
|
||||
setCityId(undefined)
|
||||
setRegionId(undefined)
|
||||
}
|
||||
}}
|
||||
>
|
||||
{regions && Array.isArray(regions) && regions.map((option) => (
|
||||
<Option key={option.id} text={option.name} value={option.id}>
|
||||
{option.name}
|
||||
</Option>
|
||||
))}
|
||||
</Combobox>
|
||||
{regionsLoading ?
|
||||
<Spinner />
|
||||
:
|
||||
<Dropdown
|
||||
placeholder='Выберите район'
|
||||
value={selectedRegion?.name ?? ""}
|
||||
selectedOptions={regionId ? [regionId.toString()] : []}
|
||||
onOptionSelect={(_, data) => {
|
||||
if (!data.optionValue) {
|
||||
setRegionId(undefined);
|
||||
return;
|
||||
}
|
||||
setRegionId(Number(data.optionValue));
|
||||
}}
|
||||
>
|
||||
{regions && Array.isArray(regions) && regions.map((option) => (
|
||||
<Option key={`region-${option.id}`} text={option.name} value={option.id}>
|
||||
{option.name}
|
||||
</Option>
|
||||
))}
|
||||
</Dropdown>
|
||||
}
|
||||
|
||||
{cities && <Combobox
|
||||
clearable
|
||||
placeholder="Выберите населенный пункт"
|
||||
onOptionSelect={(_, data) => {
|
||||
if (data.optionValue) {
|
||||
setCityId(Number(data.optionValue))
|
||||
} else {
|
||||
setCityId(undefined)
|
||||
}
|
||||
}}
|
||||
>
|
||||
{cities && Array.isArray(cities) && cities.map((option) => (
|
||||
<Option key={option.id} text={option.name} value={option.id}>
|
||||
{option.name}
|
||||
</Option>
|
||||
))}
|
||||
</Combobox>}
|
||||
{citiesLoading ?
|
||||
<Spinner />
|
||||
:
|
||||
<Dropdown
|
||||
placeholder='Выберите населенный пункт'
|
||||
value={selectedCity?.name ?? ""}
|
||||
selectedOptions={cityId ? [cityId.toString()] : []}
|
||||
onOptionSelect={(_, data) => {
|
||||
if (!data.optionValue) {
|
||||
setCityId(undefined);
|
||||
return;
|
||||
}
|
||||
setCityId(Number(data.optionValue));
|
||||
}}
|
||||
>
|
||||
{cities && Array.isArray(cities) && cities.map((option) => (
|
||||
<Option key={`region-${option.id}`} text={option.name} value={option.id}>
|
||||
{option.name}
|
||||
</Option>
|
||||
))}
|
||||
</Dropdown>
|
||||
}
|
||||
</div>
|
||||
|
||||
<div style={{
|
||||
@ -102,10 +179,6 @@ function Boilers() {
|
||||
flexDirection: 'column',
|
||||
gap: '1rem'
|
||||
}}>
|
||||
<Text size={400} weight='medium'>
|
||||
{cityId && cities && Array.isArray(cities) && cities.find(city => city.id === cityId).name}
|
||||
</Text>
|
||||
|
||||
{cityId &&
|
||||
<div style={{ display: 'flex', width: '100%', gap: '1rem', justifyContent: 'space-between' }}>
|
||||
<BoilersCard title='Всего объектов' value={boilers && Array.isArray(boilers) ? boilers.length.toString() : ''} subtitle='' />
|
||||
@ -119,80 +192,48 @@ function Boilers() {
|
||||
}
|
||||
</div>
|
||||
|
||||
<AgGridReact
|
||||
// rowData={[
|
||||
// Object.keys(table.headers).reduce((obj, key) => ({ ...obj, [key]: 'test1' }), {}),
|
||||
// Object.keys(table.headers).reduce((obj, key) => ({ ...obj, [key]: 'test' }), {})
|
||||
// ]}
|
||||
key={`boilers-${cityId}`}
|
||||
loading={boilersLoading}
|
||||
overlayLoadingTemplate='Загрузка...'
|
||||
overlayNoRowsTemplate='Нет данных'
|
||||
rowData={boilers}
|
||||
columnDefs={[
|
||||
{
|
||||
field: 'boiler_name',
|
||||
headerName: 'Наименование'
|
||||
},
|
||||
{
|
||||
field: 'boiler_code',
|
||||
headerName: 'Идент. код'
|
||||
},
|
||||
{
|
||||
field: 'id_fuels',
|
||||
headerName: 'Вид топлива',
|
||||
//editable: true,
|
||||
//cellEditor: FuelTypeEditor,
|
||||
autoHeight: true,
|
||||
cellRenderer: FuelRenderer,
|
||||
cellStyle: (_) => {
|
||||
return { padding: '1px' }
|
||||
{boilersLoading ?
|
||||
<Spinner />
|
||||
:
|
||||
<AgGridReact
|
||||
key={`boilers-${cityId}`}
|
||||
loading={boilersLoading}
|
||||
overlayLoadingTemplate='Загрузка...'
|
||||
overlayNoRowsTemplate='Нет данных'
|
||||
rowData={boilers}
|
||||
columnDefs={[
|
||||
{
|
||||
field: 'boiler_name',
|
||||
headerName: 'Наименование'
|
||||
},
|
||||
{
|
||||
field: 'boiler_code',
|
||||
headerName: 'Идент. код'
|
||||
},
|
||||
{
|
||||
field: 'id_fuels',
|
||||
headerName: 'Вид топлива',
|
||||
//editable: true,
|
||||
//cellEditor: FuelTypeEditor,
|
||||
autoHeight: true,
|
||||
cellRenderer: FuelRenderer,
|
||||
cellStyle: (_) => {
|
||||
return { padding: '1px' }
|
||||
}
|
||||
//enableCellChangeFlash: true
|
||||
},
|
||||
{
|
||||
field: 'activity',
|
||||
headerName: 'Активный',
|
||||
cellRenderer: (params: CustomCellRendererProps) => (<span>{params.value === true ? 'Да' : 'Нет'}</span>)
|
||||
}
|
||||
//enableCellChangeFlash: true
|
||||
},
|
||||
{
|
||||
field: 'activity',
|
||||
headerName: 'Активный',
|
||||
cellRenderer: (params: CustomCellRendererProps) => (<span>{params.value === true ? 'Да' : 'Нет'}</span>)
|
||||
}
|
||||
]}
|
||||
defaultColDef={{
|
||||
flex: 1,
|
||||
}}
|
||||
/>
|
||||
]}
|
||||
defaultColDef={{
|
||||
flex: 1,
|
||||
}}
|
||||
/>}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const BoilersCard = ({
|
||||
title,
|
||||
value,
|
||||
subtitle,
|
||||
}: {
|
||||
title: string
|
||||
value: string
|
||||
subtitle: string
|
||||
}) => {
|
||||
return (
|
||||
<CompoundButton
|
||||
onClick={() => { }}
|
||||
style={{ display: 'flex', width: '100%', justifyContent: 'flex-start', flexDirection: 'column', gap: '2rem', alignItems: 'flex-start', cursor: 'pointer', userSelect: 'none' }}
|
||||
//icon={icon}
|
||||
>
|
||||
|
||||
<Text weight='bold' size={300}>
|
||||
{title}
|
||||
</Text>
|
||||
|
||||
<Text weight='bold' size={500}>
|
||||
{value}
|
||||
</Text>
|
||||
|
||||
<Text weight='regular' size={200} style={{ color: 'gray' }}>
|
||||
{subtitle}
|
||||
</Text>
|
||||
</CompoundButton>
|
||||
)
|
||||
}
|
||||
|
||||
export default Boilers
|
||||
Reference in New Issue
Block a user