Skip to content

Commit 2b0f921

Browse files
committed
Fixed form submission list
1 parent b063130 commit 2b0f921

1 file changed

Lines changed: 87 additions & 71 deletions

File tree

src/forms/components/FormSubmissions.tsx

Lines changed: 87 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ interface Props {
2727
export const FormSubmissions: React.FC<Props> = memo((props) => {
2828
const [summary, setSummary] = useState<any>([]);
2929
const [summaryCsv, setSummaryCsv] = useState<any>([]);
30-
const yesNoMap: any = { True: Locale.label("common.yes"), False: Locale.label("common.no") };
30+
const yesNoMap = useMemo(() => ({ True: Locale.label("common.yes"), False: Locale.label("common.no") }), []);
3131
const yesNoDefault = useMemo(
3232
() => [
3333
{ value: "Yes", text: Locale.label("common.yes") },
@@ -38,6 +38,63 @@ export const FormSubmissions: React.FC<Props> = memo((props) => {
3838
const contentRef: any = useRef<HTMLDivElement>(null);
3939
const handleSummaryPrint = useReactToPrint({ content: () => contentRef.current });
4040

41+
const getPerson = useCallback((people: PersonInterface[], formSubmission: any) => {
42+
let result = people.find((person: PersonInterface) => person.id === formSubmission.submittedBy);
43+
if (formSubmission.contentType === "person") result = people.find((person: PersonInterface) => person.id === formSubmission.contentId);
44+
return result;
45+
}, []);
46+
47+
const setSummaryResultDefault = useCallback(
48+
(question: QuestionInterface, answer: AnswerInterface) => {
49+
const choices: any = [];
50+
const questionChoices = question.choices || yesNoDefault;
51+
questionChoices.forEach((choice: any) => {
52+
const choiceCount = { [choice.value]: 0, text: choice.text };
53+
if (question.fieldType === "Checkbox") {
54+
if (answer && answer?.value) {
55+
const splitAnswer = answer.value?.split(",");
56+
if (splitAnswer.indexOf(choice.value) > -1) choiceCount[choice.value] = 1;
57+
}
58+
} else {
59+
if (answer && answer?.value && choice.value === answer.value) choiceCount[choice.value] = 1;
60+
}
61+
choices.push(choiceCount);
62+
});
63+
return { title: question.title, values: choices };
64+
},
65+
[yesNoDefault]
66+
);
67+
68+
const setSummaryResultData = useCallback((summaryData: any, question: QuestionInterface, answer: AnswerInterface) => {
69+
const match = summaryData.find((result: any) => result.title === question.title);
70+
if (match) {
71+
match.values.forEach((resultValue: any) => {
72+
const key: string = Object.keys(resultValue)[0];
73+
if (question.fieldType === "Checkbox") {
74+
const splitAnswer = answer?.value?.split(",");
75+
if (splitAnswer?.indexOf(key) > -1) resultValue[key] = resultValue[key] + 1;
76+
} else {
77+
if (key === answer?.value) resultValue[key] = resultValue[key] + 1;
78+
}
79+
});
80+
} else summaryData.push(setSummaryResultDefault(question, answer));
81+
}, [setSummaryResultDefault]);
82+
83+
const setFormSubmissionData = useCallback(
84+
(people: PersonInterface[], formSubmission: any) => {
85+
const submittedBy = getPerson(people, formSubmission);
86+
87+
formSubmission.person = { name: submittedBy?.name?.display || Locale.label("forms.formSubmissions.anon"), id: submittedBy?.id || null };
88+
formSubmission.mappedQA = [];
89+
formSubmission.csvData = [];
90+
if (formSubmission.questions) {
91+
formSubmission.questions = formSubmission.questions.sort((a: QuestionInterface, b: QuestionInterface) => (a.title > b.title ? 1 : -1));
92+
}
93+
return formSubmission;
94+
},
95+
[getPerson]
96+
);
97+
4198
const people = useQuery<PersonInterface[]>({
4299
queryKey: ["/people", "MembershipApi"],
43100
placeholderData: [],
@@ -74,62 +131,7 @@ export const FormSubmissions: React.FC<Props> = memo((props) => {
74131
setSummary(summaryData);
75132
setSummaryCsv(csv);
76133
}
77-
}, [people.data, formSubmissions.data, yesNoMap]);
78-
79-
const setSummaryResultData = useCallback((summaryData: any, question: QuestionInterface, answer: AnswerInterface) => {
80-
const match = summaryData.find((result: any) => result.title === question.title);
81-
if (match) {
82-
match.values.forEach((resultValue: any) => {
83-
const key: string = Object.keys(resultValue)[0];
84-
if (question.fieldType === "Checkbox") {
85-
const splitAnswer = answer?.value?.split(",");
86-
if (splitAnswer?.indexOf(key) > -1) resultValue[key] = resultValue[key] + 1;
87-
} else {
88-
if (key === answer?.value) resultValue[key] = resultValue[key] + 1;
89-
}
90-
});
91-
} else summaryData.push(setSummaryResultDefault(question, answer));
92-
}, []);
93-
94-
const getPerson = useCallback((people: PersonInterface[], formSubmission: any) => {
95-
let result = people.find((person: PersonInterface) => person.id === formSubmission.submittedBy);
96-
if (formSubmission.contentType === "person") result = people.find((person: PersonInterface) => person.id === formSubmission.contentId);
97-
return result;
98-
}, []);
99-
100-
const setFormSubmissionData = useCallback(
101-
(people: PersonInterface[], formSubmission: any) => {
102-
const submittedBy = getPerson(people, formSubmission);
103-
104-
formSubmission.person = { name: submittedBy?.name?.display || Locale.label("forms.formSubmissions.anon"), id: submittedBy?.id || null };
105-
formSubmission.mappedQA = [];
106-
formSubmission.csvData = [];
107-
formSubmission.questions = formSubmission.questions.sort((a: QuestionInterface, b: QuestionInterface) => (a.title > b.title ? 1 : -1));
108-
return formSubmission;
109-
},
110-
[getPerson]
111-
);
112-
113-
const setSummaryResultDefault = useCallback(
114-
(question: QuestionInterface, answer: AnswerInterface) => {
115-
const choices: any = [];
116-
const questionChoices = question.choices || yesNoDefault;
117-
questionChoices.forEach((choice: any) => {
118-
const choiceCount = { [choice.value]: 0, text: choice.text };
119-
if (question.fieldType === "Checkbox") {
120-
if (answer && answer?.value) {
121-
const splitAnswer = answer.value?.split(",");
122-
if (splitAnswer.indexOf(choice.value) > -1) choiceCount[choice.value] = 1;
123-
}
124-
} else {
125-
if (answer && answer?.value && choice.value === answer.value) choiceCount[choice.value] = 1;
126-
}
127-
choices.push(choiceCount);
128-
});
129-
return { title: question.title, values: choices };
130-
},
131-
[yesNoDefault]
132-
);
134+
}, [people.data, formSubmissions.data, yesNoMap, getPerson, setFormSubmissionData, setSummaryResultData, setSummaryResultDefault]);
133135

134136
const getResultCount = useCallback((summaryValues: any[]) => {
135137
const results: JSX.Element[] = [];
@@ -184,8 +186,9 @@ export const FormSubmissions: React.FC<Props> = memo((props) => {
184186

185187
const getAnswers = useCallback((formSubmission: FormSubmissionInterface) => {
186188
const rows: JSX.Element[] = [];
187-
formSubmission.questions.forEach((question: QuestionInterface) => {
188-
const answer = formSubmission.answers.find((answer: AnswerInterface) => answer.questionId === question.id);
189+
formSubmission.questions?.forEach((question: QuestionInterface) => {
190+
if (!question?.id) return;
191+
const answer = formSubmission.answers?.find((answer: AnswerInterface) => answer.questionId === question.id);
189192
rows.push(
190193
<TableCell key={question.id}>
191194
<Typography variant="body2">{answer?.value || "-"}</Typography>
@@ -215,6 +218,13 @@ export const FormSubmissions: React.FC<Props> = memo((props) => {
215218
}
216219

217220
formSubmissions.data?.forEach((submission: any, i: number) => {
221+
// Process the submission data inline
222+
const processedSubmission = people.data ? setFormSubmissionData(people.data, submission) : submission;
223+
224+
// Allow submissions even without a person ID (anonymous submissions)
225+
const personName = processedSubmission.person?.name || Locale.label("forms.formSubmissions.anon");
226+
const personId = processedSubmission.person?.id;
227+
218228
rows.push(
219229
<TableRow
220230
key={i}
@@ -223,25 +233,31 @@ export const FormSubmissions: React.FC<Props> = memo((props) => {
223233
transition: "background-color 0.2s ease",
224234
}}>
225235
<TableCell key="personName">
226-
<a
227-
href={"/people/" + submission.person.id}
228-
style={{
229-
textDecoration: "none",
230-
color: "var(--c1l2)",
231-
fontWeight: 500,
232-
}}>
233-
{submission.person.name}
234-
</a>
236+
{personId ? (
237+
<a
238+
href={"/people/" + personId}
239+
style={{
240+
textDecoration: "none",
241+
color: "var(--c1l2)",
242+
fontWeight: 500,
243+
}}>
244+
{personName}
245+
</a>
246+
) : (
247+
<Typography variant="body2" sx={{ fontWeight: 500 }}>
248+
{personName}
249+
</Typography>
250+
)}
235251
</TableCell>
236252
<TableCell key="subDate">
237-
<Typography variant="body2">{DateHelper.prettyDate(new Date(submission.submissionDate))}</Typography>
253+
<Typography variant="body2">{DateHelper.prettyDate(new Date(processedSubmission.submissionDate))}</Typography>
238254
</TableCell>
239-
{getAnswers(submission)}
255+
{getAnswers(processedSubmission)}
240256
</TableRow>
241257
);
242258
});
243259
return rows;
244-
}, [formSubmissions.data, getAnswers]);
260+
}, [formSubmissions.data, people.data, getAnswers, setFormSubmissionData]);
245261

246262
const editLinks = useMemo(() => {
247263
const formName = formSubmissions.data?.length ? formSubmissions.data[0].form?.name + ".csv" : "form_submissions.csv";

0 commit comments

Comments
 (0)