-
-
Notifications
You must be signed in to change notification settings - Fork 15
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
Changes from all commits
6c1e20a
290b434
e5add3d
746bba6
2dcdab0
c629694
8b31adf
c9dc385
9fb15cd
1be5341
dde2194
70cdd75
74b72c7
23e1ac2
d0e831b
dbd01fa
5c5a388
b2f0f49
dc0d444
bcd8ff0
120742d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
<!-- Simple PR template to build some consistency in PRs. --> | ||
|
||
## Todo |
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", | ||
"cSpell.ignoreWords": ["ecotricity", "sunmills"] | ||
} |
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) |
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`, | ||
} |
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
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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? There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. There was a problem hiding this comment. Choose a reason for hiding this commentThe 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; |
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(); | ||
}); | ||
}); |
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> | ||
`; |
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
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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"> | ||
|
@@ -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> | ||
|
@@ -30,7 +51,8 @@ export default () => { | |
<button | ||
onClick={(e) => { | ||
e.preventDefault(); | ||
clearCountry(); | ||
// Store an empty string in session storage | ||
updateCountry(''); | ||
navigate('/'); | ||
}} | ||
> | ||
|
@@ -49,7 +71,7 @@ export default () => { | |
className="country-list-item" | ||
key={code} | ||
onClick={() => { | ||
setCountry(country); | ||
updateCountry(country.code); | ||
navigate('/'); | ||
}} | ||
> | ||
|
There was a problem hiding this comment.
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!