Skip to content
Merged
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
778 changes: 382 additions & 396 deletions package-lock.json

Large diffs are not rendered by default.

52 changes: 27 additions & 25 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,46 +11,48 @@
"check": "concurrently --kill-others-on-fail 'pnpm lint' 'tsc --noEmit'"
},
"dependencies": {
"@auth/drizzle-adapter": "^1.10.0",
"@auth/drizzle-adapter": "^1.11.1",
"@emotion/cache": "^11.14.0",
"@emotion/react": "^11.14.0",
"@emotion/styled": "^11.14.1",
"@hookform/resolvers": "^5.2.1",
"@mui/icons-material": "^7.3.1",
"@mui/material": "^7.3.1",
"@mui/material-nextjs": "^7.3.0",
"@mui/x-data-grid": "^8.10.0",
"@neondatabase/serverless": "^1.0.1",
"@hookform/resolvers": "^5.2.2",
"@mui/icons-material": "^7.3.6",
"@mui/material": "^7.3.6",
"@mui/material-nextjs": "^7.3.6",
"@mui/x-data-grid": "^8.22.0",
"@mui/x-date-pickers": "^8.24.0",
"@neondatabase/serverless": "^1.0.2",
"dayjs": "^1.11.19",
"dotenv": "^17.2.3",
"drizzle-orm": "^0.44.4",
"next": "15.4.10",
"next-auth": "^4.24.11",
"drizzle-orm": "^0.44.7",
"next": "15.4.6",
"next-auth": "^4.24.13",
"notistack": "^3.0.2",
"react": "19.1.0",
"react-dom": "19.1.0",
"react-hook-form": "^7.62.0",
"zod": "^4.0.17"
"react-hook-form": "^7.68.0",
"zod": "^4.1.13"
},
"devDependencies": {
"@eslint/eslintrc": "^3",
"@eslint/js": "^9.33.0",
"@next/eslint-plugin-next": "^15.4.6",
"@types/node": "^20",
"@types/react": "^19",
"@types/react-dom": "^19",
"concurrently": "^9.2.0",
"drizzle-kit": "^0.31.4",
"eslint": "^9",
"@eslint/eslintrc": "^3.3.3",
"@eslint/js": "^9.39.1",
"@next/eslint-plugin-next": "^15.5.9",
"@types/node": "^20.19.26",
"@types/react": "^19.2.7",
"@types/react-dom": "^19.2.3",
"concurrently": "^9.2.1",
"drizzle-kit": "^0.31.8",
"eslint": "^9.39.1",
"eslint-config-next": "15.4.6",
"eslint-config-prettier": "^10.1.8",
"eslint-plugin-import": "^2.32.0",
"eslint-plugin-prettier": "^5.5.4",
"eslint-plugin-simple-import-sort": "^12.1.1",
"eslint-plugin-unicorn": "^60.0.0",
"knip": "^5.62.0",
"prettier": "^3.6.2",
"tsx": "^4.20.3",
"knip": "^5.73.4",
"prettier": "^3.7.4",
"tsx": "^4.21.0",
"typescript": "5.9.2",
"typescript-eslint": "^8.39.0"
"typescript-eslint": "^8.49.0"
}
}
2,349 changes: 1,350 additions & 999 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

19 changes: 19 additions & 0 deletions src/app/filters/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
"use client";
import { Box } from "@mui/material";
import * as React from "react";

import Filters from "@/components/Filters";
import ToggleViews from "@/components/ToggleViews";

export default function FiltersPage(): React.ReactElement {
return (
<Box sx={{ display: "flex", pt: "1%" }}>
<Box sx={{ width: "70%" }}>
<Filters />
</Box>
<Box>
<ToggleViews />
</Box>
</Box>
);
}
87 changes: 87 additions & 0 deletions src/components/Filters/check-boxes.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/* Check-boxes
* Makes a vertical group of check boxes.

To use, you need three things:

These two control the state of the checkboxes

type CheckedStateTime = {
morning: boolean;
afternoon: boolean;
};

const [checkedTime, setCheckedTime] = React.useState<CheckedStateTime>({
morning: false,
afternoon: false,
});

These are the options

const times = [
{ option: "morning", label: "Morning" },
{ option: "afternoon", label: "Afternoon" },
] as const;

Example usage:
<CheckboxesGroup
checked={checkedTime}
setChecked={setCheckedTime}
options={times}
/>

*/

import Box from "@mui/material/Box";
import Checkbox from "@mui/material/Checkbox";
import FormControl from "@mui/material/FormControl";
import FormControlLabel from "@mui/material/FormControlLabel";
import FormGroup from "@mui/material/FormGroup";
import * as React from "react";

type CheckboxOption<T extends string> = {
option: T;
label: string;
};

type CheckboxesGroupProps<T extends Record<string, boolean>> = {
checked: T;
setChecked: React.Dispatch<React.SetStateAction<T>>;
options: readonly CheckboxOption<Extract<keyof T, string>>[];
};

