Skip to content

Commit

Permalink
Migrate search refinement files to TypeScript.
Browse files Browse the repository at this point in the history
  • Loading branch information
richardxia committed Sep 15, 2023
1 parent 4d86727 commit 62ceaeb
Show file tree
Hide file tree
Showing 10 changed files with 98 additions and 76 deletions.
26 changes: 0 additions & 26 deletions app/components/search/Refinements/ClearAllFilters.jsx

This file was deleted.

26 changes: 26 additions & 0 deletions app/components/search/Refinements/ClearAllFilters.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import React from "react";
import { connectCurrentRefinements } from "react-instantsearch/connectors";
import type { Refinement, RefinementValue } from "react-instantsearch-core";
import styles from "./RefinementFilters.module.scss";

type Props = {
items: Refinement[];
refine: (value: Refinement[] | RefinementValue | RefinementValue[]) => void;
setSearchRadius: (radius: string) => void;
};

const ClearAllFilter = ({ items, refine, setSearchRadius }: Props) => (
<div
role="button"
tabIndex={0}
className={styles.clearAll}
onClick={() => {
refine(items);
setSearchRadius("all");
}}
>
Clear all
</div>
);

export default connectCurrentRefinements<Props>(ClearAllFilter);
Original file line number Diff line number Diff line change
@@ -1,13 +1,31 @@
import React, { Component } from "react";
import PropTypes from "prop-types";
import { connectRefinementList } from "react-instantsearch/connectors";
import type { Hit } from "react-instantsearch-core";
import styles from "./RefinementFilters.module.scss";

type Item = {
count: number;
isRefined: boolean;
label: string;
value: string[];
};

type Props = {
items: Hit<Item>[];
refine: (value: string[]) => void;
currentRefinement: string[];
mapping: Record<string, string[]>;
};

type State = {
isChecked: Record<string, boolean>;
};

