Adding install prompt link in the header
This commit is contained in:
parent
a23e72d633
commit
d41dad14a1
@ -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}
|
||||
>
|
||||
|
@ -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>
|
||||
|
16
src/components/InstallPrompt/__snapshots__/test.js.snap
Normal file
16
src/components/InstallPrompt/__snapshots__/test.js.snap
Normal 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>
|
||||
`;
|
53
src/components/InstallPrompt/index.js
Normal file
53
src/components/InstallPrompt/index.js
Normal 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);
|
88
src/components/InstallPrompt/test.js
Normal file
88
src/components/InstallPrompt/test.js
Normal 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();
|
||||
});
|
||||
});
|
@ -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;
|
||||
|
@ -65,3 +65,5 @@
|
||||
DOWNLOAD PNG
|
||||
"Loading...": |
|
||||
LOADING...
|
||||
"Add to Home Screen": |
|
||||
ADD TO HOME SCREEN
|
||||
|
@ -65,3 +65,5 @@
|
||||
Download PNG
|
||||
"Loading...": |
|
||||
Loading...
|
||||
"Add to Home Screen": |
|
||||
Add to Home Screen
|
||||
|
Loading…
Reference in New Issue
Block a user