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 12 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
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`,
}
8 changes: 6 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"lint": "eslint src",
"start": "npm run develop",
"serve": "gatsby serve",
"test": "echo \"Write tests! -> https://gatsby.dev/unit-testing \""
"test": "jest"
},
"dependencies": {
"bootstrap": "^4.4.1",
Expand Down Expand Up @@ -46,10 +46,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
21 changes: 6 additions & 15 deletions src/components/Footer.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@ 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 LanguageDropdown from './LanguageDropdown';

const Footer = () => {
const { country } = useCountry();

return (
<footer
className="bg-dark"
Expand Down Expand Up @@ -46,24 +48,13 @@ const Footer = () => {
</div>
</Col>
<Col xs={12} md={2} lg={2}>
{/*
<Dropdown>
<Dropdown.Toggle variant="secondary" id="dropdown-basic">
Language
</Dropdown.Toggle>

<Dropdown.Menu>
<Dropdown.Item href="#/action-1">English</Dropdown.Item>
<Dropdown.Item href="#/action-2">Español</Dropdown.Item>
<Dropdown.Item href="#/action-3">Français</Dropdown.Item>
</Dropdown.Menu>
</Dropdown>
*/}
<LanguageDropdown />

<div className="change-country">
{country.name ? (
<>
<span className="current">
<span className="current selected-item">
{Countries.fromAlpha2Code(country.code).emoji}{' '}
{country.name}
</span>{' '}
Expand Down Expand Up @@ -92,4 +83,4 @@ const Footer = () => {
);
};

export default Footer;
export default Footer;
67 changes: 67 additions & 0 deletions src/components/LanguageDropdown.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import React, {useState} from 'react';
import Button from 'react-bootstrap/Button';
import Dropdown from 'react-bootstrap/Dropdown';

/**
* If the user has a language preference in session storage, we don't need to
* present the user to select a language. We render a button to _clear_ their selection.
*/
const LanguageDropdown = ({}) => {
const [language, setLanguage] = useState(sessionStorage.getItem('lang_pref'))

/**
* When a language is selected, we store
* temporary value in session storage that persists through
* reloads. This enables users to have some 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.
*
* We use the ISO 639-1 language codes to map to specified languages, e.g.
* "EN" maps to "English".
*/
const updateLanguage = (language) => {
setLanguage(language);
sessionStorage.setItem('lang_pref', language);
piperchester marked this conversation as resolved.
Show resolved Hide resolved
};

return (
<Dropdown className="change-language">
{language ?
<div className="selected-item selected-language-block">
<span>Language: {language}</span>
<span> </span>
<Button
aria-label="Clear selection"
className="clear-button"
onClick={() => {
setLanguage(null);
sessionStorage.removeItem('lang_pref')
}}variant="link"> Reset ⓧ</Button>
</div> :
(<Dropdown.Toggle id="dropdown-language">
Select language
</Dropdown.Toggle>)}

<Dropdown.Menu>
<Dropdown.Item onClick={() => {
updateLanguage('EN');
}}>
English
</Dropdown.Item>
<Dropdown.Item onClick={() => {
updateLanguage('ES');
}}>
Español
</Dropdown.Item>
<Dropdown.Item onClick={() => {
updateLanguage('FR');
}}>
Français
</Dropdown.Item>
</Dropdown.Menu>
</Dropdown>
);
};

export default LanguageDropdown;
13 changes: 13 additions & 0 deletions src/components/LanguageDropdown.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 LanguageDropdown from "./LanguageDropdown";

describe("LanguageDropdown", () => {
it("renders correctly", () => {
const tree = renderer
.create(<LanguageDropdown />)
.toJSON();
expect(tree).toMatchSnapshot();
});
});
piperchester marked this conversation as resolved.
Show resolved Hide resolved
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
20 changes: 20 additions & 0 deletions src/components/__snapshots__/LanguageDropdown.test.js.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`LanguageDropdown renders correctly 1`] = `
<div
className="change-language dropdown"
onKeyDown={[Function]}
>
<button
aria-expanded={false}
aria-haspopup={true}
className="dropdown-toggle btn btn-primary"
disabled={false}
id="dropdown-language"
onClick={[Function]}
type="button"
>
Select language
</button>
</div>
`;
20 changes: 18 additions & 2 deletions src/styles/global.scss
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +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 {
color: white;
}

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

.change-language {
margin-bottom: 10px;
}

.change-country .current {
margin-bottom: 20px;
}

Expand Down
Loading