fix(ui): uxt empty list state

This commit is contained in:
nick-delirium 2023-12-08 10:03:22 +01:00
parent eba9d9039c
commit dc5a9cd5f4
3 changed files with 88 additions and 49 deletions

View file

@ -1,12 +1,12 @@
import React from 'react';
import { UxTListEntry } from "App/services/UxtestingService";
import { UxTListEntry } from 'App/services/UxtestingService';
import { observer } from 'mobx-react-lite';
import { useStore } from 'App/mstore';
import { numberWithCommas } from 'App/utils';
import { Button, Input, Typography, Tag, Modal, Space } from 'antd';
import AnimatedSVG from 'Shared/AnimatedSVG';
import { ICONS } from 'Shared/AnimatedSVG/AnimatedSVG';
import { Loader, NoContent, Pagination, Link, Icon } from "UI";
import { Loader, NoContent, Pagination, Link, Icon } from 'UI';
import { checkForRecent, getDateFromMill } from 'App/date';
import { UnorderedListOutlined, ArrowRightOutlined } from '@ant-design/icons';
import { useHistory, useParams } from 'react-router-dom';
@ -18,8 +18,9 @@ const { Search } = Input;
const PER_PAGE = 10;
let debouncedSearch: any = () => null
const defaultDescription = `To evaluate the usability of [Feature Name], focusing on user interaction, efficiency, and satisfaction. The aim is to identify any usability issues that users may encounter, understand how they navigate [Feature Name], and gauge the intuitiveness of the workflow.`
let debouncedSearch: any = () => null;
const defaultDescription = `To evaluate the usability of [Feature Name], focusing on user interaction, efficiency, and satisfaction. The aim is to identify any usability issues that users may encounter, understand how they navigate [Feature Name], and gauge the intuitiveness of the workflow.`;
function TestsTable() {
const inputRef = React.useRef<HTMLInputElement>(null);
const [newTestTitle, setNewTestTitle] = React.useState('');
@ -29,12 +30,12 @@ function TestsTable() {
const onSearch = (value: string) => {
uxtestingStore.setQuery(value);
debouncedSearch()
}
debouncedSearch();
};
React.useEffect(() => {
uxtestingStore.getList();
debouncedSearch = debounce(uxtestingStore.getList, 500)
debouncedSearch = debounce(uxtestingStore.getList, 500);
}, []);
const onPageChange = (page: number) => {
@ -68,7 +69,7 @@ function TestsTable() {
};
return (
<div className="w-full mx-auto" style={{ maxWidth: '1360px'}}>
<div className="w-full mx-auto" style={{ maxWidth: '1360px' }}>
<Modal
title="Create Usability Test"
open={isModalVisible}
@ -120,33 +121,41 @@ function TestsTable() {
style={{ width: 200 }}
/>
</div>
<div className={'bg-gray-lightest grid grid-cols-8 items-center font-semibold p-4'}>
<div className="col-span-4">Test Title</div>
<div className="col-span-1">Created by</div>
<div className="col-span-2">Updated at</div>
<div className="col-span-1">Status</div>
</div>
<div className={'bg-white'}>
<Loader loading={uxtestingStore.isLoading} style={{ height: 300 }}>
<NoContent
show={uxtestingStore.total === 0}
title={
<div className={'flex flex-col items-center justify-center'}>
<AnimatedSVG name={ICONS.NO_FFLAGS} size={285} />
<div className="text-center text-gray-600 mt-4">
{uxtestingStore.searchQuery === ''
? "You haven't created any usability tests yet"
: 'No matching results'}
</div>
<Loader loading={uxtestingStore.isLoading} style={{ height: 300 }}>
<NoContent
show={uxtestingStore.total === 0}
title={
<div className={'flex flex-col items-center justify-center mt-10'}>
{uxtestingStore.searchQuery === '' ? (
<AnimatedSVG name={ICONS.NO_UXT} size={172} />
) : null}
<div className={'text-xl font-semibold mt-4'}>
{uxtestingStore.searchQuery === ''
? 'Uncover real user insights through usability tests.'
: 'No results matching your search'}
</div>
}
>
<div className="text-center text-gray-600">
{uxtestingStore.searchQuery === ''
? 'Conduct summative testing to observe task completion and iterate your product.'
: ''}
</div>
</div>
}
>
<div className={'bg-gray-lightest grid grid-cols-8 items-center font-semibold p-4'}>
<div className="col-span-4">Test Title</div>
<div className="col-span-1">Created by</div>
<div className="col-span-2">Updated at</div>
<div className="col-span-1">Status</div>
</div>
<div className={'bg-white'}>
{uxtestingStore.tests.map((test) => (
<Row test={test} siteId={siteId} />
))}
</NoContent>
</Loader>
</div>
</div>
</NoContent>
</Loader>
<div className={'flex items-center justify-between p-4'}>
{uxtestingStore.isLoading || uxtestingStore.tests?.length === 0 ? null : (
<>
@ -175,32 +184,38 @@ function TestsTable() {
}
const statusMap = {
preview: "Draft",
'in-progress': "Ongoing",
paused: "On Hold",
closed: "Closed",
}
preview: 'Draft',
'in-progress': 'Ongoing',
paused: 'On Hold',
closed: 'Closed',
};
function Row({ test, siteId }: { test: UxTListEntry, siteId: string }) {
const link = usabilityTestingView(test.testId.toString())
const editLink = usabilityTestingEdit(test.testId.toString())
const history = useHistory()
function Row({ test, siteId }: { test: UxTListEntry; siteId: string }) {
const link = usabilityTestingView(test.testId.toString());
const editLink = usabilityTestingEdit(test.testId.toString());
const history = useHistory();
const redirect = () => {
history.push(withSiteId(test.status === 'preview' ? editLink : link, siteId))
}
history.push(withSiteId(test.status === 'preview' ? editLink : link, siteId));
};
return (
<div className={'grid grid-cols-8 p-4 border-b hover:bg-active-blue cursor-pointer'} onClick={redirect}>
<div
className={'grid grid-cols-8 p-4 border-b hover:bg-active-blue cursor-pointer'}
onClick={redirect}
>
<Cell size={4}>
<div className={'flex items-center gap-2'}>
<div style={{ minWidth: 40 }}>
<div className={'rounded-full bg-tealx-light flex items-center justify-center'} style={{ width: 40, height: 40 }}>
<div
className={'rounded-full bg-tealx-light flex items-center justify-center'}
style={{ width: 40, height: 40 }}
>
<Icon name={'list-ul'} color={'tealx'} size={20} />
</div>
{/*<Avatar size={'large'} icon={<UnorderedListOutlined rev={undefined} />} />*/}
{/*<Avatar size={'large'} icon={<UnorderedListOutlined rev={undefined} />} />*/}
</div>
<div style={{ maxWidth: 550 }}>
<Link className='link' to={test.status === 'preview' ? editLink : link}>
<Link className="link" to={test.status === 'preview' ? editLink : link}>
{test.title}
</Link>
<div className={'text-disabled-text whitespace-nowrap text-ellipsis overflow-hidden'}>
@ -210,7 +225,9 @@ function Row({ test, siteId }: { test: UxTListEntry, siteId: string }) {
</div>
</Cell>
<Cell size={1}>{test.createdBy.name}</Cell>
<Cell size={2}>{checkForRecent(getDateFromMill(test.updatedAt)!, 'LLL dd, yyyy, hh:mm a')}</Cell>
<Cell size={2}>
{checkForRecent(getDateFromMill(test.updatedAt)!, 'LLL dd, yyyy, hh:mm a')}
</Cell>
<Cell size={1}>
<Tag color={colors[test.status]}>{statusMap[test.status]}</Tag>
</Cell>
@ -223,10 +240,10 @@ const colors = {
closed: 'grey',
paused: 'orange',
preview: 'geekblue',
} as const
} as const;
function Cell({ size, children }: { size: number; children?: React.ReactNode }) {
return <div className={`col-span-${size}`}>{children}</div>;
}
export default withPageTitle('Usability Tests')(observer(TestsTable))
export default withPageTitle('Usability Tests')(observer(TestsTable));

View file

@ -27,6 +27,7 @@ export enum ICONS {
NO_PROJECTS = 'ca-no-projects',
NO_FFLAGS = 'no-fflags',
PROCESSING = 'ca-processing',
NO_UXT = 'ca-no-uxt',
}
const ICONS_SVGS = {
@ -56,6 +57,7 @@ const ICONS_SVGS = {
[ICONS.NO_PROJECTS]: require('../../../svg/ca-no-projects.svg').default,
[ICONS.NO_FFLAGS]: require('../../../svg/no-fflags.svg').default,
[ICONS.PROCESSING]: require('../../../svg/ca-processing.svg').default,
[ICONS.NO_UXT]: require('../../../svg/empty-uxt-list.svg').default,
};
interface Props {

View file

@ -0,0 +1,20 @@
<svg width="173" height="112" viewBox="0 0 173 112" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="1.5" y="1.61172" width="170" height="109" rx="5" stroke="black" stroke-opacity="0.6" stroke-width="2"/>
<path d="M145.243 20.9749C144.648 21.5697 143.841 21.9039 143 21.9039C142.159 21.9039 141.352 21.5697 140.757 20.9749C140.162 20.3801 139.828 19.5733 139.828 18.732C139.828 17.8908 140.162 17.084 140.757 16.4892C141.352 15.8943 142.159 15.5602 143 15.5602C143.841 15.5602 144.648 15.8943 145.243 16.4892C145.838 17.084 146.172 17.8908 146.172 18.732C146.172 19.5733 145.838 20.3801 145.243 20.9749Z" fill="#434343" stroke="black"/>
<path d="M128.188 12.0492C127.408 12.0492 126.661 12.3587 126.11 12.9096C125.559 13.4605 125.25 14.2077 125.25 14.9867V26.7367C125.25 27.5158 125.559 28.263 126.11 28.8139C126.661 29.3647 127.408 29.6742 128.188 29.6742H157.812C158.592 29.6742 159.339 29.3647 159.89 28.8139C160.441 28.263 160.75 27.5158 160.75 26.7367V14.9867C160.75 14.2077 160.441 13.4605 159.89 12.9096C159.339 12.3587 158.592 12.0492 157.812 12.0492H128.188ZM150.047 28.2055C149.382 26.3402 147.462 23.7992 143 23.7992C138.539 23.7992 136.618 26.3402 135.953 28.2055H128.188C127.798 28.2055 127.424 28.0507 127.149 27.7753C126.873 27.4998 126.719 27.1263 126.719 26.7367V14.9867C126.719 14.5972 126.873 14.2236 127.149 13.9482C127.424 13.6727 127.798 13.518 128.188 13.518H157.812C158.202 13.518 158.576 13.6727 158.851 13.9482C159.127 14.2236 159.281 14.5972 159.281 14.9867V26.7367C159.281 27.1263 159.127 27.4998 158.851 27.7753C158.576 28.0507 158.202 28.2055 157.812 28.2055H150.047Z" fill="#434343"/>
<rect x="125" y="36.1117" width="36" height="19" rx="2.5" fill="#42AE5E" fill-opacity="0.1"/>
<rect x="125" y="36.1117" width="36" height="19" rx="2.5" stroke="black"/>
<path d="M148.854 41.2577C148.901 41.3042 148.938 41.3593 148.963 41.4201C148.988 41.4808 149.001 41.546 149.001 41.6117C149.001 41.6775 148.988 41.7426 148.963 41.8034C148.938 41.8641 148.901 41.9193 148.854 41.9657L141.854 48.9657C141.808 49.0123 141.753 49.0492 141.692 49.0744C141.631 49.0996 141.566 49.1126 141.5 49.1126C141.434 49.1126 141.369 49.0996 141.309 49.0744C141.248 49.0492 141.193 49.0123 141.146 48.9657L137.646 45.4657C137.552 45.3718 137.5 45.2445 137.5 45.1117C137.5 44.9789 137.552 44.8516 137.646 44.7577C137.74 44.6638 137.867 44.6111 138 44.6111C138.133 44.6111 138.26 44.6638 138.354 44.7577L141.5 47.9047L148.146 41.2577C148.193 41.2112 148.248 41.1742 148.309 41.149C148.369 41.1238 148.434 41.1108 148.5 41.1108C148.566 41.1108 148.631 41.1238 148.692 41.149C148.753 41.1742 148.808 41.2112 148.854 41.2577Z" fill="#42AE5E"/>
<rect x="125" y="59.1117" width="36" height="19" rx="2.5" fill="#42AE5E" fill-opacity="0.1"/>
<rect x="125" y="59.1117" width="36" height="19" rx="2.5" stroke="black"/>
<path d="M148.854 64.2577C148.901 64.3042 148.938 64.3593 148.963 64.4201C148.988 64.4808 149.001 64.546 149.001 64.6117C149.001 64.6775 148.988 64.7426 148.963 64.8034C148.938 64.8641 148.901 64.9193 148.854 64.9657L141.854 71.9657C141.808 72.0123 141.753 72.0492 141.692 72.0744C141.631 72.0996 141.566 72.1126 141.5 72.1126C141.434 72.1126 141.369 72.0996 141.309 72.0744C141.248 72.0492 141.193 72.0123 141.146 71.9657L137.646 68.4657C137.552 68.3718 137.5 68.2445 137.5 68.1117C137.5 67.9789 137.552 67.8516 137.646 67.7577C137.74 67.6638 137.867 67.6111 138 67.6111C138.133 67.6111 138.26 67.6638 138.354 67.7577L141.5 70.9047L148.146 64.2577C148.193 64.2112 148.248 64.1742 148.309 64.149C148.369 64.1238 148.434 64.1108 148.5 64.1108C148.566 64.1108 148.631 64.1238 148.692 64.149C148.753 64.1742 148.808 64.2112 148.854 64.2577Z" fill="#42AE5E"/>
<rect x="125" y="82.1117" width="36" height="19" rx="2.5" fill="#CC0000" fill-opacity="0.1"/>
<rect x="125" y="82.1117" width="36" height="19" rx="2.5" stroke="black"/>
<path d="M139.646 88.2577C139.692 88.2112 139.748 88.1742 139.808 88.149C139.869 88.1238 139.934 88.1108 140 88.1108C140.066 88.1108 140.131 88.1238 140.192 88.149C140.252 88.1742 140.307 88.2112 140.354 88.2577L143 90.9047L145.646 88.2577C145.692 88.2112 145.748 88.1744 145.808 88.1492C145.869 88.124 145.934 88.1111 146 88.1111C146.066 88.1111 146.131 88.124 146.192 88.1492C146.252 88.1744 146.307 88.2112 146.354 88.2577C146.4 88.3042 146.437 88.3594 146.462 88.4201C146.488 88.4809 146.501 88.546 146.501 88.6117C146.501 88.6775 146.488 88.7426 146.462 88.8033C146.437 88.864 146.4 88.9192 146.354 88.9657L143.707 91.6117L146.354 94.2577C146.4 94.3042 146.437 94.3594 146.462 94.4201C146.488 94.4809 146.501 94.546 146.501 94.6117C146.501 94.6775 146.488 94.7426 146.462 94.8033C146.437 94.864 146.4 94.9192 146.354 94.9657C146.307 95.0122 146.252 95.0491 146.192 95.0742C146.131 95.0994 146.066 95.1123 146 95.1123C145.934 95.1123 145.869 95.0994 145.808 95.0742C145.748 95.0491 145.692 95.0122 145.646 94.9657L143 92.3187L140.354 94.9657C140.307 95.0122 140.252 95.0491 140.192 95.0742C140.131 95.0994 140.066 95.1123 140 95.1123C139.934 95.1123 139.869 95.0994 139.808 95.0742C139.748 95.0491 139.692 95.0122 139.646 94.9657C139.599 94.9192 139.563 94.864 139.537 94.8033C139.512 94.7426 139.499 94.6775 139.499 94.6117C139.499 94.546 139.512 94.4809 139.537 94.4201C139.563 94.3594 139.599 94.3042 139.646 94.2577L142.293 91.6117L139.646 88.9657C139.599 88.9193 139.562 88.8641 139.537 88.8034C139.512 88.7426 139.499 88.6775 139.499 88.6117C139.499 88.546 139.512 88.4808 139.537 88.4201C139.562 88.3593 139.599 88.3042 139.646 88.2577Z" fill="#CC0000"/>
<g opacity="0.5">
<rect x="12.5" y="10.6117" width="104" height="58" rx="4" fill="#DDDDDD"/>
</g>
<g opacity="0.2">
<rect x="12.5" y="71.6117" width="104" height="31" rx="4" fill="#DDDDDD"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 5.6 KiB