diff --git a/frontend/src/app/core/pages/asset-home/index.tsx b/frontend/src/app/core/pages/asset-home/index.tsx index 7694173a..ae9cf24e 100644 --- a/frontend/src/app/core/pages/asset-home/index.tsx +++ b/frontend/src/app/core/pages/asset-home/index.tsx @@ -35,7 +35,13 @@ export const AssetHome: React.FC = () => { const [isLargerThanMd] = useMediaQuery('(min-width: 768px)') const [isSmallerThanMd] = useMediaQuery('(max-width: 768px)') - const { loadingAsset, getAssetById, updateImage } = useAssets() + const { + loadingAsset, + updatingAsset, + getAssetById, + updateImage, + updateAsset, + } = useAssets() const { loadingUserPermissions, userPermissions, getUserPermissions } = useAuth() const { getPaymentsByAssetId, loadingChart } = useDashboards() @@ -90,6 +96,34 @@ export const AssetHome: React.FC = () => { return false } + const handleUpdateAsset = async ( + name: string, + code: string + ): Promise => { + try { + if (!asset?.id) { + throw new Error('Invalid asset') + } + const isSuccess = await updateAsset(asset.id, { name: name, code: code }) + + if (isSuccess) { + if (id) { + getAssetById(id).then(asset => setAsset(asset)) + } + return true + } + + toastError(MessagesError.errorOccurred) + } catch (error) { + let message + if (error instanceof Error) message = error.message + else message = String(error) + toastError(message) + } + + return false + } + const toastError = (message: string): void => { toast({ title: 'Update logo error!', @@ -135,6 +169,8 @@ export const AssetHome: React.FC = () => { setSelectedFile={setSelectedFile} setChartPeriod={setChartPeriod} handleUploadImage={handleUploadImage} + updatingAsset={updatingAsset} + handleUpdateAsset={handleUpdateAsset} /> )} diff --git a/frontend/src/app/core/pages/cost-center/index.tsx b/frontend/src/app/core/pages/cost-center/index.tsx index 8868b0f4..2ce39564 100644 --- a/frontend/src/app/core/pages/cost-center/index.tsx +++ b/frontend/src/app/core/pages/cost-center/index.tsx @@ -26,7 +26,8 @@ export interface IHorizonData { } export const CostCenter: React.FC = () => { - const [isLargerThanMd] = useMediaQuery('(min-width: 768px)') + const [isLargerThanLg] = useMediaQuery('(min-width: 992px)') + const [sponsorAccount, setSponsorAccount] = useState() const [transactions, setTransactions] = useState() @@ -279,7 +280,7 @@ export const CostCenter: React.FC = () => { { getTransactionData={getTransactionData} /> - {isLargerThanMd && ( + {isLargerThanLg && ( @@ -319,7 +320,7 @@ export const CostCenter: React.FC = () => { )} - {!isLargerThanMd && ( + {!isLargerThanLg && ( {operatingExpensesHelperP1} diff --git a/frontend/src/app/core/pages/role-permissions/index.tsx b/frontend/src/app/core/pages/role-permissions/index.tsx index 92fbf1d0..cd07cbd6 100644 --- a/frontend/src/app/core/pages/role-permissions/index.tsx +++ b/frontend/src/app/core/pages/role-permissions/index.tsx @@ -18,7 +18,7 @@ export interface IChange { } export const RolePermissions: React.FC = () => { - const [isLargerThanMd] = useMediaQuery('(min-width: 768px)') + const [isLargerThanLg] = useMediaQuery('(min-width: 992px)') const [changes, setChanges] = useState([]) const [loading, setLoading] = useState(true) @@ -97,7 +97,7 @@ export const RolePermissions: React.FC = () => { { setChanges={setChanges} /> - {isLargerThanMd && ( + {isLargerThanLg && ( diff --git a/frontend/src/app/core/pages/roles-manage/index.tsx b/frontend/src/app/core/pages/roles-manage/index.tsx index f6b5ad3f..19779340 100644 --- a/frontend/src/app/core/pages/roles-manage/index.tsx +++ b/frontend/src/app/core/pages/roles-manage/index.tsx @@ -12,7 +12,7 @@ import { Sidebar } from 'components/organisms/sidebar' import { RolesManageTemplate } from 'components/templates/roles-manage-template' export const RolesManage: React.FC = () => { - const [isLargerThanMd] = useMediaQuery('(min-width: 768px)') + const [isLargerThanLg] = useMediaQuery('(min-width: 992px)') const { getRoles, @@ -20,11 +20,13 @@ export const RolesManage: React.FC = () => { updateRole, deleteRole, getProfile, + getUserPermissions, creatingRole, updatingRole, roles, loadingRoles, deletingRole, + userPermissions } = useAuth() const toast = useToast() @@ -33,6 +35,10 @@ export const RolesManage: React.FC = () => { getRoles() }, [getRoles]) + useEffect(() => { + getUserPermissions() + }, [getUserPermissions]) + const handleRole = async (name: string, id?: number): Promise => { try { const profile = await getProfile() @@ -112,7 +118,7 @@ export const RolesManage: React.FC = () => { { updatingRole={updatingRole} deletingRole={deletingRole} loadingRoles={loadingRoles} + userPermissions={userPermissions} handleDeleteRole={handleDeleteRole} handleRole={handleRole} /> - {isLargerThanMd && ( + {isLargerThanLg && ( diff --git a/frontend/src/app/core/pages/team-members/index.tsx b/frontend/src/app/core/pages/team-members/index.tsx index ec3970d2..b2432897 100644 --- a/frontend/src/app/core/pages/team-members/index.tsx +++ b/frontend/src/app/core/pages/team-members/index.tsx @@ -11,11 +11,12 @@ import { Sidebar } from 'components/organisms/sidebar' import { TeamMembersTemplate } from 'components/templates/team-members' export const TeamMembers: React.FC = () => { - const [isLargerThanMd] = useMediaQuery('(min-width: 768px)') + const [isLargerThanLg] = useMediaQuery('(min-width: 992px)') const { getAllUsers, editUsersRole, + updateUsername, getRoles, getUserPermissions, users, @@ -24,6 +25,7 @@ export const TeamMembers: React.FC = () => { loadingRoles, userPermissions, loadingUserPermissions, + updatingUsername, } = useAuth() useEffect(() => { @@ -42,6 +44,19 @@ export const TeamMembers: React.FC = () => { return false } + const handleUpdateUsername = async ( + id: number, + name: string + ): Promise => { + const isSuccess = await updateUsername(id, name) + + if (isSuccess) { + getAllUsers() + return true + } + return false + } + useEffect(() => { getAllUsers() getRoles() @@ -52,7 +67,7 @@ export const TeamMembers: React.FC = () => { { - {isLargerThanMd && ( + {isLargerThanLg && ( diff --git a/frontend/src/components/atoms/mob-nav-item/index.tsx b/frontend/src/components/atoms/mob-nav-item/index.tsx index f44b1a74..70f09cf0 100644 --- a/frontend/src/components/atoms/mob-nav-item/index.tsx +++ b/frontend/src/components/atoms/mob-nav-item/index.tsx @@ -13,7 +13,7 @@ export const MobileNav: React.FC = ({ onOpen }: IMobileProps) => { onClick={onOpen} aria-label="open menu" me={4} - display={{ base: 'flex', md: 'none' }} + display={{ base: 'flex', lg: 'none' }} fill="black" _dark={{ fill: 'white' }} icon={} diff --git a/frontend/src/components/molecules/header/index.tsx b/frontend/src/components/molecules/header/index.tsx index 38e932ff..ac3e3df0 100644 --- a/frontend/src/components/molecules/header/index.tsx +++ b/frontend/src/components/molecules/header/index.tsx @@ -65,7 +65,7 @@ export const Header: React.FC = ({ onOpen }) => { h="4.5rem" w="full" align="center" - ps={{ base: 2, md: 12 }} + ps={{ base: 2, lg: 12 }} pe={6} pos="fixed" zIndex={99} diff --git a/frontend/src/components/molecules/sidebar-content/index.tsx b/frontend/src/components/molecules/sidebar-content/index.tsx index 711e414f..d4da01d2 100644 --- a/frontend/src/components/molecules/sidebar-content/index.tsx +++ b/frontend/src/components/molecules/sidebar-content/index.tsx @@ -31,18 +31,18 @@ export const SidebarContent: React.FC = ({ onClose, ...rest }: ISidebarProps) => { - const [isLargerThanMd] = useMediaQuery('(min-width: 768px)') + const [isLargerThanLg] = useMediaQuery('(min-width: 992px)') return ( = ({ h={14} justifyContent="space-between" alignItems="center" - display={{ base: 'flex', md: 'none' }} + display={{ base: 'flex', lg: 'none' }} w="full" pl="2rem" mb="1rem" @@ -93,7 +93,7 @@ export const SidebarContent: React.FC = ({ ))} - {isLargerThanMd && } + {isLargerThanLg && } } @@ -110,7 +110,7 @@ export const SidebarContent: React.FC = ({ > Administration - {!isLargerThanMd && } + {!isLargerThanLg && } = ({ diff --git a/frontend/src/components/organisms/menu-admin-mobile/index.tsx b/frontend/src/components/organisms/menu-admin-mobile/index.tsx index d510a0ce..7c7177dc 100644 --- a/frontend/src/components/organisms/menu-admin-mobile/index.tsx +++ b/frontend/src/components/organisms/menu-admin-mobile/index.tsx @@ -65,7 +65,7 @@ export const MenuAdminMobile: React.FC = ({ selected }) => { } path={`${PathRoute.COST_CENTER}`} /> diff --git a/frontend/src/components/organisms/sidebar/index.tsx b/frontend/src/components/organisms/sidebar/index.tsx index 0b85d3da..103ef633 100644 --- a/frontend/src/components/organisms/sidebar/index.tsx +++ b/frontend/src/components/organisms/sidebar/index.tsx @@ -74,7 +74,7 @@ export const Sidebar: React.FC = ({ children, highlightMenu }) => { onClose()} - display={{ base: 'none', md: 'block' }} + display={{ base: 'none', lg: 'block' }} highlightMenu={highlightMenu} /> = ({ children, highlightMenu }) => { /> - + {children} diff --git a/frontend/src/components/templates/asset-home/components/form-edit-asset/index.tsx b/frontend/src/components/templates/asset-home/components/form-edit-asset/index.tsx new file mode 100644 index 00000000..c11ee468 --- /dev/null +++ b/frontend/src/components/templates/asset-home/components/form-edit-asset/index.tsx @@ -0,0 +1,56 @@ +import { Stack, Input, ButtonGroup, Button } from '@chakra-ui/react' +import { useState } from 'react' + +interface IProps { + asset: Hooks.UseAssetsTypes.IAssetDto + updatingAsset: boolean + handleUpdate(name: string, code: string): void + onClose(): void +} + +export const FormEditAsset: React.FC = ({ + asset, + updatingAsset, + handleUpdate, + onClose, +}) => { + const [name, setName] = useState(asset.name) + const [code, setCode] = useState(asset.code) + + const onSubmit = (): void => { + if (!name || !code) return + + handleUpdate(name, code) + } + + return ( + + setName(event.target.value)} + mt="1rem" + /> + setCode(event.target.value)} + /> + + + + + + ) +} diff --git a/frontend/src/components/templates/asset-home/index.tsx b/frontend/src/components/templates/asset-home/index.tsx index 5e348ea2..e056c95b 100644 --- a/frontend/src/components/templates/asset-home/index.tsx +++ b/frontend/src/components/templates/asset-home/index.tsx @@ -1,4 +1,17 @@ -import { Container, Flex, Tag, Text } from '@chakra-ui/react' +import { + Container, + Flex, + FocusLock, + IconButton, + Popover, + PopoverArrow, + PopoverCloseButton, + PopoverContent, + PopoverTrigger, + Tag, + Text, + useDisclosure, +} from '@chakra-ui/react' import React, { Dispatch, SetStateAction } from 'react' import { havePermission } from 'utils' @@ -8,8 +21,9 @@ import { TooltipsData } from 'utils/constants/tooltips-data' import { formatAccount, toCrypto } from 'utils/formatter' import { AssetImage } from './components/asset-image' +import { FormEditAsset } from './components/form-edit-asset' import { Permissions } from 'components/enums/permissions' -import { LinkIcon, WalletIcon } from 'components/icons' +import { EditIcon, LinkIcon, WalletIcon } from 'components/icons' import { TChartPeriod } from 'components/molecules/chart-period' import { ChartPayments } from '../../molecules/chart-payments' @@ -18,27 +32,34 @@ import { InfoCard } from '../../molecules/info-card' interface IAssetHomeTemplate { loading: boolean loadingChart: boolean + updatingAsset: boolean asset: Hooks.UseAssetsTypes.IAssetDto paymentsAsset: Hooks.UseDashboardsTypes.IAsset | undefined chartPeriod: TChartPeriod - permissions: Hooks.UseAuthTypes.IUserPermission[] | undefined + permissions: Hooks.UseAuthTypes.IUserPermission | undefined selectedFile: File | null setSelectedFile: Dispatch> setChartPeriod: Dispatch> handleUploadImage(): Promise + handleUpdateAsset(name: string, code: string): Promise } export const AssetHomeTemplate: React.FC = ({ asset, loadingChart, paymentsAsset, + updatingAsset, chartPeriod, permissions, selectedFile, setChartPeriod, setSelectedFile, handleUploadImage, + handleUpdateAsset, }) => { + const { onOpen, onClose, isOpen } = useDisclosure() + const firstFieldRef = React.useRef(null) + return ( @@ -57,33 +78,65 @@ export const AssetHomeTemplate: React.FC = ({ - - - {`${asset.name} (${asset.code})`} - - - window.open( - `${STELLAR_EXPERT_ASSET}/${asset.code}-${asset.issuer.key.publicKey}`, - '_blank' - ) - } - > - + + + + {`${asset.name} (${asset.code})`} + + {permissions?.admin && ( + + + } + aria-label="Edit" + /> + + + + + + + + + + )} + + {typesAsset.find(type => type.id === asset.asset_type) + ?.name || ''} + + + + window.open( + `${STELLAR_EXPERT_ASSET}/${asset.code}-${asset.issuer.key.publicKey}`, + '_blank' + ) + } + > + - - {typesAsset.find(type => type.id === asset.asset_type)?.name || - ''} - @@ -131,7 +184,7 @@ export const AssetHomeTemplate: React.FC = ({ } + icon={} value={toCrypto(Number(asset.assetData?.amount || 0))} helper={TooltipsData.totalSupply} /> diff --git a/frontend/src/components/templates/contracts-detail/index.tsx b/frontend/src/components/templates/contracts-detail/index.tsx index dd53e61f..c8a7f7ea 100644 --- a/frontend/src/components/templates/contracts-detail/index.tsx +++ b/frontend/src/components/templates/contracts-detail/index.tsx @@ -30,7 +30,7 @@ interface IContractsDetailTemplate { currentBalance: string history: Hooks.UseContractsTypes.IHistory[] | undefined deposited: number | undefined - userPermissions: Hooks.UseAuthTypes.IUserPermission[] | undefined + userPermissions: Hooks.UseAuthTypes.IUserPermission | undefined currentInVault: string | undefined hasAssetInVault: boolean hasWallet: boolean diff --git a/frontend/src/components/templates/contracts/index.tsx b/frontend/src/components/templates/contracts/index.tsx index fd9f0b59..0f19598d 100644 --- a/frontend/src/components/templates/contracts/index.tsx +++ b/frontend/src/components/templates/contracts/index.tsx @@ -31,7 +31,7 @@ import { Paginator } from 'components/molecules/paginator' interface IContractsTemplate { loading: boolean contracts: Hooks.UseContractsTypes.IContract[] | undefined - userPermissions: Hooks.UseAuthTypes.IUserPermission[] | undefined + userPermissions: Hooks.UseAuthTypes.IUserPermission | undefined currentPage: number totalPages: number changePage(page: number): void diff --git a/frontend/src/components/templates/cost-center/index.tsx b/frontend/src/components/templates/cost-center/index.tsx index 51e305c6..302ba876 100644 --- a/frontend/src/components/templates/cost-center/index.tsx +++ b/frontend/src/components/templates/cost-center/index.tsx @@ -11,7 +11,7 @@ import { IHorizonData } from 'app/core/pages/cost-center' interface ICostCenterTemplate { transactions: Hooks.UseHorizonTypes.ITransactions | undefined - userPermissions: Hooks.UseAuthTypes.IUserPermission[] | undefined + userPermissions: Hooks.UseAuthTypes.IUserPermission | undefined accountData: Hooks.UseHorizonTypes.IAccount | undefined sponsorAccount: string | undefined latestFeeCharged: number | undefined @@ -36,7 +36,7 @@ export const CostCenterTemplate: React.FC = ({ getTransactionsByLink, getTransactionData, }) => { - const [isSmallerThanMd] = useMediaQuery('(max-width: 768px)') + const [isLargerThanLg] = useMediaQuery('(min-width: 992px)') return ( @@ -50,7 +50,7 @@ export const CostCenterTemplate: React.FC = ({ Administration - {isSmallerThanMd && } + {!isLargerThanLg && } = () => { diff --git a/frontend/src/components/templates/profile/index.tsx b/frontend/src/components/templates/profile/index.tsx index 9f6bac35..cd0b5142 100644 --- a/frontend/src/components/templates/profile/index.tsx +++ b/frontend/src/components/templates/profile/index.tsx @@ -26,7 +26,7 @@ interface IProfileTemplate { profile: Hooks.UseAuthTypes.IUserDto | undefined roles: Hooks.UseAuthTypes.IRole[] | undefined loadingRoles: boolean - userPermissions: Hooks.UseAuthTypes.IUserPermission[] | undefined + userPermissions: Hooks.UseAuthTypes.IUserPermission | undefined } export const ProfileTemplate: React.FC = ({ diff --git a/frontend/src/components/templates/role-permissions-template/index.tsx b/frontend/src/components/templates/role-permissions-template/index.tsx index 940db641..7130b521 100644 --- a/frontend/src/components/templates/role-permissions-template/index.tsx +++ b/frontend/src/components/templates/role-permissions-template/index.tsx @@ -26,7 +26,7 @@ import { IChange } from 'app/core/pages/role-permissions' interface IRolePermissionsTemplate { loading: boolean roles: Hooks.UseAuthTypes.IRole[] | undefined - userPermissions: Hooks.UseAuthTypes.IUserPermission[] | undefined + userPermissions: Hooks.UseAuthTypes.IUserPermission | undefined permissions: Hooks.UseAuthTypes.IPermission[] | undefined rolesPermissions: Hooks.UseAuthTypes.IRolePermission[] | undefined updatingRolesPermissions: boolean @@ -47,7 +47,7 @@ export const RolePermissionsTemplate: React.FC = ({ onSubmit, setChanges, }) => { - const [isSmallerThanMd] = useMediaQuery('(max-width: 768px)') + const [isLargerThanLg] = useMediaQuery('(min-width: 992px)') const havePermissionByRole = ( permissionId: number, @@ -95,7 +95,7 @@ export const RolePermissionsTemplate: React.FC = ({ Administration - {isSmallerThanMd && } + {!isLargerThanLg && } handleDeleteRole(id: number, idNewUsersRole: number): Promise } @@ -38,11 +39,12 @@ export const RolesManageTemplate: React.FC = ({ updatingRole, deletingRole, loadingRoles, + userPermissions, handleRole, handleDeleteRole, }) => { const { isOpen, onOpen, onClose } = useDisclosure() - const [isSmallerThanMd] = useMediaQuery('(max-width: 768px)') + const [isLargerThanLg] = useMediaQuery('(min-width: 992px)') return ( <> @@ -69,7 +71,7 @@ export const RolesManageTemplate: React.FC = ({ Administration - {isSmallerThanMd && } + {!isLargerThanLg && } = ({ loading={creatingRole || updatingRole || deletingRole} roles={roles} loadingRoles={loadingRoles} + userPermissions={userPermissions} handleRole={handleRole} handleDeleteRole={handleDeleteRole} /> diff --git a/frontend/src/components/templates/roles-manage-template/item-role/index.tsx b/frontend/src/components/templates/roles-manage-template/item-role/index.tsx index a9ba37dd..9b28bd0e 100644 --- a/frontend/src/components/templates/roles-manage-template/item-role/index.tsx +++ b/frontend/src/components/templates/roles-manage-template/item-role/index.tsx @@ -13,6 +13,7 @@ interface IItemRole { roles: Hooks.UseAuthTypes.IRole[] | undefined loading: boolean loadingRoles: boolean + userPermissions: Hooks.UseAuthTypes.IUserPermission | undefined handleRole(name: string, id?: number): Promise handleDeleteRole(id: number, idNewUsersRole: number): Promise } @@ -22,6 +23,7 @@ export const ItemRole: React.FC = ({ roles, loading, loadingRoles, + userPermissions, handleRole, handleDeleteRole, }) => { @@ -38,7 +40,10 @@ export const ItemRole: React.FC = ({ } = useDisclosure() const isDisabled = (role: Hooks.UseAuthTypes.IRole): boolean => { - return role.admin === 1 || role.created_by != Authentication.getUser()?.id + if (userPermissions?.admin) { + return false + } + return role.created_by != Authentication.getUser()?.id } return ( diff --git a/frontend/src/components/templates/team-members/index.tsx b/frontend/src/components/templates/team-members/index.tsx index 302250d5..9c922a68 100644 --- a/frontend/src/components/templates/team-members/index.tsx +++ b/frontend/src/components/templates/team-members/index.tsx @@ -21,25 +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 roles: Hooks.UseAuthTypes.IRole[] | undefined loadingRoles: boolean - permissions: Hooks.UseAuthTypes.IUserPermission[] | undefined + permissions: Hooks.UseAuthTypes.IUserPermission | undefined + updatingUsername: boolean + handleEditRole(params: Hooks.UseAuthTypes.IUserRole): Promise + handleUpdateUsername(id: number, name: string): Promise } -export const TeamMembersTemplate: React.FC = ({ +export const TeamMembersTemplate: React.FC = ({ users, loading, - handleEditRole, roles, loadingRoles, permissions, + updatingUsername, + handleEditRole, + handleUpdateUsername, }) => { const [isSmallerThanMd] = useMediaQuery('(max-width: 768px)') - const { onOpen } = useDisclosure() + const [isLargerThanLg] = useMediaQuery('(min-width: 992px)') + + const { onOpen: onOpenChangeRole, onOpen: onOpenRename } = useDisclosure() return ( @@ -53,7 +59,7 @@ export const TeamMembersTemplate: React.FC = ({ Administration - {isSmallerThanMd && } + {!isLargerThanLg && } @@ -105,7 +111,11 @@ export const TeamMembersTemplate: React.FC = ({ {`${user.role}`} - + ))} @@ -116,6 +126,7 @@ export const TeamMembersTemplate: React.FC = ({ ID Member Role + @@ -124,10 +135,12 @@ export const TeamMembersTemplate: React.FC = ({ key={index} user={user} loading={loading} - handleEditRole={handleEditRole} roles={roles} loadingRoles={loadingRoles} permissions={permissions} + updatingUsername={updatingUsername} + handleEditRole={handleEditRole} + handleUpdateUsername={handleUpdateUsername} /> ))} diff --git a/frontend/src/components/templates/team-members/item-menu/index.tsx b/frontend/src/components/templates/team-members/item-menu/index.tsx index dd856021..c17b914a 100644 --- a/frontend/src/components/templates/team-members/item-menu/index.tsx +++ b/frontend/src/components/templates/team-members/item-menu/index.tsx @@ -13,11 +13,16 @@ import { Permissions } from 'components/enums/permissions' import { MenuDotsIcon } from 'components/icons' interface IItemMenu { - onOpen(): void - permissions: Hooks.UseAuthTypes.IUserPermission[] | undefined + onOpenChangeRole(): void + onOpenRename(): void + permissions: Hooks.UseAuthTypes.IUserPermission | undefined } -export const ItemMenu: React.FC = ({ onOpen, permissions }) => { +export const ItemMenu: React.FC = ({ + onOpenChangeRole, + onOpenRename, + permissions, +}) => { return ( <> {havePermission(Permissions.EDIT_USERS_ROLE, permissions) && ( @@ -36,7 +41,10 @@ export const ItemMenu: React.FC = ({ onOpen, permissions }) => { icon={} /> - Change role + Change role + {permissions?.admin && ( + Edit username + )} )} diff --git a/frontend/src/components/templates/team-members/item-user/index.tsx b/frontend/src/components/templates/team-members/item-user/index.tsx index 066154a1..0ff96f81 100644 --- a/frontend/src/components/templates/team-members/item-user/index.tsx +++ b/frontend/src/components/templates/team-members/item-user/index.tsx @@ -6,36 +6,57 @@ 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 + updatingUsername: boolean roles: Hooks.UseAuthTypes.IRole[] | undefined loadingRoles: boolean - permissions: Hooks.UseAuthTypes.IUserPermission[] | undefined + permissions: Hooks.UseAuthTypes.IUserPermission | undefined + handleEditRole(params: Hooks.UseAuthTypes.IUserRole): Promise + handleUpdateUsername(id: number, name: string): Promise } export const ItemUser: React.FC = ({ 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 ( <> + {user.id} @@ -43,7 +64,11 @@ export const ItemUser: React.FC = ({ {user.role} { - + } diff --git a/frontend/src/components/templates/team-members/modal-update-username/index.tsx b/frontend/src/components/templates/team-members/modal-update-username/index.tsx new file mode 100644 index 00000000..aa271946 --- /dev/null +++ b/frontend/src/components/templates/team-members/modal-update-username/index.tsx @@ -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 +} + +export const ModalUpdateUsername: React.FC = ({ + isOpen, + user, + updatingUsername, + onClose, + handleUpdateUsername, +}) => { + const [errorSubmit, setErrorSubmit] = useState(null) + const [username, setUsername] = useState(user.name) + const { handleSubmit } = useForm() + + const onSubmit = async (): Promise => { + 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 ( + + + + Edit username + + + + {errorSubmit && ( + + + {errorSubmit} + + )} +
{ + onSubmit() + })} + > + { + setUsername(event.target.value) + }} + w="full" + /> + +
+
+
+
+
+ ) +} diff --git a/frontend/src/components/templates/token-management/index.tsx b/frontend/src/components/templates/token-management/index.tsx index 58590fb4..429c881f 100644 --- a/frontend/src/components/templates/token-management/index.tsx +++ b/frontend/src/components/templates/token-management/index.tsx @@ -43,7 +43,7 @@ import { Filter } from './filter' interface ITokenManagementTemplate { loading: boolean assets: Hooks.UseAssetsTypes.IAssetDto[] | undefined - userPermissions: Hooks.UseAuthTypes.IUserPermission[] | undefined + userPermissions: Hooks.UseAuthTypes.IUserPermission | undefined currentPage: number totalPages: number changePage(page: number): void diff --git a/frontend/src/components/templates/vault-detail/components/distribute/index.tsx b/frontend/src/components/templates/vault-detail/components/distribute/index.tsx index 6f502c16..1bbca68c 100644 --- a/frontend/src/components/templates/vault-detail/components/distribute/index.tsx +++ b/frontend/src/components/templates/vault-detail/components/distribute/index.tsx @@ -38,7 +38,7 @@ interface IDistributeVault { vaults: Hooks.UseVaultsTypes.IVault[] | undefined vault: Hooks.UseVaultsTypes.IVault | undefined selectedAsset: Hooks.UseAssetsTypes.IAssetDto | undefined - userPermissions: Hooks.UseAuthTypes.IUserPermission[] | undefined + userPermissions: Hooks.UseAuthTypes.IUserPermission | undefined } export const DistributeVault: React.FC = ({ diff --git a/frontend/src/components/templates/vault-detail/index.tsx b/frontend/src/components/templates/vault-detail/index.tsx index 0d9ed98e..80836699 100644 --- a/frontend/src/components/templates/vault-detail/index.tsx +++ b/frontend/src/components/templates/vault-detail/index.tsx @@ -28,7 +28,7 @@ interface IVaultDetailTemplate { vaultCategories: Hooks.UseVaultsTypes.IVaultCategory[] | undefined deletingVault: boolean isPrevDisabled: boolean - userPermissions: Hooks.UseAuthTypes.IUserPermission[] | undefined + userPermissions: Hooks.UseAuthTypes.IUserPermission | undefined loadingUserPermissions: boolean onSubmit( amount: string, diff --git a/frontend/src/hooks/useAssets/context.tsx b/frontend/src/hooks/useAssets/context.tsx index c6f349df..046ad787 100644 --- a/frontend/src/hooks/useAssets/context.tsx +++ b/frontend/src/hooks/useAssets/context.tsx @@ -18,6 +18,7 @@ export const AssetsProvider: React.FC = ({ children }) => { const [loadingAssets, setLoadingAssets] = useState(true) const [loadingAsset, setLoadingAsset] = useState(true) const [loadingOperation, setLoadingOperation] = useState(false) + const [updatingAsset, setUpdatingAsset] = useState(false) const [assets, setAssets] = useState< Hooks.UseAssetsTypes.IAssetDto[] | undefined >() @@ -369,6 +370,24 @@ export const AssetsProvider: React.FC = ({ children }) => { } } + const updateAsset = async ( + id: number, + params: Hooks.UseAssetsTypes.IAssetUpdate + ): Promise => { + setUpdatingAsset(true) + try { + const response = await http.put(`/assets/${id}/update-name-code`, params) + return response.status === 200 + } catch (error) { + if (axios.isAxiosError(error)) { + throw new Error(error.message) + } + throw new Error(MessagesError.errorOccurred) + } finally { + setUpdatingAsset(false) + } + } + return ( = ({ children }) => { loadingAsset, loadingOperation, assets, + updatingAsset, mint, burn, distribute, @@ -391,6 +411,7 @@ export const AssetsProvider: React.FC = ({ children }) => { updateImage, updateContractId, getPagedAssets, + updateAsset, }} > {children} diff --git a/frontend/src/hooks/useAssets/use-assets-types.d.ts b/frontend/src/hooks/useAssets/use-assets-types.d.ts index d61362c5..b1fcc085 100644 --- a/frontend/src/hooks/useAssets/use-assets-types.d.ts +++ b/frontend/src/hooks/useAssets/use-assets-types.d.ts @@ -142,10 +142,16 @@ declare namespace Hooks { freeze_enabled?: boolean } + interface IAssetUpdate { + name: string + code: string + } + interface IAssetsContext { loadingOperation: boolean loadingAssets: boolean loadingAsset: boolean + updatingAsset: boolean assets: IAssetDto[] | undefined mint: (params: IMintRequest) => Promise burn: (params: IBurnRequest) => Promise @@ -169,6 +175,7 @@ declare namespace Hooks { limit: number filters?: IFilter }) => Promise + updateAsset: (id: number, params: IAssetUpdate) => Promise } } } diff --git a/frontend/src/hooks/useAuth/context.tsx b/frontend/src/hooks/useAuth/context.tsx index 8511a34d..0152fb3a 100644 --- a/frontend/src/hooks/useAuth/context.tsx +++ b/frontend/src/hooks/useAuth/context.tsx @@ -18,6 +18,7 @@ export const AuthProvider: React.FC = ({ children }) => { Authentication.getUser() ) const [loading, setLoading] = useState(false) + const [updatingUsername, setUpdatingUsername] = useState(false) const [loadingUserPermissions, setLoadingUserPermissions] = useState(true) const [updatingRolesPermissions, setUpdatingRolesPermissions] = useState(false) @@ -33,7 +34,7 @@ export const AuthProvider: React.FC = ({ children }) => { Hooks.UseAuthTypes.IUserDto | undefined >() const [userPermissions, setUserPermissions] = useState< - Hooks.UseAuthTypes.IUserPermission[] | undefined + Hooks.UseAuthTypes.IUserPermission | undefined >() const [rolesPermissions, setRolesPermissions] = useState< Hooks.UseAuthTypes.IRolePermission[] | undefined @@ -203,7 +204,7 @@ export const AuthProvider: React.FC = ({ children }) => { }, [getAccountData]) const getUserPermissions = useCallback(async (): Promise< - Hooks.UseAuthTypes.IUserPermission[] | undefined + Hooks.UseAuthTypes.IUserPermission | undefined > => { setLoadingUserPermissions(true) try { @@ -369,6 +370,25 @@ export const AuthProvider: React.FC = ({ children }) => { } } + const updateUsername = async (id: number, name: string): Promise => { + 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 ( @@ -389,6 +409,7 @@ export const AuthProvider: React.FC = ({ children }) => { createRole, updateRole, deleteRole, + updateUsername, isAuthenticated, loading, loadingRoles, @@ -403,6 +424,7 @@ export const AuthProvider: React.FC = ({ children }) => { updatingRole, deletingRole, loadingUserPermissions, + updatingUsername, }} > {children} diff --git a/frontend/src/hooks/useAuth/use-auth-types.d.ts b/frontend/src/hooks/useAuth/use-auth-types.d.ts index 3a520376..1a3c723c 100644 --- a/frontend/src/hooks/useAuth/use-auth-types.d.ts +++ b/frontend/src/hooks/useAuth/use-auth-types.d.ts @@ -46,8 +46,8 @@ declare namespace Hooks { } interface IUserPermission { - name: string - action: string + admin: boolean + permissions: { name: string; action: string }[] } interface IRolePermission { @@ -70,7 +70,7 @@ declare namespace Hooks { getProfile: () => Promise editUsersRole: (params: IUserRole) => Promise getUserPermissions: () => Promise< - Hooks.UseAuthTypes.IUserPermission[] | undefined + Hooks.UseAuthTypes.IUserPermission | undefined > getRolesPermissions: () => Promise< Hooks.UseAuthTypes.IRolePermission[] | undefined @@ -84,6 +84,7 @@ declare namespace Hooks { ) => Promise createRole: (userId: number, name: string) => Promise updateRole: (id: number, name: string) => Promise + updateUsername: (id: number, name: string) => Promise deleteRole: (id: number, idNewUsersRole: number) => Promise isAuthenticated: boolean loading: boolean @@ -91,7 +92,7 @@ declare namespace Hooks { roles: IRole[] | undefined users: IUserDto[] | undefined profile: IUserDto | undefined - userPermissions: IUserPermission[] | undefined + userPermissions: IUserPermission | undefined rolesPermissions: IRolePermission[] | undefined permissions: IPermission[] | undefined updatingRolesPermissions: boolean @@ -99,6 +100,7 @@ declare namespace Hooks { updatingRole: boolean deletingRole: boolean loadingUserPermissions: boolean + updatingUsername: boolean } } } diff --git a/frontend/src/utils/index.tsx b/frontend/src/utils/index.tsx index 63c9d231..1a48704d 100644 --- a/frontend/src/utils/index.tsx +++ b/frontend/src/utils/index.tsx @@ -6,12 +6,12 @@ export const isDark = (colorMode: 'dark' | 'light'): boolean => { export const havePermission = ( permission: Permissions, - permissions: Hooks.UseAuthTypes.IUserPermission[] | undefined + userPermission: Hooks.UseAuthTypes.IUserPermission | undefined ): boolean => { - if (!permissions) return false + if (userPermission?.admin) return true + if (!userPermission) return false return ( - permissions.filter( - (item: Hooks.UseAuthTypes.IUserPermission) => item.action === permission - ).length > 0 + userPermission.permissions.filter(item => item.action === permission) + .length > 0 ) }