Skip to content
This repository has been archived by the owner on Mar 20, 2024. It is now read-only.

Commit

Permalink
Merge branch 'main' into bug/a11y-pt1
Browse files Browse the repository at this point in the history
  • Loading branch information
gmrabian authored Mar 19, 2024
2 parents 7119674 + 7730bb2 commit 6251b34
Show file tree
Hide file tree
Showing 8 changed files with 323 additions and 81 deletions.
14 changes: 7 additions & 7 deletions src/app/components/form/CheckboxField.tsx
Original file line number Diff line number Diff line change
@@ -1,26 +1,26 @@
import { FieldValues, UseFormRegister } from "react-hook-form";
import { CheckboxOptions } from "../../types";

export const CheckboxField = ({ id, name, registerField, options }: Props) => {
return (
<div className="usa-checkbox" id={id} {...registerField(`${name}`)}>
export const CheckboxField = ({ name, registerField, options }: Props) => (
<fieldset className="usa-fieldset">
<div>
{options.map((option: CheckboxOptions) => (
<div key={option.id}>
<div className="usa-checkbox" key={option.id}>
<input
className="usa-checkbox__input"
id={option.id}
type="checkbox"
name={option.id}
value={option.id}
{...registerField(`${name}`)}
/>
<label className="usa-checkbox__label" htmlFor={option.id}>
{option.label}
</label>
</div>
))}
</div>
);
};
</fieldset>
);

