Skip to content

Commit

Permalink
Integrate Facebook Customer Chat (#331)
Browse files Browse the repository at this point in the history
  • Loading branch information
koistya authored Mar 16, 2019
1 parent de9d49b commit b1ef088
Show file tree
Hide file tree
Showing 22 changed files with 167 additions and 41 deletions.
1 change: 1 addition & 0 deletions .env
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ GOOGLE_CLIENT_SECRET=xxxxx

FACEBOOK_APP_ID=xxxxx
FACEBOOK_APP_SECRET=xxxxx
FACEBOOK_PAGE_ID=xxxxx

# PostgreSQL
# https://www.postgresql.org/docs/current/static/libpq-envars.html
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
"not ie <= 11",
"not op_mini all"
],

"dependencies": {
"@babel/polyfill": "^7.2.5",
"@babel/runtime": "^7.3.1",
Expand All @@ -39,6 +38,7 @@
"jsonwebtoken": "^8.5.0",
"jwt-passport": "^0.0.5",
"knex": "^0.16.3",
"load-script": "^1.0.0",
"lodash": "^4.17.11",
"moment-timezone": "^0.5.23",
"passport": "^0.4.0",
Expand Down
10 changes: 4 additions & 6 deletions src/common/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,12 @@ class App extends React.PureComponent {
state = { error: null };

componentDidRender = () => {
const { history, title } = this.props;
const { history, title, config } = this.props;
window.document.title = title;

gtag('config', window.config.gaTrackingId, {
page_title: title,
page_location: window.location.href,
page_path: `${window.location.pathname}${window.location.search}`,
});
// Track page views
gtag('config', config.gaTrackingId, { transport_type: 'beacon' });
// fb(FB => FB.AppEvents.logPageView());

const scrollY = getScrollPosition(history.location.key);

Expand Down
46 changes: 46 additions & 0 deletions src/common/CustomerChat.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/**
* React Starter Kit for Firebase
* https://github.com/kriasoft/react-firebase-starter
* Copyright (c) 2015-present Kriasoft | MIT License
*/

import React from 'react';
import { fb } from '../utils';
import { ConfigContext } from '../hooks';

// https://developers.facebook.com/docs/messenger-platform/discovery/customer-chat-plugin
class CustomerChat extends React.PureComponent {
componentDidMount() {
this.timeout = setTimeout(() => {
fb(FB => this.timeout && FB.XFBML.parse());
}, 3000);
}

componentWillUnmount() {
clearTimeout(this.timeout);
delete this.timeout;
}

render() {
return (
<ConfigContext.Consumer>
{config => (
<div
className="fb-customerchat"
attribution="setup_tool"
page_id={config.facebook.pageId}
// theme_color="..."
// logged_in_greeting="..."
// logged_out_greeting="..."
// greeting_dialog_display="..."
// greeting_dialog_delay="..."
// minimized="false"
// ref="..."
/>
)}
</ConfigContext.Consumer>
);
}
}

export default CustomerChat;
4 changes: 2 additions & 2 deletions src/common/LayoutToolbar.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ const styles = theme => ({

function LayoutToolbar({ classes: s, data: me, className, ...props }) {
const [userMenuEl, setUserMenuEl] = useState(null);
const { appName } = useConfig();
const { app } = useConfig();

function openUserMenu(event) {
setUserMenuEl(event.currentTarget);
Expand All @@ -60,7 +60,7 @@ function LayoutToolbar({ classes: s, data: me, className, ...props }) {
<Toolbar>
<Typography className={s.title} variant="h6" color="inherit">
<Link className={s.link} href="/">
{appName}
{app.name}
</Link>
</Typography>
<Button
Expand Down
18 changes: 13 additions & 5 deletions src/hooks.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@

/* @flow */

import React from 'react';
import React, { useContext, useEffect } from 'react';
import { ReactRelayContext } from 'react-relay';
import { fb } from './utils';

// Default history object (for unit tests)
const history = { location: { pathname: '/' } };
Expand All @@ -17,17 +18,24 @@ export const HistoryContext = React.createContext(history);
export const ResetContext = React.createContext(() => {});

export function useConfig() {
return React.useContext(ConfigContext);
return useContext(ConfigContext);
}

export function useHistory() {
return React.useContext(HistoryContext);
return useContext(HistoryContext);
}

export function useRelay() {
return React.useContext(ReactRelayContext);
return useContext(ReactRelayContext);
}

export function useReset() {
return React.useContext(ResetContext);
return useContext(ResetContext);
}

export function useFacebookEvent(event, callback, deps = []) {
useEffect(() => {
fb(FB => FB.Event.subscribe(event, callback), { async: false });
return fb(FB => FB.Event.unsubscribe(event, callback), { async: false });
}, deps);
}
1 change: 1 addition & 0 deletions src/landing/HomeSponsors.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ function HomeSponsors({ classes: s }) {
<div className={s.root}>
{sponsors.map(x => (
<a
key={x.name}
className={s.link}
href={x.link}
target="_blank"
Expand Down
2 changes: 1 addition & 1 deletion src/landing/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export default [
import(/* webpackChunkName: 'home' */ './HomeHero'),
],
render: ([Home, HomeHero], data, { config }) => ({
title: config.appName,
title: config.app.name,
component: (
<Layout data={data} hero={<HomeHero />}>
<Home data={data} />
Expand Down
6 changes: 3 additions & 3 deletions src/legal/Privacy.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ const styles = theme => ({
});

function Privacy({ classes: s }) {
const { appOrigin } = useConfig();
const { app } = useConfig();
return (
<div className={s.root}>
<Typography variant="h3" gutterBottom>
Expand All @@ -27,8 +27,8 @@ function Privacy({ classes: s }) {
<Typography paragraph>
Your privacy is important to us. It is Company&#39;s policy to respect
your privacy regarading any information we may collect from you across
our website, <a href={appOrigin}>{appOrigin}</a>, and other sites we own
and operate.
our website, <a href={`${app.origin}/`}>{app.origin}</a>, and other
sites we own and operate.
</Typography>
<Typography paragraph>
We only ask for personal information when we truly need it to provide a
Expand Down
16 changes: 8 additions & 8 deletions src/legal/Terms.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,21 +25,21 @@ const styles = theme => ({
});

function Privacy({ classes: s }) {
const { appOrigin } = useConfig();
const { app } = useConfig();
return (
<div className={s.root}>
<Typography variant="h3" gutterBottom>
Terms of Use
</Typography>
<Typography variant="h5">1. Terms</Typography>
<Typography paragraph>
By accessing the website at <a href={appOrigin}>{appOrigin}</a>, you are
agreeing to be bound by these terms of service, all applicable laws and
regulations, and agree that you are responsible for compliance with any
applicable local laws. If you do not agree with any of these terms, you
are prohibited from using or accessing this site. The materials
contained in this website are protected by applicable copyright and
trademark law.
By accessing the website at <a href={`${app.origin}/`}>{app.origin}</a>,
you are agreeing to be bound by these terms of service, all applicable
laws and regulations, and agree that you are responsible for compliance
with any applicable local laws. If you do not agree with any of these
terms, you are prohibited from using or accessing this site. The
materials contained in this website are protected by applicable
copyright and trademark law.
</Typography>
<Typography variant="h5">2. Use License</Typography>
<ol className={s.list} type="a">
Expand Down
4 changes: 2 additions & 2 deletions src/legal/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export default [
`,
components: () => [import(/* webpackChunkName: 'terms' */ './Terms')],
render: ([Terms], data, { config }) => ({
title: `Terms of Use • ${config.appName}`,
title: `Terms of Use • ${config.app.name}`,
component: (
<Layout data={data}>
<Terms data={data} />
Expand All @@ -38,7 +38,7 @@ export default [
`,
components: () => [import(/* webpackChunkName: 'privacy' */ './Privacy')],
render: ([Privacy], data, { config }) => ({
title: `Privacy Policy • ${config.appName}`,
title: `Privacy Policy • ${config.app.name}`,
component: (
<Layout data={data}>
<Privacy data={data} />
Expand Down
2 changes: 1 addition & 1 deletion src/misc/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export default [
`,
components: () => [import(/* webpackChunkName: 'about' */ './About')],
render: ([About], data, { config }) => ({
title: `About Us • ${config.appName}`,
title: `About Us • ${config.app.name}`,
component: (
<Layout data={data}>
<About data={data} />
Expand Down
2 changes: 1 addition & 1 deletion src/news/News.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ const styles = theme => ({
});

function News({ classes: s, data, ...props }) {
const [isOpen, setOpen] = useState();
const [isOpen, setOpen] = useState(false);
const [error, setError] = useState();
const { stories } = data;

Expand Down
2 changes: 1 addition & 1 deletion src/news/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export default [
}
`,
render: ([News], data, { config }) => ({
title: `News • ${config.appName}`,
title: `News • ${config.app.name}`,
component: (
<Layout data={data}>
<News data={data} />
Expand Down
21 changes: 16 additions & 5 deletions src/server/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,21 @@
* import { useConfig } from '../hooks';
*
* function Title() {
* const { appName } = useConfig();
* return <h1>{appName}</h1>
* const { app } = useConfig();
* return (<a href={app.origin}>{app.name}</a>);
* }
*
* IMPORTANT NOTE: Do not include any sensitive data into this file!
*/
export default {
// Core application settings
appName: process.env.APP_NAME,
appDescription: process.env.APP_DESCRIPTION,
appOrigin: process.env.APP_ORIGIN,
app: {
name: process.env.APP_NAME,
description: process.env.APP_DESCRIPTION,
origin: process.env.APP_ORIGIN,
version: process.env.APP_VERSION,
env: process.env.APP_ENV,
},

// Firebase
// https://firebase.google.com/docs/web/setup
Expand All @@ -27,6 +31,13 @@ export default {
apiKey: process.env.GCP_BROWSER_KEY,
},

// Facebook SDK for JavaScript (src/utils/fb.js)
// https://developers.facebook.com/docs/javascript/quickstart
facebook: {
appId: process.env.FACEBOOK_APP_ID,
pageId: process.env.FACEBOOK_PAGE_ID,
},

// Analytics
gaTrackingId: process.env.GA_TRACKING_ID,
};
6 changes: 3 additions & 3 deletions src/user/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export default [
path: '/login',
components: () => [import(/* webpackChunkName: 'login' */ './Login')],
render: ([Login], _, { config }) => ({
title: `Sign In to ${config.appName}`,
title: `Sign In to ${config.app.name}`,
component: <Login />,
chunks: ['login'],
}),
Expand All @@ -35,7 +35,7 @@ export default [
}
`,
render: ([UserProfile], data, { config }) => ({
title: `${data.user.displayName}${config.appName}`,
title: `${data.user.displayName}${config.app.name}`,
component: (
<Layout data={data}>
<UserProfile data={data.user} />
Expand All @@ -54,7 +54,7 @@ export default [
}
`,
render: ([Account], data, { config }) => ({
title: `My Account • ${config.appName}`,
title: `My Account • ${config.app.name}`,
component: (
<Layout data={data}>
<Account data={data} />
Expand Down
11 changes: 11 additions & 0 deletions src/utils/env.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/**
* React Starter Kit for Firebase
* https://github.com/kriasoft/react-firebase-starter
* Copyright (c) 2015-present Kriasoft | MIT License
*/

export const canUseDOM = !!(
typeof window !== 'undefined' &&
window.document &&
window.document.createElement
);
39 changes: 39 additions & 0 deletions src/utils/fb.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/**
* React Starter Kit for Firebase
* https://github.com/kriasoft/react-firebase-starter
* Copyright (c) 2015-present Kriasoft | MIT License
*/

import loadScript from 'load-script';
import { canUseDOM } from './env';

let initialized = false;
let queue = [];

export function fb(callback) {
if (!canUseDOM) {
return;
} else if (initialized) {
callback(window.FB);
} else {
queue.push(callback);
if (!window.fbAsyncInit) {
// https://developers.facebook.com/docs/javascript/reference/FB.init
window.fbAsyncInit = () => {
window.FB.init({
appId: window.config.facebook.appId,
autoLogAppEvents: true,
status: true,
cookie: true,
xfbml: false,
version: 'v3.2',
});
initialized = true;
queue.forEach(cb => cb(window.FB));
queue = null;
};
const isDebug = window.localStorage.getItem('fb:debug') === 'true';
loadScript(`https://connect.facebook.net/en_US/sdk/xfbml.customerchat${isDebug ? '/debug' : ''}.js`, { async: true }); // prettier-ignore
}
}
}
4 changes: 3 additions & 1 deletion src/utils/gtag.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@

/* @flow */

import { canUseDOM } from './env';

export function gtag() {
if (window !== undefined && window.config.gaTrackingId) {
if (canUseDOM && window.dataLayer) {
window.dataLayer.push(arguments);
}
}
Loading

0 comments on commit b1ef088

Please sign in to comment.