Skip to content

feat(comments): visual indicator for data values with comments#164

Open
ifoche wants to merge 5 commits intodevelopmentfrom
feature/comment-indicator
Open

feat(comments): visual indicator for data values with comments#164
ifoche wants to merge 5 commits intodevelopmentfrom
feature/comment-indicator

Conversation

@ifoche
Copy link
Member

@ifoche ifoche commented Mar 19, 2026

Summary

  • Adds comment field to DataValueBase and extracts it from the DHIS2 API response (already returned but previously discarded)
  • CommentIcon now shows a small green dot badge when the data value has an existing comment
  • Wired through DataElementItem — all form types (table, grid, grid-with-periods, etc.) inherit the indicator automatically
  • Enabled by default for all datasets, no configuration needed
  • TDD approach: 8 new tests in CommentIndicator.spec.ts

Related Tasks

Test plan

  • Verify green dot badge appears on comment icons for data values with existing comments
  • Verify no badge on data values without comments
  • Test across form types: table, grid, grid-with-periods
  • Verify clicking the comment icon still opens the DHIS2 comment dialog
  • Run yarn test — all 47 tests pass
  • Run yarn tsc --noEmit — no type errors
  • Run yarn lint — clean

🤖 Generated with Claude Code

…with comments

Add comment field to DataValueBase and extract it from the DHIS2 API
response. CommentIcon now shows a green dot badge when the associated
data value has a comment, threaded through DataElementItem. Enabled by
default for all datasets with no configuration needed.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@bundlemon
Copy link

bundlemon bot commented Mar 19, 2026

BundleMon

No change in files bundle size

Groups updated (1)
Status Path Size Limits
Build Folder
./**/*
1.22MB (+193B +0.02%) +20%

Final result: ✅

View report in BundleMon website ➡️


Current branch size history | Target branch size history

@ifoche ifoche requested a review from eperedo March 19, 2026 16:21
ifoche and others added 3 commits March 19, 2026 17:21
- Extract hasComment() to domain utility in DataValue.ts (single source
  of truth, tested via production code not test-local copy)
- Guard data value lookup behind !noComment to skip wasted work when
  comment icon is not rendered
- Make hasComment a required boolean prop on CommentIcon
- Remove unnecessary explicit comment: undefined from fixture

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Remove display:flex from CommentIcon wrapper that was inflating the
icon size. Remove temporary console.log debug statements from the
repository.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
period: Period;
categoryOptionComboId: Id;
isRequired?: boolean;
comment?: string;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think making comment an optional parameter could lead to unexpected errors. In this case we're not assigning the comment property in the method checkCompulsoryAndBuildDataValues in file Dhis2DataValueRepository.

Also it protect us if we forgot to pass the comment any time we need to use the dataValue entity. We can add the fallback to an empty string as a default value.

}

export function hasComment(dataValue: Pick<DataValueBase, "comment">): boolean {
return !!dataValue.comment;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Subjective, but I prefer dataValue.comment.length > 0 or Boolean(dataValue.comment).

!noComment &&
dataValueHasComment(
dataFormInfo.data.values.getOrEmpty(dataElement, {
orgUnitId: dataFormInfo.orgUnitId,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For orgUnitId it should be dataElement.orgUnit || dataFormInfo.orgUnitId. It will cover the case for the subnational dataSet where we need to save dataValues in a different orgUnit than the selected in the dataEntry.

Also using React.memo for the hasComment variable would be good.

- Make `comment` a required string (default "") on DataValueBase instead
  of optional, preventing missing-comment bugs in new code paths
- Introduce DataValueLookup type for store get/getOrEmpty so callers
  don't need to pass comment for lookups
- Use `dataValue.comment.length > 0` instead of `!!` in hasComment
- Fix orgUnitId in DataElementItem to use dataElement.orgUnit fallback
  for subnational datasets
- Wrap hasComment computation in React.useMemo
- Update test fixtures and assertions to match new empty-string default

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@ifoche
Copy link
Member Author

ifoche commented Mar 24, 2026

@eperedo Thanks for the review! All three points have been addressed in e3aa009:

  1. comment is now required (string, default "") on DataValueBase — added comment: "" to Dhis2DataValueRepository.checkCompulsoryAndBuildDataValues and all test fixtures. Introduced a DataValueLookup type for get/getOrEmpty so existing callers (which only need the key fields) don't have to pass comment.

  2. hasComment now uses dataValue.comment.length > 0 instead of !!.

  3. DataElementItem.tsxorgUnitId now falls back correctly with dataElement.orgUnit || dataFormInfo.orgUnitId for subnational datasets, and the hasComment computation is wrapped in React.useMemo.

@ifoche ifoche requested a review from eperedo March 24, 2026 12:53
Copy link
Contributor

@eperedo eperedo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, just a couple of things related to TS.

| DataValueMultiText;

export type DataValueLookup = Pick<DataValueBase, "orgUnitId" | "period" | "categoryOptionComboId"> &
Partial<Pick<DataValueBase, "comment" | "isRequired">>;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new type DataValueLookup is correct, but we don't need the comment or isRequired in the methods: get, getOrEmpty or getEmpty.

I think export type DataValueLookup = Pick<DataValueBase, "orgUnitId" | "period" | "categoryOptionComboId"> is enough, right?

): DataValue {
const resolvedDataElement = resolveDataElement(dataFormInfo, dataElement);
const dataValueBase: DataValueBase = {
const dataValueBase = {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And here we can use const dataValueBase: DataValueLookup = { ... } instead removing the type. Just to be extra safe in case we modify the object in the future with the type TS will yell at us if we introduce a wrong property.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants