Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Render React LOC content from session data. #1535

Merged
merged 2 commits into from
Jun 10, 2020
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
7 changes: 7 additions & 0 deletions frontend/lib/justfix-routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,13 @@ function createLetterOfComplaintRouteInfo(prefix: string) {
sampleLetterContent: createLetterStaticPageRouteInfo(
`${prefix}/sample-letter`
),
/** Letter content for the user (HTML and PDF versions). */
letterContent: createLetterStaticPageRouteInfo(
// We're calling this 'react-letter' for now because we
// don't want to collide with the Django-rendered version
// of the letter.
`${prefix}/react-letter`
),
splash: `${prefix}/splash`,
welcome: `${prefix}/welcome`,
...createJustfixCrossSiteVisitorRoutes(prefix),
Expand Down
64 changes: 63 additions & 1 deletion frontend/lib/loc/letter-content.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,22 @@ import {
BaseLetterContentProps,
letter,
baseSampleLetterProps,
getBaseLetterContentPropsFromSession,
TransformSession,
} from "../util/letter-content-util";
import { createLetterStaticPageWithQuery } from "../static-page/letter-static-page";
import {
IssueAreaChoice,
getIssueAreaChoiceLabels,
IssueAreaChoices,
} from "../../../common-data/issue-area-choices";
import {
IssueChoice,
getIssueChoiceLabels,
} from "../../../common-data/issue-choices";
import { friendlyUTCDate } from "../util/date-util";
import { AllSessionInfo } from "../queries/AllSessionInfo";
import { issuesForArea, customIssuesForArea } from "../issues/issues";

const HEAT_ISSUE_CHOICES = new Set<IssueChoice>([
"HOME__NO_HEAT",
Expand All @@ -34,7 +39,7 @@ type AreaIssues = {
type LocContentProps = BaseLetterContentProps & {
issues: AreaIssues[];
accessDates: GraphQLDate[];
hasCalled311: boolean;
hasCalled311: boolean | null;
};

const LetterTitle: React.FC<LocContentProps> = (props) => (
Expand Down Expand Up @@ -203,6 +208,63 @@ export const LocContent: React.FC<LocContentProps> = (props) => (

const LocStaticPage = createLetterStaticPageWithQuery(LocContent);

function getIssuesFromSession(session: AllSessionInfo): AreaIssues[] {
const result: AreaIssues[] = [];

for (let area of IssueAreaChoices) {
const issueChoices: Issue[] = issuesForArea(
area,
session.issues as IssueChoice[]
).map((choice) => ({
kind: "choice",
choice,
}));
const customIssues: Issue[] = customIssuesForArea(
area,
session.customIssuesV2 || []
).map((ci) => ({
kind: "custom",
value: ci.description,
}));
const issues: Issue[] = [...issueChoices, ...customIssues];
if (issues.length) {
result.push({ area, issues });
}
}

return result;
}

export function getLocContentPropsFromSession(
session: AllSessionInfo
): LocContentProps | null {
const baseProps = getBaseLetterContentPropsFromSession(session);
const onb = session.onboardingInfo;

if (!(baseProps && onb)) {
return null;
}

return {
...baseProps,
issues: getIssuesFromSession(session),
accessDates: session.accessDates,
hasCalled311: onb.hasCalled311,
};
}

export const LocForUserPage: React.FC<{ isPdf: boolean }> = ({ isPdf }) => (
<TransformSession transformer={getLocContentPropsFromSession}>
{(props) => (
<LocStaticPage
{...props}
isPdf={isPdf}
title="Your Letter of Complaint"
/>
)}
</TransformSession>
);

export const locSampleProps: LocContentProps = {
...baseSampleLetterProps,
issues: [
Expand Down
6 changes: 5 additions & 1 deletion frontend/lib/loc/letter-of-complaint.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import { createJustfixCrossSiteVisitorSteps } from "../justfix-cross-site-visito
import { ProgressStepProps } from "../progress/progress-step-route";
import { assertNotNull } from "../util/util";
import { Switch, Route } from "react-router-dom";
import { LocSamplePage } from "./letter-content";
import { LocSamplePage, LocForUserPage } from "./letter-content";
import { createLetterStaticPageRoutes } from "../static-page/routes";

export const Welcome: React.FC<ProgressStepProps> = (props) => {
Expand Down Expand Up @@ -149,6 +149,10 @@ const LetterOfComplaintRoutes: React.FC<{}> = () => (
JustfixRoutes.locale.loc.sampleLetterContent,
LocSamplePage
)}
{createLetterStaticPageRoutes(
JustfixRoutes.locale.loc.letterContent,
LocForUserPage
)}
<Route component={LetterOfComplaintProgressRoutes} />
</Switch>
);
Expand Down
35 changes: 35 additions & 0 deletions frontend/lib/loc/tests/__snapshots__/letter-content.test.tsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -174,3 +174,38 @@ exports[`<LocContent> works 1`] = `
</div>
</div>
`;

exports[`getLocContentPropsFromSession() returns expected value when user is logged in 1`] = `
Object {
"accessDates": Array [],
"aptNumber": "",
"city": "Brooklyn",
"email": "boop@jones.net",
"firstName": "Boop",
"hasCalled311": null,
"issues": Array [
Object {
"area": "HOME",
"issues": Array [
Object {
"choice": "HOME__RATS",
"kind": "choice",
},
Object {
"kind": "custom",
"value": "Rain enters through roof",
},
],
},
],
"landlordAddress": "123 Cloud City Drive
Bespin, NY 12345",
"landlordEmail": "landlordo@calrissian.net",
"landlordName": "Landlordo Calrissian",
"lastName": "Jones",
"phoneNumber": "5551234567",
"state": "NY",
"street": "150 Court St",
"zipCode": "11201",
}
`;
23 changes: 22 additions & 1 deletion frontend/lib/loc/tests/letter-content.test.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,31 @@
import React from "react";
import ReactTestingLibraryPal from "../../tests/rtl-pal";
import { LocContent, locSampleProps } from "../letter-content";
import {
LocContent,
locSampleProps,
getLocContentPropsFromSession,
} from "../letter-content";
import { newSb } from "../../tests/session-builder";

describe("<LocContent>", () => {
it("works", () => {
const pal = new ReactTestingLibraryPal(<LocContent {...locSampleProps} />);
expect(pal.rr.container).toMatchSnapshot();
});
});

const filledUser = newSb()
.withLoggedInJustfixUser()
.withLandlordDetails()
.withCustomIssue()
.withIssues();

describe("getLocContentPropsFromSession()", () => {
it("returns null when user is logged out", () => {
expect(getLocContentPropsFromSession(newSb().value)).toBe(null);
});

it("returns expected value when user is logged in", () => {
expect(getLocContentPropsFromSession(filledUser.value)).toMatchSnapshot();
});
});
24 changes: 7 additions & 17 deletions frontend/lib/norent/letter-content.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
letter,
baseSampleLetterProps,
getBaseLetterContentPropsFromSession,
TransformSession,
} from "../util/letter-content-util";
import { makeStringHelperFC } from "../util/string-helper";

Expand Down Expand Up @@ -71,7 +72,7 @@ export const NorentLetterTranslation: React.FC<{}> = () => {
return (
<article className="message jf-letter-translation">
<div className="message-body has-background-grey-lighter has-text-left has-text-weight-light">
<LetterContentPropsFromSession>
<TransformSession transformer={getNorentLetterContentPropsFromSession}>
{(props) => (
<>
<letter.DearLandlord {...props} />
Expand All @@ -82,25 +83,12 @@ export const NorentLetterTranslation: React.FC<{}> = () => {
</p>
</>
)}
</LetterContentPropsFromSession>
</TransformSession>
</div>
</article>
);
};

const LetterContentPropsFromSession: React.FC<{
children: (lcProps: NorentLetterContentProps) => JSX.Element;
}> = ({ children }) => {
const { session } = useContext(AppContext);
const lcProps = getNorentLetterContentPropsFromSession(session);

if (!lcProps) {
return <p>We don't have enough information to generate a letter yet.</p>;
}

return children(lcProps);
};

export const NorentLetterEmailToLandlord: React.FC<NorentLetterContentProps> = (
props
) => (
Expand Down Expand Up @@ -134,7 +122,8 @@ export const NorentLetterEmailToLandlord: React.FC<NorentLetterContentProps> = (
);

export const NorentLetterEmailToLandlordForUser: React.FC<{}> = () => (
<LetterContentPropsFromSession
<TransformSession
transformer={getNorentLetterContentPropsFromSession}
children={(lcProps) => <NorentLetterEmailToLandlord {...lcProps} />}
/>
);
Expand Down Expand Up @@ -252,7 +241,8 @@ function getNorentLetterContentPropsFromSession(
export const NorentLetterForUserStaticPage: React.FC<{ isPdf: boolean }> = ({
isPdf,
}) => (
<LetterContentPropsFromSession
<TransformSession
transformer={getNorentLetterContentPropsFromSession}
children={(lcProps) => (
<NorentLetterStaticPage
{...lcProps}
Expand Down
42 changes: 41 additions & 1 deletion frontend/lib/tests/session-builder.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,13 @@ import {
BlankNorentScaffolding,
} from "../queries/NorentScaffolding";
import { BlankOnboardingInfo, OnboardingInfo } from "../queries/OnboardingInfo";
import { PhoneNumberAccountStatus, Borough } from "../queries/globalTypes";
import {
PhoneNumberAccountStatus,
Borough,
CustomIssueArea,
} from "../queries/globalTypes";
import { IssueChoice } from "../../../common-data/issue-choices";
import { IssueAreaChoice } from "../../../common-data/issue-area-choices";

/**
* An attempt to encapsulate the creation of a GraphQL session object
Expand Down Expand Up @@ -54,12 +60,46 @@ export class SessionBuilder {
return this.withLoggedInUser().withOnboardingInfo({
address: "150 Court St",
borough: Borough.BROOKLYN,
city: "Brooklyn",
state: "NY",
zipcode: "11201",
agreedToJustfixTerms: true,
});
}

withIssues(issues: IssueChoice[] = ["HOME__RATS"]): SessionBuilder {
return this.with({ issues });
}

withCustomIssue(
area: IssueAreaChoice = "HOME",
description: string = "Rain enters through roof"
): SessionBuilder {
const prevIssues = this.value.customIssuesV2 || [];
return this.with({
customIssuesV2: [
...prevIssues,
{ area: area as CustomIssueArea, description, id: area + description },
],
});
}

withLandlordDetails(): SessionBuilder {
return this.with({
landlordDetails: {
name: "Landlordo Calrissian",
address: "123 Cloud City Drive\nBespin, NY 12345",
primaryLine: "123 Cloud City Drive",
city: "Bespin",
state: "NY",
zipCode: "12345",
email: "landlordo@calrissian.net",
phoneNumber: "5551234567",
isLookedUp: false,
},
});
}

withLoggedInNationalUser(): SessionBuilder {
return this.withLoggedInUser().withOnboardingInfo({
address: "152 W. 32nd St",
Expand Down
17 changes: 16 additions & 1 deletion frontend/lib/util/letter-content-util.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import React from "react";
import React, { useContext } from "react";
import { BreaksBetweenLines } from "../ui/breaks-between-lines";
import { formatPhoneNumber } from "../forms/phone-number-form-field";
import { Trans } from "@lingui/macro";
import { friendlyUTCDate, friendlyDate } from "./date-util";
import { AllSessionInfo } from "../queries/AllSessionInfo";
import { assertNotNull } from "./util";
import { makeStringHelperFC } from "./string-helper";
import { AppContext } from "../app-context";

export type BaseLetterContentProps = {
firstName: string;
Expand Down Expand Up @@ -123,6 +124,20 @@ const Title: React.FC<{ children: React.ReactNode }> = (props) => (
</h1>
);

export function TransformSession<T>(props: {
transformer: (session: AllSessionInfo) => T | null;
children: (props: T) => JSX.Element;
}) {
const { session } = useContext(AppContext);
const transformedProps = props.transformer(session);

if (!transformedProps) {
return <p>We don't have enough information to generate this content.</p>;
}

return props.children(transformedProps);
}

export const baseSampleLetterProps: BaseLetterContentProps = {
firstName: "Boop",
lastName: "Jones",
Expand Down