Skip to content

Commit cb21b7c

Browse files
authored
Merge pull request #113 from davideast/firebase-ssr-flaky-chat-network
Server-side rendering, custom element-ing, realtiming, flaky network …
2 parents 5490755 + 9042749 commit cb21b7c

14 files changed

+4868
-0
lines changed

firebase-firestore-comments/.babelrc

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"plugins": [
3+
"transform-es2015-modules-commonjs"
4+
]
5+
}
+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"projects": {
3+
"default": "supercharged-comments"
4+
}
5+
}
+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
.vscode
2+
functions
3+
node_modules
4+
public
5+
firebase-debug.log
+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"hosting": {
3+
"public": "public",
4+
"rewrites": [
5+
{
6+
"source": "**",
7+
"function": "supercharged"
8+
}
9+
]
10+
}
11+
}
+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
{
2+
"name": "supercharged",
3+
"version": "1.0.0",
4+
"main": "index.js",
5+
"license": "MIT",
6+
"scripts": {
7+
"build": "yarn build:client && yarn build:server && yarn build:components && yarn babel:components",
8+
"build:server": "cpx src/server/**/* functions",
9+
"build:client": "cpx src/client/**/* public",
10+
"build:components": "cpx src/components/**/* public/components",
11+
"babel:components": "babel src/components -d functions/components",
12+
"serve": "firebase serve --only functions,hosting"
13+
},
14+
"dependencies": {
15+
"express": "^4.16.2",
16+
"firebase": "^4.9.0",
17+
"firebase-functions": "^0.8.1"
18+
},
19+
"devDependencies": {
20+
"babel-cli": "^6.26.0",
21+
"babel-plugin-transform-es2015-modules-commonjs": "^6.26.0",
22+
"cpx": "^1.5.0",
23+
"firebase-tools": "~3.17.4"
24+
}
25+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/**
2+
*
3+
* Copyright 2018 Google Inc. All rights reserved.
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
import { LoginButton } from './components/sc-login.js';
18+
import { CommentForm } from './components/sc-comment-form.js';
19+
import { CommentList } from './components/sc-comment-list.js';
20+
import { Comment } from './components/sc-comment.js';
21+
22+
customElements.define('sc-login', LoginButton);
23+
customElements.define('sc-comment-form', CommentForm);
24+
customElements.define('sc-comment-list', CommentList);
25+
customElements.define('sc-comment', Comment);
26+
27+
const scLogin = document.querySelector('sc-login');
28+
const scForm = document.querySelector('sc-comment-form');
29+
30+
scForm.addEventListener('comment-sent', e => {
31+
const commentsRef = firebase.firestore().collection('comments');
32+
commentsRef.add({
33+
text: e.detail.text,
34+
photoUrl: scLogin.user.photoURL,
35+
authorName: scLogin.user.displayName,
36+
timestamp: firebase.firestore.FieldValue.serverTimestamp()
37+
});
38+
});
39+
40+
scLogin.addEventListener('on-auth', e => {
41+
if(e.detail) {
42+
scLogin.classList.add('sc-hidden');
43+
} else {
44+
scLogin.classList.remove('sc-hidden');
45+
}
46+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/**
2+
*
3+
* Copyright 2018 Google Inc. All rights reserved.
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
import { SCElement } from './sc-element.js';
18+
19+
const html = String.raw;
20+
21+
export class CommentForm extends SCElement {
22+
static template() {
23+
return html`
24+
<textarea></textarea>
25+
<button id="btnSend" class="sc-btn">Send</button>
26+
`;
27+
}
28+
static component() {
29+
return html`
30+
<sc-comment-form>
31+
${this.template()}
32+
</sc-comment-form>
33+
`;
34+
}
35+
connectedCallback() {
36+
this.btnSend = this.querySelector('#btnSend');
37+
this.textarea = this.querySelector('textarea');
38+
this.btnSend.addEventListener('click', e => {
39+
const text = this.textarea.value;
40+
const detail = { text };
41+
const event = new CustomEvent('comment-sent', { detail });
42+
this.dispatchEvent(event);
43+
this.textarea.value = '';
44+
});
45+
}
46+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/**
2+
*
3+
* Copyright 2018 Google Inc. All rights reserved.
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
import { SCElement } from './sc-element.js';
18+
import { Comment } from './sc-comment.js';
19+
20+
const html = String.raw;
21+
22+
export class CommentList extends SCElement {
23+
static component(state) {
24+
return html`
25+
<sc-comment-list>
26+
${state}
27+
</sc-comment-list>
28+
`;
29+
}
30+
31+
connectedCallback() {
32+
this.commentsRef = firebase.firestore().collection('comments');
33+
this.commentsRef.orderBy('timestamp').onSnapshot(snap => {
34+
snap.docChanges.forEach(change => {
35+
const elInDOM = this.querySelector(`#_${change.doc.id}`);
36+
switch(change.type) {
37+
case 'added':
38+
if(elInDOM) { return; }
39+
this.addComment(change.doc);
40+
break;
41+
case 'removed':
42+
elInDOM.remove();
43+
break;
44+
}
45+
});
46+
});
47+
}
48+
49+
addComment(doc) {
50+
const element = document.createElement('sc-comment');
51+
element.id = `_${doc.id}`;
52+
element.innerHTML = Comment.template(doc.data());
53+
this.appendChild(element);
54+
}
55+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/**
2+
*
3+
* Copyright 2018 Google Inc. All rights reserved.
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
import { SCElement } from './sc-element.js';
18+
19+
const html = String.raw;
20+
21+
export class Comment extends SCElement {
22+
static template(state) {
23+
return html`
24+
<div class="sc-author">
25+
<img class="sc-circle-avatar" src="${state.photoUrl}" alt="Profile Photo">
26+
<div class="sc-author-name">${state.authorName}</div>
27+
</div>
28+
<div class="sc-comment-text">${state.text}</div>
29+
`;
30+
}
31+
static component(state, id) {
32+
return html`
33+
<sc-comment id="_${id}">
34+
${this.template(state)}
35+
</sc-comment>
36+
`;
37+
}
38+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/**
2+
*
3+
* Copyright 2018 Google Inc. All rights reserved.
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
// are you node?
18+
// yah
19+
// umm... use this HTMLElement class I made
20+
// okay... sure?
21+
22+
// are you browser?
23+
// yah
24+
// umm... use your HTMLElement class
25+
// okay... I was gonna do that anyways? thx?
26+
27+
let _HTMLElement;
28+
if(typeof process !== 'undefined') {
29+
_HTMLElement = class HTMLElement { }
30+
} else {
31+
_HTMLElement = HTMLElement;
32+
}
33+
34+
export class SCElement extends _HTMLElement { }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/**
2+
*
3+
* Copyright 2018 Google Inc. All rights reserved.
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
const html = String.raw;
19+
20+
export class LoginButton extends HTMLElement {
21+
static template() {
22+
return html`
23+
<button id="btnLogin" class="sc-btn">Login</button>
24+
`;
25+
}
26+
connectedCallback() {
27+
this.appendChild(template.content.cloneNode(true));
28+
this.auth = firebase.auth();
29+
this.btnLogin = this.querySelector('#btnLogin');
30+
31+
this.auth.onAuthStateChanged(user => {
32+
const event = new CustomEvent('on-auth', { detail: user });
33+
this.user = user;
34+
this.dispatchEvent(event);
35+
});
36+
37+
this.btnLogin.addEventListener('click', e => {
38+
const google = new firebase.auth.GoogleAuthProvider();
39+
this.auth.signInWithRedirect(google);
40+
});
41+
}
42+
}
43+
44+
let template = document.createElement('template');
45+
template.innerHTML = LoginButton.template();
46+

0 commit comments

Comments
 (0)