Skip to content

Commit 645154a

Browse files
committed
Add location support for matcher
1 parent c22757a commit 645154a

File tree

10 files changed

+158
-72
lines changed

10 files changed

+158
-72
lines changed

csm_web/frontend/src/components/enrollment_automation/EnrollmentAutomationTypes.tsx

+1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ export interface Time {
33
startTime: number;
44
endTime: number;
55
isLinked: boolean;
6+
location: string;
67
}
78

89
export interface Slot {

csm_web/frontend/src/components/enrollment_automation/MentorSectionPreferences.tsx

+4-1
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,8 @@ export function MentorSectionPreferences({
5757
day: time.day,
5858
startTime: parseTime(time.startTime),
5959
endTime: parseTime(time.endTime),
60-
isLinked: time.isLinked
60+
isLinked: time.isLinked,
61+
location: time.location
6162
});
6263
}
6364
const parsed_slot: Slot = {
@@ -176,6 +177,8 @@ export function MentorSectionPreferences({
176177
<li key={time_idx} className="matcher-selected-time-container">
177178
<span className="matcher-selected-time">
178179
{time.day} {formatTime(time.startTime)}&#8211;{formatTime(time.endTime)}
180+
<br />
181+
<span className="matcher-selected-location">(location: {time.location})</span>
179182
</span>
180183
</li>
181184
))}

csm_web/frontend/src/components/enrollment_automation/calendar/Calendar.tsx

+15-9
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { useEffect, useMemo, useRef, useState } from "react";
1+
import React, { useEffect, useRef, useState } from "react";
22
import { formatTime } from "../utils";
33
import { CalendarDay, CalendarDayHeader } from "./CalendarDay";
44
import { CalendarEvent, CalendarEventSingleTime, DAYS } from "./CalendarTypes";
@@ -11,11 +11,14 @@ const SCROLL_AMT = 30;
1111

1212
const WIDTH_SCALE = 0.9;
1313

14+
const DEFAULT_LOCATION = "TBD";
15+
1416
interface Time {
1517
day: string;
1618
startTime: number;
1719
endTime: number;
1820
isLinked: boolean; // whether this time is linked to another within a section
21+
location: string;
1922
}
2023

