Skip to content

Commit

Permalink
Add Drawer header story
Browse files Browse the repository at this point in the history
  • Loading branch information
gustavlrsn committed Jul 4, 2024
1 parent 4c67f73 commit b50dc9e
Show file tree
Hide file tree
Showing 8 changed files with 263 additions and 59 deletions.
15 changes: 9 additions & 6 deletions .storybook/preview.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { RouterContext } from 'next/dist/shared/lib/router-context.shared-runtim
import { Toaster } from '../components/ui/Toaster';
import { TooltipProvider } from '../components/ui/Tooltip';
import UserProvider from '../components/UserProvider';
import { ModalProvider } from '../components/ModalContext';

import 'react-pdf/dist/esm/Page/TextLayer.css';
import 'react-pdf/dist/esm/Page/AnnotationLayer.css';
Expand All @@ -33,12 +34,14 @@ export const decorators = [
<ApolloProvider client={initClient()}>
<ThemeProvider theme={theme}>
<IntlProvider locale="en">
<UserProvider>
<TooltipProvider>
<Story />
<Toaster />
</TooltipProvider>
</UserProvider>
<ModalProvider>
<UserProvider>
<TooltipProvider>
<Story />
<Toaster />
</TooltipProvider>
</UserProvider>
</ModalProvider>
</IntlProvider>
</ThemeProvider>
</ApolloProvider>
Expand Down
28 changes: 20 additions & 8 deletions components/DrawerHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,26 @@ import clsx from 'clsx';
import { MoreHorizontal, X } from 'lucide-react';
import { FormattedMessage } from 'react-intl';

import type { Action } from '../lib/actions/types';
import { useWindowResize, VIEWPORTS } from '../lib/hooks/useWindowResize';

import { DropdownActionItem } from './table/RowActionsMenu';
import { Button } from './ui/Button';
import { DropdownMenu, DropdownMenuContent, DropdownMenuSeparator, DropdownMenuTrigger } from './ui/DropdownMenu';
import { SheetClose } from './ui/Sheet';

export default function DrawerHeader({ actions, entityName, entityIdentifier, entityLabel, dropdownTriggerRef }) {
type DrawerHeaderProps = {
actions?: {
primary?: Action[];
secondary?: Action[];
};
entity: React.ReactNode;
identifier: React.ReactNode;
label: React.ReactNode;
dropdownTriggerRef?: React.RefObject<HTMLButtonElement>;
};

export default function DrawerHeader({ actions, entity, identifier, label, dropdownTriggerRef }: DrawerHeaderProps) {
const { viewport } = useWindowResize();
const isMobile = viewport === VIEWPORTS.XSMALL;
const { primary, secondary } = actions || {};
Expand All @@ -20,9 +32,9 @@ export default function DrawerHeader({ actions, entityName, entityIdentifier, en
<div className="flex flex-col gap-1 border-b px-6 py-4">
<div className={clsx('flex items-center justify-between gap-4')}>
<div className="flex shrink grow items-center gap-1 text-sm text-muted-foreground">
<span className="whitespace-nowrap">{entityName}</span>
<span className="whitespace-nowrap">{entity}</span>

<div className="w-0 max-w-fit flex-1">{entityIdentifier}</div>
<div className="w-0 max-w-fit flex-1">{identifier}</div>
</div>

<div className="flex items-center gap-1">
Expand All @@ -37,14 +49,14 @@ export default function DrawerHeader({ actions, entityName, entityIdentifier, en
</div>
</div>
<div className="flex justify-between">
<div className="flex items-center gap-2">{entityLabel}</div>
<div className="flex items-center gap-2 text-xl font-semibold">{label}</div>

<div className="flex items-center gap-1">
<div className="hidden items-center gap-1 sm:flex">
{primary?.map(action => (
<Button
key={action.label}
variant="outline"
key={action.key}
variant={action.variant || 'outline'}

Check failure on line 59 in components/DrawerHeader.tsx

View workflow job for this annotation

GitHub Actions / typescript

Type 'string' is not assignable to type '"secondary" | "link" | "default" | "outline" | "destructive" | "outlineDestructive" | "ghost"'.
size="xs"
className="gap-1.5"
onClick={action.onClick}
Expand All @@ -67,11 +79,11 @@ export default function DrawerHeader({ actions, entityName, entityIdentifier, en
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
{isMobile && primary?.map(action => <DropdownActionItem key={action.label} action={action} />)}
{isMobile && primary?.map(action => <DropdownActionItem key={action.key} action={action} />)}

{isMobile && primary.length > 0 && secondary.length > 0 && <DropdownMenuSeparator />}

{secondary?.map(action => <DropdownActionItem key={action.label} action={action} />)}
{secondary?.map(action => <DropdownActionItem key={action.key} action={action} />)}
</DropdownMenuContent>
</DropdownMenu>
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 +84,9 @@ export default function LegalDocumentDrawer({
<DrawerHeader
dropdownTriggerRef={dropdownTriggerRef}
actions={getActions(document, dropdownTriggerRef)}
entityName={intl.formatMessage({ defaultMessage: 'Tax form', id: 'TaxForm' })}
entityIdentifier={<CopyID value={document.id}>{document.id}</CopyID>}
entityLabel={
entity={intl.formatMessage({ defaultMessage: 'Tax form', id: 'TaxForm' })}
identifier={<CopyID value={document.id}>{document.id}</CopyID>}
label={
<AccountHoverCard
account={document.account}
trigger={
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ export const TransactionsImportRowDrawer = ({
<React.Fragment>
<DrawerHeader
actions={getActions(row, dropdownTriggerRef)}
entityName={<FormattedMessage defaultMessage="Transaction import row" id="qqPBY/" />}
entityLabel={
entity={<FormattedMessage defaultMessage="Transaction import row" id="qqPBY/" />}
label={
<div className="text-2xl">
<span className={'font-bold text-foreground'}>
<FormattedMoneyAmount
Expand All @@ -50,7 +50,7 @@ export const TransactionsImportRowDrawer = ({
</div>
}
dropdownTriggerRef={dropdownTriggerRef}
entityIdentifier={
identifier={
<FormattedMessage defaultMessage="No. {number}" id="rowNumber" values={{ number: rowIndex + 1 }} />
}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -265,13 +265,13 @@ function TransactionDetails({ transactionId, getActions }: TransactionDetailsPro
<DrawerHeader
actions={actions}
dropdownTriggerRef={dropdownTriggerRef}
entityName={<FormattedMessage defaultMessage="Transaction" id="1+ROfp" />}
entityIdentifier={
entity={<FormattedMessage defaultMessage="Transaction" id="1+ROfp" />}
identifier={
<CopyID value={id} tooltipLabel={<FormattedMessage defaultMessage="Copy transaction ID" id="zzd7ZI" />}>
#{id}
</CopyID>
}
entityLabel={
label={
<React.Fragment>
{loading ? (
<Skeleton className="h-8 w-48" />
Expand All @@ -286,8 +286,7 @@ function TransactionDetails({ transactionId, getActions }: TransactionDetailsPro
amountStyles={{ letterSpacing: 0 }}
showCurrencyCode={false}
/>
</span>

</span>{' '}
<span className="text-muted-foreground">{transaction?.netAmount.currency}</span>
</div>
)
Expand Down
97 changes: 64 additions & 33 deletions components/table/RowActionsMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
DropdownMenuSeparator,
DropdownMenuTrigger,
} from '../ui/DropdownMenu';
import { Tooltip, TooltipContent, TooltipTrigger } from '../ui/Tooltip';

export function DropdownActionItem({ action }) {
return (
Expand Down Expand Up @@ -50,40 +51,70 @@ export function RowActionsMenu<TData>({ row, actionsMenuTriggerRef, table }: Row
};

return (
<DropdownMenu>
<DropdownMenuTrigger asChild ref={actionsMenuTriggerRef}>
<Button
size="icon-xs"
variant="outline"
className="border-transparent text-muted-foreground hover:bg-white hover:text-foreground hover:shadow-sm group-hover/row:border-border data-[state=open]:border-border data-[state=open]:text-foreground"
>
<MoreHorizontal size={18} />
</Button>
</DropdownMenuTrigger>
<div className="">
{primary?.length > 0 && (
<div className="absolute right-[2.625rem] flex items-center gap-0.5 opacity-0 transition-opacity group-hover/row:opacity-100">
{primary.map(action => (
<Tooltip delayDuration={200} key={action.key}>
<TooltipTrigger asChild>
<Button
key={action.key}
variant="outline"
// variant={action.variant || 'outline'}
size="icon-xs"
className="border-transparent text-muted-foreground hover:bg-white hover:text-foreground hover:shadow-sm group-hover/row:border-border data-[state=open]:border-border data-[state=open]:text-foreground"
onClick={action.onClick}
disabled={action.disabled}
data-cy={action['data-cy']}
>
{action.Icon && <action.Icon size={16} />}
</Button>
</TooltipTrigger>
<TooltipContent>{action.label}</TooltipContent>
</Tooltip>
))}
</div>
)}
<DropdownMenu>
<Tooltip delayDuration={200}>
<TooltipTrigger asChild>
<DropdownMenuTrigger asChild ref={actionsMenuTriggerRef}>
<Button
size="icon-xs"
variant="outline"
className="border-transparent text-muted-foreground hover:bg-white hover:text-foreground hover:shadow-sm group-hover/row:border-border data-[state=open]:border-border data-[state=open]:text-foreground"
>
<MoreHorizontal size={18} />
</Button>
</DropdownMenuTrigger>
</TooltipTrigger>
<TooltipContent>More</TooltipContent>
</Tooltip>

<DropdownMenuContent align="end">
<DropdownMenuItem onClick={() => openDetails()} className="gap-2.5">
<PanelRightOpen className="text-muted-foreground" size={16} />
<FormattedMessage defaultMessage="Open details" id="iIXH4W" />
</DropdownMenuItem>
{primary?.length > 0 && (
<React.Fragment>
<DropdownMenuSeparator />
{primary.map(action => (
<DropdownActionItem key={action.key} action={action} />
))}
</React.Fragment>
)}
<DropdownMenuContent align="end">
<DropdownMenuItem onClick={() => openDetails()} className="gap-2.5">
<PanelRightOpen className="text-muted-foreground" size={16} />
<FormattedMessage defaultMessage="Open details" id="iIXH4W" />
</DropdownMenuItem>
{primary?.length > 0 && (
<React.Fragment>
<DropdownMenuSeparator />
{primary.map(action => (
<DropdownActionItem key={action.key} action={action} />
))}
</React.Fragment>
)}

{secondary?.length > 0 && (
<React.Fragment>
<DropdownMenuSeparator />
{secondary.map(action => {
return <DropdownActionItem key={action.key} action={action} />;
})}
</React.Fragment>
)}
</DropdownMenuContent>
</DropdownMenu>
{secondary?.length > 0 && (
<React.Fragment>
<DropdownMenuSeparator />
{secondary.map(action => {
return <DropdownActionItem key={action.key} action={action} />;
})}
</React.Fragment>
)}
</DropdownMenuContent>
</DropdownMenu>
</div>
);
}
3 changes: 2 additions & 1 deletion lib/actions/types.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import type { LucideIcon } from 'lucide-react';
import type React from 'react';

type Action = {
export type Action = {
label: React.ReactNode;
onClick: () => void;
Icon?: LucideIcon;
isLoading?: boolean;
variant?: string; // TODO: use button variant
disabled?: boolean;
'data-cy'?: string;
key: string;
Expand Down
Loading

0 comments on commit b50dc9e

Please sign in to comment.