Adding install prompt link in the header

This commit is contained in:
Jeff Avallone 2019-01-16 20:09:04 -05:00
parent a23e72d633
commit d41dad14a1
8 changed files with 179 additions and 0 deletions

View File

@ -39,6 +39,9 @@ exports[`Header rendering 1`] = `
</WithMergedOptions(TransComponent)>
</mockConstructor>
</li>
<li>
<LoadNamespace(InstallPrompt) />
</li>
<li
data-requires-js={true}
>
@ -87,6 +90,9 @@ exports[`Header rendering with no banner 1`] = `
</WithMergedOptions(TransComponent)>
</mockConstructor>
</li>
<li>
<LoadNamespace(InstallPrompt) />
</li>
<li
data-requires-js={true}
>

View File

@ -6,6 +6,7 @@ import { withNamespaces, Trans } from 'react-i18next';
import GitlabIcon from 'react-feather/dist/icons/gitlab';
import LocaleSwitcher from 'components/LocaleSwitcher';
import InstallPrompt from 'components/InstallPrompt';
import style from './style.module.css';
@ -31,6 +32,9 @@ export const Header = ({ banner }) => (
<Trans>Privacy Policy</Trans>
</Link>
</li>
<li>
<InstallPrompt />
</li>
<li data-requires-js>
<LocaleSwitcher />
</li>

View File

@ -0,0 +1,16 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`InstallPrompt rendering 1`] = `""`;
exports[`InstallPrompt rendering after an install prompt has been requested 1`] = `""`;
exports[`InstallPrompt rendering after an install prompt has been requested 2`] = `
<a
href="#install"
onClick={[Function]}
>
<WithMergedOptions(TransComponent)>
Add to Home Screen
</WithMergedOptions(TransComponent)>
</a>
`;

View File

@ -0,0 +1,53 @@
import React from 'react';
import { withNamespaces, Trans } from 'react-i18next';
class InstallPrompt extends React.PureComponent {
state = {
installPrompt: null
}
componentDidMount() {
window.addEventListener('beforeinstallprompt', this.handleInstallPrompt);
}
componentWillUnmount() {
window.removeEventListener('beforeinstallprompt', this.handleInstallPrompt);
}
handleInstallPrompt = event => {
this.setState({
installPrompt: event
});
}
handleInstall = async event => {
event.preventDefault();
const { installPrompt } = this.state;
try {
installPrompt.prompt();
await installPrompt.userChoice;
}
catch {
// User cancelled install
}
this.setState({ installPrompt: null });
}
render() {
const { installPrompt } = this.state;
if (!installPrompt) {
return null;
}
return <a href="#install" onClick={ this.handleInstall }>
<Trans>Add to Home Screen</Trans>
</a>;
}
}
export { InstallPrompt };
export default withNamespaces()(InstallPrompt);

View File

@ -0,0 +1,88 @@
import React from 'react';
import { shallow } from 'enzyme';
import { InstallPrompt } from 'components/InstallPrompt';
describe('InstallPrompt', () => {
test('rendering', () => {
const component = shallow(
<InstallPrompt />
);
expect(component).toMatchSnapshot();
});
test('rendering after an install prompt has been requested', () => {
const component = shallow(
<InstallPrompt />
);
expect(component).toMatchSnapshot();
component.instance().handleInstallPrompt({
prompt: jest.fn()
});
expect(component).toMatchSnapshot();
});
test('adding and removing event listener', () => {
jest.spyOn(window, 'addEventListener');
jest.spyOn(window, 'removeEventListener');
const component = shallow(
<InstallPrompt />
);
const handleInstallPrompt = component.instance().handleInstallPrompt;
expect(window.addEventListener).toHaveBeenCalledWith(
'beforeinstallprompt',
handleInstallPrompt);
component.unmount();
expect(window.removeEventListener).toHaveBeenCalledWith(
'beforeinstallprompt',
handleInstallPrompt);
});
test('accepting install prompt', async () => {
const component = shallow(
<InstallPrompt />
);
const promptObj = {
prompt: jest.fn(),
userChoice: Promise.resolve()
};
const eventObj = { preventDefault: jest.fn() };
component.instance().handleInstallPrompt(promptObj);
component.find('a').simulate('click', eventObj);
// Allow async code to run
await new Promise(resolve => setTimeout(resolve));
expect(eventObj.preventDefault).toHaveBeenCalled();
expect(promptObj.prompt).toHaveBeenCalled();
expect(component.state('installPrompt')).toBeNull();
});
test('rejecting install prompt', async () => {
const component = shallow(
<InstallPrompt />
);
const promptObj = {
prompt: jest.fn(),
userChoice: Promise.reject()
};
const eventObj = { preventDefault: jest.fn() };
component.instance().handleInstallPrompt(promptObj);
component.find('a').simulate('click', eventObj);
// Allow async code to run
await new Promise(resolve => setTimeout(resolve));
expect(eventObj.preventDefault).toHaveBeenCalled();
expect(promptObj.prompt).toHaveBeenCalled();
expect(component.state('installPrompt')).toBeNull();
});
});

View File

@ -46,6 +46,10 @@
padding-right: var(--list-separator-width);
}
& li:empty {
display: none;
}
& li:before {
content: '//';
padding: 0 0.5rem;
@ -71,6 +75,10 @@
padding-left: var(--list-separator-width);
}
& li:empty {
display: none;
}
& li:after {
content: '//';
padding: 0 0.5rem;

View File

@ -65,3 +65,5 @@
DOWNLOAD PNG
"Loading...": |
LOADING...
"Add to Home Screen": |
ADD TO HOME SCREEN

View File

@ -65,3 +65,5 @@
Download PNG
"Loading...": |
Loading...
"Add to Home Screen": |
Add to Home Screen