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

Add Modal component and integrate Mailchimp form #96

Merged
merged 5 commits into from
Nov 17, 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
6 changes: 6 additions & 0 deletions jest/loadershim.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,9 @@
global.___loader = {
enqueue: jest.fn(),
};

// Used to allow react-modal to work in tests.
// https://github.com/facebook/react/issues/11565#issuecomment-427547413
jest.mock("react-dom", () => ({
createPortal: (node) => node,
}));
16 changes: 16 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@
"pure-react-carousel": "^1.27.6",
"react": "^16.13.1",
"react-burger-menu": "^2.9.0",
"react-helmet": "^6.1.0"
"react-helmet": "^6.1.0",
"react-modal": "^3.11.2"
},
"devDependencies": {
"@babel/core": "^7.11.6",
Expand Down
40 changes: 40 additions & 0 deletions src/components/grid-aware/Modal/Modal.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import PropTypes from "prop-types";
import React from "react";
import ReactModal from "react-modal";

import s from "./Modal.module.css";
import closeIcon from "./close-icon.svg";

const Modal = ({ children, isOpen, setIsOpen, ariaHideApp, contentLabel }) => (
<ReactModal
className={s.content}
overlayClassName={s.overlay}
isOpen={isOpen}
onRequestClose={() => setIsOpen(false)}
ariaHideApp={ariaHideApp}
contentLabel={contentLabel}
>
<button
className={s.closeButton}
onClick={() => setIsOpen(false)}
type="button"
>
<img src={closeIcon} alt="Close" />
</button>
{children}
</ReactModal>
);

Modal.propTypes = {
children: PropTypes.node.isRequired,
isOpen: PropTypes.bool.isRequired,
setIsOpen: PropTypes.func.isRequired,
ariaHideApp: PropTypes.bool,
contentLabel: PropTypes.string.isRequired,
};

Modal.defaultProps = {
ariaHideApp: true,
};

export default Modal;
45 changes: 45 additions & 0 deletions src/components/grid-aware/Modal/Modal.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
.overlay {
background-color: rgba(0, 0, 0, 0.5);
bottom: 0;
left: 0;
overflow: auto;
position: fixed;
right: 0;
top: 0;
Comment on lines +3 to +8
Copy link
Member

@davidagustin davidagustin Nov 15, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume you tried other methods in completely covering the whole view of the browser with the darkened hue of the modal but is there a shorter way to cover the whole screen than putting all bottom, top, left and right positions to 0?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I actually didn't try anything else because I had copied these styles over from the default ones that the library comes with. I'm not sure if there's a shorter way to cover it, since it's position: fixed. You still need the top: 0 since the element itself is placed based on where its parent is, not based on the page. The right and the bottom could be replaced with width: 100vw and height: 100vh, which doesn't save us much because it's a one-for-one tradeoff.

You could possibly leave out left:, but it will only work if you don't have anything that pushes the modal's parent's position away from the left edge, which makes it a little bit riskier to do.

Overall, I think setting the position across all four dimensions is pretty much as compact and reliable as we're going to get.

}

.content {
background: var(--color-white);
border-radius: 16px;
box-shadow: 0 12px 32px rgba(0, 0, 0, 0.2);
box-sizing: border-box;
margin: 80px auto 40px;
max-width: 850px;
outline: none;
padding: 50px;
position: relative;
}

.closeButton {
background: none;
border: 0;
cursor: pointer;
display: inline-block;
padding: 0;
position: absolute;
right: 30px;
top: 30px;
}

@media (--tablet-and-down) {
.content {
margin-left: 20px;
margin-right: 20px;
Comment on lines +36 to +37
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Possible shorthand can be used?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't want to override the top and bottom margin settings from the non-media-query version of this, which are set to 80px and 40px respectively.

padding: 35px 25px;
}

.closeButton {
right: 25px;
top: 25px;
}
}
47 changes: 47 additions & 0 deletions src/components/grid-aware/Modal/Modal.stories.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import React, { useState } from "react";

import Modal from "./Modal";

export default {
title: "Grid-Aware/Modal",
component: Modal,
};

const Template = () => {
const [modalIsOpen, setModalIsOpen] = useState(true);
return (
<div>
<Modal
isOpen={modalIsOpen}
setIsOpen={setModalIsOpen}
/* Disable ariaHideApp in Storybook to suppress warning about not
* setting the app element.
* https://github.com/reactjs/react-modal/issues/576
*/
ariaHideApp={false}
contentLabel="Example Modal"
>
<div style={{ font: "var(--font-body-medium)" }}>
<h1 style={{ font: "var(--font-headline)" }}>Work with Us</h1>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim
ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
aliquip ex ea commodo consequat. Duis aute irure dolor in
reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla
pariatur. Excepteur sint occaecat cupidatat non proident, sunt in
culpa qui officia deserunt mollit anim id est laborum.
</p>
</div>
</Modal>
<div>
<button type="button" onClick={() => setModalIsOpen(!modalIsOpen)}>
Toggle Modal
</button>
</div>
</div>
);
};

export const DefaultModal = Template.bind({});
DefaultModal.args = {};
4 changes: 4 additions & 0 deletions src/components/grid-aware/Modal/close-icon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions src/components/grid-aware/Modal/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from "./Modal";
6 changes: 5 additions & 1 deletion src/components/layout.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import PropTypes from "prop-types";
import React, { useState } from "react";
import React, { useState, useEffect } from "react";
import ReactModal from "react-modal";

import "../stylesheets/global.css";
import { BurgerMenu, Navigation } from "./grid-aware/Navigation";
Expand All @@ -14,6 +15,9 @@ const Layout = ({ children }) => {
const pageWrapperID = "page-wrapper";
const outerContainerID = "outer-container";
const [burgerMenuIsOpen, setBurgerMenuIsOpen] = useState(false);
useEffect(() => {
ReactModal.setAppElement(`#${outerContainerID}`);
}, []);
return (
<div id={outerContainerID}>
<BurgerMenu
Expand Down
34 changes: 34 additions & 0 deletions src/components/thirdparty/mailchimp/VolunteerSignupForm.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/* This file contains global styles because we are overriding the default styles
* that come from Mailchimp. */
/* stylelint-disable selector-max-id */

#mc_embed_signup form {
padding: 0 !important;
}

#mc_embed_signup .mc-field-group {
margin-bottom: 39px;
padding-bottom: 0 !important;
}

#mc_embed_signup .mc-field-group label {
font: var(--font-caption);
margin-bottom: 10px !important;
}

