Skip to content

Commit

Permalink
feat: update username
Browse files Browse the repository at this point in the history
  • Loading branch information
lucasmagnus committed Feb 26, 2024
1 parent 5b924b1 commit 9f4d10e
Show file tree
Hide file tree
Showing 7 changed files with 202 additions and 18 deletions.
19 changes: 18 additions & 1 deletion frontend/src/app/core/pages/team-members/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export const TeamMembers: React.FC = () => {
const {
getAllUsers,
editUsersRole,
updateUsername,
getRoles,
getUserPermissions,
users,
Expand All @@ -24,6 +25,7 @@ export const TeamMembers: React.FC = () => {
loadingRoles,
userPermissions,
loadingUserPermissions,
updatingUsername,
} = useAuth()

useEffect(() => {
Expand All @@ -42,6 +44,19 @@ export const TeamMembers: React.FC = () => {
return false
}

const handleUpdateUsername = async (
id: number,
name: string
): Promise<boolean> => {
const isSuccess = await updateUsername(id, name)

if (isSuccess) {
getAllUsers()
return true
}
return false
}

useEffect(() => {
getAllUsers()
getRoles()
Expand All @@ -61,10 +76,12 @@ export const TeamMembers: React.FC = () => {
<TeamMembersTemplate
users={users}
loading={loading || loadingUserPermissions}
handleEditRole={handleEditRole}
roles={roles}
loadingRoles={loadingRoles}
permissions={userPermissions}
updatingUsername={updatingUsername}
handleUpdateUsername={handleUpdateUsername}
handleEditRole={handleEditRole}
/>
</Flex>
{isLargerThanLg && (
Expand Down
25 changes: 18 additions & 7 deletions frontend/src/components/templates/team-members/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,27 +21,31 @@ import { MenuAdminMobile } from 'components/organisms/menu-admin-mobile'
import { ItemMenu } from './item-menu'
import { ItemUser } from './item-user'

interface ISettingsTemplate {
interface ITeamMembersTemplateTemplate {
users: Hooks.UseAuthTypes.IUserDto[] | undefined
loading: boolean
handleEditRole(params: Hooks.UseAuthTypes.IUserRole): Promise<boolean>
roles: Hooks.UseAuthTypes.IRole[] | undefined
loadingRoles: boolean
permissions: Hooks.UseAuthTypes.IUserPermission | undefined
updatingUsername: boolean
handleEditRole(params: Hooks.UseAuthTypes.IUserRole): Promise<boolean>
handleUpdateUsername(id: number, name: string): Promise<boolean>
}

export const TeamMembersTemplate: React.FC<ISettingsTemplate> = ({
export const TeamMembersTemplate: React.FC<ITeamMembersTemplateTemplate> = ({
users,
loading,
handleEditRole,
roles,
loadingRoles,
permissions,
updatingUsername,
handleEditRole,
handleUpdateUsername,
}) => {
const [isSmallerThanMd] = useMediaQuery('(max-width: 768px)')
const [isLargerThanLg] = useMediaQuery('(min-width: 992px)')

const { onOpen } = useDisclosure()
const { onOpen: onOpenChangeRole, onOpen: onOpenRename } = useDisclosure()

return (
<Flex flexDir="column" w="full">
Expand Down Expand Up @@ -107,7 +111,11 @@ export const TeamMembersTemplate: React.FC<ISettingsTemplate> = ({
<Text>{`${user.role}`}</Text>
</Flex>
</Flex>
<ItemMenu onOpen={onOpen} permissions={permissions} />
<ItemMenu
onOpenChangeRole={onOpenChangeRole}
permissions={permissions}
onOpenRename={onOpenRename}
/>
</Flex>
))}
</Flex>
Expand All @@ -118,6 +126,7 @@ export const TeamMembersTemplate: React.FC<ISettingsTemplate> = ({
<Th>ID</Th>
<Th>Member</Th>
<Th>Role</Th>
<Th />
</Tr>
</Thead>
<Tbody>
Expand All @@ -126,10 +135,12 @@ export const TeamMembersTemplate: React.FC<ISettingsTemplate> = ({
key={index}
user={user}
loading={loading}
handleEditRole={handleEditRole}
roles={roles}
loadingRoles={loadingRoles}
permissions={permissions}
updatingUsername={updatingUsername}
handleEditRole={handleEditRole}
handleUpdateUsername={handleUpdateUsername}
/>
))}
</Tbody>
Expand Down
14 changes: 11 additions & 3 deletions frontend/src/components/templates/team-members/item-menu/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,16 @@ import { Permissions } from 'components/enums/permissions'
import { MenuDotsIcon } from 'components/icons'

interface IItemMenu {
onOpen(): void
onOpenChangeRole(): void
onOpenRename(): void
permissions: Hooks.UseAuthTypes.IUserPermission | undefined
}

export const ItemMenu: React.FC<IItemMenu> = ({ onOpen, permissions }) => {
export const ItemMenu: React.FC<IItemMenu> = ({
onOpenChangeRole,
onOpenRename,
permissions,
}) => {
return (
<>
{havePermission(Permissions.EDIT_USERS_ROLE, permissions) && (
Expand All @@ -36,7 +41,10 @@ export const ItemMenu: React.FC<IItemMenu> = ({ onOpen, permissions }) => {
icon={<MenuDotsIcon />}
/>
<MenuList>
<MenuItem onClick={onOpen}>Change role</MenuItem>
<MenuItem onClick={onOpenChangeRole}>Change role</MenuItem>
{permissions?.admin && (
<MenuItem onClick={onOpenRename}>Edit username</MenuItem>
)}
</MenuList>
</>
)}
Expand Down
39 changes: 32 additions & 7 deletions frontend/src/components/templates/team-members/item-user/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,44 +6,69 @@ import { formatName } from 'utils/formatter'
import { ModalEditRole } from 'components/molecules'

import { ItemMenu } from '../item-menu'
import { ModalUpdateUsername } from '../modal-update-username'

interface IItemUser {
user: Hooks.UseAuthTypes.IUserDto
loading: boolean
handleEditRole(params: Hooks.UseAuthTypes.IUserRole): Promise<boolean>
updatingUsername: boolean
roles: Hooks.UseAuthTypes.IRole[] | undefined
loadingRoles: boolean
permissions: Hooks.UseAuthTypes.IUserPermission | undefined
handleEditRole(params: Hooks.UseAuthTypes.IUserRole): Promise<boolean>
handleUpdateUsername(id: number, name: string): Promise<boolean>
}

export const ItemUser: React.FC<IItemUser> = ({
user,
loading,
handleEditRole,
roles,
loadingRoles,
permissions,
updatingUsername,
handleEditRole,
handleUpdateUsername,
}) => {
const { isOpen, onOpen, onClose } = useDisclosure()
const {
isOpen: isOpenChangeRole,
onOpen: onOpenChangeRole,
onClose: onCloseChangeRole,
} = useDisclosure()
const {
isOpen: isOpenUpdateUsername,
onOpen: onOpenUpdateUsername,
onClose: onCloseUpdateUsername,
} = useDisclosure()

return (
<>
<ModalEditRole
isOpen={isOpen}
onClose={onClose}
isOpen={isOpenChangeRole}
loading={loading}
loadingRoles={loadingRoles}
user={user}
handleEditRole={handleEditRole}
roles={roles}
onClose={onCloseChangeRole}
handleEditRole={handleEditRole}
/>
<ModalUpdateUsername
isOpen={isOpenUpdateUsername}
user={user}
updatingUsername={updatingUsername}
onClose={onCloseUpdateUsername}
handleUpdateUsername={handleUpdateUsername}
/>
<Tr>
<Td>{user.id}</Td>
<Td>{formatName(user.name)}</Td>
<Td>{user.role}</Td>
{
<Td w="1rem" p={0}>
<ItemMenu onOpen={onOpen} permissions={permissions} />
<ItemMenu
onOpenChangeRole={onOpenChangeRole}
permissions={permissions}
onOpenRename={onOpenUpdateUsername}
/>
</Td>
}
</Tr>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import {
Alert,
AlertIcon,
Box,
Button,
Input,
Modal,
ModalBody,
ModalCloseButton,
ModalContent,
ModalHeader,
ModalOverlay,
} from '@chakra-ui/react'
import React, { useState } from 'react'
import { useForm } from 'react-hook-form'

import { GAService } from 'utils/ga'

interface IModalUpdateUsername {
isOpen: boolean
user: Hooks.UseAuthTypes.IUserDto
updatingUsername: boolean
onClose(): void
handleUpdateUsername(id: number, name: string): Promise<boolean>
}

export const ModalUpdateUsername: React.FC<IModalUpdateUsername> = ({
isOpen,
user,
updatingUsername,
onClose,
handleUpdateUsername,
}) => {
const [errorSubmit, setErrorSubmit] = useState<string | null>(null)
const [username, setUsername] = useState(user.name)
const { handleSubmit } = useForm()

const onSubmit = async (): Promise<void> => {
setErrorSubmit(null)
try {
const isSuccess = await handleUpdateUsername(user.id, username)

if (isSuccess) {
GAService.GAEvent('username_updated')
onClose()
}
} catch (error) {
let message
if (error instanceof Error) message = error.message
else message = String(error)
setErrorSubmit(message)
}
}

return (
<Modal isOpen={isOpen} onClose={onClose}>
<ModalOverlay />
<ModalContent>
<ModalHeader>Edit username</ModalHeader>
<ModalCloseButton />
<ModalBody>
<Box>
{errorSubmit && (
<Alert mb="0.75rem" status="error">
<AlertIcon />
{errorSubmit}
</Alert>
)}
<form
onSubmit={handleSubmit(() => {
onSubmit()
})}
>
<Input
placeholder="Name"
autoComplete="off"
defaultValue={username}
onChange={(event): void => {
setUsername(event.target.value)
}}
w="full"
/>
<Button
w="full"
mb="1.5rem"
type="submit"
variant="primary"
mt="1.5rem"
isLoading={updatingUsername}
>
Save
</Button>
</form>
</Box>
</ModalBody>
</ModalContent>
</Modal>
)
}
22 changes: 22 additions & 0 deletions frontend/src/hooks/useAuth/context.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export const AuthProvider: React.FC<IProps> = ({ children }) => {
Authentication.getUser()
)
const [loading, setLoading] = useState(false)
const [updatingUsername, setUpdatingUsername] = useState(false)
const [loadingUserPermissions, setLoadingUserPermissions] = useState(true)
const [updatingRolesPermissions, setUpdatingRolesPermissions] =
useState(false)
Expand Down Expand Up @@ -369,6 +370,25 @@ export const AuthProvider: React.FC<IProps> = ({ children }) => {
}
}

const updateUsername = async (id: number, name: string): Promise<boolean> => {
setUpdatingUsername(true)
try {
const response = await http.put(`users/${id}/update-name`, { name: name })
if (response.status !== 200) {
throw new Error()
}

return true
} catch (error) {
if (axios.isAxiosError(error) && error?.response?.status === 400) {
throw new Error(error.message)
}
throw new Error(MessagesError.errorOccurred)
} finally {
setUpdatingUsername(false)
}
}

const isAuthenticated = !!user

return (
Expand All @@ -389,6 +409,7 @@ export const AuthProvider: React.FC<IProps> = ({ children }) => {
createRole,
updateRole,
deleteRole,
updateUsername,
isAuthenticated,
loading,
loadingRoles,
Expand All @@ -403,6 +424,7 @@ export const AuthProvider: React.FC<IProps> = ({ children }) => {
updatingRole,
deletingRole,
loadingUserPermissions,
updatingUsername,
}}
>
{children}
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/hooks/useAuth/use-auth-types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ declare namespace Hooks {
) => Promise<boolean>
createRole: (userId: number, name: string) => Promise<boolean>
updateRole: (id: number, name: string) => Promise<boolean>
updateUsername: (id: number, name: string) => Promise<boolean>
deleteRole: (id: number, idNewUsersRole: number) => Promise<boolean>
isAuthenticated: boolean
loading: boolean
Expand All @@ -99,6 +100,7 @@ declare namespace Hooks {
updatingRole: boolean
deletingRole: boolean
loadingUserPermissions: boolean
updatingUsername: boolean
}
}
}

0 comments on commit 9f4d10e

Please sign in to comment.