// Todo: This component could potentially be consolidated with the the Refinement List Filter
// component when categories/eligibilities are standardized across the homepage Service
// Pathways results and the Search Results pages
class FacetRefinementList extends Component {
constructor(props) {
class FacetRefinementList extends Component<Props, State> {
constructor(props: Props) {
super(props);
this.changeRefinement = this.changeRefinement.bind(this);
this.setChecks = this.setChecks.bind(this);
Expand All @@ -17,7 +35,7 @@ class FacetRefinementList extends Component {
};
}

componentDidUpdate(prevProps) {
componentDidUpdate(prevProps: Props) {
const { currentRefinement } = this.props;
if (
currentRefinement.sort().join(",") !==
Expand All @@ -29,17 +47,17 @@ class FacetRefinementList extends Component {
}
}

setChecks() {
setChecks(): Record<string, boolean> {
const { mapping } = this.props;
const mapKeys = Object.keys(mapping);
const checks = {};
const checks: Record<string, boolean> = {};
mapKeys.forEach((key) => {
checks[key] = this.keyHasAtLeastOneRefined(key);
});
return checks;
}

changeRefinement(key) {
changeRefinement(key: string) {
// eslint-disable-line no-unused-vars
const { refine } = this.props;
const { currentRefinement } = this.props;
Expand All @@ -58,13 +76,13 @@ class FacetRefinementList extends Component {
refine(newRefinement);
}

keyHasAtLeastOneRefined(key) {
keyHasAtLeastOneRefined(key: string) {
const { currentRefinement } = this.props;
const { mapping } = this.props;
return mapping[key].some((value) => currentRefinement.includes(value));
}

refinementHasResults(key) {
refinementHasResults(key: string) {
// this check that a key (checkbox) has at least one sub-elements that is refined
// e.g if Learning Disabilities is can be refined but not Visual Impairment,
// Disability is still enabled as a checkbox
Expand Down Expand Up @@ -109,10 +127,4 @@ class FacetRefinementList extends Component {
}
}

FacetRefinementList.propTypes = {
items: PropTypes.array.isRequired,
refine: PropTypes.func.isRequired,
currentRefinement: PropTypes.array.isRequired,
};

export default connectRefinementList(FacetRefinementList);
export default connectRefinementList<Props>(FacetRefinementList);
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import React from "react";
import PropTypes from "prop-types";
import { connectRefinementList } from "react-instantsearch/connectors";
import { getCurrentDayTime } from "utils/index";
import styles from "./RefinementFilters.module.scss";

type Props = {
currentRefinement: string[];
refine: (value: string[]) => void;
};

/**
* A custom Algolia InstantSearch RefinementList widget representing the Open
* Now checkbos.
Expand All @@ -21,7 +25,7 @@ import styles from "./RefinementFilters.module.scss";
* filter should filter for organizations or services which have 'Su-10:00' in
* the open_times array.
*/
const OpenNowFilter = ({ currentRefinement, refine }) => {
const OpenNowFilter = ({ currentRefinement, refine }: Props) => {
const isActive = currentRefinement.length !== 0;
const toggleRefinement = () => {
if (isActive) {
Expand All @@ -39,17 +43,12 @@ const OpenNowFilter = ({ currentRefinement, refine }) => {
name="openNow"
id="openNow"
className={styles.refinementInput}
value={isActive}
value="openNow"
checked={isActive}
onChange={toggleRefinement}
/>
</label>
);
};

OpenNowFilter.propTypes = {
currentRefinement: PropTypes.arrayOf(PropTypes.string).isRequired,
refine: PropTypes.func.isRequired,
};

export default connectRefinementList(OpenNowFilter);
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import React from "react";
import PropTypes from "prop-types";
import { connectRefinementList } from "react-instantsearch/connectors";
import { getCurrentDayTime } from "utils/index";

type Props = {
currentRefinement: string[];
refine: (value: string[]) => void;
};

/**
* A custom Algolia InstantSearch RefinementList widget representing the Open
* Now button.
Expand All @@ -20,7 +24,7 @@ import { getCurrentDayTime } from "utils/index";
* filter should filter for organizations or services which have 'Su-10:00' in
* the open_times array.
*/
const OpenNowRefinementList = ({ currentRefinement, refine }) => {
const OpenNowRefinementList = ({ currentRefinement, refine }: Props) => {
const isActive = currentRefinement.length !== 0;
const toggleRefinement = () => {
if (isActive) {
Expand All @@ -40,9 +44,4 @@ const OpenNowRefinementList = ({ currentRefinement, refine }) => {
);
};

OpenNowRefinementList.propTypes = {
currentRefinement: PropTypes.arrayOf(PropTypes.string).isRequired,
refine: PropTypes.func.isRequired,
};

export default connectRefinementList(OpenNowRefinementList);
Original file line number Diff line number Diff line change
@@ -1,9 +1,19 @@
import React from "react";
import PropTypes from "prop-types";
import { connectRefinementList } from "react-instantsearch/connectors";
import styles from "./RefinementFilters.module.scss";

const RefinementListFilter = ({ items, refine }) => (
type Item = {
label: string;
value: string[];
count: number;
isRefined: boolean;
};

type Props = {
items: Item[];
refine: (value: string[]) => void;
};
const RefinementListFilter = ({ items, refine }: Props) => (
<ul>
{items.map((item) => (
<label key={item.label} className={styles.checkBox}>
Expand All @@ -21,16 +31,4 @@ const RefinementListFilter = ({ items, refine }) => (
</ul>
);

RefinementListFilter.propTypes = {
items: PropTypes.arrayOf(
PropTypes.shape({
label: PropTypes.string.isRequired,
value: PropTypes.arrayOf(PropTypes.string).isRequired,
count: PropTypes.number.isRequired,
isRefined: PropTypes.bool.isRequired,
})
).isRequired,
refine: PropTypes.func.isRequired,
};

export default connectRefinementList(RefinementListFilter);
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,19 @@ import { Link } from "react-router-dom";
import ReactMarkdown from "react-markdown";
import whiteLabel from "utils/whitelabel";
import { RelativeOpeningTime } from "components/listing/RelativeOpeningTime";
import type { SearchHit } from "models/SearchHits";
import "./SearchEntry.scss";

const {
appImages: { mohcdSeal },
} = whiteLabel;

export default class SearchEntry extends Component {
type Props = {
hitNumber: string;
hit: SearchHit;
};

export default class SearchEntry extends Component<Props> {
renderAddressMetadata() {
const { hit } = this.props;
const { addresses: rawAddresses } = hit;
Expand Down
2 changes: 1 addition & 1 deletion app/components/search/Sidebar/Sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ const Sidebar = ({
subcategories = [],
subcategoryNames = [],
}: {
setSearchRadius: (radius: any) => void;
setSearchRadius: (radius: string) => void;
searchRadius: string;
isSearchResultsPage: boolean;
eligibilities?: object[];
Expand Down
14 changes: 11 additions & 3 deletions app/models/SearchHits.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,28 @@ import { ScheduleDay, parseAlgoliaSchedule } from "./Schedule";
import { PhoneNumber } from "./Meta";
import { RecurringSchedule } from "./RecurringSchedule";

interface BaseHit {
_geoloc: { lat: number; lng: number };
is_mohcd_funded: boolean;
resource_id: number;
}

export interface ServiceHit
extends Omit<Service, "schedule" | "recurringSchedule" | "instructions"> {
extends Omit<Service, "schedule" | "recurringSchedule" | "instructions">,
BaseHit {
type: "service";
instructions: string[];
phones: PhoneNumber[];
recurringSchedule: RecurringSchedule | null;
resource_id: number;
resource_schedule: ScheduleDay[];
schedule: ScheduleDay[];
service_id: number;
service_of: string;
}

export interface OrganizationHit
extends Omit<Organization, "schedule" | "recurringSchedule"> {
extends Omit<Organization, "schedule" | "recurringSchedule">,
BaseHit {
type: "resource";
schedule: ScheduleDay[];
recurringSchedule: RecurringSchedule | null;
Expand Down
File renamed without changes.

0 comments on commit 62ceaeb

Please sign in to comment.