fix(ui) uxt fixes

This commit is contained in:
nick-delirium 2023-12-07 10:18:47 +01:00
parent d791c386f6
commit 949207102d
5 changed files with 72 additions and 35 deletions

View file

@ -85,7 +85,7 @@ function FunnelWidget(props: Props) {
));
}
function EmptyStage({ total }: any) {
export function EmptyStage({ total }: any) {
return useObserver( () => (
<div className={cn("flex items-center mb-4 pb-3", stl.step)}>
<IndexNumber index={0} />

View file

@ -2,29 +2,49 @@ import React from 'react';
import { useStore } from 'App/mstore';
import { numberWithCommas } from 'App/utils';
import { Step } from 'Components/UsabilityTesting/TestEdit';
import OutsideClickDetectingDiv from 'Shared/OutsideClickDetectingDiv';
import { Loader, NoContent, Pagination } from 'UI';
import { Button, Typography, Input } from 'antd';
import { observer } from 'mobx-react-lite';
import { DownOutlined } from '@ant-design/icons';
import { debounce } from 'App/utils'
let debounceUpdate: any = () => {}
const ResponsesOverview = observer(() => {
const { uxtestingStore } = useStore();
const [search, setSearch] = React.useState('');
const [page, setPage] = React.useState(1);
const [showAll, setShowAll] = React.useState(false);
const [taskId, setTaskId] = React.useState(uxtestingStore.instance?.tasks[0].taskId);
const [taskId, setTaskId] = React.useState<number | undefined>(undefined);
React.useEffect(() => {
void refreshData();
setTaskId(uxtestingStore.instance?.tasks.filter((t) => t.allowTyping)[0].taskId);
}, [uxtestingStore.instance?.tasks]);
React.useEffect(() => {
if (taskId) {
void refreshData();
}
}, [page, taskId]);
const refreshData = () =>
debounceUpdate = debounce((text: string) => {
void refreshData(text);
}, 200)
const refreshDataQuery = (text: string) => {
setSearch(text)
debounceUpdate(text)
}
const refreshData = (searchText?: string) =>
taskId
? uxtestingStore.fetchResponses(uxtestingStore.instance!.testId!, taskId, page, search)
? uxtestingStore.fetchResponses(uxtestingStore.instance!.testId!, taskId, page, searchText || search)
: null;
const selectedIndex = uxtestingStore.instance?.tasks.findIndex((task) => task.taskId === taskId)!;
const task = uxtestingStore.instance?.tasks.find((task) => task.taskId === taskId);
return (
<div style={{ width: 900 }} className={'h-screen p-4 bg-white flex flex-col gap-4'}>
<Typography.Title style={{ marginBottom: 0 }} level={4}>
@ -32,26 +52,28 @@ const ResponsesOverview = observer(() => {
</Typography.Title>
<div className={'flex flex-col gap-1 relative'}>
<Typography.Text strong>Select Task / Question</Typography.Text>
<Step
ind={selectedIndex}
title={task!.title}
description={task!.description}
buttons={
<div className={'self-center'}>
<Button
onClick={() => setShowAll(!showAll)}
icon={<DownOutlined rotate={showAll ? 180 : 0} rev={undefined} />}
size={'small'}
/>
</div>
}
/>
<OutsideClickDetectingDiv onClickOutside={() => setShowAll(false)}>
<div className={'cursor-pointer'} onClick={() => setShowAll(!showAll)}>
<Step
ind={selectedIndex ?? 0}
title={task?.title ?? 'Title'}
description={task?.description ?? 'Description'}
buttons={
<div className={'self-center'}>
<Button
onClick={() => setShowAll(!showAll)}
icon={<DownOutlined rotate={showAll ? 180 : 0} rev={undefined} />}
size={'small'}
/>
</div>
}
/>
</div>
</OutsideClickDetectingDiv>
{showAll ? (
<div
className={
'flex flex-col overflow-auto absolute bottom-0 w-full gap-1 z-20 rounded bg-gray-lightest border shadow'
}
style={{ maxHeight: 300, transform: 'translateY(110%)' }}
className={'flex flex-col overflow-auto absolute bottom-0 w-full z-20'}
style={{ maxHeight: 300, transform: 'translateY(100%)' }}
>
{uxtestingStore.instance?.tasks
.filter((t) => t.taskId !== taskId && t.allowTyping)
@ -87,8 +109,8 @@ const ResponsesOverview = observer(() => {
</div>
<Input.Search
allowClear
placeholder={'Filter by keyboard or participant'}
onChange={(e) => setSearch(e.target.value)}
placeholder={'Filter by keyword or participant'}
onChange={(e) => refreshDataQuery(e.target.value)}
classNames={{ input: '!border-0 focus:!border-0' }}
onSearch={() => refreshData()}
/>

View file

@ -16,6 +16,7 @@ import { confirm } from 'UI';
import StepsModal from './StepsModal';
import SidePanel from './SidePanel';
import usePageTitle from 'App/hooks/usePageTitle';
import { toast } from 'react-toastify'
const menuItems = [
{
@ -71,6 +72,7 @@ function TestEdit() {
setHasChanged(false);
if (testId && testId !== 'new') {
uxtestingStore.updateTest(uxtestingStore.instance!).then((testId) => {
toast.success('The usability test is now live and accessible to participants.');
history.push(withSiteId(usabilityTestingView(testId!.toString()), siteId));
});
} else {

View file

@ -29,18 +29,18 @@ import {
} from '@ant-design/icons';
import SessionItem from 'Shared/SessionItem';
import { CopyButton, Loader, NoContent, Pagination } from 'UI';
import copy from 'copy-to-clipboard';
import { Stage } from 'Components/Funnels/FunnelWidget/FunnelWidget';
import { Stage, EmptyStage } from 'Components/Funnels/FunnelWidget/FunnelWidget';
import { confirm } from 'UI';
import ResponsesOverview from './ResponsesOverview';
import ParticipantOverviewItem from 'Components/UsabilityTesting/ParticipantOverview';
import { toast } from 'react-toastify'
const { Option } = Select;
const statusItems = [
{ value: 'in-progress', label: 'Ongoing', icon: <HourglassOutlined rev={undefined} /> },
{ value: 'paused', label: 'On Hold', icon: <PauseCircleOutlined rev={undefined} /> },
{ value: 'closed', label: 'Closed', icon: <StopOutlined rev={undefined} /> },
{ value: 'paused', label: 'Hold', icon: <PauseCircleOutlined rev={undefined} /> },
{ value: 'closed', label: 'Close', icon: <StopOutlined rev={undefined} /> },
];
const menuItems = [
@ -310,9 +310,9 @@ const TaskSummary = observer(() => {
index={index + 1}
/>
))}
{shouldHide ? (
<div onClick={() => setShowAll(!showAll)} className={'link mt-4'}>
{showAll ? 'Hide' : 'Show All'}
{shouldHide && !showAll ? (
<div className={'cursor-pointer'} onClick={() => setShowAll(true)}>
<EmptyStage total={uxtestingStore.taskStats.length - 5}/>
</div>
) : null}
</div>
@ -326,6 +326,17 @@ const Title = observer(({ testId, siteId }: any) => {
const handleChange = (value: string) => {
uxtestingStore.updateTestStatus(value);
switch (value) {
case 'in-progress':
toast.success('The usability test is now live and accessible to participants.');
break;
case 'paused':
toast.success('Usability test is on \'Hold\'—participant activity paused. Resume at your convenience.');
break;
case 'closed':
toast.success('he usability test has been marked as completed. All participant interactions are now finalized.');
break;
}
};
const onMenuClick = async ({ key }: any) => {
@ -397,7 +408,8 @@ const Title = observer(({ testId, siteId }: any) => {
title={'Participants Link'}
content={
<div style={{ width: '220px' }}>
<div className={'p-2 bg-white rounded border break-all mb-2'}>
Distribute following link via email or other methods to share the survey with test participants.
<div style={{ background: '#E4F6F6'}} className={'p-2 rounded border shadow break-all my-2'}>
{`${uxtestingStore.instance!.startingPath}?oruxt=${
uxtestingStore.instance!.testId
}`}

View file

@ -123,8 +123,9 @@ function SessionItem(props: RouteComponentProps & Props) {
!ignoreAssist &&
(isRoute(ASSIST_ROUTE, location.pathname) ||
isRoute(ASSIST_LIVE_SESSION, location.pathname) ||
location.pathname.includes('multiview'))
|| location.pathname.includes('usability-testing');
location.pathname.includes('multiview')) ||
props.live
const isLastPlayed = lastPlayedSessionId === sessionId;
const _metaList = Object.keys(metadata)