239 lines
8.5 KiB
TypeScript
239 lines
8.5 KiB
TypeScript
import { useEffect, useState } from 'react'
|
||
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 [searchParams, setSearchParams] = useSearchParams();
|
||
|
||
const [regionId, setRegionId] = useState<number | undefined>(
|
||
searchParams.get("region_id") ? Number(searchParams.get("region_id")) : undefined
|
||
);
|
||
|
||
const [cityId, setCityId] = useState<number | undefined>(
|
||
searchParams.get("city_id") ? Number(searchParams.get("city_id")) : undefined
|
||
)
|
||
|
||
// 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)
|
||
);
|
||
|
||
// 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)
|
||
);
|
||
|
||
// 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 paramCityId = searchParams.get("city_id");
|
||
|
||
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);
|
||
}
|
||
}, [cities])
|
||
|
||
useEffect(() => {
|
||
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={{
|
||
display: 'flex',
|
||
flexDirection: 'column',
|
||
padding: '1rem',
|
||
width: '100%',
|
||
gap: '1rem'
|
||
}}>
|
||
{/* <Portal mountNode={document.querySelector('#header-portal')}>
|
||
|
||
</Portal> */}
|
||
|
||
<div style={{ display: 'flex', gap: '1rem' }}>
|
||
{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>
|
||
}
|
||
|
||
{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={{
|
||
display: 'flex',
|
||
width: '100%',
|
||
flexDirection: 'column',
|
||
gap: '1rem'
|
||
}}>
|
||
{cityId &&
|
||
<div style={{ display: 'flex', width: '100%', gap: '1rem', justifyContent: 'space-between' }}>
|
||
<BoilersCard title='Всего объектов' value={boilers && Array.isArray(boilers) ? boilers.length.toString() : ''} subtitle='' />
|
||
|
||
<BoilersCard title='Общий остаток' value={''} subtitle='' />
|
||
|
||
<BoilersCard title='Лимит на сезон' value={''} subtitle='' />
|
||
|
||
<BoilersCard title='Требуют внимания' value={''} subtitle='' />
|
||
</div>
|
||
}
|
||
</div>
|
||
|
||
{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>)
|
||
}
|
||
]}
|
||
defaultColDef={{
|
||
flex: 1,
|
||
}}
|
||
/>}
|
||
</div>
|
||
)
|
||
}
|
||
|
||
export default Boilers |