Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/alternate before next #85

Merged
merged 20 commits into from
Feb 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
5f44d09
WIP
jthrilly Feb 21, 2024
d0c14b8
fix issues with selector re-rendering caused by stage transition
jthrilly Feb 21, 2024
5b94c51
refinements to component structure, getNavigableStages selector, and …
jthrilly Feb 22, 2024
79c45b9
add getNavigationHelpers()
jthrilly Feb 22, 2024
75d4790
fix for registerBeforeNext on TieStrengthCensus and DyadCensus interf…
jthrilly Feb 22, 2024
953ef9b
sync stageMetadata from session with server
jthrilly Feb 22, 2024
246efa0
fix auto advance behaviour
jthrilly Feb 22, 2024
1b1e620
small CSS fixes
jthrilly Feb 22, 2024
e3d15e4
fix bug with navigation advancing prompt when there are no slides by …
jthrilly Feb 22, 2024
1aa0c3c
convert useSteps and useEdgeState to ts to fix bugs with stage metadata
jthrilly Feb 23, 2024
85ea545
update new useEdgeState for compatibility with tie strength census
jthrilly Feb 23, 2024
887a2a7
fix TieStrengthCensus
jthrilly Feb 23, 2024
0cc710d
allow navigation when no beforeNext function is set
jthrilly Feb 23, 2024
6fdc54f
handle case where there are no nodes in useEdgeState
jthrilly Feb 23, 2024
65e0721
automatically unregister registerBeforeNext on stage change using use…
jthrilly Feb 23, 2024
02ab883
implement beforeNext reset during animation phase
jthrilly Feb 23, 2024
b9004b1
linting
jthrilly Feb 23, 2024
95e0ceb
add missing return statements to beforeNext handlers
jthrilly Feb 23, 2024
2f47b8f
move reset call after animation
jthrilly Feb 23, 2024
cddff46
remove debug hook
jthrilly Feb 23, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -49,17 +43,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 @@ -70,14 +53,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
Loading