diff --git a/package-lock.json b/package-lock.json index 2dc9cea6..d772b1d1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,7 +17,7 @@ "@electron/notarize": "^2.3.1", "@emotion/react": "^11.14.0", "@emotion/styled": "^11.14.1", - "@fingerprintjs/fingerprintjs": "^5.0.1", + "@fingerprintjs/fingerprintjs": "^5.1.0", "@fontsource/roboto": "^5.2.6", "@fortawesome/fontawesome-svg-core": "^7.0.1", "@fortawesome/free-regular-svg-icons": "^7.0.1", @@ -1723,9 +1723,9 @@ } }, "node_modules/@fingerprintjs/fingerprintjs": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@fingerprintjs/fingerprintjs/-/fingerprintjs-5.0.1.tgz", - "integrity": "sha512-KbaeE/rk2WL8MfpRP6jTI4lSr42SJPjvkyrjP3QU6uUDkOMWWYC2Ts1sNSYcegHC8avzOoYTHBj+2fTqvZWQBA==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@fingerprintjs/fingerprintjs/-/fingerprintjs-5.1.0.tgz", + "integrity": "sha512-8h/CscV3xQ4KSLyXbSK8YFpZ5AaezzHfkl82mn8NJIEWNi1zLfbZSIu7MGGtx4pqa10oejhEk4u0MNutuE63Fw==", "license": "MIT" }, "node_modules/@floating-ui/core": { @@ -15882,24 +15882,6 @@ "dev": true, "license": "ISC" }, - "node_modules/yaml": { - "version": "2.8.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.2.tgz", - "integrity": "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==", - "dev": true, - "license": "ISC", - "optional": true, - "peer": true, - "bin": { - "yaml": "bin.mjs" - }, - "engines": { - "node": ">= 14.6" - }, - "funding": { - "url": "https://github.com/sponsors/eemeli" - } - }, "node_modules/yargs": { "version": "17.7.2", "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", diff --git a/package.json b/package.json index 5b7cf9a8..3ab54f38 100644 --- a/package.json +++ b/package.json @@ -33,7 +33,7 @@ "@electron/notarize": "^2.3.1", "@emotion/react": "^11.14.0", "@emotion/styled": "^11.14.1", - "@fingerprintjs/fingerprintjs": "^5.0.1", + "@fingerprintjs/fingerprintjs": "^5.1.0", "@fontsource/roboto": "^5.2.6", "@fortawesome/fontawesome-svg-core": "^7.0.1", "@fortawesome/free-regular-svg-icons": "^7.0.1", diff --git a/src/renderer/src/components/PassageDetail/Internalization/SelectMyResource.tsx b/src/renderer/src/components/PassageDetail/Internalization/SelectMyResource.tsx index 58ed71b7..af1a018f 100644 --- a/src/renderer/src/components/PassageDetail/Internalization/SelectMyResource.tsx +++ b/src/renderer/src/components/PassageDetail/Internalization/SelectMyResource.tsx @@ -5,6 +5,7 @@ import { ITeamCheckReferenceStrings } from '../../../model'; import { PassageDetailContext } from '../../../context/PassageDetailContext'; import { related, useArtifactCategory } from '../../../crud'; import { teamCheckRefSelector } from '../../../selector'; +import { useMobile } from '../../../utils'; interface IProps { inResource?: string; @@ -21,6 +22,7 @@ export const SelectMyResource = (props: IProps) => { const { scriptureTypeCategory } = useArtifactCategory(); const [myWidth, setMyWidth] = useState(0); const controlRef = useRef(undefined); + const isMobile = useMobile(); const t: ITeamCheckReferenceStrings = useSelector( teamCheckRefSelector, shallowEqual @@ -51,16 +53,23 @@ export const SelectMyResource = (props: IProps) => { ) : ( - + {recordContent} diff --git a/src/renderer/src/components/PassageDetail/mobile/PassageDetailPlayerMobile.tsx b/src/renderer/src/components/PassageDetail/mobile/PassageDetailPlayerMobile.tsx new file mode 100644 index 00000000..568c7dd1 --- /dev/null +++ b/src/renderer/src/components/PassageDetail/mobile/PassageDetailPlayerMobile.tsx @@ -0,0 +1,585 @@ +import { useGlobal } from '../../../context/useGlobal'; +import { Badge, Box, Button, IconButton, Typography } from '@mui/material'; +import { useContext, useEffect, useMemo, useRef, useState } from 'react'; +import { UnsavedContext } from '../../../context/UnsavedContext'; +import { + IRegion, + IRegionParams, + IRegions, + parseRegions, +} from '../../../crud/useWavesurferRegions'; +import WSAudioPlayer from '../../WSAudioPlayer'; +import { useSelector, shallowEqual } from 'react-redux'; +import { + ISharedStrings, + IWsAudioPlayerStrings, + MediaFile, + MediaFileD, + OrganizationD, + OrgWorkflowStepD, +} from '../../../model'; +import { UpdateRecord } from '../../../model/baseModel'; +import { playerSelector, sharedSelector } from '../../../selector'; +import { + getSegments, + NamedRegions, + updateSegments, +} from '../../../utils/namedSegments'; +import ViewIcon from '@mui/icons-material/RemoveRedEye'; +import TranscriptionShow from '../../TranscriptionShow'; +import { related } from '../../../crud/related'; +import { + RequestPlay, + usePlayerLogic, +} from '../../../business/player/usePlayerLogic'; +import TranscriptionLogo from '../../../control/TranscriptionLogo'; +import { + useOrgDefaults, + orgDefaultFeatures, +} from '../../../crud/useOrgDefaults'; +import BigDialog from '../../../hoc/BigDialog'; +import { BigDialogBp } from '../../../hoc/BigDialogBp'; +import SelectAsrLanguage from '../../../business/asr/SelectAsrLanguage'; +import AsrButton from '../../../control/ConfButton'; +import { IFeatures } from '../../Team/TeamSettings'; +import AsrProgress from '../../../business/asr/AsrProgress'; +import { useGetAsrSettings } from '../../../crud/useGetAsrSettings'; +import { LightTooltip, smallButtonProps } from '../../StepEditor'; +import { useOrbitData } from '../../../hoc/useOrbitData'; +import { pullTableList, ToolSlug, useStepTool } from '../../../crud'; +import IndexedDBSource from '@orbit/indexeddb'; +import JSONAPISource from '@orbit/jsonapi'; +import { useCheckOnline } from '../../../utils/useCheckOnline'; +import { useSnackBar } from '../../../hoc/SnackBar'; +import { useLocLangName } from '../../../utils/useLocLangName'; +import { SaveSegments } from '../SaveSegments'; +import { AsrTarget } from '../../../business/asr/AsrTarget'; +import { IMarker } from '../../../crud/useWaveSurfer'; + +export const PLAYER_HEIGHT = 120 + 80; + +export interface IPlayerState { + loading: boolean; + pdBusy: boolean; + setPDBusy: (busy: boolean) => void; + audioBlob?: Blob; + setupLocate: (callback?: (segments: string) => void) => void; + playing: boolean; + setPlaying: (playing: boolean) => void; + currentstep?: string; + currentSegmentIndex?: number; + setCurrentSegment?: (region: IRegion | undefined, index: number) => void; + discussionMarkers?: IMarker[]; + handleHighlightDiscussion?: (time: number) => void; + playerMediafile?: MediaFile; + forceRefresh?: () => void; +} + +export interface DetailPlayerProps { + allowSegment?: NamedRegions | undefined; + saveSegments?: SaveSegments | undefined; + allowAutoSegment?: boolean; + suggestedSegments?: string; + forceRegionOnly?: boolean; + verses?: string; + defaultSegParams?: IRegionParams; + canSetDefaultParams?: boolean; + onSegment?: (segment: string, init: boolean) => void; + onSegmentParamChange?: + | ((params: IRegionParams, teamDefault: boolean) => void) + | undefined; + onStartRegion?: (position: number) => void; + onProgress?: (progress: number) => void; + onSaveProgress?: (progress: number) => void; + onInteraction?: () => void; + onTranscription?: (transcription: string) => void; + allowZoomAndSpeed?: boolean; + position?: number; + width: number; + parentToolId?: string; + role?: string; + hasTranscription?: boolean; + contentVerses?: string[]; + metaData?: React.ReactNode; + playerState: IPlayerState; +} + +export function PassageDetailPlayerMobile(props: DetailPlayerProps) { + const { + allowSegment, + allowAutoSegment, + saveSegments, + suggestedSegments, + forceRegionOnly, + verses, + defaultSegParams, + canSetDefaultParams, + onSegment, + onSegmentParamChange, + onStartRegion, + onProgress, + onSaveProgress, + onInteraction, + onTranscription, + allowZoomAndSpeed, + position, + width, + parentToolId, + role, + hasTranscription, + contentVerses, + metaData, + playerState, + } = props; + + const [memory] = useGlobal('memory'); + const [offline] = useGlobal('offline'); //verified this is not used in a function 2/18/25 + const [user] = useGlobal('user'); + const { + toolChanged, + toolsChanged, + isChanged, + saveRequested, + clearRequested, + clearCompleted, + startSave, + saveCompleted, + } = useContext(UnsavedContext).state; + const t: IWsAudioPlayerStrings = useSelector(playerSelector, shallowEqual); + const ts: ISharedStrings = useSelector(sharedSelector, shallowEqual); + const toolId = 'ArtifactSegments'; + const [requestPlay, setRequestPlay] = useState({ + play: undefined, + regionOnly: false, + request: new Date(), + }); + const [initialposition, setInitialPosition] = useState(0); + //if (mediaFileId) newContext.setSelected(mediaFileId, PlayInPlayer.yes); + + // useEffect(() => { + // if (mediaFileId && mediaFileId !== newContext.playerMediafile?.id) { + // newContext.setSelected(mediaFileId, PlayInPlayer.yes); + // } + // }, [mediaFileId, newContext]); + + const { + loading, + pdBusy, + setPDBusy, + audioBlob, + setupLocate, + playing, + setPlaying, + currentstep, + currentSegmentIndex, + setCurrentSegment, + discussionMarkers, + handleHighlightDiscussion, + playerMediafile, + forceRefresh, + } = playerState; + + const [defaultSegments, setDefaultSegments] = useState('{}'); + const [showTranscriptionId, setShowTranscriptionId] = useState(''); + const [coordinator] = useGlobal('coordinator'); + const remote = coordinator?.getSource('remote') as JSONAPISource; + const backup = coordinator?.getSource('backup') as IndexedDBSource; + const [reporter] = useGlobal('errorReporter'); + const segmentsRef = useRef(''); + const playingRef = useRef(playing); + const savingRef = useRef(false); + const mediafileRef = useRef(undefined); + const durationRef = useRef(0); + const { getOrgDefault } = useOrgDefaults(); + const [org] = useGlobal('organization'); + const { getAsrSettings } = useGetAsrSettings(); + const teams = useOrbitData('organization'); + const orgSteps = useOrbitData('orgworkflowstep'); + const mediarecs = useOrbitData('mediafile'); + const [asrLangVisible, setAsrLangVisible] = useState(false); + const [phonetic, setPhonetic] = useState(false); + const [forceAi, setForceAi] = useState(); + + const [features, setFeatures] = useState(); + const [asrProgressVisble, setAsrProgressVisble] = useState(false); + const checkOnline = useCheckOnline(t.recognizeSpeech); + const { showMessage } = useSnackBar(); + const [getName] = useLocLangName(); + const { tool } = useStepTool(currentstep ?? ''); + + const { onPlayStatus, onCurrentSegment, setSegmentToWhole } = usePlayerLogic({ + allowSegment, + suggestedSegments, + position, + playing, + setPlaying, + setCurrentSegment, + playerMediafile, + setDefaultSegments, + setRequestPlay, + setInitialPosition, + mediafileRef, + segmentsRef, + durationRef, + playingRef, + onSegment, + }); + + const writeSegments = async () => { + if (!savingRef.current) { + savingRef.current = true; + if (mediafileRef.current) { + const mediafile = mediafileRef.current; + await memory + .update((t) => [ + ...UpdateRecord( + t, + { + type: 'mediafile', + id: mediafile.id, + attributes: { + ...mediafile?.attributes, + segments: updateSegments( + allowSegment ?? NamedRegions.BackTranslation, + mediafile.attributes?.segments || '{}', + segmentsRef.current + ), + }, + } as unknown as MediaFileD, + user + ), + ]) + .then(() => { + saveCompleted(toolId); + savingRef.current = false; + }) + .catch((err) => { + //so we don't come here...we go to continue/logout + saveCompleted(toolId, err.message); + savingRef.current = false; + }); + } + } + }; + + const onPullTasks = (remoteId: string) => { + pullTableList( + 'mediafile', + Array(remoteId), + memory, + remote, + backup, + reporter + ) + .then(() => { + if (forceRefresh) forceRefresh(); + }) + .finally(() => { + setSegmentToWhole(); + }); + }; + + const hasAiTasks = useMemo(() => { + const mediaRec = mediarecs.find((m) => m.id === playerMediafile?.id); + return ( + getSegments( + NamedRegions.TRTask, + mediaRec?.attributes?.segments || '{}' + ) !== '{}' + ); + }, [playerMediafile, mediarecs]); + + const onDuration = (duration: number) => { + durationRef.current = duration; + if ( + mediafileRef.current && + !mediafileRef.current.attributes.sourceSegments && + duration && + Math.floor(duration) !== + Math.floor(mediafileRef.current.attributes.duration) + ) { + console.log( + `update duration to ${Math.floor(duration)} from + ${Math.floor(mediafileRef.current.attributes.duration)}` + ); + memory + .update((t) => + t.replaceAttribute( + mediafileRef.current as MediaFileD, //I already checked for undefined + 'duration', + Math.floor(duration) + ) + ) + .then(() => { + if (forceRefresh) forceRefresh(); + }); + } + setSegmentToWhole(); + }; + + const setPlayerSegments = (segments: string) => { + if ( + !allowSegment || + !segmentsRef.current || + segmentsRef.current.indexOf('},{') === -1 + ) { + setDefaultSegments(segments); + onSegment && onSegment(segments, true); + } + //TT 6149 but I wonder why this was here? if (!playingRef.current) { + const segs = parseRegions(segments) as IRegions | undefined; + if ((segs?.regions?.length ?? 0) > 0) { + setInitialPosition(segs?.regions[0]?.start ?? 0); + setRequestPlay({ + play: true, + regionOnly: true, + request: new Date(), + }); + } + //} + }; + + const onSegmentChange = (segments: string) => { + segmentsRef.current = segments; + setDefaultSegments(segments); //now we'll notice if we reset them in SetPlayerSegments + onSegment && onSegment(segments, false); + if (allowSegment && saveSegments !== undefined) { + //if I have a parentToolId it will save the segments + toolChanged(parentToolId ?? toolId); + } else { + //not saving segments...so don't update changed + } + }; + + useEffect(() => { + setupLocate(setPlayerSegments); + return () => { + setupLocate(); + }; + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [currentstep, allowSegment]); + + useEffect(() => { + if (saveRequested(toolId) && !savingRef.current) writeSegments(); + else if (clearRequested(toolId)) { + clearCompleted(toolId); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [toolsChanged]); + + const handleSave = () => { + if (!saveRequested(toolId)) { + startSave(toolId); + } + //save the segments here + }; + + const handleShowTranscription = () => { + setShowTranscriptionId(related(playerMediafile, 'passage') ?? ''); + }; + + const handleCloseTranscription = () => { + setShowTranscriptionId(''); + }; + + const asrTip = useMemo(() => { + const asr = getAsrSettings(); + return (t.recognizeSpeech + '\u00A0\u00A0').replace( + '{0}', + asr?.language?.languageName?.trim() + ? `\u2039 ${ + getName(asr?.language.bcp47) || asr?.language?.languageName + } \u203A` + : '' + ); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [teams, orgSteps]); + + const handleAsrSettings = () => { + checkOnline((online) => { + if (!online) { + showMessage(ts.mustBeOnline); + return; + } + setAsrLangVisible(true); + }); + }; + + const handleTranscribe = (forceAi?: boolean) => { + checkOnline((online) => { + if (!online) { + showMessage(ts.mustBeOnline); + return; + } + const asr = getAsrSettings(); + if (asr?.mmsIso === undefined || asr?.mmsIso === 'und') { + setAsrLangVisible(true); + return; + } + setPhonetic(asr?.target === AsrTarget.phonetic); + setForceAi(forceAi); + setTimeout(() => { + setAsrLangVisible(false); + setAsrProgressVisble(true); + }, 200); + }); + }; + + useEffect(() => { + if (org) { + setFeatures(getOrgDefault(orgDefaultFeatures) as IFeatures); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [org]); + + const handleAsrProgressVisible = (v: boolean) => { + setAsrProgressVisble(v); + }; + + return ( + + + {playerMediafile?.attributes?.transcription && + tool !== ToolSlug.Transcribe ? ( + + + + ) : ( + <> + )} + {features?.aiTranscribe && !offline && onTranscription && role && ( + {asrTip ?? ''}} + > + + + {!hasTranscription && + hasAiTasks && + role === 'transcriber' ? ( + + + + ) : ( + + )} + + + + )} + {saveSegments === SaveSegments.showSaveButton ? ( + + ) : ( + <> + )} + {metaData} + + } + /> + {showTranscriptionId !== '' && ( + + )} + {asrLangVisible && onTranscription && ( + + {t.recognizePrompt} + + } + isOpen={asrLangVisible} + onOpen={() => setAsrLangVisible(false)} + > + + cancel ? setAsrLangVisible(false) : handleTranscribe(forceAi) + } + canBegin={true} + /> + + )} + {asrProgressVisble && onTranscription && ( + + handleAsrProgressVisible(false)} + /> + + )} + + ); +} + +export default PassageDetailPlayerMobile; diff --git a/src/renderer/src/components/PassageDetail/mobile/TeamCheckReferenceMobile.tsx b/src/renderer/src/components/PassageDetail/mobile/TeamCheckReferenceMobile.tsx new file mode 100644 index 00000000..ae542355 --- /dev/null +++ b/src/renderer/src/components/PassageDetail/mobile/TeamCheckReferenceMobile.tsx @@ -0,0 +1,214 @@ +import { + useContext, + useEffect, + useState, + useRef, + useLayoutEffect, + useMemo, +} from 'react'; +import { Grid, GridProps, styled } from '@mui/material'; +import SelectMyResource from '../Internalization/SelectMyResource'; +import { PassageDetailContext } from '../../../context/PassageDetailContext'; +import { getSegments, NamedRegions } from '../../../utils'; +import { storedCompareKey } from '../../../utils/storedCompareKey'; +import { PassageDetailChooser } from '../PassageDetailChooser'; +import { IRegion, ToolSlug, useStepTool } from '../../../crud'; +import { PassageDetailPlayerMobile } from './PassageDetailPlayerMobile'; +import PassageDetailPlayer from '../PassageDetailPlayer'; +import { BlobStatus, useFetchMediaBlob } from '../../../crud/useFetchMediaBlob'; +import { IMarker } from 'crud/useWaveSurfer'; + +const StyledGrid = styled(Grid)(({ theme }) => ({ + margin: theme.spacing(2), + paddingRight: theme.spacing(2), + width: '100%', + '& audio': { + display: 'flex', + width: 'inherit', + marginRight: theme.spacing(2), + justifyContent: 'center', + alignItems: 'center', + alignContent: 'center', + }, +})); + +const MobileGrid = styled(Grid)(() => ({ + display: 'flex', // ← Add this + width: '80%', // ← Add this + alignItems: 'center', // ← Add this + margin: '0 auto', + justifyContent: 'center', + alignContent: 'center', +})); + +export function TeamCheckReferenceMobile() { + const ctx = useContext(PassageDetailContext); + + const { + rowData, + setPlayItem, + setMediaSelected, + section, + passage, + currentstep, + } = ctx.state; + + const [loading] = useState(false); + const [pdBusy, setPDBusy] = useState(false); + const [blobState, fetchBlob] = useFetchMediaBlob(); + const [playing, setPlaying] = useState(false); + const [currentSegmentIndex, setCurrentSegmentIndex] = useState< + number | undefined + >(undefined); + const [discussionMarkers] = useState([]); + const [mediaId, setMediaId] = useState(undefined); + const playerMediafile = useMemo( + () => rowData.find((r) => r.id === mediaId)?.mediafile, + [mediaId, rowData] + ); + const forceRefresh = () => { + console.log('forceRefresh called'); + }; + const setupLocate = () => { + console.log('setupLocate called'); + }; + const setCurrentSegment = (region: IRegion | undefined, index: number) => { + console.log('setCurrentSegment called with index', index); + setCurrentSegmentIndex(index); + }; + + const [resource, setResource] = useState(''); + const { removeStoredKeys, saveKey, storeKey, SecSlug } = storedCompareKey( + passage, + section + ); + + const handleHighlightDiscussion = (time: number) => { + console.log('handleHighlightDiscussion called with time', time); + }; + + useEffect(() => { + console.log('mediafileId changed:', ctx.state.mediafileId); + console.log('ta dataaaaaaaaaaaa: ', resource); + console.log( + 'ta data: ', + rowData.find((r) => r.id === resource) + ); + }, [ctx.state.mediafileId, resource, rowData]); + + const handleResource = (id: string) => { + const row = rowData.find((r) => r.id === id); + console.log('handleResource', id, row); + if (row) { + removeStoredKeys(); + saveKey(id); + + const segs = getSegments( + NamedRegions.ProjectResource, + row.mediafile.attributes.segments + ); + const regions = JSON.parse(segs); + if (regions.length > 0) { + const { start, end } = regions[0]; + setMediaSelected(id, start, end); + setMediaId(id); + return; + } + } + setMediaId(id); + }; + + useEffect(() => { + if (mediaId) { + fetchBlob(mediaId); + } + }, [mediaId, fetchBlob]); + + useEffect(() => { + setPlayItem(''); + // We track the user's choices for each passage of the section + const res = localStorage.getItem(storeKey()); + const secId = localStorage.getItem(storeKey(SecSlug)); + if (res && secId === section.id) { + setResource(res); + handleResource(res); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [section, passage, currentstep]); + + //const [paneWidth, setPaneWidth] = useState(0); + const paneWidth = 100; + const tool = useStepTool(currentstep).tool; + + const containerRef = useRef(null); + const [playerWidth, setPlayerWidth] = useState(0); + + useLayoutEffect(() => { + if (!containerRef.current) return; + + const updateWidth = () => { + setPlayerWidth(containerRef.current!.offsetWidth); + }; + + updateWidth(); + + const observer = new ResizeObserver(updateWidth); + observer.observe(containerRef.current); + + return () => observer.disconnect(); + }, []); + //const currentstep = ctx.state.currentstep; + + return ( + + + + + {tool !== ToolSlug.KeyTerm && ( + + )} + + + + + + + + + + + {tool !== ToolSlug.KeyTerm && ( + + )} + + + + ); +} + +export default TeamCheckReferenceMobile; diff --git a/src/renderer/src/context/PassageDetailContext.tsx b/src/renderer/src/context/PassageDetailContext.tsx index 1d1542fb..d0e58846 100644 --- a/src/renderer/src/context/PassageDetailContext.tsx +++ b/src/renderer/src/context/PassageDetailContext.tsx @@ -202,6 +202,8 @@ const initState = { canPublish: false, discussOpen: false, setDiscussOpen: (_discussOpen: boolean) => {}, + compareMediaId: undefined as string | undefined, + setCompareMediaId: (_id: string | undefined) => {}, }; export type ICtxState = typeof initState; @@ -260,6 +262,9 @@ const PassageDetailProvider = (props: IProps) => { wfStr, prjId: prjId ?? '', }); + const [compareMediaId, setCompareMediaId] = useState( + undefined + ); const [blobState, fetchBlob] = useFetchMediaBlob(); const fetching = useRef(''); const segmentsCb = useRef<((segments: string) => void) | undefined>( @@ -1143,6 +1148,8 @@ const PassageDetailProvider = (props: IProps) => { handleHighlightDiscussion, forceRefresh, setDiscussOpen, + compareMediaId, + setCompareMediaId, sectionArr: (getProjectDefault(projDefSectionMap) ?? []) as SectionArray, }, diff --git a/src/renderer/src/routes/PassageDetail.tsx b/src/renderer/src/routes/PassageDetail.tsx index da8e33b9..de491f3e 100644 --- a/src/renderer/src/routes/PassageDetail.tsx +++ b/src/renderer/src/routes/PassageDetail.tsx @@ -47,6 +47,7 @@ import PassageDetailParatextIntegration from '../components/PassageDetail/Passag import { PassageDetailDiscuss } from '../components/PassageDetail/PassageDetailDiscuss'; import { addPt } from '../utils/addPt'; import DiscussionPanel from '../components/Discussions/DiscussionPanel'; +import TeamCheckReferenceMobile from '../components/PassageDetail/mobile/TeamCheckReferenceMobile'; const KeyTerms = React.lazy( () => import('../components/PassageDetail/Keyterms/KeyTerms') @@ -314,16 +315,25 @@ const PassageDetailGrids = () => { tool !== ToolSlug.ConsultantCheck ? ( - {(tool !== ToolSlug.KeyTerm || mediafileId) && ( + {(tool !== ToolSlug.KeyTerm || mediafileId) && !isMobile && ( )} - {tool === ToolSlug.TeamCheck && } + {tool === ToolSlug.TeamCheck && + (isMobile ? ( + + ) : ( + + ))} {tool === ToolSlug.KeyTerm && ( }> @@ -459,9 +469,7 @@ export const PassageDetail = () => { }} > - - - + {} ); };