diff --git a/src/apps/admin/src/lib/components/DialogEditUserHandle/DialogEditUserHandle.module.scss b/src/apps/admin/src/lib/components/DialogEditUserHandle/DialogEditUserHandle.module.scss new file mode 100644 index 000000000..2104049c7 --- /dev/null +++ b/src/apps/admin/src/lib/components/DialogEditUserHandle/DialogEditUserHandle.module.scss @@ -0,0 +1,34 @@ +.container { + display: flex; + flex-direction: column; + gap: 20px; + position: relative; +} + +.blockForm { + display: flex; + flex-direction: column; + gap: 20px; + position: relative; +} + +.actionButtons { + display: flex; + justify-content: flex-end; + gap: 6px; +} + +.dialogLoadingSpinnerContainer { + position: absolute; + width: 64px; + display: flex; + align-items: center; + justify-content: center; + bottom: 0; + height: 64px; + left: 0; + + .spinner { + background: none; + } +} diff --git a/src/apps/admin/src/lib/components/DialogEditUserHandle/DialogEditUserHandle.tsx b/src/apps/admin/src/lib/components/DialogEditUserHandle/DialogEditUserHandle.tsx new file mode 100644 index 000000000..cd0d98fca --- /dev/null +++ b/src/apps/admin/src/lib/components/DialogEditUserHandle/DialogEditUserHandle.tsx @@ -0,0 +1,163 @@ +/** + * Dialog edit user handle. + */ +import { FC, useCallback, useState } from 'react' +import { useForm, UseFormReturn } from 'react-hook-form' +import { toast } from 'react-toastify' +import _ from 'lodash' +import classNames from 'classnames' + +import { + BaseModal, + Button, + ConfirmModal, + InputText, + LoadingSpinner, +} from '~/libs/ui' +import { yupResolver } from '@hookform/resolvers/yup' + +import { FormEditUserHandle, UserInfo } from '../../models' +import { formEditUserHandleSchema, handleError } from '../../utils' +import { changeUserHandle } from '../../services' + +import styles from './DialogEditUserHandle.module.scss' + +interface Props { + className?: string + open: boolean + setOpen: (isOpen: boolean) => void + userInfo: UserInfo +} + +export const DialogEditUserHandle: FC = (props: Props) => { + const [isLoading, setIsLoading] = useState(false) + const handleClose = useCallback(() => { + if (!isLoading) { + props.setOpen(false) + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [isLoading]) + const [showConfirm, setShowConfirm] = useState(false) + const { + register, + handleSubmit, + getValues, + formState: { errors, isValid, isDirty }, + }: UseFormReturn = useForm({ + defaultValues: { + newHandle: '', + }, + mode: 'all', + resolver: yupResolver(formEditUserHandleSchema), + }) + const onSubmit = useCallback(() => { + setShowConfirm(true) + }, []) + const currentHandle = props.userInfo.handle + const newHandle = getValues().newHandle ?? '' + const confirmMessage = `Are you sure you want to change the handle from "${currentHandle}" ` + + `to "${newHandle}"?` + + return ( + <> + +
+
+ + +
+
+ + +
+ + {isLoading && ( +
+ +
+ )} +
+
+ { + setIsLoading(false) + toast.success('Handle updated successfully') + props.userInfo.handle = result?.handle ?? nextHandle + handleClose() + }) + .catch(e => { + handleError(e) + setIsLoading(false) + }) + }} + open={showConfirm} + > +
+

{confirmMessage}

+
+
+ + ) +} + +export default DialogEditUserHandle diff --git a/src/apps/admin/src/lib/components/DialogEditUserHandle/index.ts b/src/apps/admin/src/lib/components/DialogEditUserHandle/index.ts new file mode 100644 index 000000000..919454017 --- /dev/null +++ b/src/apps/admin/src/lib/components/DialogEditUserHandle/index.ts @@ -0,0 +1 @@ +export { default as DialogEditUserHandle } from './DialogEditUserHandle' diff --git a/src/apps/admin/src/lib/components/UsersTable/UsersTable.tsx b/src/apps/admin/src/lib/components/UsersTable/UsersTable.tsx index 6059722de..665777b74 100644 --- a/src/apps/admin/src/lib/components/UsersTable/UsersTable.tsx +++ b/src/apps/admin/src/lib/components/UsersTable/UsersTable.tsx @@ -20,6 +20,7 @@ import { import { CopyButton } from '../CopyButton' import { DialogEditUserEmail } from '../DialogEditUserEmail' +import { DialogEditUserHandle } from '../DialogEditUserHandle' import { DialogEditUserRoles } from '../DialogEditUserRoles' import { DialogEditUserGroups } from '../DialogEditUserGroups' import { DialogEditUserSSOLogin } from '../DialogEditUserSSOLogin' @@ -82,6 +83,9 @@ export const UsersTable: FC = props => { const [showDialogEditUserEmail, setShowDialogEditUserEmail] = useState< UserInfo | undefined >() + const [showDialogEditUserHandle, setShowDialogEditUserHandle] = useState< + UserInfo | undefined + >() const [showDialogEditUserRoles, setShowDialogEditUserRoles] = useState< UserInfo | undefined >() @@ -309,6 +313,8 @@ export const UsersTable: FC = props => { function onSelectOption(item: string): void { if (item === 'Primary Email') { setShowDialogEditUserEmail(data) + } else if (item === 'Change Handle') { + setShowDialogEditUserHandle(data) } else if (item === 'Roles') { setShowDialogEditUserRoles(data) } else if (item === 'Groups') { @@ -344,6 +350,7 @@ export const UsersTable: FC = props => { = props => { = props => { userInfo={showDialogEditUserEmail} /> )} + {showDialogEditUserHandle && ( + + )} {showDialogEditUserRoles && ( => { + const payload = { + newHandle: newHandle.trim(), + } + + return xhrPatchAsync( + `${EnvironmentConfig.API.V6}/members/${encodeURIComponent(handle)}/change_handle`, + payload, + ) +} + /** * Update user status. * @param userId user id. diff --git a/src/apps/admin/src/lib/utils/validation.ts b/src/apps/admin/src/lib/utils/validation.ts index a5656533b..35046a48e 100644 --- a/src/apps/admin/src/lib/utils/validation.ts +++ b/src/apps/admin/src/lib/utils/validation.ts @@ -13,6 +13,7 @@ import { FormEditClient, FormEditUserEmail, FormEditUserGroup, + FormEditUserHandle, FormEditUserRole, FormGroupMembersFilters, FormNewBillingAccountResource, @@ -442,6 +443,16 @@ export const formEditUserEmailSchema: Yup.ObjectSchema .required('Email address is required.'), }) +/** + * validation schema for form edit user handle + */ +export const formEditUserHandleSchema: Yup.ObjectSchema + = Yup.object({ + newHandle: Yup.string() + .trim() + .required('Handle is required.'), + }) + /** * validation schema for form edit sso user login */