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:
parent
0bc9a8d306
commit
24621b03f2
10 changed files with 269 additions and 169 deletions
109
app/javascript/chat/__tests__/util.test.js
Normal file
109
app/javascript/chat/__tests__/util.test.js
Normal 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,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
49
app/javascript/packs/Chat.jsx
Normal file
49
app/javascript/packs/Chat.jsx
Normal 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);
|
||||
});
|
||||
48
app/javascript/packs/Onboarding.jsx
Normal file
48
app/javascript/packs/Onboarding.jsx
Normal 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);
|
||||
}),
|
||||
);
|
||||
|
|
@ -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,
|
||||
);
|
||||
}),
|
||||
);
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -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();
|
||||
}),
|
||||
);
|
||||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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? %>
|
||||
|
|
|
|||
|
|
@ -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"/>
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue