Skip to content

Commit

Permalink
[OUR415-300] Adds fallback to fetch a Service directly from Algolia i…
Browse files Browse the repository at this point in the history
…f missing from the Shelter Tech API (#220)
  • Loading branch information
rosschapman authored Oct 3, 2024
1 parent 841b36d commit 1150eeb
Show file tree
Hide file tree
Showing 2 changed files with 98 additions and 11 deletions.
2 changes: 1 addition & 1 deletion app/components/ui/Navigation/Navigation.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useState } from "react";
import React from "react";
import { Link } from "react-router-dom";
import styles from "components/ui/Navigation/Navigation.module.scss";
import { GoogleTranslate } from "components/ui/GoogleTranslate";
Expand Down
107 changes: 97 additions & 10 deletions app/pages/ServiceListingPage/ServiceListingPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,33 +26,120 @@ import {
Service,
} from "../../models";
import styles from "./ServiceListingPage.module.scss";
import { algoliasearch } from "algoliasearch";
import config from "./../../config";

// Page at /services/123
const searchClient = algoliasearch(
config.ALGOLIA_APPLICATION_ID,
config.ALGOLIA_READ_ONLY_API_KEY
);

const INDEX_NAME = `${config.ALGOLIA_INDEX_PREFIX}_services_search`;

// NOTE: `serviceFallback` and `setServiceFallback` is a hack to fetch data from
// Algolia rather than the Shelter Tech API. It's nott known why some data is
// not in sync between ST's API and their Algolia instance.
//
// DECISION: Manage the fetched service or fallback service result separately.
// There may be a better way to write the JSX or conditional logic below. Let's
// tackle that post MVP.
//
// As a workaround we've decided to implement a partial view of the Service
// information with a warning to verify the validity of the information
// themselves.
export const ServiceListingPage = () => {
const { id } = useParams<{ id: string }>();
const [service, setService] = useState<Service | null>(null);
const [serviceFallback, setServiceFallback] = useState<Service | null>(null);
const [error, setError] = useState<FetchServiceError>();
const details = useMemo(
() => (service ? generateServiceDetails(service) : []),
[service]
);
const { search } = useLocation();

const { search, pathname } = useLocation();
const searchState = useMemo(() => qs.parse(search.slice(1)), [search]);
const { visitDeactivated } = searchState;

useEffect(() => window.scrollTo(0, 0), []);

useEffect(() => {
fetchService(id).then((s) => {
if ("message" in s) {
setService(null);
const fetchServiceOrFallback = async () => {
try {
const response = await fetchService(id);

// We need to check the contents of the response since `fetchService`
// does not throw. TODO: reconsider this design because processing a
// thrown error requires less knowledge of the response type.
if ("message" in response) {
try {
// CAVEAT: Hopefully this does not change!
const serviceObjectID = `service_${pathname.split("/")[2]}`;
const service = (await searchClient.getObject({
indexName: INDEX_NAME,
objectID: serviceObjectID,
})) as unknown as Service;

setError(s);
} else {
setService(s);
setServiceFallback(service);
setService(null);
} catch (error) {
setService(null);
setError(response);
}
} else {
setService(response);
}
} catch (error) {
setError(error as FetchServiceError);
}
});
}, [id]);
};

fetchServiceOrFallback();
}, [id, pathname]);

if (serviceFallback) {
const formattedLongDescription = serviceFallback.long_description
? removeAsterisksAndHashes(serviceFallback.long_description)
: undefined;
return (
<ListingPageWrapper
title="error"
description=""
sidebarActions={[]}
onClickAction={() => "noop"}
>
<ListingPageHeader
title={serviceFallback.name}
dataCy="service-page-title"
>
<div
style={{
background: "LightYellow",
padding: "1em",
}}
>
<strong>
{" "}
ℹ️ The information on this page is incomplete. Please contact the
service provider below to confirm the provider is still active.{" "}
</strong>
</div>
</ListingPageHeader>

<ListingInfoSection title="About" data-cy="service-about-section">
<ReactMarkdown className="rendered-markdown" linkTarget="_blank">
{formattedLongDescription || ""}
</ReactMarkdown>
</ListingInfoSection>
<ListingInfoSection title="Contact" data-cy="service-contact-section">
<ListingInfoTable
rows={[serviceFallback]}
rowRenderer={(srv) => <ContactInfoTableRows service={srv} />}
/>
</ListingInfoSection>
</ListingPageWrapper>
);
}

if (error) {
return (
Expand Down

0 comments on commit 1150eeb

Please sign in to comment.