#mc_embed_signup .mc-field-group input {
border: 1px solid var(--color-gray-400);
border-radius: 0;
font: var(--font-body-small);
padding: 16px 17px 15px !important;
}

#mc_embed_signup .button {
background-color: var(--color-sheltertech-blue) !important;
border-radius: 0 !important;
color: var(--color-white) !important;
font: var(--font-action) !important;
height: auto !important;
padding: 16px 40px !important;
text-transform: uppercase;
}
62 changes: 62 additions & 0 deletions src/components/thirdparty/mailchimp/VolunteerSignupForm.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import React from "react";

import "./VolunteerSignupForm.css";
import s from "./VolunteerSignupForm.module.css";

/* eslint-disable react/no-danger */
// This entire file is just about embedding an external form

const rawInnerHtml = {
__html: `
<!-- Begin Mailchimp Signup Form -->
<link href="//cdn-images.mailchimp.com/embedcode/classic-10_7.css" rel="stylesheet" type="text/css">
<style type="text/css">
#mc_embed_signup{background:#fff; clear:left; font:14px Helvetica,Arial,sans-serif; }
/* Add your own Mailchimp form style overrides in your site stylesheet or in this style block.
We recommend moving this block and the preceding CSS link to the HEAD of your HTML file. */
</style>
<div id="mc_embed_signup">
<form action="https://sheltertech.us19.list-manage.com/subscribe/post?u=c47829732a0bea5c8e8a94604&amp;id=08f60e42ef" method="post" id="mc-embedded-subscribe-form" name="mc-embedded-subscribe-form" class="validate" target="_blank" novalidate>
<div id="mc_embed_signup_scroll">

<div class="mc-field-group">
<label for="mce-EMAIL">Email Address </label>
<input type="email" value="" name="EMAIL" class="required email" id="mce-EMAIL">
</div>
<div class="mc-field-group">
<label for="mce-FNAME">First Name </label>
<input type="text" value="" name="FNAME" class="" id="mce-FNAME">
</div>
<div class="mc-field-group">
<label for="mce-LNAME">Last Name </label>
<input type="text" value="" name="LNAME" class="" id="mce-LNAME">
</div>
<div class="mc-field-group">
<label for="mce-MMERGE12">Volunteer Interests </label>
<input type="text" value="" name="MMERGE12" class="" id="mce-MMERGE12">
</div>
<div id="mce-responses" class="clear">
<div class="response" id="mce-error-response" style="display:none"></div>
<div class="response" id="mce-success-response" style="display:none"></div>
</div> <!-- real people should not fill this in and expect good things - do not remove this or risk form bot signups-->
<div style="position: absolute; left: -5000px;" aria-hidden="true"><input type="text" name="b_c47829732a0bea5c8e8a94604_08f60e42ef" tabindex="-1" value=""></div>
<div class="clear"><input type="submit" value="Subscribe" name="subscribe" id="mc-embedded-subscribe" class="button"></div>
</div>
</form>
</div>
<script type='text/javascript' src='//s3.amazonaws.com/downloads.mailchimp.com/js/mc-validate.js'></script><script type='text/javascript'>(function($) {window.fnames = new Array(); window.ftypes = new Array();fnames[0]='EMAIL';ftypes[0]='email';fnames[1]='FNAME';ftypes[1]='text';fnames[2]='LNAME';ftypes[2]='text';fnames[3]='ADDRESS';ftypes[3]='address';fnames[4]='PHONE';ftypes[4]='phone';fnames[5]='BIRTHDAY';ftypes[5]='birthday';fnames[6]='MMERGE6';ftypes[6]='text';fnames[7]='MMERGE7';ftypes[7]='number';fnames[8]='MMERGE8';ftypes[8]='date';fnames[9]='MMERGE9';ftypes[9]='text';fnames[10]='LGL_SAL';ftypes[10]='text';fnames[11]='LGL_ID';ftypes[11]='text';fnames[12]='MMERGE12';ftypes[12]='text';}(jQuery));var $mcj = jQuery.noConflict(true);</script>
<!--End mc_embed_signup-->
`,
};

