Skip to content

Commit 118b342

Browse files
committed
add process for room assignments
1 parent 9f13112 commit 118b342

File tree

5 files changed

+302
-0
lines changed

5 files changed

+302
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
const express = require('express')
2+
const RoomAssignment = require('../../models/RoomAssignment')
3+
const router = express.Router()
4+
5+
module.exports = router
6+
7+
const INDEX_PIPELINE = [
8+
{
9+
$lookup: {
10+
from: "rooms",
11+
localField: "room",
12+
foreignField: "_id",
13+
as: "room",
14+
}
15+
},
16+
{
17+
$lookup: {
18+
from: 'people',
19+
localField: 'person',
20+
foreignField: '_id',
21+
as: 'person',
22+
pipeline: [
23+
{
24+
$lookup: {
25+
from: 'institutions',
26+
localField: 'affiliations',
27+
foreignField: '_id',
28+
as: 'affiliations',
29+
pipeline: [
30+
{ $project: { _id: 1, name: 1 }}
31+
]
32+
}
33+
},
34+
{
35+
$project: {
36+
_id: 1,
37+
firstName: 1,
38+
lastName: 1,
39+
email: 1,
40+
affiliations: 1
41+
}
42+
}
43+
]
44+
}
45+
},
46+
{
47+
$unwind: {
48+
path: '$person',
49+
preserveNullAndEmptyArrays: true,
50+
}
51+
},
52+
{
53+
$project: {
54+
"startDate": 1,
55+
"endDate": 1,
56+
"room._id": 1,
57+
"room.code": 1,
58+
"room.building": 1,
59+
"room.floor": 1,
60+
"room.number": 1,
61+
"person": 1
62+
}
63+
}
64+
];
65+
66+
module.exports.INDEX_PIPELINE = INDEX_PIPELINE;
67+
68+
router.get('/', async (req, res) => {
69+
if (!req.user || !req.user.roles.includes('admin')) {
70+
res.status(401).json({
71+
result: "Unauthorized"
72+
})
73+
return
74+
}
75+
76+
const data = await RoomAssignment.aggregate([
77+
{ $match: {
78+
$expr: {
79+
$and: [
80+
{ $or: [ {$eq: ['$endDate', null]}, {$gte: ['$endDate', '$$NOW']}]},
81+
]
82+
}
83+
}
84+
},
85+
...INDEX_PIPELINE,
86+
])
87+
88+
res.json({ data })
89+
})

server/controllers/processes/router.js

+2
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ router.use('/visits', require('./visits'))
1616

1717
router.use('/visitsList', require('./visitsList'))
1818

19+
router.use('/roomAssignmentsList', require('./roomAssignmentsList'))
20+
1921
router.use('/roomLabels', require('./roomLabels'))
2022

2123
router.use('/planimetrie', require('./planimetrie'))

src/App.js

