Skip to content
This repository was archived by the owner on Jan 28, 2026. It is now read-only.

Commit 250240d

Browse files
author
ge85riz
committed
✨ feat(frontend): add visual indicators feature for employee acquaintances at tables on the Seat Allocation Page
- Color-code chairs: green for no acquaintances, red for known colleagues at table - Display arrows pointing to acquainted chairs when chair is clicked
1 parent 63169ee commit 250240d

4 files changed

Lines changed: 63 additions & 8 deletions

File tree

frontend/src/components/canvas/elements/Chair.tsx

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,9 @@ export class Chair implements ElementProperties {
1414
attachedTo: string | undefined;
1515
draggable: boolean;
1616
offset: { dx: number; dy: number };
17-
assigneeProfile?: Profile;
18-
belongsToVisitor?: boolean;
17+
assigneeProfile?: Profile; // we don't persist this data to DB
18+
belongsToVisitor?: boolean; // we don't persist this data to DB
19+
acquaintedProfileIds?: UUID[]; // we don't persist this data to DB
1920

2021
constructor(stageCenter: { x: number, y: number }) {
2122
this.id = uuidv4();
@@ -29,6 +30,7 @@ export class Chair implements ElementProperties {
2930
this.offset = { dx: 0, dy: 0 };
3031
this.assigneeProfile = undefined;
3132
this.belongsToVisitor = false;
33+
this.acquaintedProfileIds = undefined;
3234
}
3335
}
3436

@@ -39,7 +41,11 @@ export function ChairRender(chair: Chair) {
3941
onMouseOut={handleMouseOut}>
4042
<Circle
4143
radius={chair.radius || 10}
42-
fill={chair.color || "#cccccc"}
44+
fill={
45+
!chair.acquaintedProfileIds ? (chair.color ?? "#cccccc") :
46+
chair.acquaintedProfileIds.length > 0 ? "red" :
47+
"rgba(73,154,33,0.79)"
48+
}
4349
perfectDrawEnabled={false}
4450
/>
4551
{chair.assigneeProfile && (

frontend/src/components/canvas/elements/NeighbourArrows.tsx

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,14 @@ function NeighbourArrows({
3030

3131
const arrows = chairs
3232
.filter((chair) => chair.id !== selectedChair.id)
33-
.filter((chair) => {
33+
.filter((neighborChair) => {
3434
if (algorithmType === "table") {
35-
return selectedChair.attachedTo === chair.attachedTo;
35+
if (selectedChair.acquaintedProfileIds && neighborChair.assigneeProfile) {
36+
return selectedChair.acquaintedProfileIds.includes(neighborChair.assigneeProfile.id);
37+
}
38+
return false;
3639
} else if (algorithmType === "distance") {
37-
return areNeighbours(selectedChair, chair);
40+
return areNeighbours(selectedChair, neighborChair);
3841
} else {
3942
return false;
4043
}

frontend/src/pages/Events/EventSeatAllocation.tsx

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import useApiService from "services/apiService";
66
import { CanvasProvider, useCanvas } from "components/canvas/contexts/CanvasContext";
77
import KonvaCanvas, { type KonvaCanvasProps } from "components/canvas/KonvaCanvas";
88
import { getFullName, type Profile } from "types/employee";
9-
import { type AlgorithmType, type ElementProperties } from "components/canvas/utils/constants.tsx";
9+
import { type AlgorithmType, type ElementProperties, type UUID } from "components/canvas/utils/constants.tsx";
1010
import type { Chair } from "components/canvas/elements/Chair.tsx";
1111
import type { Table } from "components/canvas/elements/Table.tsx";
1212

@@ -49,7 +49,12 @@ const SeatAllocationContent = ({
4949
const [allocated, setAllocated] = useState<SeatAllocationResult[]>([]);
5050
const [unallocatedSearch, setUnallocatedSearch] = useState("");
5151
const [allocatedSearch, setAllocatedSearch] = useState("");
52-
const { getSeatAllocations, updateSeatAllocation, generateSeatAllocations } = useApiService();
52+
const {
53+
getSeatAllocations,
54+
updateSeatAllocation,
55+
generateSeatAllocations,
56+
findEmployeesSittingWithAcquaintances,
57+
} = useApiService();
5358
const [isCollapsed, setIsCollapsed] = useState(false);
5459
const [emptyChairCount, setEmptyChairCount] = useState(0);
5560
const [constraintInputValues, setConstraintInputValues] = useState({
@@ -151,12 +156,14 @@ const SeatAllocationContent = ({
151156
if (e.type === "chair" && chairProfileMap.has(e.id)) {
152157
(e as Chair).assigneeProfile = { ...chairProfileMap.get(e.id)! };
153158
(e as Chair).belongsToVisitor = chairProfileMap.get(e.id)!.isVisitor;
159+
(e as Chair).acquaintedProfileIds = undefined;
154160
if (!(e as Chair).attachedTo) {
155161
toast.error("Some participants are assigned to chairs that are not linked to a table. It might cause inconsistencies. Please be aware.");
156162
}
157163
} else if (e.type === "chair") {
158164
(e as Chair).assigneeProfile = undefined;
159165
(e as Chair).belongsToVisitor = undefined;
166+
(e as Chair).acquaintedProfileIds = undefined;
160167
emptyChairCount++;
161168
}
162169
});
@@ -234,6 +241,33 @@ const SeatAllocationContent = ({
234241
title="Find and go to the first chair element on the canvas">
235242
<FullscreenExitOutlined />
236243
</Button>
244+
<Button
245+
className="ms-3 mt-2"
246+
type="primary"
247+
title={`Green Chairs: every employee at the table is new \nRed Chairs: know at least one employee`}
248+
onClick={async () => {
249+
try {
250+
setLoading(true);
251+
const employeeIdsSittingWithTheirAcquaintances: Record<UUID, UUID[]> | null = await findEmployeesSittingWithAcquaintances(eventId);
252+
if (employeeIdsSittingWithTheirAcquaintances) {
253+
state.elements.forEach(element => {
254+
if (element.type === "chair") {
255+
const chair = element as Chair;
256+
// we have to clear chair's state
257+
chair.acquaintedProfileIds = undefined;
258+
if (chair.assigneeProfile && !chair.belongsToVisitor) {
259+
const employeeId = chair.assigneeProfile!.id;
260+
chair.acquaintedProfileIds = employeeIdsSittingWithTheirAcquaintances[employeeId] ?? [];
261+
}
262+
}
263+
});
264+
}
265+
} finally {
266+
setLoading(false);
267+
}
268+
}}>
269+
Show Acquainted Employees
270+
</Button>
237271
</div>
238272

239273
<Space>

frontend/src/services/apiService.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import { useAuth } from "../contexts/AuthContext.tsx";
1313
import type { AppState } from "components/canvas/reducers/CanvasReducer.tsx";
1414
import { Chair } from "components/canvas/elements/Chair.tsx";
1515
import { useNavigate } from "react-router-dom";
16+
import type { UUID } from "components/canvas/utils/constants.tsx";
1617

1718
export const BASE_URL = import.meta.env.VITE_API_ORIGIN;
1819

@@ -313,6 +314,7 @@ export default function useApiService() {
313314
if (el.type === "chair") {
314315
delete (el as Chair).assigneeProfile;
315316
delete (el as Chair).belongsToVisitor;
317+
delete (el as Chair).acquaintedProfileIds;
316318
}
317319
});
318320
const response = await request(`/schematics/${id}`, {
@@ -573,6 +575,15 @@ export default function useApiService() {
573575
}
574576
}, [request]);
575577

578+
const findEmployeesSittingWithAcquaintances = useCallback(async (eventId: string) => {
579+
try {
580+
return await request<Record<UUID, UUID[]>>(`/seat-allocation/${eventId}/findAcquaintances`);
581+
} catch (err) {
582+
toast.error("Fetching employee acquaintances for this event failed");
583+
return null;
584+
}
585+
}, [request]);
586+
576587
return {
577588
request,
578589
logoutRequest,
@@ -603,6 +614,7 @@ export default function useApiService() {
603614
updateParticipant,
604615
deleteParticipation,
605616
generateSeatAllocations,
617+
findEmployeesSittingWithAcquaintances,
606618
getSeatAllocations,
607619
updateSeatAllocation,
608620
};

0 commit comments

Comments
 (0)