Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add addOns route and actions role guard #1509

Merged
merged 2 commits into from
May 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
117 changes: 63 additions & 54 deletions src/components/addOns/AddOnItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,16 @@ gql`
interface AddOnItemProps {
addOn: AddOnItemFragment
deleteDialogRef: RefObject<DeleteAddOnDialogRef>
shouldShowItemActions: boolean
navigationProps?: ListKeyNavigationItemProps
}

export const AddOnItem = ({ addOn, deleteDialogRef, navigationProps }: AddOnItemProps) => {
export const AddOnItem = ({
addOn,
deleteDialogRef,
navigationProps,
shouldShowItemActions,
}: AddOnItemProps) => {
const { id: addOnId, name, amountCurrency, amountCents, customersCount, createdAt } = addOn

const { translate } = useInternationalization()
Expand Down Expand Up @@ -83,61 +89,64 @@ export const AddOnItem = ({ addOn, deleteDialogRef, navigationProps }: AddOnItem
</Typography>
</NameBlock>
</AddOnNameSection>
<CouponInfosSection>
<CouponInfosSection $shouldShowItemActions={shouldShowItemActions}>
<SmallCell>{customersCount}</SmallCell>
<MediumCell>{formatTimeOrgaTZ(createdAt)}</MediumCell>
</CouponInfosSection>
<ButtonMock />
{shouldShowItemActions && <ButtonMock />}
</ListItemLink>
<Popper
PopperProps={{ placement: 'bottom-end' }}
opener={({ isOpen }) => (
// eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions
<PopperOpener>
<Tooltip
placement="top-end"
disableHoverListener={isOpen}
title={translate('text_629728388c4d2300e2d3810d')}
>
<Button icon="dots-horizontal" variant="quaternary" />
</Tooltip>
</PopperOpener>
)}
>
{({ closePopper }) => (
<MenuPopper>
<ButtonLink
to={generatePath(UPDATE_ADD_ON_ROUTE, { addOnId })}
type="button"
buttonProps={{
variant: 'quaternary',
startIcon: 'pen',
align: 'left',
fullWidth: true,
}}
>
{translate('text_629728388c4d2300e2d3816a')}
</ButtonLink>
<Button
startIcon="trash"
variant="quaternary"
align="left"
fullWidth
onClick={() => {
deleteDialogRef.current?.openDialog({
addOn,
callback: () => {
navigate(ADD_ONS_ROUTE)
},
})
closePopper()
}}
>
{translate('text_629728388c4d2300e2d38182')}
</Button>
</MenuPopper>
)}
</Popper>

{shouldShowItemActions && (
<Popper
PopperProps={{ placement: 'bottom-end' }}
opener={({ isOpen }) => (
// eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions
<PopperOpener>
<Tooltip
placement="top-end"
disableHoverListener={isOpen}
title={translate('text_629728388c4d2300e2d3810d')}
>
<Button icon="dots-horizontal" variant="quaternary" />
</Tooltip>
</PopperOpener>
)}
>
{({ closePopper }) => (
<MenuPopper>
<ButtonLink
to={generatePath(UPDATE_ADD_ON_ROUTE, { addOnId })}
type="button"
buttonProps={{
variant: 'quaternary',
startIcon: 'pen',
align: 'left',
fullWidth: true,
}}
>
{translate('text_629728388c4d2300e2d3816a')}
</ButtonLink>
<Button
startIcon="trash"
variant="quaternary"
align="left"
fullWidth
onClick={() => {
deleteDialogRef.current?.openDialog({
addOn,
callback: () => {
navigate(ADD_ONS_ROUTE)
},
})
closePopper()
}}
>
{translate('text_629728388c4d2300e2d38182')}
</Button>
</MenuPopper>
)}
</Popper>
)}
</ItemContainer>
)
}
Expand Down Expand Up @@ -167,9 +176,9 @@ const NameBlock = styled.div`
min-width: 0;
`

const CouponInfosSection = styled.div`
const CouponInfosSection = styled.div<{ $shouldShowItemActions: boolean }>`
display: flex;
margin-right: ${theme.spacing(6)};
margin-right: ${({ $shouldShowItemActions }) => ($shouldShowItemActions ? theme.spacing(6) : 0)};

> *:not(:last-child) {
margin-right: ${theme.spacing(6)};
Expand Down
6 changes: 3 additions & 3 deletions src/components/plans/PlanItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ export const PlanItem = memo(
</Typography>
</NameBlock>
</PlanNameSection>
<PlanInfosSection>
<PlanInfosSection $shouldShowItemActions={shouldShowItemActions}>
<MediumCell>{activeSubscriptionsCount}</MediumCell>
<SmallCell>{chargesCount}</SmallCell>
<MediumCell>{formatTimeOrgaTZ(createdAt)}</MediumCell>
Expand Down Expand Up @@ -186,9 +186,9 @@ const PlanNameSection = styled.div`
min-width: 0;
`

const PlanInfosSection = styled.div`
const PlanInfosSection = styled.div<{ $shouldShowItemActions?: boolean }>`
display: flex;
margin-right: ${theme.spacing(6)};
margin-right: ${({ $shouldShowItemActions }) => ($shouldShowItemActions ? theme.spacing(6) : 0)};

> *:not(:last-child) {
margin-right: ${theme.spacing(6)};
Expand Down
2 changes: 2 additions & 0 deletions src/core/router/ObjectsRoutes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ export const objectListRoutes: CustomRouteObject[] = [
path: ADD_ONS_ROUTE,
private: true,
element: <AddOnsList />,
permissions: ['addonsView'],
},
{
path: [INVOICES_ROUTE, INVOICES_TAB_ROUTE],
Expand All @@ -131,6 +132,7 @@ export const objectCreationRoutes: CustomRouteObject[] = [
path: [CREATE_ADD_ON_ROUTE, UPDATE_ADD_ON_ROUTE],
private: true,
element: <CreateAddOn />,
permissions: ['addonsCreate', 'addonsUpdate'],
},
{
path: [CREATE_COUPON_ROUTE, UPDATE_COUPON_ROUTE],
Expand Down
67 changes: 37 additions & 30 deletions src/pages/AddOnDetails.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { ADD_ONS_ROUTE, UPDATE_ADD_ON_ROUTE } from '~/core/router'
import { deserializeAmount } from '~/core/serializers/serializeAmount'
import { CurrencyEnum, useGetAddOnForDetailsQuery } from '~/generated/graphql'
import { useInternationalization } from '~/hooks/core/useInternationalization'
import { usePermissions } from '~/hooks/usePermissions'
import { MenuPopper, PageHeader, theme } from '~/styles'
import { DetailsInfoGrid, DetailsSectionTitle } from '~/styles/detailsPage'

Expand All @@ -35,6 +36,7 @@ gql`

