mirror of
https://gitlab.aliens-lyon.fr/encartes/web-interface.git
synced 2026-03-17 22:51:04 +01:00
323 lines
9.0 KiB
JavaScript
323 lines
9.0 KiB
JavaScript
import * as React from 'react';
|
|
|
|
import AppBar from '@mui/material/AppBar';
|
|
import Box from '@mui/material/Box';
|
|
import Button from '@mui/material/Button';
|
|
import Chip from '@mui/material/Chip';
|
|
import CssBaseline from '@mui/material/CssBaseline';
|
|
import Dialog from '@mui/material/Dialog';
|
|
import DialogActions from '@mui/material/DialogActions';
|
|
import DialogContent from '@mui/material/DialogContent';
|
|
import DialogContentText from '@mui/material/DialogContentText';
|
|
import DialogTitle from '@mui/material/DialogTitle';
|
|
import Divider from '@mui/material/Divider';
|
|
import IconButton from '@mui/material/IconButton';
|
|
import MenuItem from '@mui/material/MenuItem';
|
|
import Select from '@mui/material/Select';
|
|
import SettingsBrightnessIcon from '@mui/icons-material/SettingsBrightness';
|
|
import TextField from '@mui/material/TextField';
|
|
import Toolbar from '@mui/material/Toolbar';
|
|
import Typography from '@mui/material/Typography';
|
|
|
|
import { ThemeProvider, createTheme } from '@mui/material/styles';
|
|
|
|
import './App.css'
|
|
|
|
import Map from './Map.js';
|
|
import Rooms from './Rooms.js';
|
|
|
|
function ChangeFloor({ currentFloor, callbackFloorChanged }) {
|
|
const [sites, setSites] = React.useState([]);
|
|
const handleFloorChanged = (event) => {
|
|
callbackFloorChanged(event.target.value);
|
|
};
|
|
|
|
React.useEffect(() => {
|
|
fetch("https://encartes.aliens-lyon.fr/api/map/get_all_floors/")
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
setSites(data);
|
|
|
|
// Display a floor
|
|
callbackFloorChanged(data[0].buildings[0].floors[0].id)
|
|
});
|
|
}, [callbackFloorChanged]);
|
|
|
|
if (currentFloor === undefined) return;
|
|
|
|
var items = [];
|
|
|
|
sites.forEach(site => {
|
|
site.buildings.forEach(building => {
|
|
building.floors.forEach(floor => {
|
|
items.push(
|
|
<MenuItem value={floor.id}>{site.name} / {building.name} / {floor.name}</MenuItem>
|
|
)
|
|
})
|
|
})
|
|
|
|
});
|
|
|
|
return <>
|
|
<div style={{ padding: '24px' }}>
|
|
<Typography component="h2" variant="h5" gutterBottom>
|
|
Changer d'étage
|
|
</Typography>
|
|
<Select
|
|
value={currentFloor}
|
|
label="Étage"
|
|
onChange={handleFloorChanged}
|
|
fullWidth
|
|
>
|
|
{items}
|
|
</Select>
|
|
</div>
|
|
</>
|
|
}
|
|
|
|
function RoomResearch({ callbackRoomSelected }) {
|
|
const [currentRequest, setCurrentRequest] = React.useState("");
|
|
const [rooms, setRooms] = React.useState([]);
|
|
|
|
const startResearch = (event) => {
|
|
fetch("https://encartes.aliens-lyon.fr/api/map/find_place_by_name/" + currentRequest)
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
setRooms(data);
|
|
});
|
|
};
|
|
|
|
return <>
|
|
<div style={{ padding: '24px' }}>
|
|
<Typography component="h2" variant="h5" gutterBottom>
|
|
Rechercher une salle
|
|
</Typography>
|
|
<TextField
|
|
label="Nom, code, occupants, ..."
|
|
value={currentRequest}
|
|
onChange={(event) => { setCurrentRequest(event.target.value) }}
|
|
variant="outlined"
|
|
fullWidth
|
|
/>
|
|
<Box
|
|
marginTop={1}
|
|
display="flex"
|
|
justifyContent="flex-end"
|
|
alignItems="flex-end"
|
|
>
|
|
<Button variant="contained" onClick={startResearch}>Rechercher</Button>
|
|
</Box>
|
|
<Rooms rooms={rooms} callbackRoomSelected={callbackRoomSelected} />
|
|
</div>
|
|
</>
|
|
}
|
|
|
|
function RoomInformation({ roomId, setIsEditDialogOpen }) {
|
|
const [names, setNames] = React.useState([]);
|
|
const [users, setUsers] = React.useState([]);
|
|
|
|
React.useEffect(() => {
|
|
if (roomId !== undefined) {
|
|
fetch("https://encartes.aliens-lyon.fr/api/map/get_place_info/" + roomId)
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
setNames(data.names);
|
|
setUsers(data.users);
|
|
});
|
|
}
|
|
}, [roomId]);
|
|
|
|
if (roomId === undefined) {
|
|
return;
|
|
}
|
|
|
|
return <div style={{ padding: '24px' }}>
|
|
<Typography component="h2" variant="h5" gutterBottom>
|
|
Salle sélectionnée
|
|
</Typography>
|
|
<ul>
|
|
<li>{
|
|
names.length === 0 ? <em>Aucun nom défini</em> : names.join(', ')
|
|
}</li>
|
|
<li>{
|
|
users.length === 0
|
|
? <em>Aucun utilisateur défini</em>
|
|
: 'Utilisée par ' + users.join(', ')
|
|
}</li>
|
|
</ul>
|
|
<a onClick={() => { setIsEditDialogOpen(true) }}>Modifier</a>
|
|
</div>
|
|
}
|
|
|
|
function TopBar({toggleTheme}) {
|
|
const [openAboutModal, setOpenAboutModal] = React.useState(false);
|
|
|
|
const handleOpenAboutModal = () => {
|
|
setOpenAboutModal(true);
|
|
};
|
|
|
|
const handleCloseAboutModal = () => {
|
|
setOpenAboutModal(false);
|
|
};
|
|
|
|
return <>
|
|
<AppBar position="static">
|
|
<Toolbar>
|
|
<Typography variant="h6" component="div" sx={{ flexGrow: 1 }}>
|
|
ENcarteS
|
|
</Typography>
|
|
<IconButton onClick={toggleTheme} size="large">
|
|
<SettingsBrightnessIcon fontSize="inherit"/>
|
|
</IconButton>
|
|
<Button color="inherit" onClick={handleOpenAboutModal}>À propos</Button>
|
|
</Toolbar>
|
|
</AppBar>
|
|
|
|
<Dialog
|
|
open={openAboutModal}
|
|
onClose={handleCloseAboutModal}
|
|
aria-labelledby="alert-dialog-title"
|
|
aria-describedby="alert-dialog-description"
|
|
>
|
|
<DialogTitle id="alert-dialog-title">
|
|
{"À propos d'ENcarteS"}
|
|
</DialogTitle>
|
|
<DialogContent>
|
|
<DialogContentText id="alert-dialog-description">
|
|
ENcarteS permet de rechercher les salles de l'ENS !
|
|
</DialogContentText>
|
|
</DialogContent>
|
|
<DialogActions>
|
|
<Button onClick={handleCloseAboutModal}>Ok</Button>
|
|
</DialogActions>
|
|
</Dialog>
|
|
</>
|
|
}
|
|
|
|
function EditDialog({ isOpen, setIsOpen, room }) {
|
|
const [names, setNames] = React.useState([]);
|
|
const [users, setUsers] = React.useState([]);
|
|
const [newPlaceName, setNewPlaceName] = React.useState("");
|
|
|
|
// Used to refresh useEffect
|
|
const [updatesCount, setupdatesCount] = React.useState(0);
|
|
|
|
React.useEffect(() => {
|
|
if (room !== undefined) {
|
|
fetch("https://encartes.aliens-lyon.fr/api/map/get_place_info/" + room)
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
setNames(data.names);
|
|
setUsers(data.users);
|
|
});
|
|
}
|
|
}, [room, updatesCount]);
|
|
|
|
const refresh = () => {
|
|
setupdatesCount(updatesCount + 1);
|
|
};
|
|
|
|
const addName = () => {
|
|
fetch("https://encartes.aliens-lyon.fr/api/map/add_place_name/" + room + "/" + encodeURI(newPlaceName))
|
|
.then(response => refresh());
|
|
};
|
|
|
|
const removeName = (placeName) => {
|
|
fetch("https://encartes.aliens-lyon.fr/api/map/del_place_name/" + room + "/" + encodeURI(placeName))
|
|
.then(response => refresh());
|
|
}
|
|
|
|
return <Dialog open={isOpen} onClose={() => { setIsOpen(false) }}>
|
|
<DialogTitle>Salle n°{room}</DialogTitle>
|
|
<DialogContent>
|
|
<DialogContentText>
|
|
Noms :<br />
|
|
{names.map(name => {
|
|
return <Chip label={name} variant="outlined" onDelete={() => { removeName(name) }} />
|
|
})}
|
|
|
|
<TextField
|
|
value={newPlaceName}
|
|
onChange={(event) => { setNewPlaceName(event.target.value) }}
|
|
label="Nouveau nom"
|
|
margin="dense"
|
|
fullWidth
|
|
/>
|
|
<Button onClick={() => { addName() }}>Ajouter</Button>
|
|
|
|
<Divider />
|
|
|
|
Utilisateurs :<br />
|
|
{users.map(name => {
|
|
return <Chip label={name} variant="outlined" onDelete={() => { }} />
|
|
})}
|
|
</DialogContentText>
|
|
|
|
</DialogContent>
|
|
<DialogActions>
|
|
<Button onClick={() => { setIsOpen(false) }}>Fermer</Button>
|
|
</DialogActions>
|
|
</Dialog>
|
|
}
|
|
|
|
function App({toggleTheme}) {
|
|
const [currentFloor, setCurrentFloor] = React.useState(undefined);
|
|
const [selectedRoom, setSelectedRoom] = React.useState(undefined);
|
|
const [isEditDialogOpen, setIsEditDialogOpen] = React.useState(false);
|
|
|
|
return <>
|
|
<EditDialog
|
|
isOpen={isEditDialogOpen}
|
|
setIsOpen={setIsEditDialogOpen}
|
|
room={selectedRoom}
|
|
/>
|
|
<TopBar toggleTheme={toggleTheme}/>
|
|
<div style={{ flexGrow: '1', display: 'flex', flexDirection: 'line', flexWrap: 'nowrap' }}>
|
|
{currentFloor !== undefined ? <Map
|
|
selectedRoom={selectedRoom}
|
|
callbackRoomSelected={setSelectedRoom}
|
|
floorID={currentFloor}
|
|
callbackChangeFloor={setCurrentFloor}
|
|
/> : <></>}
|
|
<div>
|
|
<ChangeFloor currentFloor={currentFloor} callbackFloorChanged={setCurrentFloor} />
|
|
<Divider />
|
|
<RoomResearch callbackRoomSelected={(floor, room) => {
|
|
setCurrentFloor(floor);
|
|
setSelectedRoom(room);
|
|
}} />
|
|
<Divider />
|
|
<RoomInformation
|
|
roomId={selectedRoom}
|
|
setIsEditDialogOpen={setIsEditDialogOpen}
|
|
/>
|
|
</div>
|
|
</div>
|
|
</>
|
|
}
|
|
|
|
export default function ThemedApp() {
|
|
const [themeMode, setThemeMode] = React.useState('light');
|
|
|
|
const theme = createTheme({
|
|
palette: {
|
|
mode: themeMode,
|
|
},
|
|
});
|
|
|
|
const toggleTheme = () => {
|
|
if (themeMode === 'light') {
|
|
setThemeMode('dark')
|
|
} else {
|
|
setThemeMode('light')
|
|
}
|
|
}
|
|
|
|
return (
|
|
<ThemeProvider theme={theme}>
|
|
<CssBaseline />
|
|
<App toggleTheme={toggleTheme} />
|
|
</ThemeProvider>
|
|
);
|
|
}
|