Skip to content

Commit

Permalink
Merge pull request #85 from complexdatacollective/feature/alternate-b…
Browse files Browse the repository at this point in the history
…eforeNext

Feature/alternate before next
  • Loading branch information
jthrilly committed Feb 23, 2024
2 parents 545e08a + cddff46 commit cc132f4
Show file tree
Hide file tree
Showing 58 changed files with 1,023 additions and 1,638 deletions.
26 changes: 1 addition & 25 deletions app/(interview)/interview/_components/InterviewShell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import { store } from '~/lib/interviewer/store';
import { api } from '~/trpc/client';
import { useRouter } from 'next/navigation';
import ServerSync from './ServerSync';
import { parseAsInteger, useQueryState } from 'nuqs';
import { useEffect, useState } from 'react';
import { Spinner } from '~/lib/ui/components';

Expand All @@ -22,11 +21,6 @@ const InterviewShell = ({ interviewID }: { interviewID: string }) => {
const router = useRouter();
const [initialized, setInitialized] = useState(false);

const [currentStage, setCurrentStage] = useQueryState(
'stage',
parseAsInteger,
);

const { isLoading, data: serverData } = api.interview.get.byId.useQuery(
{ id: interviewID },
{
Expand All @@ -43,17 +37,6 @@ const InterviewShell = ({ interviewID }: { interviewID: string }) => {

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

// If we have a current stage in the URL bar, and it is different from the
// server session, set the server session to the current stage.
//
// If we don't have a current stage in the URL bar, set it to the server
// session, and set the URL bar to the server session.
if (currentStage === null) {
void setCurrentStage(serverSession.currentStep);
} else if (currentStage !== serverSession.currentStep) {
serverSession.currentStep = currentStage;
}

// If there's no current stage in the URL bar, set it.
store.dispatch<SetServerSessionAction>({
type: SET_SERVER_SESSION,
Expand All @@ -64,14 +47,7 @@ const InterviewShell = ({ interviewID }: { interviewID: string }) => {
});

setInitialized(true);
}, [
serverData,
currentStage,
setCurrentStage,
router,
initialized,
setInitialized,
]);
}, [serverData, router, initialized, setInitialized]);

if (isLoading) {
return (
Expand Down
3 changes: 2 additions & 1 deletion app/(interview)/interview/_components/ServerSync.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ const ServerSync = ({
// eslint-disable-next-line react-hooks/exhaustive-deps
const debouncedSessionSync = useCallback(
debounce(syncSessionWithServer, 2000, {
leading: false,
leading: true,
trailing: true,
maxWait: 10000,
}),
Expand All @@ -55,6 +55,7 @@ const ServerSync = ({
id: interviewId,
network: currentSession.network,
currentStep: currentSession.currentStep ?? 0,
stageMetadata: currentSession.stageMetadata, // Temporary storage used by tiestrengthcensus/dyadcensus to store negative responses
});
}, [
currentSession,
Expand Down
131 changes: 0 additions & 131 deletions hooks/useNetwork.ts

This file was deleted.

32 changes: 32 additions & 0 deletions hooks/useWhatChanged.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/* eslint-disable no-console */
import { useEffect, useRef } from 'react';

export default function useWhatChanged(props: Record<string, unknown>) {
// cache the last set of props
const prev = useRef(props);

useEffect(() => {
// check each prop to see if it has changed
const changed = Object.entries(props).reduce(
(a, [key, prop]: [string, unknown]) => {
if (prev.current[key] === prop) return a;
return {
...a,
[key]: {
prev: prev.current[key],
next: prop,
},
};
},
{} as Record<string, unknown>,
);

if (Object.keys(changed).length > 0) {
console.group('Props That Changed');
console.log(changed);
console.groupEnd();
}

prev.current = props;
}, [props]);
}
48 changes: 44 additions & 4 deletions lib/interviewer/behaviours/withPrompt.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ import { useDispatch, useSelector } from 'react-redux';
import { actionCreators as sessionActions } from '../ducks/modules/session';
import { getAllVariableUUIDsByEntity } from '../selectors/protocol';
import {
getIsFirstPrompt,
getIsLastPrompt,
getPromptIndex,
getPrompts,
} from '../selectors/session';
Expand Down Expand Up @@ -35,6 +33,43 @@ const processSortRules = (prompts = [], codebookVariables) => {
});
};

/**
* @typedef {Object} Prompt
* @property {string} id
* @property {string} text
* @property {string} [variable]
* @property {string} [createEdge]
* @property {string} [edgeVariable]
*
* @typedef {Array<Prompt>} Prompts
*
* @typedef {Object} PromptState
* @property {number} promptIndex
* @property {Prompt} prompt
* @property {Prompts} prompts
* @property {Function} promptForward
* @property {Function} promptBackward
* @property {Function} setPrompt
* @property {boolean} isLastPrompt
* @property {boolean} isFirstPrompt
* @property {Function} updatePrompt
*
* @returns {PromptState}
* @private
*
* @example
* const {
* promptIndex,
* prompt,
* prompts,
* promptForward,
* promptBackward,
* setPrompt,
* isLastPrompt,
* isFirstPrompt,
* updatePrompt,
* } = usePrompts();
*/
export const usePrompts = () => {
const dispatch = useDispatch();
const updatePrompt = (promptIndex) =>
Expand All @@ -45,9 +80,9 @@ export const usePrompts = () => {

const processedPrompts = processSortRules(prompts, codebookVariables);

const isFirstPrompt = useSelector(getIsFirstPrompt);
const isLastPrompt = useSelector(getIsLastPrompt);
const promptIndex = useSelector(getPromptIndex);
const isFirstPrompt = prompts.length === 0;
const isLastPrompt = promptIndex === prompts.length - 1;

const promptForward = () => {
updatePrompt((promptIndex + 1) % processedPrompts.length);
Expand All @@ -59,6 +94,10 @@ export const usePrompts = () => {
);
};

const setPrompt = (index) => {
updatePrompt(index);
};

const currentPrompt = () => {
return processedPrompts[promptIndex] ?? { id: null };
};
Expand All @@ -69,6 +108,7 @@ export const usePrompts = () => {
prompts: processedPrompts,
promptForward,
promptBackward,
setPrompt,
isLastPrompt,
isFirstPrompt,
updatePrompt,
Expand Down
13 changes: 13 additions & 0 deletions lib/interviewer/components/MultiNodeBucket.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { DragSource } from '../behaviours/DragAndDrop';
import createSorter from '../utils/createSorter';
import { NodeTransition } from './NodeList';
import { AnimatePresence, motion } from 'framer-motion';
import useReadyForNextStage from '../hooks/useReadyForNextStage';

const EnhancedNode = DragSource(Node);

Expand All @@ -28,9 +29,21 @@ const MultiNodeBucket = (props) => {
setSortedNodes(sorted);
}, [nodes, sortOrder, listId]);

// Set the ready to advance state when there are no items left in the bucket
const { updateReady } = useReadyForNextStage();

useEffect(() => {
updateReady(sortedNodes.length === 0);

return () => {
updateReady(false);
}
}, [sortedNodes.length, updateReady]);

return (
<motion.div layout className="node-list">
<AnimatePresence mode="sync">
{sortedNodes.length === 0 && (<div className='h-full flex items-center justify-center'>No items to place</div>)}
{sortedNodes.slice(0, 3).map((node, index) => (
<NodeTransition
key={`${node[entityPrimaryKeyProperty]}_${index}`}
Expand Down
Loading

0 comments on commit cc132f4

Please sign in to comment.