Skip to content

Commit

Permalink
feat: remove useless lunatic data in visualization download (#175)
Browse files Browse the repository at this point in the history
  • Loading branch information
chloe-renaud authored Dec 3, 2024
1 parent f4c6187 commit fe12c1a
Show file tree
Hide file tree
Showing 23 changed files with 268 additions and 96 deletions.
2 changes: 1 addition & 1 deletion src/api/visualizeQueryOptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import axios, { type AxiosRequestConfig } from 'axios'
import { ZodError } from 'zod'

import { ZodErrorWithName } from '@/components/error/ZodErrorWithName'
import type { Nomenclature } from '@/components/orchestrator/utils/lunaticType'
import type { Metadata } from '@/models/Metadata'
import type { SurveyUnitData } from '@/models/SurveyUnitData'
import type { Nomenclature } from '@/models/lunaticType'
import { surveyUnitMetadataSchema } from '@/models/metadataSchema'

function axiosGet<T>(url: string, options?: AxiosRequestConfig) {
Expand Down
84 changes: 42 additions & 42 deletions src/components/orchestrator/Orchestrator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ import { usePrevious } from '@/hooks/usePrevious'
import type { Metadata } from '@/models/Metadata'
import type { StateData } from '@/models/StateData'
import type { SurveyUnitData } from '@/models/SurveyUnitData'
import type {
LunaticGetReferentiel,
LunaticPageTag,
} from '@/models/lunaticType'
import {
computeControlEvent,
computeControlSkipEvent,
Expand All @@ -43,7 +47,6 @@ import { isBlockingError } from './utils/controls'
import { trimCollectedData } from './utils/data'
import { downloadAsJson } from './utils/downloadAsJson'
import { isObjectEmpty } from './utils/isObjectEmpty'
import type { LunaticGetReferentiel, LunaticPageTag } from './utils/lunaticType'
import { hasBeenSent, shouldDisplayWelcomeModal } from './utils/orchestrator'
import { scrollAndFocusToFirstError } from './utils/scrollAndFocusToFirstError'
import { isSequencePage } from './utils/sequence'
Expand Down Expand Up @@ -102,11 +105,11 @@ export namespace OrchestratorProps {
export function Orchestrator(props: OrchestratorProps) {
const { source, surveyUnitData, getReferentiel, mode, metadata } = props

const navigate = useNavigate()

// Allow to send telemetry events once survey unit id has been set
const [isTelemetryActivated, setIsTelemetryActivated] =
useState<boolean>(false)

const navigate = useNavigate()
const {
isTelemetryDisabled,
pushEvent,
Expand All @@ -116,31 +119,6 @@ export function Orchestrator(props: OrchestratorProps) {
const { setEventToPushAfterInactivity, triggerInactivityTimeoutEvent } =
usePushEventAfterInactivity(pushEvent)

const containerRef = useRef<HTMLDivElement>(null)
const contentRef = useRef<HTMLDivElement>(null)
const pageTagRef = useRef<LunaticPageTag>('1')
const validationModalActionsRef = useRef({
open: () => Promise.resolve(),
})

const initialCurrentPage = surveyUnitData?.stateData?.currentPage
const initialState = surveyUnitData?.stateData?.state
const pagination = source.pagination ?? 'question'

/** Displays the welcome modal which allows to come back to current page */
const shouldWelcome = shouldDisplayWelcomeModal(
initialState,
initialCurrentPage,
)

const lunaticLogger = useMemo(
() =>
mode === MODE_TYPE.VISUALIZE
? createLunaticLogger({ pageTag: pageTagRef })
: undefined,
[mode],
)

/** Triggers telemetry input event on Lunatic change */
const handleLunaticChange: LunaticChangesHandler = useCallback(
(changes) => {
Expand Down Expand Up @@ -169,6 +147,25 @@ export function Orchestrator(props: OrchestratorProps) {
[pushEvent, setEventToPushAfterInactivity],
)

const containerRef = useRef<HTMLDivElement>(null)
const contentRef = useRef<HTMLDivElement>(null)
const pageTagRef = useRef<LunaticPageTag>('1')
const validationModalActionsRef = useRef({
open: () => Promise.resolve(),
})

const initialCurrentPage = surveyUnitData?.stateData?.currentPage
const initialState = surveyUnitData?.stateData?.state
const pagination = source.pagination ?? 'question'

const lunaticLogger = useMemo(
() =>
mode === MODE_TYPE.VISUALIZE
? createLunaticLogger({ pageTag: pageTagRef })
: undefined,
[mode],
)

const {
getComponents,
Provider: LunaticProvider,
Expand Down Expand Up @@ -282,9 +279,16 @@ export function Orchestrator(props: OrchestratorProps) {

/** Allows to download data for visualize */
const downloadAsJsonRef = useRefSync(() => {
const data = getData(false)
const trimmedCollectedData = trimCollectedData(data.COLLECTED)
const trimmedData = {
...data,
COLLECTED: trimmedCollectedData,
}

downloadAsJson<SurveyUnitData>({
dataToDownload: {
data: getData(false),
data: trimmedData,
stateData: getCurrentStateData.current(),
personalization: surveyUnitData?.personalization,
},
Expand Down Expand Up @@ -411,18 +415,14 @@ export function Orchestrator(props: OrchestratorProps) {
)

const handleDepositProofClick = async () => {
switch (mode) {
case MODE_TYPE.VISUALIZE: {
downloadAsJsonRef.current()
navigate({ to: '/visualize', params: {} })
break
}
case MODE_TYPE.COLLECT: {
return props.getDepositProof()
}
case MODE_TYPE.REVIEW:
default:
break
if (mode === MODE_TYPE.VISUALIZE) {
downloadAsJsonRef.current()
navigate({ to: '/visualize', params: {} })
return
}
if (mode === MODE_TYPE.COLLECT) {
props.getDepositProof()
return
}
}

Expand Down Expand Up @@ -478,7 +478,7 @@ export function Orchestrator(props: OrchestratorProps) {
? goToPage({ page: initialCurrentPage })
: null
}
open={shouldWelcome}
open={shouldDisplayWelcomeModal(initialState, initialCurrentPage)}
/>
<ValidationModal actionsRef={validationModalActionsRef} />
{mode === MODE_TYPE.VISUALIZE && <VTLDevTools />}
Expand Down
9 changes: 4 additions & 5 deletions src/components/orchestrator/SequenceHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ import { fr } from '@codegouvfr/react-dsfr'

import { useSequenceTitle } from '@/hooks/useDocumentTitle'
import { declareComponentKeys, useTranslation } from '@/i18n'

import type { LunaticOverview } from './utils/lunaticType'
import type { LunaticOverview } from '@/models/lunaticType'

type SequenceHeaderProps = {
pagination: 'question' | 'sequence'
Expand All @@ -28,16 +27,16 @@ export function SequenceHeader(props: SequenceHeaderProps) {

if (currentSequenceIndex < 0 || currentSequence === undefined) return null

const stepCount = overview.length
const currentStep = currentSequenceIndex + 1 //overview is sorted and index starts at 0

if (pagination === 'question')
return (
<div className={fr.cx('fr-mt-1w')}>
<h2 className={fr.cx('fr-stepper__title')}>{currentSequence.label}</h2>
</div>
)

const stepCount = overview.length
const currentStep = currentSequenceIndex + 1 //overview is sorted and index starts at 0

return (
<div className={fr.cx('fr-stepper', 'fr-mb-2v')}>
<h2 className={fr.cx('fr-stepper__title', 'fr-mb-0')}>
Expand Down
3 changes: 2 additions & 1 deletion src/components/orchestrator/SurveyContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,12 @@ import { MODE_TYPE } from '@/constants/mode'
import { PAGE_TYPE } from '@/constants/page'
import { declareComponentKeys, useTranslation } from '@/i18n'
import type { InternalPageType } from '@/models/Page'
import type { LunaticOverview } from '@/models/lunaticType'

import type { OrchestratorProps } from './Orchestrator'
import { SequenceHeader } from './SequenceHeader'
import type { LunaticOverview } from './utils/lunaticType'

/** Displays form, allows to go next and back */
export function SurveyContainer(
props: PropsWithChildren<{
currentPage: InternalPageType
Expand Down
5 changes: 5 additions & 0 deletions src/components/orchestrator/customPages/ValidationModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ export type Props = {
open?: () => Promise<void>
}>
}

/**
* Modal displayed at the end of the survey to make sure the user understands
* they won't be able to change their answers once submitted
*/
export function ValidationModal({ actionsRef }: Props) {
const id = useId()

Expand Down
4 changes: 4 additions & 0 deletions src/components/orchestrator/customPages/ValidationPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ import { fr } from '@codegouvfr/react-dsfr'
import { useDocumentTitle } from '@/hooks/useDocumentTitle'
import { declareComponentKeys, useTranslation } from '@/i18n'

/**
* Page displayed when the user finishes the survey before they submit their
* answers
*/
export function ValidationPage() {
const { t } = useTranslation({ ValidationPage })

Expand Down
1 change: 1 addition & 0 deletions src/components/orchestrator/customPages/WelcomePage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ function renderMetadataContents(contents: Contents[] | undefined) {
)
}

/** Page displayed when the user first arrives on the orchestrator */
export function WelcomePage(props: { metadata: Metadata }) {
const { t } = useTranslation({ WelcomePage })
const { metadata } = props
Expand Down
158 changes: 158 additions & 0 deletions src/components/orchestrator/hooks/useStromaeNavigation.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
import { act, renderHook } from '@testing-library/react'

import { PAGE_TYPE } from '@/constants/page'
import type { InternalPageType, PageType, StromaePage } from '@/models/Page'

import { useStromaeNavigation } from './useStromaeNavigation'

describe('Use stromae navigation', () => {
test.each<{ initialCurrentPage?: PageType; expected: InternalPageType }>([
{ initialCurrentPage: PAGE_TYPE.WELCOME, expected: PAGE_TYPE.LUNATIC },
{ initialCurrentPage: PAGE_TYPE.VALIDATION, expected: PAGE_TYPE.LUNATIC },
{ initialCurrentPage: PAGE_TYPE.END, expected: PAGE_TYPE.END },
{ expected: PAGE_TYPE.LUNATIC },
])(
'go to next $initialCurrentPage -> $expected',
async ({ initialCurrentPage, expected }) => {
const { result } = renderHook(() =>
useStromaeNavigation({
initialCurrentPage,
}),
)

act(() => result.current.goNext())

expect(result.current.currentPage).toBe(expected)
},
)

test('go to next lunaticPage -> lunaticPage (not last page)', () => {
const goNextWithControlsMock = (goNext: () => void) => goNext()
const goNextLunaticMock = vi.fn()

const { result } = renderHook(() =>
useStromaeNavigation({
goNextWithControls: goNextWithControlsMock,
goNextLunatic: goNextLunaticMock,
}),
)

act(() => result.current.goNext()) // go to lunatic page

act(() => result.current.goNext())

expect(goNextLunaticMock).toHaveBeenCalledOnce()
expect(result.current.currentPage).toBe(PAGE_TYPE.LUNATIC)
})

test('go to next lunaticPage -> validationPage (last page)', () => {
const goNextWithControlsMock = (goNext: () => void) => goNext()
const goNextLunaticMock = vi.fn()

const { result } = renderHook(() =>
useStromaeNavigation({
isLastPage: true,
goNextWithControls: goNextWithControlsMock,
goNextLunatic: goNextLunaticMock,
}),
)

act(() => result.current.goNext()) // go to lunatic page

act(() => result.current.goNext())

expect(goNextLunaticMock).not.toHaveBeenCalled()
expect(result.current.currentPage).toBe(PAGE_TYPE.VALIDATION)
})

test.each<{ initialCurrentPage?: PageType; expected: InternalPageType }>([
{ initialCurrentPage: PAGE_TYPE.WELCOME, expected: PAGE_TYPE.WELCOME },
{ initialCurrentPage: PAGE_TYPE.VALIDATION, expected: PAGE_TYPE.WELCOME },
{ initialCurrentPage: PAGE_TYPE.END, expected: PAGE_TYPE.END },
{ expected: PAGE_TYPE.WELCOME },
])(
'go to previous $initialCurrentPage -> $expected',
async ({ initialCurrentPage, expected }) => {
const { result } = renderHook(() =>
useStromaeNavigation({
initialCurrentPage,
}),
)

act(() => result.current.goPrevious())

expect(result.current.currentPage).toBe(expected)
},
)

test('go to previous lunaticPage -> lunaticPage (not first page)', () => {
const goPrevLunaticMock = vi.fn()

const { result } = renderHook(() =>
useStromaeNavigation({
goPrevLunatic: goPrevLunaticMock,
}),
)

act(() => result.current.goNext()) // go to lunatic page

act(() => result.current.goPrevious())

expect(goPrevLunaticMock).toHaveBeenCalledOnce()
expect(result.current.currentPage).toBe(PAGE_TYPE.LUNATIC)
})

test('go to next lunaticPage -> welcomePage (first page)', () => {
const goPrevLunaticMock = vi.fn()

const { result } = renderHook(() =>
useStromaeNavigation({
isFirstPage: true,
goPrevLunatic: goPrevLunaticMock,
}),
)

act(() => result.current.goNext()) // go to lunatic page

act(() => result.current.goPrevious())

expect(goPrevLunaticMock).not.toHaveBeenCalled()
expect(result.current.currentPage).toBe(PAGE_TYPE.WELCOME)
})

test.each<{ page: StromaePage; shouldGoToLunaticPageBeCalled?: boolean }>([
{ page: PAGE_TYPE.WELCOME },
{ page: PAGE_TYPE.VALIDATION },
{ page: PAGE_TYPE.END },
])('go to page $page', ({ page }) => {
const goToLunaticPageMock = vi.fn()

const { result } = renderHook(() =>
useStromaeNavigation({
goToLunaticPage: goToLunaticPageMock,
}),
)

act(() => result.current.goToPage({ page }))
expect(goToLunaticPageMock).not.toHaveBeenCalled()

expect(result.current.currentPage).toBe(page)
})

test('go to lunatic page ', () => {
const goToLunaticPageMock = vi.fn()

const { result } = renderHook(() =>
useStromaeNavigation({
goToLunaticPage: goToLunaticPageMock,
}),
)

act(() => result.current.goToPage({ page: 1 }))

expect(goToLunaticPageMock).toHaveBeenCalledOnce()
expect(goToLunaticPageMock).toHaveBeenCalledWith({ page: 1 })

expect(result.current.currentPage).toBe(PAGE_TYPE.LUNATIC)
})
})
Loading

0 comments on commit fe12c1a

Please sign in to comment.