From f9e9a35198077add0faa76fcc99bc363fd119ee4 Mon Sep 17 00:00:00 2001
From: I Gede Aditya Premana Putra <i.gede97@gmail.com>
Date: Sat, 18 Jun 2022 00:57:16 +0700
Subject: [PATCH] Create reminder, scheduler, notification component

---
 .env                                          |   1 +
 src/components/Main/Main.css                  |  10 +-
 src/components/Main/Main.js                   |  12 +-
 .../NotificationBell/NotificationBell.css     |  39 +++-
 .../NotificationBell/NotificationBell.js      | 116 +++++++---
 src/components/Reminder/CreateIcon.svg        |   4 +
 src/components/Reminder/Reminder.css          | 116 ++++++++++
 src/components/Reminder/Reminder.js           | 177 ++++++++++++++++
 src/components/Reminder/TrashIcon.svg         |   3 +
 src/components/Scheduler/Scheduler.js         | 199 ++++++++++++++++++
 10 files changed, 635 insertions(+), 42 deletions(-)
 create mode 100644 .env
 create mode 100644 src/components/Reminder/CreateIcon.svg
 create mode 100644 src/components/Reminder/Reminder.css
 create mode 100644 src/components/Reminder/Reminder.js
 create mode 100644 src/components/Reminder/TrashIcon.svg
 create mode 100644 src/components/Scheduler/Scheduler.js

diff --git a/.env b/.env
new file mode 100644
index 0000000..e8c00d2
--- /dev/null
+++ b/.env
@@ -0,0 +1 @@
+REACT_APP_BACKEND_API_URL=http://auth-remindme.herokuapp.com
\ No newline at end of file
diff --git a/src/components/Main/Main.css b/src/components/Main/Main.css
index 80cb769..2238b68 100644
--- a/src/components/Main/Main.css
+++ b/src/components/Main/Main.css
@@ -16,4 +16,12 @@
     color: #0E2560;
     font-weight: bold;
     font-size: x-large;
-}
\ No newline at end of file
+}
+
+.remindme-main-body {
+    margin: 2em 0 2em 0;
+    width: 100%;
+    display: flex;
+}
+
+
diff --git a/src/components/Main/Main.js b/src/components/Main/Main.js
index 45fe9fd..50be3e0 100644
--- a/src/components/Main/Main.js
+++ b/src/components/Main/Main.js
@@ -1,19 +1,27 @@
 import './Main.css';
 import { connect } from 'react-redux';
 import NotificationBell from '../NotificationBell/NotificationBell';
+import Reminder from '../Reminder/Reminder';
+import Scheduler from '../Scheduler/Scheduler';
 
-const Main = () => {
 
+const Main = ({ user, isAuthenticatd }) => {
+    console.log(user)
     return (
         <div className='remindme-main-content'>
             <div className='remindme-main-header'>
                 <div className='remindme-main-header-left'>
-                    <h1>Hello!</h1>
+                    <h1>{user && user[0] ? `Hi, ${user[0].firstName} ${user[0].lastName}` : "Hello"}!</h1>
+                    <p>Server Time, {new Date().toLocaleString()}</p>
                 </div>
                 <div className='remindme-main-header-right'>
                     <NotificationBell />
                 </div>
             </div>
+            <div className='remindme-main-body'>
+                <Scheduler />
+                <Reminder />
+            </div>
         </div>
     );
 }
diff --git a/src/components/NotificationBell/NotificationBell.css b/src/components/NotificationBell/NotificationBell.css
index c462455..42862d4 100644
--- a/src/components/NotificationBell/NotificationBell.css
+++ b/src/components/NotificationBell/NotificationBell.css
@@ -7,13 +7,19 @@
     text-align: center;
     color: white;
     background-color: red;
-    font-size: 12px;
+    font-size: 10px;
     width: 20px;
     height: 20px;
     border-radius: 50%;
     vertical-align: middle;
-    top: -8px;
-    right: 20px;
+    top: -6px;
+    left: -6px;
+    padding: 10px;
+}
+
+.remindme-notification-bell #notification-count p {
+    margin: 0;
+    transform: translate(10%, 5%);
 }
 
 .remindme-notification-bell button {
@@ -33,10 +39,10 @@
     position: absolute;
     top: 40px;
     right: 0px;
-    padding: 10px 20px;
-    padding-left: 5px;
     border-radius: 10px;
     width: 400px;
+    z-index: 99999;
+    background-color: white;
 }
 
 ul {
@@ -51,4 +57,27 @@ ul p {
     text-align: center;
     font-style: italic;
     margin: 0px;
+}
+
+.scrollbar {
+    overflow-y: scroll;
+}
+
+.scrollbar-primary {
+    scrollbar-color: #546FB2 #f5f5f500;
+}
+
+.scrollbar-primary::-webkit-scrollbar {
+    width: 4px;
+    background-color: #f5f5f500;
+}
+
+.scrollbar-primary::-webkit-scrollbar-thumb {
+    border-radius: 10px;
+    -webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.1);
+    background-color: #546FB2;
+}
+
+.scrollbar-danger {
+    scrollbar-color: #ff3547 #f5f5f5;
 }
