import { uxtestingService } from 'App/services'; import { UxTask, UxTSearchFilters, UxTListEntry, UxTest, } from 'App/services/UxtestingService'; import { makeAutoObservable } from 'mobx'; import Session from 'Types/session'; interface Stats { completed_all_tasks: number; tasks_completed: number; tasks_skipped: number; tests_attempts: number; tests_skipped: number; } interface TaskStats { taskId: number; title: string; completed: number; avgCompletionTime: number; skipped: number; } interface Response { user_id: string | null; status: string; comment: string; timestamp: number; duration: number; } const defaultGuidelines = ''; const defaultConclusion = "Thank you for your feedback. It's very important and will help us improve our product."; export default class UxtestingStore { client = uxtestingService; tests: UxTListEntry[] = []; instance: UxTestInst | null = null; instanceCreationSiteId = ''; page: number = 1; total: number = 0; pageSize: number = 10; searchQuery: string = ''; testStats: Stats | null = null; testSessions: { list: Session[]; total: number; page: number } = { list: [], total: 0, page: 1, }; testAssistSessions: { list: Session[]; total: number; page: number } = { list: [], total: 0, page: 1, }; taskStats: TaskStats[] = []; isLoading: boolean = false; responses: Record = {}; hideDevtools: boolean = localStorage.getItem('or_devtools_uxt_toggle') === '1'; constructor() { makeAutoObservable(this); } isUxt() { const queryParams = new URLSearchParams(document.location.search); return queryParams.has('uxt'); } setHideDevtools(hide: boolean) { this.hideDevtools = hide; } setLoading(loading: boolean) { this.isLoading = loading; } setList(tests: UxTListEntry[]) { this.tests = tests; } setTotal(total: number) { this.total = total; } setPage(page: number) { this.page = page; } updateTestStatus = async (status: string) => { if (!this.instance) return; this.setLoading(true); try { const test: UxTest = { ...this.instance!, status, }; this.updateInstStatus(status); await this.client.updateTest(this.instance.testId!, test); } catch (e) { console.error(e); } finally { this.setLoading(false); } }; updateTest = async (test: UxTestInst, isPreview?: boolean) => { if (!this.instance) return; this.setLoading(true); try { if (!isPreview) { this.instance.setProperty('status', 'in-progress'); } await this.client.updateTest(this.instance.testId!, test); return test.testId; } catch (e) { console.error(e); } finally { this.setLoading(false); } }; updateInstStatus = (status: string) => { if (!this.instance) return; this.instance.setProperty('status', status); }; fetchResponses = async ( testId: number, taskId: number, page: number, query?: string, ) => { try { this.responses[taskId] = await this.client.fetchTaskResponses( testId, taskId, page, 10, query, ); } catch (e) { console.error(e); } }; initNewTest(title: string, description: string, siteId: string) { this.instanceCreationSiteId = siteId; const initialData = { title, startingPath: 'https://', requireMic: false, requireCamera: false, description, guidelines: defaultGuidelines, conclusionMessage: defaultConclusion, visibility: true, tasks: [], }; this.setInstance(new UxTestInst(initialData)); } deleteTest = async (testId: number) => this.client.deleteTest(testId); setInstance(instance: UxTestInst) { this.instance = instance; } setQuery(query: string) { this.searchQuery = query; } getList = async () => { this.setLoading(true); try { const filters: Partial = { query: this.searchQuery, page: this.page, limit: this.pageSize, sortBy: 'created_at', sortOrder: 'desc', }; const { list, total } = await this.client.fetchTestsList(filters); this.setList(list); this.setTotal(total); } catch (e) { console.error(e); } finally { this.setLoading(false); } }; createNewTest = async (isPreview?: boolean) => { this.setLoading(true); try { // @ts-ignore return await this.client.createTest({ ...this.instance, status: isPreview ? 'preview' : 'in-progress', }); } catch (e) { console.error(e); } finally { this.setLoading(false); } }; getTestData = async (testId: string) => { this.setLoading(true); try { const test = await this.client.fetchTest(testId); this.setInstance(new UxTestInst(test)); return this.instance; } catch (e) { console.error(e); } finally { this.setLoading(false); } }; setTestStats(stats: Stats) { this.testStats = stats; } setTaskStats(stats: TaskStats[]) { this.taskStats = stats; } setTestSessions(sessions: { list: Session[]; total: number; page: number }) { this.testSessions = sessions; } setSessionsPage(page: number) { this.testSessions.page = page; this.client .fetchTestSessions( this.instance!.testId!.toString(), this.testSessions.page, 10, ) .then((result) => { this.setTestSessions(result); }); } setAssistSessions = (data: { sessions: Session[]; total: number; page: number; }) => { this.testAssistSessions = { list: data.sessions.map((s: any) => new Session({ ...s, metadata: {} })), total: data.total, page: data.page, }; }; getAssistSessions = async (testId: string, page: number, userId?: string) => { try { const sessions = await this.client.fetchTestSessions( testId, page, 10, true, userId, ); this.setAssistSessions(sessions); } catch (e) { console.error(e); } }; getTest = async (testId: string) => { this.setLoading(true); try { const testPr = this.client.fetchTest(testId); const statsPr = this.client.fetchTestStats(testId); const taskStatsPr = this.client.fetchTestTaskStats(testId); const sessionsPr = this.client.fetchTestSessions( testId, this.testSessions.page, 10, ); return Promise.allSettled([testPr, statsPr, taskStatsPr, sessionsPr]) .then((results) => { if (results[0].status === 'fulfilled') { const test = results[0].value; if (test) { this.setInstance(new UxTestInst(test)); } } else { throw 'Test not found'; } if (results[1].status === 'fulfilled') { const stats = results[1].value; if (stats) { this.setTestStats(stats); } } if (results[2].status === 'fulfilled') { const taskStats = results[2].value; if (taskStats) { this.setTaskStats( taskStats.sort((a: any, b: any) => a.taskId - b.taskId), ); } } if (results[3].status === 'fulfilled') { const { total, page, sessions } = results[3].value; if (sessions) { const result = { list: sessions.map( (s: any) => new Session({ ...s, metadata: {} }), ), total, page, }; this.setTestSessions(result); } } }) .then(() => true); } catch (e) { console.error(e); return false; } finally { this.setLoading(false); } }; } class UxTestInst { title: string = ''; requireMic: boolean = false; requireCamera: boolean = false; description: string = ''; guidelines: string = ''; visibility: boolean = false; tasks: UxTask[] = []; status: string; startingPath: string; testId?: number; responsesCount?: number; liveCount?: number; conclusionMessage: string; constructor(initialData: Partial = {}) { makeAutoObservable(this); Object.assign(this, initialData); } setProperty(key: T, value: UxTestInst[T]) { (this[key] as UxTestInst[T]) = value; } }