openreplay/frontend/app/mstore/uxtestingStore.ts
Andrey Babushkin fd5c0c9747
Add lokalisation (#3092)
* applied eslint

* add locales and lint the project

* removed error boundary

* updated locales

* fix min files

* fix locales
2025-03-06 17:43:15 +01:00

385 lines
8.5 KiB
TypeScript

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<number, { list: Response[]; total: number }> = {};
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<UxTSearchFilters> = {
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<UxTestInst> = {}) {
makeAutoObservable(this);
Object.assign(this, initialData);
}
setProperty<T extends keyof UxTestInst>(key: T, value: UxTestInst[T]) {
(this[key] as UxTestInst[T]) = value;
}
}