From fd59e50a9daa94dc3165d74bf48393d3d6bb95e8 Mon Sep 17 00:00:00 2001 From: Aiga115 Date: Tue, 27 May 2025 11:02:17 +0200 Subject: [PATCH 1/9] ILEX-114 add account settings dialog --- .../Dashboard/User/AccountSettingsDialog.jsx | 91 +++++++++ .../Dashboard/User/PasswordField.jsx | 41 ++++ src/components/Dashboard/User/index.jsx | 180 +++++++++++++++++- .../SingleOrganization/CreateForkDialog.jsx | 4 +- src/components/common/ActionInput.jsx | 66 +++++++ src/theme/index.jsx | 37 ++++ src/theme/variables.js | 3 +- 7 files changed, 415 insertions(+), 7 deletions(-) create mode 100644 src/components/Dashboard/User/AccountSettingsDialog.jsx create mode 100644 src/components/Dashboard/User/PasswordField.jsx create mode 100644 src/components/common/ActionInput.jsx diff --git a/src/components/Dashboard/User/AccountSettingsDialog.jsx b/src/components/Dashboard/User/AccountSettingsDialog.jsx new file mode 100644 index 00000000..022d1968 --- /dev/null +++ b/src/components/Dashboard/User/AccountSettingsDialog.jsx @@ -0,0 +1,91 @@ +import PropTypes from "prop-types"; +import Dialog from "@mui/material/Dialog"; +import IconButton from "@mui/material/IconButton"; +import CloseIcon from "@mui/icons-material/Close"; +import Typography from "@mui/material/Typography"; +import { Box, Divider, Button } from "@mui/material"; +import DialogContent from "@mui/material/DialogContent"; + +import { vars } from "../../../theme/variables"; +const { gray600, gray200 } = vars; + +const HeaderRightSideContent = ({ handleClose, handleSubmit }) => { + return ( + + + + + ); +}; + +HeaderRightSideContent.propTypes = { + handleClose: PropTypes.func.isRequired, + handleSubmit: PropTypes.func.isRequired, +}; + +const AccountSettingsDialog = ({ + children, + title, + open, + handleClose, + sx, +}) => { + return ( + + + + + + + + + {title} + + + + + + {children} + + + ); +}; + +AccountSettingsDialog.propTypes = { + children: PropTypes.node.isRequired, + title: PropTypes.string.isRequired, + open: PropTypes.bool.isRequired, + handleClose: PropTypes.func.isRequired, + // HeaderRightSideContent: PropTypes.node, + sx: PropTypes.object, +}; + +export default AccountSettingsDialog; diff --git a/src/components/Dashboard/User/PasswordField.jsx b/src/components/Dashboard/User/PasswordField.jsx new file mode 100644 index 00000000..e830b5d2 --- /dev/null +++ b/src/components/Dashboard/User/PasswordField.jsx @@ -0,0 +1,41 @@ +import { useState } from "react"; +import { Button } from "@mui/material"; +import ActionInput from "../../common/ActionInput"; +import { VisibilityOutlinedIcon, VisibilityOffOutlinedIcon } from "@mui/icons-material" +import PropTypes from "prop-types"; + +const PasswordField = ({ value, name, placeholder, handleChange }) => { + const [showPassword, setShowPassword] = useState(false) + + return ( + setShowPassword(!showPassword)} + startIcon={showPassword ? : } + > + {showPassword ? "Show" : "Hide"} + + } + type={showPassword ? "text" : "password"} + name={name} + value={value} + onChange={handleChange} + /> + ) +} + +PasswordField.propTypes = { + placeholder: PropTypes.string, + name: PropTypes.string.isRequired, + value: PropTypes.string.isRequired, + handleChange: PropTypes.func.isRequired +}; + +PasswordField.defaultProps = { + placeholder: "", +}; + + +export default PasswordField; \ No newline at end of file diff --git a/src/components/Dashboard/User/index.jsx b/src/components/Dashboard/User/index.jsx index 721e41a6..fd0e4d7b 100644 --- a/src/components/Dashboard/User/index.jsx +++ b/src/components/Dashboard/User/index.jsx @@ -1,12 +1,17 @@ -import {Box, Button, Chip, Grid, Stack, Typography} from "@mui/material"; +import { useState } from "react"; +import { Avatar, Box, Button, Chip, Grid, Stack, Typography, Divider, TextField, InputAdornment, IconButton } from "@mui/material"; import { vars } from "../../../theme/variables"; import CustomBreadcrumbs from "../../common/CustomBreadcrumbs"; import HomeOutlinedIcon from "@mui/icons-material/HomeOutlined"; import { SettingsOutlined } from "@mui/icons-material"; -import {GlobalDataContext} from "../../../contexts/DataContext"; +import { GlobalDataContext } from "../../../contexts/DataContext"; import { useContext } from "react"; +import AccountSettingsDialog from "./AccountSettingsDialog"; +import PersonOutlineIcon from '@mui/icons-material/PersonOutline'; +import ModeEditOutlineOutlinedIcon from "@mui/icons-material/ModeEditOutlineOutlined"; +import PasswordField from "./PasswordField"; -const { gray25, gray600, gray800, gray500 } = vars; +const { gray25, gray600, gray800, gray500, gray700 } = vars; const breadcrumbItems = [ { label: '', href: '/', icon: HomeOutlinedIcon }, @@ -14,7 +19,44 @@ const breadcrumbItems = [ ]; const User = () => { - const {user} = useContext(GlobalDataContext) + const { user } = useContext(GlobalDataContext) + const [open, setOpen] = useState(false); + const [showCurrentPassword, setShowCurrentPassword] = useState(false) + const [showNewPassword, setShowNewPassword] = useState(false) + const [showConfirmPassword, setShowConfirmPassword] = useState(false) + + const [formData, setFormData] = useState({ + email: "user@example.com", + currentPassword: "", + newPassword: "", + confirmPassword: "", + }) + + const handleInputChange = (field, value) => { + setFormData((prev) => ({ + ...prev, + [field]: value, + })) + } + + const handleSubmit = (e) => { + e.preventDefault() + console.log("Form submitted:", formData) + } + + const togglePasswordVisibility = (field) => { + switch (field) { + case "current": + setShowCurrentPassword(!showCurrentPassword) + break + case "new": + setShowNewPassword(!showNewPassword) + break + case "confirm": + setShowConfirmPassword(!showConfirmPassword) + break + } + } return ( { @@ -69,6 +112,135 @@ const User = () => { + setOpen(false)} + > + <> + + + + + + Aigul + aigul@metacell.us + + + + + + + + + Email + + handleInputChange("email", e.target.value)} + disabled + size="small" + sx={{ mt: 1 }} + /> + + Email address can't be changed from the interface. Please contact us to make this change. + + + + + + + + Current Password + + handleInputChange("currentPassword", e.target.value)} + placeholder="Enter your current password" + /> + + + + + + + Enter New Password + + handleInputChange("newPassword", e.target.value)} + placeholder="Enter new password" + variant="outlined" + sx={{ mt: 1 }} + // InputProps={{ + // endAdornment: ( + // + // togglePasswordVisibility("new")} + // edge="end" + // aria-label="toggle password visibility" + // > + // {showNewPassword ? : } + // + // + // ), + // }} + /> + + + + + + + Confirm New Password + + handleInputChange("confirmPassword", e.target.value)} + placeholder="Confirm new password" + variant="outlined" + sx={{ mt: 1 }} + // InputProps={{ + // endAdornment: ( + // + // togglePasswordVisibility("confirm")} + // edge="end" + // aria-label="toggle password visibility" + // > + // {showConfirmPassword ? : } + // + // + // ), + // }} + /> + + + + + + + + + + + + ); }; diff --git a/src/components/SingleOrganization/CreateForkDialog.jsx b/src/components/SingleOrganization/CreateForkDialog.jsx index 0e879396..19bfe75a 100644 --- a/src/components/SingleOrganization/CreateForkDialog.jsx +++ b/src/components/SingleOrganization/CreateForkDialog.jsx @@ -108,7 +108,7 @@ const CreateForkDialog = ({ open, handleClose, onSubmit }) => { > - Add a fork + Add a fork { - To the organization + To the organization { + return ( + + + + + + + {actionButton} + + ); +} + +ActionInput.propTypes = { + placeholder: PropTypes.string, + name: PropTypes.string.isRequired, + value: PropTypes.string.isRequired, + onChange: PropTypes.func.isRequired, + type: PropTypes.string, + actionButton: PropTypes.node +}; + +ActionInput.defaultProps = { + placeholder: "", +}; + + +export default ActionInput \ No newline at end of file diff --git a/src/theme/index.jsx b/src/theme/index.jsx index b166478a..647b95d3 100644 --- a/src/theme/index.jsx +++ b/src/theme/index.jsx @@ -113,6 +113,21 @@ const theme = createTheme({ } `, }, + MuiTypography: { + styleOverrides: { + h6: { + fontSize: '1.125rem', + fontWeight: 600 + } + } + }, + MuiDivider: { + styleOverrides: { + root: { + borderColor: gray200 + } + } + }, MuiRichTreeView: { styleOverrides: { backgroundColor: "red", @@ -197,6 +212,7 @@ const theme = createTheme({ MuiOutlinedInput: { styleOverrides: { root: { + borderRadius: "0.5rem", "& .MuiOutlinedInput-notchedOutline": { borderColor: gray200, }, @@ -221,10 +237,24 @@ const theme = createTheme({ color: error500 } }, + '&.Mui-disabled': { + background: gray50, + WebkitTextFillColor: `${gray500} !important` + } + }, + sizeSmall: { + padding: '0.5rem 0.75rem', + '& input': { padding: 0 } } }, }, + MuiTextField: { + styleOverrides: { + + } + }, + MuiContainer: { styleOverrides: { maxWidthXl: { @@ -1038,6 +1068,13 @@ const theme = createTheme({ }, }, }, + MuiSvgIcon: { + styleOverrides: { + fontSizeLarge: { + fontSize: '2rem' + } + } + } }, }); diff --git a/src/theme/variables.js b/src/theme/variables.js index 648a1927..35720016 100644 --- a/src/theme/variables.js +++ b/src/theme/variables.js @@ -73,5 +73,6 @@ export const vars = { success900: '#074D31', success950: '#053321', paperShadow: '0px 12px 16px -4px rgba(16, 24, 40, 0.08), 0px 4px 6px -2px rgba(16, 24, 40, 0.03)', - errorInputBoxShadow: '0px 1px 2px 0px rgba(16, 24, 40, 0.05), 0px 0px 0px 4px rgba(240, 68, 56, 0.24)' + errorInputBoxShadow: '0px 1px 2px 0px rgba(16, 24, 40, 0.05), 0px 0px 0px 4px rgba(240, 68, 56, 0.24)', + inputBoxShadow: '0px 1px 2px 0px rgba(16, 24, 40, 0.05)' } \ No newline at end of file From d365eadb260e29cebe1939342b55dfdc12a58d77 Mon Sep 17 00:00:00 2001 From: Aiga115 Date: Tue, 27 May 2025 14:50:39 +0200 Subject: [PATCH 2/9] ILEX-114 fix placement and styling --- .../Dashboard/User/AccountSettingsDialog.jsx | 150 +++++++++++++-- .../Dashboard/User/PasswordField.jsx | 23 +-- src/components/Dashboard/User/index.jsx | 173 +----------------- src/components/common/ActionInput.jsx | 40 ++-- 4 files changed, 174 insertions(+), 212 deletions(-) diff --git a/src/components/Dashboard/User/AccountSettingsDialog.jsx b/src/components/Dashboard/User/AccountSettingsDialog.jsx index 022d1968..eadb02ea 100644 --- a/src/components/Dashboard/User/AccountSettingsDialog.jsx +++ b/src/components/Dashboard/User/AccountSettingsDialog.jsx @@ -1,19 +1,20 @@ import PropTypes from "prop-types"; -import Dialog from "@mui/material/Dialog"; +import { useState } from "react"; +import { Dialog, Box, Divider, Button, DialogContent, Typography, Avatar, Stack, Grid, TextField } from "@mui/material"; import IconButton from "@mui/material/IconButton"; import CloseIcon from "@mui/icons-material/Close"; -import Typography from "@mui/material/Typography"; -import { Box, Divider, Button } from "@mui/material"; -import DialogContent from "@mui/material/DialogContent"; +import PasswordField from "./PasswordField"; +import PersonOutlineIcon from '@mui/icons-material/PersonOutline'; +import ModeEditOutlineOutlinedIcon from "@mui/icons-material/ModeEditOutlineOutlined"; import { vars } from "../../../theme/variables"; -const { gray600, gray200 } = vars; +const { gray600, gray200, gray700 } = vars; const HeaderRightSideContent = ({ handleClose, handleSubmit }) => { return ( - @@ -26,18 +27,43 @@ HeaderRightSideContent.propTypes = { }; const AccountSettingsDialog = ({ - children, - title, + user, open, - handleClose, - sx, + handleClose }) => { + const [showPasswordField, setShowPasswordField] = useState(false); + + const [formData, setFormData] = useState({ + email: user?.email, + currentPassword: "", + newPassword: "", + confirmPassword: "", + }) + + const handleInputChange = (field, value) => { + setFormData((prev) => ({ + ...prev, + [field]: value, + })) + } + + const handleSubmit = (e) => { + e.preventDefault() + console.log("Form submitted:", formData) + } + + const userGroupname = user?.groupname.charAt(0).toUpperCase() + user?.groupname.slice(1) + return ( - {title} + Account settings - + - {children} + + + + + + {userGroupname} + {user?.email} + + + + + + + + + Email + + handleInputChange("email", e.target.value)} + disabled + size="small" + /> + + Email address can't be changed from the interface. Please contact us to make this change. + + + + + {showPasswordField && ( + <> + + + + Current Password + + handleInputChange("currentPassword", e.target.value)} + placeholder="Enter your current password" + /> + + + + + + + Enter New Password + + handleInputChange("newPassword", e.target.value)} + placeholder="Enter new password" + /> + + + + + + + Confirm New Password + + handleInputChange("confirmPassword", e.target.value)} + placeholder="Confirm new password" + /> + + + + )} + + + + + + + + ); }; AccountSettingsDialog.propTypes = { - children: PropTypes.node.isRequired, - title: PropTypes.string.isRequired, + user: PropTypes.object.isRequired, open: PropTypes.bool.isRequired, handleClose: PropTypes.func.isRequired, - // HeaderRightSideContent: PropTypes.node, - sx: PropTypes.object, }; export default AccountSettingsDialog; diff --git a/src/components/Dashboard/User/PasswordField.jsx b/src/components/Dashboard/User/PasswordField.jsx index e830b5d2..8e93c94d 100644 --- a/src/components/Dashboard/User/PasswordField.jsx +++ b/src/components/Dashboard/User/PasswordField.jsx @@ -1,7 +1,7 @@ import { useState } from "react"; import { Button } from "@mui/material"; import ActionInput from "../../common/ActionInput"; -import { VisibilityOutlinedIcon, VisibilityOffOutlinedIcon } from "@mui/icons-material" +import { VisibilityOutlined, VisibilityOffOutlined } from "@mui/icons-material" import PropTypes from "prop-types"; const PasswordField = ({ value, name, placeholder, handleChange }) => { @@ -10,31 +10,32 @@ const PasswordField = ({ value, name, placeholder, handleChange }) => { return ( setShowPassword(!showPassword)} - startIcon={showPassword ? : } + startIcon={showPassword ? : } > {showPassword ? "Show" : "Hide"} } - type={showPassword ? "text" : "password"} - name={name} - value={value} - onChange={handleChange} /> ) } PasswordField.propTypes = { - placeholder: PropTypes.string, - name: PropTypes.string.isRequired, - value: PropTypes.string.isRequired, - handleChange: PropTypes.func.isRequired + placeholder: PropTypes.string, + name: PropTypes.string.isRequired, + value: PropTypes.string.isRequired, + handleChange: PropTypes.func.isRequired }; PasswordField.defaultProps = { - placeholder: "", + placeholder: "", }; diff --git a/src/components/Dashboard/User/index.jsx b/src/components/Dashboard/User/index.jsx index fd0e4d7b..fb52c178 100644 --- a/src/components/Dashboard/User/index.jsx +++ b/src/components/Dashboard/User/index.jsx @@ -1,5 +1,5 @@ import { useState } from "react"; -import { Avatar, Box, Button, Chip, Grid, Stack, Typography, Divider, TextField, InputAdornment, IconButton } from "@mui/material"; +import { Box, Button, Chip, Grid, Stack, Typography } from "@mui/material"; import { vars } from "../../../theme/variables"; import CustomBreadcrumbs from "../../common/CustomBreadcrumbs"; import HomeOutlinedIcon from "@mui/icons-material/HomeOutlined"; @@ -7,11 +7,8 @@ import { SettingsOutlined } from "@mui/icons-material"; import { GlobalDataContext } from "../../../contexts/DataContext"; import { useContext } from "react"; import AccountSettingsDialog from "./AccountSettingsDialog"; -import PersonOutlineIcon from '@mui/icons-material/PersonOutline'; -import ModeEditOutlineOutlinedIcon from "@mui/icons-material/ModeEditOutlineOutlined"; -import PasswordField from "./PasswordField"; -const { gray25, gray600, gray800, gray500, gray700 } = vars; +const { gray25, gray600, gray800, gray500 } = vars; const breadcrumbItems = [ { label: '', href: '/', icon: HomeOutlinedIcon }, @@ -21,42 +18,6 @@ const breadcrumbItems = [ const User = () => { const { user } = useContext(GlobalDataContext) const [open, setOpen] = useState(false); - const [showCurrentPassword, setShowCurrentPassword] = useState(false) - const [showNewPassword, setShowNewPassword] = useState(false) - const [showConfirmPassword, setShowConfirmPassword] = useState(false) - - const [formData, setFormData] = useState({ - email: "user@example.com", - currentPassword: "", - newPassword: "", - confirmPassword: "", - }) - - const handleInputChange = (field, value) => { - setFormData((prev) => ({ - ...prev, - [field]: value, - })) - } - - const handleSubmit = (e) => { - e.preventDefault() - console.log("Form submitted:", formData) - } - - const togglePasswordVisibility = (field) => { - switch (field) { - case "current": - setShowCurrentPassword(!showCurrentPassword) - break - case "new": - setShowNewPassword(!showNewPassword) - break - case "confirm": - setShowConfirmPassword(!showConfirmPassword) - break - } - } return ( { - setOpen(false)} - > - <> - - - - - - Aigul - aigul@metacell.us - - - - - - - - - Email - - handleInputChange("email", e.target.value)} - disabled - size="small" - sx={{ mt: 1 }} - /> - - Email address can't be changed from the interface. Please contact us to make this change. - - - - - - - - Current Password - - handleInputChange("currentPassword", e.target.value)} - placeholder="Enter your current password" - /> - - - - - - - Enter New Password - - handleInputChange("newPassword", e.target.value)} - placeholder="Enter new password" - variant="outlined" - sx={{ mt: 1 }} - // InputProps={{ - // endAdornment: ( - // - // togglePasswordVisibility("new")} - // edge="end" - // aria-label="toggle password visibility" - // > - // {showNewPassword ? : } - // - // - // ), - // }} - /> - - - - - - - Confirm New Password - - handleInputChange("confirmPassword", e.target.value)} - placeholder="Confirm new password" - variant="outlined" - sx={{ mt: 1 }} - // InputProps={{ - // endAdornment: ( - // - // togglePasswordVisibility("confirm")} - // edge="end" - // aria-label="toggle password visibility" - // > - // {showConfirmPassword ? : } - // - // - // ), - // }} - /> - - - - - - - - - - - - + setOpen(false)} /> ); }; diff --git a/src/components/common/ActionInput.jsx b/src/components/common/ActionInput.jsx index e1fbddb0..1ad4cc2d 100644 --- a/src/components/common/ActionInput.jsx +++ b/src/components/common/ActionInput.jsx @@ -1,14 +1,12 @@ import Paper from '@mui/material/Paper'; import InputBase from '@mui/material/InputBase'; -import Divider from '@mui/material/Divider'; import IconButton from '@mui/material/IconButton'; -import SearchIcon from '@mui/icons-material/Search'; import PropTypes from "prop-types"; import { vars } from '../../theme/variables'; -const { gray300, inputBoxShadow } = vars; +const { gray300, brand600, inputBoxShadow } = vars; -const ActionInput = ({ actionButton, placeholder, name, value, onChange, type }) => { +const ActionInput = ({ name, value, onChange, actionButton, placeholder, type, size, inputIcon }) => { return ( @@ -31,7 +34,17 @@ const ActionInput = ({ actionButton, placeholder, name, value, onChange, type }) flex: 1, paddingY: "0.625rem", paddingLeft: "0.875rem", - paddingRight: 0 + paddingRight: 0, + borderRadius: "0.5rem", + height: "100%", + borderTopRightRadius: 0, + borderBottomRightRadius: 0, + border: "1px solid", + borderColor: gray300, + '&.Mui-focused': { + borderColor: brand600, + borderWidth: "2px" + } }} type={type} value={value} @@ -40,10 +53,9 @@ const ActionInput = ({ actionButton, placeholder, name, value, onChange, type }) placeholder={placeholder} inputProps={{ 'aria-label': name }} /> - - - - + {inputIcon && ( + {inputIcon} + )} {actionButton} ); @@ -55,7 +67,9 @@ ActionInput.propTypes = { value: PropTypes.string.isRequired, onChange: PropTypes.func.isRequired, type: PropTypes.string, - actionButton: PropTypes.node + size: PropTypes.string, + actionButton: PropTypes.node, + inputIcon: PropTypes.element }; ActionInput.defaultProps = { From 2b75ab399b94652e15b1c5741848b61c543305b1 Mon Sep 17 00:00:00 2001 From: Aiga115 Date: Wed, 28 May 2025 23:33:01 +0200 Subject: [PATCH 3/9] ILEX-114 update ui design --- .../Dashboard/User/AccountSettingsDialog.jsx | 241 ++++++++---------- src/components/common/CustomizedDialog.jsx | 4 +- 2 files changed, 115 insertions(+), 130 deletions(-) diff --git a/src/components/Dashboard/User/AccountSettingsDialog.jsx b/src/components/Dashboard/User/AccountSettingsDialog.jsx index eadb02ea..4180837e 100644 --- a/src/components/Dashboard/User/AccountSettingsDialog.jsx +++ b/src/components/Dashboard/User/AccountSettingsDialog.jsx @@ -1,14 +1,14 @@ import PropTypes from "prop-types"; import { useState } from "react"; -import { Dialog, Box, Divider, Button, DialogContent, Typography, Avatar, Stack, Grid, TextField } from "@mui/material"; -import IconButton from "@mui/material/IconButton"; -import CloseIcon from "@mui/icons-material/Close"; +import { Box, Divider, Button, Typography, Avatar, Stack, Grid, TextField, Link } from "@mui/material"; +import CustomizedDialog from "../../common/CustomizedDialog"; import PasswordField from "./PasswordField"; import PersonOutlineIcon from '@mui/icons-material/PersonOutline'; import ModeEditOutlineOutlinedIcon from "@mui/icons-material/ModeEditOutlineOutlined"; +import ArrowForwardIcon from '@mui/icons-material/ArrowForward'; import { vars } from "../../../theme/variables"; -const { gray600, gray200, gray700 } = vars; +const { gray600, gray700, brand700 } = vars; const HeaderRightSideContent = ({ handleClose, handleSubmit }) => { return ( @@ -55,144 +55,127 @@ const AccountSettingsDialog = ({ const userGroupname = user?.groupname.charAt(0).toUpperCase() + user?.groupname.slice(1) return ( - } sx={{ '& .MuiDialog-paper': { maxWidth: '62.5rem' } }} > - - - - - - - - Account settings - - - + + + + + + {userGroupname} + {user?.email} + - - - - - - - {userGroupname} - {user?.email} - - - - - - - - - Email - - handleInputChange("email", e.target.value)} - disabled - size="small" - /> - - Email address can't be changed from the interface. Please contact us to make this change. - - - + + + + + + + Email + + handleInputChange("email", e.target.value)} + disabled + size="small" + /> + + Email address can't be changed from the interface. Please contact us to make this change. + + Contact support + + + + + - {showPasswordField && ( - <> - - - - Current Password - - handleInputChange("currentPassword", e.target.value)} - placeholder="Enter your current password" - /> - - + {showPasswordField && ( + <> + + + + Current Password + + handleInputChange("currentPassword", e.target.value)} + placeholder="Enter your current password" + /> + + - - - - Enter New Password - - handleInputChange("newPassword", e.target.value)} - placeholder="Enter new password" - /> - - + + + + Enter New Password + + handleInputChange("newPassword", e.target.value)} + placeholder="Enter new password" + /> + + - - - - Confirm New Password - - handleInputChange("confirmPassword", e.target.value)} - placeholder="Confirm new password" - /> - - - - )} + + + + Confirm New Password + + handleInputChange("confirmPassword", e.target.value)} + placeholder="Confirm new password" + /> + + + + )} - - - - - + + + + - - - + + + ); }; diff --git a/src/components/common/CustomizedDialog.jsx b/src/components/common/CustomizedDialog.jsx index ded95122..41f9d946 100644 --- a/src/components/common/CustomizedDialog.jsx +++ b/src/components/common/CustomizedDialog.jsx @@ -19,6 +19,7 @@ const CustomizedDialog = ({ title, open, handleClose, + fullScreen = true, HeaderRightSideContent, sx, }) => { @@ -27,7 +28,7 @@ const CustomizedDialog = ({ onClose={handleClose} aria-labelledby="customized-dialog-title" open={open} - fullScreen + fullScreen={fullScreen} TransitionComponent={Transition} sx={sx} > @@ -85,6 +86,7 @@ CustomizedDialog.propTypes = { title: PropTypes.string.isRequired, open: PropTypes.bool.isRequired, handleClose: PropTypes.func.isRequired, + fullScreen: PropTypes.bool, HeaderRightSideContent: PropTypes.node, sx: PropTypes.object, }; From f283eb8efa89ee9d606372cec746272d7d19ffe7 Mon Sep 17 00:00:00 2001 From: Aiga115 Date: Thu, 29 May 2025 13:47:01 +0200 Subject: [PATCH 4/9] ILEX-114 icon change logic --- .../Dashboard/User/AccountSettingsDialog.jsx | 36 ++++++++++++++----- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/src/components/Dashboard/User/AccountSettingsDialog.jsx b/src/components/Dashboard/User/AccountSettingsDialog.jsx index 4180837e..75a32e5e 100644 --- a/src/components/Dashboard/User/AccountSettingsDialog.jsx +++ b/src/components/Dashboard/User/AccountSettingsDialog.jsx @@ -5,6 +5,7 @@ import CustomizedDialog from "../../common/CustomizedDialog"; import PasswordField from "./PasswordField"; import PersonOutlineIcon from '@mui/icons-material/PersonOutline'; import ModeEditOutlineOutlinedIcon from "@mui/icons-material/ModeEditOutlineOutlined"; +import SaveOutlinedIcon from '@mui/icons-material/SaveOutlined'; import ArrowForwardIcon from '@mui/icons-material/ArrowForward'; import { vars } from "../../../theme/variables"; @@ -32,7 +33,7 @@ const AccountSettingsDialog = ({ handleClose }) => { const [showPasswordField, setShowPasswordField] = useState(false); - + const [showSavePasswordField, setShowSavePasswordField] = useState(false); const [formData, setFormData] = useState({ email: user?.email, currentPassword: "", @@ -53,6 +54,8 @@ const AccountSettingsDialog = ({ } const userGroupname = user?.groupname.charAt(0).toUpperCase() + user?.groupname.slice(1) + const isPasswordFormValid = formData.currentPassword.trim() !== "" && formData.newPassword.trim() !== "" && formData.confirmPassword.trim() !== ""; + return ( - + {!showPasswordField ? ( + + ) : (<> + + + )} From e13e973752e99bf91e1e2098c3dff2093bdcd6ed Mon Sep 17 00:00:00 2001 From: Aiga115 Date: Thu, 29 May 2025 13:47:35 +0200 Subject: [PATCH 5/9] ILEX-114 small change --- src/components/Dashboard/User/AccountSettingsDialog.jsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/Dashboard/User/AccountSettingsDialog.jsx b/src/components/Dashboard/User/AccountSettingsDialog.jsx index 75a32e5e..cbed836a 100644 --- a/src/components/Dashboard/User/AccountSettingsDialog.jsx +++ b/src/components/Dashboard/User/AccountSettingsDialog.jsx @@ -33,7 +33,6 @@ const AccountSettingsDialog = ({ handleClose }) => { const [showPasswordField, setShowPasswordField] = useState(false); - const [showSavePasswordField, setShowSavePasswordField] = useState(false); const [formData, setFormData] = useState({ email: user?.email, currentPassword: "", From 6ad12e234f2cab94285fcc6b7551ab269819ec90 Mon Sep 17 00:00:00 2001 From: Aiga115 Date: Wed, 4 Jun 2025 13:45:42 +0200 Subject: [PATCH 6/9] ILEX-114 update design of password change modal --- .../Dashboard/User/PasswordField.jsx | 45 +++++++++++-------- src/components/common/ActionInput.jsx | 12 ++++- src/theme/index.jsx | 6 --- src/theme/variables.js | 3 +- 4 files changed, 39 insertions(+), 27 deletions(-) diff --git a/src/components/Dashboard/User/PasswordField.jsx b/src/components/Dashboard/User/PasswordField.jsx index 8e93c94d..218d72f9 100644 --- a/src/components/Dashboard/User/PasswordField.jsx +++ b/src/components/Dashboard/User/PasswordField.jsx @@ -1,29 +1,36 @@ import { useState } from "react"; -import { Button } from "@mui/material"; +import { Button, Typography } from "@mui/material"; import ActionInput from "../../common/ActionInput"; import { VisibilityOutlined, VisibilityOffOutlined } from "@mui/icons-material" import PropTypes from "prop-types"; -const PasswordField = ({ value, name, placeholder, handleChange }) => { +const PasswordField = ({ value, name, placeholder, handleChange, error, helperText }) => { const [showPassword, setShowPassword] = useState(false) return ( - setShowPassword(!showPassword)} - startIcon={showPassword ? : } - > - {showPassword ? "Show" : "Hide"} - - } - /> +
+ setShowPassword(!showPassword)} + startIcon={showPassword ? : } + > + {showPassword ? "Show" : "Hide"} + + } + /> + {helperText && ( + + {helperText} + + )} +
) } @@ -31,6 +38,8 @@ PasswordField.propTypes = { placeholder: PropTypes.string, name: PropTypes.string.isRequired, value: PropTypes.string.isRequired, + error: PropTypes.bool, + helperText: PropTypes.string, handleChange: PropTypes.func.isRequired }; diff --git a/src/components/common/ActionInput.jsx b/src/components/common/ActionInput.jsx index 1ad4cc2d..56169187 100644 --- a/src/components/common/ActionInput.jsx +++ b/src/components/common/ActionInput.jsx @@ -4,9 +4,9 @@ import IconButton from '@mui/material/IconButton'; import PropTypes from "prop-types"; import { vars } from '../../theme/variables'; -const { gray300, brand600, inputBoxShadow } = vars; +const { gray300, brand600, error300, inputBoxShadow, inputErrorBoxShadow } = vars; -const ActionInput = ({ name, value, onChange, actionButton, placeholder, type, size, inputIcon }) => { +const ActionInput = ({ name, value, onChange, error, actionButton, placeholder, type, size, inputIcon }) => { return ( {inputIcon && ( @@ -65,6 +72,7 @@ ActionInput.propTypes = { placeholder: PropTypes.string, name: PropTypes.string.isRequired, value: PropTypes.string.isRequired, + error: PropTypes.bool, onChange: PropTypes.func.isRequired, type: PropTypes.string, size: PropTypes.string, diff --git a/src/theme/index.jsx b/src/theme/index.jsx index 647b95d3..6485976a 100644 --- a/src/theme/index.jsx +++ b/src/theme/index.jsx @@ -249,12 +249,6 @@ const theme = createTheme({ }, }, - MuiTextField: { - styleOverrides: { - - } - }, - MuiContainer: { styleOverrides: { maxWidthXl: { diff --git a/src/theme/variables.js b/src/theme/variables.js index 35720016..40a108e5 100644 --- a/src/theme/variables.js +++ b/src/theme/variables.js @@ -74,5 +74,6 @@ export const vars = { success950: '#053321', paperShadow: '0px 12px 16px -4px rgba(16, 24, 40, 0.08), 0px 4px 6px -2px rgba(16, 24, 40, 0.03)', errorInputBoxShadow: '0px 1px 2px 0px rgba(16, 24, 40, 0.05), 0px 0px 0px 4px rgba(240, 68, 56, 0.24)', - inputBoxShadow: '0px 1px 2px 0px rgba(16, 24, 40, 0.05)' + inputBoxShadow: '0px 1px 2px 0px rgba(16, 24, 40, 0.05)', + inputErrorBoxShadow: '0px 0px 0px 4px rgba(240, 68, 56, 0.24)' } \ No newline at end of file From 4455a4091d88b7a89adb5da03acfc60e131423b1 Mon Sep 17 00:00:00 2001 From: Aiga115 Date: Mon, 16 Jun 2025 17:10:01 +0200 Subject: [PATCH 7/9] ILEX-114 initial step: change from email to username --- src/api/endpoints/apiActions.ts | 2 ++ src/components/Auth/ForgotPassword.jsx | 14 +++++++------- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/api/endpoints/apiActions.ts b/src/api/endpoints/apiActions.ts index d25d8458..4d119d60 100644 --- a/src/api/endpoints/apiActions.ts +++ b/src/api/endpoints/apiActions.ts @@ -43,3 +43,5 @@ export const createGetRequest = (endpoint: string, contentType }); } } + +export const forgotPassword = () => {} diff --git a/src/components/Auth/ForgotPassword.jsx b/src/components/Auth/ForgotPassword.jsx index 16c98db9..19bf00af 100644 --- a/src/components/Auth/ForgotPassword.jsx +++ b/src/components/Auth/ForgotPassword.jsx @@ -6,12 +6,12 @@ import { Link } from "react-router-dom"; import { handleForgotPassword } from "../../api/endpoints/index"; const ForgotPassword = () => { - const [email, setEmail] = React.useState(""); + const [username, setUsername] = React.useState(""); const forgotPassword = async () => { try { - await handleForgotPassword(email); - console.log("Password reset email sent"); + await handleForgotPassword(username); + console.log("Password reset username sent"); } catch (error) { console.error("Error:", error); } @@ -29,10 +29,10 @@ const ForgotPassword = () => {
setEmail(e.target.value)} + label="Username" + placeholder="Enter your username" + value={username} + onChange={(e) => setUsername(e.target.value)} /> From 23dff94869446989294e320c9ae24b164dc3b0e7 Mon Sep 17 00:00:00 2001 From: Aiga115 Date: Mon, 16 Jun 2025 20:55:57 +0200 Subject: [PATCH 8/9] ILEX-114 handle forgot password case --- src/api/endpoints/apiActions.ts | 7 +------ src/api/endpoints/apiService.ts | 22 ++++++++++++++-------- src/components/Auth/ForgotPassword.jsx | 12 +++++++----- src/config.js | 1 + 4 files changed, 23 insertions(+), 19 deletions(-) diff --git a/src/api/endpoints/apiActions.ts b/src/api/endpoints/apiActions.ts index 4d119d60..ca5a41c7 100644 --- a/src/api/endpoints/apiActions.ts +++ b/src/api/endpoints/apiActions.ts @@ -1,8 +1,5 @@ import { AxiosRequestConfig } from 'axios'; import { customInstance } from '../../../mock/mutator/customClient'; -import { API_CONFIG } from '../../config'; -import { useCookies } from 'react-cookie' - type SecondParameter any> = Parameters[1]; @@ -42,6 +39,4 @@ export const createGetRequest = (endpoint: string, contentType return response; }); } -} - -export const forgotPassword = () => {} +} \ No newline at end of file diff --git a/src/api/endpoints/apiService.ts b/src/api/endpoints/apiService.ts index 3e2f0387..2ea26b4a 100644 --- a/src/api/endpoints/apiService.ts +++ b/src/api/endpoints/apiService.ts @@ -15,6 +15,10 @@ export interface RegisterRequest { organization: string } +interface ForgotPasswordReguest { + username: string; +} + type LabelType = | string | { '@value': string; '@language'?: string } @@ -28,9 +32,9 @@ interface JsonLdResponse { '@graph'?: GraphNode[]; } -export const login = createPostRequest(API_CONFIG.REAL_API.SIGNIN, {"Content-Type": "application/x-www-form-urlencoded"}) +export const login = createPostRequest(API_CONFIG.REAL_API.SIGNIN, { "Content-Type": "application/x-www-form-urlencoded" }) -export const register = createPostRequest(API_CONFIG.REAL_API.NEWUSER_ILX, {"Content-Type": "application/x-www-form-urlencoded"}) +export const register = createPostRequest(API_CONFIG.REAL_API.NEWUSER_ILX, { "Content-Type": "application/x-www-form-urlencoded" }) export const getUserSettings = (group: string) => { @@ -40,7 +44,7 @@ export const getUserSettings = (group: string) => { export const createNewOrganization = ({ group, data }: { group: string, data: any }) => { const endpoint = `/${group}${API_CONFIG.REAL_API.CREATE_NEW_ORGANIZATION}`; - return createPostRequest(endpoint, { "Content-Type" : "application/json" })(data); + return createPostRequest(endpoint, { "Content-Type": "application/json" })(data); }; export const getOrganizations = (group: string) => { @@ -84,7 +88,7 @@ export const createNewEntity = async ({ group, data, session }: { group: string; const endpoint = `/${group}${API_CONFIG.REAL_API.CREATE_NEW_ENTITY}`; const response = await createPostRequest( endpoint, - { "Content-Type" : "application/x-www-form-urlencoded" } + { "Content-Type": "application/x-www-form-urlencoded" } )(data); // If the response is HTML (a string), extract TMP ID @@ -141,8 +145,8 @@ export const createNewOntology = async ({ const endpoint = `/${groupname}/ontologies/uris/${ontologyName}/spec`; const data = { - title : title, - subjects : subjects, + title: title, + subjects: subjects, }; const headers = { @@ -190,10 +194,12 @@ export const createNewOntology = async ({ export const getNewTokenApi = ({ groupname, data }: { groupname: string, data: any }) => { const endpoint = `/${groupname}${API_CONFIG.REAL_API.API_NEW_TOKEN}`; - return createPostRequest(endpoint, { "Content-Type" : "application/json" })(data); + return createPostRequest(endpoint, { "Content-Type": "application/json" })(data); }; export const retrieveTokenApi = ({ groupname }: { groupname: string }) => { const endpoint = `/${groupname}${API_CONFIG.REAL_API.API_RETRIEVE_TOKEN}`; return createGetRequest(endpoint, "application/json")(); -}; \ No newline at end of file +}; + +export const forgotPassword = createPostRequest(API_CONFIG.REAL_API.USER_RECOVER, { "Content-Type": "application/x-www-form-urlencoded" }) diff --git a/src/components/Auth/ForgotPassword.jsx b/src/components/Auth/ForgotPassword.jsx index 19bf00af..7c1662ea 100644 --- a/src/components/Auth/ForgotPassword.jsx +++ b/src/components/Auth/ForgotPassword.jsx @@ -3,17 +3,18 @@ import { Box, Button, FormControl, Grid, Paper, Typography } from "@mui/material import { ArrowBack } from "@mui/icons-material"; import FormField from "./UI/Formfield"; import { Link } from "react-router-dom"; -import { handleForgotPassword } from "../../api/endpoints/index"; +import { forgotPassword } from "../../api/endpoints/apiService"; const ForgotPassword = () => { const [username, setUsername] = React.useState(""); + const [error, setError] = React.useState(""); - const forgotPassword = async () => { + const handleForgotPassword = async () => { try { - await handleForgotPassword(username); - console.log("Password reset username sent"); + await forgotPassword({username: username}); } catch (error) { console.error("Error:", error); + setError(error.message); } }; @@ -33,10 +34,11 @@ const ForgotPassword = () => { placeholder="Enter your username" value={username} onChange={(e) => setUsername(e.target.value)} + errorMessage={error} /> - diff --git a/src/config.js b/src/config.js index d280e79f..1e92e581 100644 --- a/src/config.js +++ b/src/config.js @@ -35,6 +35,7 @@ export const API_CONFIG = { API_RETRIEVE_TOKEN: "/priv/api-tokens", GET_ORGANIZATIONS: "/priv/role-other", LOGOUT: "/priv/logout", + USER_RECOVER: "/u/ops/user-recover" }, SESSION_DATA: { SETTINGS: "settings", From cc84494666d2f103ab6b683479959a8d01497d58 Mon Sep 17 00:00:00 2001 From: Aiga115 Date: Tue, 17 Jun 2025 13:42:52 +0200 Subject: [PATCH 9/9] ILEX-114 fix lint issue --- .../Dashboard/User/AccountSettingsDialog.jsx | 2 +- src/components/Dashboard/User/PasswordField.jsx | 1 + src/theme/index.jsx | 10 +++------- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/components/Dashboard/User/AccountSettingsDialog.jsx b/src/components/Dashboard/User/AccountSettingsDialog.jsx index cbed836a..abca8238 100644 --- a/src/components/Dashboard/User/AccountSettingsDialog.jsx +++ b/src/components/Dashboard/User/AccountSettingsDialog.jsx @@ -97,7 +97,7 @@ const AccountSettingsDialog = ({ size="small" /> - Email address can't be changed from the interface. Please contact us to make this change. + Email address can't be changed from the interface. Please contact us to make this change. )} + {error && {`${error.charAt(0).toUpperCase() + error.slice(1)}`}} ) } diff --git a/src/theme/index.jsx b/src/theme/index.jsx index 6485976a..7d5fb139 100644 --- a/src/theme/index.jsx +++ b/src/theme/index.jsx @@ -643,6 +643,9 @@ const theme = createTheme({ height: "1.25rem", fontSize: "1.25rem", }, + fontSizeLarge: { + fontSize: '2rem' + } }, }, MuiAccordion: { @@ -1061,13 +1064,6 @@ const theme = createTheme({ }, }, }, - }, - MuiSvgIcon: { - styleOverrides: { - fontSizeLarge: { - fontSize: '2rem' - } - } } }, });