Skip to content

Commit

Permalink
1274 intimate partner violence (#1310)
Browse files Browse the repository at this point in the history
* 1274 Add UCSF intimate partner violence data to front-end UCSF configs

* 1274 add intimate partner violence handout and conditional logic to display it or the generic service handout

* Include host origin in domestic violence pdf image src route

* Switch out intimate partner violence icon

* Replace checklist graphic text  with html/css

* 1274 Slight updates to Intimate Partner PDF CSS. Use short description instead of long description

* 1274 Increase refinements limit on UCSF whitelabel to ensure we display all desired labels on the sidebar

* 1274 Remove anyone in need refinement from intimate partner violence

* 1274 Add function to wipe sensitvie terms from UCSF Intimate Partner Violence handouts for patient discretion. Tweak PDF styles and content to provide more room on single page

* 1274 Order Intimate Partner eligibilities by cultural/ethnic identity and alphabetize. Add optional disableGeoLocation prop to category constants

* 1274 PR clean up

* PR feedback

* 1274 Show service type/categories first in UCSF discovery steps (#1312)

Co-authored-by: Brian Schroer <[email protected]>

* 1274 24 hour availability sort (#1314)

* Sort Intimate Partner Violence results by 24/7 availability. Misc code refactors

* A few small changes

* Remove comment

* PR fix

---------

Co-authored-by: Brian Schroer <[email protected]>

* Prettier

* 1274 ipv subcategory sort (#1315)

* Remove unused eligibility tags from IPV flow

* 1274 Add logic to sort sidebar algolia subcategory refinements by the order received from the API

---------

Co-authored-by: Brian Schroer <[email protected]>

---------

Co-authored-by: Brian Schroer <[email protected]>
  • Loading branch information
schroerbrian and Brian Schroer authored Mar 1, 2024
1 parent 7066404 commit 5fcffc8
Show file tree
Hide file tree
Showing 15 changed files with 1,228 additions and 69 deletions.
6 changes: 6 additions & 0 deletions app/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import { ResourceGuides, ResourceGuide } from "./pages/ResourceGuides";
import { SearchResultsPage } from "./pages/SearchResultsPage/SearchResultsPage";
import { ServiceListingPage } from "./pages/ServiceListingPage";
import { ServicePdfPage } from "./pages/Pdf/ServicePdfPage";
import { IntimatePartnerViolencePdfPage } from "./pages/Pdf/IntimatePartnerViolencePdfPage";
import { TermsOfServicePage } from "./pages/legal/TermsOfService";
import { UcsfHomePage } from "./pages/UcsfHomePage/UcsfHomePage";
import { UcsfDiscoveryForm } from "./pages/UcsfDiscoveryForm/UcsfDiscoveryForm";
Expand Down Expand Up @@ -193,6 +194,11 @@ export const App = () => {
path="/service-handout/:id"
component={ServicePdfPage}
/>
<Route
exact
path="/intimate-partner-violence-handout/:id"
component={IntimatePartnerViolencePdfPage}
/>
<Route
exact
path="/terms-of-service"
Expand Down
Binary file added app/assets/img/domestic-violence-checklist.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
52 changes: 42 additions & 10 deletions app/components/search/SearchResults/SearchResults.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
SearchResults as SearchResultsProps,
} from "react-instantsearch/connectors";
import { whiteLabel } from "utils";
import { CATEGORIES } from "pages/ServiceDiscoveryForm/constants";
import { SearchMap } from "components/search/SearchMap/SearchMap";
import ResultsPagination from "components/search/Pagination/ResultsPagination";
import { Texting } from "components/Texting";
Expand All @@ -20,9 +21,11 @@ import styles from "./SearchResults.module.scss";
const SearchResults = ({
searchResults,
expandList,
categoryId,
}: {
searchResults: SearchResultsProps;
expandList: boolean;
categoryId?: string;
}) => {
const [centerCoords] = useState(null);
const [googleMapObject, setMapObject] = useState<google.maps.Map | null>(
Expand All @@ -42,7 +45,12 @@ const SearchResults = ({

if (!searchResults) return null;

const hits = transformHits(searchResults.hits as unknown as SearchHit[]);
const category = CATEGORIES.find((c) => c.id === categoryId);
const sortBy24HourAvailability = Boolean(category?.sortBy24HourAvailability);
const hits = transformHits(
searchResults.hits as unknown as SearchHit[],
sortBy24HourAvailability
);

return (
<div className={styles.searchResultsAndMapContainer}>
Expand All @@ -60,7 +68,12 @@ const SearchResults = ({
search term.
</div>
{hits.map((hit, index) => (
<SearchResult hit={hit} index={index} key={hit.id} />
<SearchResult
hit={hit}
index={index}
categoryId={categoryId}
key={hit.id}
/>
))}
<ResultsPagination noResults={!hits || !hits.length} />
</div>
Expand All @@ -74,10 +87,29 @@ const SearchResults = ({
);
};

const SearchResult = ({ hit, index }: { hit: SearchHit; index: number }) => {
const SearchResult = ({
hit,
index,
categoryId,
}: {
hit: SearchHit;
index: number;
categoryId: string | undefined;
}) => {
const [textingIsOpen, setTextingIsOpen] = useState(false);
const [clinicianActionsIsOpen, setClinicianActionsIsOpen] = useState(false);
const [handoutModalIsOpen, setHandoutModalIsOpen] = useState(false);
type HandoutLanguage = "es" | "tl" | "zh-TW" | "vi" | "ru" | "ar";
const handoutUrl = (hitId: number, language: HandoutLanguage | null) => {
const handoutRoute =
categoryId === "2000006"
? "intimate-partner-violence-handout"
: "service-handout";

return `/${handoutRoute}/${hitId}${
language ? `?handoutLanguage=${language}` : ""
}`;
};

let listing: TextListing;
if (hit.type === "service") {
Expand Down Expand Up @@ -210,37 +242,37 @@ const SearchResult = ({ hit, index }: { hit: SearchHit; index: number }) => {
{
key: -1,
description: "English",
url: `/service-handout/${hit.id}`,
url: handoutUrl(hit.id, null),
},
{
key: -2,
description: "Spanish",
url: `/service-handout/${hit.id}?handoutLanguage=es`,
url: handoutUrl(hit.id, "es"),
},
{
key: -3,
description: "Tagalog",
url: `/service-handout/${hit.id}?handoutLanguage=tl`,
url: handoutUrl(hit.id, "tl"),
},
{
key: -4,
description: "Chinese (Traditional)",
url: `/service-handout/${hit.id}?handoutLanguage=zh-TW`,
url: handoutUrl(hit.id, "zh-TW"),
},
{
key: -5,
description: "Vietnamese",
url: `/service-handout/${hit.id}?handoutLanguage=vi`,
url: handoutUrl(hit.id, "vi"),
},
{
key: -6,
description: "Russian",
url: `/service-handout/${hit.id}?handoutLanguage=ru`,
url: handoutUrl(hit.id, "ru"),
},
{
key: -7,
description: "Arabic",
url: `/service-handout/${hit.id}?handoutLanguage=ar`,
url: handoutUrl(hit.id, "ar"),
},
]}
/>
Expand Down
32 changes: 30 additions & 2 deletions app/components/search/Sidebar/Sidebar.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import React, { useState, useMemo } from "react";

import type { Category } from "models/Meta";

import {
eligibilitiesMapping,
categoriesMapping,
Expand All @@ -21,20 +23,42 @@ const Sidebar = ({
categorySlug = "",
subcategories = [],
subcategoryNames = [],
sortAlgoliaSubcategoryRefinements = false,
}: {
setSearchRadius: (radius: string) => void;
searchRadius: string;
isSearchResultsPage: boolean;
eligibilities?: object[];
categorySlug?: string;
subcategories?: object[];
subcategories?: Category[];
subcategoryNames?: string[];
sortAlgoliaSubcategoryRefinements?: boolean;
}) => {
const [filterMenuVisible, setfilterMenuVisible] = useState(false);
let categoryRefinementJsx: React.ReactElement | null = null;
let eligibilityRefinementJsx: React.ReactElement | null = null;
const orderByLabel = (a: { label: string }, b: { label: string }) =>
a.label.localeCompare(b.label);

const orderByPriorityRanking = (
a: { label: string },
b: { label: string }
) => {
// Our API has the ability to sort subcategories using the "child_priority_rank" on the
// CategoryRelationship table. In cases where we want to sort our sidebar categories
// following this order, we can use this sorting function, which sorts the categories
// that we receive from Algolia using the order that we get from the API.
const priorityA = subcategoryNames.indexOf(a.label);
const priorityB = subcategoryNames.indexOf(b.label);

// If an element in the data returned from Algolia does not exist in the API's ordered array
// (i.e., Algolia is out of sync with our API), move the element to the back of the list.
if (priorityA < 0) return 1;
if (priorityB < 0) return -1;

return priorityA - priorityB;
};

const onChangeValue = (evt: React.ChangeEvent<HTMLInputElement>) => {
setSearchRadius(evt.target.value);
};
Expand Down Expand Up @@ -128,7 +152,11 @@ const Sidebar = ({
transformItems={(items: { label: string }[]) =>
items
.filter(({ label }) => subcategoryNames.includes(label))
.sort(orderByLabel)
.sort(
sortAlgoliaSubcategoryRefinements
? orderByPriorityRanking
: orderByLabel
)
}
/>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ export const EligibilityRefinements = ({

return (
<>
<div className={styles.refinementsBox_title}>Client Identity</div>
<div className={styles.refinementsBox_title}>Patient Identity</div>
<ol className={styles.refinementsLabels}>
{resourceEligibilityGroups.map((eligibilityGroup) => (
<li key={eligibilityGroup.label} className={styles.listContainer}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ export const SubcategoryRefinements = ({
selectedSubcategories: SelectedSubcategories;
setSelectedSubcategories: (categories: SelectedSubcategories) => void;
}) => {
// This prevents the UI from flashing before the subcategories are fetched
if (subcategories.length === 0) return null;

// Add generic "See All" element to subcategory array if it is not there yet
if (!subcategories[0] || subcategories[0].id !== seeAllPseudoId) {
subcategories.unshift({ id: seeAllPseudoId, name: "See All" });
Expand Down
Loading

0 comments on commit 5fcffc8

Please sign in to comment.