Skip to content

Add location support for matcher #371

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ export interface Time {
startTime: number;
endTime: number;
isLinked: boolean;
location: string;
}

export interface Slot {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,8 @@ export function MentorSectionPreferences({
day: time.day,
startTime: parseTime(time.startTime),
endTime: parseTime(time.endTime),
isLinked: time.isLinked
isLinked: time.isLinked,
location: time.location
});
}
const parsed_slot: Slot = {
Expand Down Expand Up @@ -176,6 +177,8 @@ export function MentorSectionPreferences({
<li key={time_idx} className="matcher-selected-time-container">
<span className="matcher-selected-time">
{time.day} {formatTime(time.startTime)}&#8211;{formatTime(time.endTime)}
<br />
<span className="matcher-selected-location">(location: {time.location})</span>
</span>
</li>
))}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useEffect, useMemo, useRef, useState } from "react";
import React, { useEffect, useRef, useState } from "react";
import { formatTime } from "../utils";
import { CalendarDay, CalendarDayHeader } from "./CalendarDay";
import { CalendarEvent, CalendarEventSingleTime, DAYS } from "./CalendarTypes";
Expand All @@ -11,11 +11,14 @@ const SCROLL_AMT = 30;

const WIDTH_SCALE = 0.9;

const DEFAULT_LOCATION = "TBD";

interface Time {
day: string;
startTime: number;
endTime: number;
isLinked: boolean; // whether this time is linked to another within a section
location: string;
}

