diff --git a/src/entities/abTrail/lib/types/test.ts b/src/entities/abTrail/lib/types/test.ts index 9bde68c05..90c03961a 100644 --- a/src/entities/abTrail/lib/types/test.ts +++ b/src/entities/abTrail/lib/types/test.ts @@ -29,12 +29,6 @@ export type OnResultLog = { currentIndex: number; }; -export type StreamEventPoint = { - x: number; - y: number; - time: number; -}; - export type AbTestResult = { width: number; startTime: number; diff --git a/src/entities/abTrail/ui/AbCanvas.tsx b/src/entities/abTrail/ui/AbCanvas.tsx index cdf57915e..c41190c42 100644 --- a/src/entities/abTrail/ui/AbCanvas.tsx +++ b/src/entities/abTrail/ui/AbCanvas.tsx @@ -13,17 +13,15 @@ import { } from '@shopify/react-native-skia'; import { AbTestPayload, Point, TestNode } from '@app/abstract/lib'; -import { StreamEventLoggable } from '@shared/lib'; +import { + AbTestStreamEvent, + AbTestStreamEventErrorType, + StreamEventLoggable, +} from '@shared/lib'; import { Box, BoxProps } from '@shared/ui'; import AbShapes from './AbShapes'; -import { - LogLine, - LogPoint, - MessageType, - OnResultLog, - StreamEventPoint, -} from '../lib'; +import { LogLine, LogPoint, MessageType, OnResultLog } from '../lib'; import { getDistance, transformCoordinates } from '../lib/utils'; const paint = Skia.Paint(); @@ -41,7 +39,7 @@ type Props = { onLogResult: (data: OnResultLog) => void; onMessage: (message: MessageType) => void; onComplete: () => void; -} & StreamEventLoggable & +} & StreamEventLoggable & BoxProps; const AbCanvas: FC = props => { @@ -78,7 +76,7 @@ const AbCanvas: FC = props => { onMessage, width, readonly, - onLog, + onLog: onAddPointToStream, } = props; const canvasData = useMemo( @@ -195,24 +193,73 @@ const AbCanvas: FC = props => { return foundNode ?? null; }; - const createLogPoint = (point: Point): LogPoint => { + const getCurrentAndNextNodeLabels = () => { const index = getCurrentIndex(); const currentNode = findNodeByIndex(index); const nextNode = findNodeByIndex(index + 1); + return [currentNode.label, nextNode.label]; + }; + + const createLogPoint = (point: Point): LogPoint => { + const [currentNodeLabel, nextNodeLabel] = getCurrentAndNextNodeLabels(); + const logPoint: LogPoint = { x: point.x, y: point.y, time: new Date().getTime(), valid: null, - start: currentNode.label, - end: nextNode.label, + start: currentNodeLabel, + end: nextNodeLabel, actual: null, }; return logPoint; }; + const createStreamEventPoint = (point: Point): AbTestStreamEvent => { + const [currentNodeLabel, nextNodeLabel] = getCurrentAndNextNodeLabels(); + + return { + x: (point.x * width) / 100, + y: (point.y * width) / 100, + time: Date.now(), + lineNumber: logLines?.length - 1, + error: AbTestStreamEventErrorType.NotDefined, + currentNodeLabel, + nextNodeLabel, + type: 'AbTest', + }; + }; + + const addOverCorrectPointToStream = (point: Point) => { + const streamEventPoint = createStreamEventPoint(point); + streamEventPoint.error = AbTestStreamEventErrorType.OverCorrectPoint; + + onAddPointToStream(streamEventPoint); + }; + + const addOverWrongPointToStream = (point: Point, wrongPointLabel: string) => { + const streamEventPoint = createStreamEventPoint(point); + streamEventPoint.error = AbTestStreamEventErrorType.OverWrongPoint; + streamEventPoint.wrongPointLabel = wrongPointLabel; + + onAddPointToStream(streamEventPoint); + }; + + const addPointToStream = (point: Point) => { + const streamEventPoint = createStreamEventPoint(point); + + onAddPointToStream(streamEventPoint); + }; + + const addOverUndefinedPointToStream = (point: Point) => { + const streamEventPoint = createStreamEventPoint(point); + streamEventPoint.error = AbTestStreamEventErrorType.OverUndefinedPoint; + + onAddPointToStream(streamEventPoint); + }; + const addLogLine = ({ x, y }: Point): void => { const newLine: LogLine = { points: [createLogPoint({ x, y })], @@ -274,11 +321,8 @@ const AbCanvas: FC = props => { reCreatePath(point); drawPath(); reRender(); - onLog({ - x: (touchInfo.x * width) / 100, - y: (touchInfo.y * width) / 100, - time: Date.now(), - }); + + onAddPointToStream(createStreamEventPoint(point)); }; const onTouchProgress = (touchInfo: TouchInfo) => { @@ -305,14 +349,9 @@ const AbCanvas: FC = props => { resetCloseToNextRerendered(); } - onLog({ - x: (touchInfo.x * width) / 100, - y: (touchInfo.y * width) / 100, - time: Date.now(), - }); - if (isOverNext(point) && isOverLast(point)) { markLastLogPoints({ valid: true }); + addOverCorrectPointToStream(point); keepPathInState(); resetCurrentPath(); onLogResult({ @@ -321,14 +360,17 @@ const AbCanvas: FC = props => { }); onMessage(MessageType.Completed); onComplete(); + return; } if (isOverNext(point)) { markLastLogPoints({ valid: true }); + addOverCorrectPointToStream(point); keepPathInState(); reCreatePath(point); incrementCurrentIndex(); + return; } @@ -339,7 +381,12 @@ const AbCanvas: FC = props => { resetCurrentPath(); setFlareGreenPointIndex({ index: getCurrentIndex() }); onMessage(MessageType.IncorrectLine); + + addOverWrongPointToStream(point, node.label); + return; } + + addPointToStream(point); }; const onTouchEnd = (touchInfo: TouchInfo) => { @@ -357,6 +404,8 @@ const AbCanvas: FC = props => { setFlareGreenPointIndex({ index: getCurrentIndex() }); } + addOverUndefinedPointToStream(point); + markLastLogPoints({ valid: false, actual: node?.label ?? 'none' }); }; diff --git a/src/entities/abTrail/ui/AbTest.tsx b/src/entities/abTrail/ui/AbTest.tsx index 67e30d4f8..16e1a43ec 100644 --- a/src/entities/abTrail/ui/AbTest.tsx +++ b/src/entities/abTrail/ui/AbTest.tsx @@ -3,21 +3,16 @@ import { FC, useEffect, useMemo, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { AbTestPayload } from '@app/abstract/lib'; -import { colors, StreamEventLoggable } from '@shared/lib'; +import { AbTestStreamEvent, colors, StreamEventLoggable } from '@shared/lib'; import { Box, BoxProps, Text, XStack } from '@shared/ui'; import AbCanvas from './AbCanvas'; -import { - AbTestResult, - MessageType, - MessageTypeStrings, - StreamEventPoint, -} from '../lib'; +import { AbTestResult, MessageType, MessageTypeStrings } from '../lib'; type Props = { testData: AbTestPayload; onResponse?: (response: AbTestResult) => void; -} & StreamEventLoggable & +} & StreamEventLoggable & BoxProps; const ShapesRectPadding = 15; diff --git a/src/entities/drawer/ui/DrawingBoard.tsx b/src/entities/drawer/ui/DrawingBoard.tsx index 46ed60ee7..19b617b0e 100644 --- a/src/entities/drawer/ui/DrawingBoard.tsx +++ b/src/entities/drawer/ui/DrawingBoard.tsx @@ -1,6 +1,6 @@ import React, { useRef, FC, useMemo } from 'react'; -import { StreamEventLoggable } from '@shared/lib'; +import { DrawingStreamEvent, StreamEventLoggable } from '@shared/lib'; import { Box, SketchCanvas, SketchCanvasRef, useOnUndo } from '@shared/ui'; import { DrawLine, ResponseSerializer, DrawResult } from '../lib'; @@ -10,7 +10,7 @@ type Props = { value: Array; onResult: (result: DrawResult) => void; width: number; -} & StreamEventLoggable; +} & StreamEventLoggable; const DrawingBoard: FC = props => { const { value, onResult, width, onLog } = props; @@ -50,8 +50,9 @@ const DrawingBoard: FC = props => { startTime: Date.now(), points: [drawPoint], }; + const logPoint = drawPoint.scale(vector) as DrawPoint; - onLog(drawPoint.scale(vector)); + onLog({ ...logPoint, lineNumber: value?.length, type: 'DrawingTest' }); }; const onTouchProgress = (x: number, y: number) => { @@ -59,7 +60,9 @@ const DrawingBoard: FC = props => { drawingValueLineRef.current.points.push(drawPoint); - onLog(drawPoint.scale(vector)); + const logPoint = drawPoint.scale(vector); + + onLog({ ...logPoint, lineNumber: value?.length, type: 'DrawingTest' }); }; const onTouchEnd = () => { diff --git a/src/entities/drawer/ui/DrawingTest.tsx b/src/entities/drawer/ui/DrawingTest.tsx index 6bfc2fe7a..112cac1a5 100644 --- a/src/entities/drawer/ui/DrawingTest.tsx +++ b/src/entities/drawer/ui/DrawingTest.tsx @@ -4,10 +4,10 @@ import { FC, useState } from 'react'; import { CachedImage } from '@georstat/react-native-image-cache'; import { Box, BoxProps, XStack } from '@app/shared/ui'; -import { StreamEventLoggable } from '@shared/lib'; +import { DrawingStreamEvent, StreamEventLoggable } from '@shared/lib'; import DrawingBoard from './DrawingBoard'; -import { DrawLine, DrawPoint, DrawResult, SvgFileManager } from '../lib'; +import { DrawLine, DrawResult, SvgFileManager } from '../lib'; const RectPadding = 15; @@ -17,7 +17,7 @@ type Props = { backgroundImageUrl: string | null; onResult: (result: DrawResult) => void; toggleScroll: (isScrollEnabled: boolean) => void; -} & StreamEventLoggable & +} & StreamEventLoggable & BoxProps; const DrawingTest: FC = props => { diff --git a/src/entities/flanker/ui/HtmlFlanker/HtmlFlanker.tsx b/src/entities/flanker/ui/HtmlFlanker/HtmlFlanker.tsx index 1b647bdd2..302bbd06f 100644 --- a/src/entities/flanker/ui/HtmlFlanker/HtmlFlanker.tsx +++ b/src/entities/flanker/ui/HtmlFlanker/HtmlFlanker.tsx @@ -46,34 +46,6 @@ const HtmlFlanker: FC = props => { configuration.buttons, )}); \n ${parsedConfiguration}`; - const generateLiveEvent = ( - data: FlankerWebViewLogRecord, - ): FlankerLiveEvent => { - let screenCountPerTrial = 1; - - if (configuration.showFeedback) { - screenCountPerTrial++; - } - if (configuration.showFixation) { - screenCountPerTrial++; - } - - const liveEvent = { - trial_index: Math.ceil((data.trial_index + 1) / screenCountPerTrial), - duration: data.rt, - question: data.stimulus, - button_pressed: data.button_pressed, - start_time: data.image_time, - correct: data.correct, - start_timestamp: data.start_timestamp, - offset: data.start_timestamp - data.start_time, - tag: data.tag, - response_touch_timestamp: data.rt ? data.start_timestamp + data.rt : null, - }; - - return liveEvent; - }; - return ( = props => { } if (type === 'response') { - const liveEvent = generateLiveEvent( - data as FlankerWebViewLogRecord, - ); + const responseData = parsed.data as FlankerWebViewLogRecord; + + const liveEvent: FlankerLiveEvent = { + trialIndex: responseData.trial_index, + duration: responseData.rt, + question: responseData.stimulus, + buttonPressed: responseData.button_pressed, + imageTime: responseData.image_time, + startTime: responseData.start_time, + correct: responseData.correct, + startTimestamp: responseData.start_timestamp, + tag: responseData.tag, + showFeedback: configuration.showFeedback, + showFixation: configuration.showFixation, + type: 'Flanker', + }; props.onLog(liveEvent); diff --git a/src/entities/flanker/ui/NativeIosFlanker/NativeIosFlanker.tsx b/src/entities/flanker/ui/NativeIosFlanker/NativeIosFlanker.tsx index 2265e0ee4..74817dcc1 100644 --- a/src/entities/flanker/ui/NativeIosFlanker/NativeIosFlanker.tsx +++ b/src/entities/flanker/ui/NativeIosFlanker/NativeIosFlanker.tsx @@ -60,16 +60,17 @@ const NativeIosFlanker: FC = props => { } const liveEvent: FlankerLiveEvent = { - trial_index: parsed.trial_index, + trialIndex: parsed.trial_index, duration: parsed.rt, question: parsed.stimulus, correct: parsed.correct, - response_touch_timestamp: parsed.response_touch_timestamp, + responseTouchTimeStamp: parsed.response_touch_timestamp, tag: parsed.tag, - start_time: parsed.start_time, - start_timestamp: parsed.image_time, + startTime: parsed.start_time, + startTimestamp: parsed.image_time, offset: 0, - button_pressed: parsed.button_pressed, + buttonPressed: parsed.button_pressed, + type: 'Flanker', }; if (type === 'response') { diff --git a/src/entities/stabilityTracker/ui/StabilityTrackerItem.tsx b/src/entities/stabilityTracker/ui/StabilityTrackerItem.tsx index 4ad95f862..6a065cf94 100644 --- a/src/entities/stabilityTracker/ui/StabilityTrackerItem.tsx +++ b/src/entities/stabilityTracker/ui/StabilityTrackerItem.tsx @@ -11,8 +11,11 @@ import { orientation } from 'react-native-sensors'; import Svg, { Circle } from 'react-native-svg'; import { useToast } from 'react-native-toast-notifications'; -import { StabilityTrackerAnswerValue } from '@shared/api'; -import { useForceUpdate, StreamEventLoggable } from '@shared/lib'; +import { + useForceUpdate, + StreamEventLoggable, + StabilityTrackerEvent, +} from '@shared/lib'; import { YStack } from '@shared/ui'; import ControlBar from './ControlBar'; @@ -65,7 +68,7 @@ type Props = { onComplete: (response: StabilityTrackerResponse) => void; onMaxLambdaChange: (contextKey: string, contextValue: unknown) => void; maxLambda?: number; -} & StreamEventLoggable; +} & StreamEventLoggable; const StabilityTrackerItemScreen = (props: Props) => { const toast = useToast(); @@ -334,7 +337,7 @@ const StabilityTrackerItemScreen = (props: Props) => { }; const saveResponses = () => { - const response = { + const response: StabilityTrackerEvent = { timestamp: new Date().getTime(), circlePosition: [circlePosition.current[1] / PANEL_RADIUS - 1], userPosition: [userPosition.current[1] / PANEL_RADIUS - 1], @@ -342,19 +345,10 @@ const StabilityTrackerItemScreen = (props: Props) => { lambda: lambdaValue.current, score: score.current, lambdaSlope: lambdaSlope.current, + type: 'StabilityTracker', }; - const liveEvent: StabilityTrackerAnswerValue = { - timestamp: response.timestamp, - stimPos: response.circlePosition, - targetPos: response.targetPosition, - userPos: response.userPosition, - score: response.score, - lambda: response.lambda, - lambdaSlope: response.lambdaSlope, - }; - - onLog(liveEvent); + onLog(response); responses.current.push(response); }; diff --git a/src/features/pass-survey/model/index.ts b/src/features/pass-survey/model/index.ts index 3ee2be554..8087026cb 100644 --- a/src/features/pass-survey/model/index.ts +++ b/src/features/pass-survey/model/index.ts @@ -4,3 +4,4 @@ export * from './hooks'; export * from './ActivityRecordInitializer'; export { default as AlertsExtractor } from './AlertsExtractor'; export { default as ScoresExtractor } from './ScoresExtractor'; +export * from './streamEventMapper'; diff --git a/src/features/pass-survey/model/streamEventMapper.ts b/src/features/pass-survey/model/streamEventMapper.ts new file mode 100644 index 000000000..8f8db1cde --- /dev/null +++ b/src/features/pass-survey/model/streamEventMapper.ts @@ -0,0 +1,126 @@ +import { FlankerLiveEvent, IS_ANDROID, LiveEventDto } from '@shared/lib'; +import { + AbTestStreamEventDto, + AbTestStreamEventErrorType, + AbTestStreamEvent, + DrawingStreamEvent, + DrawingStreamEventDto, + StabilityTrackerEvent, + StabilityTrackerEventDto, + LiveEvent, +} from '@shared/lib/tcp/types'; +const mapABTestStreamEventToDto = ( + streamEvent: AbTestStreamEvent, +): AbTestStreamEventDto => { + let actualPath = '-1'; + if (streamEvent.wrongPointLabel) { + actualPath = streamEvent.wrongPointLabel; + } + if (streamEvent.error === AbTestStreamEventErrorType.OverCorrectPoint) { + actualPath = `${streamEvent.currentNodeLabel} ~ ${streamEvent.nextNodeLabel}`; + } + + const dto = { + x: streamEvent.x, + y: streamEvent.y, + time: streamEvent.time, + line_number: streamEvent.lineNumber, + error: streamEvent.error, + correct_path: `${streamEvent.currentNodeLabel} ~ ${streamEvent.nextNodeLabel}`, + actual_path: actualPath, + }; + + return dto; +}; +const mapDrawingStreamEventToDto = ( + streamEvent: DrawingStreamEvent, +): DrawingStreamEventDto => { + const dto = { + x: streamEvent.x, + y: streamEvent.y, + line_number: streamEvent.lineNumber, + time: streamEvent.time, + }; + + return dto; +}; + +const mapStabilityTrackerStreamEventToDto = ( + streamEvent: StabilityTrackerEvent, +): StabilityTrackerEventDto => { + const dto = { + timestamp: streamEvent.timestamp, + stimPos: streamEvent.circlePosition, + targetPos: streamEvent.targetPosition, + userPos: streamEvent.userPosition, + score: streamEvent.score, + lambda: streamEvent.lambda, + lambdaSlope: streamEvent.lambdaSlope, + }; + + return dto; +}; + +const mapFlankerStreamEventToDto = (streamEvent: FlankerLiveEvent) => { + if (IS_ANDROID) { + let screenCountPerTrial = 1; + + if (streamEvent.showFeedback) { + screenCountPerTrial++; + } + if (streamEvent.showFixation) { + screenCountPerTrial++; + } + + const dto = { + trial_index: Math.ceil( + (streamEvent.trialIndex + 1) / screenCountPerTrial, + ), + duration: streamEvent.duration, + question: streamEvent.question, + button_pressed: streamEvent.buttonPressed, + start_time: streamEvent.imageTime, + correct: streamEvent.correct, + start_timestamp: streamEvent.startTimestamp, + offset: streamEvent.startTimestamp - streamEvent.startTime, + tag: streamEvent.tag, + response_touch_timestamp: streamEvent.duration + ? streamEvent.startTimestamp + streamEvent.duration + : null, + }; + + return dto; + } + + const dto = { + trial_index: streamEvent.trialIndex, + duration: streamEvent.duration, + question: streamEvent.question, + correct: streamEvent.correct, + response_touch_timestamp: streamEvent.responseTouchTimeStamp, + tag: streamEvent.tag, + start_time: streamEvent.startTime, + start_timestamp: streamEvent.startTimestamp, + offset: 0, + button_pressed: streamEvent.buttonPressed, + }; + + return dto; +}; + +export const mapStreamEventToDto = (streamEvent: LiveEvent): LiveEventDto => { + const type = streamEvent.type; + + switch (type) { + case 'AbTest': + return mapABTestStreamEventToDto(streamEvent); + case 'DrawingTest': + return mapDrawingStreamEventToDto(streamEvent); + case 'Flanker': + return mapFlankerStreamEventToDto(streamEvent); + case 'StabilityTracker': + return mapStabilityTrackerStreamEventToDto(streamEvent); + default: + return streamEvent; + } +}; diff --git a/src/features/pass-survey/model/tests/ScoresCalculator.collectMaxScores.test.ts b/src/features/pass-survey/model/tests/ScoresCalculator.collectMaxScores.test.ts index 23ae745a7..6e30f5686 100644 --- a/src/features/pass-survey/model/tests/ScoresCalculator.collectMaxScores.test.ts +++ b/src/features/pass-survey/model/tests/ScoresCalculator.collectMaxScores.test.ts @@ -59,6 +59,7 @@ const getEmptyRadioItem = (name: string): RadioPipelineItem => { setAlerts: false, setPalette: false, options: [], + autoAdvance: false, }, type: 'Radio', }; diff --git a/src/features/pass-survey/model/tests/ScoresCalculator.collectScoreForRadio.test.ts b/src/features/pass-survey/model/tests/ScoresCalculator.collectScoreForRadio.test.ts index 7c95bccf5..0a7695066 100644 --- a/src/features/pass-survey/model/tests/ScoresCalculator.collectScoreForRadio.test.ts +++ b/src/features/pass-survey/model/tests/ScoresCalculator.collectScoreForRadio.test.ts @@ -34,6 +34,7 @@ const getEmptyItem = (): RadioPipelineItem => { setAlerts: false, setPalette: false, options: [], + autoAdvance: false, }, type: 'Radio', }; diff --git a/src/features/pass-survey/ui/ActivityItem.tsx b/src/features/pass-survey/ui/ActivityItem.tsx index fcf1df41d..a292ab8b6 100644 --- a/src/features/pass-survey/ui/ActivityItem.tsx +++ b/src/features/pass-survey/ui/ActivityItem.tsx @@ -22,7 +22,7 @@ import { useAppletStreamingStatus } from '@entities/applet/lib/hooks'; import { DrawingTest } from '@entities/drawer'; import { HtmlFlanker, NativeIosFlanker } from '@entities/flanker'; import { StabilityTracker } from '@entities/stabilityTracker'; -import { IS_ANDROID, useSendEvent, wait } from '@shared/lib'; +import { IS_ANDROID, LiveEvent, useSendEvent, wait } from '@shared/lib'; import { RadioActivityItem, SurveySlider, @@ -40,6 +40,7 @@ import { PipelineItemResponse, ActivityIdentityContext, } from '../lib'; +import { mapStreamEventToDto } from '../model'; type Props = ActivityItemProps & PipelineItemAnswer & { @@ -69,6 +70,12 @@ function ActivityItem({ const { sendLiveEvent } = useSendEvent(streamEnabled); + const processLiveEvent = (streamEvent: LiveEvent) => { + const liveEventDto = mapStreamEventToDto(streamEvent); + + sendLiveEvent(liveEventDto); + }; + const { next } = useContext(HandlersContext); let item: JSX.Element | null; @@ -112,7 +119,7 @@ function ActivityItem({ ); @@ -129,7 +136,7 @@ function ActivityItem({ }} onMaxLambdaChange={onContextChange} maxLambda={context?.maxLambda as number} - onLog={sendLiveEvent} + onLog={processLiveEvent} /> ); @@ -147,7 +154,7 @@ function ActivityItem({ lines: value?.answer?.lines ?? [], }} onResult={onResponse} - onLog={sendLiveEvent} + onLog={processLiveEvent} /> ); @@ -161,7 +168,7 @@ function ActivityItem({ onResponse(data); moveToNextItem(); }} - onLog={sendLiveEvent} + onLog={processLiveEvent} /> ) : ( ); break; diff --git a/src/shared/lib/tcp/types.ts b/src/shared/lib/tcp/types.ts index 82900de1c..0ca46a028 100644 --- a/src/shared/lib/tcp/types.ts +++ b/src/shared/lib/tcp/types.ts @@ -1,11 +1,30 @@ +import { DrawPoint } from '@entities/drawer'; + export type FlankerLiveEvent = { + trialIndex: number; + duration: number; + question: string; + buttonPressed: string; + imageTime?: number; + correct: boolean; + tag: string; + startTime: number; + startTimestamp: number; + offset?: number; + responseTouchTimeStamp?: number; + showFixation?: boolean; + showFeedback?: boolean; + type: 'Flanker'; +}; + +export type FlankerLiveEventDto = { trial_index: number; duration: number; question: string; correct: boolean; - response_touch_timestamp: number | null; + response_touch_timestamp?: number | null; tag: string; - start_time: number; + start_time?: number; start_timestamp: number; offset: number; button_pressed: string; @@ -14,3 +33,72 @@ export type FlankerLiveEvent = { export type StreamEventLoggable = { onLog: (event: T) => void; }; + +export type LiveEvent = + | AbTestStreamEvent + | DrawingStreamEvent + | StabilityTrackerEvent + | FlankerLiveEvent; + +export type StabilityTrackerEventDto = { + timestamp: number; + stimPos: number[]; + userPos: number[]; + targetPos: number[]; + lambda: number; + score: number; + lambdaSlope: number; +}; + +export type StabilityTrackerEvent = { + timestamp: number; + circlePosition: number[]; + userPosition: number[]; + targetPosition: number[]; + lambda: number; + score: number; + lambdaSlope: number; + type: 'StabilityTracker'; +}; + +export type DrawingStreamEvent = DrawPoint & { + lineNumber: number; + type: 'DrawingTest'; +}; + +export type DrawingStreamEventDto = DrawPoint & { line_number: number }; + +export const enum AbTestStreamEventErrorType { + NotDefined = '?', + OverCorrectPoint = 'E0', + OverWrongPoint = 'E1', + OverUndefinedPoint = 'E2', +} + +export type AbTestStreamEvent = { + x: number; + y: number; + time: number; + lineNumber: number; + error: AbTestStreamEventErrorType; + currentNodeLabel: string; + nextNodeLabel: string; + wrongPointLabel?: string; + type: 'AbTest'; +}; + +export type AbTestStreamEventDto = { + x: number; + y: number; + time: number; + line_number: number; + error: AbTestStreamEventErrorType; + correct_path: string; + actual_path: string; +}; + +export type LiveEventDto = + | AbTestStreamEventDto + | DrawingStreamEventDto + | FlankerLiveEventDto + | StabilityTrackerEventDto; diff --git a/src/shared/lib/tcp/useSendLiveEvent.ts b/src/shared/lib/tcp/useSendLiveEvent.ts index 45f140545..913c68387 100644 --- a/src/shared/lib/tcp/useSendLiveEvent.ts +++ b/src/shared/lib/tcp/useSendLiveEvent.ts @@ -1,27 +1,22 @@ import { useCallback } from 'react'; -import { DrawPoint } from '@entities/drawer'; -import { StabilityTrackerAnswerValue } from '@shared/api'; - -import { FlankerLiveEvent } from './types'; +import { LiveEventDto } from './types'; import { useTCPSocket } from './useTCPSocket'; -type LiveEvent = DrawPoint | StabilityTrackerAnswerValue | FlankerLiveEvent; - export function useSendEvent(streamEnabled: boolean) { const { sendMessage, connected } = useTCPSocket({ onClosed: () => {}, }); const sendLiveEvent = useCallback( - (data: LiveEvent) => { + (dataDto: LiveEventDto) => { if (!connected || !streamEnabled) { return; } const liveEvent = { type: 'live_event', - data, + data: dataDto, }; sendMessage(JSON.stringify(liveEvent));