Skip to content

Commit fc1f3ef

Browse files
committed
feat(workplace): update desk auto-assign to factor in user groups
1 parent 2cd5043 commit fc1f3ef

File tree

3 files changed

+42
-12
lines changed

3 files changed

+42
-12
lines changed

apps/workplace/src/app/book/desk-flow/auto-assigned-desk-modal.component.ts

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import {
1919
} from '@placeos/bookings';
2020
import {
2121
AsyncHandler,
22+
currentUser,
2223
Desk,
2324
firstTruthyValueFrom,
2425
i18n,
@@ -44,7 +45,7 @@ import { isBefore, startOfMinute } from 'date-fns';
4445
>
4546
<!-- Header -->
4647
<header
47-
class="sticky top-0 z-10 m-2 h-14 w-[calc(100%-1rem)] min-w-[20rem] rounded border-none bg-base-200 p-2"
48+
class="bg-base-200 sticky top-0 z-10 m-2 h-14 w-[calc(100%-1rem)] min-w-[20rem] rounded border-none p-2"
4849
>
4950
<h2 class="px-2 text-xl font-medium">
5051
{{ 'BOOKINGS.DESK_AUTO_ASSIGNED_TITLE' | translate }}
@@ -84,7 +85,7 @@ import { isBefore, startOfMinute } from 'date-fns';
8485
<!-- Success Message -->
8586
<div class="mb-6 flex items-start space-x-3">
8687
<div
87-
class="flex h-8 w-8 items-center justify-center rounded-full bg-success text-white"
88+
class="bg-success flex h-8 w-8 items-center justify-center rounded-full text-white"
8889
>
8990
<icon class="text-xl">done</icon>
9091
</div>
@@ -103,12 +104,12 @@ import { isBefore, startOfMinute } from 'date-fns';
103104
104105
<!-- Desk Details Card -->
105106
<div
106-
class="mb-4 space-y-3 rounded-lg border border-base-200 bg-base-100 p-4"
107+
class="border-base-200 bg-base-100 mb-4 space-y-3 rounded-lg border p-4"
107108
>
108109
<div class="flex items-center space-x-2">
109110
<icon class="text-2xl">chair</icon>
110111
<div class="leading-tight">
111-
<div class="text-xs uppercase tracking-wide">
112+
<div class="text-xs tracking-wide uppercase">
112113
{{ 'RESOURCE.DESK' | translate }}
113114
</div>
114115
<div class="text-lg font-medium">
@@ -122,7 +123,7 @@ import { isBefore, startOfMinute } from 'date-fns';
122123
<div class="flex items-center space-x-2">
123124
<icon class="text-2xl">layers</icon>
124125
<div class="leading-tight">
125-
<div class="text-xs uppercase tracking-wide">
126+
<div class="text-xs tracking-wide uppercase">
126127
{{ 'COMMON.FLOOR' | translate }}
127128
</div>
128129
<div class="text-lg font-medium">
@@ -133,7 +134,7 @@ import { isBefore, startOfMinute } from 'date-fns';
133134
<div class="flex items-center space-x-2">
134135
<icon class="text-2xl">place</icon>
135136
<div class="leading-none">
136-
<div class="text-xs uppercase tracking-wide">
137+
<div class="text-xs tracking-wide uppercase">
137138
{{
138139
'BOOKINGS.DESK_NEIGHBOURHOOD'
139140
| translate
@@ -151,7 +152,7 @@ import { isBefore, startOfMinute } from 'date-fns';
151152
{{ 'BOOKINGS.DESK_LOCATION_ON_MAP' | translate }}
152153
</div>
153154
<div
154-
class="relative h-64 overflow-hidden rounded-lg border border-base-200 bg-base-200"
155+
class="border-base-200 bg-base-200 relative h-64 overflow-hidden rounded-lg border"
155156
>
156157
@if (map_url()) {
157158
<interactive-map
@@ -162,7 +163,7 @@ import { isBefore, startOfMinute } from 'date-fns';
162163
></interactive-map>
163164
} @else {
164165
<div
165-
class="flex h-full w-full items-center justify-center text-base-content opacity-30"
166+
class="text-base-content flex h-full w-full items-center justify-center opacity-30"
166167
>
167168
<div class="text-center">
168169
<icon class="mb-2 text-4xl">map</icon>
@@ -181,7 +182,7 @@ import { isBefore, startOfMinute } from 'date-fns';
181182
182183
<!-- Footer -->
183184
<footer
184-
class="flex items-center justify-between gap-2 border-t border-base-200 p-4"
185+
class="border-base-200 flex items-center justify-between gap-2 border-t p-4"
185186
>
186187
<button
187188
btn
@@ -332,8 +333,22 @@ export class AutoAssignedDeskModalComponent
332333

333334
// Fallback to original logic if no nearby desk found
334335
if (!assigned_desk) {
336+
// Prefer desks whose tags match the current user's groups
337+
const user_groups = currentUser()?.groups || [];
338+
const tag_matched = user_groups.length
339+
? available_desks.filter(
340+
(desk) =>
341+
desk.tags?.length &&
342+
desk.tags.some((tag) =>
343+
user_groups.includes(tag),
344+
),
345+
)
346+
: [];
347+
const pool =
348+
tag_matched.length > 0 ? tag_matched : available_desks;
349+
335350
// Group desks by level and find level with most available desks
336-
const desks_by_level = available_desks.reduce(
351+
const desks_by_level = pool.reduce(
337352
(acc, desk) => {
338353
const zone_id = desk.zone?.id || 'unknown';
339354
if (!acc[zone_id]) {

libs/bookings/src/lib/booking-form.service.ts

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ export interface BookingAsset {
122122
groups?: string[];
123123
assigned_to?: string;
124124
features: string[];
125+
tags?: string[];
125126
}
126127

127128
@Injectable({
@@ -891,16 +892,27 @@ export class BookingFormService extends AsyncHandler {
891892

892893
/**
893894
* Auto-allocate a desk from the active building.
894-
* Picks the level with the most available desks, then selects one at random.
895+
* Prefers desks with tags matching the user's groups, then
896+
* picks the level with the most available desks and selects one at random.
895897
*/
896898
public async autoAllocateDesk(): Promise<void> {
897899
const available = await nextValueFrom(this.available_resources);
898900
if (!available?.length) {
899901
throw i18n('BOOKINGS.DESK_AVAILABLE_ERROR');
900902
}
903+
// Prefer desks whose tags match the current user's groups
904+
const user_groups = currentUser()?.groups || [];
905+
const tag_matched = user_groups.length
906+
? available.filter(
907+
(asset) =>
908+
asset.tags?.length &&
909+
asset.tags.some((tag) => user_groups.includes(tag)),
910+
)
911+
: [];
912+
const pool = tag_matched.length ? tag_matched : available;
901913
// Group available desks by zone (level) id
902914
const zone_map: Record<string, BookingAsset[]> = {};
903-
for (const asset of available) {
915+
for (const asset of pool) {
904916
const zone_id = asset.zone?.id || 'unknown';
905917
if (!zone_map[zone_id]) zone_map[zone_id] = [];
906918
zone_map[zone_id].push(asset);

libs/common/src/lib/types/desk.class.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ export class Desk implements Record<string, any> {
2323
public readonly features: string[];
2424
/** List of URLs to images */
2525
public readonly images: string[];
26+
/** Tags associated with the desk for group-based auto-assignment */
27+
public readonly tags: string[];
2628
/** Homebase associated with the desk */
2729
public readonly homebase: string;
2830
/** */
@@ -41,6 +43,7 @@ export class Desk implements Record<string, any> {
4143
this.qr_code = data.qr_code || '';
4244
this.features = data.features || [];
4345
this.images = data.images || [];
46+
this.tags = data.tags || [];
4447
this.homebase = data.homebase || '';
4548
this.security = data.security || '';
4649
for (const key in data) {

0 commit comments

Comments
 (0)