-
-
Notifications
You must be signed in to change notification settings - Fork 24
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #35 from complexdatacollective/feature/interviewer…
…-port-1 Initial Interviewer port
- Loading branch information
Showing
839 changed files
with
49,257 additions
and
445 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,10 @@ | ||
{ | ||
"css.customData": ["./.vscode/css-data.json"], | ||
"css.customData": [ | ||
"./.vscode/css-data.json" | ||
], | ||
"typescript.tsdk": "node_modules/typescript/lib", | ||
"typescript.enablePromptUseWorkspaceTsdk": true, | ||
"WillLuke.nextjs.addTypesOnSave": true, | ||
"WillLuke.nextjs.hasPrompted": true | ||
} | ||
"WillLuke.nextjs.hasPrompted": true, | ||
"jest.jestCommandLine": "pnpm run test" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
export default function Loading() { | ||
// Or a custom loading skeleton component | ||
return <p>Loading interview...</p>; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,46 +1,19 @@ | ||
import { InterviewProvider } from '~/providers/InterviewProvider'; | ||
import Stage from '~/app/(interview)/interview/_components/Stage'; | ||
import InterviewNavigation from '~/app/(interview)/interview/_components/InterviewNavigation'; | ||
import type { NcNetwork, Protocol } from '@codaco/shared-consts'; | ||
import Link from 'next/link'; | ||
import { api } from '~/trpc/server'; | ||
import { Button } from '~/components/ui/Button'; | ||
import InterviewShell from '../_components/InterviewShell'; | ||
import NoSSRWrapper from '~/utils/NoSSRWrapper'; | ||
|
||
export default function Page({ params }: { params: { interviewId: string } }) { | ||
const { interviewId } = params; | ||
|
||
export default async function Page({ | ||
params: { interviewId }, | ||
}: { | ||
params: { interviewId: string }; | ||
}) { | ||
// Fetch interview data from the database | ||
if (!interviewId) { | ||
return 'No interview id found'; | ||
} | ||
|
||
const interview = await api.interview.get.byId.query({ id: interviewId }); | ||
|
||
if (!interview) { | ||
return 'No interview found'; | ||
} | ||
|
||
const initialNetwork = interview.network as NcNetwork; | ||
const interviewProtocol = interview.protocol as unknown as Protocol; | ||
|
||
return ( | ||
<InterviewProvider | ||
interviewId={interviewId} | ||
initialNetwork={initialNetwork} | ||
protocol={interviewProtocol} | ||
> | ||
<div className="flex grow flex-col justify-between p-10"> | ||
<h1 className="text-3xl">Interview</h1> | ||
<Link href="/"> | ||
<Button>Exit Interview</Button> | ||
</Link> | ||
<Stage /> | ||
<aside className="flex items-center justify-center"> | ||
<InterviewNavigation /> | ||
</aside> | ||
</div> | ||
</InterviewProvider> | ||
<div className="flex h-[100vh] max-h-[100vh] flex-col bg-[var(--nc-background)] text-[var(--nc-text)]"> | ||
<NoSSRWrapper> | ||
<InterviewShell interviewID={interviewId} /> | ||
</NoSSRWrapper> | ||
</div> | ||
); | ||
} |
117 changes: 117 additions & 0 deletions
117
app/(interview)/interview/_components/InterviewShell.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
'use client'; | ||
|
||
import { Provider, useSelector } from 'react-redux'; | ||
import DialogManager from '~/lib/interviewer/components/DialogManager'; | ||
import ProtocolScreen from '~/lib/interviewer/containers/ProtocolScreen'; | ||
import { store } from '~/lib/interviewer/store'; | ||
import UserBanner from './UserBanner'; | ||
import { useEffect, useState } from 'react'; | ||
import { | ||
SET_SERVER_SESSION, | ||
type SetServerSessionAction, | ||
} from '~/lib/interviewer/ducks/modules/setServerSession'; | ||
import { getActiveSession } from '~/lib/interviewer/selectors/session'; | ||
import { api } from '~/trpc/client'; | ||
import { useQueryState } from 'next-usequerystate'; | ||
import usePrevious from '~/hooks/usePrevious'; | ||
import { isEqual } from 'lodash'; | ||
|
||
// The job of ServerSync is to listen to actions in the redux store, and to sync | ||
// data with the server. | ||
const ServerSync = ({ interviewId }: { interviewId: string }) => { | ||
const [init, setInit] = useState(false); | ||
// Current stage | ||
const currentSession = useSelector(getActiveSession); | ||
const prevCurrentSession = usePrevious(currentSession); | ||
const { mutate: syncSessionWithServer } = api.interview.sync.useMutation(); | ||
|
||
useEffect(() => { | ||
if (!init) { | ||
setInit(true); | ||
return; | ||
} | ||
|
||
if ( | ||
isEqual(currentSession, prevCurrentSession) || | ||
!currentSession || | ||
!prevCurrentSession | ||
) { | ||
return; | ||
} | ||
|
||
// check if current stage index is null (happens when hot reloading) | ||
if (currentSession.currentStep === null) { | ||
console.log('⚠️ Current stage index is null. Skipping sync.'); | ||
return; | ||
} | ||
|
||
console.log(`⬆️ Syncing session with server...`); | ||
syncSessionWithServer({ | ||
id: interviewId, | ||
network: currentSession.network, | ||
currentStep: currentSession.currentStep, | ||
}); | ||
}, [ | ||
currentSession, | ||
prevCurrentSession, | ||
interviewId, | ||
syncSessionWithServer, | ||
init, | ||
]); | ||
|
||
return null; | ||
}; | ||
|
||
// The job of interview shell is to receive the server-side session and protocol | ||
// and create a redux store with that data. | ||
// Eventually it will handle syncing this data back. | ||
const InterviewShell = ({ interviewID }: { interviewID: string }) => { | ||
const [currentStage, setCurrentStage] = useQueryState('stage'); | ||
|
||
const { isLoading } = api.interview.get.byId.useQuery( | ||
{ id: interviewID }, | ||
{ | ||
refetchOnMount: false, | ||
refetchOnWindowFocus: false, | ||
refetchOnReconnect: false, | ||
onSuccess: async (data) => { | ||
if (!data) { | ||
return; | ||
} | ||
|
||
const { protocol, ...serverSession } = data; | ||
|
||
console.log( | ||
'✅ Received server session. Setting current stage, and initializing redux store...', | ||
); | ||
|
||
if (!currentStage) { | ||
await setCurrentStage(serverSession.currentStep.toString()); | ||
} | ||
|
||
store.dispatch<SetServerSessionAction>({ | ||
type: SET_SERVER_SESSION, | ||
payload: { | ||
protocol, | ||
session: serverSession, | ||
}, | ||
}); | ||
}, | ||
}, | ||
); | ||
|
||
if (isLoading) { | ||
return 'Second loading stage...'; | ||
} | ||
|
||
return ( | ||
<Provider store={store}> | ||
<ServerSync interviewId={interviewID} /> | ||
<UserBanner /> | ||
<ProtocolScreen /> | ||
<DialogManager /> | ||
</Provider> | ||
); | ||
}; | ||
|
||
export default InterviewShell; |
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.