Skip to content

Commit

Permalink
Merge pull request #56 from the-deep/fix/optimize-query
Browse files Browse the repository at this point in the history
Fetch questions query only when leaf node is expanded
  • Loading branch information
AdityaKhatri authored Sep 13, 2023
2 parents cb2d93f + c0609e6 commit 174a319
Show file tree
Hide file tree
Showing 8 changed files with 339 additions and 287 deletions.
2 changes: 1 addition & 1 deletion backend
Submodule backend updated 1 files
+1 −0 main/settings.py
10 changes: 5 additions & 5 deletions src/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,10 @@
--padding-medium: 2em;

/* font-weights */
--font-weight-light: 300;
--font-weight-medium: 400;
--font-weight-bold: 700;
--font-weight-black: 900;
--dui-font-weight-light: 300;
--dui-font-weight-medium: 400;
--dui-font-weight-bold: 700;
--dui-font-weight-black: 900;

/* overriding deep-ui variables */
--dui-color-accent: #5A3070;
Expand All @@ -41,7 +41,7 @@
line-height: 1.5;
color: var(--text-color);
font-family: 'Source Sans 3', sans-serif;
font-weight: var(--font-weight-medium);
font-weight: var(--dui-font-weight-medium);
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ import {

import {
QUESTION_FRAGMENT,
} from '../queries';
} from '#views/QuestionnaireEdit/queries';

import styles from './index.module.css';

Expand Down
318 changes: 318 additions & 0 deletions src/views/QuestionnaireEdit/QuestionList/LeafNode/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,318 @@
import {
useState,
useCallback,
useMemo,
} from 'react';
import {
useQuery,
useMutation,
gql,
} from '@apollo/client';
import {
isNotDefined,
} from '@togglecorp/fujs';
import {
useAlert,
} from '@the-deep/deep-ui';

import SortableList from '#components/SortableList';
import {
QuestionsForLeafGroupQuery,
QuestionsForLeafGroupQueryVariables,
UpdateQuestionsVisibilityMutation,
UpdateQuestionsVisibilityMutationVariables,
UpdateQuestionsOrderMutation,
UpdateQuestionsOrderMutationVariables,
VisibilityActionEnum,
} from '#generated/types';
import {
type ProjectScope,
} from '#utils/common';

import QuestionPreview from './QuestionPreview';
import {
QUESTION_FRAGMENT,
} from '../../queries';

type Question = NonNullable<NonNullable<ProjectScope<QuestionsForLeafGroupQuery>['questions']>['items']>[number];
const questionKeySelector = (q: Question) => q.id;

const QUESTIONS_FOR_LEAF_GROUP = gql`
${QUESTION_FRAGMENT}
query QuestionsForLeafGroup(
$projectId: ID!,
$questionnaireId: ID!,
$leafGroupId: ID!,
) {
private {
projectScope(pk: $projectId) {
id
questions(
filters: {
questionnaire: {
pk: $questionnaireId,
},
leafGroup: {
pk: $leafGroupId,
},
}
order: {
order: ASC
}
) {
count
limit
offset
items {
...QuestionResponse
}
}
}
}
}
`;

const UPDATE_QUESTIONS_ORDER = gql`
${QUESTION_FRAGMENT}
mutation UpdateQuestionsOrder(
$projectId: ID!,
$questionnaireId: ID!,
$leafGroupId: ID!,
$data: [QuestionOrderInputType!]!
) {
private {
projectScope(pk: $projectId) {
bulkUpdateQuestionsOrder(
data: $data
leafGroupId: $leafGroupId
questionnaireId: $questionnaireId
) {
errors
results {
...QuestionResponse
}
}
}
}
}
`;

const UPDATE_QUESTIONS_VISIBILITY = gql`
${QUESTION_FRAGMENT}
mutation UpdateQuestionsVisibility(
$projectId: ID!,
$questionIds: [ID!]!,
$questionnaireId: ID!,
$visibility: VisibilityActionEnum!,
){
private {
projectScope(pk: $projectId) {
updateQuestionsVisibility(
ids: $questionIds,
questionnaireId: $questionnaireId,
visibility: $visibility,
) {
errors
results {
...QuestionResponse
}
}
}
}
}
`;

interface Props {
className?: string;
projectId: string;
questionnaireId: string;
leafGroupId: string;
onEditQuestionClick: (val?: string | undefined) => void;
setSelectedQuestionType: React.Dispatch<React.SetStateAction<string | undefined>>;
setActiveQuestionId: React.Dispatch<React.SetStateAction<string | undefined>>;
setSelectedLeafGroupId: React.Dispatch<React.SetStateAction<string | undefined>>;
}

