Skip to content

This file was deleted.

67 changes: 55 additions & 12 deletions jsapp/js/components/submissions/DataTableCell/RepeatGroupCell.tsx
Original file line number Diff line number Diff line change
@@ -1,27 +1,70 @@
import { List } from '@mantine/core'
import type { SubmissionResponse } from '#/dataInterface'
import { getRepeatGroupAnswers } from '../submissionUtils'
import styles from './RepeatGroupCell.module.scss'
import {
type RepeatGroupAnswerTreeNode,
formatRepeatGroupAnswerValueToText,
getRepeatGroupAnswerTree,
} from '../repeatGroupUtils'
import TextModalCell from './TextModalCell'

interface RepeatGroupCellProps {
submissionData: SubmissionResponse
rowName: string
columnName: string
submissionIndex: number
submissionTotal: number
}

function formatIndexPath(indexPath: number[]): string {
return `${indexPath.join('.')}.`
}

function formatInlineAnswer(answerNode: RepeatGroupAnswerTreeNode, indexPath: number[]): string {
if (!Array.isArray(answerNode)) {
return `${formatIndexPath(indexPath)} ${formatRepeatGroupAnswerValueToText(answerNode)}`
}

return answerNode
.map((childNode, childIndex) => formatInlineAnswer(childNode, [...indexPath, childIndex + 1]))
.join('; ')
}

function collectIndexedLeafAnswers(answerNode: RepeatGroupAnswerTreeNode, indexPath: number[]): string[] {
if (!Array.isArray(answerNode)) {
return [`${formatIndexPath(indexPath)} ${formatRepeatGroupAnswerValueToText(answerNode)}`]
}

return answerNode.flatMap((childNode, childIndex) =>
collectIndexedLeafAnswers(childNode, [...indexPath, childIndex + 1]),
)
}

/**
* Displays a list of answers from a repeat group question.
*/
export default function RepeatGroupCell(props: RepeatGroupCellProps) {
const repeatGroupAnswers = getRepeatGroupAnswers(props.submissionData, props.rowName)
if (!repeatGroupAnswers) return null
const repeatGroupAnswers = getRepeatGroupAnswerTree(props.submissionData, props.rowName)
if (!repeatGroupAnswers || repeatGroupAnswers.length <= 0) return null

return (
<div className={styles.repeatGroupCell} dir='auto'>
{repeatGroupAnswers.map((answer, i) => (
<span key={i}>
{i > 0 && ', '}
{answer}
</span>
const inlineText = repeatGroupAnswers.map((answer, i) => formatInlineAnswer(answer, [i + 1])).join('; ')

const modalRows = repeatGroupAnswers.flatMap((answer, i) => collectIndexedLeafAnswers(answer, [i + 1]))

const modalContent = (
<List pl={0}>
{modalRows.map((rowText, i) => (
<List.Item key={i}>{rowText}</List.Item>
))}
</div>
</List>
)

return (
<TextModalCell
text={inlineText}
modalContent={modalContent}
columnName={props.columnName}
submissionIndex={props.submissionIndex}
submissionTotal={props.submissionTotal}
/>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ interface TextModalCellProps {
columnName: string
submissionIndex: number
submissionTotal: number
modalContent?: React.ReactNode
}

/**
Expand Down Expand Up @@ -69,7 +70,7 @@ export default function TextModalCell(props: TextModalCellProps) {

<KoboModalContent>
<div className={styles.modalContent} dir='auto'>
{props.text}
{props.modalContent ?? props.text}
</div>
</KoboModalContent>
</KoboModal>
Expand Down
33 changes: 31 additions & 2 deletions jsapp/js/components/submissions/DataTableCell/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,22 @@ export default function DataTableCell(props: DataTableCellProps) {
const submissionIndex = props.reactTableRow.index + 1
const columnName = getColumnLabel(props.asset, props.columnKey, props.showGroupName, props.translationIndex)

const shouldRenderUndefinedNestedKeyAsRepeat = (() => {
if (props.reactTableRow.value !== undefined || !props.columnKey.includes('/')) {
return false
}

const keyPathSegments = props.columnKey.split('/')
for (let i = keyPathSegments.length - 1; i >= 1; i--) {
const parentPath = keyPathSegments.slice(0, i).join('/')
if (Array.isArray(submission[parentPath])) {
return true
}
}

return false
})()

if (
props.isBulkProcessingInProgress &&
props.reactTableRow.value === undefined &&
Expand All @@ -47,8 +63,21 @@ export default function DataTableCell(props: DataTableCellProps) {
)
}

if (typeof props.reactTableRow.value === 'object' && !props.columnKey.startsWith(SUPPLEMENTAL_DETAILS_PROP)) {
return <RepeatGroupCell submissionData={submission} rowName={props.columnKey} />
// Some repeat answers are stored under related nested keys, so a direct lookup for this column key can be
// undefined even though repeat data exists in the submission payload.
if (
!props.columnKey.startsWith(SUPPLEMENTAL_DETAILS_PROP) &&
(typeof props.reactTableRow.value === 'object' || shouldRenderUndefinedNestedKeyAsRepeat)
) {
return (
<RepeatGroupCell
submissionData={submission}
rowName={props.columnKey}
columnName={columnName}
submissionIndex={submissionIndex}
submissionTotal={props.submissionCount}
/>
)
}
Comment thread
greptile-apps[bot] marked this conversation as resolved.

if (props.question && props.question.type && props.reactTableRow.value) {
Expand Down
Loading
Loading