interface CalendarProps {
Expand Down Expand Up @@ -63,7 +66,8 @@ export function Calendar({
day: "",
startTime: -1,
endTime: -1,
isLinked: false
isLinked: false,
location: DEFAULT_LOCATION
});

const [eventExtrema, setEventExtrema] = useState<{ min: number; max: number }>({
Expand Down Expand Up @@ -222,7 +226,7 @@ export function Calendar({
if (!eventCreationEnabled) {
return;
}
setCurCreatedEvent({ day, startTime, endTime, isLinked: createdTimes.length > 0 });
setCurCreatedEvent({ day, startTime, endTime, isLinked: createdTimes.length > 0, location: DEFAULT_LOCATION });
setCreatingEvent(true);
setEventHoverIndex(-1);
setSelectedEventIndices([]);
Expand All @@ -237,7 +241,8 @@ export function Calendar({
day: curCreatedEvent.day,
startTime: curCreatedEvent.startTime,
endTime: end_time,
isLinked: curCreatedEvent.isLinked
isLinked: curCreatedEvent.isLinked,
location: curCreatedEvent.location
});
};

Expand All @@ -246,12 +251,12 @@ export function Calendar({
return;
}
onEventCreated(normalizeCreatedEvent());
setCurCreatedEvent({ day: "", startTime: -1, endTime: -1, isLinked: false });
setCurCreatedEvent({ day: "", startTime: -1, endTime: -1, isLinked: false, location: DEFAULT_LOCATION });
setCreatingEvent(false);
};

const onCreateDragEndCancel = (e: MouseEvent | FocusEvent) => {
setCurCreatedEvent({ day: "", startTime: -1, endTime: -1, isLinked: false });
setCurCreatedEvent({ day: "", startTime: -1, endTime: -1, isLinked: false, location: DEFAULT_LOCATION });
setCreatingEvent(false);
};

Expand All @@ -263,7 +268,8 @@ export function Calendar({
day: curCreatedEvent.day,
startTime: curCreatedEvent.endTime - INTERVAL_LENGTH,
endTime: curCreatedEvent.startTime + INTERVAL_LENGTH,
isLinked: curCreatedEvent.isLinked
isLinked: curCreatedEvent.isLinked,
location: "TBD"
};
}
};
Expand Down Expand Up @@ -296,8 +302,8 @@ export function Calendar({
onEventHover={
disableHover
? () => {
/* do nothing */
}
/* do nothing */
}
: setEventHoverIndex
}
onEventClick={eventClickWrapper}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ interface NumberTime {
startTime: number;
endTime: number;
isLinked: boolean;
location: string;
}

enum EventType {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ interface StrTime {
day: string;
startTime: string;
endTime: string;
location: string;
}

export function CoordinatorMatcherForm({
Expand Down Expand Up @@ -66,7 +67,8 @@ export function CoordinatorMatcherForm({
startTime: parseTime(time.startTime),
endTime: parseTime(time.endTime),
day: time.day,
isLinked: slot.times.length > 0
isLinked: slot.times.length > 0,
location: time.location
};
});
return {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,17 @@ import { formatInterval, formatTime, parseTime, serializeTime } from "../utils";

import InfoIcon from "../../../../static/frontend/img/info.svg";
import XIcon from "../../../../static/frontend/img/x.svg";
import { useMatcherConfigMutation, useMatcherSlotsMutation } from "../../../utils/queries/matcher";
import { useMatcherSlotsMutation } from "../../../utils/queries/matcher";

const DEFAULT_LOCATION = "TBD";

interface TileDetails {
days: string[];
daysLinked: boolean;
startTime: number;
endTime: number;
length: number;
location: string;
}

interface CreateStageProps {
Expand Down Expand Up @@ -61,15 +64,15 @@ export function CreateStage({ profile, initialSlots, nextStage }: CreateStagePro
daysLinked: true,
startTime: -1,
endTime: -1,
length: 60
length: 60,
location: DEFAULT_LOCATION
});

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

const matcherConfigMutation = useMatcherConfigMutation(profile.courseId);
const matcherSlotsMutation = useMatcherSlotsMutation(profile.courseId);

/**
Expand All @@ -87,7 +90,8 @@ export function CreateStage({ profile, initialSlots, nextStage }: CreateStagePro
startTime: React.createRef<HTMLInputElement>(),
endTime: React.createRef<HTMLInputElement>(),
length: React.createRef<HTMLInputElement>(),
toggle: React.createRef<HTMLInputElement>()
toggle: React.createRef<HTMLInputElement>(),
location: React.createRef<HTMLInputElement>()
};

/**
Expand All @@ -114,7 +118,8 @@ export function CreateStage({ profile, initialSlots, nextStage }: CreateStagePro
startTime: t,
endTime: t + tileDetails.length,
// linked only if there are multiple days and user wants to link them
isLinked: tileDetails.daysLinked && tileDetails.days.length > 1
isLinked: tileDetails.daysLinked && tileDetails.days.length > 1,
location: tileDetails.location
});
}
}
Expand All @@ -130,7 +135,8 @@ export function CreateStage({ profile, initialSlots, nextStage }: CreateStagePro
const times = slot.times.map(time => ({
day: time.day,
startTime: serializeTime(time.startTime),
endTime: serializeTime(time.endTime)
endTime: serializeTime(time.endTime),
location: time.location
}));
return {
...slot,
Expand Down Expand Up @@ -254,6 +260,22 @@ export function CreateStage({ profile, initialSlots, nextStage }: CreateStagePro
setCurCreatedTimes(newTimes);
};

/**
* Edit the location field of an event
*
* @param index index of time to edit
* @param newLocation new location value
*/
const editTime_location = (index: number, newLocation: string) => {
const newTimes = [...curCreatedTimes];
if (newLocation.trim() === "") {
newTimes[index]["location"] = DEFAULT_LOCATION;
} else {
newTimes[index]["location"] = newLocation;
}
setCurCreatedTimes(newTimes);
};

const toggleCreatingTiledEvents = (e: React.ChangeEvent<HTMLInputElement>): void => {
// current value of checkbox after click
const checked = e.target.checked;
Expand Down Expand Up @@ -297,6 +319,10 @@ export function CreateStage({ profile, initialSlots, nextStage }: CreateStagePro
setTileDetails({ ...tileDetails, daysLinked: e.target.checked });
};

const editTiled_location = (value: string): void => {
setTileDetails({ ...tileDetails, location: value });
};

const saveTiledEvents = () => {
const newSlots = [];
for (let t = tileDetails.startTime; t <= tileDetails.endTime - tileDetails.length; t += tileDetails.length) {
Expand All @@ -307,17 +333,28 @@ export function CreateStage({ profile, initialSlots, nextStage }: CreateStagePro
day: day,
startTime: t,
endTime: t + tileDetails.length,
isLinked: tileDetails.days.length > 1
isLinked: tileDetails.days.length > 1,
location: tileDetails.location
});
}
newSlots.push(newEvent);
} else {
for (const day of tileDetails.days) {
newSlots.push({ times: [{ day: day, startTime: t, endTime: t + tileDetails.length, isLinked: false }] });
newSlots.push({
times: [
{
day: day,
startTime: t,
endTime: t + tileDetails.length,
isLinked: false,
location: tileDetails.location
}
]
});
}
}
}
setSlots([...slots, ...newSlots]);
setSlots([...slots, ...newSlots] as Slot[]);
// stop creating tiled events
tileRefs.toggle.current!.checked = false;
toggleCreatingTiledEvents({ target: tileRefs.toggle.current! } as React.ChangeEvent<HTMLInputElement>);
Expand All @@ -327,7 +364,7 @@ export function CreateStage({ profile, initialSlots, nextStage }: CreateStagePro
* Save the newly created event and times
*/
const saveEvent = () => {
const newEvent = { times: curCreatedTimes };
const newEvent: Slot = { times: curCreatedTimes };
setSlots([...slots, newEvent]);
setCurCreatedTimes([]);
setSavedExistingEvent(null);
Expand All @@ -340,7 +377,7 @@ export function CreateStage({ profile, initialSlots, nextStage }: CreateStagePro
*/
const cancelEvent = () => {
if (savedExistingEvent !== null) {
setSlots([...slots, savedExistingEvent]);
setSlots([...slots, savedExistingEvent] as Slot[]);
setSavedExistingEvent(null);
}
// proceed with resetting current event
Expand Down Expand Up @@ -472,6 +509,16 @@ export function CreateStage({ profile, initialSlots, nextStage }: CreateStagePro
/>
mins
</div>
<div className="matcher-tiling-location-container">
<div className="matcher-tiling-subheader">Location:</div>
<input
className="matcher-tiling-locatoin-input"
type="text"
ref={tileRefs.location}
defaultValue={tileDetails.location}
onChange={e => editTiled_location(e.target.value)}
/>
</div>
</div>
</div>
<div className="matcher-sidebar-tiling-bottom">
Expand All @@ -494,32 +541,43 @@ export function CreateStage({ profile, initialSlots, nextStage }: CreateStagePro
<XIcon className="icon matcher-remove-time-icon" onClick={() => deleteTime(time_idx)} />
</div>
<div className="matcher-created-time">
<select
defaultValue={time.day}
key={`day_${time_idx}/${selectedEventIndices}`}
onChange={e => editTime_day(time_idx, e.target.value)}
>
{DAYS.map(day => (
<option key={day} value={day}>
{DAYS_ABBREV[day]}
</option>
))}
</select>
<input
type="time"
key={`start_${time_idx}/${selectedEventIndices}`}
defaultValue={serializeTime(time.startTime)}
step="900"
onChange={e => editTime_startTime(time_idx, e.target.value)}
/>
&#8211;
<input
type="time"
key={`end_${time_idx}/${selectedEventIndices}`}
defaultValue={serializeTime(time.endTime)}
step="900"
onChange={e => editTime_endTime(time_idx, e.target.value)}
/>
<div className="matcher-created-time-detail">
<select
defaultValue={time.day}
key={`day_${time_idx}/${selectedEventIndices}`}
onChange={e => editTime_day(time_idx, e.target.value)}
>
{DAYS.map(day => (
<option key={day} value={day}>
{DAYS_ABBREV[day]}
</option>
))}
</select>
<input
type="time"
key={`start_${time_idx}/${selectedEventIndices}`}
defaultValue={serializeTime(time.startTime)}
step="900"
onChange={e => editTime_startTime(time_idx, e.target.value)}
/>
&#8211;
<input
type="time"
key={`end_${time_idx}/${selectedEventIndices}`}
defaultValue={serializeTime(time.endTime)}
step="900"
onChange={e => editTime_endTime(time_idx, e.target.value)}
/>
</div>
<div className="matcher-created-time-location">
<span>Location:</span>
<input
type="text"
key={`location_${time_idx}/${selectedEventIndices}`}
defaultValue={time.location}
onChange={e => editTime_location(time_idx, e.target.value)}
/>
</div>
</div>
</div>
))}
Expand Down Expand Up @@ -558,6 +616,8 @@ export function CreateStage({ profile, initialSlots, nextStage }: CreateStagePro
<span className="matcher-selected-time">
{time.day} {formatTime(time.startTime)}&#8211;{formatTime(time.endTime)}
</span>
<br />
<span className="matcher-selected-location">(location: {time.location})</span>
</li>
))}
</ul>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -703,7 +703,7 @@ const EditTableRow = ({
* Format a datetime as a string for display.
*/
const displayTime = (time: Time) => {
return `${DAYS_ABBREV[time.day]} ${formatTime(time.startTime)}\u2013${formatTime(time.endTime)}`;
return `${DAYS_ABBREV[time.day]} ${formatTime(time.startTime)}\u2013${formatTime(time.endTime)} (${time.location})`;
};

/**
Expand Down
Loading