Skip to content

Commit

Permalink
Merge f7f7407 into 85c4003
Browse files Browse the repository at this point in the history
  • Loading branch information
macfarlandian committed May 6, 2021
2 parents 85c4003 + f7f7407 commit c9370b2
Show file tree
Hide file tree
Showing 20 changed files with 551 additions and 19 deletions.
2 changes: 2 additions & 0 deletions spotlight-client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -82,9 +82,11 @@
"react-modal": "^3.12.1",
"react-portal": "^4.2.1",
"react-scripts": "3.4.3",
"react-share": "^4.4.0",
"react-simple-maps": "^2.3.0",
"react-spring": "^8.0.27",
"react-stickyfill": "^0.2.5",
"react-use-clipboard": "^1.0.7",
"semiotic": "^1.20.6",
"smoothscroll-polyfill": "^0.4.4",
"string-strip-html": "^8.2.2",
Expand Down
82 changes: 82 additions & 0 deletions spotlight-client/src/ShareModal/ShareModal.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
// Recidiviz - a data platform for criminal justice reform
// Copyright (C) 2021 Recidiviz, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
// =============================================================================

import { screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { runInAction } from "mobx";
import React from "react";
import DataStore from "../DataStore";
import { NarrativesSlug } from "../routerUtils/types";
import { renderWithStore } from "../testUtils";
import ShareModal from "./ShareModal";

const renderModal = () => {
renderWithStore(<ShareModal isOpen onRequestClose={() => undefined} />);
};

afterEach(() => {
runInAction(() => {
DataStore.tenantStore.currentTenantId = undefined;
DataStore.tenantStore.currentNarrativeTypeId = undefined;
DataStore.tenantStore.currentSectionNumber = undefined;
});
});

test("display url", () => {
renderModal();
expect(screen.getByText("localhost")).toBeVisible();

runInAction(() => {
DataStore.tenantStore.currentTenantId = "US_PA";
});

expect(screen.getByText("localhost/us-pa")).toBeVisible();

runInAction(() => {
DataStore.tenantStore.currentNarrativeTypeId = "RacialDisparities";
});

expect(
screen.getByText(`localhost/us-pa/${NarrativesSlug}/racial-disparities`)
).toBeVisible();
});

test("include narrative section in url", () => {
runInAction(() => {
DataStore.tenantStore.currentTenantId = "US_PA";
DataStore.tenantStore.currentNarrativeTypeId = "RacialDisparities";
DataStore.tenantStore.currentSectionNumber = 2;
});

renderModal();

expect(
screen.getByText(`localhost/us-pa/${NarrativesSlug}/racial-disparities`)
).toBeVisible();

userEvent.click(screen.getByRole("checkbox"));

expect(
screen.getByText(`localhost/us-pa/${NarrativesSlug}/racial-disparities/2`)
).toBeVisible();

userEvent.click(screen.getByRole("checkbox"));

expect(
screen.getByText(`localhost/us-pa/${NarrativesSlug}/racial-disparities`)
).toBeVisible();
});
232 changes: 232 additions & 0 deletions spotlight-client/src/ShareModal/ShareModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,232 @@
// Recidiviz - a data platform for criminal justice reform
// Copyright (C) 2021 Recidiviz, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
// =============================================================================

import { observer } from "mobx-react-lite";
import { rem } from "polished";
import React, { useState } from "react";
import {
EmailShareButton,
FacebookShareButton,
TwitterShareButton,
} from "react-share";
import { animated, useTransition } from "react-spring/web.cjs";
import useClipboard from "react-use-clipboard";
import styled from "styled-components/macro";
import emailPath from "../assets/email-logo-white.svg";
import facebookPath from "../assets/facebook-logo-white.svg";
import twitterPath from "../assets/twitter-logo-white.svg";
import getUrlForResource from "../routerUtils/getUrlForResource";
import { useDataStore } from "../StoreProvider";
import {
animation,
Checkbox,
colors,
Modal,
ModalHeading,
SpotlightModalProps,
typefaces,
} from "../UiLibrary";

const Button = styled.button.attrs({ type: "button" })`
align-items: center;
background-color: ${colors.link};
border-radius: 3em;
border: none;
color: ${colors.textLight};
cursor: pointer;
display: flex;
font-size: ${rem(11)};
justify-content: center;
padding: ${rem(12)} ${rem(16)};
transition: background-color ${animation.defaultDuration}ms;
&:disabled {
cursor: not-allowed;
}
&:hover,
&:focus {
background-color: ${colors.text};
}
&:active {
background-color: ${colors.text};
}
`;

const ShareActions = styled.div`
border-color: ${colors.rule};
border-style: solid;
border-width: 1px 0;
margin: ${rem(24)} 0;
padding: ${rem(24)} 0;
position: relative;
`;

const UrlText = styled.div`
font-family: ${typefaces.display};
font-size: ${rem(21)};
letter-spacing: -0.04em;
padding-bottom: ${rem(16)};
`;

const ShareButtons = styled.div`
display: flex;
& > button {
margin: 0 ${rem(4)};
&:first-of-type {
margin-left: 0;
}
&:last-of-type {
margin-right: 0;
}
}
`;

const IconTwitter = styled.img.attrs({
alt: "Twitter",
src: twitterPath,
})``;

const IconEmail = styled.img.attrs({
alt: "E-mail",
src: emailPath,
})``;

const IconFacebook = styled.img.attrs({
alt: "Facebook",
src: facebookPath,
})``;

const CopyConfirmation = styled(animated.div).attrs({ role: "status" })`
bottom: ${rem(4)};
font-size: ${rem(11)};
position: absolute;
`;

const IncludeSectionLabel = styled.label`
align-items: baseline;
display: flex;
font-size: ${rem(14)};
line-height: 1.4;
`;

const SectionTitle = styled.span`
color: ${colors.link};
`;

const ShareModal = (
modalProps: Omit<SpotlightModalProps, "children">
): JSX.Element => {
const {
tenantStore: {
currentTenantId,
currentNarrative,
currentNarrativeTypeId,
currentSectionNumber,
},
} = useDataStore();
const [includeSection, setIncludeSection] = useState(false);

let urlToShare = window.location.host;

if (currentTenantId) {
if (currentNarrativeTypeId) {
urlToShare += getUrlForResource({
page: "narrative",
params: {
tenantId: currentTenantId,
narrativeTypeId: currentNarrativeTypeId,
sectionNumber: includeSection ? currentSectionNumber : undefined,
},
});
} else {
urlToShare += getUrlForResource({
page: "tenant",
params: { tenantId: currentTenantId },
});
}
}

const [isCopied, copyUrl] = useClipboard(urlToShare, {
successDuration: 5000,
});

const transitionConfirmation = useTransition(isCopied, null, {
from: { opacity: 0 },
enter: { opacity: 1 },
leave: { opacity: 0 },
});

return (
<Modal {...modalProps}>
<ModalHeading>Share</ModalHeading>
<ShareActions>
<UrlText>{urlToShare}</UrlText>
<ShareButtons>
<Button onClick={() => copyUrl()}>Copy URL</Button>
<EmailShareButton url={urlToShare}>
<Button as="div">
<IconEmail />
</Button>
</EmailShareButton>
<FacebookShareButton url={urlToShare}>
<Button as="div">
<IconFacebook />
</Button>
</FacebookShareButton>
<TwitterShareButton url={urlToShare}>
<Button as="div">
<IconTwitter />
</Button>
</TwitterShareButton>
</ShareButtons>
{transitionConfirmation.map(
({ item, key, props }) =>
item && (
<CopyConfirmation key={key} style={props}>
The URL has been copied to your clipboard.
</CopyConfirmation>
)
)}
</ShareActions>
<>
{currentSectionNumber && currentSectionNumber > 1 && (
<IncludeSectionLabel>
<Checkbox
checked={includeSection}
onChange={(e) => {
setIncludeSection(e.target.checked);
}}
/>
<span>
Link to current section:{" "}
<SectionTitle>
{currentNarrative?.sections[currentSectionNumber - 2].title}
</SectionTitle>
</span>
</IncludeSectionLabel>
)}
</>
</Modal>
);
};

export default observer(ShareModal);
18 changes: 18 additions & 0 deletions spotlight-client/src/ShareModal/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Recidiviz - a data platform for criminal justice reform
// Copyright (C) 2021 Recidiviz, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
// =============================================================================

export { default } from "./ShareModal";
2 changes: 1 addition & 1 deletion spotlight-client/src/SiteFooter/SiteFooter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ const SiteFooter: React.FC = () => {
</Legalese>
<BrandLinks>
<SocialLinks>
<SocialLink href="https://twitter.com/RecidivizOrg">
<SocialLink href="https://twitter.com/Recidiviz">
<img alt="Twitter" src={twitterPath} />
</SocialLink>
<SocialLink href="https://www.linkedin.com/company/recidiviz/">
Expand Down
Loading

0 comments on commit c9370b2

Please sign in to comment.