Skip to content

Commit

Permalink
chore: Pages empty state consistency (#29439)
Browse files Browse the repository at this point in the history
  • Loading branch information
dougfabris authored Jun 12, 2023
1 parent b57b2f1 commit 742eac7
Show file tree
Hide file tree
Showing 106 changed files with 2,225 additions and 2,221 deletions.
Original file line number Diff line number Diff line change
@@ -1,22 +1,25 @@
import type { Icon } from '@rocket.chat/fuselage';
import { States, StatesIcon, StatesTitle, StatesSubtitle, StatesActions, StatesAction } from '@rocket.chat/fuselage';
import { useTranslation } from '@rocket.chat/ui-contexts';
import type { ComponentProps } from 'react';
import React from 'react';

type GenericNoResultsProps = {
icon: ComponentProps<typeof Icon>['name'];
title: string;
description: string;
icon?: ComponentProps<typeof Icon>['name'];
title?: string;
description?: string;
buttonTitle?: string;
buttonAction?: () => void;
};

const GenericNoResults = ({ icon, title, description, buttonTitle, buttonAction }: GenericNoResultsProps) => {
const GenericNoResults = ({ icon = 'magnifier', title, description, buttonTitle, buttonAction }: GenericNoResultsProps) => {
const t = useTranslation();

return (
<States>
<StatesIcon name={icon} />
<StatesTitle>{title}</StatesTitle>
<StatesSubtitle>{description}</StatesSubtitle>
<StatesTitle>{title || t('No_results_found')}</StatesTitle>
{description && <StatesSubtitle>{description}</StatesSubtitle>}
{buttonTitle && buttonAction && (
<StatesActions>
<StatesAction onClick={buttonAction}>{buttonTitle}</StatesAction>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
import { Box, States, StatesIcon, StatesSubtitle, StatesTitle } from '@rocket.chat/fuselage';
import { Box } from '@rocket.chat/fuselage';
import { useTranslation } from '@rocket.chat/ui-contexts';
import type { VFC } from 'react';
import React from 'react';

import GenericNoResults from '../../../components/GenericNoResults';

const FederatedRoomListEmptyPlaceholder: VFC = () => {
const t = useTranslation();

return (
<Box display='flex' justifyContent='center' height='full' backgroundColor='surface'>
<States>
<StatesIcon name='magnifier' />
<StatesTitle>{t('No_results_found')}</StatesTitle>
<StatesSubtitle>{t('There_are_no_rooms_for_the_given_search_criteria')}</StatesSubtitle>
</States>
<GenericNoResults description={t('There_are_no_rooms_for_the_given_search_criteria')} />
</Box>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import type { ReactElement, RefObject } from 'react';
import React, { useMemo, useCallback } from 'react';

import GenericModal from '../../../../components/GenericModal';
import GenericNoResults from '../../../../components/GenericNoResults';
import {
GenericTable,
GenericTableHeader,
Expand Down Expand Up @@ -173,12 +174,7 @@ const AccountTokensTable = (): ReactElement => {
/>
</>
)}
{phase === AsyncStatePhase.RESOLVED && filteredTokens?.length === 0 && (
<States>
<StatesIcon name='magnifier' />
<StatesTitle>{t('No_results_found')}</StatesTitle>
</States>
)}
{phase === AsyncStatePhase.RESOLVED && filteredTokens?.length === 0 && <GenericNoResults />}
</>
);
};
Expand Down
8 changes: 2 additions & 6 deletions apps/meteor/client/views/admin/customEmoji/CustomEmoji.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import type { FC, MutableRefObject } from 'react';
import React, { useEffect, useMemo, useState } from 'react';

import FilterByText from '../../../components/FilterByText';
import GenericNoResults from '../../../components/GenericNoResults';
import {
GenericTable,
GenericTableBody,
Expand Down Expand Up @@ -111,12 +112,7 @@ const CustomEmoji: FC<CustomEmojiProps> = ({ onClick, reload }) => {
/>
</>
)}
{isSuccess && data && data.emojis.length === 0 && (
<States>
<StatesIcon name='magnifier' />
<StatesTitle>{t('No_results_found')}</StatesTitle>
</States>
)}
{isSuccess && data && data.emojis.length === 0 && <GenericNoResults />}
{isError && (
<States>
<StatesIcon name='warning' variation='danger' />
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Button, Icon } from '@rocket.chat/fuselage';
import { Button } from '@rocket.chat/fuselage';
import { useRoute, useRouteParameter, usePermission, useTranslation } from '@rocket.chat/ui-contexts';
import type { ReactElement } from 'react';
import React, { useCallback, useRef } from 'react';
Expand Down Expand Up @@ -47,7 +47,7 @@ const CustomEmojiRoute = (): ReactElement => {
<Page name='admin-emoji-custom'>
<Page.Header title={t('Custom_Emoji')}>
<Button primary onClick={handleAddEmoji} aria-label={t('New')}>
<Icon name='plus' /> {t('New')}
{t('New')}
</Button>
</Page.Header>
<Page.Content>
Expand Down
70 changes: 70 additions & 0 deletions apps/meteor/client/views/admin/customSounds/CustomSoundsPage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { Button } from '@rocket.chat/fuselage';
import { useRoute, useRouteParameter, useTranslation } from '@rocket.chat/ui-contexts';
import React, { useCallback, useRef } from 'react';

import { ContextualbarTitle, Contextualbar, ContextualbarClose, ContextualbarHeader } from '../../../components/Contextualbar';
import Page from '../../../components/Page';
import AddCustomSound from './AddCustomSound';
import CustomSoundsTable from './CustomSoundsTable';
import EditCustomSound from './EditCustomSound';

const CustomSoundsPage = () => {
const t = useTranslation();
const id = useRouteParameter('id');
const route = useRoute('custom-sounds');
const context = useRouteParameter('context');

const reload = useRef(() => null);

const handleItemClick = useCallback(
(_id) => (): void => {
route.push({
context: 'edit',
id: _id,
});
},
[route],
);

const handleNewButtonClick = useCallback(() => {
route.push({ context: 'new' });
}, [route]);

const handleClose = useCallback(() => {
route.push({});
}, [route]);

const handleReload = useCallback(() => {
reload.current();
}, []);

return (
<Page flexDirection='row'>
<Page name='admin-custom-sounds'>
<Page.Header title={t('Custom_Sounds')}>
<Button primary onClick={handleNewButtonClick} aria-label={t('New')}>
{t('New')}
</Button>
</Page.Header>
<Page.Content>
<CustomSoundsTable reload={reload} onClick={handleItemClick} />
</Page.Content>
</Page>
{context && (
<Contextualbar flexShrink={0}>
<ContextualbarHeader>
<ContextualbarTitle>
{context === 'edit' && t('Custom_Sound_Edit')}
{context === 'new' && t('Custom_Sound_Add')}
</ContextualbarTitle>
<ContextualbarClose onClick={handleClose} />
</ContextualbarHeader>
{context === 'edit' && <EditCustomSound _id={id} close={handleClose} onChange={handleReload} />}
{context === 'new' && <AddCustomSound goToNew={handleItemClick} close={handleClose} onChange={handleReload} />}
</Contextualbar>
)}
</Page>
);
};

export default CustomSoundsPage;
166 changes: 4 additions & 162 deletions apps/meteor/client/views/admin/customSounds/CustomSoundsRoute.tsx
Original file line number Diff line number Diff line change
@@ -1,176 +1,18 @@
import { Button, Icon, Pagination, States, StatesIcon, StatesActions, StatesAction, StatesTitle } from '@rocket.chat/fuselage';
import { useDebouncedValue } from '@rocket.chat/fuselage-hooks';
import { escapeRegExp } from '@rocket.chat/string-helpers';
import { useRoute, useRouteParameter, usePermission, useTranslation, useEndpoint, useToastMessageDispatch } from '@rocket.chat/ui-contexts';
import { useQuery } from '@tanstack/react-query';
import { usePermission } from '@rocket.chat/ui-contexts';
import type { ReactElement } from 'react';
import React, { useMemo, useState, useCallback } from 'react';
import React from 'react';

import { ContextualbarTitle, Contextualbar, ContextualbarClose, ContextualbarHeader } from '../../../components/Contextualbar';
import FilterByText from '../../../components/FilterByText';
import { GenericTable } from '../../../components/GenericTable/V2/GenericTable';
import { GenericTableBody } from '../../../components/GenericTable/V2/GenericTableBody';
import { GenericTableHeader } from '../../../components/GenericTable/V2/GenericTableHeader';
import { GenericTableHeaderCell } from '../../../components/GenericTable/V2/GenericTableHeaderCell';
import { GenericTableLoadingTable } from '../../../components/GenericTable/V2/GenericTableLoadingTable';
import { usePagination } from '../../../components/GenericTable/hooks/usePagination';
import { useSort } from '../../../components/GenericTable/hooks/useSort';
import Page from '../../../components/Page';
import NotAuthorizedPage from '../../notAuthorized/NotAuthorizedPage';
import AddCustomSound from './AddCustomSound';
import CustomSoundRow from './CustomSoundRow';
import EditCustomSound from './EditCustomSound';
import CustomSoundsPage from './CustomSoundsPage';

const CustomSoundsRoute = (): ReactElement => {
const t = useTranslation();
const id = useRouteParameter('id');
const route = useRoute('custom-sounds');
const context = useRouteParameter('context');
const canManageCustomSounds = usePermission('manage-sounds');

const { sortBy, sortDirection, setSort } = useSort<'name'>('name');
const { current, itemsPerPage, setItemsPerPage: onSetItemsPerPage, setCurrent: onSetCurrent, ...paginationProps } = usePagination();

const [text, setParams] = useState('');

const query = useDebouncedValue(
useMemo(
() => ({
query: JSON.stringify({ name: { $regex: escapeRegExp(text), $options: 'i' } }),
sort: `{ "${sortBy}": ${sortDirection === 'asc' ? 1 : -1} }`,
...(itemsPerPage && { count: itemsPerPage }),
...(current && { offset: current }),
}),
[text, itemsPerPage, current, sortBy, sortDirection],
),
500,
);

const getSounds = useEndpoint('GET', '/v1/custom-sounds.list');
const dispatchToastMessage = useToastMessageDispatch();

const { data, refetch, isLoading, isError, isSuccess } = useQuery(
['custom-sounds', query],
async () => {
const { sounds } = await getSounds(query);

return sounds;
},
{
onError: (error) => {
dispatchToastMessage({ type: 'error', message: error });
},
},
);

const handleItemClick = useCallback(
(_id) => (): void => {
route.push({
context: 'edit',
id: _id,
});
},
[route],
);

const handleNewButtonClick = useCallback(() => {
route.push({ context: 'new' });
}, [route]);

const handleClose = useCallback(() => {
route.push({});
}, [route]);

const handleChange = useCallback(() => {
refetch();
}, [refetch]);

const headers = useMemo(
() => [
<GenericTableHeaderCell key='name' direction={sortDirection} active={sortBy === 'name'} onClick={setSort} sort='name'>
{t('Name')}
</GenericTableHeaderCell>,
<GenericTableHeaderCell w='x40' key='action' />,
],
[setSort, sortBy, sortDirection, t],
);

if (!canManageCustomSounds) {
return <NotAuthorizedPage />;
}

return (
<Page flexDirection='row'>
<Page name='admin-custom-sounds'>
<Page.Header title={t('Custom_Sounds')}>
<Button primary onClick={handleNewButtonClick} aria-label={t('New')}>
<Icon name='plus' /> {t('New')}
</Button>
</Page.Header>
<Page.Content>
<>
<FilterByText onChange={({ text }): void => setParams(text)} />
{isLoading && (
<GenericTable>
<GenericTableHeader>{headers}</GenericTableHeader>
<GenericTableBody>
<GenericTableLoadingTable headerCells={2} />
</GenericTableBody>
</GenericTable>
)}
{isSuccess && data && data.length > 0 && (
<>
<GenericTable>
<GenericTableHeader>{headers}</GenericTableHeader>
<GenericTableBody>
{data?.map((sound) => (
<CustomSoundRow key={sound._id} sound={sound} onClick={handleItemClick} />
))}
</GenericTableBody>
</GenericTable>
<Pagination
divider
current={current}
itemsPerPage={itemsPerPage}
count={data.length || 0}
onSetItemsPerPage={onSetItemsPerPage}
onSetCurrent={onSetCurrent}
{...paginationProps}
/>
</>
)}
{isSuccess && data?.length === 0 && (
<States>
<StatesIcon name='magnifier' />
<StatesTitle>{t('No_results_found')}</StatesTitle>
</States>
)}

{isError && (
<States>
<StatesIcon name='warning' variation='danger' />
<StatesTitle>{t('Something_went_wrong')}</StatesTitle>
<StatesActions>
<StatesAction onClick={() => refetch()}>{t('Reload_page')}</StatesAction>
</StatesActions>
</States>
)}
</>
</Page.Content>
</Page>
{context && (
<Contextualbar flexShrink={0}>
<ContextualbarHeader>
{context === 'edit' && <ContextualbarTitle>{t('Custom_Sound_Edit')}</ContextualbarTitle>}
{context === 'new' && <ContextualbarTitle>{t('Custom_Sound_Add')}</ContextualbarTitle>}
<ContextualbarClose onClick={handleClose} />
</ContextualbarHeader>
{context === 'edit' && <EditCustomSound _id={id} close={handleClose} onChange={handleChange} />}
{context === 'new' && <AddCustomSound goToNew={handleItemClick} close={handleClose} onChange={handleChange} />}
</Contextualbar>
)}
</Page>
);
return <CustomSoundsPage />;
};

export default CustomSoundsRoute;
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import { useCustomSound, useTranslation } from '@rocket.chat/ui-contexts';
import type { ReactElement } from 'react';
import React, { useCallback, useState } from 'react';

import { GenericTableCell } from '../../../components/GenericTable/V2/GenericTableCell';
import { GenericTableRow } from '../../../components/GenericTable/V2/GenericTableRow';
import { GenericTableCell } from '../../../../components/GenericTable/V2/GenericTableCell';
import { GenericTableRow } from '../../../../components/GenericTable/V2/GenericTableRow';

type CustomSoundRowProps = {
onClick: (soundId: string) => () => void;
Expand Down
Loading

0 comments on commit 742eac7

Please sign in to comment.