upgrade show
for /route
route
This commit is contained in:
@ -1,19 +1,196 @@
|
|||||||
import {Stack, Typography} from '@mui/material'
|
import {Stack, Typography, Box, Grid2 as Grid, Button, MenuItem, Select, FormControl, InputLabel} from '@mui/material'
|
||||||
import {useShow} from '@refinedev/core'
|
import {useShow} from '@refinedev/core'
|
||||||
import {Show, TextFieldComponent as TextField} from '@refinedev/mui'
|
import {Show, TextFieldComponent as TextField} from '@refinedev/mui'
|
||||||
|
import {useEffect, useState} from 'react'
|
||||||
|
import axios from 'axios'
|
||||||
|
import {BACKEND_URL, VEHICLE_TYPES} from '../../lib/constants'
|
||||||
|
|
||||||
|
type StationItem = {
|
||||||
|
id: number
|
||||||
|
name: string
|
||||||
|
description: string
|
||||||
|
[key: string]: string | number
|
||||||
|
}
|
||||||
|
|
||||||
|
type VehicleItem = {
|
||||||
|
id: number
|
||||||
|
tail_number: number
|
||||||
|
type: number
|
||||||
|
[key: string]: string | number
|
||||||
|
}
|
||||||
|
|
||||||
export const RouteShow = () => {
|
export const RouteShow = () => {
|
||||||
const {query} = useShow({})
|
const {query} = useShow({})
|
||||||
const {data, isLoading} = query
|
const {data, isLoading} = query
|
||||||
|
|
||||||
const record = data?.data
|
const record = data?.data
|
||||||
|
|
||||||
|
// Station states
|
||||||
|
const [stations, setStations] = useState<StationItem[]>([])
|
||||||
|
const [linkedStations, setLinkedStations] = useState<StationItem[]>([])
|
||||||
|
const [selectedStationId, setSelectedStationId] = useState<number | ''>('')
|
||||||
|
const [stationsLoading, setStationsLoading] = useState<boolean>(true)
|
||||||
|
|
||||||
|
// Vehicle states
|
||||||
|
const [vehicles, setVehicles] = useState<VehicleItem[]>([])
|
||||||
|
const [linkedVehicles, setLinkedVehicles] = useState<VehicleItem[]>([])
|
||||||
|
const [selectedVehicleId, setSelectedVehicleId] = useState<number | ''>('')
|
||||||
|
const [vehiclesLoading, setVehiclesLoading] = useState<boolean>(true)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (record?.id) {
|
||||||
|
axios
|
||||||
|
.get(`${BACKEND_URL}/route/${record.id}/station`)
|
||||||
|
.then((response) => {
|
||||||
|
setLinkedStations(response?.data || [])
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
setLinkedStations([])
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}, [record?.id])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
axios
|
||||||
|
.get(`${BACKEND_URL}/station/`)
|
||||||
|
.then((response) => {
|
||||||
|
setStations(response?.data || [])
|
||||||
|
setStationsLoading(false)
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
setStations([])
|
||||||
|
setStationsLoading(false)
|
||||||
|
})
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const availableStations = stations.filter((station) => !linkedStations.some((linked) => linked.id === station.id))
|
||||||
|
|
||||||
|
const linkStation = () => {
|
||||||
|
if (selectedStationId) {
|
||||||
|
axios
|
||||||
|
.post(
|
||||||
|
`${BACKEND_URL}/route/${record?.id}/station`,
|
||||||
|
{station_id: selectedStationId},
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
accept: 'application/json',
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.then(() => {
|
||||||
|
axios
|
||||||
|
.get(`${BACKEND_URL}/route/${record?.id}/station`)
|
||||||
|
.then((response) => {
|
||||||
|
setLinkedStations(response?.data || [])
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
setLinkedStations([])
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error('Error linking station:', error)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const deleteStation = (stationId: number) => {
|
||||||
|
axios
|
||||||
|
.delete(`${BACKEND_URL}/route/${record?.id}/station`, {
|
||||||
|
data: {station_id: stationId},
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
setLinkedStations((prevStations) => prevStations.filter((item) => item.id !== stationId))
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error('Error deleting station:', error)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Vehicle effects
|
||||||
|
useEffect(() => {
|
||||||
|
if (record?.id) {
|
||||||
|
axios
|
||||||
|
.get(`${BACKEND_URL}/route/${record.id}/vehicle`)
|
||||||
|
.then((response) => {
|
||||||
|
setLinkedVehicles(response?.data || [])
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
setLinkedVehicles([])
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}, [record?.id])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
axios
|
||||||
|
.get(`${BACKEND_URL}/vehicle/`)
|
||||||
|
.then((response) => {
|
||||||
|
setVehicles(response?.data || [])
|
||||||
|
setVehiclesLoading(false)
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
setVehicles([])
|
||||||
|
setVehiclesLoading(false)
|
||||||
|
})
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const availableVehicles = vehicles.filter((vehicle) => !linkedVehicles.some((linked) => linked.id === vehicle.id))
|
||||||
|
|
||||||
|
const linkVehicle = () => {
|
||||||
|
if (selectedVehicleId) {
|
||||||
|
axios
|
||||||
|
.post(
|
||||||
|
`${BACKEND_URL}/route/${record?.id}/vehicle`,
|
||||||
|
{vehicle_id: selectedVehicleId},
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
accept: 'application/json',
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.then(() => {
|
||||||
|
axios
|
||||||
|
.get(`${BACKEND_URL}/route/${record?.id}/vehicle`)
|
||||||
|
.then((response) => {
|
||||||
|
setLinkedVehicles(response?.data || [])
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
setLinkedVehicles([])
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error('Error linking vehicle:', error)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const deleteVehicle = (vehicleId: number) => {
|
||||||
|
axios
|
||||||
|
.delete(`${BACKEND_URL}/route/${record?.id}/vehicle`, {
|
||||||
|
data: {vehicle_id: vehicleId},
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
setLinkedVehicles((prevVehicles) => prevVehicles.filter((item) => item.id !== vehicleId))
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error('Error deleting vehicle:', error)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
const fields = [
|
const fields = [
|
||||||
// {label: 'ID', data: 'id'},
|
|
||||||
// {label: 'ID перевозчика', data: 'carrier_id'},
|
|
||||||
{label: 'Перевозчик', data: 'carrier'},
|
{label: 'Перевозчик', data: 'carrier'},
|
||||||
{label: 'Номер маршрута', data: 'route_number'},
|
{label: 'Номер маршрута', data: 'route_number'},
|
||||||
{label: 'Путь', data: 'path'}, // #
|
{label: 'Путь', data: 'path'},
|
||||||
|
]
|
||||||
|
|
||||||
|
const stationFields: Array<{label: string; data: keyof StationItem}> = [
|
||||||
|
{label: 'Название', data: 'name'},
|
||||||
|
{label: 'Описание', data: 'description'},
|
||||||
|
]
|
||||||
|
|
||||||
|
const vehicleFields: Array<{label: string; data: keyof VehicleItem}> = [
|
||||||
|
{label: 'Бортовой номер', data: 'tail_number'},
|
||||||
|
{label: 'Тип', data: 'type'},
|
||||||
]
|
]
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -28,11 +205,122 @@ export const RouteShow = () => {
|
|||||||
</Stack>
|
</Stack>
|
||||||
))}
|
))}
|
||||||
|
|
||||||
<Stack gap={1}>
|
<Stack gap={2}>
|
||||||
<Typography variant="body1" fontWeight="bold">
|
<Typography variant="body1" fontWeight="bold">
|
||||||
Направление маршрута
|
Привязанные станции
|
||||||
</Typography>
|
</Typography>
|
||||||
<TextField style={{color: record?.route_direction ? '#48989f' : '#7f6b58'}} value={record?.route_direction ? 'прямое' : 'обратное'} />
|
|
||||||
|
<Grid container gap={2}>
|
||||||
|
{stationsLoading ? (
|
||||||
|
<Typography>Загрузка станций...</Typography>
|
||||||
|
) : linkedStations.length > 0 ? (
|
||||||
|
linkedStations.map((station, index) => (
|
||||||
|
<Box
|
||||||
|
key={index}
|
||||||
|
sx={{
|
||||||
|
marginBottom: '8px',
|
||||||
|
padding: '14px',
|
||||||
|
borderRadius: 2,
|
||||||
|
border: (theme) => `2px solid ${theme.palette.divider}`,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Stack gap={0.5}>
|
||||||
|
{stationFields.map(({label, data}) => (
|
||||||
|
<Typography key={data}>
|
||||||
|
<strong>{label}:</strong> {station[data]}
|
||||||
|
</Typography>
|
||||||
|
))}
|
||||||
|
|
||||||
|
<Button variant="outlined" color="error" onClick={() => deleteStation(station?.id)} sx={{mt: 1.5}}>
|
||||||
|
Отвязать
|
||||||
|
</Button>
|
||||||
|
</Stack>
|
||||||
|
</Box>
|
||||||
|
))
|
||||||
|
) : (
|
||||||
|
<Typography>Станции не найдены</Typography>
|
||||||
|
)}
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<Stack gap={2}>
|
||||||
|
<Typography variant="body1" fontWeight="bold">
|
||||||
|
Привязать станцию
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
<FormControl fullWidth>
|
||||||
|
<InputLabel>Станция</InputLabel>
|
||||||
|
<Select value={selectedStationId} onChange={(e) => setSelectedStationId(Number(e.target.value))} label="Станция" fullWidth>
|
||||||
|
{availableStations.map((station) => (
|
||||||
|
<MenuItem key={station.id} value={station.id}>
|
||||||
|
{station.name}
|
||||||
|
</MenuItem>
|
||||||
|
))}
|
||||||
|
</Select>
|
||||||
|
</FormControl>
|
||||||
|
|
||||||
|
<Button variant="contained" onClick={linkStation} disabled={!selectedStationId}>
|
||||||
|
Привязать
|
||||||
|
</Button>
|
||||||
|
</Stack>
|
||||||
|
</Stack>
|
||||||
|
|
||||||
|
<Stack gap={2}>
|
||||||
|
<Typography variant="body1" fontWeight="bold">
|
||||||
|
Привязанные транспортные средства
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
<Grid container gap={2}>
|
||||||
|
{vehiclesLoading ? (
|
||||||
|
<Typography>Загрузка транспорта...</Typography>
|
||||||
|
) : linkedVehicles.length > 0 ? (
|
||||||
|
linkedVehicles.map((vehicle, index) => (
|
||||||
|
<Box
|
||||||
|
key={index}
|
||||||
|
sx={{
|
||||||
|
marginBottom: '8px',
|
||||||
|
padding: '14px',
|
||||||
|
borderRadius: 2,
|
||||||
|
border: (theme) => `2px solid ${theme.palette.divider}`,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Stack gap={0.5}>
|
||||||
|
{vehicleFields.map(({label, data}) => (
|
||||||
|
<Typography key={data}>
|
||||||
|
<strong>{label}:</strong> {vehicle[data]}
|
||||||
|
</Typography>
|
||||||
|
))}
|
||||||
|
|
||||||
|
<Button variant="outlined" color="error" onClick={() => deleteVehicle(vehicle?.id)} sx={{mt: 1.5}}>
|
||||||
|
Отвязать
|
||||||
|
</Button>
|
||||||
|
</Stack>
|
||||||
|
</Box>
|
||||||
|
))
|
||||||
|
) : (
|
||||||
|
<Typography>Транспортные средства не найдены</Typography>
|
||||||
|
)}
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<Stack gap={2}>
|
||||||
|
<Typography variant="body1" fontWeight="bold">
|
||||||
|
Привязать транспортное средство
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
<FormControl fullWidth>
|
||||||
|
<InputLabel>Транспортное средство</InputLabel>
|
||||||
|
<Select value={selectedVehicleId} onChange={(e) => setSelectedVehicleId(Number(e.target.value))} label="Транспортное средство" fullWidth>
|
||||||
|
{availableVehicles.map((vehicle) => (
|
||||||
|
<MenuItem key={vehicle.id} value={vehicle.id}>
|
||||||
|
{`${vehicle.tail_number} (${VEHICLE_TYPES.find((type) => type.value === vehicle.type)?.label || vehicle.type})`}
|
||||||
|
</MenuItem>
|
||||||
|
))}
|
||||||
|
</Select>
|
||||||
|
</FormControl>
|
||||||
|
|
||||||
|
<Button variant="contained" onClick={linkVehicle} disabled={!selectedVehicleId}>
|
||||||
|
Привязать
|
||||||
|
</Button>
|
||||||
|
</Stack>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Show>
|
</Show>
|
||||||
|
Reference in New Issue
Block a user