Skip to content

Commit

Permalink
Add RoleDetails component and integrate into SafeRoleDetailsPage for …
Browse files Browse the repository at this point in the history
…enhanced role management
  • Loading branch information
Da-Colon committed Dec 4, 2024
1 parent 27a1595 commit 4309d6c
Show file tree
Hide file tree
Showing 3 changed files with 246 additions and 35 deletions.
238 changes: 238 additions & 0 deletions src/components/Roles/RoleDetails.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,238 @@
import { Badge, Box, Flex, Grid, GridItem, Icon, Text } from '@chakra-ui/react';
import { CheckSquare, List, User } from '@phosphor-icons/react';
import { RefObject, useMemo, useRef } from 'react';
import { useTranslation } from 'react-i18next';
import { useNavigate } from 'react-router-dom';
import PencilWithLineIcon from '../../assets/theme/custom/icons/PencilWithLineIcon';
import { DAO_ROUTES } from '../../constants/routes';
import useAddress from '../../hooks/utils/useAddress';
import useAvatar from '../../hooks/utils/useAvatar';
import { useCanUserCreateProposal } from '../../hooks/utils/useCanUserSubmitProposal';
import { useCopyText } from '../../hooks/utils/useCopyText';
import { useGetAccountName } from '../../hooks/utils/useGetAccountName';
import { useNetworkConfig } from '../../providers/NetworkConfig/NetworkConfigProvider';
import { useDaoInfoStore } from '../../store/daoInfo/useDaoInfoStore';
import {
paymentSorterByActiveStatus,
paymentSorterByStartDate,
paymentSorterByWithdrawAmount,
} from '../../store/roles/rolesStoreUtils';
import {
RoleDetailsDrawerEditingRoleHatProp,
RoleDetailsDrawerRoleHatProp,
} from '../../types/roles';
import { BarLoader } from '../ui/loaders/BarLoader';
import ModalTooltip from '../ui/modals/ModalTooltip';
import Avatar from '../ui/page/Header/Avatar';
import PageHeader from '../ui/page/Header/PageHeader';
import Markdown from '../ui/proposal/Markdown';
import Divider from '../ui/utils/Divider';
import RoleDetailsTabs from './RoleDetailsTabs';

export function RoleProposalPermissionBadge({
containerRef,
}: {
containerRef: RefObject<HTMLDivElement>;
}) {
const { t } = useTranslation('roles');
return (
<ModalTooltip
containerRef={containerRef}
label={t('permissionsProposalsTooltip')}
>
<Badge
color="celery-0"
bgColor="celery--6"
textTransform="unset"
fontSize="1rem"
lineHeight="1.5rem"
fontWeight="normal"
borderRadius="0.25rem"
px="0.5rem"
>
{t('permissionsProposals')}
</Badge>
</ModalTooltip>
);
}
function RoleAndDescriptionLabel({ label, icon }: { label: string; icon: React.ElementType }) {
return (
<Flex
gap="0.5rem"
alignItems="center"
>
<Icon as={icon} />
<Text
textStyle="labels-large"
color="neutral-7"
>
{label}
</Text>
</Flex>
);
}