2124
interface CalendarProps {
@@ -63,7 +66,8 @@ export function Calendar({
6366
day: "",
6467
startTime: -1,
6568
endTime: -1,
66-
isLinked: false
69+
isLinked: false,
70+
location: DEFAULT_LOCATION
6771
});
6872

6973
const [eventExtrema, setEventExtrema] = useState<{ min: number; max: number }>({
@@ -222,7 +226,7 @@ export function Calendar({
222226
if (!eventCreationEnabled) {
223227
return;
224228
}
225-
setCurCreatedEvent({ day, startTime, endTime, isLinked: createdTimes.length > 0 });
229+
setCurCreatedEvent({ day, startTime, endTime, isLinked: createdTimes.length > 0, location: DEFAULT_LOCATION });
226230
setCreatingEvent(true);
227231
setEventHoverIndex(-1);
228232
setSelectedEventIndices([]);
@@ -237,7 +241,8 @@ export function Calendar({
237241
day: curCreatedEvent.day,
238242
startTime: curCreatedEvent.startTime,
239243
endTime: end_time,
240-
isLinked: curCreatedEvent.isLinked
244+
isLinked: curCreatedEvent.isLinked,
245+
location: curCreatedEvent.location
241246
});
242247
};
243248

@@ -246,12 +251,12 @@ export function Calendar({
246251
return;
247252
}
248253
onEventCreated(normalizeCreatedEvent());
249-
setCurCreatedEvent({ day: "", startTime: -1, endTime: -1, isLinked: false });
254+
setCurCreatedEvent({ day: "", startTime: -1, endTime: -1, isLinked: false, location: DEFAULT_LOCATION });
250255
setCreatingEvent(false);
251256
};
252257

253258
const onCreateDragEndCancel = (e: MouseEvent | FocusEvent) => {
254-
setCurCreatedEvent({ day: "", startTime: -1, endTime: -1, isLinked: false });
259+
setCurCreatedEvent({ day: "", startTime: -1, endTime: -1, isLinked: false, location: DEFAULT_LOCATION });
255260
setCreatingEvent(false);
256261
};
257262

@@ -263,7 +268,8 @@ export function Calendar({
263268
day: curCreatedEvent.day,
264269
startTime: curCreatedEvent.endTime - INTERVAL_LENGTH,
265270
endTime: curCreatedEvent.startTime + INTERVAL_LENGTH,
266-
isLinked: curCreatedEvent.isLinked
271+
isLinked: curCreatedEvent.isLinked,
272+
location: "TBD"
267273
};
268274
}
269275
};
@@ -296,8 +302,8 @@ export function Calendar({
296302
onEventHover={
297303
disableHover
298304
? () => {
299-
/* do nothing */
300-
}
305+
/* do nothing */
306+
}
301307
: setEventHoverIndex
302308
}
303309
onEventClick={eventClickWrapper}

csm_web/frontend/src/components/enrollment_automation/calendar/CalendarDay.tsx

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ interface NumberTime {
99
startTime: number;
1010
endTime: number;
1111
isLinked: boolean;
12+
location: string;
1213
}
1314

1415
enum EventType {

csm_web/frontend/src/components/enrollment_automation/coordinator/CoordinatorMatcherForm.tsx

+3-1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ interface StrTime {
3131
day: string;
3232
startTime: string;
3333
endTime: string;
34+
location: string;
3435
}
3536

3637
export function CoordinatorMatcherForm({
@@ -66,7 +67,8 @@ export function CoordinatorMatcherForm({
6667
startTime: parseTime(time.startTime),
6768
endTime: parseTime(time.endTime),
6869
day: time.day,
69-
isLinked: slot.times.length > 0
70+
isLinked: slot.times.length > 0,
71+
location: time.location
7072
};
7173
});
7274
return {

csm_web/frontend/src/components/enrollment_automation/coordinator/CreateStage.tsx

+97-37
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,17 @@ import { formatInterval, formatTime, parseTime, serializeTime } from "../utils";
1010

1111
import InfoIcon from "../../../../static/frontend/img/info.svg";
1212
import XIcon from "../../../../static/frontend/img/x.svg";
13-
import { useMatcherConfigMutation, useMatcherSlotsMutation } from "../../../utils/queries/matcher";
13+
import { useMatcherSlotsMutation } from "../../../utils/queries/matcher";
14+
15+
const DEFAULT_LOCATION = "TBD";
1416

1517
interface TileDetails {
1618
days: string[];
1719
daysLinked: boolean;
1820
startTime: number;
1921
endTime: number;
2022
length: number;
23+
location: string;
2124
}
2225

2326
interface CreateStageProps {
@@ -61,15 +64,15 @@ export function CreateStage({ profile, initialSlots, nextStage }: CreateStagePro
6164
daysLinked: true,
6265
startTime: -1,
6366
endTime: -1,
64-
length: 60
67+
length: 60,
68+
location: DEFAULT_LOCATION
6569
});
6670

6771
/**
6872
* Whether or not anything has been edited
6973
*/
7074
const [edited, setEdited] = useState<boolean>(false);
7175

72-
const matcherConfigMutation = useMatcherConfigMutation(profile.courseId);
7376
const matcherSlotsMutation = useMatcherSlotsMutation(profile.courseId);
7477

7578
/**
@@ -87,7 +90,8 @@ export function CreateStage({ profile, initialSlots, nextStage }: CreateStagePro
8790
startTime: React.createRef<HTMLInputElement>(),
8891
endTime: React.createRef<HTMLInputElement>(),
8992
length: React.createRef<HTMLInputElement>(),
90-
toggle: React.createRef<HTMLInputElement>()
93+
toggle: React.createRef<HTMLInputElement>(),
94+
location: React.createRef<HTMLInputElement>()
9195
};
9296

9397
/**
@@ -114,7 +118,8 @@ export function CreateStage({ profile, initialSlots, nextStage }: CreateStagePro
114118
startTime: t,
115119
endTime: t + tileDetails.length,
116120
// linked only if there are multiple days and user wants to link them
117-
isLinked: tileDetails.daysLinked && tileDetails.days.length > 1
121+
isLinked: tileDetails.daysLinked && tileDetails.days.length > 1,
122+
location: tileDetails.location
118123
});
119124
}
120125
}
@@ -130,7 +135,8 @@ export function CreateStage({ profile, initialSlots, nextStage }: CreateStagePro
130135
const times = slot.times.map(time => ({
131136
day: time.day,
132137
startTime: serializeTime(time.startTime),
133-
endTime: serializeTime(time.endTime)
138+
endTime: serializeTime(time.endTime),
139+
location: time.location
134140
}));
135141
return {
136142
...slot,
@@ -254,6 +260,22 @@ export function CreateStage({ profile, initialSlots, nextStage }: CreateStagePro
254260
setCurCreatedTimes(newTimes);
255261
};
256262

263+
/**
264+
* Edit the location field of an event
265+
*
266+
* @param index index of time to edit
267+
* @param newLocation new location value
268+
*/
269+
const editTime_location = (index: number, newLocation: string) => {
270+
const newTimes = [...curCreatedTimes];
271+
if (newLocation.trim() === "") {
272+
newTimes[index]["location"] = DEFAULT_LOCATION;
273+
} else {
274+
newTimes[index]["location"] = newLocation;
275+
}
276+
setCurCreatedTimes(newTimes);
277+
};
278+
257279
const toggleCreatingTiledEvents = (e: React.ChangeEvent<HTMLInputElement>): void => {
258280
// current value of checkbox after click
259281
const checked = e.target.checked;
@@ -297,6 +319,10 @@ export function CreateStage({ profile, initialSlots, nextStage }: CreateStagePro
297319
setTileDetails({ ...tileDetails, daysLinked: e.target.checked });
298320
};
299321

322+
const editTiled_location = (value: string): void => {
323+
setTileDetails({ ...tileDetails, location: value });
324+
};
325+
300326
const saveTiledEvents = () => {
301327
const newSlots = [];
302328
for (let t = tileDetails.startTime; t <= tileDetails.endTime - tileDetails.length; t += tileDetails.length) {
@@ -307,17 +333,28 @@ export function CreateStage({ profile, initialSlots, nextStage }: CreateStagePro
307333
day: day,
308334
startTime: t,
309335
endTime: t + tileDetails.length,
310-
isLinked: tileDetails.days.length > 1
336+
isLinked: tileDetails.days.length > 1,
337+
location: tileDetails.location
311338
});
312339
}
313340
newSlots.push(newEvent);
314341
} else {
315342
for (const day of tileDetails.days) {
316-
newSlots.push({ times: [{ day: day, startTime: t, endTime: t + tileDetails.length, isLinked: false }] });
343+
newSlots.push({
344+
times: [
345+
{
346+
day: day,
347+
startTime: t,
348+
endTime: t + tileDetails.length,
349+
isLinked: false,
350+
location: tileDetails.location
351+
}
352+
]
353+
});
317354
}
318355
}
319356
}
320-
setSlots([...slots, ...newSlots]);
357+
setSlots([...slots, ...newSlots] as Slot[]);
321358
// stop creating tiled events
322359
tileRefs.toggle.current!.checked = false;
323360
toggleCreatingTiledEvents({ target: tileRefs.toggle.current! } as React.ChangeEvent<HTMLInputElement>);
@@ -327,7 +364,7 @@ export function CreateStage({ profile, initialSlots, nextStage }: CreateStagePro
327364
* Save the newly created event and times
328365
*/
329366
const saveEvent = () => {
330-
const newEvent = { times: curCreatedTimes };
367+
const newEvent: Slot = { times: curCreatedTimes };
331368
setSlots([...slots, newEvent]);
332369
setCurCreatedTimes([]);
333370
setSavedExistingEvent(null);
@@ -340,7 +377,7 @@ export function CreateStage({ profile, initialSlots, nextStage }: CreateStagePro
340377
*/
341378
const cancelEvent = () => {
342379
if (savedExistingEvent !== null) {
343-
setSlots([...slots, savedExistingEvent]);
380+
setSlots([...slots, savedExistingEvent] as Slot[]);
344381
setSavedExistingEvent(null);
345382
}
346383
// proceed with resetting current event
@@ -472,6 +509,16 @@ export function CreateStage({ profile, initialSlots, nextStage }: CreateStagePro
472509
/>
473510
mins
474511
</div>
512+
<div className="matcher-tiling-location-container">
513+
<div className="matcher-tiling-subheader">Location:</div>
514+
<input
515+
className="matcher-tiling-locatoin-input"
516+
type="text"
517+
ref={tileRefs.location}
518+
defaultValue={tileDetails.location}
519+
onChange={e => editTiled_location(e.target.value)}
520+
/>
521+
</div>
475522
</div>
476523
</div>
477524
<div className="matcher-sidebar-tiling-bottom">
@@ -494,32 +541,43 @@ export function CreateStage({ profile, initialSlots, nextStage }: CreateStagePro
494541
<XIcon className="icon matcher-remove-time-icon" onClick={() => deleteTime(time_idx)} />
495542
</div>
496543
<div className="matcher-created-time">
497-
<select
498-
defaultValue={time.day}
499-
key={`day_${time_idx}/${selectedEventIndices}`}
500-
onChange={e => editTime_day(time_idx, e.target.value)}
501-
>
502-
{DAYS.map(day => (
503-
<option key={day} value={day}>
504-
{DAYS_ABBREV[day]}
505-
</option>
506-
))}
507-
</select>
508-
<input
509-
type="time"
510-
key={`start_${time_idx}/${selectedEventIndices}`}
511-
defaultValue={serializeTime(time.startTime)}
512-
step="900"
513-
onChange={e => editTime_startTime(time_idx, e.target.value)}
514-
/>
515-
&#8211;
516-
<input
517-
type="time"
518-
key={`end_${time_idx}/${selectedEventIndices}`}
519-
defaultValue={serializeTime(time.endTime)}
520-
step="900"
521-
onChange={e => editTime_endTime(time_idx, e.target.value)}
522-
/>
544+
<div className="matcher-created-time-detail">
545+
<select
546+
defaultValue={time.day}
547+
key={`day_${time_idx}/${selectedEventIndices}`}
548+
onChange={e => editTime_day(time_idx, e.target.value)}
549+
>
550+
{DAYS.map(day => (
551+
<option key={day} value={day}>
552+
{DAYS_ABBREV[day]}
553+
</option>
554+
))}
555+
</select>
556+
<input
557+
type="time"
558+
key={`start_${time_idx}/${selectedEventIndices}`}
559+
defaultValue={serializeTime(time.startTime)}
560+
step="900"
561+
onChange={e => editTime_startTime(time_idx, e.target.value)}
562+
/>
563+
&#8211;
564+
<input
565+
type="time"
566+
key={`end_${time_idx}/${selectedEventIndices}`}
567+
defaultValue={serializeTime(time.endTime)}
568+
step="900"
569+
onChange={e => editTime_endTime(time_idx, e.target.value)}
570+
/>
571+
</div>
572+
<div className="matcher-created-time-location">
573+
<span>Location:</span>
574+
<input
575+
type="text"
576+
key={`location_${time_idx}/${selectedEventIndices}`}
577+
defaultValue={time.location}
578+
onChange={e => editTime_location(time_idx, e.target.value)}
579+
/>
580+
</div>
523581
</div>
524582
</div>
525583
))}
@@ -558,6 +616,8 @@ export function CreateStage({ profile, initialSlots, nextStage }: CreateStagePro
558616
<span className="matcher-selected-time">
559617
{time.day} {formatTime(time.startTime)}&#8211;{formatTime(time.endTime)}
560618
</span>
619+
<br />
620+
<span className="matcher-selected-location">(location: {time.location})</span>
561621
</li>
562622
))}
563623
</ul>

csm_web/frontend/src/components/enrollment_automation/coordinator/EditStage.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -703,7 +703,7 @@ const EditTableRow = ({
703703
* Format a datetime as a string for display.
704704
*/
705705
const displayTime = (time: Time) => {
706-
return `${DAYS_ABBREV[time.day]} ${formatTime(time.startTime)}\u2013${formatTime(time.endTime)}`;
706+
return `${DAYS_ABBREV[time.day]} ${formatTime(time.startTime)}\u2013${formatTime(time.endTime)} (${time.location})`;
707707
};
708708

709709
/**

0 commit comments

Comments
 (0)