diff --git a/client-side/package-lock.json b/client-side/package-lock.json index 58199e400..a8452a08b 100644 --- a/client-side/package-lock.json +++ b/client-side/package-lock.json @@ -11,6 +11,7 @@ "@emotion/react": "^11.11.4", "@emotion/styled": "^11.11.5", "@fontsource/roboto": "^5.0.13", + "@mui/base": "^5.0.0-beta.40", "@mui/icons-material": "^5.16.0", "@mui/material": "^5.16.0", "@mui/styled-engine-sc": "^6.0.0-alpha.18", @@ -28,6 +29,7 @@ "jest": "^29.7.0", "jspdf": "^2.5.1", "jspdf-autotable": "^3.8.2", + "mongodb": "^6.8.0", "react": "^18.3.1", "react-dom": "^18.3.1", "react-google-recaptcha": "^3.1.0", @@ -4843,6 +4845,15 @@ "react": ">=16" } }, + "node_modules/@mongodb-js/saslprep": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.1.8.tgz", + "integrity": "sha512-qKwC/M/nNNaKUBMQ0nuzm47b7ZYWQHN3pcXq4IIcoSBc2hOIrflAxJduIvvqmhoz3gR2TacTAs8vlsCVPkiEdQ==", + "license": "MIT", + "dependencies": { + "sparse-bitfield": "^3.0.3" + } + }, "node_modules/@mui/base": { "version": "5.0.0-beta.40", "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-beta.40.tgz", @@ -9504,6 +9515,21 @@ "integrity": "sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA==", "dev": true }, + "node_modules/@types/webidl-conversions": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.3.tgz", + "integrity": "sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==", + "license": "MIT" + }, + "node_modules/@types/whatwg-url": { + "version": "11.0.5", + "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-11.0.5.tgz", + "integrity": "sha512-coYR071JRaHa+xoEvvYqvnIHaVqaYrLPbsufM9BF63HkwI5Lgmy2QR8Q5K/lYDYo5AK82wOvSOS0UsLTpTG7uQ==", + "license": "MIT", + "dependencies": { + "@types/webidl-conversions": "*" + } + }, "node_modules/@types/ws": { "version": "8.5.10", "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.10.tgz", @@ -11350,6 +11376,15 @@ "node-int64": "^0.4.0" } }, + "node_modules/bson": { + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/bson/-/bson-6.8.0.tgz", + "integrity": "sha512-iOJg8pr7wq2tg/zSlCCHMi3hMm5JTOxLTagf3zxhcenHsFp+c6uOs6K7W5UE7A4QIJGtqh/ZovFNMP4mOPJynQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=16.20.1" + } + }, "node_modules/btoa": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/btoa/-/btoa-1.2.1.tgz", @@ -22031,6 +22066,12 @@ "map-or-similar": "^1.5.0" } }, + "node_modules/memory-pager": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz", + "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==", + "license": "MIT" + }, "node_modules/merge-descriptors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", @@ -22235,6 +22276,96 @@ "ufo": "^1.5.3" } }, + "node_modules/mongodb": { + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.8.0.tgz", + "integrity": "sha512-HGQ9NWDle5WvwMnrvUxsFYPd3JEbqD3RgABHBQRuoCEND0qzhsd0iH5ypHsf1eJ+sXmvmyKpP+FLOKY8Il7jMw==", + "license": "Apache-2.0", + "dependencies": { + "@mongodb-js/saslprep": "^1.1.5", + "bson": "^6.7.0", + "mongodb-connection-string-url": "^3.0.0" + }, + "engines": { + "node": ">=16.20.1" + }, + "peerDependencies": { + "@aws-sdk/credential-providers": "^3.188.0", + "@mongodb-js/zstd": "^1.1.0", + "gcp-metadata": "^5.2.0", + "kerberos": "^2.0.1", + "mongodb-client-encryption": ">=6.0.0 <7", + "snappy": "^7.2.2", + "socks": "^2.7.1" + }, + "peerDependenciesMeta": { + "@aws-sdk/credential-providers": { + "optional": true + }, + "@mongodb-js/zstd": { + "optional": true + }, + "gcp-metadata": { + "optional": true + }, + "kerberos": { + "optional": true + }, + "mongodb-client-encryption": { + "optional": true + }, + "snappy": { + "optional": true + }, + "socks": { + "optional": true + } + } + }, + "node_modules/mongodb-connection-string-url": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-3.0.1.tgz", + "integrity": "sha512-XqMGwRX0Lgn05TDB4PyG2h2kKO/FfWJyCzYQbIhXUxz7ETt0I/FqHjUeqj37irJ+Dl1ZtU82uYyj14u2XsZKfg==", + "license": "Apache-2.0", + "dependencies": { + "@types/whatwg-url": "^11.0.2", + "whatwg-url": "^13.0.0" + } + }, + "node_modules/mongodb-connection-string-url/node_modules/tr46": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-4.1.1.tgz", + "integrity": "sha512-2lv/66T7e5yNyhAAC4NaKe5nVavzuGJQVVtRYLyQ2OI8tsJ61PMLlelehb0wi2Hx6+hT/OJUWZcw8MjlSRnxvw==", + "license": "MIT", + "dependencies": { + "punycode": "^2.3.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/mongodb-connection-string-url/node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + } + }, + "node_modules/mongodb-connection-string-url/node_modules/whatwg-url": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-13.0.0.tgz", + "integrity": "sha512-9WWbymnqj57+XEuqADHrCJ2eSXzn8WXIW/YSGaZtb2WKAInQ6CHfaUUcTyyver0p8BDg5StLQq8h1vtZuwmOig==", + "license": "MIT", + "dependencies": { + "tr46": "^4.1.1", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=16" + } + }, "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -24895,7 +25026,6 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "dev": true, "engines": { "node": ">=6" } @@ -28032,6 +28162,15 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/sparse-bitfield": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", + "integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==", + "license": "MIT", + "dependencies": { + "memory-pager": "^1.0.2" + } + }, "node_modules/spdx-correct": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", diff --git a/client-side/package.json b/client-side/package.json index c4ea39a4b..20398b777 100644 --- a/client-side/package.json +++ b/client-side/package.json @@ -6,6 +6,7 @@ "@emotion/react": "^11.11.4", "@emotion/styled": "^11.11.5", "@fontsource/roboto": "^5.0.13", + "@mui/base": "^5.0.0-beta.40", "@mui/icons-material": "^5.16.0", "@mui/material": "^5.16.0", "@mui/styled-engine-sc": "^6.0.0-alpha.18", @@ -24,6 +25,7 @@ "html2pdf.js": "^0.10.2", "jspdf": "^2.5.1", "jspdf-autotable": "^3.8.2", + "mongodb": "^6.8.0", "react": "^18.3.1", "react-dom": "^18.3.1", "react-google-recaptcha": "^3.1.0", diff --git a/client-side/src/stories/GenericInput/genericInput.jsx b/client-side/src/stories/GenericInput/genericInput.jsx index bf2525546..988fa9aeb 100644 --- a/client-side/src/stories/GenericInput/genericInput.jsx +++ b/client-side/src/stories/GenericInput/genericInput.jsx @@ -2,7 +2,7 @@ import React, { useState, useEffect } from 'react'; import PropTypes from 'prop-types'; import { INVALID_INPUT_MESSAGE } from './constants'; import { TextField, InputAdornment } from '@mui/material'; -import '../GenericInput/genericInput.scss'; +//import '../GenericInput/genericInput.scss'; const GenericInput = ({ label, diff --git a/client-side/src/stories/GenericInput/genericInput.scss b/client-side/src/stories/GenericInput/genericInput.scss index ee3d4f636..92174b69e 100644 --- a/client-side/src/stories/GenericInput/genericInput.scss +++ b/client-side/src/stories/GenericInput/genericInput.scss @@ -1,5 +1,5 @@ @import url('https://fonts.googleapis.com/css2?family=Montserrat:wght@400;700&display=swap'); -@import './style.scss'; +@import '../variables.scss'; .generic-input { .MuiOutlinedInput-root { diff --git a/client-side/src/stories/genericInput.jsx b/client-side/src/stories/genericInput.jsx deleted file mode 100644 index 278b1e33d..000000000 --- a/client-side/src/stories/genericInput.jsx +++ /dev/null @@ -1,86 +0,0 @@ -import React, { useState, useEffect } from 'react'; -import PropTypes from 'prop-types'; -import { TextField, InputAdornment } from '@mui/material'; -import '../style/genericInput.scss'; - -const GenericInput = ({ - label, - type = 'text', - value = '', - onChange = () => {}, - size = 'medium', - width = '20%', - icon: Icon=null, - disabled= false, - validation = () => {}, - ...rest -}) => { - const [inputValue, setInputValue] = useState(value); - const [error, setError] = useState(false); - const [helperText, setHelperText] = useState(''); - - useEffect(() => { - if (validation && typeof validation === 'function') { - handleValidation(inputValue); - } - }, [inputValue]); - - const handleChange = (e) => { - const newValue = e.target.value; - setInputValue(newValue); - onChange(newValue); - }; - - const handleValidation = (inputValue) => { - const validationResult = validation(inputValue); - if (validationResult && validationResult.error) { - setError(true); - setHelperText(validationResult.helperText || 'Invalid input'); - } else { - setError(false); - setHelperText(''); - } - }; - - const inputStyle = { - width, - }; - - return ( -
- - - - ), - ...rest.InputProps, - }} - style={inputStyle} - {...rest} - /> -
- ); -}; - -GenericInput.propTypes = { - label: PropTypes.string.isRequired, - type: PropTypes.oneOf(['text', 'number', 'email', 'password']), - value: PropTypes.string, - onChange: PropTypes.func, - size: PropTypes.oneOf(['small', 'medium']), - width: PropTypes.string, - icon: PropTypes.elementType, - validation: PropTypes.func, -}; - -export default GenericInput; diff --git a/client-side/src/stories/genericInput.scss b/client-side/src/stories/genericInput.scss deleted file mode 100644 index 2dcefb748..000000000 --- a/client-side/src/stories/genericInput.scss +++ /dev/null @@ -1,78 +0,0 @@ -@import url('https://fonts.googleapis.com/css2?family=Montserrat:wght@400;700&display=swap'); - -$color-border: rgb(61, 192, 155); -$color-border-hover: rgb(45, 158, 126); -$color-error: red; -$color-black: black; - -.generic-input { - .MuiOutlinedInput-root { - border-radius: 8px; - transition: border-color 0.3s ease, box-shadow 0.3s ease; - border-color: $color-border; - border-width: 1px; - width: 100%; - - &:hover { - border-color: $color-border-hover; - box-shadow: 0 0 5px rgba($color-border, 0.5); - } - - &.Mui-focused fieldset { - border-color: $color-border-hover; - box-shadow: 0 0 8px rgba($color-border, 0.8); - } - - &:not(.Mui-error) fieldset { - border-color: $color-border; - } - - &.Mui-disabled { - opacity: 0.7; - cursor: not-allowed; - - input { - color: rgba($color-black, 0.7); - pointer-events: none; - } - } - - input { - color: $color-black; - font-family: 'Montserrat', sans-serif; - font-weight: 400; - font-size: 14px; - transition: color 0.3s ease; - } - - &.Mui-error { - border-color: $color-error; - } - } - - .MuiFormLabel-root { - color: $color-black; - font-family: 'Montserrat', sans-serif; - font-weight: 400; - font-size: 16px; - transition: color 0.3s ease; - - &.Mui-focused { - color: $color-border-hover; - } - } - - .MuiFormHelperText-root { - color: $color-black; - font-family: 'Montserrat', sans-serif; - font-weight: 400; - font-size: 12px; - transition: color 0.3s ease; - - &.Mui-error { - color: $color-error; - } - } -} - - diff --git a/client-side/src/stories/genericInput.stories.js b/client-side/src/stories/genericInput.stories.js deleted file mode 100644 index 308b466c4..000000000 --- a/client-side/src/stories/genericInput.stories.js +++ /dev/null @@ -1,91 +0,0 @@ - -import React from 'react'; -import GenericInput from '../inputs/genericInput'; -import PersonIcon from '@mui/icons-material/Person'; - -export default { - title: 'Components/StyledInput', - component: GenericInput, - argTypes: { - size: { - control: { - type: 'select', - options: ['small', 'medium'], - }, - width: { - control: 'text', - description: 'Width of the input, e.g. 100%, 50%, 300px' - }, - - }, - }, -}; - -const Template = (args) => ; - -export const Default = Template.bind({}); -Default.args = { - label: 'Enter your details', - type: 'text', -}; - -export const InputWithPlaceholder = Template.bind({}); -InputWithPlaceholder.args = { - type: 'text', - label:'this is lable', - placeholder: 'This is Placeholder', -}; - -export const InputWithError = Template.bind({}); -InputWithError.args = { - label: 'Enter your details', - type: 'text', - helperText: 'Error message', - error: true, -}; - -export const EmailInput = Template.bind({}); -EmailInput.args = { - label:'email input', - type: 'email', - placeholder: 'example@example.com', - -}; - -export const InputWithIcon = Template.bind({}); -InputWithIcon.args = { - label: 'input with icon', - icon:PersonIcon, -}; - -export const NumberInput = Template.bind({}); -NumberInput.args = { - label: 'Choose number', - type: 'number', - size: 'small', - -}; - -export const DisabledInput = Template.bind({}); -DisabledInput.args = { - label: 'Disabled Input', - type: 'text', - disabled: true, - width:'300px', -}; - -export const TimeInput = Template.bind({}); -TimeInput.args = { - label:'', - type: 'time', - size:'medium', - width:'50%', -}; - -export const PasswordInput = Template.bind({}); -PasswordInput.args = { - label: 'Enter password', - type: 'password', - -}; - diff --git a/client-side/src/stories/header/header.scss b/client-side/src/stories/header/header.scss index 0cbaf297b..cee00a620 100644 --- a/client-side/src/stories/header/header.scss +++ b/client-side/src/stories/header/header.scss @@ -1,6 +1,5 @@ @import '../variables.scss'; -.arooundDiv{ - .navbar{ +.navbar{ background-color: $primary-color ; color: $secondary-color ; } @@ -31,4 +30,3 @@ display: flex; } } -} \ No newline at end of file diff --git a/client-side/src/stories/popup/MessageStatusUpdater.scss b/client-side/src/stories/popup/MessageStatusUpdater.scss new file mode 100644 index 000000000..1dce43ae8 --- /dev/null +++ b/client-side/src/stories/popup/MessageStatusUpdater.scss @@ -0,0 +1,15 @@ +// MessageStatusUpdater.scss + +.message-status-updater { + .icon-button { + color: black; + + &.read { + color: rgb(103, 252, 210); + } + + &.unread { + color: rgb(103, 252, 210); + } + } +} diff --git a/client-side/src/stories/popup/changeStatusAllMessage.jsx b/client-side/src/stories/popup/changeStatusAllMessage.jsx new file mode 100644 index 000000000..31402f97a --- /dev/null +++ b/client-side/src/stories/popup/changeStatusAllMessage.jsx @@ -0,0 +1,45 @@ +import React, { useState } from 'react'; +import { IconButton, Tooltip } from '@mui/material'; +import { CheckCircleOutline, RadioButtonUnchecked } from '@mui/icons-material'; +import './MessageStatusUpdater.scss'; + +const MessageStatusUpdater = () => { + const [hoveredIcon, setHoveredIcon] = useState(null); + + const handleUpdateStatus = async (readStatus) => { + for (const message of messages) { + try { + await update(message.id, readStatus); + } catch (error) { + console.error(`Error updating message with id ${message.id}:`, error); + } + } + }; + + return ( +
+ + handleUpdateStatus(true)} + onMouseEnter={() => setHoveredIcon('read')} + onMouseLeave={() => setHoveredIcon(null)} + > + + + + + handleUpdateStatus(false)} + onMouseEnter={() => setHoveredIcon('unread')} + onMouseLeave={() => setHoveredIcon(null)} + > + + + +
+ ); +}; + +export default MessageStatusUpdater; diff --git a/client-side/src/stories/popup/popup.jsx b/client-side/src/stories/popup/popup.jsx new file mode 100644 index 000000000..c84bd1931 --- /dev/null +++ b/client-side/src/stories/popup/popup.jsx @@ -0,0 +1,28 @@ +import * as React from 'react'; +import { Unstable_Popup as BasePopup } from '@mui/base/Unstable_Popup'; +import GenericButton from '../Button/GenericButton'; +import './popup.scss'; + +export default function SimplePopup({message='',labelButtonOutThePopup='open message',iconInButton,labelButtonInThePopup='delete message',onClick}) { + const [anchor, setAnchor] = React.useState(null); + + const handleClick = (event) => { + setAnchor(anchor ? null : event.currentTarget); + }; + + const open = Boolean(anchor); + const id = open ? 'simple-popup' : undefined; + + return ( +
+ + +
+
{message}
+ +
+
+
+ ); +} + diff --git a/client-side/src/stories/popup/popup.stories.js b/client-side/src/stories/popup/popup.stories.js new file mode 100644 index 000000000..0a7842145 --- /dev/null +++ b/client-side/src/stories/popup/popup.stories.js @@ -0,0 +1,24 @@ +import React from "react"; + +import SimplePopup from "./popup.jsx"; + + +export default{ + title: 'popup', + component: SimplePopup, +}; + + + +const Template = (args) => ; + +export const Primary = Template.bind({}); +Primary.args ={ + message:'', + labelButtonOutThePopup:'open message', + iconInButton, + labelButtonInThePopup:'delete message', + onClick +} + +