function LeafNode(props: Props) {
const {
className,
projectId,
questionnaireId,
leafGroupId,
onEditQuestionClick,
setSelectedQuestionType,
setActiveQuestionId,
setSelectedLeafGroupId,
} = props;

const alert = useAlert();

const questionsVariables = useMemo(() => {
if (isNotDefined(projectId)
|| isNotDefined(questionnaireId)
|| isNotDefined(leafGroupId)) {
return undefined;
}

return ({
projectId,
questionnaireId,
leafGroupId,
});
}, [
projectId,
questionnaireId,
leafGroupId,
]);

const [
orderedQuestions,
setOrderedQuestions,
] = useState<Question[] | undefined>();

const {
loading: questionsPending,
refetch: retriggerQuestionsFetch,
} = useQuery<QuestionsForLeafGroupQuery, QuestionsForLeafGroupQueryVariables>(
QUESTIONS_FOR_LEAF_GROUP,
{
skip: isNotDefined(questionsVariables),
variables: questionsVariables,
onCompleted: (response) => {
const questions = response?.private?.projectScope?.questions?.items;
setOrderedQuestions(questions);
},
},
);

const [
triggerQuestionsOrderUpdate,
{ loading: questionsOrderUpdatePending },
] = useMutation<UpdateQuestionsOrderMutation, UpdateQuestionsOrderMutationVariables>(
UPDATE_QUESTIONS_ORDER,
{
onCompleted: (response) => {
const questionOrderResponse = response?.private
?.projectScope?.bulkUpdateQuestionsOrder;
if (questionOrderResponse?.errors) {
alert.show(
'Failed to update questions order',
{ variant: 'error' },
);
}
},
onError: () => {
alert.show(
'Failed to update questions order',
{ variant: 'error' },
);
},
},
);

const [
triggerQuestionsVisibilityUpdate,
] = useMutation<UpdateQuestionsVisibilityMutation, UpdateQuestionsVisibilityMutationVariables>(
UPDATE_QUESTIONS_VISIBILITY,
{
onCompleted: (response) => {
const questionsResponse = response?.private
?.projectScope?.updateQuestionsVisibility;
if (questionsResponse?.errors) {
alert.show(
'Failed to update questions visibility',
);
}
},
onError: () => {
alert.show(
'Failed to update questions visibility',
);
},
},
);

const handleQuestionOrderChange = useCallback((val: Question[]) => {
if (!val || !leafGroupId) {
return;
}
const orderedQuestionsToSend = val.map(
(question, index) => ({
id: question.id,
order: index + 1,
}),
);

triggerQuestionsOrderUpdate({
variables: {
projectId,
questionnaireId,
leafGroupId,
data: orderedQuestionsToSend,
},
});
setOrderedQuestions(val);
}, [
projectId,
questionnaireId,
leafGroupId,
triggerQuestionsOrderUpdate,
]);

const handleSelectedQuestionsChange = useCallback((val: boolean, id: string) => {
triggerQuestionsVisibilityUpdate({
variables: {
projectId,
questionnaireId,
questionIds: [id],
visibility: val
? 'SHOW' as VisibilityActionEnum
: 'HIDE' as VisibilityActionEnum,
},
});
}, [
triggerQuestionsVisibilityUpdate,
projectId,
questionnaireId,
]);

const questionRendererParams = useCallback((_: string, datum: Question) => ({
question: datum,
showAddQuestionPane: onEditQuestionClick,
setSelectedQuestionType,
projectId,
setActiveQuestionId,
onSelectedQuestionsChange: handleSelectedQuestionsChange,
setSelectedLeafGroupId,
refetchQuestionList: retriggerQuestionsFetch,
}), [
onEditQuestionClick,
projectId,
setActiveQuestionId,
setSelectedQuestionType,
handleSelectedQuestionsChange,
setSelectedLeafGroupId,
retriggerQuestionsFetch,
]);

return (
<SortableList
name="questions"
className={className}
data={orderedQuestions}
direction="vertical"
keySelector={questionKeySelector}
renderer={QuestionPreview}
rendererParams={questionRendererParams}
onChange={handleQuestionOrderChange}
borderBetweenItem
emptyMessage="There are no questions in this questionnaire yet."
pending={questionsPending || questionsOrderUpdatePending}
messageShown
filtered={false}
errored={false}
/>
);
}

export default LeafNode;
5 changes: 3 additions & 2 deletions src/views/QuestionnaireEdit/QuestionList/index.module.css
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
.list {
display: flex;
flex-direction: column;
overflow: unset;

--heading-font-size-large: 1.2rem;
--heading-font-size-medium: 1rem;
Expand All @@ -9,7 +10,7 @@

.item {
border: none;
overflow-y: unset;
overflow: unset;

.header {
background-color: transparent;
Expand All @@ -31,7 +32,7 @@

.content {
background-color: var(--dui-color-white);
overflow-y: unset;
overflow: unset;
}

&.first {
Expand Down
Loading

0 comments on commit 174a319

Please sign in to comment.