fix(ui) uxt fixes
This commit is contained in:
parent
68ead7292e
commit
7dbd2ecea2
7 changed files with 87 additions and 59 deletions
|
|
@ -170,6 +170,7 @@ function TestEdit() {
|
|||
<Typography.Text strong>Test Objective (optional)</Typography.Text>
|
||||
<Input.TextArea
|
||||
value={newTestDescription}
|
||||
rows={6}
|
||||
onChange={(e) => {
|
||||
setHasChanged(true);
|
||||
setNewTestDescription(e.target.value);
|
||||
|
|
@ -222,7 +223,7 @@ function TestEdit() {
|
|||
{isOverviewEditing ? (
|
||||
<Input.TextArea
|
||||
autoFocus
|
||||
rows={5}
|
||||
rows={6}
|
||||
placeholder={
|
||||
'Enter a brief introduction to the test and its goals here. Follow with clear, step-by-step guidelines for participants.'
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import { durationFormatted } from 'App/date';
|
||||
import usePageTitle from 'App/hooks/usePageTitle';
|
||||
import { numberWithCommas } from 'App/utils';
|
||||
import { getPdf2 } from 'Components/AssistStats/pdfGenerator';
|
||||
import { useModal } from 'Components/Modal';
|
||||
|
|
@ -20,10 +19,7 @@ import {
|
|||
UserDeleteOutlined,
|
||||
CheckCircleOutlined,
|
||||
FastForwardOutlined,
|
||||
PauseCircleOutlined,
|
||||
StopOutlined,
|
||||
HourglassOutlined,
|
||||
FilePdfOutlined,
|
||||
// FilePdfOutlined,
|
||||
DeleteOutlined,
|
||||
ClockCircleOutlined,
|
||||
} from '@ant-design/icons';
|
||||
|
|
@ -33,22 +29,20 @@ 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;
|
||||
import { toast } from 'react-toastify';
|
||||
|
||||
const statusItems = [
|
||||
{ value: 'in-progress', label: 'Ongoing', icon: <HourglassOutlined rev={undefined} /> },
|
||||
{ value: 'paused', label: 'Hold', icon: <PauseCircleOutlined rev={undefined} /> },
|
||||
{ value: 'closed', label: 'Close', icon: <StopOutlined rev={undefined} /> },
|
||||
{ value: 'in-progress', label: 'Ongoing' },
|
||||
{ value: 'paused', label: 'Hold' },
|
||||
{ value: 'closed', label: 'Close' },
|
||||
];
|
||||
|
||||
const menuItems = [
|
||||
{
|
||||
key: '1',
|
||||
label: 'Download Results',
|
||||
icon: <FilePdfOutlined rev={undefined} />,
|
||||
},
|
||||
// {
|
||||
// key: '1',
|
||||
// label: 'Download Results',
|
||||
// icon: <FilePdfOutlined rev={undefined} />,
|
||||
// },
|
||||
{
|
||||
key: '2',
|
||||
label: 'Edit',
|
||||
|
|
@ -82,7 +76,7 @@ function TestOverview() {
|
|||
};
|
||||
|
||||
return (
|
||||
<div className="w-full mx-auto" style={{ maxWidth: '1360px' }}>
|
||||
<div className="w-full mx-auto" style={{ maxWidth: '1360px' }} id={'pdf-anchor'}>
|
||||
<Breadcrumb
|
||||
items={[
|
||||
{
|
||||
|
|
@ -94,13 +88,13 @@ function TestOverview() {
|
|||
},
|
||||
]}
|
||||
/>
|
||||
<div className={'rounded border bg-white'} id={'pdf-anchor'}>
|
||||
<div className={'rounded border bg-white'}>
|
||||
<Title testId={testId} siteId={siteId} />
|
||||
{uxtestingStore.instance.liveCount ? (
|
||||
<div className={'p-4 flex items-center gap-2'}>
|
||||
<div className={'relative h-4 w-4'}>
|
||||
<div className={'absolute w-4 h-4 animate-ping bg-tealx rounded-full opacity-75'} />
|
||||
<div className={'absolute w-4 h-4 bg-tealx rounded-full'} />
|
||||
<div className={'absolute w-4 h-4 animate-ping bg-green rounded-full opacity-75'} />
|
||||
<div className={'absolute w-4 h-4 bg-green rounded-full'} />
|
||||
</div>
|
||||
<Typography.Text>
|
||||
{uxtestingStore.instance.liveCount} participants are engaged in this usability test at
|
||||
|
|
@ -312,7 +306,7 @@ const TaskSummary = observer(() => {
|
|||
))}
|
||||
{shouldHide && !showAll ? (
|
||||
<div className={'cursor-pointer'} onClick={() => setShowAll(true)}>
|
||||
<EmptyStage total={uxtestingStore.taskStats.length - 5}/>
|
||||
<EmptyStage total={uxtestingStore.taskStats.length - 5} />
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
|
|
@ -331,10 +325,14 @@ const Title = observer(({ testId, siteId }: any) => {
|
|||
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. Switch it to “ongoing” to resume activity.');
|
||||
toast.success(
|
||||
"Usability test is on 'Hold'—participant activity paused. Switch it to “ongoing” to resume activity."
|
||||
);
|
||||
break;
|
||||
case 'closed':
|
||||
toast.success('The usability test has been marked as completed. All participant interactions are now finalized.');
|
||||
toast.success(
|
||||
'The usability test has been marked as completed. All participant interactions are now finalized.'
|
||||
);
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
|
@ -369,10 +367,18 @@ const Title = observer(({ testId, siteId }: any) => {
|
|||
? uxtestingStore.instance?.description.substring(0, 250) + '...'
|
||||
: uxtestingStore.instance?.description;
|
||||
const redirectToEdit = async () => {
|
||||
const confirmationTitle =
|
||||
uxtestingStore.instance!.status === 'in-progress'
|
||||
? 'Editing Active Usability Test'
|
||||
: 'Editing Test on Hold';
|
||||
const confirmationStr =
|
||||
uxtestingStore.instance!.status === 'in-progress'
|
||||
? "You're editing a test that's currently active. Please be aware that you can only modify the test title and objective. Editing test steps is not permitted to avoid confusion with existing responses. Proceed with caution! 🚧"
|
||||
: 'This usability test is on hold. You can only update the title and descriptions. Task editing is not allowed to avoid confusion with existing responses.';
|
||||
if (
|
||||
await confirm({
|
||||
confirmation:
|
||||
'This test already has responses, making edits at this stage may result in confusing outcomes.',
|
||||
header: confirmationTitle,
|
||||
confirmation: confirmationStr,
|
||||
confirmButton: 'Edit',
|
||||
})
|
||||
) {
|
||||
|
|
@ -380,6 +386,9 @@ const Title = observer(({ testId, siteId }: any) => {
|
|||
}
|
||||
};
|
||||
|
||||
// @ts-ignore
|
||||
const getColor = (status) => colors[status];
|
||||
|
||||
return (
|
||||
<div className={'p-4 border-b'}>
|
||||
<div className={'flex items-center gap-2'}>
|
||||
|
|
@ -389,16 +398,21 @@ const Title = observer(({ testId, siteId }: any) => {
|
|||
value={uxtestingStore.instance!.status}
|
||||
style={{ width: 150 }}
|
||||
onChange={handleChange}
|
||||
options={statusItems}
|
||||
optionRender={(item) => (
|
||||
<Space align={'center'}>
|
||||
<div
|
||||
style={{ background: getColor(item.value), width: 12, height: 12, borderRadius: 32 }}
|
||||
/>
|
||||
{item.data.icon} {item.label}
|
||||
</Space>
|
||||
)}
|
||||
/>
|
||||
<Button
|
||||
disabled={uxtestingStore.instance!.status === 'closed'}
|
||||
type={'primary'}
|
||||
onClick={redirectToEdit}
|
||||
>
|
||||
{statusItems.map((item) => (
|
||||
<Option key={item.value} value={item.value} label={item.label}>
|
||||
<Space align={'center'}>
|
||||
{item.icon} {item.label}
|
||||
</Space>
|
||||
</Option>
|
||||
))}
|
||||
</Select>
|
||||
<Button type={'primary'} onClick={redirectToEdit}>
|
||||
<Space align={'center'}>
|
||||
{uxtestingStore.instance!.tasks.length} Tasks <EditOutlined rev={undefined} />{' '}
|
||||
</Space>
|
||||
|
|
@ -408,8 +422,12 @@ const Title = observer(({ testId, siteId }: any) => {
|
|||
title={'Participants Link'}
|
||||
content={
|
||||
<div style={{ width: '220px' }}>
|
||||
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'}>
|
||||
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
|
||||
}`}
|
||||
|
|
@ -430,7 +448,15 @@ const Title = observer(({ testId, siteId }: any) => {
|
|||
</Space>
|
||||
</Button>
|
||||
</Popover>
|
||||
<Dropdown menu={{ items: menuItems, onClick: onMenuClick }}>
|
||||
<Dropdown
|
||||
menu={{
|
||||
items:
|
||||
uxtestingStore.instance!.status === 'closed'
|
||||
? menuItems.filter((i) => i.label !== 'Edit')
|
||||
: menuItems,
|
||||
onClick: onMenuClick,
|
||||
}}
|
||||
>
|
||||
<Button icon={<MoreOutlined rev={undefined} />}></Button>
|
||||
</Dropdown>
|
||||
</div>
|
||||
|
|
@ -443,4 +469,12 @@ const Title = observer(({ testId, siteId }: any) => {
|
|||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
const colors = {
|
||||
'in-progress': '#52c41a',
|
||||
closed: '#bfbfbf',
|
||||
paused: '#fa8c16',
|
||||
preview: '#2f54eb',
|
||||
};
|
||||
|
||||
export default observer(TestOverview);
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@ function TestsTable() {
|
|||
/>
|
||||
<Typography.Text strong>Test Objective (optional)</Typography.Text>
|
||||
<Input.TextArea
|
||||
rows={9}
|
||||
rows={6}
|
||||
value={newTestDescription}
|
||||
onChange={(e) => setNewTestDescription(e.target.value)}
|
||||
placeholder="Share a brief statement about what you aim to discover through this study."
|
||||
|
|
@ -220,9 +220,9 @@ function Row({ test, siteId }: { test: UxTListEntry, siteId: string }) {
|
|||
|
||||
const colors = {
|
||||
'in-progress': 'green',
|
||||
closed: 'geekblue',
|
||||
paused: 'grey',
|
||||
preview: 'orange',
|
||||
closed: 'grey',
|
||||
paused: 'orange',
|
||||
preview: 'geekblue',
|
||||
} as const
|
||||
|
||||
function Cell({ size, children }: { size: number; children?: React.ReactNode }) {
|
||||
|
|
|
|||
|
|
@ -135,13 +135,10 @@ export default class UxtestingStore {
|
|||
};
|
||||
|
||||
fetchResponses = async (testId: number, taskId: number, page: number, query?: string) => {
|
||||
this.setLoading(true);
|
||||
try {
|
||||
this.responses[taskId] = await this.client.fetchTaskResponses(testId, taskId, page, 10, query);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
} finally {
|
||||
this.setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "@openreplay/tracker",
|
||||
"description": "The OpenReplay tracker main package",
|
||||
"version": "11.0.0",
|
||||
"version": "11.0.1-6",
|
||||
"keywords": [
|
||||
"logging",
|
||||
"replay"
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import App from '../../app/index.js'
|
||||
import { containerStyle } from './styles.js'
|
||||
import * as styles from './styles.js'
|
||||
import Recorder, { Quality } from './recorder.js'
|
||||
import attachDND from './dnd.js'
|
||||
|
|
@ -181,15 +182,9 @@ export default class UserTestManager {
|
|||
'div',
|
||||
'description',
|
||||
styles.descriptionStyle,
|
||||
'Welcome, this session will be recorded. You have complete control, and can stop the session at any time.',
|
||||
)
|
||||
const noticeElement = createElement(
|
||||
'div',
|
||||
'notice',
|
||||
styles.noticeStyle,
|
||||
`Please note that your ${micRequired ? 'audio,' : ''} ${cameraRequired ? 'video,' : ''} ${
|
||||
micRequired || cameraRequired ? 'and' : ''
|
||||
} screen will be recorded for research purposes during this test.`,
|
||||
`Welcome, you're here to help us improve, not to be judged. Your insights matter!\n
|
||||
📹 We're recording this browser tab to learn from your experience.
|
||||
🎤 Please enable mic and camera if asked, to give us a complete picture.`,
|
||||
)
|
||||
const buttonElement = createElement(
|
||||
'div',
|
||||
|
|
@ -204,7 +199,6 @@ export default class UserTestManager {
|
|||
void this.userRecorder.startRecording(30, Quality.Standard, micRequired, cameraRequired)
|
||||
}
|
||||
this.container.removeChild(buttonElement)
|
||||
this.container.removeChild(noticeElement)
|
||||
this.container.removeChild(descriptionElement)
|
||||
this.container.removeChild(titleElement)
|
||||
return false
|
||||
|
|
@ -213,10 +207,11 @@ export default class UserTestManager {
|
|||
this.removeGreeting()
|
||||
this.durations.testStart = this.app.timestamp()
|
||||
void this.signalTest('begin')
|
||||
this.container.style.gap = '8px'
|
||||
this.showWidget(this.test?.guidelines || '', this.test?.tasks || [])
|
||||
}
|
||||
|
||||
this.container.append(titleElement, descriptionElement, noticeElement, buttonElement)
|
||||
this.container.append(titleElement, descriptionElement, buttonElement)
|
||||
this.bg.appendChild(this.container)
|
||||
document.body.appendChild(this.bg)
|
||||
}
|
||||
|
|
@ -247,7 +242,7 @@ export default class UserTestManager {
|
|||
})
|
||||
// Create title section
|
||||
const titleSection = this.createTitleSection()
|
||||
Object.assign(this.container.style, styles.containerWidgetStyle)
|
||||
Object.assign(this.container.style, styles.containerStyle)
|
||||
const descriptionSection = this.createDescriptionSection(guidelines)
|
||||
const tasksSection = this.createTasksSection(tasks)
|
||||
const stopButton = createElement('div', 'stop_bn_or', styles.stopWidgetStyle, 'Abort Session')
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ export const containerStyle = {
|
|||
export const containerWidgetStyle = {
|
||||
display: 'flex',
|
||||
'flex-direction': 'column',
|
||||
gap: '8px',
|
||||
gap: '1.5rem',
|
||||
'align-items': 'center',
|
||||
padding: '1rem',
|
||||
'border-radius': '0.375rem',
|
||||
|
|
@ -53,6 +53,7 @@ export const descriptionStyle = {
|
|||
fontStyle: 'normal',
|
||||
fontWeight: '400',
|
||||
lineHeight: '1.5rem',
|
||||
whiteSpace: 'pre-wrap',
|
||||
}
|
||||
|
||||
export const noticeStyle = {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue