Skip to content
This repository has been archived by the owner on Jun 3, 2024. It is now read-only.

QMAPS-2033 add "add to home" infobox on mobile after the 5th visit #1161

Draft
wants to merge 3 commits into
base: master
Choose a base branch
from
Draft
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
35 changes: 35 additions & 0 deletions src/components/AddToHomeInfoBox.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/* global _ */
import React, { useState } from 'react';
import { Notification } from './ui';
import { get, set } from 'src/adapters/store';

const AddToHomeInfoBox = () => {
const [closed, setClosed] = useState(get('add_to_home_closed'));
const closeBetaPopup = () => {
set('add_to_home_closed', 1);
setClosed(true);
};

const visits = parseInt(get('visits') || 0) + 1;
set('visits', visits);
Copy link
Contributor

Choose a reason for hiding this comment

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

This is a good example of a side effect that we want to control more and safely separate from the component rendering.

If we put it here in the render function, we will increment visits each time this component is re-rendered, which can happen at any moment in the app not related to a single hit.
You can already see it in these cases:

  • when the window is resized and the device is changed from desktop to mobile (as it's rendered as a child of a DeviceContext.Provider)
  • after the box is displayed and we call setClosed(true)

To ensure this increment happens only on mounting the component, you could put it inside a useEffect(…, [ ]).
But this still means if for some reason we unmount and remount this component during a user session, it will be counted twice.
So the safer approach IMO is to update this counter outside this component, where we are 100% sure we'll execute code only once per session. For example, as a sideEffect of RootComponent or in app_panel. The get can still happen here as it doesn't modify anything.


return (
// Show popup on mobile, at the fifth visit, if it hasn't already been closed
visits >= 5 &&
!closed && (
<Notification
title={_('Psst, do you come here often ?')}
description={_('Add a Qwant Maps shortcut to your Home screen !')}
type="info"
onClose={closeBetaPopup}
footer={
<div className="notification-link">
<a href="#">{_('Follow the guide to add the shortcut')}</a>
</div>
}
/>
)
);
};

export default AddToHomeInfoBox;
30 changes: 30 additions & 0 deletions src/components/ui/Notification.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import React from 'react';
import cs from 'classnames';
import { string, func, node, oneOfType } from 'prop-types';
import { CloseButton } from 'src/components/ui';
import { IconInformation } from 'src/components/ui/icons';
import { ACTION_BLUE_BASE } from 'src/libs/colors';

const Notification = ({ className = '', title, description, onClose, footer }) => (
<div className={cs('notification', className)}>
<span className="notification-title">
<span>
<IconInformation className="u-mr-xs" fill={ACTION_BLUE_BASE} />
<span role="notification">{title}</span>
</span>
<CloseButton onClick={onClose} position="topRight" />
</span>
<div className="notification-content">
<span role="notification">{description}</span>
</div>
{footer}
</div>
);
Notification.propTypes = {
className: string,
title: string.isRequired,
description: oneOfType([string, node]).isRequired,
onClose: func.isRequired,
};

export default Notification;
2 changes: 2 additions & 0 deletions src/components/ui/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import FloatingItems from './FloatingItems';
import SourceFooter from './SourceFooter';
import UserFeedbackQuestion from './UserFeedbackQuestion';
import UserFeedbackYesNo from './UserFeedbackYesNo';
import Notification from './Notification';
import Alert from './Alert';
import Chevron from './Chevron';

Expand All @@ -41,6 +42,7 @@ export {
SourceFooter,
UserFeedbackQuestion,
UserFeedbackYesNo,
Notification,
Alert,
Chevron,
};
2 changes: 2 additions & 0 deletions src/panel/RootComponent.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import Menu from 'src/panel/Menu';
import PanelManager from 'src/panel/PanelManager';
import { isMobileDevice, mobileDeviceMediaQuery, DeviceContext } from 'src/libs/device';
import { fire } from 'src/libs/customEvents';
import AddToHomeInfoBox from 'src/components/AddToHomeInfoBox';
import { useConfig } from 'src/hooks';
import { PoiProvider } from 'src/libs/poiContext';

Expand Down Expand Up @@ -34,6 +35,7 @@ const RootComponent = ({ router }) => {
<PanelManager router={router} />
</PoiProvider>
{!isMobile && isBurgerMenuEnabled && <Menu />}
{isMobile && <AddToHomeInfoBox />}
</DeviceContext.Provider>
);
};
Expand Down
51 changes: 51 additions & 0 deletions src/scss/includes/components/notification.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
.notification {
position: fixed;
top: 92px;
width: 360px;
right: 12px;
padding: 16px;
border-radius: 12px;
color: $grey-semi-darkness;
background-color: $background;
box-shadow: 0 1px 4px 0 rgba(12, 12, 14, 0.2), 0 0 2px 0 rgba(12, 12, 14, 0.12);

@media (max-width: 760px) {
width: 200px;
}

@media (max-width: 640px) {
width: 360px;
top: calc(64px + 16px);
bottom: unset;
right: 12px;
max-width: calc(100vw - 24px);
}

&-title {
display: inline-flex;
align-items: center;
justify-content: space-between;
width: 100%;
margin-bottom: $spacing-xs;
font-size: 14px;
font-weight: bold;
line-height: 18px;
color: $grey-black;

> span {
display: inline-flex;
align-items: center;
}
}

&-content {
color: $grey-semi-darkness;
font-size: 14px;
line-height: 18px;
}

&-link {
margin: $spacing-xs 0;
cursor: pointer;
}
}
1 change: 1 addition & 0 deletions src/scss/includes/ui_components.scss
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
@import "./components/alert";
@import "./components/notification";
@import "./components/badge";
@import "./components/panel";
@import "./components/itemList";
Expand Down
4 changes: 4 additions & 0 deletions src/scss/includes/z_index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@
z-index: 3;
}

.notification {
z-index: 3;
}

.modal_overlay {
z-index: 6;
}
Expand Down