Skip to content

Commit 8479c79

Browse files
authored
kl/SCRUM-129: Fix restriction and form related bugs (#67)
Co-authored-by: kevin-lann <[email protected]>
1 parent 2c6d152 commit 8479c79

File tree

5 files changed

+110
-12
lines changed

5 files changed

+110
-12
lines changed

course-matrix/frontend/src/components/time-picker-hr.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ export function TimePickerHr({ date, setDate }: TimePickerHrProps) {
6060
</div> */}
6161
<div className="grid gap-1 text-center">
6262
<Label htmlFor="period" className="text-xs">
63-
Period
63+
AM/PM
6464
</Label>
6565
<TimePeriodSelect
6666
period={period}

course-matrix/frontend/src/models/timetable-form.ts

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,40 @@ export const RestrictionSchema = z
177177
message: "Number must be at least 1",
178178
path: ["numDays"],
179179
},
180+
)
181+
.refine(
182+
(data) => {
183+
if (
184+
data.type &&
185+
data.type === "Restrict Before" &&
186+
data.endTime?.getHours() === 0 &&
187+
data.endTime?.getMinutes() === 0
188+
) {
189+
return false;
190+
}
191+
return true;
192+
},
193+
{
194+
message: "Cannot restrict whole day",
195+
path: ["endTime"],
196+
},
197+
)
198+
.refine(
199+
(data) => {
200+
if (
201+
data.type &&
202+
data.type === "Restrict After" &&
203+
data.startTime?.getHours() === 0 &&
204+
data.startTime?.getMinutes() === 0
205+
) {
206+
return false;
207+
}
208+
return true;
209+
},
210+
{
211+
message: "Cannot restrict whole day",
212+
path: ["startTime"],
213+
},
180214
);
181215

182216
export const TimetableFormSchema: ZodType<TimetableForm> = z
@@ -208,6 +242,26 @@ export const TimetableFormSchema: ZodType<TimetableForm> = z
208242
message: "Cannot pick more than 8 courses",
209243
path: ["search"],
210244
},
245+
)
246+
.refine(
247+
(data) => {
248+
return !(
249+
data.restrictions.filter((r) => r.type === "Days Off").length > 1
250+
);
251+
},
252+
{
253+
message: "Already added minimum days off per week",
254+
path: ["restrictions"],
255+
},
256+
)
257+
.refine(
258+
(data) => {
259+
return !hasDuplicate(data.restrictions);
260+
},
261+
{
262+
message: "Duplicate restriction detected. Please remove.",
263+
path: ["restrictions"],
264+
},
211265
);
212266

213267
export const baseTimetableForm: TimetableForm = {
@@ -224,3 +278,23 @@ export const baseRestrictionForm: RestrictionForm = {
224278
days: [],
225279
disabled: false,
226280
};
281+
282+
function hasDuplicate(restrictions: RestrictionForm[]) {
283+
const seen: RestrictionForm[] = [];
284+
for (const r of restrictions) {
285+
if (
286+
seen.some(
287+
(s) =>
288+
s.type === r.type &&
289+
((s.numDays && r.numDays && s.numDays === r.numDays) ||
290+
(s.days?.sort().join(" ") === r.days?.sort().join(" ") &&
291+
s.startTime?.getHours() === r.startTime?.getHours() &&
292+
s.endTime?.getHours() === s.endTime?.getHours())),
293+
)
294+
) {
295+
return true;
296+
}
297+
seen.push(r);
298+
}
299+
return false;
300+
}

course-matrix/frontend/src/pages/TimetableBuilder/CourseSearch.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ const CourseSearch = ({
8181
const handleAddCourse = (item: CourseModel) => {
8282
if (!form) return;
8383
const currentList = form.getValues("courses") || [];
84+
if (currentList.length > 7) return; // ensure max courses added is 8
8485
if (currentList.find((c) => c.id === item.id)) return; // ensure uniqueness
8586
const newList = [...currentList, item];
8687
console.log(newList);

course-matrix/frontend/src/pages/TimetableBuilder/CreateCustomSetting.tsx

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,16 @@ const CreateCustomSetting = ({
9696
closeHandler();
9797
};
9898

99+
const form = useContext(FormContext);
100+
101+
const isDaysOffRestrictionApplied = () => {
102+
const val = form
103+
?.getValues("restrictions")
104+
.some((r) => r.type === "Days Off");
105+
console.log(val);
106+
return val;
107+
};
108+
99109
const getRestrictionType = (value: string) => {
100110
if (
101111
value === "Restrict Before" ||
@@ -166,7 +176,10 @@ const CreateCustomSetting = ({
166176
<SelectItem value="Restrict Day">
167177
Restrict Entire Day
168178
</SelectItem>
169-
<SelectItem value="Days Off">
179+
<SelectItem
180+
value="Days Off"
181+
disabled={isDaysOffRestrictionApplied()}
182+
>
170183
Enforce Minimum Days Off Per Week
171184
</SelectItem>
172185
</SelectContent>

course-matrix/frontend/src/pages/TimetableBuilder/TimetableBuilder.tsx

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,7 @@ const TimetableBuilder = () => {
292292
</div>
293293
<div className="flex flex-col">
294294
<p className="text-sm pb-2">
295-
Selected courses: {selectedCourses.length}
295+
Selected courses: {selectedCourses.length} (Max 8)
296296
</p>
297297
<div className="flex gap-2 flex-col">
298298
{selectedCourses.map((course, index) => (
@@ -332,9 +332,18 @@ const TimetableBuilder = () => {
332332
</div>
333333

334334
<div className="flex flex-col">
335-
<p className="text-sm pb-2">
336-
Enabled Restrictions: {enabledRestrictions.length}
337-
</p>
335+
<FormField
336+
control={form.control}
337+
name="restrictions"
338+
render={({ field }) => (
339+
<FormItem className="pb-2">
340+
<p className="text-sm">
341+
Enabled Restrictions: {enabledRestrictions.length}
342+
</p>
343+
<FormMessage />
344+
</FormItem>
345+
)}
346+
/>
338347
<div className="flex gap-2 flex-col">
339348
{enabledRestrictions.map((restric, index) => (
340349
<div
@@ -372,18 +381,19 @@ const TimetableBuilder = () => {
372381

373382
<Button type="submit">Generate</Button>
374383
</form>
384+
385+
{isCustomSettingsOpen && (
386+
<CreateCustomSetting
387+
submitHandler={handleAddRestriction}
388+
closeHandler={() => setIsCustomSettingsOpen(false)}
389+
/>
390+
)}
375391
</FormContext.Provider>
376392
</Form>
377393
</div>
378394
<div className="w-3/5">
379395
<Calendar courseEvents={courseEvents} userEvents={userEvents} />
380396
</div>
381-
{isCustomSettingsOpen && (
382-
<CreateCustomSetting
383-
submitHandler={handleAddRestriction}
384-
closeHandler={() => setIsCustomSettingsOpen(false)}
385-
/>
386-
)}
387397

388398
{showFilters && (
389399
<SearchFilters

0 commit comments

Comments
 (0)