363 lines
13 KiB
JavaScript
363 lines
13 KiB
JavaScript
import React, { Fragment } from 'react';
|
|
import { NextAuth } from 'next-auth/client'
|
|
import Layout from '../components/MyLayout.js'
|
|
import withStyles from '@material-ui/core/styles/withStyles';
|
|
import Paper from '@material-ui/core/Paper';
|
|
import Stepper from '@material-ui/core/Stepper';
|
|
import Step from '@material-ui/core/Step';
|
|
import StepLabel from '@material-ui/core/StepLabel';
|
|
import Button from '@material-ui/core/Button';
|
|
import Typography from '@material-ui/core/Typography';
|
|
import PushParamForm from '../components/push/PushParamForm';
|
|
import PushReview from '../components/push/PushReview';
|
|
import PushTargetForm from '../components/push/PushTargetForm';
|
|
import CircularProgress from '@material-ui/core/CircularProgress';
|
|
import axios from 'axios'
|
|
import getConfig from 'next/config'
|
|
import green from '@material-ui/core/colors/green';
|
|
import orange from '@material-ui/core/colors/orange';
|
|
import Snackbar from '@material-ui/core/Snackbar';
|
|
import SnackbarContent from '@material-ui/core/SnackbarContent';
|
|
import dynamic from 'next/dynamic'
|
|
import Link from 'next/link'
|
|
import Cookies from 'universal-cookie'
|
|
import Router from 'next/router'
|
|
|
|
const styles = theme => ({
|
|
appBar: {
|
|
position: 'relative',
|
|
},
|
|
layout: {
|
|
width: 'auto',
|
|
marginLeft: theme.spacing.unit * 2,
|
|
marginRight: theme.spacing.unit * 2,
|
|
[theme.breakpoints.up(600 + theme.spacing.unit * 2 * 2)]: {
|
|
width: 600,
|
|
marginLeft: 'auto',
|
|
marginRight: 'auto',
|
|
},
|
|
},
|
|
paper: {
|
|
marginTop: theme.spacing.unit * 3,
|
|
marginBottom: theme.spacing.unit * 3,
|
|
padding: theme.spacing.unit * 2,
|
|
[theme.breakpoints.up(600 + theme.spacing.unit * 3 * 2)]: {
|
|
marginTop: theme.spacing.unit * 6,
|
|
marginBottom: theme.spacing.unit * 6,
|
|
padding: theme.spacing.unit * 3,
|
|
},
|
|
},
|
|
stepper: {
|
|
padding: `${theme.spacing.unit * 3}px 0 ${theme.spacing.unit * 5}px`,
|
|
},
|
|
buttons: {
|
|
display: 'flex',
|
|
justifyContent: 'flex-end',
|
|
},
|
|
button: {
|
|
marginTop: theme.spacing.unit * 3,
|
|
marginLeft: theme.spacing.unit,
|
|
},
|
|
});
|
|
|
|
|
|
const { publicRuntimeConfig } = getConfig()
|
|
|
|
let back = ''
|
|
const steps = ['Parameters', 'Target', 'Review'];
|
|
|
|
class PushCreator extends React.Component {
|
|
state = {
|
|
session: this.props.session,
|
|
isSignedIn: (this.props.session.user) ? true : false,
|
|
activeStep: 0,
|
|
title: '',
|
|
body: '',
|
|
action: publicRuntimeConfig.push.defaultAction,
|
|
iconLink: publicRuntimeConfig.push.defaultIconLink,
|
|
imageLink: publicRuntimeConfig.push.defaultImageLink,
|
|
target: 'a',
|
|
topic: '',
|
|
loading: false,
|
|
openSnack: false,
|
|
error: false,
|
|
warning: false,
|
|
success: false,
|
|
snackMessage: ""
|
|
};
|
|
|
|
static async getInitialProps({ req }) {
|
|
let props = {};
|
|
|
|
props.session = await NextAuth.init({ req })
|
|
|
|
return props
|
|
}
|
|
|
|
constructor(props) {
|
|
super(props);
|
|
}
|
|
async componentDidMount() {
|
|
|
|
}
|
|
|
|
getStepContent = (step) => {
|
|
switch (step) {
|
|
case 0:
|
|
return <PushParamForm
|
|
onSelectedTitle={this.setTitle}
|
|
onSelectedBody={this.setBody}
|
|
onSelectedAction={this.setAction}
|
|
onSelectedImageLink={this.setImageLink}
|
|
onSelectedIconLink={this.setIconLink}
|
|
title={this.state.title}
|
|
body={this.state.body}
|
|
action={this.state.action}
|
|
imageLink={this.state.imageLink}
|
|
iconLink={this.state.iconLink}
|
|
/>;
|
|
case 1:
|
|
return <PushTargetForm
|
|
onSelectedTarget={this.setTarget}
|
|
onSelectedTopic={this.setTopic}
|
|
target={this.state.target}
|
|
topic={this.state.topic} />;
|
|
case 2:
|
|
return <PushReview
|
|
title={this.state.title}
|
|
body={this.state.body}
|
|
action={this.state.action}
|
|
imageLink={this.state.imageLink}
|
|
iconLink={this.state.iconLink}
|
|
target={this.state.target} />;
|
|
default:
|
|
throw new Error('Unknown step');
|
|
}
|
|
}
|
|
|
|
setTitle = (title) => {
|
|
this.setState(state => ({
|
|
title
|
|
}));
|
|
}
|
|
|
|
setBody = (body) => {
|
|
this.setState(state => ({
|
|
body
|
|
}));
|
|
}
|
|
|
|
setAction = (action) => {
|
|
this.setState(state => ({
|
|
action
|
|
}));
|
|
}
|
|
setImageLink = (imageLink) => {
|
|
this.setState(state => ({
|
|
imageLink
|
|
}));
|
|
}
|
|
setIconLink = (iconLink) => {
|
|
this.setState(state => ({
|
|
iconLink
|
|
}));
|
|
}
|
|
setTarget = (target) => {
|
|
this.setState(state => ({
|
|
target
|
|
}));
|
|
}
|
|
setTopic = (topic) => {
|
|
this.setState(state => ({
|
|
topic
|
|
}));
|
|
}
|
|
async componentDidMount() {
|
|
//loading lib for client side only
|
|
let result = await import("../src/backSync.js")
|
|
back = result.default
|
|
|
|
const cookies = new Cookies()
|
|
cookies.set('redirect_url', window.location.pathname, { path: '/' })
|
|
}
|
|
|
|
sendPush(url, payload) {
|
|
axios.post(url, {
|
|
payload
|
|
}).then(response => {
|
|
this.setState({ success: true, error: false, warning: false, message: '', snackMessage: "Votre message à bien été envoyé.", loading: false, openSnack: false })
|
|
}).catch(error => {
|
|
if (error.status != 500) {
|
|
if (process.browser) {
|
|
// client-side-only code
|
|
back.saveEventDataLocally([{ message: this.state.message }]);
|
|
}
|
|
}
|
|
this.setState({ success: false, error: false, warning: true, snackMessage: "📴 Votre message n'a pas pu aboutir, mais a été sauvegardé. Nous l'enverrons lorsque nous aurons une meilleure connectivité.", loading: false, openSnack: true })
|
|
});
|
|
}
|
|
|
|
async sendSingleMessage(payload) {
|
|
let EdeclicLib = (await import('../components/firebase-client.js')).default
|
|
if (!EdeclicLib.messaging)
|
|
return
|
|
payload.message.token = await EdeclicLib.askForToken();
|
|
|
|
this.sendPush("/push/message", payload)
|
|
}
|
|
|
|
sendToAll(payload) {
|
|
this.sendPush("/push/allsubscribers", payload)
|
|
}
|
|
|
|
sendToTopic(payload) {
|
|
payload.message.topic = this.state.topic
|
|
this.sendPush("/push/message", payload)
|
|
}
|
|
|
|
handleNext = async () => {
|
|
"use strict";
|
|
if (this.state.activeStep == 2) {
|
|
//TODO: verify infos
|
|
let payload = {
|
|
message: {
|
|
webpush: {
|
|
headers: {
|
|
Urgency: "high"
|
|
},
|
|
notification: {
|
|
title: this.state.title,
|
|
body: this.state.body,
|
|
icon: this.state.iconLink,
|
|
image: this.state.imageLink,
|
|
click_action: this.state.action
|
|
}
|
|
}
|
|
}
|
|
}
|
|
//single
|
|
if (this.state.target === 'a') {
|
|
this.sendSingleMessage(payload)
|
|
}//to All
|
|
else if (this.state.target === 'b') {
|
|
this.sendToAll(payload.message)
|
|
}//to topics
|
|
else if (this.state.target === 'c') {
|
|
this.sendToTopic(payload)
|
|
}
|
|
|
|
}
|
|
this.setState(state => ({
|
|
activeStep: state.activeStep + 1,
|
|
}));
|
|
};
|
|
|
|
handleBack = () => {
|
|
this.setState(state => ({
|
|
activeStep: state.activeStep - 1,
|
|
}));
|
|
};
|
|
|
|
handleReset = () => {
|
|
this.setState({
|
|
activeStep: 0,
|
|
});
|
|
};
|
|
|
|
handleClose = () => {
|
|
this.setState({ openSnack: false })
|
|
}
|
|
|
|
render() {
|
|
const { classes } = this.props;
|
|
const { activeStep } = this.state;
|
|
|
|
return (
|
|
<Layout menu={this.props.menu}>
|
|
{(this.state.isSignedIn) &&
|
|
(<Fragment>
|
|
<main className={classes.layout}>
|
|
<Paper className={classes.paper}>
|
|
{this.state.loading && (
|
|
<div className="alert alert-info">
|
|
<CircularProgress color="secondary" />Verification en cours...
|
|
</div>
|
|
)}
|
|
<Typography component="h1" variant="h4" align="center">
|
|
Push Notification Launcher
|
|
</Typography>
|
|
<Stepper activeStep={activeStep} className={classes.stepper}>
|
|
{steps.map(label => (
|
|
<Step key={label}>
|
|
<StepLabel>{label}</StepLabel>
|
|
</Step>
|
|
))}
|
|
</Stepper>
|
|
<Fragment>
|
|
{activeStep === steps.length ? (
|
|
<Fragment>
|
|
<Typography variant="h5" gutterBottom>
|
|
Votre push a été envoyé sur firebase.
|
|
</Typography>
|
|
<Typography variant="subtitle1">
|
|
Il devrait être soumis dans quelques instants.
|
|
</Typography>
|
|
<div className={classes.buttons}>
|
|
<Button
|
|
variant="contained"
|
|
color="primary"
|
|
onClick={this.handleReset} className={classes.button}>
|
|
Nouveau 🏭
|
|
</Button>
|
|
</div>
|
|
</Fragment>
|
|
) : (
|
|
<Fragment>
|
|
{this.getStepContent(activeStep)}
|
|
<div className={classes.buttons}>
|
|
{activeStep !== 0 && (
|
|
<Button onClick={this.handleBack} className={classes.button}>
|
|
Retour
|
|
</Button>
|
|
)}
|
|
<Button
|
|
variant="contained"
|
|
color="primary"
|
|
onClick={this.handleNext}
|
|
className={classes.button}
|
|
>
|
|
{activeStep === steps.length - 1 ? 'Launch 🚀' : 'Next'}
|
|
</Button>
|
|
</div>
|
|
</Fragment>
|
|
)}
|
|
</Fragment>
|
|
</Paper>
|
|
</main>
|
|
</Fragment>
|
|
)}
|
|
{(!this.state.isSignedIn) &&
|
|
(<Button
|
|
variant="contained"
|
|
color="primary"
|
|
className={classes.button}
|
|
onClick={() => Router.push('/auth/credentials')}>Sign in to use that feature</Button>)
|
|
}
|
|
<Snackbar
|
|
autoHideDuration={6000}
|
|
anchorOrigin={{ vertical: 'bottom', horizontal: 'right' }}
|
|
open={this.state.openSnack}
|
|
onClose={this.handleClose}
|
|
>
|
|
<SnackbarContent
|
|
className={classes[this.state.error ? 'error' : this.state.warning ? 'warning' : 'success']}
|
|
message={<span id="message-id">{this.state.snackMessage}</span>}
|
|
/></Snackbar>
|
|
</Layout>
|
|
);
|
|
}
|
|
}
|
|
|
|
|
|
export default withStyles(styles)(PushCreator);
|