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

[docs] Revamp the notifications #19615

Merged
merged 9 commits into from
Feb 11, 2020
Merged
Show file tree
Hide file tree
Changes from 2 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
9 changes: 6 additions & 3 deletions docs/notifications.json
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
[
{
"id": 27,
"title": "Tweet tweet!",
"text": "You can <a style=\"color: inherit;\" target=\"_blank\" rel=\"noopener\" href=\"https://twitter.com/MaterialUI\">follow us on Twitter</a> to receive exclusive tips and updates about Material-UI and the React ecosystem."
Copy link
Member

@oliviertassinari oliviertassinari Feb 10, 2020

Choose a reason for hiding this comment

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

I believe (looking for stats to support it, hold on) this message has been driving most of our new followers on Twitter. Should we keep it?

Copy link
Member

Choose a reason for hiding this comment

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

  • The message was introduced In October 2018: eaa0052
  • We went from an average of 70 new followers/month to 300 since then.

Copy link
Member

Choose a reason for hiding this comment

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

We went from an average of 70 new followers/month to 300 since then.

What did we get from the twitter followers? More poll participation, comments, issue participation in linked issues?

Copy link
Member

Choose a reason for hiding this comment

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

The pros I can think of Twitter followers:

  • Reach our users even when they are not directly using the product (polls, discussions)
  • Reach the React community at large, when our users' retweet

Copy link
Member Author

Choose a reason for hiding this comment

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

Should we keep it?

My logic for removing it was that it isn't news or an announcement, and we already have the twitter followers button (and footer link) on the home page. A better use might be, for example, to announce Twitter polls here, and in the poll tweet put "Follow @MaterialUI for the final results of this poll".

Copy link
Member

@oliviertassinari oliviertassinari Feb 10, 2020

Choose a reason for hiding this comment

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

I would be careful with the operational cost of using multiple channels for the same use case, but for important news, like the survey, it would definitely be interesting. Removing this message could be a way to measure the impact.

Copy link
Member Author

Choose a reason for hiding this comment

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

Okay, let's try it and see. If Twitter follower growth tanks, we'll have to reevaluate what the best method to promote the twitter account is.

Copy link
Member

Choose a reason for hiding this comment

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

The pros I can think of Twitter followers:

Sure but this is just a hypothesis. Did the participation in polls increase?

What do we get in retweets? Did you see download/funding increase?

As far as I can tell we're not monetizing the twitter account, right? It's only a promotional channel so we should see the effects on that in download/funding numbers.

},
{
"id": 35,
"text": "Let's translate! <a style=\"color: inherit;\" target=\"_blank\" rel=\"noopener\" data-ga-event-category=\"l10n\" data-ga-event-action=\"notification\" data-ga-event-label=\"zh\" href=\"https://translate.material-ui.com/\">帮助 Material-UI 将文档翻译成中文</a>. 🇨🇳",
"title": "Let's translate!",
"text": "<a style=\"color: inherit;\" target=\"_blank\" rel=\"noopener\" data-ga-event-category=\"l10n\" data-ga-event-action=\"notification\" data-ga-event-label=\"zh\" href=\"https://translate.material-ui.com/\">帮助 Material-UI 将文档翻译成中文</a>. 🇨🇳",
"userLanguage": "zh"
},
{
"id": 47,
"text": "New blog post: <a style=\"color: inherit;\" target=\"_blank\" rel=\"noopener\" href=\"https://medium.com/material-ui/2019-in-review-and-beyond-34f85e29926\">2019 in review and beyond</a>."
"title": "New blog post",
"text": "<a style=\"color: inherit;\" target=\"_blank\" rel=\"noopener\" href=\"https://medium.com/material-ui/2019-in-review-and-beyond-34f85e29926\">2019 in review and beyond</a>. 2019 was a great year for Material-UI. It puts us on an exciting path to solve even greater challenges in the coming years!"
}
]
]
2 changes: 1 addition & 1 deletion docs/src/modules/components/AppFrame.js
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,6 @@ function AppFrame(props) {
<MuiLink color="secondary" className={classes.skipNav} href="#main-content">
{t('skipToContent')}
</MuiLink>
<Notifications />
<MarkdownLinks />
<AppBar className={appBarClassName}>
<Toolbar>
Expand Down Expand Up @@ -320,6 +319,7 @@ function AppFrame(props) {
)}
</IconButton>
</Tooltip>
<Notifications />
<Tooltip title={t('github')} enterDelay={300}>
<IconButton
edge="end"
Expand Down
133 changes: 90 additions & 43 deletions docs/src/modules/components/Notifications.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,25 @@
import 'isomorphic-fetch';
import React from 'react';
import { useSelector } from 'react-redux';
import Button from '@material-ui/core/Button';
import { useRouter } from 'next/router';
import Snackbar from '@material-ui/core/Snackbar';
import { makeStyles } from '@material-ui/core/styles';
import NotificationsIcon from '@material-ui/icons/Notifications';
import Tooltip from '@material-ui/core/Tooltip';
import NoSsr from '@material-ui/core/NoSsr';
import IconButton from '@material-ui/core/IconButton';
import Badge from '@material-ui/core/Badge';
import Menu from '@material-ui/core/Menu';
import ListItem from '@material-ui/core/ListItem';
import ListItemText from '@material-ui/core/ListItemText';
import Divider from '@material-ui/core/Divider';
import sleep from 'modules/waterfall/sleep';
import { getCookie } from 'docs/src/modules/utils/helpers';
import notifications from '../../../notifications.json';

