Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
9 changes: 9 additions & 0 deletions .changeset/quiet-ties-sin.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
'@o2s/blocks.order-details': minor
'@o2s/blocks.ticket-list': minor
'@o2s/ui': minor
---

- add MoreActionsMenu component and refactor ActionList
- migrate OrderDetails and TicketList to unified ActionList API
- improve breadcrumbs visibility and card border styling
73 changes: 27 additions & 46 deletions packages/blocks/order-details/src/frontend/OrderDetails.client.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ import { Typography } from '@o2s/ui/elements/typography';
import { Model, Request } from '../api-harmonization/order-details.client';
import { sdk } from '../sdk';

import { OrderDetailsPureProps } from './OrderDetails.types';
import { Action, OrderDetailsPureProps } from './OrderDetails.types';

const ProgressBar: React.FC<
Readonly<{
Expand Down Expand Up @@ -166,22 +166,27 @@ export const OrderDetailsPure: React.FC<Readonly<OrderDetailsPureProps>> = ({
});
};

const buttons = [
const actionsDefinition: Action[] = [
{
label: data.payOnlineLabel,
icon: 'ArrowUpRight',
variant: 'destructive',
},
{
label: data.reorderLabel,
icon: 'IterationCw',
variant: data.order.overdue.isOverdue ? 'secondary' : 'default',
className: data.order.overdue.isOverdue ? 'flex-1' : '',
},
{
label: data.trackOrderLabel,
icon: 'Truck',
variant: data.order.overdue.isOverdue ? 'ghost' : 'secondary',
className: data.order.overdue.isOverdue ? 'w-full justify-start h-8' : 'flex-1',
},
];

const actions = data.order.overdue.isOverdue ? buttons : buttons.slice(1);
const actions = data.order.overdue.isOverdue ? actionsDefinition : actionsDefinition.slice(1);

const t = useTranslations();

Expand All @@ -206,49 +211,25 @@ export const OrderDetailsPure: React.FC<Readonly<OrderDetailsPureProps>> = ({
<div className="flex flex-row justify-end">
<div className="flex flex-col gap-4 sm:flex-row sm:items-center w-full sm:w-auto">
<ActionList
visibleActions={[
<TooltipHover
key={actions[0]?.label}
trigger={(setIsOpen) => (
<Button
variant={data.order.overdue.isOverdue ? 'destructive' : 'default'}
onClick={() => setIsOpen(true)}
>
{actions[0]?.icon && <DynamicIcon name={actions[0].icon} size={16} />}
{actions[0]?.label}
</Button>
)}
content={<p>{t('general.comingSoon')}</p>}
/>,
<TooltipHover
key={actions[1]?.label}
trigger={(setIsOpen) => (
<Button variant={'secondary'} onClick={() => setIsOpen(true)}>
{actions[1]?.icon && <DynamicIcon name={actions[1].icon} size={16} />}
{actions[1]?.label}
</Button>
)}
content={<p>{t('general.comingSoon')}</p>}
/>,
]}
dropdownActions={actions.slice(2).map((action) => (
<TooltipHover
key={action.label}
trigger={(setIsOpen) => (
<Button
variant="ghost"
size="sm"
disabled
className="w-full justify-start h-8"
onClick={() => setIsOpen(true)}
>
{action.icon && <DynamicIcon name={action.icon} size={16} />}
{action.label}
</Button>
)}
content={<p>{t('general.comingSoon')}</p>}
/>
))}
actions={actions.map(
(action) =>
action.label && (
<TooltipHover
key={action.label}
trigger={(setIsOpen) => (
<Button
variant={action.variant}
onClick={() => setIsOpen(true)}
className={action.className}
>
{action.icon && <DynamicIcon name={action.icon} size={16} />}
{action.label}
</Button>
)}
content={<p>{t('general.comingSoon')}</p>}
/>
),
)}
showMoreLabel={data.labels.showMore}
/>
</div>
Expand Down
10 changes: 10 additions & 0 deletions packages/blocks/order-details/src/frontend/OrderDetails.types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import { VariantProps } from 'class-variance-authority';
import { defineRouting } from 'next-intl/routing';

import { baseVariant } from '@o2s/ui/lib/utils';

import { Model } from '../api-harmonization/order-details.client';

export interface OrderDetailsProps {
Expand All @@ -16,3 +19,10 @@ export type OrderDetailsPureProps = OrderDetailsProps & Model.OrderDetailsBlock;
export interface OrderDetailsRendererProps extends Omit<OrderDetailsProps, 'orderId'> {
slug: string[];
}

export type Action = {
label?: string;
icon?: string;
variant: VariantProps<typeof baseVariant>['variant'];
className?: string;
};
70 changes: 44 additions & 26 deletions packages/blocks/ticket-list/src/frontend/TicketList.client.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import { Typography } from '@o2s/ui/elements/typography';
import { Model, Request } from '../api-harmonization/ticket-list.client';
import { sdk } from '../sdk';

import { TicketListPureProps } from './TicketList.types';
import { Action, TicketListPureProps } from './TicketList.types';

export const TicketListPure: React.FC<TicketListPureProps> = ({ locale, accessToken, routing, meta, ...component }) => {
const { Link: LinkComponent } = createNavigation(routing);
Expand Down Expand Up @@ -88,6 +88,31 @@ export const TicketListPure: React.FC<TicketListPureProps> = ({ locale, accessTo
});
};

const actions: Action[] = [
{
label: data.forms?.[0]?.label,
icon: data.forms?.[0]?.icon,
url: data.forms?.[0]?.url || '',
variant: 'default',
className: 'no-underline hover:no-underline',
},
{
label: data.forms?.[1]?.label,
icon: data.forms?.[1]?.icon,
url: data.forms?.[1]?.url || '',
variant: 'secondary',
className: 'no-underline hover:no-underline flex-1',
},
{
label: data.forms?.[2]?.label,
icon: data.forms?.[2]?.icon,
url: data.forms?.[2]?.url || '',
variant: 'ghost',
className:
'flex items-center gap-2 !no-underline hover:!no-underline cursor-pointer h-8 w-full justify-start',
},
];

// Define columns configuration outside JSX for better readability
const columns = data.table.columns.map((column) => {
switch (column.id) {
Expand Down Expand Up @@ -123,7 +148,7 @@ export const TicketListPure: React.FC<TicketListPureProps> = ({ locale, accessTo
};
}
}) as DataListColumnConfig<Model.Ticket>[];
const actions = data.table.actions
const tableActions = data.table.actions
? {
...data.table.actions,
render: (ticket: Model.Ticket) => {
Expand All @@ -150,29 +175,22 @@ export const TicketListPure: React.FC<TicketListPureProps> = ({ locale, accessTo

{data.forms && (
<ActionList
visibleActions={data.forms.slice(0, 2).map((form, index) => (
<Button
asChild
variant={index === 0 ? 'default' : 'secondary'}
key={form.label}
className="no-underline hover:no-underline"
>
<LinkComponent href={form.url}>
{form.icon && <DynamicIcon name={form.icon} size={16} />}
{form.label}
</LinkComponent>
</Button>
))}
dropdownActions={data.forms.slice(2).map((form) => (
<LinkComponent
href={form.url}
key={form.label}
className="flex items-center gap-2 !no-underline hover:!no-underline cursor-pointer"
>
{form.icon && <DynamicIcon name={form.icon} size={16} />}
{form.label}
</LinkComponent>
))}
actions={actions.map(
(action) =>
action.label && (
<Button
asChild
variant={action.variant}
key={action.label}
className={action.className}
>
<LinkComponent href={action.url}>
{action.icon && <DynamicIcon name={action.icon} size={16} />}
{action.label}
</LinkComponent>
</Button>
),
)}
showMoreLabel={data.labels.showMore}
/>
)}
Expand Down Expand Up @@ -215,7 +233,7 @@ export const TicketListPure: React.FC<TicketListPureProps> = ({ locale, accessTo
viewMode={viewMode}
data={data.tickets.data}
columns={columns}
actions={actions}
actions={tableActions}
cardHeaderSlots={data.cardHeaderSlots}
enableRowSelection={component.enableRowSelection}
selectedRows={selectedRows}
Expand Down
11 changes: 11 additions & 0 deletions packages/blocks/ticket-list/src/frontend/TicketList.types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import { VariantProps } from 'class-variance-authority';
import { defineRouting } from 'next-intl/routing';

import { baseVariant } from '@o2s/ui/lib/utils';

import { Model } from '../api-harmonization/ticket-list.client';

export interface TicketListProps {
Expand All @@ -17,3 +20,11 @@ export type TicketListPureProps = TicketListProps & Model.TicketListBlock;
export type TicketListRendererProps = Omit<TicketListProps, ''> & {
slug: string[];
};

export type Action = {
label?: string;
icon?: string;
url: string;
variant: VariantProps<typeof baseVariant>['variant'];
className?: string;
};
39 changes: 5 additions & 34 deletions packages/ui/src/components/ActionList/ActionList.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,21 +19,13 @@ export const Default: Story = {
args: {
showMoreLabel: 'Show more actions',
triggerVariant: 'outline',
visibleActions: [
actions: [
<Button key="primary" variant="primary">
Primary Action
</Button>,
<Button key="secondary" variant="secondary">
Secondary Action
</Button>,
<Button key="tertiary1" variant="outline">
Tertiary Action 1
</Button>,
<Button key="tertiary2" variant="ghost">
Tertiary Action 2
</Button>,
],
dropdownActions: [
<Link key="primary" variant="primary">
Primary Action
</Link>,
Expand All @@ -53,60 +45,39 @@ export const Default: Story = {
export const SingleAction: Story = {
args: {
showMoreLabel: 'Show more actions',
visibleActions: [
actions: [
<Button key="primary" variant="primary">
Single Action
</Button>,
],
dropdownActions: [
<Link key="primary" variant="primary">
Single Action
</Link>,
],
},
};

export const TwoActions: Story = {
args: {
showMoreLabel: 'Show more actions',
visibleActions: [
actions: [
<Button key="primary" variant="primary">
Primary Action
</Button>,
<Button key="secondary" variant="secondary">
Secondary Action
</Button>,
],
dropdownActions: [
<Link key="primary" variant="primary">
Primary Action
</Link>,
<Link key="secondary" variant="secondary">
Secondary Action
</Link>,
],
},
};

export const WithDifferentVariant: Story = {
args: {
showMoreLabel: 'Show more actions',
triggerVariant: 'destructive',
visibleActions: [
<Button key="primary" variant="primary">
actions: [
<Button key="primary" variant="destructive">
Primary Action
</Button>,
<Button key="secondary" variant="secondary">
Secondary Action
</Button>,
<Button key="tertiary1" variant="outline">
Tertiary Action 1
</Button>,
<Button key="tertiary2" variant="ghost">
Tertiary Action 2
</Button>,
],
dropdownActions: [
<Link key="primary" variant="primary">
Primary Action
</Link>,
Expand Down
Loading