Merge branch 'master' into feat/server-db-images

This commit is contained in:
Alex Holliday committed 2024-06-05 13:23:43 -07:00
commit b6da1ce7c1
69 files changed
+4439 -813

No files matched your search

+1494 -350
View File
File diff suppressed because it is too large. Load diff
+3
View File
@@ -18,9 +18,12 @@
"@mui/x-charts": "^7.5.1",
"@mui/x-data-grid": "7.3.2",
"@mui/x-date-pickers": "7.3.2",
"@reduxjs/toolkit": "2.2.5",
"axios": "1.7.2",
"dayjs": "1.11.11",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-redux": "9.1.2",
"react-router": "^6.23.0",
"react-router-dom": "^6.23.0"
},
+13 -2
View File
@@ -6,17 +6,21 @@ import Register from "./Pages/Register";
import HomeLayout from "./Layouts/HomeLayout";
import Demo from "./Pages/Demo/Demo";
import PlayGround from "./Pages/PlayGround/PlayGround";
import Monitors from "./Pages/Monitors"
import Monitors from "./Pages/Monitors";
import Incidents from "./Pages/Incidents";
import Status from "./Pages/Status";
import Integrations from "./Pages/Integrations";
import Settings from "./Pages/Settings";
import ForgotPassword from "./Pages/ForgotPassword";
import CheckEmail from "./Pages/CheckEmail";
import SetNewPassword from "./Pages/SetNewPassword";
import NewPasswordConfirmed from "./Pages/NewPasswordConfirmed";
function App() {
return (
<>
<Routes>
<Route exact path="/" element={<HomeLayout />} >
<Route exact path="/" element={<HomeLayout />}>
<Route path="monitors" element={<Monitors />} />
<Route path="incidents" element={<Incidents />} />
<Route path="status" element={<Status />} />
@@ -28,6 +32,13 @@ function App() {
<Route exact path="/demo" element={<Demo />} />
<Route path="*" element={<NotFound />} />
<Route path="/playground" element={<PlayGround />} />
<Route path="/forgot-password" element={<ForgotPassword />} />
<Route path="/check-email" element={<CheckEmail />} />
<Route path="/set-new-password" element={<SetNewPassword />} />
<Route
path="/new-password-confirmed"
element={<NewPasswordConfirmed />}
/>
</Routes>
</>
);
@@ -1,22 +1,5 @@
:root {
--update-subscription-color-0: #101828;
--update-subscription-color-1: #475467;
--update-subscription-color-2: #fff;
--update-subscription-color-3: #eaecf0;
--update-subscription-color-4: #7f56d9;
--update-subscription-color-5: #1570ef;
--update-subscription-color-6: #344054;
--update-subscription-color-7: #d0d5dd;
--update-subscription-padding-0: 12px 16px;
--update-subscription-margin-right: 12px;
--update-subscription-font-size: 13px;
--update-subscription-radius-0: 4px;
--spacing-1: 16px;
--spacing-2: 20px;
}
.update-subscription {
margin: var(--spacing-2);
margin: 20px;
}
.update-subscription,
@@ -33,7 +16,7 @@
.subscription-dialog-title {
font-size: 1rem;
font-weight: 700;
color: var(--update-subscription-color-0);
color: var(--env-var-color-1);
}
.v-spacing-small {
@@ -46,7 +29,7 @@
.subscription-dialog-text {
font-size: 13px;
color: var(--update-subscription-color-1);
color: var(--env-var-color-2);
}
.subscription-dialog-controls {
@@ -54,28 +37,28 @@
}
.controls-negative {
padding: var(--update-subscription-padding-0);
margin-right: var(--update-subscription-margin-right);
border-radius: var(--update-subscription-radius-0);
border: 1px solid var(--update-subscription-color-3);
background-color: var(--update-subscription-color-2);
font-size: var(--update-subscription-font-size);
padding: 12px 16px;
margin-right: 12px;
border-radius: var(--env-var-radius-1);
border: 1px solid var(--env-var-color-6);
background-color: var(--env-var-color-8);
font-size: var(--env-var-font-size-medium);
}
.controls-positive,
.subscribe-button {
padding: var(--update-subscription-padding-0);
margin-right: var(--update-subscription-margin-right);
border-radius: var(--update-subscription-radius-0);
border: 1px solid var(--update-subscription-color-4);
background-color: var(--update-subscription-color-5);
color: var(--update-subscription-color-2);
font-size: var(--update-subscription-font-size);
padding: 12px 16px;
margin-right: 12px;
border-radius: var(--env-var-radius-1);
border: 1px solid var(--env-var-color-7);
background-color: var(--env-var-color-3);
color: var(--env-var-color-8);
font-size: var(--env-var-font-size-medium);
}
.update-subscription-title {
color: var(--update-subscription-color-6);
padding: 0 var(--spacing-2);
color: var(--env-var-color-5);
padding: 0 20px;
font-weight: 700;
font-size: 13px;
margin-bottom: 10px;
@@ -83,17 +66,17 @@
.subscription-email {
display: flex;
padding: 0 var(--spacing-2);
padding: 0 20px;
}
.subscription-email-field {
width: 290px;
height: 24px;
border-radius: var(--update-subscription-radius-0);
border: 1px solid var(--update-subscription-color-7);
border-radius: var(--env-var-radius-1);
border: 1px solid var(--env-var-color-4);
box-shadow: 0px 1px 2px 0px rgba(101, 182, 28, 0.05);
padding: 5px 15px;
margin-right: var(--spacing-2);
margin-right: 20px;
}
.subscribe-button {
@@ -1,24 +1,11 @@
:root {
--announcement-border-color: #d0d5dd;
--announcement-border-radius: 4px;
--announcement-border-radius-2: 8px;
--announcement-font-size-0: 13px;
--announcement-font-color-0: #344054;
--announcement-font-color-1: #475467;
--announcement-font-color-2: #1570ef;
--announcement-padding: 16px;
--info-icon-frame-color: #eaecf0;
--margin: 20px;
}
.announcement-without-tile {
margin: var(--margin);
margin: 20px;
max-width: 343px;
width: fit-content;
display: flex;
border: 1px solid var(--announcement-border-color);
padding: var(--announcement-padding);
border-radius: var(--announcement-border-radius);
border: 1px solid var(--env-var-color-4);
padding: 16px;
border-radius: var(--env-var-radius-1);
}
.h-spacing {
@@ -26,13 +13,13 @@
}
.announcement-without-content-subject {
font-size: var(--announcement-font-size-0);
color: var(--announcement-font-color-0);
font-size: var(--env-var-font-size-medium);
color: var(--env-var-color-5);
font-weight: 700;
margin-bottom: 10px;
}
.announcement-without-content-body {
font-size: var(--announcement-font-size-0);
color: var(--announcement-font-color-1);
font-size: var(--env-var-font-size-medium);
color: var(--env-var-color-2);
}
@@ -1,71 +1,58 @@
:root {
--announcement-border-color: #d0d5dd;
--announcement-border-radius: 4px;
--announcement-border-radius-2: 8px;
--announcement-font-size-0: 13px;
--announcement-font-color-0: #344054;
--announcement-font-color-1: #475467;
--announcement-font-color-2: #1570ef;
--announcement-padding: 16px;
--info-icon-frame-color: #eaecf0;
--tile-margin: 20px;
}
.announcement-tile {
margin: var(--tile-margin);
margin: 20px;
width: fit-content;
display: flex;
border: 1px solid var(--announcement-border-color);
padding: var(--announcement-padding);
border-radius: var(--announcement-border-radius);
border: 1px solid var(--env-var-color-4);
padding: 16px;
border-radius: var(--env-var-radius-1);
}
.info-icon-frame {
display: flex;
width: 40px;
height: 40px;
border: 1px solid var(--info-icon-frame-color);
border-radius: var(--announcement-border-radius-2);
width: var(--env-var-default-2);
height: var(--env-var-default-2);
border: 1px solid var(--env-var-color-6);
border-radius: var(--env-var-radius-2);
justify-content: center;
align-items: center;
}
.announcement-content {
padding: 0 var(--announcement-padding);
padding: 0 16px;
}
.announcement-content-subject {
font-size: var(--announcement-font-size-0);
color: var(--announcement-font-color-0);
font-size: var(--env-var-font-size-medium);
color: var(--env-var-color-5);
font-weight: 700;
margin-bottom: 10px;
}
.announcement-content-body {
font-size: var(--announcement-font-size-0);
color: var(--announcement-font-color-1);
font-size: var(--env-var-font-size-medium);
color: var(--env-var-color-2);
font-weight: 300;
}
.announcement-content-controllers {
display: flex;
font-size: var(--announcement-font-size-0);
font-size: var(--env-var-font-size-medium);
margin-top: 15px;
}
.controllers-button-esc {
font-size: var(--announcement-font-size-0);
font-size: var(--env-var-font-size-medium);
font-weight: 600;
margin-right: 12px;
}
.controllers-button-primary {
font-size: var(--announcement-font-size-0);
font-size: var(--env-var-font-size-medium);
font-weight: 600;
color: var(--announcement-font-color-2);
color: var(--env-var-color-3);
}
.announcement-close {
width: 24px;
height: 24px;
width: var(--env-var-default-1);
height: var(--env-var-default-1);
}
@@ -1,13 +1,7 @@
:root {
--announcement-font-size-0: 13px;
--announcement-padding: 16px;
--margin: 20px;
}
.announcement-messagebar-body {
margin: var(--margin);
font-size: var(--announcement-font-size-0);
padding: 0 var(--announcement-padding) 0 0;
margin: 20px;
font-size: var(--env-var-font-size-medium);
padding: 0 16px 0 0;
justify-content: center;
align-items: center;
margin: auto;
+5 -2
View File
@@ -39,20 +39,22 @@ const levelConfig = {
* @param {string} props.label - The label of the button
* @param {React.ReactNode} props.img - Image for button
* @param {boolean} [props.disabled] - Whether the button is disabled
* @param {Object} prps.sx - Styles for the button
* @param {function} props.onClick - Function to run when the button is clicked
* @param {Object} props.sx - Styles for the button
* @returns {JSX.Element}
* @example
* // Render an error button
* <Button level="error" label="Error" disabled sx={{marginTop: "1rem"}}/>
*/
const Button = ({ level, label, disabled, img, sx }) => {
const Button = ({ level, label, disabled, img, onClick, sx }) => {
const { variant, color } = levelConfig[level];
return (
<MuiButton
variant={variant}
color={color}
disabled={disabled}
onClick={onClick}
sx={{
textTransform: "none",
...sx,
@@ -68,6 +70,7 @@ Button.propTypes = {
level: PropTypes.string.isRequired,
label: PropTypes.string.isRequired,
img: PropTypes.node,
onClick: PropTypes.func,
sx: PropTypes.object,
disabled: PropTypes.bool,
};
+4 -4
View File
@@ -5,8 +5,8 @@
}
.check-icon {
width: 20px;
height: 20px;
width: var(--env-var-img-width-1);
height: var(--env-var-img-width-1);
}
.check-h-spacing {
@@ -14,7 +14,7 @@
}
.check-label {
font-size: 11px;
font-size: var(--env-var-font-size-small);
font-weight: 600;
color: #475467;
color: var(--env-var-color-2);
}
+5 -5
View File
@@ -1,12 +1,12 @@
.checkbox-holder {
height: 20px;
height: var(--env-var-img-width-1);
display: flex;
align-items: center;
}
.checkbox {
width: 13px;
height: 13px;
width: var(--env-var-font-size-medium);
height: var(--env-var-font-size-medium);
margin: 0;
padding: 0;
cursor: pointer;
@@ -14,8 +14,8 @@
.checkbox-label {
margin-left: 5px;
font-size: 13px;
color: #344054;
font-size: var(--env-var-font-size-medium);
color: var(--env-var-color-5);
font-weight: 600;
cursor: pointer;
}
+19 -14
View File
@@ -1,15 +1,20 @@
.dashboard-menu-container {
display: flex;
flex-direction: column;
padding: 20px;
}
.icon-container {
display: flex;
align-items: center;
margin-bottom: 12px;
}
.text-container {
display: flex;
align-items: center;
}
.dashboard-menu-text {
margin-left: 8px;
}
display: flex;
align-items: center;
margin-bottom: 12px;
}
.text-container {
display: flex;
align-items: center;
}
.dashboard-menu-text {
margin-left: 8px;
}
@@ -1,4 +1,4 @@
import { BarChart } from '@mui/x-charts/BarChart';
import { BarChart } from "@mui/x-charts/BarChart";
const ChartsOverviewDemo = () => {
return (
@@ -10,7 +10,7 @@ const ChartsOverviewDemo = () => {
{ data: [60, 50, 15, 25] },
]}
height={290}
xAxis={[{ data: ['Q1', 'Q2', 'Q3', 'Q4'], scaleType: 'band' }]}
xAxis={[{ data: ["Q1", "Q2", "Q3", "Q4"], scaleType: "band" }]}
margin={{ top: 10, bottom: 30, left: 40, right: 10 }}
/>
);
@@ -0,0 +1,31 @@
.dashboard-sidebar {
height: 100vh;
width: 250px;
background-color: #f4f4f4;
box-shadow: 2px 0 5px rgba(0, 0, 0, 0.1);
position: fixed;
top: 0;
left: 0;
display: flex;
flex-direction: column;
justify-content: space-between;
padding: 20px 0;
}
.menu-container {
margin-top: 60px;
}
.support-container {
display: flex;
align-items: center;
padding: 10px 20px;
margin-bottom: 40px;
}
.support-text {
margin-left: 8px;
font-size: 16px;
color: #333;
}
@@ -0,0 +1,27 @@
import DashboardMenu from '../../Components/DashboardMenu';
import SupportIcon from '@mui/icons-material/Support';
import SvgIcon from '@mui/material/SvgIcon';
import './index.css';
/**
* @component
* DashboardSidebar component serves as a sidebar containing the DashboardMenu and a Support icon at the bottom.
*
* @returns {JSX.Element} The JSX element representing the DashboardSidebar component.
*/
function DashboardSidebar() {
return (
<div className="dashboard-sidebar">
<div className="menu-container">
<DashboardMenu />
</div>
<div className="support-container">
<SvgIcon component={SupportIcon} />
<span className="support-text">Support</span>
</div>
</div>
);
}
export default DashboardSidebar;
+2 -2
View File
@@ -46,8 +46,8 @@ function NavBar() {
};
return (
<AppBar position="static">
<Container maxWidth="xl">
<AppBar position="fixed" sx={{ width: '100%' }}>
<Container maxWidth="xxl" sx={{ width: '100%' }}>
<Toolbar disableGutters>
<Typography
variant="h6"
@@ -1,11 +1,3 @@
:root {
--popup-color-border-0: #f2f2f2;
--popup-color-0: #101828;
--popup-color-1: #475467;
--color-0: #1570ef;
--color-1: #175cd3;
}
.dual-button-popup-modal-holder {
width: 380px;
height: 130px;
@@ -13,19 +5,19 @@
padding: 30px;
box-shadow: 0px 8px 8px -4px rgba(16, 24, 40, 0.03),
0px 20px 24px -4px rgba(16, 24, 40, 0.08);
border: 1px solid var(--popup-color-border-0);
border-radius: 4px;
border: 1px solid var(--env-var-color-9);
border-radius: var(--env-var-radius-1);
}
.dual-button-popup-modal-subject {
color: var(--popup-color-0);
color: var(--env-var-color-1);
font-weight: bolder;
font-size: 16px;
}
.dual-button-popup-modal-description {
color: var(--popup-color-1);
font-size: 13px;
color: var(--env-var-color-2);
font-size: var(--env-var-font-size-medium);
margin-top: 10px;
}
@@ -42,19 +34,19 @@
width: 145px;
height: 35px;
padding: 5px 20px;
background-color: var(--color-0);
border: 1px solid var(--color-1);
border-radius: 4px;
background-color: var(--env-var-color-3);
border: 1px solid var(--env-var-color-10);
border-radius: var(--env-var-radius-1);
margin: 5px 0;
margin-left: 20px;
color: white;
color: var(--env-var-color-8);
cursor: pointer;
font-size: 13px;
font-size: var(--env-var-font-size-medium);
}
.transparent-discard-button {
border: none;
background-color: transparent;
margin: 5px 10px;
font-size: 13px;
font-size: var(--env-var-font-size-medium);
}
@@ -1,16 +1,10 @@
:root {
--popup-color-with-input-border-0: #f2f2f2;
--popup-color-with-input-border-1: #d0d5dd;
--popup-modal-with-input-title-color: #344054;
}
.popup-modal-holder {
width: 480px;
font-family: var(--popup-font-family-0);
padding: 50px 40px;
border-radius: 4px;
border-radius: var(--env-var-radius-1);
margin: 10px 20px;
border: 1px solid var(--popup-color-with-input-border-0);
border: 1px solid var(--env-var-color-9);
box-shadow: 0px 8px 8px -4px rgba(16, 24, 40, 0.03),
0px 20px 24px -4px rgba(16, 24, 40, 0.08);
}
@@ -31,14 +25,14 @@
.popup-modal-input-title {
margin-bottom: 15px;
color: var(--popup-modal-with-input-title-color);
color: var(--env-var-color-5);
}
.popup-modal-text-field {
width: 100%;
height: 35px;
border: 1px solid var(--popup-color-with-input-border-1);
border-radius: 4px;
border: 1px solid var(--env-var-color-4);
border-radius: var(--env-var-radius-1);
}
.popup-modal-controllers {
@@ -54,8 +48,8 @@
width: 145px;
height: 35px;
padding: 5px 20px;
border: 1px solid var(--popup-color-with-input-border-1);
border-radius: 4px;
border: 1px solid var(--env-var-color-4);
border-radius: var(--env-var-radius-1);
cursor: pointer;
font-size: 13px;
font-size: var(--env-var-font-size-medium);
}
+1 -2
View File
@@ -16,7 +16,7 @@ import AddIcon from "@mui/icons-material/Add";
/**
* @component
* @param {Object} props
* @param { Array} props.montitors - Array of monitors associated with the section
* @param { Array} props.monitors - Array of monitors associated with the section
* @returns {JSX.Element}
* @example
* // Renders a section component with a list of monitors
@@ -29,7 +29,6 @@ const Section = ({ monitors }) => {
);
useEffect(() => {
console.log("Monitor states updated", monitorStates);
// Update DB here
}, [monitorStates]);
@@ -1,32 +1,64 @@
:root {
--color-title-1: #344054;
--text-field-margin-0: 10px 20px;
--description-color-0: #344054;
--env-var-color-1: #101828;
--env-var-color-2: #475467;
--env-var-color-3: #1570ef;
--env-var-color-4: #d0d5dd;
--env-var-color-5: #344054;
--env-var-color-6: #eaecf0;
--env-var-color-7: #7f56d9;
--env-var-color-8: #fff;
--env-var-color-9: #f2f2f2;
--env-var-color-10: #175cd3;
--env-var-radius-1: 4px;
--env-var-radius-2: 8px;
--env-var-width-1: 100vw;
--env-var-width-2: 360px;
--env-var-height-1: 100vh;
--env-var-spacing-1: 12px;
--env-var-spacing-2: 24px;
--env-var-spacing-3: 32px;
--env-var-spacing-4: 40px;
--env-var-font-size-small: 11px;
--env-var-font-size-medium: 13px;
--env-var-font-size-medium-plus: 14px;
--env-var-font-size-large: 16px;
--env-var-font-size-xlarge: 30px;
--env-var-img-width-1: 20px;
--env-var-default-1: 24px;
--env-var-default-2: 40px;
}
.description-field-holder {
margin: var(--text-field-margin-0);
margin: 10px 20px;
margin-top: 20px;
}
.text-field-title {
color: var(--color-title-1);
color: var(--env-var-color-5);
font-weight: bold;
margin-bottom: 10px;
font-size: 13px;
color: var(--description-color-0);
font-size: var(--env-var-font-size-medium);
color: var(--env-var-color-5);
font-weight: bold;
}
.description-field-area {
min-width: 320px;
font-size: 13px;
font-size: var(--env-var-font-size-medium);
border-radius: 8px;
}
.description-field-label {
margin-top: 10px;
font-size: 11px;
font-size: var(--env-var-font-size-small);
}
.with-error {
@@ -36,10 +68,10 @@
#description-field-area-helper-text {
margin-left: 0;
margin-top: 10px;
font-size: 11px;
font-size: var(--env-var-font-size-small);
}
#description-field-area {
min-width: 320px;
font-size: 13px;
font-size: var(--env-var-font-size-medium);
}
@@ -1,6 +1,39 @@
:root {
--textfield-color-0: #344054;
--textfield-font-size: 13px;
--env-var-color-1: #101828;
--env-var-color-2: #475467;
--env-var-color-3: #1570ef;
--env-var-color-4: #d0d5dd;
--env-var-color-5: #344054;
--env-var-color-6: #eaecf0;
--env-var-color-7: #7f56d9;
--env-var-color-8: #fff;
--env-var-color-9: #f2f2f2;
--env-var-color-10: #175cd3;
--env-var-radius-1: 4px;
--env-var-radius-2: 8px;
--env-var-width-1: 100vw;
--env-var-width-2: 360px;
--env-var-height-1: 100vh;
--env-var-spacing-1: 12px;
--env-var-spacing-2: 24px;
--env-var-spacing-3: 32px;
--env-var-spacing-4: 40px;
--env-var-font-size-small: 11px;
--env-var-font-size-medium: 13px;
--env-var-font-size-medium-plus: 14px;
--env-var-font-size-large: 16px;
--env-var-font-size-xlarge: 30px;
--env-var-img-width-1: 20px;
--env-var-default-1: 24px;
--env-var-default-2: 40px;
}
.email-text-field {
@@ -11,24 +44,24 @@
#outlined-basic {
width: 320px;
height: 14px;
font-size: var(--textfield-font-size);
font-size: var(--env-var-font-size-medium);
padding: 8px 12px;
}
.email-text-field-title {
font-size: var(--textfield-font-size);
color: var(--textfield-color-0);
font-size: var(--env-var-font-size-medium);
color: var(--env-var-color-5);
font-weight: bold;
}
.email-text-field-input {
font-size: var(--textfield-font-size);
font-size: var(--env-var-font-size-medium);
}
#outlined-basic-helper-text {
margin-left: 0;
margin-top: 10px;
font-size: 11px;
font-size: var(--env-var-font-size-small);
}
.text-field-icon {
@@ -1,5 +1,39 @@
:root {
--textfield-color-0: #344054;
--env-var-color-1: #101828;
--env-var-color-2: #475467;
--env-var-color-3: #1570ef;
--env-var-color-4: #d0d5dd;
--env-var-color-5: #344054;
--env-var-color-6: #eaecf0;
--env-var-color-7: #7f56d9;
--env-var-color-8: #fff;
--env-var-color-9: #f2f2f2;
--env-var-color-10: #175cd3;
--env-var-radius-1: 4px;
--env-var-radius-2: 8px;
--env-var-width-1: 100vw;
--env-var-width-2: 360px;
--env-var-height-1: 100vh;
--env-var-spacing-1: 12px;
--env-var-spacing-2: 24px;
--env-var-spacing-3: 32px;
--env-var-spacing-4: 40px;
--env-var-font-size-small: 11px;
--env-var-font-size-medium: 13px;
--env-var-font-size-medium-plus: 14px;
--env-var-font-size-large: 16px;
--env-var-font-size-xlarge: 30px;
--env-var-img-width-1: 20px;
--env-var-default-1: 24px;
--env-var-default-2: 40px;
}
.password-text-field {
@@ -10,20 +44,20 @@
#outlined-basic {
width: 320px;
height: 14px;
font-size: 13px;
font-size: var(--env-var-font-size-medium);
padding: 8px 12px;
}
.password-text-field-title {
font-size: 13px;
color: var(--textfield-color-0);
font-size: var(--env-var-font-size-medium);
color: var(--env-var-color-5);
font-weight: bold;
}
#outlined-basic-helper-text {
margin-left: 0;
margin-top: 10px;
font-size: 11px;
font-size: var(--env-var-font-size-small);
}
.text-field-icon {
@@ -0,0 +1,37 @@
:root {
--env-var-color-1: #101828;
--env-var-color-2: #475467;
--env-var-color-3: #1570ef;
--env-var-color-4: #d0d5dd;
--env-var-color-5: #344054;
--env-var-color-6: #eaecf0;
--env-var-color-7: #7f56d9;
--env-var-color-8: #fff;
--env-var-color-9: #f2f2f2;
--env-var-color-10: #175cd3;
--env-var-radius-1: 4px;
--env-var-radius-2: 8px;
--env-var-width-1: 100vw;
--env-var-width-2: 360px;
--env-var-height-1: 100vh;
--env-var-spacing-1: 12px;
--env-var-spacing-2: 24px;
--env-var-spacing-3: 32px;
--env-var-spacing-4: 40px;
--env-var-font-size-small: 11px;
--env-var-font-size-medium: 13px;
--env-var-font-size-medium-plus: 14px;
--env-var-font-size-large: 16px;
--env-var-font-size-xlarge: 30px;
--env-var-img-width-1: 20px;
--env-var-default-1: 24px;
--env-var-default-2: 40px;
}
@@ -1,17 +1,46 @@
:root {
--website-color-0: #344054;
--border-color: #d0d5dd;
--label-font-color: #475467;
--icon-color: #98a2b3;
--text-field-margin-0: 10px 20px;
--text-field-margin-1: 10px 20px 5px;
--env-var-color-1: #101828;
--env-var-color-2: #475467;
--env-var-color-3: #1570ef;
--env-var-color-4: #d0d5dd;
--env-var-color-5: #344054;
--env-var-color-6: #eaecf0;
--env-var-color-7: #7f56d9;
--env-var-color-8: #fff;
--env-var-color-9: #f2f2f2;
--env-var-color-10: #175cd3;
--env-var-radius-1: 4px;
--env-var-radius-2: 8px;
--env-var-width-1: 100vw;
--env-var-width-2: 360px;
--env-var-height-1: 100vh;
--env-var-spacing-1: 12px;
--env-var-spacing-2: 24px;
--env-var-spacing-3: 32px;
--env-var-spacing-4: 40px;
--env-var-font-size-small: 11px;
--env-var-font-size-medium: 13px;
--env-var-font-size-medium-plus: 14px;
--env-var-font-size-large: 16px;
--env-var-font-size-xlarge: 30px;
--env-var-img-width-1: 20px;
--env-var-default-1: 24px;
--env-var-default-2: 40px;
}
.website-textfield-title {
margin: 0 20px;
margin-top: 30px;
font-size: 13px;
color: var(--website-color-0);
color: var(--env-var-color-5);
font-weight: bold;
}
@@ -19,17 +48,17 @@
display: flex;
align-items: center;
position: relative;
margin: var(--text-field-margin-1);
margin: 10px 20px 5px;
}
.website-textfield-hint {
margin: var(--text-field-margin-0);
margin: 10px 20px;
font-size: 11px;
}
.website-label {
padding: 6px 20px 6px 10px;
border: solid 1px var(--border-color);
border: solid 1px var(--env-var-color-4);
border-right: none;
border-radius: 4px 0 0 4px;
font-size: 13px;
@@ -37,21 +66,21 @@
display: flex;
justify-content: center;
align-items: center;
color: var(--label-font-color);
color: var(--env-var-color-2);
}
.website-url {
width: 248px;
height: 31.5px;
padding: 0px 15px;
border: solid 1px var(--border-color);
border: solid 1px var(--env-var-color-4);
}
.website-icon-holder {
width: 40px;
height: 33px;
padding: 5px;
border: solid 1px var(--border-color);
border: solid 1px var(--env-var-color-4);
border-left: none;
text-align: center;
display: flex;
@@ -61,7 +90,7 @@
.copy-to-clipboard-button {
padding: 5.5px 20px 6px 10px;
border: solid 1px var(--border-color);
border: solid 1px var(--env-var-color-4);
border-left: none;
border-radius: 0 8px 8px 0;
font-size: 13px;
@@ -69,7 +98,7 @@
display: flex;
justify-content: space-evenly;
align-items: center;
color: var(--label-font-color);
color: var(--env-var-color-2);
cursor: pointer;
}
@@ -1,17 +1,49 @@
:root {
--tooltip-color-0: #d0d5dd;
--tooltip-margin: 5px;
--tooltip-font-size: 12px;
--env-var-color-1: #101828;
--env-var-color-2: #475467;
--env-var-color-3: #1570ef;
--env-var-color-4: #d0d5dd;
--env-var-color-5: #344054;
--env-var-color-6: #eaecf0;
--env-var-color-7: #7f56d9;
--env-var-color-8: #fff;
--env-var-color-9: #f2f2f2;
--env-var-color-10: #175cd3;
--env-var-radius-1: 4px;
--env-var-radius-2: 8px;
--env-var-width-1: 100vw;
--env-var-width-2: 360px;
--env-var-height-1: 100vh;
--env-var-spacing-1: 12px;
--env-var-spacing-2: 24px;
--env-var-spacing-3: 32px;
--env-var-spacing-4: 40px;
--env-var-font-size-small: 11px;
--env-var-font-size-medium: 13px;
--env-var-font-size-medium-plus: 14px;
--env-var-font-size-large: 16px;
--env-var-font-size-xlarge: 30px;
--env-var-img-width-1: 20px;
--env-var-default-1: 24px;
--env-var-default-2: 40px;
}
.tooltip-title {
font-size: var(--tooltip-font-size);
font-size: var(--env-var-font-size-medium);
font-weight: bold;
margin: var(--tooltip-margin);
margin: 5px;
}
.tooltip-description {
font-size: var(--tooltip-font-size);
color: var(--tooltip-color-0);
margin: var(--tooltip-margin);
font-size: var(--env-var-font-size-medium);
color: var(--env-var-color-4);
margin: 5px;
}
@@ -0,0 +1,51 @@
import axios from "axios";
import { createAsyncThunk, createSlice } from "@reduxjs/toolkit";
const initialState = {
isLoading: false,
monitors: [],
success: null,
msg: null,
};
export const getMonitors = createAsyncThunk(
"monitors/getMonitors",
async (token, thunkApi) => {
try {
const res = await axios.get(
import.meta.env.VITE_APP_API_BASE_URL + "/monitors"
);
return res.data;
} catch (error) {
return thunkApi.rejectWithValue(error.response.data);
}
}
);
const monitorsSlice = createSlice({
name: "monitors",
initialState,
reducers: {},
extraReducers: (builder) => {
builder
.addCase(getMonitors.pending, (state, action) => {
state.isLoading = true;
})
.addCase(getMonitors.fulfilled, (state, action) => {
state.isLoading = false;
state.success = action.payload.success;
state.msg = action.payload.msg;
console.log(action.payload);
state.monitors = action.payload.data;
})
.addCase(getMonitors.rejected, (state, action) => {
state.isLoading = false;
state.success = action.payload.success;
state.msg = action.payload.msg;
});
},
});
export const { setMonitors } = monitorsSlice.actions;
export default monitorsSlice.reducer;
+11 -1
View File
@@ -1 +1,11 @@
/*Homelayout styles*/
.home-layout {
display: flex;
}
.main-content {
margin-left: 250px;
flex: 1;
padding: 20px;
overflow-y: auto;
}
+13 -17
View File
@@ -1,21 +1,17 @@
import NavBar from '../../Components/NavBar'
import { Outlet } from 'react-router'
import Home from '../../Pages/Home'
import './index.css'
import ChartsOverviewDemo from '../../Components/DashboardProgressBars'
import DashboardSettings from '../../Components/DashboardSettingsIcon'
import NavBar from '../../Components/NavBar';
import { Outlet } from 'react-router';
import DashboardSidebar from '../../Components/DashboardSidebar';
import './index.css';
const HomeLayout = () => {
return (
<>
<NavBar />
<Home />
<Outlet />
<ChartsOverviewDemo />
<DashboardSettings />
</>
)
return (
<div className="home-layout">
<DashboardSidebar />
<div className="main-content">
<NavBar />
</div>
</div>
);
}
export default HomeLayout
export default HomeLayout;
+83
View File
@@ -0,0 +1,83 @@
.check-email-page {
width: var(--env-var-width-1);
display: flex;
justify-content: center;
min-height: var(--env-var-height-1);
}
.check-email-form {
width: var(--env-var-width-2);
margin: 90px auto;
}
.check-email-form-header {
justify-content: center;
align-items: center;
text-align: center;
}
.check-email-v-gap-large {
height: var(--env-var-spacing-3);
}
.check-email-v-gap-medium {
height: var(--env-var-spacing-2);
}
.check-email-v-gap-small {
height: var(--env-var-spacing-1);
}
.check-email-form-heading {
font-size: var(--env-var-font-size-large);
font-weight: 700;
color: var(--env-var-color-1);
}
.check-email-form-subheading {
font-size: var(--env-var-font-size-medium);
font-weight: 400;
color: var(--env-var-color-2);
}
.check-email-form-subheading span {
font-weight: 700;
}
.check-email-body {
width: var(--env-var-width-2);
}
.check-email-resend {
font-size: var(--env-var-font-size-medium);
font-weight: 400;
color: var(--env-var-color-2);
text-align: center;
cursor: pointer;
}
.check-email-resend span {
font-weight: 700;
color: var(--env-var-color-3);
}
.check-email-back-button {
display: flex;
justify-content: center;
align-items: center;
}
.check-email-back-button-img {
width: var(--env-var-img-width-1);
height: var(--env-var-img-width-1);
margin-right: 5px;
align-items: center;
}
.check-email-back-button-text {
height: var(--env-var-img-width-1);
font-size: var(--env-var-font-size-medium);
font-weight: 500;
color: var(--env-var-color-2);
align-items: center;
}
+58
View File
@@ -0,0 +1,58 @@
import BackgroundPattern from "../../Components/BackgroundPattern/BackgroundPattern";
import "./index.css";
import React from "react";
import EmailIcon from "../../assets/Images/email.png";
import Button from "../../Components/Button";
import LeftArrow from "../../assets/Images/arrow-left.png";
const CheckEmail = () => {
return (
<div className="check-email-page">
<BackgroundPattern />
<div className="check-email-form">
<div className="check-email-form-header">
<img
className="check-email-form-header-logo"
src={EmailIcon}
alt="EmailIcon"
/>
<div className="check-email-v-gap-medium"></div>
<div className="check-email-form-heading">Check your email</div>
<div className="check-email-v-gap-small"></div>
<div className="check-email-form-subheading">
We sent a password reset link to <span>username@email.com</span>
</div>
</div>
<div className="check-email-v-gap-large"></div>
<div className="check-email-body">
<Button
level="primary"
label="Open email app"
sx={{
width: "100%",
fontSize: "13px",
fontWeight: "200",
height: "44px",
}}
/>
</div>
<div className="check-email-v-gap-large"></div>
<div className="check-email-resend">
Didn’t receive the email?
<span> Click to resend</span>
</div>
<div className="check-email-v-gap-large"></div>
<div className="check-email-back-button">
<img
className="check-email-back-button-img"
src={LeftArrow}
alt="LeftArrow"
/>
<div className="check-email-back-button-text">Back to log in</div>
</div>
</div>
</div>
);
};
export default CheckEmail;
+50 -2
View File
@@ -1,4 +1,5 @@
import React from "react";
import axios from "axios";
import Button from "../../Components/Button/";
import Link from "../../Components/Link";
import {
@@ -12,6 +13,7 @@ import {
RadioGroup,
Tab,
Tabs,
Typography,
} from "@mui/material";
import { ColoredLabel, StatusLabel } from "../../Components/Label/";
import Avatar from "../../Components/Avatar/";
@@ -25,6 +27,11 @@ import { AdapterDayjs } from "@mui/x-date-pickers/AdapterDayjs";
import AddIcon from "@mui/icons-material/Add";
import Divider from "@mui/material/Divider";
// Redux
import { useSelector } from "react-redux";
import { useDispatch } from "react-redux";
import { getMonitors } from "../../Features/Monitors/monitorsSlice";
const cols = [
{
field: "name",
@@ -84,13 +91,15 @@ const steps = [
{ label: "Invite your team", content: "Start collaborating with your team" },
];
const monitors = [
const demoMonitors = [
{ id: 0, name: "Google", isActive: true },
{ id: 1, name: "Yahoo", isActive: false },
{ id: 2, name: "Reddit", isActive: true },
];
const Demo = () => {
const dispatch = useDispatch();
const [radio, setRadio] = React.useState(1);
const [tab, setTab] = React.useState("departments");
const [date, setDate] = React.useState("Pick a date!");
@@ -167,8 +176,47 @@ const Demo = () => {
];
const theme = useTheme();
// *********************************
// Redux Demo
// *********************************
const monitorState = useSelector((state) => state.monitors);
const { monitors, msg } = monitorState;
return (
<div>
<div style={{ padding: "4rem", border: "1px solid black" }}>
<Typography variant="h4">Redux Demo</Typography>
<Typography variant="h6">Monitors</Typography>
<table
style={{ border: "1px solid black", borderCollapse: "collapse" }}
>
<tbody>
<tr>
<th style={{ border: "1px solid black" }}>Name</th>
<th style={{ border: "1px solid black" }}>URL</th>
</tr>
{monitors &&
monitors.map((monitor) => {
return (
<tr key={monitor._id}>
<td style={{ border: "1px solid black" }}>
{monitor.name}
</td>
<td style={{ border: "1px solid black" }}>{monitor.url}</td>
</tr>
);
})}
</tbody>
</table>
<p>Message: {msg}</p>
<Button
level="primary"
label="Get Monitors"
onClick={() => {
dispatch(getMonitors());
}}
/>
</div>
<ul style={{ listStyle: "none" }}>
{links.map((link) => (
<li key={link.url}>
@@ -304,7 +352,7 @@ const Demo = () => {
</div>
<Divider sx={{ margin: `${theme.spacing(2)}` }} />
<h4 id="section">Section</h4>
<Section monitors={monitors} />
<Section monitors={demoMonitors} />
</div>
);
};
+73
View File
@@ -0,0 +1,73 @@
.forgot-password-page {
width: var(--env-var-width-1);
display: flex;
justify-content: center;
min-height: var(--env-var-height-1);
}
.forgot-password-form {
width: var(--env-var-width-2);
margin: 90px auto;
}
.forgot-password-form-header {
justify-content: center;
align-items: center;
text-align: center;
}
.forgot-password-form-header-logo {
margin: 0 auto;
}
.forgot-password-v-gap-large {
height: var(--env-var-spacing-3);
}
.forgot-password-v-gap-medium {
height: var(--env-var-spacing-2);
}
.forgot-password-v-gap-small {
height: var(--env-var-spacing-1);
}
.forgot-password-form-heading {
font-size: var(--env-var-font-size-large);
font-weight: 700;
color: var(--env-var-color-1);
}
.forgot-password-form-subheading {
font-size: var(--env-var-font-size-medium);
font-weight: 500;
color: var(--env-var-color-2);
}
.forgot-password-body {
width: var(--env-var-width-2);
}
#forgot-password-email-input {
width: 308px;
height: 11px;
font-size: var(--env-var-font-size-medium);
}
.forgot-password-back-button {
display: flex;
justify-content: center;
align-items: center;
}
.forgot-password-back-button-img {
width: var(--env-var-img-width-1);
height: var(--env-var-img-width-1);
margin-right: 5px;
}
.forgot-password-back-button-text {
font-size: var(--env-var-font-size-medium);
font-weight: 500;
color: var(--env-var-color-2);
}
+60
View File
@@ -0,0 +1,60 @@
import BackgroundPattern from "../../Components/BackgroundPattern/BackgroundPattern";
import "./index.css";
import React from "react";
import Logomark from "../../assets/Images/key-password.png";
import EmailTextField from "../../Components/TextFields/Email/EmailTextField";
import Button from "../../Components/Button";
import LeftArrow from "../../assets/Images/arrow-left.png";
const ForgotPassword = () => {
return (
<div className="forgot-password-page">
<BackgroundPattern></BackgroundPattern>
<div className="forgot-password-form">
<div className="forgot-password-form-header">
<img
className="forgot-password-form-header-logo"
src={Logomark}
alt="Logomark"
/>
<div className="forgot-password-v-gap-medium"></div>
<div className="forgot-password-form-heading">Forgot password?</div>
<div className="forgot-password-v-gap-small"></div>
<div className="forgot-password-form-subheading">
No worries, we’ll send you reset instructions.
</div>
</div>
<div className="forgot-password-v-gap-large"></div>
<div className="forgot-password-body">
<EmailTextField
error={false}
placeholder="Enter your email"
id="forgot-password-email-input"
/>
<div className="forgot-password-v-gap-medium"></div>
<Button
level="primary"
label="Reset password"
sx={{
width: "100%",
fontSize: "13px",
fontWeight: "200",
height: "44px",
}}
/>
</div>
<div className="forgot-password-v-gap-large"></div>
<div className="forgot-password-back-button">
<img
className="forgot-password-back-button-img"
src={LeftArrow}
alt="LeftArrow"
/>
<div className="forgot-password-back-button-text">Back to log in</div>
</div>
</div>
</div>
);
};
export default ForgotPassword;
+18 -38
View File
@@ -1,34 +1,13 @@
:root {
--spacing-1: 15px;
--spacing-2: 20px;
--spacing-3: 25px;
--textfield-font-size: 13px;
--login-page-width-1: 100vw;
--login-page-height-1: 100vh;
--login-form-width-1: 360px;
--login-form-height-1: 526px;
--logo-width-1: 20px;
--login-font-size-medium: 13px;
--login-color-1: #101828;
--login-color-2: #1570ef;
--login-color-3: #475467;
}
.login-page {
width: var(--login-page-width-1);
width: var(--env-var-width-1);
display: flex;
justify-content: center;
align-items: center;
min-height: var(--login-page-height-1);
min-height: var(--env-var-height-1);
}
.login-form {
width: var(--login-form-width-1);
height: var(--login-form-height-1);
width: var(--env-var-width-2);
margin: 90px auto;
}
@@ -43,27 +22,27 @@
}
.login-form-v-spacing {
height: var(--spacing-1);
height: var(--env-var-spacing-1);
}
.login-form-v2-spacing {
height: var(--spacing-2);
height: var(--env-var-spacing-2);
}
.login-form-v3-spacing {
height: var(--spacing-3);
height: var(--env-var-spacing-3);
}
.login-form-heading {
font-size: 30px;
font-size: var(--env-var-font-size-xlarge);
font-weight: 700;
color: var(--login-color-1);
color: var(--env-var-color-1);
}
#login-email-input {
width: 308px;
height: 11px;
font-size: var(--textfield-font-size);
font-size: var(--env-var-font-size-medium);
}
.login-form-password-options {
@@ -73,15 +52,15 @@
}
.login-form-forgot-password {
color: var(--login-color-2);
color: var(--env-var-color-3);
font-weight: 600;
cursor: pointer;
font-size: var(--login-font-size-medium);
font-size: var(--env-var-font-size-medium);
}
.google-enter {
width: var(--logo-width-1);
height: var(--logo-width-1);
width: var(--env-var-img-width-1);
height: var(--env-var-img-width-1);
margin-right: 10px;
}
@@ -89,14 +68,15 @@
display: flex;
justify-content: center;
align-items: center;
color: var(--login-color-3);
font-size: var(--login-font-size-medium);
color: var(--env-var-color-2);
font-size: var(--env-var-font-size-medium);
font-weight: 600;
}
.new-account-option-span {
margin-left: 5px;
color: var(--login-color-2);
font-size: 14px;
color: var(--env-var-color-3);
font-size: var(--env-var-font-size-medium);
cursor: pointer;
font-weight: 700;
}
@@ -0,0 +1,67 @@
.password-confirmed-page {
width: var(--env-var-width-1);
display: flex;
justify-content: center;
min-height: var(--env-var-height-1);
}
.password-confirmed-form {
width: var(--env-var-width-2);
margin: 90px auto;
}
.password-confirmed-form-header {
justify-content: center;
align-items: center;
text-align: center;
}
.password-confirmed-v-gap-large {
height: var(--env-var-spacing-3);
}
.password-confirmed-v-gap-medium {
height: var(--env-var-spacing-2);
}
.password-confirmed-v-gap-small {
height: var(--env-var-spacing-1);
}
.password-confirmed-form-heading {
font-size: var(--env-var-font-size-large);
font-weight: 700;
color: var(--env-var-color-1);
}
.password-confirmed-form-subheading {
font-size: var(--env-var-font-size-medium);
font-weight: 600;
color: var(--env-var-color-2);
}
.password-confirmed-body {
width: var(--env-var-width-2);
}
.password-confirmed-back-button {
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
}
.password-confirmed-back-button-img {
width: var(--env-var-img-width-1);
height: var(--env-var-img-width-1);
margin-right: 5px;
align-items: center;
}
.password-confirmed-back-button-text {
height: var(--env-var-img-width-1);
font-size: var(--env-var-font-size-medium);
font-weight: 600;
color: var(--env-var-color-2);
text-align: center;
}
@@ -0,0 +1,56 @@
import BackgroundPattern from "../../Components/BackgroundPattern/BackgroundPattern";
import "./index.css";
import React from "react";
import SuccessIcon from "../../assets/Images/success-icon.png";
import Button from "../../Components/Button";
import LeftArrow from "../../assets/Images/arrow-left.png";
const NewPasswordConfirmed = () => {
return (
<div className="password-confirmed-page">
<BackgroundPattern />
<div className="password-confirmed-form">
<div className="password-confirmed-form-header">
<img
className="password-confirmed-form-header-logo"
src={SuccessIcon}
alt="SuccessIcon"
/>
<div className="password-confirmed-v-gap-medium"></div>
<div className="password-confirmed-form-heading">Password reset</div>
<div className="password-confirmed-v-gap-small"></div>
<div className="password-confirmed-form-subheading">
Your password has been successfully reset. Click below to log in
magically.
</div>
</div>
<div className="password-confirmed-v-gap-large"></div>
<div className="password-confirmed-body">
<Button
level="primary"
label="Continue"
sx={{
width: "100%",
fontSize: "13px",
fontWeight: "200",
height: "44px",
}}
/>
</div>
<div className="password-confirmed-v-gap-large"></div>
<div className="password-confirmed-back-button">
<img
className="password-confirmed-back-button-img"
src={LeftArrow}
alt="LeftArrow"
/>
<div className="password-confirmed-back-button-text">
Back to log in
</div>
</div>
</div>
</div>
);
};
export default NewPasswordConfirmed;
+12 -33
View File
@@ -1,29 +1,12 @@
:root {
--dimension-width-1: 100vw;
--dimension-width-2: 360px;
--dimension-height-1: 100vh;
--spacing-small: 12px;
--spacing-medium: 24px;
--spacing-large: 40px;
--font-size-small: 13px;
--font-size-medium: 16px;
--register-form-heading-color-1: #101828;
--register-form-subheading-color-1: #475467;
}
.register-page {
width: var(--dimension-width-1);
width: var(--env-var-width-1);
display: flex;
justify-content: center;
min-height: var(--dimension-height-1);
min-height: var(--env-var-height-1);
}
.register-form {
width: var(--dimension-width-2);
width: var(--env-var-width-2);
margin: 140px auto;
}
@@ -37,27 +20,23 @@
margin: 0 auto;
}
.register-form-v-spacing-24px {
height: var(--spacing-medium);
.register-form-v-spacing-large {
height: var(--env-var-spacing-3);
}
.register-form-v-spacing-12px {
height: var(--spacing-small);
}
.register-form-v-spacing-40px {
height: var(--spacing-large);
.register-form-v-spacing-small {
height: var(--env-var-spacing-1);
}
.register-form-heading {
font-size: var(--spacing-medium);
font-size: var(--env-var-font-size-large);
font-weight: 700;
color: var(--register-form-heading-color-1);
color: var(--env-var-color-1);
}
.register-form-subheading {
font-size: var(--spacing-small);
color: var(--register-form-subheading-color-1);
font-size: var(--env-var-font-size-medium);
color: var(--env-var-color-2);
font-weight: 600;
}
@@ -65,7 +44,7 @@
#register-lastname-input,
#register-email-input,
#register-password-input {
font-size: var(--spacing-small);
font-size: var(--env-var-font-size-medium);
width: 294px;
height: 11px;
padding: 12px 14px;
+3 -6
View File
@@ -20,12 +20,9 @@ const Register = () => {
src={Logomark}
alt="Logomark"
/>
<div className="register-form-v-spacing-24px" />
<div className="register-form-v-spacing-large" />
<div className="register-form-heading">Create an account</div>
<div className="register-form-v-spacing-12px"></div>
<div className="register-form-subheading">
Start your 30-day free trial.
</div>
<div className="register-form-v-spacing-large"></div>
</div>
<div className="register-form-v-spacing-40px" />
<div className="register-form-inputs">
@@ -60,7 +57,7 @@ const Register = () => {
<div className="login-form-v2-spacing" />
<div className="register-form-checks">
<Check text="Must be at least 8 characters" />
<div className="register-form-v-spacing-12px"></div>
<div className="register-form-v-spacing-small"></div>
<Check text="Must contain one special character" />
</div>
<div className="login-form-v2-spacing" />
+63
View File
@@ -0,0 +1,63 @@
.set-new-password-page {
width: var(--env-var-width-1);
display: flex;
justify-content: center;
min-height: var(--env-var-height-1);
}
.set-new-password-form {
width: var(--env-var-width-2);
margin: 90px auto;
}
.set-new-password-form-header {
justify-content: center;
align-items: center;
text-align: center;
}
.set-new-password-form-gap-large {
height: var(--env-var-spacing-3);
}
.set-new-password-form-gap-medium {
height: var(--env-var-spacing-2);
}
.set-new-password-form-gap-small {
height: var(--env-var-spacing-1);
}
.set-new-password-form-heading {
font-size: var(--env-var-font-size-large);
color: var(--env-var-color-1);
font-weight: 700;
}
.set-new-password-form-subheading {
font-size: var(--env-var-font-size-medium);
color: var(--env-var-color-2);
font-weight: 600;
}
.set-new-password-back-button {
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
}
.set-new-password-back-button-img {
width: var(--env-var-img-width-1);
height: var(--env-var-img-width-1);
margin-right: 5px;
align-items: center;
}
.set-new-password-back-button-text {
height: var(--env-var-img-width-1);
font-size: var(--env-var-font-size-medium);
color: var(--env-var-color-2);
font-weight: 600;
align-items: center;
}
+77
View File
@@ -0,0 +1,77 @@
import BackgroundPattern from "../../Components/BackgroundPattern/BackgroundPattern";
import "./index.css";
import React from "react";
import LockIcon from "../../assets/Images/lock-icon.png";
import PasswordTextField from "../../Components/TextFields/Password/PasswordTextField";
import Check from "../../Components/Check/Check";
import Button from "../../Components/Button";
import LeftArrow from "../../assets/Images/arrow-left.png";
const SetNewPassword = () => {
return (
<div className="set-new-password-page">
<BackgroundPattern />
<div className="set-new-password-form">
<div className="set-new-password-form-header">
<img
className="set-new-password-form-header-logo"
src={LockIcon}
alt="LockIcon"
/>
<div className="set-new-password-form-gap-medium" />
<div className="set-new-password-form-heading">Set new password</div>
<div className="set-new-password-form-gap-small" />
<div className="set-new-password-form-subheading">
Your new password must be different to previously used passwords.
</div>
</div>
<div className="set-new-password-form-gap-large"></div>
<div className="set-new-password-form-content">
<PasswordTextField
label="Password"
error={false}
placeholder="••••••••"
id="register-password-input"
/>
<div className="set-new-password-form-gap-medium"></div>
<PasswordTextField
label="Confirm password"
error={false}
placeholder="••••••••"
id="register-password-input"
/>
<div className="set-new-password-form-gap-medium"></div>
<div className="set-new-password-form-checks">
<Check text="Must be at least 8 characters" />
<div className="set-new-password-form-gap-small"></div>
<Check text="Must contain one special character" />
</div>
<div className="set-new-password-form-gap-medium"></div>
<Button
level="primary"
label="Reset passwprd"
sx={{
width: "100%",
fontSize: "13px",
fontWeight: "200",
height: "35px",
}}
/>
</div>
<div className="set-new-password-form-gap-medium"></div>
<div className="set-new-password-back-button">
<img
className="set-new-password-back-button-img"
src={LeftArrow}
alt="LeftArrow"
/>
<div className="set-new-password-back-button-text">
Back to log in
</div>
</div>
</div>
</div>
);
};
export default SetNewPassword;
+20 -1
View File
@@ -13,10 +13,20 @@ const labelPurple = "#6941C6";
const labelGreen = "#067647";
const labelRed = "#F04438";
//Section colros
// Section colors
const sectionBorder = "#D0D5DD";
const sectionBg = "#F8F9F8";
// Other Colors
const otherColorsBlackish = "#101828";
const otherColorsBluishGray = "#344054";
const otherColorsGraishWhite = "#eaecf0";
const otherColorsPurple = "#7f56d9";
const otherColorsWhite = "#fff";
const otherColorsGraishWhiteLight = "#f2f2f2";
const otherColorsStrongBlue = "#f2f2f2";
// Global Font Family
const fontFamilyDefault = '"Roboto", "Helvetica", "Arial", sans-serif';
@@ -51,6 +61,15 @@ const theme = createTheme({
borderColor: sectionBorder,
bgColor: sectionBg,
},
otherColors: {
blackish: otherColorsBlackish,
bluishGray: otherColorsBluishGray,
graishWhite: otherColorsGraishWhite,
purple: otherColorsPurple,
white: otherColorsWhite,
graishWhiteLight: otherColorsGraishWhiteLight,
strongBlue: otherColorsStrongBlue,
},
},
font :{
default: {
Binary file not shown.

After

Width:  |  Height:  |  Size: 310 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

+38
View File
@@ -11,6 +11,44 @@
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
/* Generalized Stylings */
--env-var-color-1: #101828;
--env-var-color-2: #475467;
--env-var-color-3: #1570ef;
--env-var-color-4: #d0d5dd;
--env-var-color-5: #344054;
--env-var-color-6: #eaecf0;
--env-var-color-7: #7f56d9;
--env-var-color-8: #fff;
--env-var-color-9: #f2f2f2;
--env-var-color-10: #175cd3;
--env-var-radius-1: 4px;
--env-var-radius-2: 8px;
--env-var-width-1: 100vw;
--env-var-width-2: 360px;
--env-var-height-1: 100vh;
--env-var-spacing-1: 12px;
--env-var-spacing-2: 24px;
--env-var-spacing-3: 32px;
--env-var-spacing-4: 40px;
--env-var-font-size-small: 11px;
--env-var-font-size-medium: 13px;
--env-var-font-size-medium-plus: 14px;
--env-var-font-size-large: 16px;
--env-var-font-size-xlarge: 30px;
--env-var-img-width-1: 20px;
--env-var-default-1: 24px;
--env-var-default-2: 40px;
}
a {
+10 -5
View File
@@ -5,12 +5,17 @@ import "./index.css";
import { BrowserRouter as Router, HashRouter } from "react-router-dom";
import theme from "./Utils/Theme.js";
import { ThemeProvider } from "@mui/material";
import { Provider } from "react-redux";
import store from "./store";
ReactDOM.createRoot(document.getElementById("root")).render(
<React.StrictMode>
<ThemeProvider theme={theme}>
<Router>
<App />
</Router>
</ThemeProvider>
<Provider store={store}>
<ThemeProvider theme={theme}>
<Router>
<App />
</Router>
</ThemeProvider>
</Provider>
</React.StrictMode>
);
+6
View File
@@ -0,0 +1,6 @@
import { configureStore } from "@reduxjs/toolkit";
import monitorsReducer from "./Features/Monitors/monitorsSlice";
export default configureStore({
reducer: { monitors: monitorsReducer },
});
@@ -1,10 +0,0 @@
// vite.config.js
import { defineConfig } from "file:///c:/Users/cosmi/OneDrive/Desktop/BlueWave/Uptime-Monitor/bluewave-uptime/Client/node_modules/vite/dist/node/index.js";
import react from "file:///c:/Users/cosmi/OneDrive/Desktop/BlueWave/Uptime-Monitor/bluewave-uptime/Client/node_modules/@vitejs/plugin-react/dist/index.mjs";
var vite_config_default = defineConfig({
plugins: [react()]
});
export {
vite_config_default as default
};
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsidml0ZS5jb25maWcuanMiXSwKICAic291cmNlc0NvbnRlbnQiOiBbImNvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9kaXJuYW1lID0gXCJjOlxcXFxVc2Vyc1xcXFxjb3NtaVxcXFxPbmVEcml2ZVxcXFxEZXNrdG9wXFxcXEJsdWVXYXZlXFxcXFVwdGltZS1Nb25pdG9yXFxcXGJsdWV3YXZlLXVwdGltZVxcXFxDbGllbnRcIjtjb25zdCBfX3ZpdGVfaW5qZWN0ZWRfb3JpZ2luYWxfZmlsZW5hbWUgPSBcImM6XFxcXFVzZXJzXFxcXGNvc21pXFxcXE9uZURyaXZlXFxcXERlc2t0b3BcXFxcQmx1ZVdhdmVcXFxcVXB0aW1lLU1vbml0b3JcXFxcYmx1ZXdhdmUtdXB0aW1lXFxcXENsaWVudFxcXFx2aXRlLmNvbmZpZy5qc1wiO2NvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9pbXBvcnRfbWV0YV91cmwgPSBcImZpbGU6Ly8vYzovVXNlcnMvY29zbWkvT25lRHJpdmUvRGVza3RvcC9CbHVlV2F2ZS9VcHRpbWUtTW9uaXRvci9ibHVld2F2ZS11cHRpbWUvQ2xpZW50L3ZpdGUuY29uZmlnLmpzXCI7aW1wb3J0IHsgZGVmaW5lQ29uZmlnIH0gZnJvbSAndml0ZSdcclxuaW1wb3J0IHJlYWN0IGZyb20gJ0B2aXRlanMvcGx1Z2luLXJlYWN0J1xyXG5cclxuLy8gaHR0cHM6Ly92aXRlanMuZGV2L2NvbmZpZy9cclxuZXhwb3J0IGRlZmF1bHQgZGVmaW5lQ29uZmlnKHtcclxuICBwbHVnaW5zOiBbcmVhY3QoKV0sXHJcbn0pXHJcbiJdLAogICJtYXBwaW5ncyI6ICI7QUFBOGEsU0FBUyxvQkFBb0I7QUFDM2MsT0FBTyxXQUFXO0FBR2xCLElBQU8sc0JBQVEsYUFBYTtBQUFBLEVBQzFCLFNBQVMsQ0FBQyxNQUFNLENBQUM7QUFDbkIsQ0FBQzsiLAogICJuYW1lcyI6IFtdCn0K
@@ -1,10 +0,0 @@
// vite.config.js
import { defineConfig } from "file:///c:/Users/cosmi/OneDrive/Desktop/BlueWave/Uptime-Monitor/bluewave-uptime/Client/node_modules/vite/dist/node/index.js";
import react from "file:///c:/Users/cosmi/OneDrive/Desktop/BlueWave/Uptime-Monitor/bluewave-uptime/Client/node_modules/@vitejs/plugin-react/dist/index.mjs";
var vite_config_default = defineConfig({
plugins: [react()]
});
export {
vite_config_default as default
};
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsidml0ZS5jb25maWcuanMiXSwKICAic291cmNlc0NvbnRlbnQiOiBbImNvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9kaXJuYW1lID0gXCJjOlxcXFxVc2Vyc1xcXFxjb3NtaVxcXFxPbmVEcml2ZVxcXFxEZXNrdG9wXFxcXEJsdWVXYXZlXFxcXFVwdGltZS1Nb25pdG9yXFxcXGJsdWV3YXZlLXVwdGltZVxcXFxDbGllbnRcIjtjb25zdCBfX3ZpdGVfaW5qZWN0ZWRfb3JpZ2luYWxfZmlsZW5hbWUgPSBcImM6XFxcXFVzZXJzXFxcXGNvc21pXFxcXE9uZURyaXZlXFxcXERlc2t0b3BcXFxcQmx1ZVdhdmVcXFxcVXB0aW1lLU1vbml0b3JcXFxcYmx1ZXdhdmUtdXB0aW1lXFxcXENsaWVudFxcXFx2aXRlLmNvbmZpZy5qc1wiO2NvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9pbXBvcnRfbWV0YV91cmwgPSBcImZpbGU6Ly8vYzovVXNlcnMvY29zbWkvT25lRHJpdmUvRGVza3RvcC9CbHVlV2F2ZS9VcHRpbWUtTW9uaXRvci9ibHVld2F2ZS11cHRpbWUvQ2xpZW50L3ZpdGUuY29uZmlnLmpzXCI7aW1wb3J0IHsgZGVmaW5lQ29uZmlnIH0gZnJvbSAndml0ZSdcclxuaW1wb3J0IHJlYWN0IGZyb20gJ0B2aXRlanMvcGx1Z2luLXJlYWN0J1xyXG5cclxuLy8gaHR0cHM6Ly92aXRlanMuZGV2L2NvbmZpZy9cclxuZXhwb3J0IGRlZmF1bHQgZGVmaW5lQ29uZmlnKHtcclxuICBwbHVnaW5zOiBbcmVhY3QoKV0sXHJcbn0pXHJcbiJdLAogICJtYXBwaW5ncyI6ICI7QUFBOGEsU0FBUyxvQkFBb0I7QUFDM2MsT0FBTyxXQUFXO0FBR2xCLElBQU8sc0JBQVEsYUFBYTtBQUFBLEVBQzFCLFNBQVMsQ0FBQyxNQUFNLENBQUM7QUFDbkIsQ0FBQzsiLAogICJuYW1lcyI6IFtdCn0K
Whitespace-only changes.
@@ -1,10 +0,0 @@
// vite.config.js
import { defineConfig } from "file:///c:/Users/cosmi/OneDrive/Desktop/BlueWave/Uptime-Monitor/bluewave-uptime/Client/node_modules/vite/dist/node/index.js";
import react from "file:///c:/Users/cosmi/OneDrive/Desktop/BlueWave/Uptime-Monitor/bluewave-uptime/Client/node_modules/@vitejs/plugin-react/dist/index.mjs";
var vite_config_default = defineConfig({
plugins: [react()]
});
export {
vite_config_default as default
};
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsidml0ZS5jb25maWcuanMiXSwKICAic291cmNlc0NvbnRlbnQiOiBbImNvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9kaXJuYW1lID0gXCJjOlxcXFxVc2Vyc1xcXFxjb3NtaVxcXFxPbmVEcml2ZVxcXFxEZXNrdG9wXFxcXEJsdWVXYXZlXFxcXFVwdGltZS1Nb25pdG9yXFxcXGJsdWV3YXZlLXVwdGltZVxcXFxDbGllbnRcIjtjb25zdCBfX3ZpdGVfaW5qZWN0ZWRfb3JpZ2luYWxfZmlsZW5hbWUgPSBcImM6XFxcXFVzZXJzXFxcXGNvc21pXFxcXE9uZURyaXZlXFxcXERlc2t0b3BcXFxcQmx1ZVdhdmVcXFxcVXB0aW1lLU1vbml0b3JcXFxcYmx1ZXdhdmUtdXB0aW1lXFxcXENsaWVudFxcXFx2aXRlLmNvbmZpZy5qc1wiO2NvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9pbXBvcnRfbWV0YV91cmwgPSBcImZpbGU6Ly8vYzovVXNlcnMvY29zbWkvT25lRHJpdmUvRGVza3RvcC9CbHVlV2F2ZS9VcHRpbWUtTW9uaXRvci9ibHVld2F2ZS11cHRpbWUvQ2xpZW50L3ZpdGUuY29uZmlnLmpzXCI7aW1wb3J0IHsgZGVmaW5lQ29uZmlnIH0gZnJvbSAndml0ZSdcclxuaW1wb3J0IHJlYWN0IGZyb20gJ0B2aXRlanMvcGx1Z2luLXJlYWN0J1xyXG5cclxuLy8gaHR0cHM6Ly92aXRlanMuZGV2L2NvbmZpZy9cclxuZXhwb3J0IGRlZmF1bHQgZGVmaW5lQ29uZmlnKHtcclxuICBwbHVnaW5zOiBbcmVhY3QoKV0sXHJcbn0pXHJcbiJdLAogICJtYXBwaW5ncyI6ICI7QUFBOGEsU0FBUyxvQkFBb0I7QUFDM2MsT0FBTyxXQUFXO0FBR2xCLElBQU8sc0JBQVEsYUFBYTtBQUFBLEVBQzFCLFNBQVMsQ0FBQyxNQUFNLENBQUM7QUFDbkIsQ0FBQzsiLAogICJuYW1lcyI6IFtdCn0K
Whitespace-only changes.
@@ -1,10 +0,0 @@
// vite.config.js
import { defineConfig } from "file:///c:/Users/cosmi/OneDrive/Desktop/BlueWave/Uptime-Monitor/bluewave-uptime/Client/node_modules/vite/dist/node/index.js";
import react from "file:///c:/Users/cosmi/OneDrive/Desktop/BlueWave/Uptime-Monitor/bluewave-uptime/Client/node_modules/@vitejs/plugin-react/dist/index.mjs";
var vite_config_default = defineConfig({
plugins: [react()]
});
export {
vite_config_default as default
};
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsidml0ZS5jb25maWcuanMiXSwKICAic291cmNlc0NvbnRlbnQiOiBbImNvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9kaXJuYW1lID0gXCJjOlxcXFxVc2Vyc1xcXFxjb3NtaVxcXFxPbmVEcml2ZVxcXFxEZXNrdG9wXFxcXEJsdWVXYXZlXFxcXFVwdGltZS1Nb25pdG9yXFxcXGJsdWV3YXZlLXVwdGltZVxcXFxDbGllbnRcIjtjb25zdCBfX3ZpdGVfaW5qZWN0ZWRfb3JpZ2luYWxfZmlsZW5hbWUgPSBcImM6XFxcXFVzZXJzXFxcXGNvc21pXFxcXE9uZURyaXZlXFxcXERlc2t0b3BcXFxcQmx1ZVdhdmVcXFxcVXB0aW1lLU1vbml0b3JcXFxcYmx1ZXdhdmUtdXB0aW1lXFxcXENsaWVudFxcXFx2aXRlLmNvbmZpZy5qc1wiO2NvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9pbXBvcnRfbWV0YV91cmwgPSBcImZpbGU6Ly8vYzovVXNlcnMvY29zbWkvT25lRHJpdmUvRGVza3RvcC9CbHVlV2F2ZS9VcHRpbWUtTW9uaXRvci9ibHVld2F2ZS11cHRpbWUvQ2xpZW50L3ZpdGUuY29uZmlnLmpzXCI7aW1wb3J0IHsgZGVmaW5lQ29uZmlnIH0gZnJvbSAndml0ZSdcclxuaW1wb3J0IHJlYWN0IGZyb20gJ0B2aXRlanMvcGx1Z2luLXJlYWN0J1xyXG5cclxuLy8gaHR0cHM6Ly92aXRlanMuZGV2L2NvbmZpZy9cclxuZXhwb3J0IGRlZmF1bHQgZGVmaW5lQ29uZmlnKHtcclxuICBwbHVnaW5zOiBbcmVhY3QoKV0sXHJcbn0pXHJcbiJdLAogICJtYXBwaW5ncyI6ICI7QUFBOGEsU0FBUyxvQkFBb0I7QUFDM2MsT0FBTyxXQUFXO0FBR2xCLElBQU8sc0JBQVEsYUFBYTtBQUFBLEVBQzFCLFNBQVMsQ0FBQyxNQUFNLENBQUM7QUFDbkIsQ0FBQzsiLAogICJuYW1lcyI6IFtdCn0K
@@ -1,10 +0,0 @@
// vite.config.js
import { defineConfig } from "file:///c:/Users/cosmi/OneDrive/Desktop/BlueWave/Uptime-Monitor/bluewave-uptime/Client/node_modules/vite/dist/node/index.js";
import react from "file:///c:/Users/cosmi/OneDrive/Desktop/BlueWave/Uptime-Monitor/bluewave-uptime/Client/node_modules/@vitejs/plugin-react/dist/index.mjs";
var vite_config_default = defineConfig({
plugins: [react()]
});
export {
vite_config_default as default
};
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsidml0ZS5jb25maWcuanMiXSwKICAic291cmNlc0NvbnRlbnQiOiBbImNvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9kaXJuYW1lID0gXCJjOlxcXFxVc2Vyc1xcXFxjb3NtaVxcXFxPbmVEcml2ZVxcXFxEZXNrdG9wXFxcXEJsdWVXYXZlXFxcXFVwdGltZS1Nb25pdG9yXFxcXGJsdWV3YXZlLXVwdGltZVxcXFxDbGllbnRcIjtjb25zdCBfX3ZpdGVfaW5qZWN0ZWRfb3JpZ2luYWxfZmlsZW5hbWUgPSBcImM6XFxcXFVzZXJzXFxcXGNvc21pXFxcXE9uZURyaXZlXFxcXERlc2t0b3BcXFxcQmx1ZVdhdmVcXFxcVXB0aW1lLU1vbml0b3JcXFxcYmx1ZXdhdmUtdXB0aW1lXFxcXENsaWVudFxcXFx2aXRlLmNvbmZpZy5qc1wiO2NvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9pbXBvcnRfbWV0YV91cmwgPSBcImZpbGU6Ly8vYzovVXNlcnMvY29zbWkvT25lRHJpdmUvRGVza3RvcC9CbHVlV2F2ZS9VcHRpbWUtTW9uaXRvci9ibHVld2F2ZS11cHRpbWUvQ2xpZW50L3ZpdGUuY29uZmlnLmpzXCI7aW1wb3J0IHsgZGVmaW5lQ29uZmlnIH0gZnJvbSAndml0ZSdcclxuaW1wb3J0IHJlYWN0IGZyb20gJ0B2aXRlanMvcGx1Z2luLXJlYWN0J1xyXG5cclxuLy8gaHR0cHM6Ly92aXRlanMuZGV2L2NvbmZpZy9cclxuZXhwb3J0IGRlZmF1bHQgZGVmaW5lQ29uZmlnKHtcclxuICBwbHVnaW5zOiBbcmVhY3QoKV0sXHJcbn0pXHJcbiJdLAogICJtYXBwaW5ncyI6ICI7QUFBOGEsU0FBUyxvQkFBb0I7QUFDM2MsT0FBTyxXQUFXO0FBR2xCLElBQU8sc0JBQVEsYUFBYTtBQUFBLEVBQzFCLFNBQVMsQ0FBQyxNQUFNLENBQUM7QUFDbkIsQ0FBQzsiLAogICJuYW1lcyI6IFtdCn0K
@@ -1,10 +0,0 @@
// vite.config.js
import { defineConfig } from "file:///c:/Users/cosmi/OneDrive/Desktop/BlueWave/Uptime-Monitor/bluewave-uptime/Client/node_modules/vite/dist/node/index.js";
import react from "file:///c:/Users/cosmi/OneDrive/Desktop/BlueWave/Uptime-Monitor/bluewave-uptime/Client/node_modules/@vitejs/plugin-react/dist/index.mjs";
var vite_config_default = defineConfig({
plugins: [react()]
});
export {
vite_config_default as default
};
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsidml0ZS5jb25maWcuanMiXSwKICAic291cmNlc0NvbnRlbnQiOiBbImNvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9kaXJuYW1lID0gXCJjOlxcXFxVc2Vyc1xcXFxjb3NtaVxcXFxPbmVEcml2ZVxcXFxEZXNrdG9wXFxcXEJsdWVXYXZlXFxcXFVwdGltZS1Nb25pdG9yXFxcXGJsdWV3YXZlLXVwdGltZVxcXFxDbGllbnRcIjtjb25zdCBfX3ZpdGVfaW5qZWN0ZWRfb3JpZ2luYWxfZmlsZW5hbWUgPSBcImM6XFxcXFVzZXJzXFxcXGNvc21pXFxcXE9uZURyaXZlXFxcXERlc2t0b3BcXFxcQmx1ZVdhdmVcXFxcVXB0aW1lLU1vbml0b3JcXFxcYmx1ZXdhdmUtdXB0aW1lXFxcXENsaWVudFxcXFx2aXRlLmNvbmZpZy5qc1wiO2NvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9pbXBvcnRfbWV0YV91cmwgPSBcImZpbGU6Ly8vYzovVXNlcnMvY29zbWkvT25lRHJpdmUvRGVza3RvcC9CbHVlV2F2ZS9VcHRpbWUtTW9uaXRvci9ibHVld2F2ZS11cHRpbWUvQ2xpZW50L3ZpdGUuY29uZmlnLmpzXCI7aW1wb3J0IHsgZGVmaW5lQ29uZmlnIH0gZnJvbSAndml0ZSdcclxuaW1wb3J0IHJlYWN0IGZyb20gJ0B2aXRlanMvcGx1Z2luLXJlYWN0J1xyXG5cclxuLy8gaHR0cHM6Ly92aXRlanMuZGV2L2NvbmZpZy9cclxuZXhwb3J0IGRlZmF1bHQgZGVmaW5lQ29uZmlnKHtcclxuICBwbHVnaW5zOiBbcmVhY3QoKV0sXHJcbn0pXHJcbiJdLAogICJtYXBwaW5ncyI6ICI7QUFBOGEsU0FBUyxvQkFBb0I7QUFDM2MsT0FBTyxXQUFXO0FBR2xCLElBQU8sc0JBQVEsYUFBYTtBQUFBLEVBQzFCLFNBQVMsQ0FBQyxNQUFNLENBQUM7QUFDbkIsQ0FBQzsiLAogICJuYW1lcyI6IFtdCn0K
+976 -33
View File
File diff suppressed because it is too large. Load diff
+185
View File
@@ -0,0 +1,185 @@
const express = require("express");
const logger = require("../utils/logger");
require("dotenv").config();
const {
createAlertParamValidation,
createAlertBodyValidation,
getAlertsByUserIdParamValidation,
getAlertsByMonitorIdParamValidation,
getAlertByIdParamValidation,
editAlertParamValidation,
editAlertBodyValidation,
deleteAlertParamValidation,
} = require("../validation/joi");
const { get } = require("mongoose");
const SERVICE_NAME = "alerts";
/**
* Creates an alert for a monitor
* @async
* @param {Express.Request} req
* @param {Express.Response} res
* @returns {Promise<Express.Response>}
* @throws {Error}
*/
const createAlert = async (req, res, next) => {
try {
await createAlertParamValidation.validateAsync(req.params);
await createAlertBodyValidation.validateAsync(req.body);
} catch (error) {
error.status = 422;
error.message = error.details[0].message;
error.service = SERVICE_NAME;
next(error);
return;
}
try {
const alertData = { ...req.body };
const alert = await req.db.createAlert(alertData);
return res
.status(200)
.json({ success: true, msg: "Alert created", data: alert });
} catch (error) {
error.service = SERVICE_NAME;
next(error);
}
};
/**
* Gets all alerts for a user
* @async
* @param {Express.Request} req
* @param {Express.Response} res
* @returns {Promise<Express.Response>}
* @throws {Error}
*/
const getAlertsByUserId = async (req, res, next) => {
try {
await getAlertsByUserIdParamValidation.validateAsync(req.params);
} catch (error) {
error.status = 422;
error.message = error.details[0].message;
error.service = SERVICE_NAME;
next(error);
return;
}
try {
const alerts = await req.db.getAlertsByUserId(req.params.userId);
return res
.status(200)
.json({ success: true, msg: "Got alerts", data: alerts });
} catch (error) {
error.service = SERVICE_NAME;
next(error);
}
};
const getAlertsByMonitorId = async (req, res, next) => {
try {
await getAlertsByMonitorIdParamValidation.validateAsync(req.params);
} catch (error) {
error.status = 422;
error.message = error.details[0].message;
error.service = SERVICE_NAME;
next(error);
return;
}
try {
const alerts = await req.db.getAlertsByMonitorId(req.params.monitorId);
return res.status(200).json({
success: true,
msg: "Got alerts by Monitor",
data: alerts,
});
} catch (error) {
error.service = SERVICE_NAME;
next(error);
}
};
const getAlertById = async (req, res, next) => {
try {
await getAlertByIdParamValidation.validateAsync(req.params);
} catch (error) {
error.status = 422;
error.message = error.details[0].message;
error.service = SERVICE_NAME;
next(error);
return;
}
try {
const alert = await req.db.getAlertById(req.params.alertId);
return res.status(200).json({
success: true,
msg: "Got Alert By alertID",
data: alert,
});
} catch (error) {
error.service = SERVICE_NAME;
next(error);
}
};
const editAlert = async (req, res, next) => {
try {
await editAlertParamValidation.validateAsync(req.params);
await editAlertBodyValidation.validateAsync(req.body);
} catch (error) {
console.log(error);
error.status = 422;
error.message = error.details[0].message;
error.service = SERVICE_NAME;
next(error);
return;
}
try {
const alertData = { ...req.body };
const alert = await req.db.editAlert(req.params.alertId, alertData);
return res.status(200).json({
success: true,
msg: "Edited alert",
data: alert,
});
} catch (error) {
error.service = SERVICE_NAME;
next(error);
}
};
const deleteAlert = async (req, res, next) => {
try {
await deleteAlertParamValidation.validateAsync(req.params);
} catch (error) {
error.status = 422;
error.message = error.details[0].message;
error.service = SERVICE_NAME;
next(error);
return;
}
try {
const deleted = await req.db.deleteAlert(req.params.alertId);
return res.status(200).json({
success: true,
msg: "Deleted alert",
data: deleted,
});
} catch (error) {
error.service = SERVICE_NAME;
next(error);
}
};
module.exports = {
createAlert,
getAlertsByUserId,
getAlertsByMonitorId,
getAlertById,
editAlert,
deleteAlert,
};
+2 -2
View File
@@ -17,7 +17,7 @@ const SERVICE_NAME = "auth";
* @returns {String}
*/
const issueToken = (payload) => {
return jwt.sign(payload, process.env.JWT_SECRET, { expiresIn: "1h" });
return jwt.sign(payload, process.env.JWT_SECRET, { expiresIn: "99d" });
};
/**
@@ -31,7 +31,7 @@ const registerController = async (req, res, next) => {
try {
await registerValidation.validateAsync(req.body);
} catch (error) {
error.status = 400;
error.status = 422;
error.service = SERVICE_NAME;
error.message = error.details[0].message;
next(error);
+81
View File
@@ -0,0 +1,81 @@
const {
createCheckParamValidation,
createCheckBodyValidation,
getChecksParamValidation,
deleteChecksParamValidation,
} = require("../validation/joi");
const SERVICE_NAME = "check";
const createCheck = async (req, res, next) => {
try {
await createCheckParamValidation.validateAsync(req.params);
await createCheckBodyValidation.validateAsync(req.body);
} catch (error) {
error.status = 422;
error.service = SERVICE_NAME;
error.message = error.details[0].message;
next(error);
return;
}
try {
const checkData = { ...req.body };
const check = await req.db.createCheck(checkData);
return res
.status(200)
.json({ success: true, msg: "Check created", data: check });
} catch (error) {
error.service = SERVICE_NAME;
next(error);
}
};
const getChecks = async (req, res, next) => {
try {
await getChecksParamValidation.validateAsync(req.params);
} catch (error) {
error.status = 422;
error.service = SERVICE_NAME;
error.message = error.details[0].message;
next(error);
return;
}
try {
const checks = await req.db.getChecks(req.params.monitorId);
return res
.status(200)
.json({ success: true, msg: "Checks retrieved", data: checks });
} catch (error) {
error.service = SERVICE_NAME;
next(error);
}
};
const deleteChecks = async (req, res, next) => {
try {
await deleteChecksParamValidation.validateAsync(req.params);
} catch (error) {
error.status = 422;
error.service = SERVICE_NAME;
error.message = error.details[0].message;
next(error);
return;
}
try {
const deletedCount = await req.db.deleteChecks(req.params.monitorId);
return res
.status(200)
.json({ success: true, msg: "Checks deleted", data: { deletedCount } });
} catch (error) {
error.service = SERVICE_NAME;
next(error);
}
};
module.exports = {
createCheck,
getChecks,
deleteChecks,
};
+203
View File
@@ -1,6 +1,8 @@
const Monitor = require("../models/Monitor");
const mongoose = require("mongoose");
const UserModel = require("../models/user");
const Check = require("../models/Check");
const Alert = require("../models/Alert");
const verifyId = (userId, monitorId) => {
return userId.toString() === monitorId.toString();
@@ -16,6 +18,10 @@ const connect = async () => {
}
};
//****************************************
// Users
//****************************************
/**
* Insert a User
* @async
@@ -80,6 +86,10 @@ const updateUser = async (req, res) => {
}
};
//****************************************
// Monitors
//****************************************
/**
* Get all monitors
* @async
@@ -194,6 +204,190 @@ const editMonitor = async (req, res) => {
}
};
//****************************************
// Checks
//****************************************
/**
* Create a check for a monitor
* @async
* @param {Object} checkData
* @param {string} checkData.monitorId
* @param {boolean} checkData.status
* @param {number} checkData.responseTime
* @param {number} checkData.statusCode
* @param {string} checkData.message
* @returns {Promise<Check>}
* @throws {Error}
*/
const createCheck = async (checkData) => {
try {
console.log(checkData);
const check = await new Check({ ...checkData }).save();
return check;
} catch (error) {
throw error;
}
};
/**
* Get all checks for a monitor
* @async
* @param {string} monitorId
* @returns {Promise<Array<Check>>}
* @throws {Error}
*/
const getChecks = async (monitorId) => {
try {
const checks = await Check.find({ monitorId });
return checks;
} catch (error) {
throw error;
}
};
/**
* Delete all checks for a monitor
* @async
* @param {string} monitorId
* @returns {number}
* @throws {Error}
*/
const deleteChecks = async (monitorId) => {
try {
const result = await Check.deleteMany({ monitorId });
if (result.deletedCount > 0) {
return result.deletedCount;
} else {
throw new Error(`No checks found for monitor with id ${monitorId}`);
}
} catch (error) {
throw error;
}
};
//****************************************
// Alerts
//****************************************
/**
* Creates an Alert associated with a Monitor and User
* @async
* @param {Object} alertData
* @param {string} alertData.checkId
* @param {string} alert.monitorId
* @param {string} alert.userId
* @param {boolean} alert.status
* @param {string} alert.message
* @param {boolean} alert.notifiedStatus
* @param {boolean} alert.acknowledgeStatus
* @returns {<Promise<Alert>>}
* @throws {Error}
*/
const createAlert = async (alertData) => {
try {
const alert = await new Alert({ ...alertData }).save();
return alert;
} catch (error) {
throw error;
}
};
/**
* Gets all alerts a User has set
* @async
* @param {string} userId
* @returns {<Promise<Array<Alert>>}
* @throws {Error}
*/
const getAlertsByUserId = async (userId) => {
try {
const alerts = await Alert.find({ userId });
return alerts;
} catch (error) {
throw error;
}
};
/**
* Gets all alerts a for an associated Monitor
* @async
* @param {string} monitorId
* @returns {<Promise<Array<Alert>>}
* @throws {Error}
*/
const getAlertsByMonitorId = async (monitorId) => {
try {
const alerts = await Alert.find({ monitorId });
return alerts;
} catch (error) {
throw error;
}
};
/**
* Returns an alert with specified ID
* @async
* @param {string} alertId
* @returns {Promise<Alert>}
* @throws {Error}
*/
const getAlertById = async (alertId) => {
try {
const alert = await Alert.findById(alertId);
return alert;
} catch (error) {
throw error;
}
};
/**
* Returns an edited alert with the specified ID
* @async
* @param {string} alertId
* @param {Object} alertData
* @param {string} alertData.checkId
* @param {string} alertData.monitorId
* @param {string} alertData.userId
* @param {boolean} alertData.status
* @param {string} alertData.message
* @param {boolean} alertData.notifiedStatus
* @param {boolean} alertData.acknowledgeStatus
* @param {Express.Response} res
* @returns {Promise<Alert>>}
* @throws {Error}
*/
const editAlert = async (alertId, alertData) => {
try {
const editedAlert = await Alert.findByIdAndUpdate(alertId, alertData, {
new: true,
});
return editedAlert;
} catch (error) {
throw error;
}
};
/**
* Deletes an alert with the specified ID
* @async
* @param {string} alertId
* @throws {Error}
*/
const deleteAlert = async (alertId) => {
try {
const result = await Alert.findByIdAndDelete(alertId);
if (result) {
return result;
} else throw new Error(`Alert with id ${alertId} not found`);
} catch (error) {
throw error;
}
};
module.exports = {
connect,
insertUser,
@@ -205,4 +399,13 @@ module.exports = {
createMonitor,
deleteMonitor,
editMonitor,
createCheck,
getChecks,
deleteChecks,
createAlert,
getAlertsByUserId,
getAlertsByMonitorId,
getAlertById,
editAlert,
deleteAlert,
};
+5 -13
View File
@@ -3,14 +3,14 @@ const helmet = require("helmet");
const cors = require("cors");
const authRouter = require("./routes/authRoute");
const monitorRouter = require("./routes/monitorRoute");
const checkRouter = require("./routes/checkRoute");
const alertRouter = require("./routes/alertRoute");
const { connectDbAndRunServer } = require("./configs/db");
require("dotenv").config();
const logger = require("./utils/logger");
const { verifyJWT } = require("./middleware/verifyJWT");
const { handleErrors } = require("./middleware/handleErrors");
// const { sendEmail } = require('./utils/sendEmail')
// **************************
// Here is where we can swap out DBs easily. Spin up a mongoDB instance and try it out.
// Simply comment out the FakeDB and uncomment the MongoDB or vice versa.
@@ -33,11 +33,6 @@ const db = DB_TYPE[process.env.DB_TYPE]
? DB_TYPE[process.env.DB_TYPE]()
: require("./db/FakeDb");
/**
* NOTES
* Email Service will be added
* Logger Service will be added (Winston or similar)
*/
const app = express();
@@ -61,13 +56,10 @@ app.use((req, res, next) => {
//routes
app.use("/api/v1/auth", authRouter);
app.use("/api/v1/monitors", verifyJWT, monitorRouter);
app.use("/api/v1/monitors", monitorRouter);
app.use("/api/v1/checks", verifyJWT, checkRouter);
app.use("/api/v1/alerts", verifyJWT, alertRouter);
// Testing email service
// app.use('/sendEmail', async (req, res) => {
// const response = sendEmail(['veysel.boybay@bluewavelabs.ca'], 'Testing email service', '<h1>Testing Bluewavelabs</h1>');
// console.log(response);
// })
//health check
app.use("/api/v1/healthy", (req, res) => {
+10
View File
@@ -7,6 +7,16 @@ const AlertSchema = mongoose.Schema(
ref: 'Check',
immutable: true,
},
monitorId: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Monitor',
immutable: true,
},
userId: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User',
immutable: true,
},
status: {
type: Boolean,
},
+115
View File
@@ -9,6 +9,7 @@
"version": "1.0.0",
"license": "ISC",
"dependencies": {
"@sendgrid/mail": "^8.1.3",
"bcrypt": "^5.1.1",
"cors": "^2.8.5",
"dotenv": "^16.4.5",
@@ -96,6 +97,41 @@
"sparse-bitfield": "^3.0.3"
}
},
"node_modules/@sendgrid/client": {
"version": "8.1.3",
"resolved": "https://registry.npmjs.org/@sendgrid/client/-/client-8.1.3.tgz",
"integrity": "sha512-mRwTticRZIdUTsnyzvlK6dMu3jni9ci9J+dW/6fMMFpGRAJdCJlivFVYQvqk8kRS3RnFzS7sf6BSmhLl1ldDhA==",
"dependencies": {
"@sendgrid/helpers": "^8.0.0",
"axios": "^1.6.8"
},
"engines": {
"node": ">=12.*"
}
},
"node_modules/@sendgrid/helpers": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/@sendgrid/helpers/-/helpers-8.0.0.tgz",
"integrity": "sha512-Ze7WuW2Xzy5GT5WRx+yEv89fsg/pgy3T1E3FS0QEx0/VvRmigMZ5qyVGhJz4SxomegDkzXv/i0aFPpHKN8qdAA==",
"dependencies": {
"deepmerge": "^4.2.2"
},
"engines": {
"node": ">= 12.0.0"
}
},
"node_modules/@sendgrid/mail": {
"version": "8.1.3",
"resolved": "https://registry.npmjs.org/@sendgrid/mail/-/mail-8.1.3.tgz",
"integrity": "sha512-Wg5iKSUOER83/cfY6rbPa+o3ChnYzWwv1OcsR8gCV8SKi+sUPIMroildimlnb72DBkQxcbylxng1W7f0RIX7MQ==",
"dependencies": {
"@sendgrid/client": "^8.1.3",
"@sendgrid/helpers": "^8.0.0"
},
"engines": {
"node": ">=12.*"
}
},
"node_modules/@sideway/address": {
"version": "4.1.5",
"resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.5.tgz",
@@ -229,6 +265,21 @@
"resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz",
"integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg=="
},
"node_modules/asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
},
"node_modules/axios": {
"version": "1.7.2",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.7.2.tgz",
"integrity": "sha512-2A8QhOMrbomlDuiLeK9XibIBzuHeRcqqNOHp0Cyp5EoJ1IFDh+XZH3A6BkXtv0K4gFGCI0Y4BM7B1wOEi0Rmgw==",
"dependencies": {
"follow-redirects": "^1.15.6",
"form-data": "^4.0.0",
"proxy-from-env": "^1.1.0"
}
},
"node_modules/balanced-match": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
@@ -422,6 +473,17 @@
"text-hex": "1.0.x"
}
},
"node_modules/combined-stream": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
"dependencies": {
"delayed-stream": "~1.0.0"
},
"engines": {
"node": ">= 0.8"
}
},
"node_modules/concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
@@ -484,6 +546,14 @@
"ms": "2.0.0"
}
},
"node_modules/deepmerge": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz",
"integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/define-data-property": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
@@ -500,6 +570,14 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/delegates": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
@@ -689,6 +767,38 @@
"resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz",
"integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw=="
},
"node_modules/follow-redirects": {
"version": "1.15.6",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz",
"integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==",
"funding": [
{
"type": "individual",
"url": "https://github.com/sponsors/RubenVerborgh"
}
],
"engines": {
"node": ">=4.0"
},
"peerDependenciesMeta": {
"debug": {
"optional": true
}
}
},
"node_modules/form-data": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
"integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
"dependencies": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.8",
"mime-types": "^2.1.12"
},
"engines": {
"node": ">= 6"
}
},
"node_modules/forwarded": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
@@ -1703,6 +1813,11 @@
"node": ">= 0.10"
}
},
"node_modules/proxy-from-env": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
},
"node_modules/pstree.remy": {
"version": "1.1.8",
"resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz",
+1
View File
@@ -11,6 +11,7 @@
"author": "",
"license": "ISC",
"dependencies": {
"@sendgrid/mail": "^8.1.3",
"bcrypt": "^5.1.1",
"cors": "^2.8.5",
"dotenv": "^16.4.5",
+27
View File
@@ -0,0 +1,27 @@
const router = require("express").Router();
const alertController = require("../controllers/alertController");
const { verifyOwnership } = require("../middleware/verifyOwnership");
const Alert = require("../models/Alert");
// Create alert
router.post("/:monitorId", alertController.createAlert);
// Get all alerts for a user
router.get("/user/:userId", alertController.getAlertsByUserId);
// Get all alerts for a monitor
router.get("/monitor/:monitorId", alertController.getAlertsByMonitorId);
// Get a single alert
router.get("/:alertId", alertController.getAlertById);
// Edit
router.post(
"/edit/:alertId",
verifyOwnership(Alert, "alertId"),
alertController.editAlert
);
//Delete
router.post(
"/delete/:alertId",
verifyOwnership(Alert, "alertId"),
alertController.deleteAlert
);
module.exports = router;
+24
View File
@@ -0,0 +1,24 @@
const router = require("express").Router();
const checkController = require("../controllers/checkController");
const { verifyOwnership } = require("../middleware/verifyOwnership");
const Monitor = require("../models/Monitor");
router.post(
"/:monitorId",
verifyOwnership(Monitor, "monitorId"),
checkController.createCheck
);
router.get(
"/:monitorId",
verifyOwnership(Monitor, "monitorId"),
checkController.getChecks
);
router.post(
"/delete/:monitorId",
verifyOwnership(Monitor, "monitorId"),
checkController.deleteChecks
);
module.exports = router;
+27 -34
View File
@@ -1,43 +1,36 @@
const { MailerSend, EmailParams, Sender, Recipient } = require('mailersend')
const logger = require('../utils/logger')
const mailersend = new MailerSend({
apiKey: process.env.MAILERSEND_API_KEY,
})
const sgMail = require('@sendgrid/mail')
const logger = require('./logger')
sgMail.setApiKey(process.env.SENDGRID_API_KEY)
const SERVICE_NAME = 'Email_Service';
/**
* @async
* @function
* @param {[string]} receivers - takes an array of strings
* @param {string} subject - takes a single string
* @param {string} contentHTML - takes a single string that contains HTML
* @returns {JSON}
* @example
* sendEmail(['veysel@bluewavelabs.ca','alex@bluewavelabs.ca','monzer@bluewavelabs.ca'],'Testing Email Servide','<h1>BlueWaveLabs</h1>')
* @param {[String]} receivers - takes an array of strings
* @param {String} subject - takes a single string
* @param {String} contentHTML - takes a single string that contains HTML
* @param {String} contentText - takes a string to be used if contentHTML is not compatible
* @example
* await sendEmail(['veysel@bluewavelabs.ca','alex@bluewavelabs.ca'],'Testing Email Service','<h1>BlueWaveLabs</h1>','Testing Email Service')
*/
// TODO: from email should be in .env file
const sendEmail = async (receivers,subject,contentHTML) => {
// Sender
const from = process.env.SYSTEM_EMAIL_ADDRESS;
const sender = new Sender(from);
// receivers
let recipients = []
receivers.map(email => recipients.push(new Recipient(email)));
// Set params
const emailParams = new EmailParams()
.setFrom(sender)
.setTo(recipients)
.setSubject(subject)
.setHtml(contentHTML);
const sendEmail = async (receivers,subject, contentHTML, contentText = null ) => {
const msg = {
to: receivers,
from: {
name: 'Uptime System',
email: process.env.SYSTEM_EMAIL_ADDRESS // must be verified email by sendgrid
},
subject: subject,
text: contentText || contentHTML,
html: contentHTML,
}
try {
const response = await mailersend.email.send(emailParams);
logger.info("Email sent to receivers!",{"service":"Email"})
return response;
await sgMail.send(msg);
logger.info(`Emails sent to receivers:${receivers} with the subject:${subject}`,{service:SERVICE_NAME})
} catch (error) {
logger.error(error.body,{"service":"email"})
console.log(error.body)
logger.error(`Sending Email action failed, ERROR:${error}`, { service: SERVICE_NAME });
}
}
module.exports = {sendEmail}
+94 -5
View File
@@ -1,5 +1,9 @@
const joi = require("joi");
//****************************************
// Auth
//****************************************
const loginValidation = joi.object({
email: joi.string().email().required(),
password: joi.string().min(8).required(),
@@ -11,6 +15,20 @@ const registerValidation = joi.object({
password: joi.string().min(8).required(),
});
const editUserParamValidation = joi.object({
userId: joi.string().required(),
});
const editUserBodyValidation = joi.object({
firstname: joi.string(),
lastname: joi.string(),
profilePicUrl: joi.string(),
});
//****************************************
// Monitors
//****************************************
const getMonitorByIdValidation = joi.object({
monitorId: joi.string().required(),
});
@@ -29,14 +47,73 @@ const monitorValidation = joi.object({
interval: joi.number(),
});
const editUserParamValidation = joi.object({
//****************************************
// Alerts
//****************************************
const createAlertParamValidation = joi.object({
monitorId: joi.string().required(),
});
const createAlertBodyValidation = joi.object({
checkId: joi.string().required(),
monitorId: joi.string().required(),
userId: joi.string().required(),
status: joi.boolean(),
message: joi.string(),
notifiedStatus: joi.boolean(),
acknowledgeStatus: joi.boolean(),
});
const getAlertsByUserIdParamValidation = joi.object({
userId: joi.string().required(),
});
const editUserBodyValidation = joi.object({
firstname: joi.string(),
lastname: joi.string(),
profilePicUrl: joi.string(),
const getAlertsByMonitorIdParamValidation = joi.object({
monitorId: joi.string().required(),
});
const getAlertByIdParamValidation = joi.object({
alertId: joi.string().required(),
});
const editAlertParamValidation = joi.object({
alertId: joi.string().required(),
});
const editAlertBodyValidation = joi.object({
status: joi.boolean(),
message: joi.string(),
notifiedStatus: joi.boolean(),
acknowledgeStatus: joi.boolean(),
});
const deleteAlertParamValidation = joi.object({
alertId: joi.string().required(),
});
//****************************************
// Checks
//****************************************
const createCheckParamValidation = joi.object({
monitorId: joi.string().required(),
});
const createCheckBodyValidation = joi.object({
monitorId: joi.string().required(),
status: joi.boolean().required(),
responseTime: joi.number().required(),
statusCode: joi.number().required(),
message: joi.string().required(),
});
const getChecksParamValidation = joi.object({
monitorId: joi.string().required(),
});
const deleteChecksParamValidation = joi.object({
monitorId: joi.string().required(),
});
module.exports = {
@@ -47,4 +124,16 @@ module.exports = {
monitorValidation,
editUserParamValidation,
editUserBodyValidation,
createAlertParamValidation,
createAlertBodyValidation,
getAlertsByUserIdParamValidation,
getAlertsByMonitorIdParamValidation,
getAlertByIdParamValidation,
editAlertParamValidation,
editAlertBodyValidation,
deleteAlertParamValidation,
createCheckParamValidation,
createCheckBodyValidation,
getChecksParamValidation,
deleteChecksParamValidation,
};