const useStyles = makeStyles(theme => ({
menu: {
maxWidth: theme.spacing(40),
},
}));

function getLastSeenNotification() {
const seen = getCookie('lastSeenNotification');
Expand All @@ -15,6 +29,10 @@ function getLastSeenNotification() {

let messages = null;

if (process.env.NODE_ENV !== 'production') {
messages = notifications;
}

async function getMessages() {
try {
if (!messages) {
Expand All @@ -32,43 +50,47 @@ async function getMessages() {
}

export default function Notifications() {
const [open, setOpen] = React.useState(false);
const [message, setMessage] = React.useState({});
const { route } = useRouter();
const classes = useStyles();
const [messageList, setMessageList] = React.useState([]);
const [unseenNotificationsCount, setUnseenNotificationsCount] = React.useState(0);
const [notificationsMenu, setNotificationsMenu] = React.useState(null);
const t = useSelector(state => state.options.t);
const userLanguage = useSelector(state => state.options.userLanguage);

const handleNotificationsMenuClick = event => {
setNotificationsMenu(event.currentTarget);
setUnseenNotificationsCount(0);
document.cookie = `lastSeenNotification=${messageList[0].id};path=/;max-age=31536000`;
};

const handleNotificationsMenuClose = () => {
setNotificationsMenu(null);
};

const handleMessage = () => {
const lastSeen = getLastSeenNotification();
const unseenMessages = messages.filter(message2 => {
if (message2.id <= lastSeen) {
return false;
}

const userMessages = messages.filter(message => {
if (
message2.userLanguage &&
message2.userLanguage !== userLanguage &&
message2.userLanguage !== navigator.language.substring(0, 2)
message.userLanguage &&
message.userLanguage !== userLanguage &&
message.userLanguage !== navigator.language.substring(0, 2)
) {
return false;
}

if (message2.route && message2.route !== route) {
return false;
}

return true;
});

if (unseenMessages.length > 0) {
setMessage(unseenMessages[0]);
setOpen(true);
const unseenCount = userMessages.reduce(
(count, message) => (message.id > lastSeen ? count + 1 : count),
0,
);

if (unseenCount > 0) {
setUnseenNotificationsCount(unseenCount);
}
};

const handleClose = () => {
setOpen(false);
document.cookie = `lastSeenNotification=${message.id};path=/;max-age=31536000`;
setMessageList(userMessages.reverse());
};

React.useEffect(() => {
Expand All @@ -89,25 +111,50 @@ export default function Notifications() {
return () => {
active = false;
};
}, [route]);
}, []);

return (
<Snackbar
key={message.id}
anchorOrigin={{ vertical: 'top', horizontal: 'center' }}
ContentProps={{ 'aria-describedby': 'notification-message' }}
message={
<span id="notification-message" dangerouslySetInnerHTML={{ __html: message.text }} />
}
action={
<Button size="small" color="secondary" onClick={handleClose}>
{t('close')}
</Button>
}
open={open}
autoHideDuration={20e3}
onClose={handleClose}
onExited={handleMessage}
/>
<React.Fragment>
<Tooltip title={t('notifications')} enterDelay={300}>
<IconButton
color="inherit"
aria-owns={notificationsMenu ? 'notifications-menu' : undefined}
aria-haspopup="true"
aria-label={t('notifications')}
onClick={handleNotificationsMenuClick}
data-ga-event-category="AppBar"
data-ga-event-action="notifications"
>
<Badge color="secondary" badgeContent={unseenNotificationsCount}>
<NotificationsIcon />
</Badge>
</IconButton>
</Tooltip>
<NoSsr>
<Menu
id="notifications-menu"
anchorEl={notificationsMenu}
open={Boolean(notificationsMenu)}
onClose={handleNotificationsMenuClose}
>
mbrookes marked this conversation as resolved.
Show resolved Hide resolved
{messageList.map((message, index) => (
<div key={message.id} className={classes.menu}>
<ListItem alignItems="flex-start">
<ListItemText
primary={message.title}
secondary={
<span
id="notification-message"
dangerouslySetInnerHTML={{ __html: message.text }}
/>
}
/>
</ListItem>
{index < messageList.length - 1 ? <Divider /> : null}
</div>
))}
</Menu>
</NoSsr>
</React.Fragment>
);
}
1 change: 1 addition & 0 deletions docs/translations/translations.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"useDarkTheme": "Use dark theme",
"toggleTheme": "Toggle light/dark theme",
"toggleRTL": "Toggle right-to-left/left-to-right",
"notifications": "Notifications",
"github": "GitHub repository",
"strapline": "React components for faster and easier web development. Build your own design system, or start with Material Design.",
"getStarted": "Get Started",
Expand Down