From 7888205375647a215030d0d245f26622af0ac41b Mon Sep 17 00:00:00 2001 From: MuhammadKhalilzadeh Date: Wed, 15 May 2024 09:40:50 +0330 Subject: [PATCH] tsx to jsx and components to Components --- .../AnnouncementUpdateSubscription.jsx | 71 +++++++++++++ .../announcementUpdateSubscription.css | 99 +++++++++++++++++++ .../AnnouncementsDualButton.jsx | 55 +++++++++++ .../announcementsDualButton.css | 38 +++++++ .../announcementsDualButtonWithIcon.css | 69 +++++++++++++ .../AnnouncementsMessageBar.jsx | 36 +++++++ .../announcementsMessageBar.css | 12 +++ .../Charts/Servers/ServerStatus.jsx | 37 +++++++ .../Charts/Servers/serverStatus.css | 44 +++++++++ .../Charts/Statistics/Statistic.jsx | 35 +++++++ .../Charts/Statistics/statistic.css | 31 ++++++ .../Icons/ComplexAlert/ComplexAlert.jsx | 36 +++++++ .../Icons/ComplexAlert/complexAlert.css | 44 +++++++++ .../DualButtonPopupModal.jsx | 55 +++++++++++ .../dualButtonPopupModal.css | 60 +++++++++++ .../DualButtonPopupModalWithTextfields.jsx | 73 ++++++++++++++ .../dualButtonPopupModalWithTextfields.css | 61 ++++++++++++ .../Description/DescriptionTextField.jsx | 47 +++++++++ .../Description/descriptionTextField.css | 45 +++++++++ .../TextFields/Email/EmailTextField.jsx | 88 +++++++++++++++++ .../TextFields/Email/emailTextField.css | 41 ++++++++ .../TextFields/Website/WebsiteTextField.jsx | 72 ++++++++++++++ .../TextFields/Website/websiteTextField.css | 82 +++++++++++++++ .../TooltipWithTail/tooltipWithTail.css | 17 ++++ 24 files changed, 1248 insertions(+) create mode 100644 Client/src/Components/Announcements/AnnouncementUpdateSubscription/AnnouncementUpdateSubscription.jsx create mode 100644 Client/src/Components/Announcements/AnnouncementUpdateSubscription/announcementUpdateSubscription.css create mode 100644 Client/src/Components/Announcements/AnnouncementsDualButton/AnnouncementsDualButton.jsx create mode 100644 Client/src/Components/Announcements/AnnouncementsDualButton/announcementsDualButton.css create mode 100644 Client/src/Components/Announcements/AnnouncementsDualButtonWithIcon/announcementsDualButtonWithIcon.css create mode 100644 Client/src/Components/Announcements/AnnouncementsMessageBar/AnnouncementsMessageBar.jsx create mode 100644 Client/src/Components/Announcements/AnnouncementsMessageBar/announcementsMessageBar.css create mode 100644 Client/src/Components/Charts/Servers/ServerStatus.jsx create mode 100644 Client/src/Components/Charts/Servers/serverStatus.css create mode 100644 Client/src/Components/Charts/Statistics/Statistic.jsx create mode 100644 Client/src/Components/Charts/Statistics/statistic.css create mode 100644 Client/src/Components/Icons/ComplexAlert/ComplexAlert.jsx create mode 100644 Client/src/Components/Icons/ComplexAlert/complexAlert.css create mode 100644 Client/src/Components/PopupModals/DualButtonPopupModal/DualButtonPopupModal.jsx create mode 100644 Client/src/Components/PopupModals/DualButtonPopupModal/dualButtonPopupModal.css create mode 100644 Client/src/Components/PopupModals/DualButtonPopupModalWithTextfields/DualButtonPopupModalWithTextfields.jsx create mode 100644 Client/src/Components/PopupModals/DualButtonPopupModalWithTextfields/dualButtonPopupModalWithTextfields.css create mode 100644 Client/src/Components/TextFields/Description/DescriptionTextField.jsx create mode 100644 Client/src/Components/TextFields/Description/descriptionTextField.css create mode 100644 Client/src/Components/TextFields/Email/EmailTextField.jsx create mode 100644 Client/src/Components/TextFields/Email/emailTextField.css create mode 100644 Client/src/Components/TextFields/Website/WebsiteTextField.jsx create mode 100644 Client/src/Components/TextFields/Website/websiteTextField.css create mode 100644 Client/src/Components/Tooltips/TooltipWithTail/tooltipWithTail.css diff --git a/Client/src/Components/Announcements/AnnouncementUpdateSubscription/AnnouncementUpdateSubscription.jsx b/Client/src/Components/Announcements/AnnouncementUpdateSubscription/AnnouncementUpdateSubscription.jsx new file mode 100644 index 000000000..f3363e866 --- /dev/null +++ b/Client/src/Components/Announcements/AnnouncementUpdateSubscription/AnnouncementUpdateSubscription.jsx @@ -0,0 +1,71 @@ +import "./announcementUpdateSubscription.css"; +import React from "react"; +import PropTypes from "prop-types"; +import { useTheme } from "@mui/material"; + +/** + * @component + * @param {Object} props + * @param {string} props.title - Title text for the update subscription dialog (required) + * @param {string} props.text - Body text for the update subscription dialog (required) + * @param {string} props.cancel - Text for the negative (cancel) button (required) + * @param {string} props.positive - Text for the positive button (required) + * @param {string} props.header - Title text for the email subscription section (required) + * @param {string} props.button - Text for the subscribe button (required) + * @returns {JSX.Element} - Renders the announcement update subscription component + */ + +const AnnouncementUpdateSubscription = ({ + title, + text, + cancel, + positive, + header, + button, +}) => { + const theme = useTheme(); + + const fontLookup = { + default: theme.font.default.font, + }; + + const fontFamily = fontLookup["default"]; + + return ( +
+
+
{title}
+
+
{text}
+
+
+ + +
+
+
+
+
{header}
+
+ + +
+
+
+ ); +}; + +AnnouncementUpdateSubscription.propTypes = { + title: PropTypes.string.isRequired, + text: PropTypes.string.isRequired, + cancel: PropTypes.string.isRequired, + positive: PropTypes.string.isRequired, + header: PropTypes.string.isRequired, + button: PropTypes.string.isRequired, +}; + +export default AnnouncementUpdateSubscription; diff --git a/Client/src/Components/Announcements/AnnouncementUpdateSubscription/announcementUpdateSubscription.css b/Client/src/Components/Announcements/AnnouncementUpdateSubscription/announcementUpdateSubscription.css new file mode 100644 index 000000000..7974ee799 --- /dev/null +++ b/Client/src/Components/Announcements/AnnouncementUpdateSubscription/announcementUpdateSubscription.css @@ -0,0 +1,99 @@ +: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, +.update-subscription-dialog { + max-width: 770px; + border-radius: 4px; + border: 1px solid #eaecf0; +} + +.update-subscription-dialog { + padding: 15px 30px; +} + +.subscription-dialog-title { + font-size: 1rem; + font-weight: 700; + color: var(--update-subscription-color-0); +} + +.v-spacing-small { + height: 10px; +} + +.v-spacing-medium { + height: 15px; +} + +.subscription-dialog-text { + font-size: 13px; + color: var(--update-subscription-color-1); +} + +.subscription-dialog-controls { + display: flex; +} + +.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); +} + +.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); +} + +.update-subscription-title { + color: var(--update-subscription-color-6); + padding: 0 var(--spacing-2); + font-weight: 700; + font-size: 13px; + margin-bottom: 10px; +} + +.subscription-email { + display: flex; + padding: 0 var(--spacing-2); +} + +.subscription-email-field { + width: 290px; + height: 24px; + border-radius: var(--update-subscription-radius-0); + border: 1px solid var(--update-subscription-color-7); + box-shadow: 0px 1px 2px 0px rgba(101, 182, 28, 0.05); + padding: 5px 15px; + margin-right: var(--spacing-2); +} + +.subscribe-button { + width: 100px; + height: 34px; + padding: 2px 15px; +} diff --git a/Client/src/Components/Announcements/AnnouncementsDualButton/AnnouncementsDualButton.jsx b/Client/src/Components/Announcements/AnnouncementsDualButton/AnnouncementsDualButton.jsx new file mode 100644 index 000000000..2abbadb1e --- /dev/null +++ b/Client/src/Components/Announcements/AnnouncementsDualButton/AnnouncementsDualButton.jsx @@ -0,0 +1,55 @@ +import "./announcementsDualButton.css"; +import React from "react"; +import CloseIcon from "@mui/icons-material/Close"; +import PropTypes from "prop-types"; +import { useTheme } from "@mui/material"; + +/** + * @component + * @param {Object} props + * @param {string} props.subject - The announcement subject text + * @param {string} props.body - The announcement body text content + * @param {string} props.esc - The text for the escape button + * @param {string} props.primary - The text for the primary button + * @returns {JSX.Element} - Renders the announcement dual button component + */ + +const AnnouncementsDualButton = ({ subject, body, esc, primary }) => { + const theme = useTheme(); + + const fontLookup = { + default: theme.font.default.font, + }; + + const fontFamily = fontLookup["default"]; + + return ( +
+
+
{subject}
+
+
{body}
+
+
{esc}
+
{primary}
+
+
+
+
+ +
+
+ ); +}; + +AnnouncementsDualButton.propTypes = { + subject: PropTypes.string.isRequired, + body: PropTypes.string.isRequired, + esc: PropTypes.string.isRequired, + primary: PropTypes.string.isRequired, +}; + +export default AnnouncementsDualButton; diff --git a/Client/src/Components/Announcements/AnnouncementsDualButton/announcementsDualButton.css b/Client/src/Components/Announcements/AnnouncementsDualButton/announcementsDualButton.css new file mode 100644 index 000000000..837fd0bb5 --- /dev/null +++ b/Client/src/Components/Announcements/AnnouncementsDualButton/announcementsDualButton.css @@ -0,0 +1,38 @@ +:root { + --announcement-border-color: #d0d5dd; + --announcement-border-radius: 4px; + --announcement-border-radius-2: 8px; + /* --announcement-font-family: "Roboto", "Helvetica", "Arial", sans-serif; */ + --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; +} + +.announcement-without-tile { + max-width: 343px; + width: fit-content; + display: flex; + border: 1px solid var(--announcement-border-color); + /* font-family: var(--announcement-font-family); */ + padding: var(--announcement-padding); + border-radius: var(--announcement-border-radius); +} + +.h-spacing { + width: 20px; +} + +.announcement-without-content-subject { + font-size: var(--announcement-font-size-0); + color: var(--announcement-font-color-0); + font-weight: 700; + margin-bottom: 10px; +} + +.announcement-without-content-body { + font-size: var(--announcement-font-size-0); + color: var(--announcement-font-color-1); +} diff --git a/Client/src/Components/Announcements/AnnouncementsDualButtonWithIcon/announcementsDualButtonWithIcon.css b/Client/src/Components/Announcements/AnnouncementsDualButtonWithIcon/announcementsDualButtonWithIcon.css new file mode 100644 index 000000000..80c6ae265 --- /dev/null +++ b/Client/src/Components/Announcements/AnnouncementsDualButtonWithIcon/announcementsDualButtonWithIcon.css @@ -0,0 +1,69 @@ +: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; +} + +.announcement-tile { + width: fit-content; + display: flex; + border: 1px solid var(--announcement-border-color); + padding: var(--announcement-padding); + border-radius: var(--announcement-border-radius); +} + +.info-icon-frame { + display: flex; + width: 40px; + height: 40px; + border: 1px solid var(--info-icon-frame-color); + border-radius: var(--announcement-border-radius-2); + justify-content: center; + align-items: center; +} + +.announcement-content { + padding: 0 var(--announcement-padding); +} + +.announcement-content-subject { + font-size: var(--announcement-font-size-0); + color: var(--announcement-font-color-0); + font-weight: 700; + margin-bottom: 10px; +} + +.announcement-content-body { + font-size: var(--announcement-font-size-0); + color: var(--announcement-font-color-1); + font-weight: 300; +} + +.announcement-content-controllers { + display: flex; + font-size: var(--announcement-font-size-0); + margin-top: 15px; +} + +.controllers-button-esc { + font-size: var(--announcement-font-size-0); + font-weight: 600; + margin-right: 12px; +} + +.controllers-button-primary { + font-size: var(--announcement-font-size-0); + font-weight: 600; + color: var(--announcement-font-color-2); +} + +.announcement-close { + width: 24px; + height: 24px; +} diff --git a/Client/src/Components/Announcements/AnnouncementsMessageBar/AnnouncementsMessageBar.jsx b/Client/src/Components/Announcements/AnnouncementsMessageBar/AnnouncementsMessageBar.jsx new file mode 100644 index 000000000..20a179052 --- /dev/null +++ b/Client/src/Components/Announcements/AnnouncementsMessageBar/AnnouncementsMessageBar.jsx @@ -0,0 +1,36 @@ +import "./announcementsMessageBar.css"; +import React from "react"; +import CloseIcon from "@mui/icons-material/Close"; +import PropTypes from "prop-types"; +import { useTheme } from "@mui/material"; + +/** + * @component + * @param {Object} props + * @param {string} props.message - The announcement message text content (required) + * @returns {JSX.Element} - Renders the announcement message bar component + */ +const AnnouncementsMessageBar = ({ message }) => { + const theme = useTheme(); + + const fontLookup = { + default: theme.font.default.font, + }; + + const fontFamily = fontLookup["default"]; + + return ( +
+
{message}
+
+ +
+
+ ); +}; + +AnnouncementsMessageBar.propTypes = { + message: PropTypes.string.isRequired, +}; + +export default AnnouncementsMessageBar; diff --git a/Client/src/Components/Announcements/AnnouncementsMessageBar/announcementsMessageBar.css b/Client/src/Components/Announcements/AnnouncementsMessageBar/announcementsMessageBar.css new file mode 100644 index 000000000..2e9f95e83 --- /dev/null +++ b/Client/src/Components/Announcements/AnnouncementsMessageBar/announcementsMessageBar.css @@ -0,0 +1,12 @@ +:root { + --announcement-font-size-0: 13px; + --announcement-padding: 16px; +} + +.announcement-messagebar-body { + font-size: var(--announcement-font-size-0); + padding: 0 var(--announcement-padding) 0 0; + justify-content: center; + align-items: center; + margin: auto; +} diff --git a/Client/src/Components/Charts/Servers/ServerStatus.jsx b/Client/src/Components/Charts/Servers/ServerStatus.jsx new file mode 100644 index 000000000..f910abf27 --- /dev/null +++ b/Client/src/Components/Charts/Servers/ServerStatus.jsx @@ -0,0 +1,37 @@ +import React from "react"; +import "./serverStatus.css"; +import PropTypes from "prop-types"; +import { useTheme } from "@mui/material"; + +/** + * @component + * @param {Object} props + * @param {string} props.title - The title text for the server status (required) + * @param {string} props.value - The value text to be displayed (required) + * @param {string} props.state - The state of the server (e.g., "online", "offline", "warning") (required) + * @returns {JSX.Element} - Renders the server status component + */ +const ServerStatus = ({ title, value, state }) => { + const theme = useTheme(); + + const fontLookup = { + default: theme.font.default.font, + }; + + const fontFamily = fontLookup["default"]; + + return ( +
+
{title}
+
{value}
+
+ ); +}; + +ServerStatus.propTypes = { + title: PropTypes.string.isRequired, + value: PropTypes.string.isRequired, + state: PropTypes.string.isRequired, +}; + +export default ServerStatus; diff --git a/Client/src/Components/Charts/Servers/serverStatus.css b/Client/src/Components/Charts/Servers/serverStatus.css new file mode 100644 index 000000000..9126d9b3b --- /dev/null +++ b/Client/src/Components/Charts/Servers/serverStatus.css @@ -0,0 +1,44 @@ +:root { + --spacing-general-0: 10px 25px; + --spacing-general-1: 20px; + --color-border-0: #eaecf0; + --border-radius-0: 4px; + --font-size-0: 1rem; + --font-size-2: 36px; + + --color-up: #17b26a; + --color-down: #f04438; + --color-pause: #fdb022; +} + +.server-status-tile { + width: 230px; + margin: var(--spacing-general-0); + margin-left: 10px; + padding: var(--spacing-general-1); + border: 1px solid var(--color-border-0); + border-radius: var(--border-radius-0); +} + +.server-status-tile-title { + font-size: var(--font-size-0); + font-weight: bold; + margin-bottom: 25px; +} + +.server-status-tile-value { + font-size: var(--font-size-2); + font-weight: bolder; +} + +.up { + color: var(--color-up); +} + +.down { + color: var(--color-down); +} + +.pause { + color: var(--color-pause); +} diff --git a/Client/src/Components/Charts/Statistics/Statistic.jsx b/Client/src/Components/Charts/Statistics/Statistic.jsx new file mode 100644 index 000000000..99ad2066f --- /dev/null +++ b/Client/src/Components/Charts/Statistics/Statistic.jsx @@ -0,0 +1,35 @@ +import React from "react"; +import "./statistic.css"; +import PropTypes from "prop-types"; +import { useTheme } from "@mui/material"; + +/** + * @component + * @param {Object} props + * @param {string} props.title - The title text for the statistic (required) + * @param {string} props.value - The numerical or textual value for the statistic (required) + * @returns {JSX.Element} - Renders the statistic component + */ +const Statistic = ({ title, value }) => { + const theme = useTheme(); + + const fontLookup = { + default: theme.font.default.font, + }; + + const fontFamily = fontLookup["default"]; + + return ( +
+
{title}
+
{value}
+
+ ); +}; + +Statistic.propTypes = { + title: PropTypes.string.isRequired, + value: PropTypes.string.isRequired, +}; + +export default Statistic; diff --git a/Client/src/Components/Charts/Statistics/statistic.css b/Client/src/Components/Charts/Statistics/statistic.css new file mode 100644 index 000000000..a8834199d --- /dev/null +++ b/Client/src/Components/Charts/Statistics/statistic.css @@ -0,0 +1,31 @@ +:root { + --stats-spacing-general-0: 5px 10px; + --color-border-0: #eaecf0; + --border-radius-0: 4px; + --font-size-0: 1rem; + --font-size-1: 13px; + --font-color-0: #344054; + --margin-bottom-0: 10px; +} + +.statistic-tile { + margin: var(--stats-spacing-general-0); + padding: var(--stats-spacing-general-0); + border: 1px solid var(--color-border-0); + border-radius: var(--border-radius-0); + + width: 180px; +} + +.statistic-tile-title { + font-size: var(--font-size-0); + color: var(--font-color-0); + margin-bottom: var(--margin-bottom-0); +} + +.statistic-tile-value { + font-size: var(--font-size-1); + color: var(--font-color-0); + font-weight: 700; + margin-bottom: var(--margin-bottom-0); +} diff --git a/Client/src/Components/Icons/ComplexAlert/ComplexAlert.jsx b/Client/src/Components/Icons/ComplexAlert/ComplexAlert.jsx new file mode 100644 index 000000000..67af3ab88 --- /dev/null +++ b/Client/src/Components/Icons/ComplexAlert/ComplexAlert.jsx @@ -0,0 +1,36 @@ +import "./complexAlert.css"; +import React from "react"; +import ErrorOutlineIcon from "@mui/icons-material/ErrorOutline"; +import PropTypes from "prop-types"; + +/** + * @component + * @param {Object} props + * @param {"red" | "green"} props.theme - The color theme for the alert (required) - must be either "red" or "green" + * @returns {JSX.Element} - Renders the complex alert component with dynamic color theme + */ +const ComplexAlert = ({ theme }) => { + if (theme === "red") { + return ( +
+
+ +
+
+ ); + } else if (theme === "green") { + return ( +
+
+ +
+
+ ); + } +}; + +ComplexAlert.propTypes = { + theme: PropTypes.string.isRequired, +}; + +export default ComplexAlert; diff --git a/Client/src/Components/Icons/ComplexAlert/complexAlert.css b/Client/src/Components/Icons/ComplexAlert/complexAlert.css new file mode 100644 index 000000000..ab3cea714 --- /dev/null +++ b/Client/src/Components/Icons/ComplexAlert/complexAlert.css @@ -0,0 +1,44 @@ +.icon-holder-outer-red { + width: 38px; + height: 38px; + border-radius: 50%; + border: 2px solid #d92d2019; + display: flex; + justify-content: center; + align-items: center; +} + +.icon-holder-inner-red { + width: 28px; + height: 28px; + border-radius: 50%; + border: 2px solid #d92d204d; + display: flex; + justify-content: center; + align-items: center; +} + +.icon-holder-outer-green { + width: 38px; + height: 38px; + border-radius: 50%; + border: 2px solid #07945519; + display: flex; + justify-content: center; + align-items: center; +} + +.icon-holder-inner-green { + width: 28px; + height: 28px; + border-radius: 50%; + border: 2px solid #0794554d; + display: flex; + justify-content: center; + align-items: center; +} + +.icon-core { + width: 20px; + height: 20px; +} diff --git a/Client/src/Components/PopupModals/DualButtonPopupModal/DualButtonPopupModal.jsx b/Client/src/Components/PopupModals/DualButtonPopupModal/DualButtonPopupModal.jsx new file mode 100644 index 000000000..42a3f2a8a --- /dev/null +++ b/Client/src/Components/PopupModals/DualButtonPopupModal/DualButtonPopupModal.jsx @@ -0,0 +1,55 @@ +import "./dualButtonPopupModal.css"; +import React from "react"; +import PropTypes from "prop-types"; +import { useTheme } from "@mui/material"; + +/** + * @component + * @param {Object} props + * @param {boolean} [props.open=true] - Controls the visibility of the modal (defaults to true) + * @param {string} props.subject - The title text for the modal (required) + * @param {string} props.description - The description text for the modal (required) + * @param {string} props.esc - The text for the discard button (usually "Cancel", "Dismiss" or "Discard") (required) + * @param {string} props.save - The text for the save button (required) + * @returns {JSX.Element} - Renders the dual button popup modal component + */ +const DualButtonPopupModal = ({ + open = true, + subject, + description, + esc, + save, +}) => { + const theme = useTheme(); + + const fontLookup = { + default: theme.font.default.font, + }; + + const fontFamily = fontLookup["default"]; + + return ( +
+
{subject}
+
{description}
+
+
+ + +
+
+ ); +}; + +DualButtonPopupModal.propTypes = { + open: PropTypes.bool, + subject: PropTypes.string.isRequired, + description: PropTypes.string.isRequired, + esc: PropTypes.string.isRequired, + save: PropTypes.string.isRequired, +}; + +export default DualButtonPopupModal; diff --git a/Client/src/Components/PopupModals/DualButtonPopupModal/dualButtonPopupModal.css b/Client/src/Components/PopupModals/DualButtonPopupModal/dualButtonPopupModal.css new file mode 100644 index 000000000..92ac7f5d6 --- /dev/null +++ b/Client/src/Components/PopupModals/DualButtonPopupModal/dualButtonPopupModal.css @@ -0,0 +1,60 @@ +: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; + margin: 10px 20px; + 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; +} + +.dual-button-popup-modal-subject { + color: var(--popup-color-0); + font-weight: bolder; + font-size: 16px; +} + +.dual-button-popup-modal-description { + color: var(--popup-color-1); + font-size: 13px; + margin-top: 10px; +} + +.dual-modal-spacing { + height: 40px; +} + +.dual-button-popup-modal-controllers { + display: flex; + justify-content: end; +} + +.blue-save-button { + width: 145px; + height: 35px; + padding: 5px 20px; + background-color: var(--color-0); + border: 1px solid var(--color-1); + border-radius: 4px; + margin: 5px 0; + margin-left: 20px; + color: white; + cursor: pointer; + font-size: 13px; +} + +.transparent-discard-button { + border: none; + background-color: transparent; + margin: 5px 10px; + font-size: 13px; +} diff --git a/Client/src/Components/PopupModals/DualButtonPopupModalWithTextfields/DualButtonPopupModalWithTextfields.jsx b/Client/src/Components/PopupModals/DualButtonPopupModalWithTextfields/DualButtonPopupModalWithTextfields.jsx new file mode 100644 index 000000000..b8b424323 --- /dev/null +++ b/Client/src/Components/PopupModals/DualButtonPopupModalWithTextfields/DualButtonPopupModalWithTextfields.jsx @@ -0,0 +1,73 @@ +import "./dualButtonPopupModalWithTextfields.css"; +import React from "react"; +import CloseIcon from "@mui/icons-material/Close"; +import PropTypes from "prop-types"; +import { useTheme } from "@mui/material"; + +/** + * @component + * @param {Object} props + * @param {string} props.title - The title text for the modal (required) + * @returns {JSX.Element} - Renders a single text field component within a popup modal + */ +const PopupModalTextfield = ({ title }) => { + const theme = useTheme(); + + const fontLookup = { + default: theme.font.default.font, + }; + + const fontFamily = fontLookup["default"]; + + return ( +
+
{title}
+ +
+ ); +}; + +/** + * @component + * @param {Object} props + * @param {string} props.title - The title text for the modal (required) + * @param {string} props.esc - The text for the cancel button (required) + * @param {string} props.save - The text for the save button (required) + * @returns {JSX.Element} - Renders the dual button popup modal component with text fields + */ +const DualButtonPopupModalWithTextfields = ({ title, esc, save }) => { + const theme = useTheme(); + + const fontLookup = { + default: theme.font.default.font, + }; + + const fontFamily = fontLookup["default"]; + + return ( +
+
+
{title}
+
+ +
+
+
+ +
+
+
+ + +
+
+ ); +}; + +DualButtonPopupModalWithTextfields.propTypes = { + title: PropTypes.string.isRequired, + esc: PropTypes.string.isRequired, + save: PropTypes.string.isRequired, +}; + +export default DualButtonPopupModalWithTextfields; diff --git a/Client/src/Components/PopupModals/DualButtonPopupModalWithTextfields/dualButtonPopupModalWithTextfields.css b/Client/src/Components/PopupModals/DualButtonPopupModalWithTextfields/dualButtonPopupModalWithTextfields.css new file mode 100644 index 000000000..a1be3cd3a --- /dev/null +++ b/Client/src/Components/PopupModals/DualButtonPopupModalWithTextfields/dualButtonPopupModalWithTextfields.css @@ -0,0 +1,61 @@ +: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; + margin: 10px 20px; + border: 1px solid var(--popup-color-with-input-border-0); + box-shadow: 0px 8px 8px -4px rgba(16, 24, 40, 0.03), + 0px 20px 24px -4px rgba(16, 24, 40, 0.08); +} + +.popup-modal-header { + display: flex; + justify-content: space-between; + font-weight: bold; +} + +.popup-modal-close { + cursor: pointer; +} + +.spacing-height { + height: 30px; +} + +.popup-modal-input-title { + margin-bottom: 15px; + color: var(--popup-modal-with-input-title-color); +} + +.popup-modal-text-field { + width: 100%; + height: 35px; + border: 1px solid var(--popup-color-with-input-border-1); + border-radius: 4px; +} + +.popup-modal-controllers { + display: flex; + justify-content: end; +} + +.white-cancel-button { + border: none; + background-color: transparent; + font-family: var(--popup-font-family-0); + margin: 5px 10px; + width: 145px; + height: 35px; + padding: 5px 20px; + border: 1px solid var(--popup-color-with-input-border-1); + border-radius: 4px; + cursor: pointer; + font-size: 13px; +} diff --git a/Client/src/Components/TextFields/Description/DescriptionTextField.jsx b/Client/src/Components/TextFields/Description/DescriptionTextField.jsx new file mode 100644 index 000000000..7f3ba908a --- /dev/null +++ b/Client/src/Components/TextFields/Description/DescriptionTextField.jsx @@ -0,0 +1,47 @@ +import React from "react"; +import "./descriptionTextField.css"; +import { TextField } from "@mui/material"; +import PropTypes from "prop-types"; +import { useTheme } from "@mui/material"; + +/** + * @component + * @param {Object} props + * @param {string} props.hintText - The hint text displayed within the text field (required) + * @param {boolean} props.hasError - A flag indicating if the text field has an error (required) + * @returns {JSX.Element} - Renders the description text field component + */ +const DescriptionTextField = ({ hintText, hasError }) => { + const theme = useTheme(); + + const fontLookup = { + default: theme.font.default.font, + }; + + const fontFamily = fontLookup["default"]; + + return ( +
+
Description
+ +
+ ); +}; + +DescriptionTextField.propTypes = { + hintText: PropTypes.string.isRequired, + hasError: PropTypes.bool.isRequired, +}; + +export default DescriptionTextField; diff --git a/Client/src/Components/TextFields/Description/descriptionTextField.css b/Client/src/Components/TextFields/Description/descriptionTextField.css new file mode 100644 index 000000000..28616863e --- /dev/null +++ b/Client/src/Components/TextFields/Description/descriptionTextField.css @@ -0,0 +1,45 @@ +:root { + --color-title-1: #344054; + --text-field-margin-0: 10px 20px; + --description-color-0: #344054; +} + +.description-field-holder { + margin: var(--text-field-margin-0); + margin-top: 20px; +} + +.text-field-title { + color: var(--color-title-1); + font-weight: bold; + margin-bottom: 10px; + font-size: 13px; + color: var(--description-color-0); + font-weight: bold; +} + +.description-field-area { + min-width: 320px; + font-size: 13px; + border-radius: 8px; +} + +.description-field-label { + margin-top: 10px; + font-size: 11px; +} + +.with-error { + color: red; +} + +#description-field-area-helper-text { + margin-left: 0; + margin-top: 10px; + font-size: 11px; +} + +#description-field-area { + min-width: 320px; + font-size: 13px; +} diff --git a/Client/src/Components/TextFields/Email/EmailTextField.jsx b/Client/src/Components/TextFields/Email/EmailTextField.jsx new file mode 100644 index 000000000..b1428e1c5 --- /dev/null +++ b/Client/src/Components/TextFields/Email/EmailTextField.jsx @@ -0,0 +1,88 @@ +import React, { useState } from "react"; +import "./emailTextField.css"; +import { InputAdornment, TextField } from "@mui/material"; +import ErrorOutlineIcon from "@mui/icons-material/ErrorOutline"; +import HelpOutlineIcon from "@mui/icons-material/HelpOutline"; +import { useTheme } from "@mui/material"; + +/** + * @component + * @param {Object} props + * @param {string} props.id - Unique ID for the text field (optional) + * @param {string} props.label - The label text displayed above the text field (optional) + * @param {"standard" | "outlined" | "filled"} props.variant - The variant of the text field (e.g., "outlined") (optional) + * @param {string} props.placeholder - The placeholder text displayed within the text field (optional) + * @param {"error" | "help"} [props.icon] - The type of icon to display (error or help) (optional) + * @param {string} props.helperText - The helper text displayed below the text field (optional) + * @param {boolean} props.error - A flag indicating if the text field has an error (required) + * @returns {JSX.Element} - Renders the email text field component with dynamic icon display + */ +const EmailTextField = ({ + id, + label, + variant, + placeholder, + icon, + helperText, + error, +}) => { + const theme = useTheme(); + + const fontLookup = { + default: theme.font.default.font, + }; + + const fontFamily = fontLookup["default"]; + + const [showIcon, setShowIcon] = useState(false); + + const handleMouseEnter = () => setShowIcon(true); + const handleMouseLeave = () => setShowIcon(false); + + return ( +
+
Email
+
+ +
+ {error && showIcon && ( + + )} + {error && !showIcon && ( + + )} + {!error && showIcon && ( + + )} +
+ + ), + }} + helperText={helperText} + onMouseEnter={handleMouseEnter} + onMouseLeave={handleMouseLeave} + /> +
+
+ ); +}; + +export default EmailTextField; diff --git a/Client/src/Components/TextFields/Email/emailTextField.css b/Client/src/Components/TextFields/Email/emailTextField.css new file mode 100644 index 000000000..ff38a29df --- /dev/null +++ b/Client/src/Components/TextFields/Email/emailTextField.css @@ -0,0 +1,41 @@ +:root { + --textfield-color-0: #344054; +} + +.email-text-field { + position: relative; + margin: 10px 20px; +} + +#outlined-basic { + width: 320px; + height: 14px; + font-size: 13px; + padding: 8px 12px; +} + +.email-text-field-title { + margin: 0 20px; + margin-top: 30px; + font-size: 13px; + color: var(--textfield-color-0); + font-weight: bold; +} + +#outlined-basic-helper-text { + margin-left: 0; + margin-top: 10px; + font-size: 11px; +} + +.text-field-icon { + width: 16px; + height: 16px; +} + +.icon-holder { + width: 16px; + height: 16px; + padding: 0; + margin: 0; +} diff --git a/Client/src/Components/TextFields/Website/WebsiteTextField.jsx b/Client/src/Components/TextFields/Website/WebsiteTextField.jsx new file mode 100644 index 000000000..d18e33dd9 --- /dev/null +++ b/Client/src/Components/TextFields/Website/WebsiteTextField.jsx @@ -0,0 +1,72 @@ +import React, { useState } from "react"; +import "./websiteTextField.css"; +import HelpOutlineIcon from "@mui/icons-material/HelpOutline"; +import ContentCopyIcon from "@mui/icons-material/ContentCopy"; +import { useTheme } from "@mui/material"; + +/** + * @component + * @param {Object} props + * @param {boolean} [props.showHelp=true] - Controls the visibility of the help icon (defaults to true) + * @param {boolean} [props.hasCopyButton=false] - Controls the visibility of the copy button (defaults to false) + * @param {string} props.hintText - The hint text displayed below the text field (required) + * @returns {JSX.Element} - Renders the website text field component with optional help and copy features + */ +const WebsiteTextField = ({ + showHelp = true, + hasCopyButton = false, + hintText, +}) => { + const theme = useTheme(); + + const fontLookup = { + default: theme.font.default.font, + }; + + const fontFamily = fontLookup["default"]; + + const [copied, setCopied] = useState(false); + + const handleCopy = () => { + setCopied(true); + setTimeout(() => setCopied(false), 1000); + }; + + return ( +
+
Website
+
+ + + {showHelp && ( +
+ +
+ )} + {hasCopyButton && ( +
+ + {copied ? " Copied " : " Copy "} +
+ )} +
+ +
+ ); +}; + +export default WebsiteTextField; diff --git a/Client/src/Components/TextFields/Website/websiteTextField.css b/Client/src/Components/TextFields/Website/websiteTextField.css new file mode 100644 index 000000000..66cdf4fa4 --- /dev/null +++ b/Client/src/Components/TextFields/Website/websiteTextField.css @@ -0,0 +1,82 @@ +: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; +} + +.website-textfield-title { + margin: 0 20px; + margin-top: 30px; + font-size: 13px; + color: var(--website-color-0); + font-weight: bold; +} + +.website-textfield { + display: flex; + align-items: center; + position: relative; + margin: var(--text-field-margin-1); +} + +.website-textfield-hint { + margin: var(--text-field-margin-0); + font-size: 11px; +} + +.website-label { + padding: 6px 20px 6px 10px; + border: solid 1px var(--border-color); + border-right: none; + border-radius: 4px 0 0 4px; + font-size: 13px; + text-align: center; + display: flex; + justify-content: center; + align-items: center; + color: var(--label-font-color); +} + +.website-url { + width: 248px; + height: 31.5px; + padding: 0px 15px; + border: solid 1px var(--border-color); +} + +.website-icon-holder { + width: 40px; + height: 33px; + padding: 5px; + border: solid 1px var(--border-color); + border-left: none; + text-align: center; + display: flex; + justify-content: center; + align-items: center; +} + +.copy-to-clipboard-button { + padding: 5.5px 20px 6px 10px; + border: solid 1px var(--border-color); + border-left: none; + border-radius: 0 8px 8px 0; + font-size: 13px; + text-align: center; + display: flex; + justify-content: space-evenly; + align-items: center; + color: var(--label-font-color); + cursor: pointer; +} + +.copy-icon { + margin-right: 5px; +} + +.with-no-copy-button { + display: none; +} diff --git a/Client/src/Components/Tooltips/TooltipWithTail/tooltipWithTail.css b/Client/src/Components/Tooltips/TooltipWithTail/tooltipWithTail.css new file mode 100644 index 000000000..1b1adf507 --- /dev/null +++ b/Client/src/Components/Tooltips/TooltipWithTail/tooltipWithTail.css @@ -0,0 +1,17 @@ +:root { + --tooltip-color-0: #d0d5dd; + --tooltip-margin: 5px; + --tooltip-font-size: 12px; +} + +.tooltip-title { + font-size: var(--tooltip-font-size); + font-weight: bold; + margin: var(--tooltip-margin); +} + +.tooltip-description { + font-size: var(--tooltip-font-size); + color: var(--tooltip-color-0); + margin: var(--tooltip-margin); +}