const AddOnDetails = () => {
const navigate = useNavigate()
const { hasPermissions } = usePermissions()
const { translate } = useInternationalization()
const { addOnId } = useParams()

Expand All @@ -58,6 +60,8 @@ const AddOnDetails = () => {
},
)

const shouldShowActions = hasPermissions(['addonsCreate', 'addonsUpdate', 'addonsDelete'])

return (
<>
<PageHeader $withSide>
Expand All @@ -80,44 +84,47 @@ const AddOnDetails = () => {
)}
<Typography variant="bodyHl" color="textSecondary" noWrap></Typography>
</HeaderInlineBreadcrumbBlock>
<Popper
PopperProps={{ placement: 'bottom-end' }}
opener={
<Button endIcon="chevron-down">{translate('text_626162c62f790600f850b6fe')}</Button>
}
>
{({ closePopper }) => (
<MenuPopper>
<Button
variant="quaternary"
align="left"
onClick={() => {
navigate(generatePath(UPDATE_ADD_ON_ROUTE, { addOnId: addOnId as string }))
closePopper()
}}
>
{translate('text_625fd39a15394c0117e7d792')}
</Button>
{addOn && (

{shouldShowActions && (
<Popper
PopperProps={{ placement: 'bottom-end' }}
opener={
<Button endIcon="chevron-down">{translate('text_626162c62f790600f850b6fe')}</Button>
}
>
{({ closePopper }) => (
<MenuPopper>
<Button
variant="quaternary"
align="left"
onClick={() => {
deleteDialogRef.current?.openDialog({
addOn,
callback: () => {
navigate(ADD_ONS_ROUTE)
},
})
navigate(generatePath(UPDATE_ADD_ON_ROUTE, { addOnId: addOnId as string }))
closePopper()
}}
>
{translate('text_629728388c4d2300e2d38182')}
{translate('text_625fd39a15394c0117e7d792')}
</Button>
)}
</MenuPopper>
)}
</Popper>
{addOn && (
<Button
variant="quaternary"
align="left"
onClick={() => {
deleteDialogRef.current?.openDialog({
addOn,
callback: () => {
navigate(ADD_ONS_ROUTE)
},
})
closePopper()
}}
>
{translate('text_629728388c4d2300e2d38182')}
</Button>
)}
</MenuPopper>
)}
</Popper>
)}
</PageHeader>

