diff --git a/src/pages/Users/components/UserDetail/AddressDetail.tsx b/src/pages/Users/components/UserDetail/AddressDetail.tsx index 9f30e70..641fc2c 100644 --- a/src/pages/Users/components/UserDetail/AddressDetail.tsx +++ b/src/pages/Users/components/UserDetail/AddressDetail.tsx @@ -10,64 +10,80 @@ import LoaderSkeleton from 'common/components/Loader/LoaderSkeleton'; /** * Properties for the `AddressDetail` component. * @param {Address} [address] - An `Address` object. + * @param {boolean} [isLoading] - Indicates if the `user` is being loaded. * @see {@link BaseComponentProps} */ interface AddressDetailProps extends BaseComponentProps { address?: Address; + isLoading?: boolean; } /** * The `AddressDetail` component renders a block which displays a single * `Address`. * - * If the `address` property is null or undefined, a loading state is rendered. + * If `isLoading` is `true` the loading state is rendered. + * + * If `isLoading` is `false` and the `address` property is provided, the + * address attributes are rendered. + * + * If `isLoading` is `false` and the `address` property is empty, the + * component returns `false` so that the component remains in the React + * hierarchy, but does not render anything. * * @param {AddressDetailProps} props - Component properties. - * @returns JSX + * @returns {JSX.Element | false} Returns JSX when loading or a user is + * provided, otherwise returns `false`. */ const AddressDetail = ({ address, className, + isLoading = false, testid = 'address-detail', -}: AddressDetailProps): JSX.Element => { +}: AddressDetailProps): JSX.Element | false => { const baseProps = { className: classNames('address-detail', className), 'data-testid': testid, }; - if (address) { - // success state + if (isLoading) { + // loading state return (
-
+
-
Address
+
-
{address.street}
-
{address.suite}
-
{address.city}
-
{address.zipcode}
+ + + +
); - } else { - // loading state + } + + if (address) { + // success state return (
-
+
- +
Address
- - - - +
{address.street}
+
{address.suite}
+
{address.city}
+
{address.zipcode}
); } + + // not loading and no user + return false; }; export default AddressDetail; diff --git a/src/pages/Users/components/UserDetail/CompanyDetail.tsx b/src/pages/Users/components/UserDetail/CompanyDetail.tsx index f0b2348..9bbf737 100644 --- a/src/pages/Users/components/UserDetail/CompanyDetail.tsx +++ b/src/pages/Users/components/UserDetail/CompanyDetail.tsx @@ -10,62 +10,78 @@ import LoaderSkeleton from 'common/components/Loader/LoaderSkeleton'; /** * Properties for the `CompanyDetail` component. * @param {Company} [company] - A `Company` object. + * @param {boolean} [isLoading] - Indicates if the `user` is being loaded. * @see {@link BaseComponentProps} */ interface CompanyDetailProps extends BaseComponentProps { company?: Company; + isLoading?: boolean; } /** * The `CompanyDetail` component renders a block which provides details about * a single `Company`. * - * If the `company` property is null or undefined, a loading state is rendered. + * If `isLoading` is `true` the loading state is rendered. + * + * If `isLoading` is `false` and the `company` property is provided, the + * company attributes are rendered. + * + * If `isLoading` is `false` and the `company` property is empty, the + * component returns `false` so that the component remains in the React + * hierarchy, but does not render anything. * * @param {CompanyDetailProps} props - Component properties. - * @returns JSX + * @returns {JSX.Element | false} Returns JSX when loading or a user is + * provided, otherwise returns `false`. */ const CompanyDetail = ({ className, company, + isLoading = false, testid = 'company-detail', -}: CompanyDetailProps): JSX.Element => { +}: CompanyDetailProps): JSX.Element | false => { const baseProps = { className: classNames('company-detail', className), 'data-testid': testid, }; - if (company) { - // success state + if (isLoading) { + // loading state return (
-
+
-
Company
+
-
{company.name}
-
{company.catchPhrase}
-
{company.bs}
+ + +
); - } else { - // loading state + } + + if (company) { + // success state return (
-
+
- +
Company
- - - +
{company.name}
+
{company.catchPhrase}
+
{company.bs}
); } + + // not loading and no user + return false; }; export default CompanyDetail; diff --git a/src/pages/Users/components/UserDetail/UserDetail.scss b/src/pages/Users/components/UserDetail/UserDetail.scss index c1f0da3..995f40a 100644 --- a/src/pages/Users/components/UserDetail/UserDetail.scss +++ b/src/pages/Users/components/UserDetail/UserDetail.scss @@ -4,7 +4,6 @@ } ion-grid { - --ion-grid-columns: 2; --ion-grid-padding: 0; --ion-grid-column-padding: 0.25rem; diff --git a/src/pages/Users/components/UserDetail/UserDetail.tsx b/src/pages/Users/components/UserDetail/UserDetail.tsx index 281c493..5c8456b 100644 --- a/src/pages/Users/components/UserDetail/UserDetail.tsx +++ b/src/pages/Users/components/UserDetail/UserDetail.tsx @@ -29,14 +29,14 @@ interface UserDetailProps extends BaseComponentProps { * error message is displayed. * * @param {UserDetailProps} props - Component properties. - * @returns JSX + * @returns {JSX.Element} JSX */ const UserDetail = ({ className, testid = 'user-detail', userId, }: UserDetailProps): JSX.Element => { - const { data: user, isError } = useGetUser({ userId }); + const { data: user, isError, isLoading } = useGetUser({ userId }); const baseProps = { className: classNames('user-detail', className), @@ -57,14 +57,22 @@ const UserDetail = ({ // Success state return (
- + - - + + - - + + diff --git a/src/pages/Users/components/UserDetail/UserSummary.tsx b/src/pages/Users/components/UserDetail/UserSummary.tsx index 1940fcb..4f6b705 100644 --- a/src/pages/Users/components/UserDetail/UserSummary.tsx +++ b/src/pages/Users/components/UserDetail/UserSummary.tsx @@ -6,13 +6,16 @@ import './UserSummary.scss'; import { BaseComponentProps } from 'common/components/types'; import { User } from 'common/models/user'; import LoaderSkeleton from 'common/components/Loader/LoaderSkeleton'; +import { boolean } from 'yup'; /** * Properties for the `UserSummary` component. + * @param {boolean} [isLoading] - Indicates if the `user` is being loaded. * @param {User} [user] - A `User` object. * @see {@link BaseComponentProps} */ interface UserSummaryProps extends BaseComponentProps { + isLoading?: boolean; user?: User; } @@ -20,23 +23,50 @@ interface UserSummaryProps extends BaseComponentProps { * The `UserSummary` component renders a block containing summary information * about a single `User` including their name, email, phone, and website. * - * If the supplied `user` is null or undefined, a loading state is rendered. + * If `isLoading` is `true` the loading state is rendered. + * + * If `isLoading` is `false` and the `user` property is provided, the + * user attributes are rendered. + * + * If `isLoading` is `false` and the `user` property is empty, the + * component returns `false` so that the component remains in the React + * hierarchy, but does not render anything. * * @param {UserSummaryProps} props - Component propertiers. - * @returns JSX + * @returns {JSX.Element | false} Returns JSX when loading or a user is + * provided, otherwise returns `false`. */ const UserSummary = ({ className, + isLoading = false, testid = 'user-summary', user, -}: UserSummaryProps): JSX.Element => { +}: UserSummaryProps): JSX.Element | false => { const baseProps = { className: classNames('user-summary', className), 'data-testid': testid, }; + if (isLoading) { + // loading state + return ( +
+
+
+ +
+
+ + + +
+
+
+ ); + } + if (user) { - // successstate + // success state return (
@@ -60,23 +90,10 @@ const UserSummary = ({
); - } else { - // loading state - return ( -
-
-
- -
-
- - - -
-
-
- ); } + + // not loading and no user + return false; }; export default UserSummary; diff --git a/src/pages/Users/components/UserDetail/__tests__/AddressDetail.test.tsx b/src/pages/Users/components/UserDetail/__tests__/AddressDetail.test.tsx index 4c649cc..87b9bc1 100644 --- a/src/pages/Users/components/UserDetail/__tests__/AddressDetail.test.tsx +++ b/src/pages/Users/components/UserDetail/__tests__/AddressDetail.test.tsx @@ -1,6 +1,6 @@ import { describe, expect, it } from 'vitest'; -import { render, screen } from 'test/test-utils'; +import { render, screen, waitFor } from 'test/test-utils'; import { userFixture1 } from '__fixtures__/users'; import AddressDetail from '../AddressDetail'; @@ -17,10 +17,19 @@ describe('AddressDetail', () => { it('should render loading state', async () => { // ARRANGE - render(); + render(); await screen.findByTestId('address-detail-loader'); // ASSERT expect(screen.getByTestId('address-detail-loader')).toBeDefined(); }); + + it('should render empty state', async () => { + // ARRANGE + const { container } = render(); + await waitFor(() => expect(container).toBeDefined()); + + // ASSERT + expect(screen.queryByTestId('address-detail')).toBeNull(); + }); }); diff --git a/src/pages/Users/components/UserDetail/__tests__/CompanyDetail.test.tsx b/src/pages/Users/components/UserDetail/__tests__/CompanyDetail.test.tsx index 2c94ace..a0b9c28 100644 --- a/src/pages/Users/components/UserDetail/__tests__/CompanyDetail.test.tsx +++ b/src/pages/Users/components/UserDetail/__tests__/CompanyDetail.test.tsx @@ -1,6 +1,6 @@ import { describe, expect, it } from 'vitest'; -import { render, screen } from 'test/test-utils'; +import { render, screen, waitFor } from 'test/test-utils'; import { userFixture1 } from '__fixtures__/users'; import CompanyDetail from '../CompanyDetail'; @@ -17,10 +17,19 @@ describe('CompanyDetail', () => { it('should render loading state', async () => { // ARRANGE - render(); + render(); await screen.findByTestId('company-detail-loader'); // ASSERT expect(screen.getByTestId('company-detail-loader')).toBeDefined(); }); + + it('should render empty state', async () => { + // ARRANGE + const { container } = render(); + await waitFor(() => expect(container).toBeDefined()); + + // ASSERT + expect(screen.queryByTestId('company-detail')).toBeNull(); + }); }); diff --git a/src/pages/Users/components/UserDetail/__tests__/UserSummary.test.tsx b/src/pages/Users/components/UserDetail/__tests__/UserSummary.test.tsx index 7adbc16..ebe980a 100644 --- a/src/pages/Users/components/UserDetail/__tests__/UserSummary.test.tsx +++ b/src/pages/Users/components/UserDetail/__tests__/UserSummary.test.tsx @@ -1,6 +1,6 @@ import { describe, expect, it } from 'vitest'; -import { render, screen } from 'test/test-utils'; +import { render, screen, waitFor } from 'test/test-utils'; import { userFixture1 } from '__fixtures__/users'; import UserSummary from '../UserSummary'; @@ -17,10 +17,19 @@ describe('UserSummary', () => { it('should render loading state', async () => { // ARRANGE - render(); + render(); await screen.findByTestId('user-summary-loader'); // ASSERT expect(screen.getByTestId('user-summary-loader')).toBeDefined(); }); + + it('should render empty state', async () => { + // ARRANGE + const { container } = render(); + await waitFor(() => expect(container).toBeDefined()); + + // ASSERT + expect(screen.queryByTestId('user-summary')).toBeNull(); + }); });