export default function RolesDetails({
roleHat,
}: {
roleHat: RoleDetailsDrawerRoleHatProp | RoleDetailsDrawerEditingRoleHatProp;
}) {
const { safe } = useDaoInfoStore();
const navigate = useNavigate();
const { addressPrefix } = useNetworkConfig();
const permissionsContainerRef = useRef<HTMLDivElement>(null);

const roleHatWearer = 'wearer' in roleHat ? roleHat.wearer : roleHat.wearerAddress;

const { address: roleHatWearerAddress, isLoading: loadingRoleHatWearerAddress } =
useAddress(roleHatWearer);

const { displayName } = useGetAccountName(roleHatWearerAddress);

const { t } = useTranslation(['roles']);
const avatarURL = useAvatar(roleHatWearer);

const sortedPayments = useMemo(
() =>
roleHat.payments
? [...roleHat.payments]
.sort(paymentSorterByWithdrawAmount)
.sort(paymentSorterByStartDate)
.sort(paymentSorterByActiveStatus)
: [],
[roleHat.payments],
);

const { canUserCreateProposal } = useCanUserCreateProposal();
const copyToClipboard = useCopyText();

if (!safe?.address) return null;

return (
<>
<PageHeader
breadcrumbs={[
{
terminus: t('roles'),
path: DAO_ROUTES.roles.relative(addressPrefix, safe.address),
},
{
terminus: roleHat.name,
path: '',
},
]}
buttonProps={
canUserCreateProposal
? {
variant: 'secondary',
size: 'sm',
leftIcon: (
<Box mr="-0.25rem">
<PencilWithLineIcon
w="1rem"
h="1rem"
/>
</Box>
),
gap: 0,
children: t('editRoles'),
onClick: () => navigate(DAO_ROUTES.rolesEdit.relative(addressPrefix, safe.address)),
}
: undefined
}
/>
<Text
textStyle="heading-large"
color="white-0"
my="1rem"
>
{roleHat.name}
</Text>
<Grid
gridTemplateAreas={`
"mLabel mValue"
"dLabel dValue"
"pLabel pValue"
`}
gridRowGap="1rem"
gridColumnGap="2rem"
alignItems="center"
>
<GridItem area="mLabel">
<RoleAndDescriptionLabel
label={t('member')}
icon={User}
/>
</GridItem>
<GridItem area="dLabel">
<RoleAndDescriptionLabel
label={t('description')}
icon={List}
/>
</GridItem>
<GridItem area="pLabel">
{roleHat.canCreateProposals && (
<RoleAndDescriptionLabel
label={t('permissions')}
icon={CheckSquare}
/>
)}
</GridItem>
<GridItem area="mValue">
<Flex
alignItems="center"
gap="0.5rem"
p="0.25rem 0.5rem"
ml="-0.75rem"
rounded="1rem"
bg="neutral-3"
color="lilac-0"
_hover={{
color: 'white-0',
bg: 'neutral-4',
}}
cursor="pointer"
maxW="fit-content"
onClick={() => copyToClipboard(roleHatWearerAddress)}
>
{loadingRoleHatWearerAddress || !roleHatWearerAddress ? (
<BarLoader />
) : (
<Avatar
size="icon"
address={roleHatWearerAddress}
url={avatarURL}
/>
)}
<Text>{displayName}</Text>
</Flex>
</GridItem>
<GridItem area="dValue">
<Markdown
content={roleHat.description}
collapsedLines={100}
/>
</GridItem>
<GridItem
area="pValue"
ref={permissionsContainerRef}
>
{roleHat.canCreateProposals && (
<RoleProposalPermissionBadge containerRef={permissionsContainerRef} />
)}
</GridItem>
</Grid>
<Divider
variant="darker"
my={4}
/>
<RoleDetailsTabs
hatId={roleHat.id}
roleHatSmartAccountAddress={roleHat.smartAddress}
roleTerms={roleHat.roleTerms}
roleHatWearerAddress={roleHatWearerAddress}
sortedPayments={sortedPayments}
/>
</>
);
}
38 changes: 4 additions & 34 deletions src/pages/dao/roles/details/SafeRoleDetailsPage.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,11 @@
import { Show } from '@chakra-ui/react';
import { useNavigate, useSearchParams } from 'react-router-dom';
import RolesDetailsDrawer from '../../../../components/Roles/RolesDetailsDrawer';
import RolesDetailsDrawerMobile from '../../../../components/Roles/RolesDetailsDrawerMobile';
import { DAO_ROUTES } from '../../../../constants/routes';
import { useNetworkConfig } from '../../../../providers/NetworkConfig/NetworkConfigProvider';
import { useSearchParams } from 'react-router-dom';
import RolesDetails from '../../../../components/Roles/RoleDetails';

import { useDaoInfoStore } from '../../../../store/daoInfo/useDaoInfoStore';
import { useRolesStore } from '../../../../store/roles/useRolesStore';

export function SafeRoleDetailsPage() {
const { safe } = useDaoInfoStore();
const navigate = useNavigate();
const { addressPrefix } = useNetworkConfig();

const { hatsTree } = useRolesStore();
const [searchParams] = useSearchParams();
Expand All @@ -21,31 +16,6 @@ export function SafeRoleDetailsPage() {
// @todo add logic for loading
// @todo add redirect for hat not found
if (!roleHat || !safeAddress) return null;
const handleDrawerClose = () => {
navigate(DAO_ROUTES.roles.relative(addressPrefix, safeAddress), { replace: true });
};

const handleEditRoleClick = () => {
navigate(DAO_ROUTES.rolesEditDetails.relative(addressPrefix, safeAddress, roleHat.id), {
replace: true,
});
};
return (
<>
<Show below="md">
<RolesDetailsDrawerMobile
roleHat={{ ...roleHat, wearer: roleHat.wearerAddress }}
onClose={handleDrawerClose}
onEdit={handleEditRoleClick}
/>
</Show>
<Show above="md">
<RolesDetailsDrawer
roleHat={{ ...roleHat, wearer: roleHat.wearerAddress }}
onClose={handleDrawerClose}
onEdit={handleEditRoleClick}
/>
</Show>
</>
);
return <RolesDetails roleHat={{ ...roleHat, wearer: roleHat.wearerAddress }} />;
}
5 changes: 4 additions & 1 deletion src/router.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,11 @@ export const router = (addressPrefix: string, daoAddress: string | undefined) =>
},
{
path: DAO_ROUTES.roles.path,
element: <SafeRolesPage />,
children: [
{
index: true,
element: <SafeRolesPage />,
},
{
path: 'details',
element: <SafeRoleDetailsPage />,
Expand Down

0 comments on commit 4309d6c

Please sign in to comment.