diff --git a/assets/times.svg b/assets/times.svg
new file mode 100644
index 00000000..c528bcdd
--- /dev/null
+++ b/assets/times.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/components/common/Toast.js b/components/common/Toast.js
new file mode 100644
index 00000000..12787985
--- /dev/null
+++ b/components/common/Toast.js
@@ -0,0 +1,26 @@
+import React, { useEffect } from 'react';
+import ReactDOM from 'react-dom';
+import { useSpring, animated } from 'react-spring';
+import styles from './Toast.module.css';
+import Icon from 'components/common/Icon';
+import Close from 'assets/times.svg';
+
+export default function Toast({ message, timeout = 3000, onClose }) {
+ const props = useSpring({
+ opacity: 1,
+ transform: 'translate3d(0,0px,0)',
+ from: { opacity: 0, transform: 'translate3d(0,-40px,0)' },
+ });
+
+ useEffect(() => {
+ setTimeout(onClose, timeout);
+ }, []);
+
+ return ReactDOM.createPortal(
+
+ {message}
+ } size="small" />
+ ,
+ document.getElementById('__modals'),
+ );
+}
diff --git a/components/common/Toast.module.css b/components/common/Toast.module.css
new file mode 100644
index 00000000..bfcd26bb
--- /dev/null
+++ b/components/common/Toast.module.css
@@ -0,0 +1,25 @@
+.toast {
+ position: absolute;
+ top: 30px;
+ left: 0;
+ right: 0;
+ width: 300px;
+ border-radius: 5px;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 8px 16px;
+ color: var(--gray50);
+ background: var(--green400);
+ margin: auto;
+ z-index: 2;
+ cursor: pointer;
+}
+
+.message {
+ font-size: var(--font-size-normal);
+}
+
+.close {
+ margin-left: 20px;
+}
diff --git a/components/settings/AccountSettings.js b/components/settings/AccountSettings.js
index cde8bedc..cdf55988 100644
--- a/components/settings/AccountSettings.js
+++ b/components/settings/AccountSettings.js
@@ -14,12 +14,14 @@ import Plus from 'assets/plus.svg';
import Trash from 'assets/trash.svg';
import Check from 'assets/check.svg';
import styles from './AccountSettings.module.css';
+import Toast from '../common/Toast';
export default function AccountSettings() {
const [addAccount, setAddAccount] = useState();
const [editAccount, setEditAccount] = useState();
const [deleteAccount, setDeleteAccount] = useState();
const [saved, setSaved] = useState(0);
+ const [message, setMessage] = useState();
const { data } = useFetch(`/api/accounts`, {}, { update: [saved] });
const Checkmark = ({ is_admin }) => (is_admin ? } size="medium" /> : null);
@@ -52,6 +54,7 @@ export default function AccountSettings() {
function handleSave() {
setSaved(state => state + 1);
+ setMessage('Saved successfully.');
handleClose();
}
@@ -97,6 +100,7 @@ export default function AccountSettings() {
/>
)}
+ {message && setMessage(null)} />}
>
);
}
diff --git a/components/settings/ProfileSettings.js b/components/settings/ProfileSettings.js
index 1aac00af..3c873d73 100644
--- a/components/settings/ProfileSettings.js
+++ b/components/settings/ProfileSettings.js
@@ -5,12 +5,19 @@ import Button from 'components/common/Button';
import ChangePasswordForm from '../forms/ChangePasswordForm';
import Modal from 'components/common/Modal';
import Dots from 'assets/ellipsis-h.svg';
+import Toast from '../common/Toast';
export default function ProfileSettings() {
const user = useSelector(state => state.user);
const [changePassword, setChangePassword] = useState(false);
+ const [message, setMessage] = useState();
const { user_id } = user;
+ function handleSave() {
+ setChangePassword(false);
+ setMessage('Saved successfully.');
+ }
+
return (
<>
@@ -27,11 +34,12 @@ export default function ProfileSettings() {
setChangePassword(false)}
+ onSave={handleSave}
onClose={() => setChangePassword(false)}
/>
)}
+ {message && setMessage(null)} />}
>
);
}
diff --git a/components/settings/WebsiteSettings.js b/components/settings/WebsiteSettings.js
index a08b61f6..0b6d9a88 100644
--- a/components/settings/WebsiteSettings.js
+++ b/components/settings/WebsiteSettings.js
@@ -17,6 +17,7 @@ import Code from 'assets/code.svg';
import Link from 'assets/link.svg';
import styles from './WebsiteSettings.module.css';
import useFetch from '../../hooks/useFetch';
+import Toast from '../common/Toast';
export default function WebsiteSettings() {
const [editWebsite, setEditWebsite] = useState();
@@ -25,6 +26,7 @@ export default function WebsiteSettings() {
const [showCode, setShowCode] = useState();
const [showUrl, setShowUrl] = useState();
const [saved, setSaved] = useState(0);
+ const [message, setMessage] = useState();
const { data } = useFetch(`/api/websites`, {}, { update: [saved] });
const Buttons = row => (
@@ -66,6 +68,7 @@ export default function WebsiteSettings() {
function handleSave() {
setSaved(state => state + 1);
+ setMessage('Saved successfully.');
handleClose();
}
@@ -127,6 +130,7 @@ export default function WebsiteSettings() {
)}
+ {message && setMessage(null)} />}
>
);
}