type Props = {
id: string;
Expand Down
4 changes: 2 additions & 2 deletions src/app/components/form/DropdownField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,10 @@ export const DropdownField = ({
<select
className="usa-select"
id={id}
{...registerField(`${name}`, { required: required })}
{...registerField(`${name}`)}
aria-describedby={hint?.id}
>
<option>- Select -</option>
<option value={undefined}>- Select -</option>
{options.map((option: DropdownOptions) => (
<option key={option.id} value={option.id}>
{option.label}
Expand Down
12 changes: 11 additions & 1 deletion src/app/components/institutions/InstitutionProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,25 @@ import { College } from "../../types";

export interface InstitutionContextShape {
institutionsArray: College[] | undefined;
filteredInstitutions: College[] | [] | undefined;
setFilteredInstitutions: Function;
institutionsObject: { [key: string]: College } | undefined;
}

export const InstitutionContext = createContext<InstitutionContextShape>({
institutionsArray: undefined as College[] | undefined,
filteredInstitutions: [] as College[] | [] | undefined,
setFilteredInstitutions: Function,
institutionsObject: undefined as { [key: string]: College } | undefined,
});

export const InstitutionProvider = ({ children }: Props) => {
const [institutionsArray, setInstitutionsArray] = useState<
College[] | undefined
>();
const [filteredInstitutions, setFilteredInstitutions] = useState<
College[] | undefined
>();
const [institutionsObject, setInstitutionsObject] = useState<
{ [key: string]: College } | undefined
>();
Expand All @@ -26,6 +33,7 @@ export const InstitutionProvider = ({ children }: Props) => {
try {
const result = await getInstitutions();
setInstitutionsArray(result);
setFilteredInstitutions(result);
// create object from array, indexed by institution id
const objectForm: { [key: string]: College } = result.reduce(
(acc, val) => ({ ...acc, [val.id]: val }),
Expand All @@ -44,9 +52,11 @@ export const InstitutionProvider = ({ children }: Props) => {
const providerValue = useMemo(
() => ({
institutionsArray,
filteredInstitutions,
setFilteredInstitutions,
institutionsObject,
}),
[institutionsArray, institutionsObject],
[institutionsArray, filteredInstitutions, institutionsObject],
);

return (
Expand Down
24 changes: 15 additions & 9 deletions src/app/components/layout/Browse.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { College } from "../../types";
import arrow_upward from "../../assets/icons/arrow_upward.svg";

export const Browse = () => {
const { institutionsArray } = useContext(InstitutionContext);
const { filteredInstitutions } = useContext(InstitutionContext);
const [scrollPosition, setScrollPosition] = useState<boolean>(false);
const [isModalVisible, setIsModalVisible] = useState<boolean>(false);

Expand All @@ -31,10 +31,10 @@ export const Browse = () => {
setIsModalVisible(true);
};

if (!filteredInstitutions) return <Spinner />;
return (
<>
{!institutionsArray && <Spinner />}
{institutionsArray && (
{filteredInstitutions && (
<div className="browse_header">
<h2 className="browse_header-title">Browse colleges</h2>
<p className="site_text-intro browse_header-subtitle">
Expand All @@ -48,12 +48,18 @@ export const Browse = () => {
{isModalVisible && (
<FilterModal closeHandler={() => setIsModalVisible(false)} />
)}
<ul className="usa-card-group">
{institutionsArray?.map((school: College) => (
<CollegeCard key={school.id} college={school} />
))}
</ul>
{institutionsArray && scrollPosition && (
{filteredInstitutions?.length > 0 ? (
<ul className="usa-card-group">
{filteredInstitutions.map((school: College) => (
<CollegeCard key={school.id} college={school} />
))}
</ul>
) : (
<p className="site_text-intro browse_header-subtitle">
No matches found for filters.
</p>
)}
{filteredInstitutions.length > 0 && scrollPosition && (
<Button
type="button"
className="browse_back-to-top-button"
Expand Down
129 changes: 69 additions & 60 deletions src/app/components/modals/FilterModal.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { MouseEventHandler } from "react";
"use client";
import { MouseEventHandler, useContext } from "react";
import {
Button,
ButtonGroup,
Expand All @@ -7,25 +8,34 @@ import {
} from "@trussworks/react-uswds";
import Image from "next/image";
import close from "../../assets/icons/close.svg";
import { CollegeType, stateOptions } from "../../types";

import { CheckboxField } from "../form/CheckboxField";
import { DropdownField } from "../form/DropdownField";
import { useForm } from "react-hook-form";
import { InstitutionContext } from "../institutions/InstitutionProvider";
import { filterInstitutions } from "../../utils/filtering";

export const FilterModal = ({ closeHandler }: Props) => {
const { handleSubmit, register } = useForm();
const form = useForm();
const { institutionsArray, setFilteredInstitutions } =
useContext(InstitutionContext);
// const [filterState, setFilterState] = useState<Object | undefined>(undefined);

const closeModal = () => {
closeHandler();
// TODO: Add tracking
};

const applyFilters = (data: any) => {
// eslint-disable-next-line no-console
console.log(data);
// TODO: handle data
// TODO: Add tracking
const applyFilters = async (filters: any) => {
// TODO: persist filters
const filteredInstitutions = filterInstitutions(
institutionsArray!,
filters,
);
setFilteredInstitutions(filteredInstitutions);
closeHandler();
// TODO: Add tracking
};

return (
Expand All @@ -36,22 +46,18 @@ export const FilterModal = ({ closeHandler }: Props) => {
aria-describedby="modal-1-description"
>
<div data-testid="modalOverlay" className="usa-modal-overlay">
<form onSubmit={handleSubmit(applyFilters)}></form>
<div className="usa-modal usa-modal--lg" tabIndex={-1}>
<ModalHeading>Filter schools</ModalHeading>
<fieldset className="usa-fieldset">
<form id="" onSubmit={form.handleSubmit(applyFilters)}>
<div className="usa-modal usa-modal--lg" tabIndex={-1}>
<ModalHeading>Filter schools</ModalHeading>
<div className="filter_section">
<p className="filter_section-heading">Location</p>
<DropdownField
id="filter-state"
name="filter-state"
label="State"
required={false}
options={[
{ id: "1", label: "first one" },
{ id: "2", label: "second one" },
]}
registerField={register}
options={stateOptions}
registerField={form.register}
/>
</div>
<div className="filter_section">
Expand All @@ -60,10 +66,11 @@ export const FilterModal = ({ closeHandler }: Props) => {
id="filter-type"
name="filter-type"
options={[
{ id: "public", label: "Public" },
{ id: "private", label: "Private" },
{ id: CollegeType.PUBLIC, label: CollegeType.PUBLIC },
{ id: CollegeType.PRIVATE_NP, label: CollegeType.PRIVATE_NP },
{ id: CollegeType.PRIVATE_FP, label: CollegeType.PRIVATE_FP },
]}
registerField={register}
registerField={form.register}
/>
</div>
<div className="filter_section">
Expand All @@ -72,12 +79,13 @@ export const FilterModal = ({ closeHandler }: Props) => {
id="filter-undergrad-pop"
name="filter-undergrad-pop"
options={[
{ id: "1-3", label: "1,000 - 3,000" },
{ id: "3-10", label: "3,000 - 10,000" },
{ id: "<2", label: "Less than 2,000" },
{ id: "2-5", label: "2,000 - 5,000" },
{ id: "5-10", label: "5,000 - 10,000" },
{ id: "10-20", label: "10,000 - 20,000" },
{ id: ">20", label: "20,000 +" },
]}
registerField={register}
registerField={form.register}
/>
</div>
<div className="filter_section">
Expand All @@ -87,11 +95,11 @@ export const FilterModal = ({ closeHandler }: Props) => {
name="filter-grad-rate"
options={[
{ id: ">90", label: "More than 90%" },
{ id: "50-90", label: "50% - 90%" },
{ id: "25-50", label: "25% - 50%" },
{ id: "<25", label: "Less than 25%" },
{ id: "60-90", label: "60% - 90%" },
{ id: "30-60", label: "30% - 60%" },
{ id: "<30", label: "Less than 30%" },
]}
registerField={register}
registerField={form.register}
/>
</div>
<div className="filter_section">
Expand All @@ -100,44 +108,45 @@ export const FilterModal = ({ closeHandler }: Props) => {
id="filter-avg-cost-per-year"
name="filter-avg-cost-per-year"
options={[
{ id: "<10>", label: "Less than $10,000" },
{ id: "10-30", label: "$10,000 - $30,000" },
{ id: "30-60", label: "$30,000 - $60,000" },
{ id: "<10", label: "Less than $10,000" },
{ id: "10-20", label: "$10,000 - $20,000" },
{ id: "20-40", label: "$20,000 - $40,000" },
{ id: "40-60", label: "$40,000 - $60,000" },
{ id: ">60", label: "More than $60,000" },
]}
registerField={register}
registerField={form.register}
/>
</div>
</fieldset>
<ModalFooter>
<ButtonGroup>
<Button type="submit">Apply Filters</Button>
<Button
type="button"
onClick={closeModal}
unstyled
className="padding-105 text-center"
>
Close
</Button>
</ButtonGroup>
</ModalFooter>
<button
type="button"
className="usa-button usa-modal__close filter_close"
aria-label="Close this window"
data-close-modal
onClick={closeModal as MouseEventHandler}
>
<Image
src={close}
className="filter-modal_icon-image"
height="30"
width="30"
alt="close icon"
/>
</button>
</div>
<ModalFooter>
<ButtonGroup>
<Button type="submit">Apply Filters</Button>
<Button
type="button"
onClick={closeModal}
unstyled
className="padding-105 text-center"
>
Close
</Button>
</ButtonGroup>
</ModalFooter>
<button
type="button"
className="usa-button usa-modal__close filter_close"
aria-label="Close this window"
data-close-modal
onClick={closeModal as MouseEventHandler}
>
<Image
src={close}
className="filter-modal_icon-image"
height="30"
width="30"
alt="close icon"
/>
</button>
</div>
</form>
</div>
</div>
);
Expand Down
3 changes: 1 addition & 2 deletions src/app/testing/jest/frontend/Homepage.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,7 @@ jest.mock("../../../utils/institutions", () => ({
describe("Test Homepage", () => {
test("Check that page renders", async () => {
render(await Home());
expect(screen.queryAllByText("Browse colleges").length).toBe(0);
expect(screen.getByTitle("spinner")).toBeVisible();
expect(screen.queryAllByText("Browse colleges")[0]).toBeVisible();
});
});

Expand Down
Loading

0 comments on commit 6251b34

Please sign in to comment.