\ No newline at end of file
diff --git a/src/components/NotificationBell/NotificationBell.js b/src/components/NotificationBell/NotificationBell.js
index 96aec02..90da14d 100644
--- a/src/components/NotificationBell/NotificationBell.js
+++ b/src/components/NotificationBell/NotificationBell.js
@@ -5,39 +5,59 @@ import Stomp from 'stompjs'
 import { connect } from 'react-redux';
 import { load_user as handleLoadUser } from '../../actions/auth';
 import axios from 'axios';
+import { Row, Col } from 'react-bootstrap';
 
 const NotificationBell = React.memo(({ user, isAuthenticated, load_user }) => {
 
-    const [notificationCount, setNotificationCount] = useState(0);
     const [showNotificationBox, setShowNotificationBox] = useState(false);
-    const [itemList, setItemList] = useState([]);
+    const [itemList, setItemList] = useState([
+        {
+            name: "Test Notification 1",
+            notification_time: new Date()
+        },
+        {
+            name: "Test Notification 2",
+            notification_time: new Date()
+        }
+    ]);
+    var [newNotification, setNewNotification] = useState(0);
+
+    const messageCallBack = function (message) {
+        if (message.body) {
+            setNewNotification(++newNotification)
+            var b = JSON.parse(message.body)
+            b.notification_time = new Date(b.notification_time)
+            itemList.push(b)
+            setItemList(itemList);
+        }
+    }
+
+    var calledTimes = 0
+    const createWebSocket = (queue) => {
+        if (calledTimes > 0)
+            return
+        calledTimes++
 
-    const createWebSocket = async (queue) => {
+        var url = "wss://cloud.dirtboll.com:15673/ws";
+        var wss = new WebSocket(url);
+        var client = Stomp.over(wss);
         var connect_callback = function () {
             console.log('connected websocket!');
+            client.subscribe(`/queue/${queue}`, messageCallBack, { durable: false, exclusive: false, "auto-delete": true });
         };
         var error_callback = function (error) {
             console.log('unable to connect to websocket.');
             console.log(error);
         };
-        var url = "ws://34.69.147.3:15674/ws";
-        var wss = new WebSocket(url);
-        var client = Stomp.over(wss);
-        client.connect('admin', 'adminadmin', connect_callback, error_callback, '/');
-        setTimeout(() => {
-            client.subscribe(`/queue/${queue}`, maessageCallBack);
-        }, 5000)
-
-
-        const maessageCallBack = function (message) {
-            if (message.body) {
-                itemList.push(message)
-                setItemList(itemList);
-                setNotificationCount(notificationCount + 1);
-            }
-        }
+        client.debug = null;
+        client.connect('receiver', 'receiver321', connect_callback, error_callback, '/');
     }
 
+    React.useEffect(() => {
+        if (user && user[0])
+            createWebSocket(user[0].username)
+    }, [user])
+
     const config = {
         headers: {
             'Content-Type': 'application/json',
@@ -46,15 +66,42 @@ const NotificationBell = React.memo(({ user, isAuthenticated, load_user }) => {
         }
     };
 
-    const getUser = async () => {
-        let res = await axios.get(`${process.env.REACT_APP_BACKEND_API_URL}/api/create-user/`, config)
-        return res
+    const MIN = 60
+    const HOUR = 60 * MIN
+    const DAY = 24 * HOUR
+    function diffTime(date) {
+        var diff = Math.round((new Date() - date) / 1000)
+
+        var days = Math.round(diff / DAY)
+        if (days > 0)
+            return `${days} day${days > 1 ? "s" : ""} ago`
+
+        diff %= DAY
+        var hours = Math.round(diff / HOUR)
+        if (hours > 0)
+            return `${hours} hour${hours > 1 ? "s" : ""} ago`
+
+        diff %= HOUR
+        var minutes = Math.round(diff / MIN)
+        if (minutes > 0)
+            return `${minutes} minute${minutes > 1 ? "s" : ""} ago`
+
+        diff %= MIN
+        return `${diff} second${diff > 1 ? "s" : ""} ago`
     }
-    // Create web socket
-    console.log(getUser().then((result) => { createWebSocket(result.data[0].username); }))
+
+    // const getUser = async () => {
+    //     let res = await axios.get(`${process.env.REACT_APP_BACKEND_API_URL}/api/create-user/`, config)
+    //     return res
+    // }
+    // // Create web socket
+    // console.log(getUser().then((result) => { createWebSocket(result.data[0].username); }))
 
     function handleClickNotif() {
-        setNotificationCount(0);
+        setNewNotification(0)
+        if (showNotificationBox) {
+            itemList.forEach(v => v.is_read = true)
+        }
         setShowNotificationBox(!showNotificationBox);
     }
 
@@ -62,16 +109,17 @@ const NotificationBell = React.memo(({ user, isAuthenticated, load_user }) => {
         <div className='remindme-notification-bell'>
             <button onClick={handleClickNotif}>
                 <img src={Notification} alt="Notification Bell" />
-                <div id="notification-count">{notificationCount}</div>
+                <div className="d-flex flex-row align-items-center justify-content-center" id="notification-count"><p>{newNotification}</p></div>
             </button>
-            <div id="remindme-notification-box" style={{ display: showNotificationBox ? 'block' : 'none' }}>
-                <ul>
-                    {itemList.length != 0 ? itemList.map(item => (
-                        <li>{item}</li>
-                    )) : <p>There is no item to be reminded!</p>}
-                    {/* <li>Minum air putih biar sehat!</li>
-                    <li>Kasih makan doggy</li> */}
-                </ul>
+            <div id="remindme-notification-box" className="px-3 py-3" style={{ display: showNotificationBox ? 'block' : 'none', overflow: "hidden" }}>
+                <div className='px-1 scrollbar scrollbar-primary' style={{ maxWidth: "30em", maxHeight: "20em", overflowY: "auto", overflowX: "hidden" }}>
+                    {itemList.length !== 0 ? itemList.slice().reverse().map((item, i) => (
+                        <Row key={i} className={`${i !== itemList.length - 1 ? 'mb-3' : ''}`} as="div">
+                            <Col xs="7" style={{ fontSize: "14px", color: "#546FB2", fontWeight: item.is_read ? "400" : "900" }}>{item.name}</Col>
+                            <Col style={{ fontSize: "12px", textAlign: "right" }}>{diffTime(item.notification_time)}</Col>
+                        </Row>
+                    )) : <p className='m-0'>There is no item to be reminded!</p>}
+                </div>
             </div>
         </div>
     )
diff --git a/src/components/Reminder/CreateIcon.svg b/src/components/Reminder/CreateIcon.svg
new file mode 100644
index 0000000..8441a80
--- /dev/null
+++ b/src/components/Reminder/CreateIcon.svg
@@ -0,0 +1,4 @@
+<svg width="60" height="60" viewBox="0 0 60 60" fill="none" xmlns="http://www.w3.org/2000/svg">
+<circle cx="30" cy="30" r="30" fill="#0E2560"/>
+<path d="M38.7188 27.7441V32.1562H21.1758V27.7441H38.7188ZM32.3555 20.8008V39.4336H27.5566V20.8008H32.3555Z" fill="white"/>
+</svg>
diff --git a/src/components/Reminder/Reminder.css b/src/components/Reminder/Reminder.css
new file mode 100644
index 0000000..b089916
--- /dev/null
+++ b/src/components/Reminder/Reminder.css
@@ -0,0 +1,116 @@
+.remindme-notification {
+    width: 100%;
+    display: flex;
+    flex-direction: row;
+}
+
+.remindme-notification-reminder {
+    width: 100%;
+    height: fit-content;
+    flex-direction: column;
+
+    border: 1px solid #000000;
+    filter: drop-shadow(0px 4px 5px #00000030);
+    border-radius: 10px;
+    background-color: #FFF;
+
+    margin-left: 2em;
+    padding: 1.5em;
+}
+
+.remindme-notification-scheduler {
+    width: 100%;
+    height: fit-content;
+    flex-direction: column;
+
+    border: 1px solid #000000;
+    filter: drop-shadow(0px 4px 5px #00000030);
+    border-radius: 10px;
+    background-color: #FFF;
+
+    margin-right: 2em;
+    padding: 1.5em;
+}
+
+.remindme-notification-title {
+    text-align: center;
+    font-weight: 900;
+    color: #0E2560;
+    margin-bottom: 1em;
+}
+
+.remindme-notification-item {
+    margin-top: 15px;
+    display: flex;
+    flex-direction: row;
+    align-items: center;
+    justify-content: space-between;
+}
+
+.remindme-notification-item-content {
+    width: fit-content;
+    display: flex;
+    flex-direction: column;
+}
+
+.remindme-notification-item-title {
+    font-size: 20px;
+    font-weight: 900;
+    margin: 0 0 0 0;
+    width: auto;
+}
+
+.remindme-notification-item-subtitle {
+    font-size: 14px;
+    font-weight: 600;
+    margin: 0 0 0 0;
+    transform: translateY(-4px);
+    color: #0E2560;
+}
+
+.remindme-notification-item-delete {
+    display: flex;
+    flex-direction: row;
+    align-items: center;
+    cursor: pointer;
+}
+
+.remindme-notification-item-delete p {
+    color: #DC0B0B;
+    font-size: 12px;
+    max-width: 10em;
+    margin: 0 0 0 1em;
+}
+
+.remindme-notification-item-create {
+    cursor: pointer;
+    transform: translate(7px,7px);
+    margin-top: 1em;
+}
+
+.remindme-notification-nothing {
+    color: rgba(103, 103, 103, 0.651);
+    font-style: italic;
+    font-size: 14px;
+    margin: 0;
+}
+
+.remindme-modal-header-div {
+    display: flex;
+    flex-direction: row;
+    width: 100%;
+    justify-content: center;
+}
+
+.remindme-modal-header {
+    text-align: center;
+    font-weight: 900;
+    color: #0E2560;
+    margin: 0;
+}
+
+.remindme-modal-body {
+    font-weight: 400;
+    margin: 0;
+    font-size: 16px;
+}
\ No newline at end of file
diff --git a/src/components/Reminder/Reminder.js b/src/components/Reminder/Reminder.js
new file mode 100644
index 0000000..d6268b0
--- /dev/null
+++ b/src/components/Reminder/Reminder.js
@@ -0,0 +1,177 @@
+import React, { useState } from 'react';
+import './Reminder.css';
+import TrashIcon from './TrashIcon.svg';
+import CreateIcon from './CreateIcon.svg';
+import { connect } from 'react-redux';
+import axios from 'axios';
+import { Modal, Button, Form, Row, Col } from 'react-bootstrap';
+
+const Reminder = ({ user, isAuthenticatd }) => {
+
+    const [reminders, setReminders] = useState([])
+    const [show, setShow] = useState(false);
+    const [reminderChg, setReminderChg] = useState(false)
+    const [modalId, setModalId] = useState(-1)
+
+    React.useEffect(() => {
+        axios.get(`https://cloud.dirtboll.com:8686/api/reminder/all`, {
+            headers: {
+                'Authorization': `Bearer ${localStorage.getItem('access')}`
+            }
+        }).then(resp => {
+            setReminders(resp.data.data)
+        })
+            .catch(err => console.error(err))
+    }, [reminderChg])
+
+    // Delete Reminder
+    const handleClose = () => setShow(false);
+    const handleShow = (id) => {
+        return () => {
+            setModalId(id)
+            setShow(true)
+        }
+    };
+    function handleDelete() {
+        if (modalId < 0) {
+            setShow(false)
+            return
+        }
+        axios.delete(`https://cloud.dirtboll.com:8686/api/reminder/${modalId}`, {
+            headers: {
+                'Authorization': `Bearer ${localStorage.getItem('access')}`
+            }
+        }).then(() => {
+            setShow(false)
+            setReminderChg(!reminderChg)
+        })
+    }
+
+    // Create Reminder
+    const [showCreate, setShowCreate] = useState(false);
+    const [formData, setFormData] = useState({
+        activity_name: '',
+        remind_time: ''
+    })
+    const onChangeCreate = (e) => {
+        setFormData({ ...formData, [e.target.name]: e.target.value });
+    }
+    const handleCloseCreate = () => setShowCreate(false);
+    const handleShowCreate = () => setShowCreate(true);
+
+    const handleSubmitCreate = (e) => {
+        e.preventDefault();
+        formData.remind_time = new Date(formData.remind_time).toISOString()
+        axios.post("https://cloud.dirtboll.com:8686/api/reminder", formData, {
+            headers: {
+                'Authorization': `Bearer ${localStorage.getItem('access')}`
+            }
+        }).then(() => {
+            setShowCreate(false)
+            setReminderChg(!reminderChg)
+        }).catch(e => {
+            console.error(e)
+        })
+    }
+
+    return (
+        <div className="remindme-notification-reminder">
+            <h4 className="remindme-notification-title">Reminder</h4>
+            {
+                reminders.length !== 0 ? reminders.map((v) => (
+                    <div key={v.id} className="remindme-notification-item">
+                        <div className="remindme-notification-item-content">
+                            <p className="remindme-notification-item-title">
+                                {v.activity_name}
+                            </p>
+                            <p className="remindme-notification-item-subtitle">
+                                {(new Date(v.remind_time)).toLocaleString()}
+                            </p>
+                        </div>
+                        <div onClick={handleShow(v.id)} className="remindme-notification-item-delete">
+                            <img src={TrashIcon} alt="Delete Reminder" />
+                        </div>
+                    </div>
+                )) : <p className='remindme-notification-nothing'>There's nothing in here</p>
+            }
+            <div className="d-flex flex-row justify-content-end remindme-notification-item-create">
+                <img style={{ width: "32px" }} onClick={handleShowCreate} src={CreateIcon} alt="Create Reminder" />
+            </div>
+
+            <Modal show={show} onHide={handleClose}>
+                <Modal.Header>
+                    <div className="remindme-modal-header-div">
+                        <h3 className="remindme-modal-header">
+                            Are you sure?
+                        </h3>
+                    </div>
+                </Modal.Header>
+                <Modal.Body>
+                    <p className="remindme-modal-body">
+                        Do you really want to delete this reminder? This process cannot be undone
+                    </p>
+                </Modal.Body>
+                <Modal.Footer>
+                    <Button variant="secondary" onClick={handleClose}>
+                        Cancel
+                    </Button>
+                    <Button variant="danger" onClick={handleDelete}>
+                        Delete
+                    </Button>
+                </Modal.Footer>
+            </Modal>
+
+            <Modal show={showCreate} onHide={handleCloseCreate} centered>
+                <Modal.Header>
+                    <div className="remindme-modal-header-div">
+                        <h3 className="remindme-modal-header">
+                            Add Reminder Item
+                        </h3>
+                    </div>
+                </Modal.Header>
+                <Modal.Body>
+                    <Form className="p-2" onSubmit={handleSubmitCreate}>
+                        <Form.Group as={Row} className="mb-3" controlId="formActivityName">
+                            <Form.Label column sm={2}>
+                                Activity
+                            </Form.Label>
+                            <Col sm={10}>
+                                <Form.Control
+                                    type="text"
+                                    name="activity_name"
+                                    onChange={onChangeCreate}
+                                    required
+                                />
+                            </Col>
+                        </Form.Group>
+                        <Form.Group as={Row} className="mb-3" controlId="formDate">
+                            <Form.Label column sm={2}>
+                                Date
+                            </Form.Label>
+                            <Col sm={10}>
+                                <Form.Control
+                                    type="datetime-local"
+                                    name="remind_time"
+                                    onChange={onChangeCreate}
+                                    min={new Date().toISOString().slice(0, 16)}
+                                    required
+                                />
+                            </Col>
+                        </Form.Group>
+                        <div className="d-flex flex-row justify-content-end">
+                            <Button variant="secondary" onClick={handleCloseCreate}>Cancel</Button>
+                            <Button variant="primary" className="ml-2" type="submit">Submit form</Button>
+                        </div>
+                    </Form>
+                </Modal.Body>
+            </Modal>
+        </div>
+    )
+}
+
+const mapStateToProps = (state) => ({
+    isAuthenticated: state.auth.isAuthenticated,
+    user: state.auth.user
+})
+
+export default connect(mapStateToProps)(Reminder);
\ No newline at end of file
diff --git a/src/components/Reminder/TrashIcon.svg b/src/components/Reminder/TrashIcon.svg
new file mode 100644
index 0000000..8ec1f24
--- /dev/null
+++ b/src/components/Reminder/TrashIcon.svg
@@ -0,0 +1,3 @@
+<svg width="19" height="19" viewBox="0 0 19 19" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M5.73393 0.656465C5.96295 0.254125 6.43371 0 6.94688 0H12.0531C12.5663 0 13.0371 0.254125 13.2661 0.656465L13.5714 1.1875H17.6429C18.3935 1.1875 19 1.71928 19 2.375C19 3.03072 18.3935 3.5625 17.6429 3.5625H1.35714C0.607746 3.5625 0 3.03072 0 2.375C0 1.71928 0.607746 1.1875 1.35714 1.1875H5.42857L5.73393 0.656465ZM1.31897 4.75H17.6429V16.625C17.6429 17.935 16.4257 19 14.9286 19H4.03326C2.57221 19 1.31897 17.935 1.31897 16.625V4.75ZM4.71183 7.71875V16.0312C4.71183 16.3578 5.05536 16.625 5.3904 16.625C5.80179 16.625 6.06897 16.3578 6.06897 16.0312V7.71875C6.06897 7.39219 5.80179 7.125 5.3904 7.125C5.05536 7.125 4.71183 7.39219 4.71183 7.71875ZM8.78326 7.71875V16.0312C8.78326 16.3578 9.12679 16.625 9.46183 16.625C9.87321 16.625 10.1786 16.3578 10.1786 16.0312V7.71875C10.1786 7.39219 9.87321 7.125 9.46183 7.125C9.12679 7.125 8.78326 7.39219 8.78326 7.71875ZM12.8929 7.71875V16.0312C12.8929 16.3578 13.1982 16.625 13.5714 16.625C13.9446 16.625 14.25 16.3578 14.25 16.0312V7.71875C14.25 7.39219 13.9446 7.125 13.5714 7.125C13.1982 7.125 12.8929 7.39219 12.8929 7.71875Z" fill="#DC0B0B"/>
+</svg>
\ No newline at end of file
diff --git a/src/components/Scheduler/Scheduler.js b/src/components/Scheduler/Scheduler.js
new file mode 100644
index 0000000..28ca07f
--- /dev/null
+++ b/src/components/Scheduler/Scheduler.js
@@ -0,0 +1,199 @@
+import React, { useState } from 'react';
+import '../Reminder/Reminder.css';
+import TrashIcon from '../Reminder/TrashIcon.svg';
+import CreateIcon from '../Reminder/CreateIcon.svg';
+import { connect } from 'react-redux';
+import axios from 'axios';
+import { Modal, Button, Form, Row, Col } from 'react-bootstrap';
+
+const Schedule = ({ user, isAuthenticatd }) => {
+
+    const [schedulers, setSchedulers] = useState([])
+    const [show, setShow] = useState(false);
+    const [scheduleChg, setScheduleChg] = useState(false)
+    const [modalId, setModalId] = useState(-1)
+
+    React.useEffect(() => {
+        axios.get(`https://cloud.dirtboll.com:8686/api/scheduler/all`, {
+            headers: {
+                'Authorization': `Bearer ${localStorage.getItem('access')}`
+            }
+        }).then(resp => {
+            setSchedulers(resp.data)
+        })
+            .catch(err => console.error(err))
+    }, [scheduleChg])
+
+    // Delete Schedule
+    const handleClose = () => setShow(false);
+    const handleShow = (id) => {
+        return () => {
+            setModalId(id)
+            setShow(true)
+        }
+    };
+    function handleDelete() {
+        if (modalId < 0) {
+            setShow(false)
+            return
+        }
+        axios.delete(`https://cloud.dirtboll.com:8686/api/scheduler/${modalId}`, {
+            headers: {
+                'Authorization': `Bearer ${localStorage.getItem('access')}`
+            }
+        }).then(() => {
+            setShow(false)
+            setScheduleChg(!scheduleChg)
+        })
+    }
+
+    // Create Scheduler
+    const [showCreate, setShowCreate] = useState(false);
+    const [formData, setFormData] = useState({
+        activity_name: '',
+        schedule_time: 0,
+        schedule_interval: ''
+    })
+    const onChangeCreate = (e) => {
+        setFormData({ ...formData, [e.target.name]: e.target.value });
+    }
+    const handleCloseCreate = () => setShowCreate(false);
+    const handleShowCreate = () => setShowCreate(true);
+
+    const handleSubmitCreate = (e) => {
+        e.preventDefault();
+        formData.schedule_time = parseInt(formData.schedule_time) || 1
+        axios.post("https://cloud.dirtboll.com:8686/api/scheduler", formData, {
+            headers: {
+                'Authorization': `Bearer ${localStorage.getItem('access')}`
+            }
+        }).then(() => {
+            setShowCreate(false)
+            setScheduleChg(!scheduleChg)
+        }).catch(e => {
+            console.error(e)
+        })
+    }
+
+    return (
+        <div className="remindme-notification-scheduler">
+            <h4 className="remindme-notification-title">Scheduler</h4>
+            {
+                schedulers.length !== 0 ? schedulers.map((v) => (
+                    <div key={v.id} className="remindme-notification-item">
+                        <div className="remindme-notification-item-content">
+                            <p className="remindme-notification-item-title">
+                                {v.activity_name}
+                            </p>
+                            <p className="remindme-notification-item-subtitle">
+                                Every {v.schedule_time} {v.schedule_time > 1 ? v.schedule_interval : v.schedule_interval.slice(0, -1)}
+                            </p>
+                        </div>
+                        <div onClick={handleShow(v.id)} className="remindme-notification-item-delete">
+                            <img src={TrashIcon} alt="Delete Schedule" />
+                        </div>
+                    </div>
+                )) : <p className='remindme-notification-nothing'>There's nothing in here</p>
+            }
+            <div className="d-flex flex-row justify-content-end remindme-notification-item-create">
+                <img style={{ width: "32px" }} onClick={handleShowCreate} src={CreateIcon} alt="Create Schedule" />
+            </div>
+
+            <Modal show={show} onHide={handleClose}>
+                <Modal.Header>
+                    <div className="remindme-modal-header-div">
+                        <h3 className="remindme-modal-header">
+                            Are you sure?
+                        </h3>
+                    </div>
+                </Modal.Header>
+                <Modal.Body>
+                    <p className="remindme-modal-body">
+                        Do you really want to delete this scheduler? This process cannot be undone
+                    </p>
+                </Modal.Body>
+                <Modal.Footer>
+                    <Button variant="secondary" onClick={handleClose}>
+                        Cancel
+                    </Button>
+                    <Button variant="danger" onClick={handleDelete}>
+                        Delete
+                    </Button>
+                </Modal.Footer>
+            </Modal>
+
+            <Modal show={showCreate} onHide={handleCloseCreate} centered>
+                <Modal.Header>
+                    <div className="remindme-modal-header-div">
+                        <h3 className="remindme-modal-header">
+                            Add Schedule Item
+                        </h3>
+                    </div>
+                </Modal.Header>
+                <Modal.Body>
+                    <Form className="p-2" onSubmit={handleSubmitCreate}>
+                        <Form.Group as={Row} className="mb-3" controlId="formActivityName">
+                            <Form.Label column sm={2}>
+                                Activity
+                            </Form.Label>
+                            <Col sm={10}>
+                                <Form.Control
+                                    type="text"
+                                    name="activity_name"
+                                    onChange={onChangeCreate}
+                                    required
+                                />
+                            </Col>
+                        </Form.Group>
+                        <Form.Group as={Row} className="mb-3" controlId="formInterval">
+                            <Form.Label column sm={2}>
+                                Interval
+                            </Form.Label>
+                            <Col sm={10}>
+                                <Form.Control
+                                    type="number"
+                                    name="schedule_time"
+                                    onChange={onChangeCreate}
+                                    min="1"
+                                    required
+                                />
+                            </Col>
+                        </Form.Group>
+                        <Form.Group as={Row} className="mb-3" controlId="formDate">
+                            <Form.Label column sm={2}>
+                                Time
+                            </Form.Label>
+                            <Col sm={10}>
+                                <Form.Select
+                                    aria-label="Interval Time"
+                                    name="schedule_interval"
+                                    onChange={onChangeCreate}
+                                    required
+                                    defaultValue={""}
+                                >
+                                    <option disabled="disabled" value="">Select interval type</option>
+                                    <option value="Minutes">Minutes</option>
+                                    <option value="Hours">Hours</option>
+                                    <option value="Days">Days</option>
+                                    <option value="Weeks">Weeks</option>
+                                    <option value="Months">Months</option>
+                                </Form.Select>
+                            </Col>
+                        </Form.Group>
+                        <div className="d-flex flex-row justify-content-end">
+                            <Button variant="secondary" onClick={handleCloseCreate}>Cancel</Button>
+                            <Button variant="primary" className="ml-2" type="submit">Submit form</Button>
+                        </div>
+                    </Form>
+                </Modal.Body>
+            </Modal>
+        </div>
+    )
+}
+
+const mapStateToProps = (state) => ({
+    isAuthenticated: state.auth.isAuthenticated,
+    user: state.auth.user
+})
+
+export default connect(mapStateToProps)(Schedule);
\ No newline at end of file
-- 
GitLab