const VolunteerSignupForm = () => (
<div>
<h1 className={s.title}>Work With Us</h1>
<p className={s.description}>
Thank you for your interest in partnering with ShelterTech! Enter your
contact information below and we&apos;ll get back to you shortly.
</p>
<div dangerouslySetInnerHTML={rawInnerHtml} />
</div>
);
export default VolunteerSignupForm;
11 changes: 11 additions & 0 deletions src/components/thirdparty/mailchimp/VolunteerSignupForm.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
.title {
font: var(--font-headline);
margin-bottom: 20px;
margin-top: 0;
}

.description {
font: var(--font-body-medium);
margin-bottom: 40px;
margin-top: 0;
}
27 changes: 27 additions & 0 deletions src/components/thirdparty/mailchimp/VolunteerSignupForm.stories.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import React from "react";

import VolunteerSignupForm from "./VolunteerSignupForm";

export default {
title: "Third Party/Mailchimp/VolunteerSignupForm",
component: VolunteerSignupForm,
};

const Template = () => (
<div style={{ maxWidth: "850px", padding: "50px" }}>
<p
style={{
fontStyle: "italic",
backgroundColor: "var(--color-gray-300)",
padding: "15px",
}}
>
Note: This is a real form, and submitting it will really subscribe you to
a Mailchimp list.
</p>
<VolunteerSignupForm />
</div>
);

export const Default = Template.bind({});
Default.args = {};
Loading