Skip to content

Commit

Permalink
refactor interview fetching to happen in client component
Browse files Browse the repository at this point in the history
  • Loading branch information
jthrilly committed Dec 8, 2023
1 parent 4af084a commit bba0f87
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 84 deletions.
28 changes: 3 additions & 25 deletions app/(interview)/interview/[interviewId]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,40 +1,18 @@
import { api } from '~/trpc/server';
import InterviewShell from '../_components/InterviewShell';
import NoSSRWrapper from '~/utils/NoSSRWrapper';
import type { Prisma } from '@prisma/client';

export const dynamic = 'force-dynamic';

export type ServerSession = Prisma.InterviewGetPayload<null>;

export default async function Page({
params,
}: {
params: { interviewId: string };
}) {
export default function Page({ params }: { params: { interviewId: string } }) {
const { interviewId } = params;
// Fetch interview data from the database

if (!interviewId) {
console.log('no interview ID...creating one');
return 'No interview id found';
}

const interview = await api.interview.get.byId.query({ id: interviewId });

if (!interview) {
return 'No interview found';
}

const { protocol, ...serverSession } = interview;

return (
<div className="flex h-[100vh] max-h-[100vh] flex-col bg-[var(--nc-background)] text-[var(--nc-text)]">
<NoSSRWrapper>
<InterviewShell
interviewID={interviewId}
serverProtocol={protocol}
serverSession={serverSession}
/>
<InterviewShell interviewID={interviewId} />
</NoSSRWrapper>
</div>
);
Expand Down
59 changes: 30 additions & 29 deletions app/(interview)/interview/_components/InterviewShell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,21 @@ import ProtocolScreen from '~/lib/interviewer/containers/ProtocolScreen';
import { store } from '~/lib/interviewer/store';
import UserBanner from './UserBanner';
import { useEffect, useState } from 'react';
import type { Protocol } from '@codaco/shared-consts';
import type { ServerSession } from '../[interviewId]/page';
import {
SET_SERVER_SESSION,
type SetServerSessionAction,
} from '~/lib/interviewer/ducks/modules/setServerSession';
import { getStageIndex } from '~/lib/interviewer/selectors/session';
import { api } from '~/trpc/client';
import { useQueryState } from 'next-usequerystate';

// 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 currentStage = useSelector(getStageIndex);
const { mutate: updateStage } =
api.interview.sync.updateStageIndex.useMutation();
const { mutate: updateStage } = api.interview.sync.stageIndex.useMutation();

useEffect(() => {
if (!init) {
Expand All @@ -40,35 +38,38 @@ const ServerSync = ({ interviewId }: { interviewId: string }) => {
// 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,
serverProtocol,
serverSession,
}: {
interviewID: string;
serverProtocol: Protocol;
serverSession: ServerSession;
}) => {
const [loading, setLoading] = useState(true);
const [init, setInit] = useState(false);
const InterviewShell = ({ interviewID }: { interviewID: string }) => {
const [currentStage, setCurrentStage] = useQueryState('stage');

useEffect(() => {
if (init) {
return;
}
const { isLoading } = api.interview.get.byId.useQuery(
{ id: interviewID },
{
refetchOnMount: false,
refetchOnWindowFocus: false,
refetchOnReconnect: false,
onSuccess: async (data) => {
if (!data) {
return;
}

store.dispatch<SetServerSessionAction>({
type: SET_SERVER_SESSION,
payload: {
protocol: serverProtocol,
session: serverSession,
const { protocol, ...serverSession } = data;

if (!currentStage) {
await setCurrentStage(serverSession.currentStep.toString());
}

store.dispatch<SetServerSessionAction>({
type: SET_SERVER_SESSION,
payload: {
protocol,
session: serverSession,
},
});
},
});
setLoading(false);
setInit(true);
}, [serverSession, serverProtocol, init]);
},
);

if (loading) {
if (isLoading) {
return 'Second loading stage...';
}

Expand Down
11 changes: 6 additions & 5 deletions lib/interviewer/components/Navigation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -97,11 +97,12 @@ const useNavigationHelpers = (

// If currentStage is null, this is the first run. We need to set it based on
// the sessions current stage index.
useEffect(() => {
if (currentStage === null) {
setCurrentStage(stageIndex);
}
}, [currentStage, setCurrentStage, stageIndex]);
// useEffect(() => {
// if (currentStage === null) {
// console.log('current stage is null, setting to', stageIndex);
// setCurrentStage(stageIndex);
// }
// }, [currentStage, setCurrentStage, stageIndex]);

return {
progress,
Expand Down
57 changes: 32 additions & 25 deletions server/routers/interview.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { ensureError } from '~/utils/ensureError';

export const interviewRouter = router({
sync: router({
updateStageIndex: publicProcedure
stageIndex: publicProcedure
.input(
z.object({
interviewId: z.string().cuid(),
Expand All @@ -18,20 +18,50 @@ export const interviewRouter = router({
)
.mutation(async ({ input: { interviewId, stageIndex } }) => {
try {
await prisma.interview.update({
const result = await prisma.interview.update({
where: {
id: interviewId,
},
data: {
currentStep: stageIndex,
lastUpdated: new Date(),
},
});

console.log(result);

return { success: true, error: null };
} catch (error) {
return { success: false, error: 'Failed to update interview' };
}
}),
network: publicProcedure
.input(
z.object({
interviewId: z.string().cuid(),
network: NcNetworkZod.or(z.null()),
}),
)
.mutation(async ({ input: { interviewId, network } }) => {
try {
const updatedInterview = await prisma.interview.update({
where: {
id: interviewId,
},
data: {
network,
lastUpdated: new Date(),
},
});

return { error: null, updatedInterview };
} catch (error) {
return {
error: 'Failed to update interview',
updatedInterview: null,
};
}
}),
}),
create: publicProcedure
.input(participantIdentifierSchema)
Expand Down Expand Up @@ -82,29 +112,6 @@ export const interviewRouter = router({
};
}
}),
updateNetwork: publicProcedure
.input(
z.object({
interviewId: z.string().cuid(),
network: NcNetworkZod.or(z.null()),
}),
)
.mutation(async ({ input: { interviewId, network } }) => {
try {
const updatedInterview = await prisma.interview.update({
where: {
id: interviewId,
},
data: {
network,
},
});

return { error: null, updatedInterview };
} catch (error) {
return { error: 'Failed to update interview', updatedInterview: null };
}
}),
get: router({
all: publicProcedure.query(async () => {
const interviews = await prisma.interview.findMany({
Expand Down

0 comments on commit bba0f87

Please sign in to comment.