{isAddOnLoading ? (
Expand Down
14 changes: 10 additions & 4 deletions src/pages/AddOnsList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { AddOnItemFragmentDoc, useAddOnsLazyQuery } from '~/generated/graphql'
import { useInternationalization } from '~/hooks/core/useInternationalization'
import { useListKeysNavigation } from '~/hooks/ui/useListKeyNavigation'
import { useDebouncedSearch } from '~/hooks/useDebouncedSearch'
import { usePermissions } from '~/hooks/usePermissions'
import EmptyImage from '~/public/images/maneki/empty.svg'
import ErrorImage from '~/public/images/maneki/error.svg'
import { ListContainer, ListHeader, PageHeader, theme } from '~/styles'
Expand All @@ -37,6 +38,7 @@ gql`
const AddOnsList = () => {
const { translate } = useInternationalization()
let navigate = useNavigate()
const { hasPermissions } = usePermissions()
const deleteDialogRef = useRef<DeleteAddOnDialogRef>(null)
const { onKeyDown } = useListKeysNavigation({
getElmId: (i) => `add-on-item-${i}`,
Expand All @@ -51,6 +53,7 @@ const AddOnsList = () => {
const { debouncedSearch, isLoading } = useDebouncedSearch(getAddOns, loading)
const list = data?.addOns?.collection || []
let index = -1
const shouldShowItemActions = hasPermissions(['addonsCreate', 'addonsUpdate', 'addonsDelete'])

return (
<div role="grid" tabIndex={-1} onKeyDown={onKeyDown}>
Expand All @@ -63,14 +66,16 @@ const AddOnsList = () => {
onChange={debouncedSearch}
placeholder={translate('text_63bee4e10e2d53912bfe4db8')}
/>
<ButtonLink type="button" to={CREATE_ADD_ON_ROUTE} data-test="create-addon-cta">
{translate('text_629728388c4d2300e2d38085')}
</ButtonLink>
{hasPermissions(['addonsCreate']) && (
<ButtonLink type="button" to={CREATE_ADD_ON_ROUTE} data-test="create-addon-cta">
{translate('text_629728388c4d2300e2d38085')}
</ButtonLink>
)}
</HeaderRigthBlock>
</Header>

<ListContainer>
<ListHead $withActions>
<ListHead $withActions={shouldShowItemActions}>
<NameSection>
<Typography color="disabled" variant="bodyHl">
{translate('text_629728388c4d2300e2d380bd')}
Expand Down Expand Up @@ -151,6 +156,7 @@ const AddOnsList = () => {
key={addOn.id}
addOn={addOn}
deleteDialogRef={deleteDialogRef}
shouldShowItemActions={shouldShowItemActions}
navigationProps={{
id: `add-on-item-${index}`,
'data-id': addOn.id,
Expand Down
Loading