diff --git a/components/ContactModal/index.js b/components/ContactModal/index.js
new file mode 100644
index 0000000..327c897
--- /dev/null
+++ b/components/ContactModal/index.js
@@ -0,0 +1,207 @@
+import React, { useState } from 'react';
+import PropTypes from 'prop-types';
+import {
+ Container,
+ Typography,
+ Button,
+ Grid,
+ makeStyles,
+ Dialog,
+} from '@material-ui/core';
+import MailIcon from '@material-ui/icons/Mail';
+
+import { Formik, Form, Field } from 'formik';
+import { TextField } from 'formik-material-ui';
+
+import SnackAlert from '../shared/SnackAlert';
+import emailValidator from '../../utils/emailValidator';
+import api from '../../utils/api';
+
+const useStyles = makeStyles((theme) => ({
+ paper: {
+ backgroundColor: theme.palette.background.paper,
+ boxShadow: theme.shadows[5],
+ padding: theme.spacing(2, 4, 3),
+ borderRadius: '10px',
+ },
+ mailIcon: {
+ color: theme.palette.secondary.main,
+ fontSize: '4rem',
+ justifyContent: 'center',
+ },
+ aside: {
+ backgroundColor: theme.palette.primary.main,
+ height: '100%',
+ },
+ title: {
+ marginBottom: theme.spacing(2),
+ },
+}));
+
+export default function Contact({ open, setOpen }) {
+ const classes = useStyles();
+ const [successOpen, setSuccessOpen] = useState(false);
+ const [errorOpen, setErrorOpen] = useState(false);
+
+ const handleClose = () => {
+ setOpen(false);
+ };
+
+ const initialValues = {
+ full_name: '',
+ email: '',
+ message: '',
+ };
+
+ const handleValidate = (values) => {
+ const errors = {};
+ if (!values.full_name) {
+ errors.full_name = 'Required';
+ }
+
+ if (!values.email) {
+ errors.email = 'Required';
+ } else if (emailValidator(values.email)) {
+ errors.email = 'Invalid Email Address';
+ }
+
+ if (!values.message) {
+ errors.message = 'Required';
+ }
+ return errors;
+ };
+
+ const handleSubmit = async (values) => {
+ api.post('/contact', values)
+ .then(() => setSuccessOpen(true))
+ .catch(() => setErrorOpen(true));
+ };
+
+ const handleSnackClose = (_, reason) => {
+ if (reason === 'clickaway') {
+ return;
+ }
+
+ setSuccessOpen(false);
+ setErrorOpen(false);
+ };
+
+ return (
+
+
+
+
+
+ );
+}
+
+Contact.propTypes = {
+ open: PropTypes.bool.isRequired,
+ setOpen: PropTypes.func.isRequired,
+};
diff --git a/components/Dashboard/Card.js b/components/Dashboard/Card.js
index 12fcb24..5104b7f 100644
--- a/components/Dashboard/Card.js
+++ b/components/Dashboard/Card.js
@@ -5,8 +5,9 @@ import {
makeStyles,
Divider,
Typography,
- Link,
+ // Link,
} from '@material-ui/core';
+import Link from 'next/link';
const useStyles = makeStyles((theme) => ({
title: {
@@ -37,17 +38,18 @@ function Card({ bridge, index }) {
return (
-
-
+
+
{bridge.title}
-
-
+
+
+
@@ -92,13 +94,18 @@ function Card({ bridge, index }) {
{bridge.eventId ? (
-
-
+
+
+
View Events
-
-
+
+
) : (
-
+
View Events
)}
@@ -115,7 +122,7 @@ export default Card;
Card.propTypes = {
bridge: PropTypes.shape({
- id: PropTypes.number.isRequired,
+ slug: PropTypes.string.isRequired,
title: PropTypes.string.isRequired,
updatedAt: PropTypes.string.isRequired,
eventCount: PropTypes.number.isRequired,
diff --git a/components/Editor/ActionsDialog/index.js b/components/Editor/ActionsDialog/index.js
index 83a981c..678a007 100644
--- a/components/Editor/ActionsDialog/index.js
+++ b/components/Editor/ActionsDialog/index.js
@@ -26,7 +26,7 @@ const useStyles = makeStyles({
});
function ActionsDialog({
- active, open, onClose, bridgeId,
+ active, open, onClose, bridgeSlug,
}) {
const [errorOpen, setErrorOpen] = useState(false);
const [successOpen, setSuccessOpen] = useState(false);
@@ -35,7 +35,7 @@ function ActionsDialog({
const handleAbort = () => {
api.patch('/events/abort', {
- bridge_id: bridgeId,
+ bridge_slug: bridgeSlug,
})
.then((res) => {
if (res.status === 200) {
@@ -51,8 +51,8 @@ function ActionsDialog({
};
const handleActivate = async () => {
- await api.patch(`/bridges/${bridgeId}/${active ? 'deactivate' : 'activate'}`).then(() => {
- router.push(`/bridge/${bridgeId}`);
+ await api.patch(`/bridges/${bridgeSlug}/${active ? 'deactivate' : 'activate'}`).then(() => {
+ router.push(`/bridge/${bridgeSlug}`);
setSuccessOpen(true);
setTimeout(() => {
setSuccessOpen(false);
@@ -66,7 +66,7 @@ function ActionsDialog({
};
const handleDelete = () => {
- api.delete(`/bridges/${bridgeId}`).then(() => {
+ api.delete(`/bridges/${bridgeSlug}`).then(() => {
router.push('/dashboard');
}).catch(() => {
setErrorOpen(true);
@@ -136,7 +136,7 @@ ActionsDialog.propTypes = {
active: PropTypes.bool.isRequired,
onClose: PropTypes.func.isRequired,
open: PropTypes.bool.isRequired,
- bridgeId: PropTypes.number.isRequired,
+ bridgeSlug: PropTypes.string.isRequired,
};
export default ActionsDialog;
diff --git a/components/Editor/index.js b/components/Editor/index.js
index 69719f4..1d6080d 100644
--- a/components/Editor/index.js
+++ b/components/Editor/index.js
@@ -49,7 +49,7 @@ function Editor({ bridge, isEditView }) {
const {
active,
- id,
+ slug,
outboundUrl,
httpMethod,
headers,
@@ -140,9 +140,9 @@ function Editor({ bridge, isEditView }) {
const handleSubmit = async (values, setSubmitting) => {
if (validatePayloads(values.payloadCode, values.testPayloadCode)) {
// POST if new bridge, otherwise PATCH
- if (id) {
+ if (slug) {
await api
- .patch(`/bridges/${id}`, generatePayload(values))
+ .patch(`/bridges/${slug}`, generatePayload(values))
.then(() => setOpen(true))
.catch(() => setErrorOpen(true));
} else {
@@ -153,7 +153,7 @@ function Editor({ bridge, isEditView }) {
// TODO: Should timeout so user gets a chance to read the snack
// but is 200ms the time we want?
setTimeout(() => {
- router.push(`/bridge/${res.data.id}`);
+ router.push(`/bridge/${res.data.slug}`);
}, 200);
})
.catch(() => setErrorOpen(true));
@@ -175,7 +175,7 @@ function Editor({ bridge, isEditView }) {
return (
<>
-
+
@@ -209,7 +209,7 @@ function Editor({ bridge, isEditView }) {
active={active}
open={actionsDialogOpen}
onClose={() => setActionsDialogOpen(false)}
- bridgeId={id}
+ bridgeSlug={slug}
/>