Combine home and notification page and store ID in local storage
This commit is contained in:
parent
59ad62e2af
commit
86f23ed1a4
|
@ -29,7 +29,7 @@
|
|||
"moment": "^2.17.1",
|
||||
"qrcode.react": "^0.6.1",
|
||||
"react": "^0.13.0",
|
||||
"react-router": "^0.13.3",
|
||||
"react-router": "^2.0.0",
|
||||
"shortid": "^2.2.6",
|
||||
"socket.io": "^1.7.2",
|
||||
"socket.io-client": "^1.7.2"
|
||||
|
|
|
@ -6,7 +6,7 @@ body {
|
|||
background: #84DCCF;
|
||||
text-align: center;
|
||||
box-shadow: 0 0 7px #555;
|
||||
margin-bottom: 2.0rem;
|
||||
margin-bottom: 2.5rem;
|
||||
}
|
||||
|
||||
.title {
|
||||
|
@ -40,6 +40,11 @@ body {
|
|||
color: #cc0000;
|
||||
}
|
||||
|
||||
.storSupport p {
|
||||
background: rgba(132, 220, 207, 0.2);
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
code {
|
||||
white-space: normal;
|
||||
}
|
||||
|
|
33
src/App.js
33
src/App.js
|
@ -1,33 +0,0 @@
|
|||
import React from 'react';
|
||||
import Router, { RouteHandler } from 'react-router';
|
||||
|
||||
class App extends React.Component {
|
||||
constructor( props, context ) {
|
||||
super();
|
||||
this.publishRouter( context.router );
|
||||
}
|
||||
render() {
|
||||
let params = this.context.router.getCurrentParams();
|
||||
return (
|
||||
<RouteHandler {...params} />
|
||||
);
|
||||
}
|
||||
publishRouter( router ){
|
||||
var routes = {};
|
||||
|
||||
// Use route names as constants
|
||||
router.routes[0].childRoutes.forEach( function( r ){
|
||||
routes[ r.name ] = r.path;
|
||||
});
|
||||
|
||||
// Render the router accessible without contexts
|
||||
Router.currentRouter = router;
|
||||
Router.routes = routes;
|
||||
}
|
||||
}
|
||||
|
||||
App.contextTypes = {
|
||||
router: React.PropTypes.func
|
||||
};
|
||||
|
||||
export default App;
|
17
src/index.js
17
src/index.js
|
@ -1,10 +1,9 @@
|
|||
import React from 'react';
|
||||
import Router from 'react-router';
|
||||
import routes from './routes';
|
||||
import React from 'react'
|
||||
import { Router, Route, browserHistory } from 'react-router'
|
||||
import Site from './ui/Site';
|
||||
|
||||
Router.run( routes, Router.HistoryLocation, function( Handler ){
|
||||
React.render(
|
||||
React.createElement( Handler ),
|
||||
document.getElementById('root')
|
||||
);
|
||||
});
|
||||
React.render((
|
||||
<Router history={browserHistory}>
|
||||
<Route path="/*" component={Site} />
|
||||
</Router>
|
||||
), document.getElementById('root'))
|
||||
|
|
|
@ -1,13 +0,0 @@
|
|||
'use strict';
|
||||
import React from 'react';
|
||||
import Router, {Route, NotFoundRoute, DefaultRoute} from 'react-router';
|
||||
import App from './App';
|
||||
import Site from './ui/Site';
|
||||
|
||||
var routes = (
|
||||
<Route name="app" path="/*" handler={ App } >
|
||||
<DefaultRoute name="site" handler={ Site } />
|
||||
</Route>
|
||||
);
|
||||
|
||||
export default routes;
|
188
src/ui/Home.js
188
src/ui/Home.js
|
@ -1,14 +1,130 @@
|
|||
'use strict';
|
||||
import React from 'react';
|
||||
import Shortid from 'shortid';
|
||||
import { Router, Route, Link } from 'react-router';
|
||||
import io from 'socket.io-client';
|
||||
import QRCode from 'qrcode.react';
|
||||
|
||||
export default class Home extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
supported: false,
|
||||
registration: null,
|
||||
haveperm: false,
|
||||
connected: false,
|
||||
socket: io.connect()
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.connect();
|
||||
this.checksupport();
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.setState({socket: this.state.socket.removeAllListeners()});
|
||||
}
|
||||
|
||||
connect() {
|
||||
let socket = this.state.socket;
|
||||
|
||||
let room = this.props.id;
|
||||
|
||||
socket.on('connect', () => {
|
||||
socket.emit('room', room);
|
||||
this.setState({connected: true});
|
||||
|
||||
socket.on('disconnect', () => {
|
||||
this.setState({connected: false});
|
||||
});
|
||||
});
|
||||
|
||||
socket.on('message', (data) => {
|
||||
console.log("Notification: " + data);
|
||||
this.sendNotification(data);
|
||||
});
|
||||
}
|
||||
|
||||
sendNotification(data) {
|
||||
let title = data || 'Received a notification!';
|
||||
|
||||
let options = {
|
||||
body: 'Notification from Notica',
|
||||
icon: 'img/icon.png',
|
||||
iconUrl: 'img/icon.png',
|
||||
vibrate: [200, 100, 200]
|
||||
};
|
||||
|
||||
if (this.state.registration) {
|
||||
console.log(this.state.registration.showNotification(title, options));
|
||||
} else {
|
||||
console.log(new Notification(title, options));
|
||||
}
|
||||
}
|
||||
|
||||
checksupport() {
|
||||
let supported = ('Notification' in window);
|
||||
this.setState({supported: supported});
|
||||
|
||||
if (supported) {
|
||||
Notification.requestPermission(permission => {
|
||||
this.checkperm(permission);
|
||||
|
||||
try {
|
||||
navigator.serviceWorker.register('/js/sw.js').then((reg) => {
|
||||
this.setState({registration: reg});
|
||||
});
|
||||
} catch (e) { // If we are on a browser without serviceWorker
|
||||
this.setState({registration: false});
|
||||
}
|
||||
}.bind(this));
|
||||
}
|
||||
}
|
||||
|
||||
checkperm(permission) {
|
||||
if (permission === 'granted') {
|
||||
this.setState({haveperm: true});
|
||||
}
|
||||
else {
|
||||
this.setState({haveperm: false});
|
||||
}
|
||||
}
|
||||
|
||||
render(){
|
||||
let id = this.props.urlid || Shortid.generate();
|
||||
let id = this.props.id;
|
||||
let storSupport = this.props.storSupport;
|
||||
let supported = this.state.supported;
|
||||
let haveperm = this.state.haveperm;
|
||||
let connected = this.state.connected;
|
||||
|
||||
return (
|
||||
<div className="container">
|
||||
<div className="row">
|
||||
<div className="twelve columns">
|
||||
{ supported || <div className="error"><p>
|
||||
<i className="fa fa-times" aria-hidden="true"></i> This browser does not support desktop notifications.
|
||||
</p></div>}
|
||||
{ !haveperm && supported && <div>
|
||||
<p>
|
||||
Please give this site permission to display notifications.
|
||||
<br />
|
||||
<a className="button" href="javascript:void(0)" onClick={() => this.checkperm(Notification.permission)}>
|
||||
Check Again
|
||||
</a>
|
||||
</p>
|
||||
</div>}
|
||||
{ !connected && supported && <div className="error">
|
||||
<p>
|
||||
<i className="fa fa-times" aria-hidden="true"></i> Unable to connect to the Notica server.
|
||||
<br />
|
||||
Attempting to reconnect...
|
||||
</p>
|
||||
</div>}
|
||||
{ haveperm && connected && supported && <p>
|
||||
<i className="fa fa-check" aria-hidden="true"></i> This page is monitoring for notifications.
|
||||
</p>}
|
||||
</div>
|
||||
</div>
|
||||
<div className="row">
|
||||
<div className="twelve columns">
|
||||
<h4>Usage</h4>
|
||||
|
@ -21,7 +137,7 @@ export default class Home extends React.Component {
|
|||
<div className="six columns">
|
||||
<p><code>$ long-running-command; notica Finished!</code></p>
|
||||
<p>
|
||||
This will wait until the first command completes before running Notica. That way you can go do other things while your long task runs. Then you will recieve a notification on any devices that have the Notica website open.
|
||||
This will wait until the first command completes before running Notica. That way you can go do other things while your long task runs. Then you will recieve a notification on any devices that have the Notica website open with your unique ID.
|
||||
</p>
|
||||
</div>
|
||||
<div className="six columns">
|
||||
|
@ -37,7 +153,7 @@ export default class Home extends React.Component {
|
|||
$ echo 'notica() { curl --data "d:$*" https://notica.us/{id} ; }' >> ~/.bashrc && source ~/.bashrc
|
||||
</code>
|
||||
</p>
|
||||
<p>Go to this link to receive your notifications (bookmark it since it's yours): <Link to={'/' + id}>https://notica.us/{id}</Link></p>
|
||||
<p>Now open this page on any devices you want to receive the notifications on: <a href={'https://notica.us/' + id}>{'https://notica.us/' + id}</a></p>
|
||||
|
||||
<h4>Setup</h4>
|
||||
<p>Curl is required to use Notica.</p>
|
||||
|
@ -52,10 +168,66 @@ export default class Home extends React.Component {
|
|||
<code>$ source .bashrc</code>
|
||||
</p>
|
||||
<p>
|
||||
All done! Now go to this link (bookmark it since it's yours): <br />
|
||||
<Link to={'/' + id}>https://notica.us/{id}</Link>
|
||||
All done! Now open this page on any devices you want to receive the notifications on: <a href={'https://notica.us/' + id}>{'https://notica.us/' + id}</a><br />
|
||||
</p>
|
||||
|
||||
{ storSupport && <div className="storSupport"><p>
|
||||
<i className="fa fa-info-circle" aria-hidden="true"></i> Notica uses Local Storage to keep track of your unique ID. If you would like to generate a new random ID, <a href="/clear">click here</a>.
|
||||
</p></div>}
|
||||
</div>
|
||||
</div>
|
||||
<div className="row">
|
||||
<div className="six columns">
|
||||
<h4>Examples</h4>
|
||||
<p>Here are some different ways to use Notica:</p>
|
||||
<p>
|
||||
Just run it from your terminal: <br />
|
||||
<code>
|
||||
$ notica
|
||||
</code>
|
||||
</p>
|
||||
<p>
|
||||
Add a custom message: <br />
|
||||
<code>
|
||||
$ notica Hello world!
|
||||
</code>
|
||||
</p>
|
||||
<p>
|
||||
Get an alert when a command finishes: <br />
|
||||
<code>
|
||||
$ sudo apt-get update; notica Done!
|
||||
</code>
|
||||
</p>
|
||||
<p>
|
||||
Get an alert when a command succeeds: <br />
|
||||
<code>
|
||||
$ make all && notica Success!
|
||||
</code>
|
||||
</p>
|
||||
<p>
|
||||
Get an alert when a command fails: <br />
|
||||
<code>
|
||||
$ make all || notica Failed!
|
||||
</code>
|
||||
</p>
|
||||
</div>
|
||||
<div className="six columns">
|
||||
<h4>Tips</h4>
|
||||
<p>Bookmark this page! It is unique to the function in your <code className="smallcode">.bashrc</code> file.
|
||||
Notifications will be sent to all open pages with the same ID code in the URL.</p>
|
||||
<p>
|
||||
Use quotes on messages with special characters: <br />
|
||||
<code>
|
||||
$ notica "This is awesome :)"
|
||||
</code>
|
||||
</p>
|
||||
<p>
|
||||
Open this page on your phone:
|
||||
<center><QRCode value={'https://notica.us/' + id} /></center>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="row">
|
||||
<div className="twelve columns">
|
||||
<h4>About</h4>
|
||||
<p>
|
||||
Notica was written by <a href="http://tannercollin.com" target="_blank">Tanner Collin</a> after he got tired of checking if his commands were done running.
|
||||
|
|
|
@ -1,189 +0,0 @@
|
|||
'use strict';
|
||||
import React from 'react';
|
||||
import io from 'socket.io-client';
|
||||
import { Router, Route, Link } from 'react-router';
|
||||
import QRCode from 'qrcode.react';
|
||||
|
||||
export default class NotifPage extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
supported: false,
|
||||
registration: null,
|
||||
haveperm: false,
|
||||
connected: false,
|
||||
socket: io.connect()
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.connect();
|
||||
this.checksupport();
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.setState({socket: this.state.socket.removeAllListeners()});
|
||||
}
|
||||
|
||||
connect() {
|
||||
let socket = this.state.socket;
|
||||
|
||||
let room = this.props.urlid;
|
||||
|
||||
socket.on('connect', () => {
|
||||
socket.emit('room', room);
|
||||
this.setState({connected: true});
|
||||
|
||||
socket.on('disconnect', () => {
|
||||
this.setState({connected: false});
|
||||
});
|
||||
});
|
||||
|
||||
socket.on('message', (data) => {
|
||||
console.log("Notification: " + data);
|
||||
this.sendNotification(data);
|
||||
});
|
||||
}
|
||||
|
||||
sendNotification(data) {
|
||||
let title = data || 'Received a notification!';
|
||||
|
||||
let options = {
|
||||
body: 'Notification from Notica',
|
||||
icon: 'img/icon.png',
|
||||
iconUrl: 'img/icon.png',
|
||||
vibrate: [200, 100, 200]
|
||||
};
|
||||
|
||||
if (this.state.registration) {
|
||||
console.log(this.state.registration.showNotification(title, options));
|
||||
} else {
|
||||
console.log(new Notification(title, options));
|
||||
}
|
||||
}
|
||||
|
||||
checksupport() {
|
||||
let supported = ('Notification' in window);
|
||||
this.setState({supported: supported});
|
||||
|
||||
if (supported) {
|
||||
Notification.requestPermission(permission => {
|
||||
this.checkperm(permission);
|
||||
|
||||
try {
|
||||
navigator.serviceWorker.register('/js/sw.js').then((reg) => {
|
||||
this.setState({registration: reg});
|
||||
});
|
||||
} catch (e) { // If we are on a browser without serviceWorker
|
||||
this.setState({registration: false});
|
||||
}
|
||||
}.bind(this));
|
||||
}
|
||||
}
|
||||
|
||||
checkperm(permission) {
|
||||
if (permission === 'granted') {
|
||||
this.setState({haveperm: true});
|
||||
}
|
||||
else {
|
||||
this.setState({haveperm: false});
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
let supported = this.state.supported;
|
||||
let haveperm = this.state.haveperm;
|
||||
let connected = this.state.connected;
|
||||
let urlid = this.props.urlid;
|
||||
|
||||
return (
|
||||
<div className="container">
|
||||
<div className="row">
|
||||
<div className="twelve columns">
|
||||
<h4>Notification Page</h4>
|
||||
{ supported || <div className="error"><p>
|
||||
<i className="fa fa-times" aria-hidden="true"></i> This browser does not support desktop notifications.
|
||||
</p></div>}
|
||||
{ !haveperm && supported && <div>
|
||||
<p>
|
||||
Please give this site permission to display notifications.
|
||||
<br />
|
||||
<a className="button" href="#" onClick={() => this.checkperm(Notification.permission)}>
|
||||
Check Again
|
||||
</a>
|
||||
</p>
|
||||
</div>}
|
||||
{ !connected && supported && <div className="error">
|
||||
<p>
|
||||
<i className="fa fa-times" aria-hidden="true"></i> Unable to connect to the Notica server.
|
||||
<br />
|
||||
Attempting to reconnect...
|
||||
</p>
|
||||
</div>}
|
||||
{ haveperm && connected && supported && <p>
|
||||
<i className="fa fa-check" aria-hidden="true"></i> This page is monitoring for notifications.
|
||||
</p>}
|
||||
</div>
|
||||
</div>
|
||||
<div className="row">
|
||||
<div className="six columns">
|
||||
<h4>Examples</h4>
|
||||
<p>Here are some different ways to use Notica:</p>
|
||||
<p>
|
||||
Just run it from your terminal: <br />
|
||||
<code>
|
||||
$ notica
|
||||
</code>
|
||||
</p>
|
||||
<p>
|
||||
Add a custom message: <br />
|
||||
<code>
|
||||
$ notica Hello world!
|
||||
</code>
|
||||
</p>
|
||||
<p>
|
||||
Get an alert when a command finishes: <br />
|
||||
<code>
|
||||
$ sudo apt-get update; notica Done!
|
||||
</code>
|
||||
</p>
|
||||
<p>
|
||||
Get an alert when a command succeeds: <br />
|
||||
<code>
|
||||
$ make all && notica Success!
|
||||
</code>
|
||||
</p>
|
||||
<p>
|
||||
Get an alert when a command fails: <br />
|
||||
<code>
|
||||
$ make all || notica Failed!
|
||||
</code>
|
||||
</p>
|
||||
</div>
|
||||
<div className="six columns">
|
||||
<h4>Tips</h4>
|
||||
<p>Bookmark this page! It is unique to the function in your <code className="smallcode">.bashrc</code> file.
|
||||
Notifications will be sent to all open pages with the same ID code in the URL.</p>
|
||||
<p>
|
||||
Use quotes on messages with special characters: <br />
|
||||
<code>
|
||||
$ notica "This is awesome :)"
|
||||
</code>
|
||||
</p>
|
||||
<p>
|
||||
Need to set Notica up again? <br />
|
||||
<Link to={'/home/' + urlid}>
|
||||
Click here to go back to the instructions.
|
||||
</Link>
|
||||
</p>
|
||||
<p>
|
||||
Open this page on your phone:
|
||||
<center><QRCode value={'https://notica.us/' + urlid} /></center>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,37 +1,72 @@
|
|||
'use strict';
|
||||
import React from 'react';
|
||||
import Home from './Home';
|
||||
import NotifPage from './NotifPage';
|
||||
import Error from './Error';
|
||||
import Shortid from 'shortid';
|
||||
import { Router, Route, Link } from 'react-router';
|
||||
import { Link, browserHistory } from 'react-router';
|
||||
|
||||
export default class Site extends React.Component {
|
||||
render(){
|
||||
let url = this.props.splat;
|
||||
let page = null;
|
||||
let id = '';
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
page: null,
|
||||
id: '',
|
||||
storSupport: (typeof localStorage !== 'undefined')
|
||||
}
|
||||
}
|
||||
|
||||
componentWillMount() {
|
||||
this.setPage();
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
let oldUrl = prevProps.params.splat;
|
||||
let newUrl = this.props.params.splat;
|
||||
if (newUrl !== oldUrl) this.setPage();
|
||||
}
|
||||
|
||||
setId(url) {
|
||||
if (this.state.storSupport) {
|
||||
if (localStorage.getItem('id')) {
|
||||
this.state.id = url || localStorage.getItem('id');
|
||||
} else {
|
||||
this.state.id = url || Shortid.generate();
|
||||
}
|
||||
localStorage.setItem('id', this.state.id);
|
||||
} else {
|
||||
this.state.id = url || Shortid.generate();
|
||||
}
|
||||
}
|
||||
|
||||
setPage() {
|
||||
let url = this.props.params.splat;
|
||||
|
||||
if (url == 'clear') {
|
||||
localStorage.clear();
|
||||
url = '';
|
||||
}
|
||||
|
||||
if (url == '') {
|
||||
page = <Home />;
|
||||
}
|
||||
else if (url.substring(0, 4) == 'home') {
|
||||
id = url.substring(5);
|
||||
page = <Home urlid={id} />;
|
||||
this.setId();
|
||||
browserHistory.push('/' + this.state.id);
|
||||
this.state.page = <Home id={this.state.id} storSupport={this.state.storSupport} />;
|
||||
}
|
||||
else if (Shortid.isValid(url)) {
|
||||
id = url;
|
||||
page = <NotifPage urlid={url} />;
|
||||
this.setId(url);
|
||||
this.state.page = <Home id={this.state.id} storSupport={this.state.storSupport} />;
|
||||
}
|
||||
else {
|
||||
page = <Error />;
|
||||
this.state.page = <Error />;
|
||||
}
|
||||
}
|
||||
|
||||
render(){
|
||||
return (
|
||||
<div>
|
||||
<div className="hero">
|
||||
<div className="title">
|
||||
<Link to={'/home/' + id}>
|
||||
<Link to={'/' + this.state.id}>
|
||||
<img src="/img/logo.svg" />
|
||||
<span className="name">Notica</span>
|
||||
</Link>
|
||||
|
@ -40,7 +75,7 @@ export default class Site extends React.Component {
|
|||
Send browser notifications from your terminal. No installation. No registration.
|
||||
</div>
|
||||
</div>
|
||||
{page}
|
||||
{this.state.page}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user