From 7dbd2ecea2ae835e9850bbb13d7b3f549a88d4ec Mon Sep 17 00:00:00 2001 From: nick-delirium Date: Thu, 7 Dec 2023 12:10:59 +0100 Subject: [PATCH] fix(ui) uxt fixes --- .../components/UsabilityTesting/TestEdit.tsx | 3 +- .../UsabilityTesting/TestOverview.tsx | 108 ++++++++++++------ .../UsabilityTesting/UsabilityTesting.tsx | 8 +- frontend/app/mstore/uxtestingStore.ts | 3 - tracker/tracker/package.json | 2 +- .../src/main/modules/userTesting/index.ts | 19 ++- .../src/main/modules/userTesting/styles.ts | 3 +- 7 files changed, 87 insertions(+), 59 deletions(-) diff --git a/frontend/app/components/UsabilityTesting/TestEdit.tsx b/frontend/app/components/UsabilityTesting/TestEdit.tsx index 9bdcabf05..e233789f2 100644 --- a/frontend/app/components/UsabilityTesting/TestEdit.tsx +++ b/frontend/app/components/UsabilityTesting/TestEdit.tsx @@ -170,6 +170,7 @@ function TestEdit() { Test Objective (optional) { setHasChanged(true); setNewTestDescription(e.target.value); @@ -222,7 +223,7 @@ function TestEdit() { {isOverviewEditing ? ( }, - { value: 'paused', label: 'Hold', icon: }, - { value: 'closed', label: 'Close', icon: }, + { value: 'in-progress', label: 'Ongoing' }, + { value: 'paused', label: 'Hold' }, + { value: 'closed', label: 'Close' }, ]; const menuItems = [ - { - key: '1', - label: 'Download Results', - icon: , - }, + // { + // key: '1', + // label: 'Download Results', + // icon: , + // }, { key: '2', label: 'Edit', @@ -82,7 +76,7 @@ function TestOverview() { }; return ( -
+
-
+
{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); diff --git a/frontend/app/components/UsabilityTesting/UsabilityTesting.tsx b/frontend/app/components/UsabilityTesting/UsabilityTesting.tsx index e4f596678..3adec71fe 100644 --- a/frontend/app/components/UsabilityTesting/UsabilityTesting.tsx +++ b/frontend/app/components/UsabilityTesting/UsabilityTesting.tsx @@ -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 }) { diff --git a/frontend/app/mstore/uxtestingStore.ts b/frontend/app/mstore/uxtestingStore.ts index 29ba6b6bb..cba6f8f56 100644 --- a/frontend/app/mstore/uxtestingStore.ts +++ b/frontend/app/mstore/uxtestingStore.ts @@ -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); } }; diff --git a/tracker/tracker/package.json b/tracker/tracker/package.json index a5e9b90d2..7d974a6a5 100644 --- a/tracker/tracker/package.json +++ b/tracker/tracker/package.json @@ -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" diff --git a/tracker/tracker/src/main/modules/userTesting/index.ts b/tracker/tracker/src/main/modules/userTesting/index.ts index b2c97edb2..2bc8e502d 100644 --- a/tracker/tracker/src/main/modules/userTesting/index.ts +++ b/tracker/tracker/src/main/modules/userTesting/index.ts @@ -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') diff --git a/tracker/tracker/src/main/modules/userTesting/styles.ts b/tracker/tracker/src/main/modules/userTesting/styles.ts index 5de928d71..ab23e9143 100644 --- a/tracker/tracker/src/main/modules/userTesting/styles.ts +++ b/tracker/tracker/src/main/modules/userTesting/styles.ts @@ -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 = {