Skip to content
Draft
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
2 changes: 1 addition & 1 deletion eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export default defineConfig(
js.configs.recommended,
tseslint.configs.strictTypeChecked,
tseslint.configs.stylisticTypeChecked,
// reactHooks.configs.flat.recommended,
reactHooks.configs.flat.recommended,
reactRefresh.configs.vite,
eslintConfigPrettier,
],
Expand Down
23 changes: 23 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
"@types/react": "^19.2.7",
"@types/react-dom": "19.2.3",
"@vitest/eslint-plugin": "^1.5.2",
"babel-plugin-react-compiler": "^1.0.0",
"eslint": "^9.39.1",
"eslint-config-prettier": "^10.1.8",
"eslint-plugin-react-hooks": "^7.0.1",
Expand All @@ -69,6 +70,7 @@
"typescript": "^5.9.3",
"typescript-eslint": "^8.48.1",
"vite": "^7.2.6",
"vite-plugin-babel": "^1.3.2",
"vite-plugin-checker": "^0.11.0",
"vite-plugin-node-polyfills": "^0.24.0",
"vite-tsconfig-paths": "^5.1.4",
Expand Down
90 changes: 45 additions & 45 deletions src/components/ActivityButtons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import {
parseColor,
} from "@chakra-ui/react";
import type { ComponentPropsWithRef, FormEvent } from "react";
import { useContext, useLayoutEffect, useState } from "react";
import { useContext, useState } from "react";

import { ColorPickerInput } from "./ui/colorpicker-input";

Expand Down Expand Up @@ -67,7 +67,7 @@ function OverrideLocations(props: { secs: Sections }) {
setRoom(secs.roomOverride);
};
const onConfirm = () => {
secs.roomOverride = room.trim();
secs.setRoomOverride(room.trim());
setIsOverriding(false);
state.updateActivities();
};
Expand Down Expand Up @@ -108,6 +108,7 @@ function OverrideLocations(props: { secs: Sections }) {

/** Div containing section manual selection interface. */
function ClassManualSections(props: { cls: Class }) {
"use no memo";
const { cls } = props;
const { state } = useContext(HydrantContext);
const genSelected = (cls: Class) =>
Expand All @@ -119,22 +120,19 @@ function ClassManualSections(props: { cls: Class }) {
: LockOption.Auto,
);
const [selected, setSelected] = useState(genSelected(cls));
useLayoutEffect(() => {
setSelected(genSelected(cls));
}, [cls]);

const RenderOptions = () => {
const getLabel = (sec: SectionLockOption, humanReadable?: boolean) => {
if (sec === LockOption.Auto) {
return humanReadable ? "Auto (default)" : LockOption.Auto;
} else if (sec === LockOption.None) {
return LockOption.None;
} else {
return humanReadable ? sec.parsedTime : sec.rawTime;
}
};

return (

const getLabel = (sec: SectionLockOption, humanReadable?: boolean) => {
if (sec === LockOption.Auto) {
return humanReadable ? "Auto (default)" : LockOption.Auto;
} else if (sec === LockOption.None) {
return LockOption.None;
} else {
return humanReadable ? sec.parsedTime : sec.rawTime;
}
};

return (
<Flex>
<>
{cls.sections.map((secs, sectionIndex) => {
const options = [LockOption.Auto, LockOption.None, ...secs.sections];
Expand Down Expand Up @@ -181,12 +179,6 @@ function ClassManualSections(props: { cls: Class }) {
);
})}
</>
);
};

return (
<Flex>
<RenderOptions />
</Flex>
);
}
Expand Down Expand Up @@ -246,8 +238,9 @@ function ActivityColor(props: { activity: Activity; onHide: () => void }) {

/** Buttons in class description to add/remove class, and lock sections. */
export function ClassButtons(props: { cls: Class }) {
"use no memo";
const { cls } = props;
const { state } = useContext(HydrantContext);
const { state, hydrantState } = useContext(HydrantContext);
const [showManual, setShowManual] = useState(false);
const [showColors, setShowColors] = useState(false);
const isSelected = state.isSelectedActivity(cls);
Expand Down Expand Up @@ -285,7 +278,9 @@ export function ClassButtons(props: { cls: Class }) {
</ToggleButton>
)}
</ButtonGroup>
{isSelected && showManual && <ClassManualSections cls={cls} />}
{isSelected && showManual && (
<ClassManualSections cls={cls} key={cls.id + hydrantState.saveId} />
)}
{isSelected && showColors && (
<ActivityColor
activity={cls}
Expand All @@ -298,6 +293,29 @@ export function ClassButtons(props: { cls: Class }) {
);
}

const RenderCheckboxes = (props: {
days: Record<string, boolean>;
setDays: React.Dispatch<React.SetStateAction<Record<string, boolean>>>;
}) => {
const { days, setDays } = props;

return (
<>
{WEEKDAY_STRINGS.map((day) => (
<Checkbox
key={day}
checked={days[day]}
onCheckedChange={(e) => {
setDays({ ...days, [day]: !!e.checked });
}}
>
{day}
</Checkbox>
))}
</>
);
};

/** Form to add a timeslot to a non-class. */
function NonClassAddTime(props: { activity: NonClass }) {
const { activity } = props;
Expand All @@ -321,24 +339,6 @@ function NonClassAddTime(props: { activity: NonClass }) {
}
};

const RenderCheckboxes = () => {
return (
<>
{WEEKDAY_STRINGS.map((day) => (
<Checkbox
key={day}
checked={days[day]}
onCheckedChange={(e) => {
setDays({ ...days, [day]: !!e.checked });
}}
>
{day}
</Checkbox>
))}
</>
);
};

const timesCollection = createListCollection({
items: TIMESLOT_STRINGS,
});
Expand Down Expand Up @@ -384,7 +384,7 @@ function NonClassAddTime(props: { activity: NonClass }) {
Add time
</Button>
<Group wrap="wrap">
<RenderCheckboxes />
<RenderCheckboxes days={days} setDays={setDays} />
</Group>
<Flex align="center" gap={1}>
{renderTimeDropdown("start")} to {renderTimeDropdown("end")}
Expand Down
4 changes: 2 additions & 2 deletions src/components/Banner.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export const Banner = () => {
color="whiteAlpha.900"
_hover={{ bg: "blackAlpha.300" }}
onClick={() => {
state.showBanner = false;
state.setShowBanner(false);
}}
/>
</Flex>
Expand All @@ -56,7 +56,7 @@ export const Banner = () => {
color="whiteAlpha.900"
_hover={{ bg: "blackAlpha.300" }}
onClick={() => {
state.showBanner = false;
state.setShowBanner(false);
}}
/>
</Float>
Expand Down
4 changes: 2 additions & 2 deletions src/components/ClassTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -311,11 +311,11 @@ function ClassFlags(props: {
// this callback needs to get called when the set of classes change, because
// the filter has to change as well
useEffect(() => {
state.fitsScheduleCallback = () => {
state.setFitsScheduleCallback(() => {
if (flags.get("fits")) {
updateFilter();
}
};
});
}, [state, flags, updateFilter]);

const onChange = (flag: Filter, value: boolean) => {
Expand Down
1 change: 1 addition & 0 deletions src/components/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import hydraAnt from "../assets/hydraAnt.png";
import { SIPBLogo } from "./SIPBLogo";

export function PreferencesDialog() {
"use no memo";
const { state, hydrantState } = useContext(HydrantContext);
const { preferences: originalPreferences } = hydrantState;

Expand Down
15 changes: 12 additions & 3 deletions src/components/ScheduleSwitcher.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {
Portal,
} from "@chakra-ui/react";
import type { ComponentPropsWithoutRef, ReactNode } from "react";
import { useContext, useEffect, useState } from "react";
import { useContext, useState } from "react";

import type { Save } from "../lib/schema";
import { HydrantContext } from "../lib/hydrant";
Expand Down Expand Up @@ -249,9 +249,18 @@ export function ScheduleSwitcher() {
const [name, setName] = useState(currentName);
const defaultScheduleId = state.defaultSchedule;

useEffect(() => {
const [prevSaves, setPrevSaves] = useState(saves);
const [prevSaveId, setPrevSaveId] = useState(saveId);

if (prevSaves !== saves) {
setPrevSaves(saves);
setName(saves.find((save) => save.id === saveId)?.name ?? "");
}

if (prevSaveId !== saveId) {
setPrevSaveId(saveId);
setName(saves.find((save) => save.id === saveId)?.name ?? "");
}, [saves, saveId]);
}

const [renderHeading, renderButtons] = (() => {
if (isRenaming) {
Expand Down
4 changes: 4 additions & 0 deletions src/lib/class.ts
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,10 @@ export class Sections {
/** Overridden location for this particular section. */
roomOverride = "";

setRoomOverride(room: string) {
this.roomOverride = room;
}

constructor(
cls: Class,
kind: SectionKind,
Expand Down
6 changes: 5 additions & 1 deletion src/lib/state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,10 @@ export class State {
this.initState();
}

setFitsScheduleCallback(callback: () => void): void {
this.fitsScheduleCallback = callback;
}

/** All activities. */
get selectedActivities(): Activity[] {
return [...this.selectedClasses, ...this.selectedNonClasses];
Expand Down Expand Up @@ -312,7 +316,7 @@ export class State {
);
}

set showBanner(show: boolean) {
setShowBanner(show: boolean) {
this.preferences.showBanner = show;
this.preferences.showBannerChanged = new Date().valueOf();
this.updateState();
Expand Down
12 changes: 12 additions & 0 deletions vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,24 @@ import { defineConfig } from "vite";
import tsconfigPaths from "vite-tsconfig-paths";
import checker from "vite-plugin-checker";
import { nodePolyfills } from "vite-plugin-node-polyfills";
import babel from "vite-plugin-babel";

const ReactCompilerConfig = {
/* ... */
};

// https://vitejs.dev/config/
export default defineConfig({
plugins: [
reactRouter(),
tsconfigPaths(),
babel({
filter: /\.[jt]sx?$/,
babelConfig: {
presets: ["@babel/preset-typescript"], // if you use TypeScript
plugins: [["babel-plugin-react-compiler", ReactCompilerConfig]],
},
}),
nodePolyfills({ include: ["buffer"] }),
checker({
typescript: true,
Expand Down
Loading