Skip to content

Commit 6e56039

Browse files
Merge pull request #25 from peek-travel/feat/timeslot-resource-allocations-fallback
feat: fall back to regular resourceAllocations for timeslots
2 parents ed128e7 + 9868239 commit 6e56039

3 files changed

Lines changed: 124 additions & 2 deletions

File tree

src/internal/peek/timeslots/timeslot-converter.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,13 +55,28 @@ export function fromTimeslotNode(
5555
durationMin: node.minuteLength ?? 0,
5656
date: node.date || "",
5757
startTime: node.start ?? null,
58-
assignedResources: mapAssignedResources(node.inheritedResourceAllocations),
58+
assignedResources: mapAssignedResources(selectResourceAllocations(node)),
5959
};
6060
}
6161

6262
/** Only allocations with this status are considered assigned. */
6363
const ACTIVE_ALLOCATION_STATUS = "ACTIVE";
6464

65+
/**
66+
* Timeslots may carry both inherited (schedule-level) and directly-assigned
67+
* resource allocations. Prefer inherited; fall back to the regular allocations
68+
* only when the inherited field is absent or empty.
69+
*/
70+
function selectResourceAllocations(
71+
node: TimeslotNode,
72+
): TimeslotResourceAllocationNode[] | null | undefined {
73+
const inherited = node.inheritedResourceAllocations;
74+
if (Array.isArray(inherited) && inherited.length > 0) {
75+
return inherited;
76+
}
77+
return node.resourceAllocations;
78+
}
79+
6580
function mapAssignedResources(
6681
allocations: TimeslotResourceAllocationNode[] | null | undefined,
6782
): AssignedResource[] {

src/internal/peek/timeslots/timeslot-queries.ts

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,24 @@ export const TIMESLOTS_QUERY = `
2121
status
2222
date
2323
inheritedResourceAllocations {
24+
id
25+
status
26+
quantity
27+
resourcePool {
28+
id
29+
name
30+
category
31+
capacity
32+
accountUser {
33+
id
34+
}
35+
}
36+
}
37+
resourceAllocations {
2438
quantity
2539
status
2640
resourcePool {
41+
id
2742
name
2843
category
2944
capacity
@@ -61,9 +76,24 @@ export const TIMESLOT_BY_ID_QUERY = `
6176
status
6277
date
6378
inheritedResourceAllocations {
79+
id
80+
status
81+
quantity
82+
resourcePool {
83+
id
84+
name
85+
category
86+
capacity
87+
accountUser {
88+
id
89+
}
90+
}
91+
}
92+
resourceAllocations {
6493
quantity
6594
status
6695
resourcePool {
96+
id
6797
name
6898
category
6999
capacity
@@ -99,11 +129,17 @@ export const UPDATE_TIMESLOT_MUTATION = `
99129
}
100130
`;
101131

102-
/** A single inherited resource allocation on a timeslot node. */
132+
/**
133+
* A single resource allocation on a timeslot node. Shared by both the
134+
* `inheritedResourceAllocations` and `resourceAllocations` selections; the
135+
* allocation-level `id` is only present on the inherited variant.
136+
*/
103137
export interface TimeslotResourceAllocationNode {
138+
id?: string | null;
104139
quantity: number | null;
105140
status: string | null;
106141
resourcePool: {
142+
id: string;
107143
name: string;
108144
category: string;
109145
capacity: number | null;
@@ -125,6 +161,7 @@ export interface TimeslotNode {
125161
date: string | null;
126162
start?: string | null;
127163
inheritedResourceAllocations: TimeslotResourceAllocationNode[] | null;
164+
resourceAllocations: TimeslotResourceAllocationNode[] | null;
128165
}
129166

130167
/** `data` payload of {@link TIMESLOTS_QUERY}. */

test/peek/timeslots/timeslot-converter.test.ts

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,15 @@ const fullNode: TimeslotNode = {
2323
quantity: 1,
2424
status: "ACTIVE",
2525
resourcePool: {
26+
id: "rp-1",
2627
name: "Ada",
2728
category: "guide",
2829
capacity: 5,
2930
accountUser: { id: "u1" },
3031
},
3132
},
3233
],
34+
resourceAllocations: null,
3335
};
3436

3537
describe("fromTimeslotNode", () => {
@@ -116,6 +118,74 @@ describe("fromTimeslotNode", () => {
116118
expect(fromTimeslotNode(node, "act-1").assignedResources).toEqual([]);
117119
});
118120

121+
it("falls back to resourceAllocations when inherited is null", () => {
122+
const node = {
123+
...fullNode,
124+
inheritedResourceAllocations: null,
125+
resourceAllocations: [
126+
{
127+
quantity: 2,
128+
status: "ACTIVE",
129+
resourcePool: {
130+
id: "rp-2",
131+
name: "Bob",
132+
category: "guide",
133+
capacity: 3,
134+
accountUser: { id: "u2" },
135+
},
136+
},
137+
],
138+
} as unknown as TimeslotNode;
139+
const { assignedResources } = fromTimeslotNode(node, "act-1");
140+
expect(assignedResources).toEqual([
141+
{ name: "Bob", capacity: 3, category: "guide", quantity: 2, accountUserId: "u2" },
142+
]);
143+
});
144+
145+
it("falls back to resourceAllocations when inherited is an empty array", () => {
146+
const node = {
147+
...fullNode,
148+
inheritedResourceAllocations: [],
149+
resourceAllocations: [
150+
{
151+
quantity: 1,
152+
status: "ACTIVE",
153+
resourcePool: {
154+
id: "rp-2",
155+
name: "Bob",
156+
category: "guide",
157+
capacity: 3,
158+
accountUser: { id: "u2" },
159+
},
160+
},
161+
],
162+
} as unknown as TimeslotNode;
163+
expect(fromTimeslotNode(node, "act-1").assignedResources).toHaveLength(1);
164+
expect(fromTimeslotNode(node, "act-1").assignedResources[0].name).toBe("Bob");
165+
});
166+
167+
it("prefers inherited over regular resourceAllocations when both are present", () => {
168+
const node = {
169+
...fullNode,
170+
resourceAllocations: [
171+
{
172+
quantity: 9,
173+
status: "ACTIVE",
174+
resourcePool: {
175+
id: "rp-2",
176+
name: "Bob",
177+
category: "guide",
178+
capacity: 3,
179+
accountUser: { id: "u2" },
180+
},
181+
},
182+
],
183+
} as unknown as TimeslotNode;
184+
const { assignedResources } = fromTimeslotNode(node, "act-1");
185+
expect(assignedResources).toHaveLength(1);
186+
expect(assignedResources[0].name).toBe("Ada");
187+
});
188+
119189
it("filters out allocations whose status is not ACTIVE", () => {
120190
const node = {
121191
...fullNode,

0 commit comments

Comments
 (0)