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

Fix/manager components #14056

Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,11 @@ export type TStepProps = {
label: string | JSX.Element;
isDisabled?: boolean;
};
cancel?: {
skip?: {
action: (id: string) => void;
label: string | JSX.Element;
isDisabled?: boolean;
hint?: string;
};
children?: JSX.Element | JSX.Element[];
};
Expand All @@ -58,88 +59,94 @@ export const StepComponent = ({
children,
next,
edit,
cancel,
}: TStepProps): JSX.Element => {
return (
<section className="flex flex-row border-0 border-t-[1px] border-solid border-t-[#b3b3b3] pt-5 mb-5">
<div className="basis-[40px]">
{isChecked ? (
<OsdsIcon
size={ODS_ICON_SIZE.sm}
name={ODS_ICON_NAME.CHECK}
className={'mr-2'}
color={ODS_THEME_COLOR_INTENT.primary}
/>
) : (
skip,
}: TStepProps): JSX.Element => (
<section className="flex flex-row border-0 border-t-[1px] border-solid border-t-[#b3b3b3] pt-5 mb-5">
<div className="basis-[40px]">
{isChecked ? (
<OsdsIcon
size={ODS_ICON_SIZE.sm}
name={ODS_ICON_NAME.CHECK}
className="mr-2"
color={ODS_THEME_COLOR_INTENT.primary}
/>
) : (
<div
className={clsx(
'flex justify-center items-center font-bold border-2 border-solid rounded-full h-10 w-10',
isOpen ? 'border-[#0050d7]' : 'border-[grey]',
)}
>
<OsdsText
level={ODS_THEME_TYPOGRAPHY_LEVEL.body}
size={ODS_THEME_TYPOGRAPHY_SIZE._500}
color={
isOpen
? ODS_THEME_COLOR_INTENT.text
: ODS_THEME_COLOR_INTENT.default
}
>
{order}
</OsdsText>
</div>
)}
</div>
<div className="basis-full px-5">
<div className="flex flex-col md:flex-row">
<div
className={clsx(
'font-sans font-normal p-0 m-0 w-full md:w-5/6 flex',
isOpen ? 'text-[#00185e]' : 'text-[grey]',
)}
>
<div
className={clsx(
'flex justify-center items-center font-bold border-2 border-solid rounded-full h-10 w-10',
isOpen ? 'border-[#0050d7]' : 'border-[grey]',
'leading-10',
isOpen ? 'text-[1.625rem]' : 'text-[1.25rem]',
)}
>
<OsdsText
level={ODS_THEME_TYPOGRAPHY_LEVEL.body}
size={ODS_THEME_TYPOGRAPHY_SIZE._500}
color={
isOpen
? ODS_THEME_COLOR_INTENT.text
: ODS_THEME_COLOR_INTENT.default
}
{title}
</div>
{skip?.hint && <div className="leading-10 ml-2">{skip.hint}</div>}
</div>
{edit?.action && isLocked && (
<div className="text-2xl w-full md:w-1/6" data-testid="edit">
<OsdsLink
data-testid="edit-cta"
className="float-left md:float-right"
color={ODS_THEME_COLOR_INTENT.primary}
{...(edit.isDisabled ? { disabled: true } : {})}
onClick={() => {
if (!edit.isDisabled) {
edit.action(id);
}
}}
>
{order}
</OsdsText>
{edit.label}
</OsdsLink>
</div>
)}
</div>
<div className="basis-full px-5">
<div className="flex flex-col md:flex-row">
{isOpen && (
<>
{subtitle && <div>{subtitle}</div>}
<div
data-testid="content"
className={clsx(
'font-sans font-normal p-0 m-0 w-full md:w-5/6 leading-10',
isOpen
? 'text-[1.625rem] text-[#00185e]'
: 'text-[1.25rem] text-[grey]',
'mt-5',
isLocked && 'cursor-not-allowed pointer-events-none opacity-50',
)}
>
{title}
</div>
{edit?.action && isLocked && (
<div className="text-2xl w-full md:w-1/6" data-testid="edit">
<OsdsLink
data-testid="edit-cta"
className="float-left md:float-right"
color={ODS_THEME_COLOR_INTENT.primary}
{...(edit.isDisabled ? { disabled: true } : {})}
onClick={() => {
if (!edit.isDisabled) {
edit.action(id);
}
}}
>
{edit.label}
</OsdsLink>
</div>
)}
</div>
{isOpen && (
<>
{subtitle && <div>{subtitle}</div>}
<div
data-testid="content"
className={clsx(
'mt-5',
isLocked && 'cursor-not-allowed pointer-events-none opacity-50',
)}
<Suspense
fallback={<OsdsSpinner inline size={ODS_SPINNER_SIZE.md} />}
>
<Suspense
fallback={<OsdsSpinner inline size={ODS_SPINNER_SIZE.md} />}
>
{children}
</Suspense>
</div>
{!isLocked && (next || cancel) && (
<div className="flex mt-6">
{next && (
{children}
</Suspense>
</div>
{!isLocked && (
<div className="flex mt-6">
{next?.action && (
<div data-testid="next">
<OsdsButton
data-testid="next-cta"
size={ODS_BUTTON_SIZE.md}
Expand All @@ -152,29 +159,30 @@ export const StepComponent = ({
>
{next.label}
</OsdsButton>
)}
{cancel && (
</div>
)}
{skip?.action && (
<div>
<OsdsButton
data-testid="cancel-cta"
size={ODS_BUTTON_SIZE.md}
color={ODS_THEME_COLOR_INTENT.primary}
variant={ODS_BUTTON_VARIANT.ghost}
onClick={() => {
cancel.action(id);
skip.action(id);
}}
className="w-fit"
{...(cancel.isDisabled ? { disabled: true } : {})}
{...(skip.isDisabled ? { disabled: true } : {})}
>
{cancel.label}
{skip.label}
</OsdsButton>
)}
</div>
)}
</>
)}
</div>
</section>
);
};
</div>
)}
</div>
)}
</>
)}
</div>
</section>
);

export default StepComponent;
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { vitest } from 'vitest';
import React, { useEffect } from 'react';
import { render } from '@testing-library/react';
import { render, waitFor } from '@testing-library/react';
import { useNotifications, NotificationType } from './useNotifications';
import { Notifications } from './notifications.component';

Expand Down Expand Up @@ -38,11 +38,27 @@ describe('notifications component', () => {
expect(container.children[0].children[0].innerHTML).toBe('Notification-1');
expect(container.children[1].children[0].innerHTML).toBe('Notification-2');
});
it('should clear notifications', async () => {
it('should not clear notifications created within the last 1000ms', async () => {
let { container } = render(<Notifications />);
expect(container.children.length).not.toBe(0);
expect(container.children.length).toBe(2);

render(<ClearNotifications />);
container = render(<Notifications />).container;
expect(container.children.length).toBe(0);

expect(container.children.length).toBe(2);
});

it('should clear notifications older than 1000ms', async () => {
let { container } = render(<Notifications />);
expect(container.children.length).toBe(2);

await new Promise((resolve) => setTimeout(resolve, 2000));

render(<ClearNotifications />);
container = render(<Notifications />).container;

await waitFor(() => {
expect(container.children.length).toBe(0);
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export interface Notification {
content: ReactNode;
type: NotificationType;
dismissable?: boolean;
creationTimestamp?: number;
}

export interface NotificationState {
Expand Down Expand Up @@ -44,7 +45,13 @@ export const useNotifications = create<NotificationState>((set, get) => ({
uid: state.uid + 1,
notifications: [
...state.notifications,
{ uid: state.uid, content, type, dismissable },
{
uid: state.uid,
content,
type,
dismissable,
creationTimestamp: Date.now(),
},
],
})),
addSuccess: (content: ReactNode, dismissable = false) =>
Expand All @@ -61,7 +68,12 @@ export const useNotifications = create<NotificationState>((set, get) => ({
({ uid }) => uid !== toRemoveUid,
),
})),
clearNotifications: () => set(() => ({ notifications: [] })),
clearNotifications: () =>
set((state) => ({
notifications: state.notifications.filter(
(notification) => Date.now() - notification.creationTimestamp < 1000,
),
})),
}));

export default useNotifications;
Loading
Loading