Restructure pack files part I (#377)

* Renamed pack file from chat.jsx to Chat.jsx.

* refactor

* Missed a js pack where chat.js -> Chat.jsx

* 👷Refactor

* 👷Refactor

* 👷Refactor

* 👷Refactor

* Tests

* Fixed some wording in a test description.
This commit is contained in:
Nick Taylor 2018-08-29 12:59:20 -04:00 committed by Mac Siri
parent 0bc9a8d306
commit 24621b03f2
10 changed files with 269 additions and 169 deletions

View file

@ -0,0 +1,109 @@
import { getUserDataAndCsrfToken } from '../util';
const ERROR_MESSAGE = "Couldn't find user data on page.";
describe('Chat utilities', () => {
describe('getUserDataAndCsrfToken', () => {
afterEach(() => {
document.head.innerHTML = '';
document.body.removeAttribute('data-user');
});
test('should reject if no user or csrf token found.', async () => {
await expect(getUserDataAndCsrfToken(document)).rejects.toThrow(
ERROR_MESSAGE,
);
});
test('should reject if csrf token found but no user.', async () => {
document.head.innerHTML =
'<meta name="csrf-token" content="some-csrf-token" />';
await expect(getUserDataAndCsrfToken(document)).rejects.toThrow(
ERROR_MESSAGE,
);
});
test('should reject if user found but no csrf token found.', async () => {
document.body.setAttribute('data-user', '{}');
await expect(getUserDataAndCsrfToken(document)).rejects.toThrow(
ERROR_MESSAGE,
);
});
test('should resolve if user and csrf token found.', () => {
const csrfToken = 'some-csrf-token';
const currentUser = {
id: 41,
name: 'Guy Fieri',
username: 'guyfieri',
profile_image_90:
'/uploads/user/profile_image/41/0841dbe2-208c-4daa-b498-b2f01f3d37b2.png',
followed_tag_names: [],
followed_tags: '[]',
followed_user_ids: [
2,
31,
7,
38,
22,
37,
14,
26,
20,
24,
11,
27,
29,
3,
6,
28,
4,
39,
8,
40,
25,
30,
35,
34,
5,
12,
33,
36,
21,
18,
23,
1,
32,
19,
15,
13,
16,
9,
10,
17,
],
reading_list_ids: [48, 49, 34, 51, 64, 56],
saw_onboarding: true,
onboarding_checklist: {
write_your_first_article: false,
follow_your_first_tag: false,
fill_out_your_profile: false,
leave_your_first_reaction: true,
follow_your_first_dev: true,
leave_your_first_comment: false,
},
checked_code_of_conduct: false,
number_of_comments: 0,
display_sponsors: true,
trusted: false,
};
document.head.innerHTML = `<meta name="csrf-token" content="${csrfToken}" />`;
document.body.setAttribute('data-user', JSON.stringify(currentUser));
expect(getUserDataAndCsrfToken(document)).resolves.toEqual({
currentUser,
csrfToken,
});
});
});
});

View file

@ -1,35 +1,40 @@
import 'intersection-observer';
import { sendKeys } from './actions';
export function getCsrfToken() {
const element = document.querySelector(`meta[name='csrf-token']`);
return element !== null ? element.content : undefined;
}
const getWaitOnUserDataHandler = ({ resolve, reject, waitTime = 20 }) => {
let totalTimeWaiting = 0;
return function waitingOnUserData() {
if (totalTimeWaiting === 3000) {
reject(new Error("Couldn't find user data on page."));
return;
}
const csrfToken = getCsrfToken(document);
const { user } = document.body.dataset;
if (user && csrfToken !== undefined) {
const currentUser = JSON.parse(user);
resolve({ currentUser, csrfToken });
return;
}
totalTimeWaiting += waitTime;
setTimeout(waitingOnUserData, waitTime);
};
};
export function getUserDataAndCsrfToken() {
const promise = new Promise((resolve, reject) => {
let i = 0;
const waitingOnUserData = setInterval(() => {
let userData = null;
const dataUserAttribute = document.body.getAttribute('data-user');
const meta = document.querySelector("meta[name='csrf-token']");
if (
dataUserAttribute &&
dataUserAttribute !== 'undefined' &&
dataUserAttribute !== undefined &&
meta &&
meta.content !== 'undefined' &&
meta.content !== undefined
) {
userData = JSON.parse(dataUserAttribute);
}
i += 1;
if (userData) {
clearInterval(waitingOnUserData);
resolve(userData);
} else if (i === 3000) {
clearInterval(waitingOnUserData);
reject(new Error("Couldn't find user data on page."));
}
}, 5);
return new Promise((resolve, reject) => {
getWaitOnUserDataHandler({ resolve, reject })();
});
return promise;
}
export function scrollToBottom() {
@ -76,39 +81,41 @@ export function adjustTimestamp(timestamp) {
return time;
}
export function setupNotifications() {
navigator.serviceWorker.ready.then((serviceWorkerRegistration) => {
serviceWorkerRegistration.pushManager.getSubscription()
.then(function(subscription) {
navigator.serviceWorker.ready.then(serviceWorkerRegistration => {
serviceWorkerRegistration.pushManager
.getSubscription()
.then(subscription => {
if (subscription) {
return subscription;
}
return serviceWorkerRegistration.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: window.vapidPublicKey
applicationServerKey: window.vapidPublicKey,
});
}).then(function(subscription) {
sendKeys(subscription.toJSON(), null, null)
})
.then(subscription => {
sendKeys(subscription.toJSON(), null, null);
});
});
}
export function getNotificationState() {
//Not yet ready
if (!window.location.href.includes('ask-for-notifications')){
return "dont-ask"
// Not yet ready
if (!window.location.href.includes('ask-for-notifications')) {
return 'dont-ask';
}
// Let's check if the browser supports notifications
if (!("Notification" in window)) {
return "not-supported"
} else if (Notification.permission === "granted") {
setupNotifications();
return "granted"
} else if (Notification.permission !== 'denied') {
return "waiting-permission"
} else {
return "denied"
if (!('Notification' in window)) {
return 'not-supported';
}
}
const { permission } = Notification;
if (permission === 'granted') {
setupNotifications();
}
return permission === 'default' ? 'waiting-permission' : permission;
}

View file

@ -0,0 +1,49 @@
import { h, render } from 'preact';
import { getUserDataAndCsrfToken } from '../chat/util';
import Chat from '../chat/chat';
function initializeChat(loadChat) {
getUserDataAndCsrfToken()
.then(loadChat)
.catch(error => {
// eslint-disable-next-line no-console
console.error('Unable to load chat', error);
});
}
function renderChat(root) {
render(<Chat {...root.dataset} />, root, root.firstChild);
}
const loadChat = ({ currentUser, csrfToken }) => {
const root = document.getElementById('chat');
if (!root) {
return;
}
window.currentUser = currentUser;
window.csrfToken = csrfToken;
const placeholder = document.getElementById('chat_placeholder');
renderChat(root);
if (placeholder) {
root.removeChild(placeholder);
}
window.InstantClick.on('change', () => {
if (window.location.href.indexOf('/connect') === -1) {
return;
}
renderChat(root);
});
};
initializeChat(loadChat);
window.InstantClick.on('change', () => {
initializeChat(loadChat);
});

View file

@ -0,0 +1,48 @@
import { h, render } from 'preact';
import { getUserDataAndCsrfToken } from '../chat/util';
import getUnopenedChannels from '../src/utils/getUnopenedChannels';
HTMLDocument.prototype.ready = new Promise(resolve => {
if (document.readyState !== 'loading') {
return resolve();
}
document.addEventListener('DOMContentLoaded', () => resolve());
return null;
});
function isUserSignedIn() {
return (
document.head.querySelector(
'meta[name="user-signed-in"][content="true"]',
) !== null
);
}
function renderPage() {
import('../src/Onboarding')
.then(({ default: Onboarding }) =>
render(<Onboarding />, document.getElementById('top-bar')),
)
.catch(error => {
// eslint-disable-next-line no-console
console.error('Unable to load onboarding', error);
});
}
document.ready.then(
getUserDataAndCsrfToken()
.then(({ currentUser, csrfToken }) => {
window.currentUser = currentUser;
window.csrfToken = csrfToken;
getUnopenedChannels();
if (isUserSignedIn() && !currentUser.saw_onboarding) {
renderPage();
}
})
.catch(error => {
// eslint-disable-next-line no-console
console.error('Error getting user and CSRF Token', error);
}),
);

View file

@ -11,19 +11,17 @@ HTMLDocument.prototype.ready = new Promise(resolve => {
});
document.ready.then(
getUserDataAndCsrfToken().then(currentUser => {
getUserDataAndCsrfToken().then(({ currentUser, csrfToken }) => {
window.currentUser = currentUser;
window.csrfToken = csrfToken;
const root = document.getElementById('article-form');
window.csrfToken = document.querySelector(
"meta[name='csrf-token']",
).content;
const { article, organization } = root.dataset;
render(
<ArticleForm
article={document.getElementById('article-form').dataset.article}
organization={document.getElementById('article-form').dataset.organization}
/>,
<ArticleForm article={article} organization={organization} />,
root,
root.firstElementChild
root.firstElementChild,
);
}),
);

View file

@ -1,71 +0,0 @@
import { h, render } from 'preact';
import { getUserDataAndCsrfToken } from '../chat/util';
import Chat from '../chat/chat';
HTMLDocument.prototype.ready = new Promise(resolve => {
if (document.readyState !== 'loading') {
return resolve();
}
document.addEventListener('DOMContentLoaded', () => resolve());
return null;
});
loadChat(); // Load initially
window.InstantClick.on('change', () => {
loadChat(); // Load via instantclick nav
});
function loadChat() {
getUserDataAndCsrfToken().then(currentUser => {
if (document.getElementById('chat')) {
const {
chatChannels,
pusherKey,
chatOptions,
algoliaKey,
algoliaId,
algoliaIndex,
githubToken,
} = document.getElementById('chat').dataset;
window.currentUser = currentUser;
window.csrfToken = document.querySelector(
"meta[name='csrf-token']",
).content;
const renderTarget = document.getElementById('chat');
const placeholder = document.getElementById('chat_placeholder');
const root = render(
<Chat
pusherKey={pusherKey}
chatChannels={chatChannels}
chatOptions={chatOptions}
algoliaId={algoliaId}
algoliaKey={algoliaKey}
algoliaIndex={algoliaIndex}
githubToken={githubToken}
/>,
renderTarget,
renderTarget.firstChild,
);
if (placeholder) {
renderTarget.removeChild(placeholder);
}
window.InstantClick.on('change', () => {
if (window.location.href.indexOf('/connect') != -1) {
const root = render(
<Chat
pusherKey={pusherKey}
chatChannels={chatChannels}
chatOptions={chatOptions}
algoliaId={algoliaId}
algoliaKey={algoliaKey}
algoliaIndex={algoliaIndex}
githubToken={githubToken}
/>,
renderTarget,
renderTarget.firstChild,
);
}
});
}
});
}

View file

@ -1,40 +0,0 @@
import { h, render } from 'preact';
import Onboarding from '../src/Onboarding';
import { getUserDataAndCsrfToken } from '../chat/util';
import getUnopenedChannels from '../src/utils/getUnopenedChannels';
HTMLDocument.prototype.ready = new Promise(resolve => {
if (document.readyState !== 'loading') {
return resolve();
}
document.addEventListener('DOMContentLoaded', () => resolve());
return null;
});
function shouldShowOnboarding() {
return (
document.head.getElementsByTagName('meta')[2].content === 'true' &&
document.body.getAttribute('data-user') &&
document.body.getAttribute('data-user') !== 'undefined' &&
JSON.parse(document.body.getAttribute('data-user')).saw_onboarding === false
);
}
function renderPage() {
if (shouldShowOnboarding()) {
setTimeout(() => {
render(<Onboarding />, document.getElementById('top-bar'));
}, 580);
}
}
document.ready.then(
getUserDataAndCsrfToken().then(currentUser => {
window.currentUser = currentUser;
window.csrfToken = document.querySelector(
"meta[name='csrf-token']",
).content;
renderPage();
getUnopenedChannels();
}),
);

View file

@ -8,7 +8,7 @@
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.38.0/theme/material.min.css">
<% if user_signed_in? %>
<%= javascript_pack_tag 'chat', defer: true %>
<%= javascript_pack_tag 'Chat', defer: true %>
<div class="chat-page-wrapper">
<div
id="chat"

View file

@ -41,7 +41,7 @@
<% if core_pages? %>
<%= javascript_include_tag 'base', defer: true %>
<% if user_signed_in? %>
<%= javascript_pack_tag 'pack', defer: true %>
<%= javascript_pack_tag 'Onboarding', defer: true %>
<% end %>
<% end %>
<% if !core_pages? %>

View file

@ -1,5 +1,5 @@
<% if user_signed_in? %>
<%= javascript_pack_tag 'chat', defer: true %>
<%= javascript_pack_tag 'Chat', defer: true %>
<% end %>
<% title "DEV Live 📡👩‍💻👨‍💻👩‍💻👨‍💻" %>
<link rel="canonical" href="https://dev.to/live"/>