export default function CheckboxesGroup<T extends Record<string, boolean>>(
props: CheckboxesGroupProps<T>,
): React.ReactElement {
const { checked, setChecked, options } = props;

const handleChange = (event: React.ChangeEvent<HTMLInputElement>): void => {
const name = event.target.name as keyof T;
setChecked((prev) => ({
...prev,
[name]: event.target.checked,
}));
};

return (
<Box sx={{ display: "flex" }}>
<FormControl component="fieldset" variant="standard">
<FormGroup>
{options.map((opt) => (
<FormControlLabel
key={String(opt.option)}
control={
<Checkbox
size="small"
checked={checked[opt.option]}
onChange={handleChange}
name={String(opt.option)}
/>
}
label={opt.label}
/>
))}
</FormGroup>
</FormControl>
</Box>
);
}
33 changes: 33 additions & 0 deletions src/components/Filters/date-picker.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/* Date Picker */
/* Creates two boxes that allow the user to enter a beginning date and end date */

import Box from "@mui/material/Box";
import Typography from "@mui/material/Typography";
import { AdapterDayjs } from "@mui/x-date-pickers/AdapterDayjs";
import { DatePicker } from "@mui/x-date-pickers/DatePicker";
import { LocalizationProvider } from "@mui/x-date-pickers/LocalizationProvider";
import { Dayjs } from "dayjs";
import * as React from "react";

export default function DatePickerValue(): React.ReactElement {
const [start, setStart] = React.useState<Dayjs | null>(null);
const [end, setEnd] = React.useState<Dayjs | null>(null);

return (
<LocalizationProvider dateAdapter={AdapterDayjs}>
<Box display="flex" gap={2} sx={{ alignItems: "center", pt: "1%" }}>
<DatePicker
label="Start Date"
value={start}
onChange={(newValue) => setStart(newValue)}
/>
<Typography sx={{ color: "GrayText" }}>TO</Typography>
<DatePicker
label="End Date"
value={end}
onChange={(newValue) => setEnd(newValue)}
/>
</Box>
</LocalizationProvider>
);
}
73 changes: 73 additions & 0 deletions src/components/Filters/dropdown-menu.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/* Dropdown menu prop */
/* Creates a dropdown menu with the options you pass in.
Requires the following to be used:

const [slot, setSlots] = React.useState("");
const slots = ["1", "2", "3"];
const handleChangeSlot = (event: SelectChangeEvent): void => {
setSlots(event.target.value as string);
};

Which control the selection of an option, and the options which are passed in.

Example usage:
<Dropdown
label="Slots"
value={slot}
options={slots}
onChange={handleChangeSlot}
/>
*/

import {
FormControl,
InputLabel,
MenuItem,
Select,
SelectChangeEvent,
} from "@mui/material";
import React from "react";

type DropdownProps = {
label: string;
value: string;
options: string[];
onChange: (event: SelectChangeEvent) => void;
};

export default function Dropdown({
label,
value,
options,
onChange,
}: DropdownProps): React.ReactElement {
return (
<FormControl
sx={{
// TODO: Commenting this out for now to be consisten with date-picker until that is figured out
// "& .MuiOutlinedInput-notchedOutline": { borderColor: "black" },
paddingRight: "2%",
}}
size="small"
fullWidth
>
<InputLabel id={`${label}-label`}>{label}</InputLabel>
<Select
labelId={`${label}-label`}
id={label}
value={value}
label={label}
onChange={onChange}
sx={{
"& .MuiSelect-icon": { color: "secondary" },
}}
>
{options.map((opt) => (
<MenuItem key={opt} value={opt}>
{opt}
</MenuItem>
))}
</Select>
</FormControl>
);
}
74 changes: 74 additions & 0 deletions src/components/Filters/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/*
This is the filters bar.
Has a few basic dropdowns, and a button that opens a card for more filter options.
*/
"use client";
import { Box, Button } from "@mui/material";
import { SelectChangeEvent } from "@mui/material/Select";
import * as React from "react";

import Dropdown from "./dropdown-menu";
import FiltersModal from "./modal";

export default function Filters(): React.ReactElement {
const [open, setOpen] = React.useState(false);
const [event, setEvent] = React.useState("");
const [slot, setSlots] = React.useState("");
const events = [
"Cornestone/Westland",
"Spring Semester Meal Train",
"Kappa Kappa Gamma Opportunities",
"Etc",
];
const slots = ["1", "2", "3"];
const handleChangeEvent = (event: SelectChangeEvent): void => {
setEvent(event.target.value as string);
};
const handleChangeSlot = (event: SelectChangeEvent): void => {
setSlots(event.target.value as string);
};

return (
<Box>
<Box
sx={{
display: "flex",
alignItems: "center",
justifyContent: "space-between",
width: "70%",
justifySelf: "center",
}}
>
<Box
sx={{
display: "flex",
width: "60%",
alignItems: "center",
}}
>
<Dropdown
label="Events"
value={event}
options={events}
onChange={handleChangeEvent}
/>
<Dropdown
label="Slots"
value={slot}
options={slots}
onChange={handleChangeSlot}
/>
<Button
size="large"
variant="outlined"
sx={{ color: "GrayText", borderColor: "#0000003B" }}
onClick={() => setOpen(true)}
>
Filters
</Button>
</Box>
</Box>
<FiltersModal open={open} setOpen={setOpen} />
</Box>
);
}
Loading
Loading