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

refactor: [M3-6354] - MUI v5 Migration - Components > LandingLoading #9282

Merged
merged 3 commits into from
Jun 27, 2023
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
@@ -0,0 +1,5 @@
---
"@linode/manager": Tech Stories
---

MUI v5 Migration - `Components > LandingLoading` ([#9282](https://github.com/linode/manager/pull/9282))
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import React from 'react';
import type { Meta, StoryObj } from '@storybook/react';
import { LandingLoading, DEFAULT_DELAY } from './LandingLoading';

const meta: Meta<typeof LandingLoading> = {
title: 'Components/LandingLoading',
component: LandingLoading,
argTypes: {},
args: {
shouldDelay: false,
delayInMS: DEFAULT_DELAY,
children: undefined,
},
};

export default meta;

type Story = StoryObj<typeof LandingLoading>;

export const Default: Story = {
args: {},
render: (args) => <LandingLoading {...args} />,
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import * as React from 'react';
import { LandingLoading, DEFAULT_DELAY } from './LandingLoading';
import { render, screen, act } from '@testing-library/react';

jest.useFakeTimers();

const LOADING_ICON = 'circle-progress';

describe('LandingLoading', () => {
afterEach(() => {
jest.clearAllTimers();
});

it('renders the loading indicator by default', () => {
render(<LandingLoading />);
expect(screen.getByTestId(LOADING_ICON)).toBeInTheDocument();
});

it('renders custom loading indicator when children are provided', () => {
render(
<LandingLoading>
<div data-testid="custom-loading-indicator">Loading...</div>
</LandingLoading>
);
expect(screen.getByTestId('custom-loading-indicator')).toBeInTheDocument();
expect(screen.queryByTestId(LOADING_ICON)).toBeNull();
});

it('does not render the loading indicator when shouldDelay is true', () => {
render(<LandingLoading shouldDelay />);
expect(screen.queryByTestId(LOADING_ICON)).toBeNull();
});

it('renders the loading indicator after the delay', () => {
render(<LandingLoading shouldDelay />);
expect(screen.queryByTestId(LOADING_ICON)).toBeNull();
act(() => {
jest.advanceTimersByTime(DEFAULT_DELAY);
});
expect(screen.getByTestId(LOADING_ICON)).toBeInTheDocument();
});

it('renders the loading indicator after the specified delayInMS', () => {
render(<LandingLoading delayInMS={2000} />);
expect(screen.queryByTestId(LOADING_ICON)).toBeNull();
act(() => {
jest.advanceTimersByTime(2000);
});
expect(screen.getByTestId(LOADING_ICON)).toBeInTheDocument();
});

it('does not render the loading indicator when shouldDelay is false and no delayInMS is provided', () => {
render(<LandingLoading shouldDelay={false} />);
expect(screen.getByTestId(LOADING_ICON)).toBeInTheDocument();
});
});
44 changes: 19 additions & 25 deletions packages/manager/src/components/LandingLoading/LandingLoading.tsx
Original file line number Diff line number Diff line change
@@ -1,41 +1,38 @@
import * as React from 'react';
import { CircleProgress } from 'src/components/CircleProgress';

const DEFAULT_DELAY = 1000;
export const DEFAULT_DELAY = 1000;

interface Props {
interface LandingLoadingProps {
/** If true, the loading indicator will not be rendered for 1 second which may give user's with fast connections a more fluid experience. */
shouldDelay?: boolean;
/** If given, the loading indicator will not be rendered for the given duration in milliseconds */
delayInMS?: number;
/** Allow children to be passed in to override the default loading indicator */
children?: JSX.Element;
}

/**
*
* LandingLoading
*
* If the `shouldDelay` prop is given, the loading indicator will
* not be rendered for 1 second, which may give user's with fast
* connections a more fluid experience. Use the `delayInMS` prop
* to specify an exact delay duration.
*/
export const LandingLoading: React.FC<Props> = ({
export const LandingLoading = ({
shouldDelay,
delayInMS,
children,
}) => {
}: LandingLoadingProps): JSX.Element | null => {
const [showLoading, setShowLoading] = React.useState<boolean>(false);

React.useEffect(() => {
/* This `didCancel` business is to prevent a warning from React.
* See: https://github.com/facebook/react/issues/14369#issuecomment-468267798
*/
let didCancel = false;
// Reference to the timeoutId so we can cancel it
let timeoutId: NodeJS.Timeout | null = null;

if (shouldDelay || typeof delayInMS === 'number') {
// Used specified duration or default
const delayDuration =
typeof delayInMS === 'number' ? delayInMS : DEFAULT_DELAY;

setTimeout(() => {
timeoutId = setTimeout(() => {
if (!didCancel) {
setShowLoading(true);
}
Expand All @@ -45,16 +42,13 @@ export const LandingLoading: React.FC<Props> = ({
}
return () => {
didCancel = true;
if (timeoutId) {
clearTimeout(timeoutId);
}
};
}, []);
return showLoading ? (
!!children ? (
/** allows us to pass a custom Loader if we please */
<React.Fragment>{children}</React.Fragment>
) : (
<CircleProgress />
)
) : null;
};
}, [shouldDelay, delayInMS]);

export default LandingLoading;
return showLoading
? children || <CircleProgress data-testid="circle-progress" />
: null;
};
2 changes: 0 additions & 2 deletions packages/manager/src/components/LandingLoading/index.ts

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import Paper from 'src/components/core/Paper';
import { createStyles, withStyles, WithStyles } from '@mui/styles';
import { Theme } from '@mui/material/styles';
import { ErrorState } from 'src/components/ErrorState/ErrorState';
import Loading from 'src/components/LandingLoading';
import { LandingLoading } from 'src/components/LandingLoading/LandingLoading';
import { Notice } from 'src/components/Notice/Notice';
import AppPanelSection from 'src/features/Linodes/LinodesCreate/AppPanelSection';
import { getQueryParamFromQueryString } from 'src/utilities/queryParams';
Expand Down Expand Up @@ -132,7 +132,7 @@ class SelectAppPanel extends React.PureComponent<CombinedProps> {
return (
<Panel className={classes.panel} error={error} title="Select App">
<span className={classes.loading}>
<Loading />
<LandingLoading />
</span>
</Panel>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { makeStyles } from '@mui/styles';
import { Theme } from '@mui/material/styles';
import { DocumentTitleSegment } from 'src/components/DocumentTitle';
import { ErrorState } from 'src/components/ErrorState/ErrorState';
import LandingLoading from 'src/components/LandingLoading';
import { LandingLoading } from 'src/components/LandingLoading/LandingLoading';
import { Placeholder } from 'src/components/Placeholder/Placeholder';
import { WithStartAndEnd } from '../../../request.types';
import TimeRangeSelect from '../../../shared/TimeRangeSelect';
Expand Down
4 changes: 2 additions & 2 deletions packages/manager/src/features/Volumes/VolumesLanding.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { TableHead } from 'src/components/TableHead';
import { DocumentTitleSegment } from 'src/components/DocumentTitle';
import { ErrorState } from 'src/components/ErrorState/ErrorState';
import LandingHeader from 'src/components/LandingHeader';
import Loading from 'src/components/LandingLoading';
import { LandingLoading } from 'src/components/LandingLoading/LandingLoading';
import { PaginationFooter } from 'src/components/PaginationFooter/PaginationFooter';
import { Table } from 'src/components/Table';
import { TableCell } from 'src/components/TableCell';
Expand Down Expand Up @@ -199,7 +199,7 @@ export const VolumesLanding = (props: CombinedProps) => {
};

if (isLoading) {
return <Loading />;
return <LandingLoading />;
}

if (error) {
Expand Down