diff --git a/.eslintrc b/.eslintrc index 6e125953..e16dcc44 100644 --- a/.eslintrc +++ b/.eslintrc @@ -14,6 +14,7 @@ "comma-dangle": 0, "indent": [2, 2, {"SwitchCase": 1}], "react/prop-types": 0, - "jsx-quotes": [2, "prefer-single"] + "jsx-quotes": [2, "prefer-single"], + "no-param-reassign": ["error", { "props": false }] } } diff --git a/css/components/_home.css b/css/components/_home.css index 86b009e6..0256ebf4 100644 --- a/css/components/_home.css +++ b/css/components/_home.css @@ -184,3 +184,7 @@ input { .ReactTags__selected .ReactTags__remove { margin-left: 3px; } + +.Select.is-open { + z-index: 100; +} diff --git a/index.html b/index.html index 12fd8eb3..760c0258 100644 --- a/index.html +++ b/index.html @@ -5,7 +5,7 @@ - + diff --git a/js/app.js b/js/app.js index ed9ab3c5..0481d933 100644 --- a/js/app.js +++ b/js/app.js @@ -13,11 +13,14 @@ // import 'file-loader?name=[name].[ext]!../.htaccess'; // Check for ServiceWorker support before trying to install it -// if (process.env.NODE_ENV === 'production') { -// if ('serviceWorker' in navigator) { +// if (process.env.NODE_ENV === 'development') { +// if ('serviceWorker' in navigator && 'PushManager' in window) { // navigator.serviceWorker.register('/serviceworker.js') // .then( -// registration => console.log('ServiceWorker registration successful with scope: ', registration.scope), +// registration => { +// console.log('ServiceWorker registration successful with scope: ', registration.scope); +// window.swRegistration = registration; +// }, // err => console.log('ServiceWorker registration failed: ', err) // ).catch(err => { // // Registration failed diff --git a/js/components/Email/EmailPanel/EmailPanel.jsx b/js/components/Email/EmailPanel/EmailPanel.jsx index 127592e6..296c66ba 100644 --- a/js/components/Email/EmailPanel/EmailPanel.jsx +++ b/js/components/Email/EmailPanel/EmailPanel.jsx @@ -20,7 +20,6 @@ import isJSON from 'validator/lib/isJSON'; import Select from 'react-select'; -import VirtualizedSelect from 'react-virtualized-select'; import ReactTooltip from 'react-tooltip' import RaisedButton from 'material-ui/RaisedButton'; import FlatButton from 'material-ui/FlatButton'; @@ -43,7 +42,6 @@ import PauseOverlay from './PauseOverlay.jsx'; import 'react-select/dist/react-select.css'; import 'react-virtualized/styles.css'; -import 'react-virtualized-select/styles.css'; import './react-select-hack.css'; import 'node_modules/alertifyjs/build/css/alertify.min.css'; import './ReactTagsStyle.css'; @@ -127,6 +125,7 @@ class EmailPanel extends Component { this.onClearClick = this._onClearClick.bind(this); this.checkEmailDupes = this._checkEmailDupes.bind(this); this.changeEmailSignature = this._changeEmailSignature.bind(this); + this.onSendTestEmail = this.onSendTestEmail.bind(this); // cleanups this.onEmailSendClick = _ => this.checkEmailDupes().then(this.onPreviewEmailsClick); @@ -226,6 +225,10 @@ class EmailPanel extends Component { this.setState({bodyEditorState: templateJSON.data}); this.props.saveEditorState(templateJSON.data); this.setState({subjectHtml}); + if (templateJSON.date) { + window.Intercom('trackEvent', 'use_prev_email_template', {date: templateJSON.date}); + mixpanel.track('use_prev_email_template', {date: templateJSON.date}); + } } else { this.props.setBodyHtml(bodyHtml); this.setState({bodyHtml, subjectHtml}); @@ -338,7 +341,6 @@ class EmailPanel extends Component { else invalidEmailContacts.push(contact); }); const {contactEmails, emptyFields} = this.getGeneratedHtmlEmails(validEmailContacts, subject, body); - console.log(emptyFields); Promise.resolve() .then(_ => @@ -405,7 +407,47 @@ class EmailPanel extends Component { .catch(_ => { console.log('CANCELLED'); }); + } + onSendTestEmail() { + // const {subject, body} = this.state; + // const email = this.props.person.email; + // let newHtml = html; + + // this.state.fieldsmap.map(fieldObj => { + // let value = ''; + // const replaceValue = _getter(contact, fieldObj); + // if (replaceValue) value = replaceValue; + // const regexValue = new RegExp('\{' + fieldObj.name + '\}', 'g'); + // // count num custom vars used + // const matches = newHtml.match(regexValue); + // if (matches !== null) { + // if (!value) emptyFields.push(fieldObj.name); + // matchCount[fieldObj.name] = matches.length; + // } + // newHtml = newHtml.replace(regexValue, value); + // if (expectedMatches !== null) expectedMatches = expectedMatches.filter(match => match !== `{${fieldObj.name}}`); + // }); + + // const bodyObj = replaceAll(body, selectedContacts[i], this.state.fieldsmap); + // const subjectObj = replaceAll(subject, selectedContacts[i], this.state.fieldsmap); + // let emailObj = { + // listid: this.props.listId, + // to: contact.email, + // subject: subjectObj.html, + // body: bodyObj.html, + // contactid: contact.id, + // templateid: this.state.currentTemplateId, + // cc: this.props.cc.map(item => item.text), + // bcc: this.props.bcc.map(item => item.text), + // fromemail: this.props.from, + // }; + // if (this.props.scheduledtime !== null) { + // emailObj.sendat = this.props.scheduledtime; + // } + // if (subjectObj.numMatches > 0) { + // emailObj.baseSubject = subject; + // } } _onClearClick() { @@ -473,7 +515,13 @@ class EmailPanel extends Component { {props.isImageReceiving && } -
+
+ { + /* + + + */ + } name || 'ignore_column'); this.props.onAddHeaders(order) .then(_ => { - if (!this.props.didInvalidate) setTimeout(_ => this.props.router.push(`/tables/${this.props.listId}?justCreated=true`), 5000); + if (!this.props.didInvalidate) { + this.setState({isLoading: true}); + setTimeout(_ => this.props.router.push(`/tables/${this.props.listId}?justCreated=true`), 2000); + } }); } @@ -180,12 +189,25 @@ class HeaderNaming extends Component { _ => {}); } + onListPresetSelect(list) { + if (!list) { + this.setState({selected: undefined}); + return; + } + const fieldsmap = generateTableFieldsmap(list) + .filter(field => field.customfield && !field.readonly && !this.state.options.some(option => option.value === field.value)) + .map(field => ({value: field.value, label: field.name, selected: false})); + const options = [...this.state.options, ...fieldsmap]; + this.setState({options, selected: list}, _ => this._headernames.recomputeGridSize()); + } + render() { const props = this.props; const state = this.state; return (
- {props.isReceiving && LOADING ...} + {props.isReceiving && + LOADING ...} {props.headers &&
@@ -195,6 +217,10 @@ class HeaderNaming extends Component { Tabulae will start to aggregate feeds from each contact's social fields once its connected. Upload Guide
+
+ Add Existing List Properties to Dropdown + +
+
+
+ + +
+ +
+ ); + } +} + +const styles = { + instructionContainer: {margin: '20px 0'}, + columnsContainer: {paddingTop: 20}, + preset: { + label: {fontSize: '1.2em', color: grey600}, + dropdown: {margin: 10} + }, + panel: { + backgroundColor: yellow50, + margin: 10, + padding: 10 + }, +}; + +const mapStateToProps = (state, props) => { + const lists = state.listReducer.lists.map(id => state.listReducer[id]); + const listId = props.listId; + const list = state.listReducer[listId]; + + const rawFieldsmap = generateTableFieldsmap(list); + return { + fieldsmap: rawFieldsmap, + list: list, + lists, + }; +}; + +const mapDispatchToProps = (dispatch, props) => { + return { + patchList: listObj => dispatch(listActions.patchList(listObj)), + fetchLists: _ => dispatch(listActions.fetchLists()), + }; +}; + +export default connect(mapStateToProps, mapDispatchToProps)(DragDropContext(HTML5Backend)(ColumnEditPanel)); diff --git a/js/components/ListTable/ColumnEditPanelHOC/Container.jsx b/js/components/ListTable/ColumnEditPanel/Container.jsx similarity index 95% rename from js/components/ListTable/ColumnEditPanelHOC/Container.jsx rename to js/components/ListTable/ColumnEditPanel/Container.jsx index 181474f9..3af247c6 100644 --- a/js/components/ListTable/ColumnEditPanelHOC/Container.jsx +++ b/js/components/ListTable/ColumnEditPanel/Container.jsx @@ -24,6 +24,12 @@ class Container extends Component { this.moveCard = this.moveCard.bind(this); } + componentWillReceiveProps(nextProps) { + if (this.props.list !== nextProps.list) { + this.setState({cards: nextProps.list}); + } + } + pushCard(card) { const {updateList, containerType} = this.props; const newCard = Object.assign({}, card, {hidden: containerType === 'hiddenList'}); @@ -129,8 +135,8 @@ const cardStyle = { const cardTarget = { hover(targetProps, monitor) { - const sourceProps = monitor.getItem(); - // console.log(targetProps); + const sourceProps = monitor.getItem(); + // console.log(targetProps); }, drop(props, monitor, component) { diff --git a/js/components/ListTable/ColumnEditPanelHOC/react_sortable_hoc.css b/js/components/ListTable/ColumnEditPanel/react_sortable_hoc.css similarity index 100% rename from js/components/ListTable/ColumnEditPanelHOC/react_sortable_hoc.css rename to js/components/ListTable/ColumnEditPanel/react_sortable_hoc.css diff --git a/js/components/ListTable/ColumnEditPanelHOC/ColumnEditPanelHOC.jsx b/js/components/ListTable/ColumnEditPanelHOC/ColumnEditPanelHOC.jsx deleted file mode 100644 index 8e21c61d..00000000 --- a/js/components/ListTable/ColumnEditPanelHOC/ColumnEditPanelHOC.jsx +++ /dev/null @@ -1,148 +0,0 @@ -import React, { Component } from 'react'; -import { DragDropContext } from 'react-dnd'; -import {actions as listActions} from 'components/Lists'; -import HTML5Backend from 'react-dnd-html5-backend'; -import Container from './Container.jsx'; -import {connect} from 'react-redux'; -import Dialog from 'material-ui/Dialog'; -import FlatButton from 'material-ui/FlatButton'; -import RaisedButton from 'material-ui/RaisedButton'; -import {yellow50} from 'material-ui/styles/colors'; - -import { - generateTableFieldsmap, - measureSpanSize, - exportOperations, - isNumber, - _getter, - reformatFieldsmap -} from 'components/ListTable/helpers'; -import alertify from 'alertifyjs'; - -alertify.promisifyConfirm = (title, description) => new Promise((resolve, reject) => { - alertify.confirm(title, description, resolve, reject); -}); - -alertify.promisifyPrompt = (title, description, defaultValue) => new Promise((resolve, reject) => { - alertify.prompt(title, description, defaultValue, (e, value) => resolve(value), reject); -}); - -class ColumnEditPanelHOC extends Component { - constructor(props) { - super(props); - const hiddenList = this.props.fieldsmap.filter(field => field.hidden && !field.tableOnly); - const showList = this.props.fieldsmap.filter(field => !field.hidden && !field.tableOnly); - this.state = { - hiddenList, - showList, - open: false, - isUpdating: false, - dirty: false, - }; - this.updateList = this.updateList.bind(this); - this.onSubmit = this.onSubmit.bind(this); - } - - updateList(list, containerType) { - this.setState({[containerType]: list, dirty: true}); - } - - onSubmit() { - const fieldsmap = reformatFieldsmap([...this.state.showList, ...this.state.hiddenList]); - const listBody = { - listId: this.props.listId, - name: this.props.list.name, - fieldsmap - }; - this.setState({isUpdating: true}); - this.props.patchList(listBody) - .then(_ => this.setState({isUpdating: false, open: false})) - } - - render() { - const state = this.state; - const actions = [ - this.setState({open: false})} - />, - , - ]; - - // console.log(this.props.fieldsmap); - - return ( -
- this.setState({open: false})}> -
- - Drag each card to reorder the order of you columns. Drag column cards from Hidden Columns to Showing Columns to activate or de-activate default columns. You can also create custom columns that you can use as template variable in emails. - -
- -
- - There is a number of auto-generated columns that are activated when certain columns are not hidden. For example, - activating Instagram Likes and Instagram Comments also activates Likes-to-Comments ratio. - -
-
- - -
-
- {this.props.children({onRequestOpen: _ => this.setState({open: true})})} -
- ); - } -} - -const style = { - // display: 'flex', - // justifyContent: 'space-around', - paddingTop: '20px' -}; - -const mapStateToProps = (state, props) => { - const listId = props.listId; - const list = state.listReducer[listId]; - - const rawFieldsmap = generateTableFieldsmap(list); - return { - fieldsmap: rawFieldsmap, - list: list - } -}; - -const mapDispatchToProps = (dispatch, props) => { - return { - patchList: listObj => dispatch(listActions.patchList(listObj)), - }; -}; - -export default connect(mapStateToProps, mapDispatchToProps)(DragDropContext(HTML5Backend)(ColumnEditPanelHOC)); diff --git a/js/components/ListTable/CopyToHOC/CopyToHOC.jsx b/js/components/ListTable/CopyToHOC/CopyToHOC.jsx index dd27a35a..66d0c145 100644 --- a/js/components/ListTable/CopyToHOC/CopyToHOC.jsx +++ b/js/components/ListTable/CopyToHOC/CopyToHOC.jsx @@ -93,9 +93,11 @@ class CopyToHOC extends Component { {props.selected.length === 0 && none selected} {props.selectedContacts && - {props.selectedContacts - .map(contact => contact.firstname || contact.lastname || contact.email) - .join(', ')}} + { + props.selectedContacts + .map(contact => contact.firstname || contact.lastname || contact.email || contact.id) + .join(', ') + }}

Select the List(s) to Copy these selected contacts to:

@@ -181,6 +183,7 @@ const styles = { const mapStateToProps = (state, props) => { const lists = state.listReducer.lists.map(id => state.listReducer[id]); + return { lists, list: state.listReducer[props.listId], diff --git a/js/components/ListTable/EmptyListStatement.jsx b/js/components/ListTable/EmptyListStatement.jsx index 7ff5e891..5312f406 100644 --- a/js/components/ListTable/EmptyListStatement.jsx +++ b/js/components/ListTable/EmptyListStatement.jsx @@ -3,10 +3,11 @@ import React from 'react'; const EmptyListStatement = ({className, style}) => (
-

You haven't added any contacts. You will see a master sheet of them here after you added some.

+

You haven't added any contact. You will see a master sheet of them here after you added some.

  • "Add Contact" icon on top to add ONE contact
  • Go back to Home and "Upload from Existing" Excel sheet
  • +
  • Want to use same columns as an another list? Use "Apply Presets" by clicking on icon
); diff --git a/js/components/ListTable/ListTable.jsx b/js/components/ListTable/ListTable.jsx index 6d79ba50..003513b8 100644 --- a/js/components/ListTable/ListTable.jsx +++ b/js/components/ListTable/ListTable.jsx @@ -36,7 +36,7 @@ import Drawer from 'material-ui/Drawer'; import {ControlledInput} from '../ToggleableEditInput'; import Waiting from '../Waiting'; import CopyToHOC from './CopyToHOC'; -import ColumnEditPanelHOC from 'components/ListTable/ColumnEditPanelHOC/ColumnEditPanelHOC.jsx'; +import ColumnEditPanel from 'components/ListTable/ColumnEditPanel/ColumnEditPanel.jsx'; import AddContactHOC from './AddContactHOC.jsx'; import AddTagDialogHOC from './AddTagDialogHOC.jsx'; import EditMultipleContactsHOC from './EditMultipleContactsHOC.jsx'; @@ -98,9 +98,10 @@ class ListTable extends Component { scrollToRow: undefined, currentSearchIndex: 0, isDeleting: false, - showEditPanel: false, + showContactEditPanel: false, currentEditContactId: undefined, showEmailPanel: true, + showColumnEditPanel: false, }; // store outside of state to update synchronously for PanelOverlay @@ -487,7 +488,7 @@ class ListTable extends Component { ); contentBody2 = !this.props.listData.readonly && this.setState({currentEditContactId: rowData.id, showEditPanel: true})} + onClick={_ => this.setState({currentEditContactId: rowData.id, showContactEditPanel: true})} className='fa fa-edit pointer' style={styles.profileIcon} color={blue300} @@ -704,8 +705,8 @@ class ListTable extends Component { this.setState({showEditPanel: false})} + open={state.showContactEditPanel} + onClose={_ => this.setState({showContactEditPanel: false})} /> {this.showProfileTooltip && )} - - {({onRequestOpen}) => ( - )} - + this.setState({showColumnEditPanel: true})} + /> + this.setState({showColumnEditPanel: false})} open={state.showColumnEditPanel} listId={props.listId} /> {({onRequestOpen}) => ( { - const res = normalize(response, { - data: arrayOf(listSchema), - }); + const res = normalize(response, {data: arrayOf(listSchema)}); const newOffset = response.data.length < PAGE_LIMIT ? null : OFFSET + PAGE_LIMIT; return dispatch(receiveLists(res.entities.lists, res.result.data, newOffset)); }) @@ -129,9 +127,7 @@ export function fetchPublicLists() { dispatch(requestLists()); return api.get(`/lists/public?limit=${PAGE_LIMIT}&offset=${OFFSET}`) .then(response => { - const res = normalize(response, { - data: arrayOf(listSchema), - }); + const res = normalize(response, {data: arrayOf(listSchema)}); const newOffset = response.data.length < PAGE_LIMIT ? null : OFFSET + PAGE_LIMIT; return dispatch({ type: listConstant.RECEIVE_MULTIPLE, @@ -175,9 +171,7 @@ export function fetchTagLists(tagQuery) { dispatch(requestLists()); return api.get(`/lists?q=tag:${tagQuery}&limit=${PAGE_LIMIT}&offset=${OFFSET}`) .then(response => { - const res = normalize(response, { - data: arrayOf(listSchema), - }); + const res = normalize(response, {data: arrayOf(listSchema)}); const newOffset = response.data.length < PAGE_LIMIT ? null : OFFSET + PAGE_LIMIT; return dispatch({ type: listConstant.RECEIVE_MULTIPLE, @@ -200,9 +194,7 @@ export function fetchArchivedLists() { dispatch(requestLists()); return api.get(`/lists/archived?limit=${PAGE_LIMIT}&offset=${OFFSET}&order=-Created`) .then(response => { - const res = normalize(response, { - data: arrayOf(listSchema), - }); + const res = normalize(response, {data: arrayOf(listSchema)}); const newOffset = response.data.length < PAGE_LIMIT ? null : OFFSET + PAGE_LIMIT; return dispatch({ type: listConstant.RECEIVE_MULTIPLE, diff --git a/js/components/UserProfile/BasicSettings.jsx b/js/components/UserProfile/BasicSettings.jsx index 8cb3ac8a..b5e4280f 100644 --- a/js/components/UserProfile/BasicSettings.jsx +++ b/js/components/UserProfile/BasicSettings.jsx @@ -4,6 +4,7 @@ import {ToggleableEditInputHOC, ToggleableEditInput} from '../ToggleableEditInpu import {fromJS, is} from 'immutable'; import {grey500} from 'material-ui/styles/colors'; import RaisedButton from 'material-ui/RaisedButton'; +import Toggle from 'material-ui/Toggle'; import {actions as loginActions} from 'components/Login'; @@ -43,9 +44,26 @@ class BasicSettings extends Component { this.state = { immuperson: fromJS(this.props.person), newPerson: fromJS(this.props.person), + notifySubscribed: false }; + // this.onToggle = this.onToggle.bind(this); + // this.onSubscribe = this.onSubscribe.bind(this); + // this.onUnsubscribe = this.onUnsubscribe.bind(this); } + // componentWillMount() { + // navigator.serviceWorker.ready.then(swRegistration => { + // swRegistration.pushManager.getSubscription() + // .then(subscription => { + // const isSubscribed = !(subscription === null); + // console.log('subscription'); + // console.log(isSubscribed); + // this.setState({notifySubscribed: isSubscribed}); + // }); + // window.swRegistration = swRegistration; + // }); + // } + componentWillUnmount() { if (!is(this.state.immuperson, this.state.newPerson)) { const newPerson = this.state.newPerson; @@ -59,6 +77,38 @@ class BasicSettings extends Component { } } + // onToggle(e, isToggled) { + // if (isToggled) this.onSubscribe(); + // else this.onUnsubscribe(); + // } + + // onSubscribe() { + // window.swRegistration.pushManager + // .subscribe({userVisibleOnly: true}) + // .then(subscription => { + // console.log(subscription); + // this.setState({notifySubscribed: true}); + // }) + // .catch(e => { + // console.log('Push Notify subscription denied by user'); + // }); + // } + + // onUnsubscribe() { + // window.swRegistration.pushManager.getSubscription() + // .then(subscription => { + // if (!subscription) { + // this.setState({notifySubscribed: false}); + // } + // subscription.unsubscribe() + // .then(_ => this.setState({notifySubscribed: false})); + // }) + // .then(e => { + // console.log('failed to subscribe'); + // }); + // } + + render() { const {person} = this.props; const state = this.state; @@ -105,6 +155,16 @@ class BasicSettings extends Component { />}
+ {/* +
+
+ Browser Notifications +
+
+ +
+
+ */} ); diff --git a/manifest.json b/manifest.json index 6891b967..dfd0284f 100644 --- a/manifest.json +++ b/manifest.json @@ -30,5 +30,5 @@ "start_url": "index.html", "display": "standalone", "orientation": "portrait", - "background_color": "#FFFFFF" + "background_color": "#FFFFFF", } \ No newline at end of file diff --git a/package.json b/package.json index 1cc85397..ec3f6b78 100644 --- a/package.json +++ b/package.json @@ -6,13 +6,14 @@ "alertifyjs": "^1.10.0", "axios": "^0.9.1", "classnames": "^2.2.5", - "draft-convert": "^1.4.3", + "draft-convert": "^1.4.7", "draft-js": "^0.10.0", "es6-promise": "^4.0.5", "fontfaceobserver": "^1.5.1", "fuse.js": "^2.6.2", "fuzzy": "^0.1.1", "hopscotch": "^0.2.6", + "ifvisible.js": "^1.0.6", "immutability-helper": "^2.2.2", "immutable": "^3.8.1", "install": "^0.8.1", @@ -25,7 +26,6 @@ "moment": "^2.14.1", "moment-timezone": "^0.5.9", "normalizr": "^2.2.1", - "npm": "^3.10.6", "numbro": "^1.9.3", "object-assign": "^4.1.0", "pikaday": "^1.4.0", @@ -70,8 +70,7 @@ "regression": "^1.2.1", "sanitize-html": "^1.14.1", "tlds": "^1.157.0", - "validator": "^5.5.0", - "zeroclipboard": "^2.2.0" + "validator": "^5.5.0" }, "devDependencies": { "appcache-webpack-plugin": "^1.2.0", diff --git a/serviceworker.js b/serviceworker.js index a811bbee..9c86de4f 100644 --- a/serviceworker.js +++ b/serviceworker.js @@ -1,61 +1,100 @@ -var CACHE_NAME = 'react-boilerplate-cache-v1'; -// The files we want to cache -var urlsToCache = [ - // '/', - '/css/main.css' -// '/js/bundle.js' -]; - -// Set the callback for the install step -self.addEventListener('install', function(event) { - // Perform install steps +self.addEventListener('push', function(event) { + console.log('Received a push message', event); + + // var title = 'Yay a message.'; + // var body = 'We have received a push message.'; + // var tag = 'simple-push-demo-notification-tag'; + // event.waitUntil( - caches.open(CACHE_NAME) - .then(function(cache) { - console.log('Opened cache'); - return cache.addAll(urlsToCache); - }); -}); + // self.registration.showNotification(title, { + // body: body, + // tag: tag + // }) + // ); + function log(argument) { + console.log(argument); + } + + function notification(args) { + var notifications = JSON.parse(args.data); + for (var i = notifications.length - 1; i >= 0; i--) { + self.registration.showNotification('Tabulae Notification', { + body: notifications[i].message, + }); + } + } -// Set the callback when the files get fetched -self.addEventListener('fetch', function(event) { - event.respondWith( - caches.match(event.request) - .then(function(response) { - // Cached files available, return those - if (response) { - return response; - } - - // IMPORTANT: Clone the request. A request is a stream and - // can only be consumed once. Since we are consuming this - // once by cache and once by the browser for fetch, we need - // to clone the response - var fetchRequest = event.request.clone(); - - // Start request again since there are no files in the cache - return fetch(fetchRequest).then(function(response) { - // If response is invalid, throw error - if (!response || response.status !== 200 || response.type !== 'basic') { - return response; - } - - // IMPORTANT: Clone the response. A response is a stream - // and because we want the browser to consume the response - // as well as the cache consuming the response, we need - // to clone it so we have 2 stream. - var responseToCache = response.clone(); - - // Otherwise cache the downloaded files - caches.open(CACHE_NAME) - .then(function(cache) { - cache.put(event.request, responseToCache); - }); - - // And return the network response - return response; - } - ); - }) - ); + event.waitUntil( + fetch('/users/me/token') + .then(response => { + const channel = new goog.appengine.Channel(response.token); + const socket = channel.open(); + socket.onopen = log; + socket.onmessage = args => notification(args); + socket.onerror = log; + socket.onclose = log; + })); }); + + +// var CACHE_NAME = 'react-boilerplate-cache-v1'; +// // The files we want to cache +// var urlsToCache = [ +// // '/', +// '/css/main.css' +// // '/js/bundle.js' +// ]; + +// // Set the callback for the install step +// self.addEventListener('install', function(event) { +// // Perform install steps +// // event.waitUntil( +// caches.open(CACHE_NAME) +// .then(function(cache) { +// console.log('Opened cache'); +// return cache.addAll(urlsToCache); +// }); +// }); + +// // Set the callback when the files get fetched +// self.addEventListener('fetch', function(event) { +// event.respondWith( +// caches.match(event.request) +// .then(function(response) { +// // Cached files available, return those +// if (response) { +// return response; +// } + +// // IMPORTANT: Clone the request. A request is a stream and +// // can only be consumed once. Since we are consuming this +// // once by cache and once by the browser for fetch, we need +// // to clone the response +// var fetchRequest = event.request.clone(); + +// // Start request again since there are no files in the cache +// return fetch(fetchRequest).then(function(response) { +// // If response is invalid, throw error +// if (!response || response.status !== 200 || response.type !== 'basic') { +// return response; +// } + +// // IMPORTANT: Clone the response. A response is a stream +// // and because we want the browser to consume the response +// // as well as the cache consuming the response, we need +// // to clone it so we have 2 stream. +// var responseToCache = response.clone(); + +// // Otherwise cache the downloaded files +// caches.open(CACHE_NAME) +// .then(function(cache) { +// cache.put(event.request, responseToCache); +// }); + +// // And return the network response +// return response; +// } +// ); +// }) +// ); +// });