integrate sight data into /station/show page

This commit is contained in:
maxim 2025-02-14 00:34:26 +03:00
parent bf72f78020
commit 5d3c6fe7f9
3 changed files with 150 additions and 5 deletions

View File

@ -122,7 +122,6 @@ function App() {
create: '/station/create',
edit: '/station/edit/:id',
show: '/station/show/:id',
// добавить SHOW для station->sight (https://wn.krbl.ru/station/2/sight)
meta: {
canDelete: true,
label: 'Остановки',

View File

@ -39,7 +39,7 @@ export const SightShow = () => {
useEffect(() => {
axios
.get(`${BACKEND_URL}/article/`)
.get(`${BACKEND_URL}/article/`) // without "/" throws CORS error
.then((response) => {
setArticles(response?.data || [])
setArticlesLoading(false)

View File

@ -1,13 +1,100 @@
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 {Show, TextFieldComponent as TextField} from '@refinedev/mui'
import {useEffect, useState} from 'react'
import axios from 'axios'
import {BACKEND_URL} from '../../lib/constants'
type SightItem = {
id: number
name: string
latitude: number
longitude: number
city_id: number
}
export const StationShow = () => {
const {query} = useShow({})
const {data, isLoading} = query
const record = data?.data
const [sights, setSights] = useState<SightItem[]>([])
const [linkedSights, setLinkedSights] = useState<SightItem[]>([])
const [selectedSightId, setSelectedSightId] = useState<number | ''>('')
const [sightsLoading, setSightsLoading] = useState<boolean>(true)
useEffect(() => {
if (record?.id) {
axios
.get(`${BACKEND_URL}/station/${record.id}/sight`)
.then((response) => {
setLinkedSights(response?.data || [])
})
.catch(() => {
setLinkedSights([])
})
}
}, [record?.id])
useEffect(() => {
axios
.get(`${BACKEND_URL}/sight/`) // without "/" throws CORS error
.then((response) => {
setSights(response?.data || [])
setSightsLoading(false)
})
.catch(() => {
setSights([])
setSightsLoading(false)
})
}, [])
const availableSights = sights.filter((sight) => !linkedSights.some((linked) => linked.id === sight.id))
const linkSight = () => {
if (selectedSightId) {
axios
.post(
`${BACKEND_URL}/station/${record?.id}/sight`,
{sight_id: selectedSightId},
{
headers: {
accept: 'application/json',
'Content-Type': 'application/json',
},
},
)
.then(() => {
axios
.get(`${BACKEND_URL}/station/${record?.id}/sight`)
.then((response) => {
setLinkedSights(response?.data || [])
})
.catch(() => {
setLinkedSights([])
})
})
.catch((error) => {
console.error('Error linking sight:', error)
})
}
}
const deleteSight = (sightId: number) => {
axios
.delete(`${BACKEND_URL}/station/${record?.id}/sight`, {
data: {sight_id: sightId},
})
.then(() => {
setLinkedSights((prevSights) => prevSights.filter((item) => item.id !== sightId))
})
.catch((error) => {
console.error('Error deleting sight:', error)
})
}
const fields = [
{label: 'ID', data: 'id'},
{label: 'Name', data: 'name'},
@ -16,6 +103,14 @@ export const StationShow = () => {
{label: 'Description', data: 'description'},
]
const sightFields = [
{label: 'ID', data: 'id' as keyof SightItem},
{label: 'Name', data: 'name' as keyof SightItem},
{label: 'Latitude', data: 'latitude' as keyof SightItem},
{label: 'Longitude', data: 'longitude' as keyof SightItem},
{label: 'City ID', data: 'city_id' as keyof SightItem},
]
return (
<Show isLoading={isLoading}>
<Stack gap={4}>
@ -24,9 +119,60 @@ export const StationShow = () => {
<Typography variant="body1" fontWeight="bold">
{label}
</Typography>
<TextField value={record?.[data]} />
<TextField value={record?.[data] || ''} />
</Stack>
))}
<Stack gap={2}>
<Typography variant="body1" fontWeight="bold">
Linked Sights
</Typography>
<Grid container gap={2}>
{sightsLoading ? (
<Typography>Loading sights...</Typography>
) : linkedSights.length > 0 ? (
linkedSights.map((sight, index) => (
<Box key={index} sx={{border: '2px solid #dddddd25', padding: '20px', marginBottom: '8px'}}>
<Stack gap={0.5}>
{sightFields.map(({label, data}) => (
<Typography key={data}>
<strong>{label}:</strong> {sight?.[data]}
</Typography>
))}
<Button variant="outlined" color="error" onClick={() => deleteSight(sight?.id)} sx={{mt: 2}}>
Delete
</Button>
</Stack>
</Box>
))
) : (
<Typography>No sights found</Typography>
)}
</Grid>
<Stack gap={2}>
<Typography variant="body1" fontWeight="bold">
Link Sight
</Typography>
<FormControl fullWidth>
<InputLabel>Sight</InputLabel>
<Select value={selectedSightId} onChange={(e) => setSelectedSightId(Number(e.target.value))} label="Sight" fullWidth>
{availableSights.map((sight) => (
<MenuItem key={sight.id} value={sight.id}>
{sight.name}
</MenuItem>
))}
</Select>
</FormControl>
<Button variant="contained" onClick={linkSight} disabled={!selectedSightId}>
Link Sight
</Button>
</Stack>
</Stack>
</Stack>
</Show>
)