+3
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import ManageConferences from './processes/Conferences'
2828
import ProcessVisits from './processes/Visits'
2929
import ProcessVisit from './processes/Visit'
3030
import ProcessVisitsList from './processes/VisitsList'
31+
import ProcessRoomAssignmentsList from './processes/RoomAssignmentsList'
3132
import ManageRoomLabels from './processes/RoomLabels'
3233
import SanityCheck from './processes/SanityCheck'
3334
import ProcessUrls from './processes/Urls'
@@ -104,6 +105,8 @@ function Internal() {
104105
<Route path="/process/visits/:id" element={<ProcessVisit variant=""/>}/>
105106
<Route path="/process/visitsList" element={<ProcessVisitsList variant=""/>}/>
106107

108+
<Route path="/process/roomAssignmentsList" element={<ProcessRoomAssignmentsList variant=""/>}/>
109+
107110
<Route path="/process/roomLabels" element={<ManageRoomLabels/>}/>
108111

109112
<Route path="/process/sanityCheck" element={<SanityCheck/>}/>

src/processes/Home.js

+17
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,23 @@ export default function Home() {
9999
</Card>
100100
</div>
101101
}
102+
{ user.hasProcessPermission('/process/roomAssignmentsList') &&
103+
<div className="col-lg-6 p-3">
104+
<Card className="shadow">
105+
<Card.Header>
106+
<div className="d-flex flex-row justify-content-between">
107+
<strong>Elenco Assegnazioni Stanze</strong>
108+
<a href="/process/roomAssignmentsList"><button className="btn btn-sm btn-primary stretched-link">Inizia</button></a>
109+
</div>
110+
</Card.Header>
111+
<Card.Body>
112+
<ul>
113+
<li>Visualizza le informazioni sulle assegnazioni delle stanze</li>
114+
</ul>
115+
</Card.Body>
116+
</Card>
117+
</div>
118+
}
102119
{ user.hasProcessPermission('/process/roomLabels') &&
103120
<div className="col-lg-6 p-3">
104121
<Card className="shadow">

src/processes/RoomAssignmentsList.js

+191
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
import { useQuery } from 'react-query'
2+
import { myDateFormat, useQueryFilter } from '../Engine'
3+
4+
export default function ProcessAssignmentsList() {
5+
return <>
6+
<h1 className="text-primary pb-0 mb-3">Elenco assegnazioni</h1>
7+
<AssignmentsList/>
8+
**Vengono visualizzate le assegnazioni delle stanze attuali e future.
9+
<div>
10+
<i>Chi può accedere a questa pagina?</i><br />
11+
Questa pagina è accessibile a tutti gli utenti
12+
con permesso <i>/process/roomAssignmentsList</i>.
13+
</div>
14+
</>
15+
}
16+
17+
function AssignmentsList() {
18+
const filter = useQueryFilter({ _search: '' });
19+
const { isLoading, error, data } = useQuery(['process', 'roomAssignmentsList']);
20+
21+
if (isLoading) {
22+
return 'Loading...';
23+
}
24+
25+
if (error || !data?.data) {
26+
return 'Error: ' + (error ? error.message : 'Dati non disponibili');
27+
}
28+
29+
const updateFilter = (evt) => {
30+
filter.setFilter(filter => ({
31+
...filter,
32+
"_search": evt.target.value
33+
}));
34+
};
35+
36+
const filterAssignments = (assignments) => {
37+
if (!filter.filter._search) return assignments;
38+
39+
return assignments.filter(assignment => {
40+
const searchString = filter.filter._search.toLowerCase();
41+
const { person, room } = assignment;
42+
const roomData = room[0] || {};
43+
44+
const searchableText = `
45+
${person.firstName?.toLowerCase() || ''}
46+
${person.lastName?.toLowerCase() || ''}
47+
${person.affiliations?.map(aff => aff.name?.toLowerCase()).join(' ') || ''}
48+
${roomData.floor?.toString().toLowerCase() || ''}
49+
${roomData.number?.toString().toLowerCase() || ''}
50+
${roomData.code?.toLowerCase() || ''}
51+
${roomData.building?.toLowerCase() || ''}
52+
${assignment.startDate ? myDateFormat(assignment.startDate).toLowerCase() : ''}
53+
${assignment.endDate ? myDateFormat(assignment.endDate).toLowerCase() : ''}
54+
`;
55+
56+
return searchableText.includes(searchString);
57+
});
58+
};
59+
60+
const sortedAssignments = [...data.data].sort((a, b) => a.room[0]?.code.localeCompare(b.room[0]?.code));
61+
const filteredAssignments = filterAssignments(sortedAssignments);
62+
63+
const currentAssignmentsA = [], futureAssignmentsA = [];
64+
const currentAssignmentsB = [], futureAssignmentsB = [];
65+
const currentAssignmentsX = [], futureAssignmentsX = [];
66+
67+
const today = new Date();
68+
69+
filteredAssignments.forEach((assignment) => {
70+
const startDate = assignment.startDate ? new Date(assignment.startDate) : null;
71+
const endDate = assignment.endDate ? new Date(assignment.endDate) : null;
72+
const building = assignment.room[0]?.building;
73+
74+
const isCurrent = (!startDate || startDate <= today) && (!endDate || endDate >= today);
75+
const isFuture = startDate && startDate > today;
76+
77+
if (isCurrent) {
78+
if (building === "A") currentAssignmentsA.push(assignment);
79+
else if (building === "B") currentAssignmentsB.push(assignment);
80+
else if (building === "X") currentAssignmentsX.push(assignment);
81+
}
82+
83+
if (isFuture) {
84+
if (building === "A") futureAssignmentsA.push(assignment);
85+
else if (building === "B") futureAssignmentsB.push(assignment);
86+
else if (building === "X") futureAssignmentsX.push(assignment);
87+
}
88+
});
89+
90+
return (
91+
<div>
92+
<div className="mb-4">
93+
<input
94+
type="text"
95+
className="form-control"
96+
placeholder="Cerca per nome, stanza, piano..."
97+
value={filter.filter._search}
98+
onChange={updateFilter}
99+
/>
100+
</div>
101+
102+
<h2 className="mb-4">Assegnazioni Attuali</h2>
103+
104+
{currentAssignmentsA.length > 0 && (
105+
<>
106+
<h4 className="mb-2">Edificio A</h4>
107+
<RoomAssignmentsTable assignments={currentAssignmentsA} className="mb-4" />
108+
</>
109+
)}
110+
{currentAssignmentsB.length > 0 && (
111+
<>
112+
<h4 className="mb-2">Edificio B</h4>
113+
<RoomAssignmentsTable assignments={currentAssignmentsB} className="mb-4" />
114+
</>
115+
)}
116+
{currentAssignmentsX.length > 0 && (
117+
<>
118+
<h4 className="mb-2">Edificio Ex Albergo</h4>
119+
<RoomAssignmentsTable assignments={currentAssignmentsX} className="mb-4" />
120+
</>
121+
)}
122+
123+
<h2 className="mb-4 mt-5">Assegnazioni Future</h2>
124+
125+
{futureAssignmentsA.length > 0 && (
126+
<>
127+
<h4 className="mb-2">Edificio A</h4>
128+
<RoomAssignmentsTable assignments={futureAssignmentsA} className="mb-4" />
129+
</>
130+
)}
131+
{futureAssignmentsB.length > 0 && (
132+
<>
133+
<h4 className="mb-2">Edificio B</h4>
134+
<RoomAssignmentsTable assignments={futureAssignmentsB} className="mb-4" />
135+
</>
136+
)}
137+
{futureAssignmentsX.length > 0 && (
138+
<>
139+
<h4 className="mb-2">Edificio Ex Albergo</h4>
140+
<RoomAssignmentsTable assignments={futureAssignmentsX} className="mb-4" />
141+
</>
142+
)}
143+
</div>
144+
);
145+
}
146+
147+
function RoomAssignmentsTable({ assignments }) {
148+
if (assignments.length === 0) {
149+
return
150+
}
151+
152+
return (
153+
<table className="table table-striped table-bordered">
154+
<thead className="table-dark">
155+
<tr>
156+
<th scope="col">Piano</th>
157+
<th scope="col">Stanza</th>
158+
<th scope="col">Assegnazione</th>
159+
<th scope="col">Periodo</th>
160+
</tr>
161+
</thead>
162+
<tbody>
163+
{assignments.map((assignment) => {
164+
const { person, room, startDate, endDate } = assignment;
165+
const { firstName, lastName, affiliations } = person;
166+
const roomData = room[0] || {};
167+
168+
const period =
169+
startDate && endDate
170+
? `${myDateFormat(startDate)} - ${myDateFormat(endDate)}`
171+
: startDate
172+
? `Dal ${myDateFormat(startDate)}`
173+
: endDate
174+
? `Fino al ${myDateFormat(endDate)}`
175+
: "";
176+
177+
return (
178+
<tr key={assignment._id}>
179+
<td>{roomData.floor}</td>
180+
<td>{roomData.number}</td>
181+
<td>
182+
{firstName} {lastName} ({affiliations.map((aff) => aff.name).join(", ")})
183+
</td>
184+
<td>{period}</td>
185+
</tr>
186+
);
187+
})}
188+
</tbody>
189+
</table>
190+
);
191+
}

0 commit comments

Comments
 (0)