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

feat: implement persisted country selection; deps for writing tests #94

Closed
wants to merge 21 commits into from
Closed
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
3 changes: 3 additions & 0 deletions .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<!-- Simple PR template to build some consistency in PRs. -->

## Todo
8 changes: 3 additions & 5 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
{
"editor.formatOnSave": true,
"editor.formatOnPaste": true,
"cSpell.ignoreWords": [
"ecotricity",
"sunmills"
]
}
"editor.defaultFormatter": "esbenp.prettier-vscode",
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added this to automatically invoke prettier on save. This streamlines my DX but can definitely pull this out if undesired!

"cSpell.ignoreWords": ["ecotricity", "sunmills"]
}
4 changes: 4 additions & 0 deletions jest-preprocess.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
const babelOptions = {
presets: ["babel-preset-gatsby"],
}
module.exports = require("babel-jest").createTransformer(babelOptions)
19 changes: 19 additions & 0 deletions jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/**
* See https://gatsby.dev/unit-testing for more info on writing tests.
*/

module.exports = {
transform: {
"^.+\\.jsx?$": `<rootDir>/jest-preprocess.js`,
},
moduleNameMapper: {
".+\\.(css|styl|less|sass|scss)$": `identity-obj-proxy`,
".+\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": `<rootDir>/__mocks__/file-mock.js`,
},
testPathIgnorePatterns: [`node_modules`, `\\.cache`, `<rootDir>.*/public`],
transformIgnorePatterns: [`node_modules/(?!(gatsby)/)`],
globals: {
__PATH_PREFIX__: ``,
},
testURL: `http://localhost`,
}
9 changes: 7 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
"format": "prettier --write \"**/*.{js,jsx,json,md}\"",
"lint": "eslint src",
"start": "npm run develop",
"serve": "gatsby serve"
"serve": "gatsby serve",
"test": "jest"
},
"dependencies": {
"bootstrap": "^4.4.1",
Expand Down Expand Up @@ -44,10 +45,14 @@
"title-case": "^3.0.2"
},
"devDependencies": {
"babel-jest": "^26.6.1",
"babel-preset-gatsby": "^0.5.14",
"eslint-config-prettier": "^6.9.0",
"eslint-config-react-app": "^5.1.0",
"eslint-plugin-prettier": "^3.1.2",
"prettier": "^2.0.5"
"jest": "^26.6.1",
"prettier": "^2.0.5",
"react-test-renderer": "^17.0.1"
},
"repository": {
"type": "git",
Expand Down
38 changes: 38 additions & 0 deletions src/components/CountrySelection.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import React, { useState } from 'react';
import Button from 'react-bootstrap/Button';

import Countries from '../countries';

/**
* Renders a button to select a new country, and the currently
* selected country if one's been set in session storage.
*
* If the user has a country preference in session storage, we
* update the button text to "Change country".
*/
const CountrySelection = ({}) => {
// Get the country code. e.g., "BG" for "Bulgaria"
const [country] = useState(sessionStorage.getItem('country_pref'));

// Default to Great Britain
const countryName = Countries.fromAlpha2Code(country || 'GB').name;
const countryEmoji = Countries.fromAlpha2Code(country || 'GB').emoji;
Comment on lines +14 to +19
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Always look into the session storage first. Defaults to 'GB' which I could see being controversial. @ reviewers, wdyt?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Cn we make the default be no country? The idea of a filter is that it reduces the overall data to a subset of more relevant information, but that is an optional feature which is only used when folks need it.

Copy link
Contributor Author

@piperchester piperchester Nov 9, 2020

Choose a reason for hiding this comment

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

Sure thing! Will fix this 👍. I'll continually update the "TODO" section in the PR description and toggle between ready / draft.


return (
<div className="change-country">
{countryName && countryEmoji ? (
<>
<span className="current selected-item">
{countryName} {countryEmoji}
</span>{' '}
</>
) : null}

<Button href="/select-your-country" className="link text-white">
{countryName ? 'Change' : 'Filter site for your'} country
</Button>
</div>
);
};

export default CountrySelection;
13 changes: 13 additions & 0 deletions src/components/CountrySelection.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import React from "react";
import renderer from "react-test-renderer";

import CountrySelection from "./CountrySelection";

describe("CountrySelection", () => {
it("renders correctly", () => {
const tree = renderer
.create(<CountrySelection />)
.toJSON();
expect(tree).toMatchSnapshot();
});
});
23 changes: 5 additions & 18 deletions src/components/Footer.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,11 @@ import React from 'react';
import Button from 'react-bootstrap/Button';
import Container from 'react-bootstrap/Container';
import Col from 'react-bootstrap/Col';
// import Dropdown from 'react-bootstrap/Dropdown';
import Row from 'react-bootstrap/Row';
import { useCountry } from '../context/country-context';
import Countries from '../countries';

import CountrySelection from './CountrySelection';

const Footer = () => {
const { country } = useCountry();
return (
<footer
className="bg-dark"
Expand Down Expand Up @@ -51,6 +49,9 @@ const Footer = () => {
</div>
</Col>
<Col xs={12} md={2} lg={2}>
{/* Enable country selection, preview, and clearing. */}
<CountrySelection />

<Row noGutters>
<a
href="https://www.netlify.com"
Expand All @@ -67,20 +68,6 @@ const Footer = () => {
<Row noGutters>
<a href="/">&copy; {new Date().getFullYear()} - Protect.Earth</a>
</Row>

{/* <div className="change-country">
{country.name ? (
<>
<span className="current">
{Countries.fromAlpha2Code(country.code).emoji}{' '}
{country.name}
</span>{' '}
</>
) : null}
<Button href="/select-your-country" className="link text-white">
{country.name ? 'Change' : 'Filter site for your'} country
</Button>
</div> */}
</Col>
</Row>
</Container>
Expand Down
5 changes: 3 additions & 2 deletions src/components/RecentLinkItem.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,13 @@ export default ({ link }) => {
link.tags.map((tag) => {
return (
<Badge
key={tag}
variant="secondary"
className="ml-4"
style={{
marginLeft: '2em',
'font-size': '60%',
'font-weight': 300,
'fontSize': '60%',
'fontWeight': 300,
piperchester marked this conversation as resolved.
Show resolved Hide resolved
}}
>
<a href={`/tags/${tag}`} style={{ color: 'white' }}>
Expand Down
25 changes: 25 additions & 0 deletions src/components/__snapshots__/CountrySelection.test.js.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`CountrySelection renders correctly 1`] = `
<div
className="change-country"
>
<span
className="current selected-item"
>
United Kingdom

🇬🇧
</span>

<a
className="link text-white btn btn-primary"
href="/select-your-country"
onClick={[Function]}
onKeyDown={[Function]}
>
Change
country
</a>
</div>
`;
2 changes: 2 additions & 0 deletions src/countries.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ const Countries = {
};
});
},

// Takes a country code, e.g. 'GB'
fromAlpha2Code: (code) => {
return {
code,
Expand Down
32 changes: 27 additions & 5 deletions src/pages/select-your-country.jsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,35 @@
import React from 'react';
import React, { useState } from 'react';
import { graphql, navigate } from 'gatsby';

import { Layout } from '../components';
import { useCountry } from '../context/country-context';
import Countries from '../countries';

/**
* If the user has a country preference in session storage, we don't need to
* present the user to select a country. We update the button to _clear_ their selection.
*/
export default () => {
const { country, setCountry, clearCountry } = useCountry();
const countries = Countries.getAll();

const [country, setCountry] = useState(
sessionStorage.getItem('country_pref')
);

/**
* When a country is selected, we store a
* temporary "country_pref" value in session storage
* that persists through reloads. This enables users to have
* continuity when refreshing, or returning to the site.
*
* We also bind the update to React's state, so that when a user re-selects
* an option, we trigger a state change to refresh the site.
*/
const updateCountry = (country) => {
setCountry(country);
sessionStorage.setItem('country_pref', country);
};
Comment on lines +19 to +31
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is the core piece where we write to session storage, and update React's state.


return (
<Layout title="Select Your Country">
<div className="select-your-country padding">
Expand All @@ -21,7 +42,7 @@ export default () => {
/>
</div>
<div>
{country.name !== null ? (
{country && country.name ? (
<div className="country-list-item selected" key={country.code}>
<small>Currently selected</small>
<div>
Expand All @@ -30,7 +51,8 @@ export default () => {
<button
onClick={(e) => {
e.preventDefault();
clearCountry();
// Store an empty string in session storage
updateCountry('');
navigate('/');
}}
>
Expand All @@ -49,7 +71,7 @@ export default () => {
className="country-list-item"
key={code}
onClick={() => {
setCountry(country);
updateCountry(country.code);
navigate('/');
}}
>
Expand Down
21 changes: 18 additions & 3 deletions src/styles/global.scss
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,26 @@ blockquote p {
display: inline;
}

// Ensure the selected country is
.selected-language-block {
display: flex;
align-items: center;
}

// Ensure selected language and country is
// readable on the #333 footer.
.change-country .current {
.selected-item {
text-align: center;
margin-bottom: 7px;
color: white;
margin-bottom: 20px;
}

.clear-button {
padding: 0; // reset default padding applied by React Bootstrap
}

.change-country {
display: flex;
flex-direction: column;
}

/* Select Your Country */
Expand Down