Issue Resolution with Mandatory Comments & Attachments
Table of Contents
- Overview
- Settings Configuration
- Implementation Locations
- User Experience
- Technical Architecture
- Localization Support
- Code References
Overview
This feature enables organizations to enforce documentation requirements when resolving issues. Based on configurable settings, users can be required to provide:
- Comments explaining the resolution
- Supporting attachments (photos, videos, or documents)
- Or both
Benefits
- Accountability: Ensures proper documentation of issue resolutions
- Knowledge Base: Creates a historical record of how issues were resolved
- Compliance: Meets organizational requirements for audit trails
- Quality Assurance: Reduces rushed resolutions without proper documentation
Settings Configuration
Data Model
Settings are stored in the IssueTrackerSettingsExtended interface and retrieved via the organization’s issue tracker settings:
File: packages/app/shared/type/issue-tracker-settings-extended.ts
export interface IssueTrackerSettingsExtended extends BaseIssueTrackerSettings {
/** Whether a comment is required when resolving issues */
requireCommentOnResolve?: boolean
/** Whether at least one attachment is required when resolving issues */
requireAttachmentOnResolve?: boolean
}Three Configuration Modes
Mode 1: No Requirements (Default)
Settings:
{
"requireCommentOnResolve": false,
"requireAttachmentOnResolve": false
}Behavior:
- No modal is shown when resolving issues
- Users can resolve directly without comments or attachments
- Traditional quick-resolve flow
Mode 2: Comment Required (Optional Attachments)
Settings:
{
"requireCommentOnResolve": true,
"requireAttachmentOnResolve": false
}Behavior:
- Modal is displayed when attempting to resolve
- Comment is required (minimum 1 character)
- Attachments are optional (max 10)
- Submit button is disabled until comment is provided
User Message:
“Add maximum 10 attachments (optional)“
Mode 3: Comment + At Least 1 Attachment Required
Settings:
{
"requireCommentOnResolve": true, // Can be false, still enforced
"requireAttachmentOnResolve": true
}Behavior:
- Modal is displayed when attempting to resolve
- Comment is required (minimum 1 character)
- At least 1 attachment is required
- Submit button is disabled until both requirements are met
User Messages:
“At least one attachment is required” “Add at least 1 attachment (max. 10)”
Important: When requireAttachmentOnResolve is true, the comment becomes automatically required regardless of the requireCommentOnResolve setting.
Validation Logic
File: packages/app/features/issues/hooks/use-issue-resolution-requirements.ts:31-45
const requireCommentOnResolve = issueTrackerSettings.requireCommentOnResolve || false
const requireAttachmentOnResolve = issueTrackerSettings.requireAttachmentOnResolve || false
// Logic:
// - If requireAttachmentOnResolve is true, BOTH comment and attachment are required
// - If only requireCommentOnResolve is true, only comment is required
// - If both are false, no modal is shown
const requireComment = requireCommentOnResolve || requireAttachmentOnResolve
const requireAttachment = requireAttachmentOnResolve
return {
showCommentModal: requireCommentOnResolve || requireAttachmentOnResolve,
requireComment,
requireAttachment,
}Implementation Locations
The feature is implemented in 4 primary locations where users can resolve issues:
1. Issue Details - Quick Resolve Button
Location: Issue Details Screen → “Resolve This Issue” Button
Component: QuickResolveButton with QuickResolveComment modal
Path: /issues/details/:issueID
Trigger Flow:
- User clicks “Resolve This Issue” button
- Alert dialog appears: “Are you sure you want to resolve this issue?”
- User clicks “Resolve” in the alert
- If
showCommentModalistrue: Comment modal opens - If
showCommentModalisfalse: Issue resolves immediately
Code Reference:
// https://github.com/Nimbly-Technologies/audit-lite/blob/master/packages/app/features/issues/details/components/quick-resolve-issue.tsx#L32-L38
const handleResolveIssue = async () => {
if (selectedIssue.status !== IssueStatusType.RESOLVED) {
if (showCommentModal) {
setQuickResolveMessageSheet(true)
setOpen(false)
return
}
// ... direct resolve
}
}2. Issue Details - Status Dropdown
Location: Issue Details Screen → Status Field Dropdown
Component: IssueStatus with IssueResolvedComment modal
Path: /issues/details/:issueID (Details Tab)
Trigger Flow:
- User clicks on Status dropdown in issue details
- User selects “Resolved” from the list
- If
showCommentModalistrue: Comment modal opens - If
showCommentModalisfalse: Status updates immediately
Code Reference:
// https://github.com/Nimbly-Technologies/audit-lite/blob/master/packages/app/features/issues/details/components/issue-status.tsx#L39-L48
const handleUpdate = (item: SelectorItemType) => {
if (item.id === IssueStatusType.BLOCKED) {
setIssueBlockMessageSheet(true)
return
}
if (item.id === IssueStatusType.RESOLVED && showCommentModal) {
setIssueResolvedMessageSheet(true)
return
}
// ... direct update
}3. Bulk Edit - Resolving Multiple Issues
Location: Issue List → Select Multiple Issues → Bulk Edit
Component: BulkEditList with BulkResolvedComment modal
Path: /issues/bulkEdit?ids=...
Trigger Flow:
- User selects multiple issues from the issue list
- User navigates to Bulk Edit screen
- User changes Status to “Resolved”
- User clicks “Update Issues” button
- If
showCommentModalistrue: Bulk comment modal opens - Comment and attachments apply to ALL selected issues
- If
showCommentModalisfalse: All issues update immediately
Code Reference:
// https://github.com/Nimbly-Technologies/audit-lite/blob/master/packages/app/features/issues/components/bulkEdit.tsx#L53-L59
const handleUpdateIssue = handleSubmit(async (data: UpdateIssueRequest) => {
// If status is resolved AND comment/attachment is required, show comment sheet
if (data.status === "resolved" && showCommentModal) {
setPendingUpdate(data)
setShowCommentSheet(true)
return
}
// ... direct update
})Special Note: The bulk comment modal shows a subtitle indicating how many issues will be affected:
“Please provide details about the resolution. (3 Issues)“
4. Issue Blocking (Bonus Feature)
While not part of the resolution requirements, the same infrastructure handles blocking issues:
Component: IssueBlockComment Trigger: When changing status to “Blocked”
This always requires a comment explaining why the issue is blocked.
User Experience
Comment Modal Features
All comment modals share these features:
1. Comment Input
- Character Limit: 250 characters (with live counter)
- Mentions: Support for @mentions of team members
- Type
@to trigger user suggestions - Suggestions filter as you type
- Selected users receive notifications
- Type
- Multiline: Supports multiple lines of text
- Placeholder: “Enter resolution details”
2. Attachment Support
Attachment Types:
- 📷 Photos: JPEG, JPG, PNG, GIF
- 🎥 Videos: MP4, AVI, MKV, MOV
- 📄 Documents: PDF and other document types
Attachment Sources:
- Camera (with watermark option)
- Photo Gallery
- Document Picker
- Video Recorder
Attachment Limits:
- Minimum: 0 (optional) or 1 (required based on settings)
- Maximum: 10 attachments
- File size: Individual file size limits enforced
File Information Display:
- Supported file size and formats shown in info box
- Max size details
- Supported image types
- Supported document types
- Supported video types
3. Validation & Feedback
Submit Button States:
The submit button is disabled when:
// Disabled if:
!(
(!requireComment || comment?.length > 0) && // Comment check
(!requireAttachment || refercenceKeys.length > 0) && // Attachment check
!issueAttachMentUploading && // Upload in progress
!isLoading // Request in progress
)Error Messages:
- If attachment required but missing: “At least one attachment is required” (shown in red)
- Upload failures: Error toast notification
Loading States:
- Attachment upload: Individual file upload progress
- Form submission: “Submitting…” button text
4. Workflow Example
Scenario: Organization requires comment + 1 attachment
- User clicks “Resolve This Issue”
- Alert confirms: “Are you sure you want to resolve this issue?”
- User clicks “Resolve”
- Modal opens: “Resolve Issue”
- Subtitle: “Please provide details about the resolution.”
- User types comment: “Fixed by replacing faulty component”
- Submit button still disabled (no attachment)
- Error message: “At least one attachment is required”
- User clicks “Add Photo” → Takes photo from camera
- Photo uploads and thumbnail appears
- Submit button becomes enabled
- User clicks “Submit”
- Comment is created with attachment
- Issue status changes to “Resolved”
- NPS survey triggers (if configured)
- Modal closes, success confirmation
Technical Architecture
Core Hook: useIssueResolutionRequirements
File: packages/app/features/issues/hooks/use-issue-resolution-requirements.ts
This hook centralizes the logic for determining resolution requirements:
export interface IssueResolutionRequirements {
/** Whether to show comment modal when resolving issues */
showCommentModal: boolean
/** Whether comment is required when resolving issues */
requireComment: boolean
/** Whether at least one attachment is required when resolving issues */
requireAttachment: boolean
}Usage Example:
const { showCommentModal, requireComment, requireAttachment } = useIssueResolutionRequirements()
// Check if modal should be shown
if (showCommentModal) {
setShowCommentSheet(true)
}
// Validate form
const canSubmit =
(!requireComment || comment.length > 0) && (!requireAttachment || attachments.length > 0)Component Architecture
Quick Resolve Components
- Modal:
QuickResolveComment- Main comment modal for quick resolve - Attachments:
QuickResolveCommentAttachments- Attachment picker/manager - State Atoms:
quickResolveMessageSheetAtom- Modal open statequickResolveCommentAtom- Comment textquickResolveCommentAttachment- Attachment dataquickResolveCommentAttachmentUpload- Upload statusquickResolveCommentAttachmentReferenceKeys- Storage references
Issue Resolved Components
- Modal:
IssueResolvedComment- Comment modal for status change - Attachments:
IssueResolvedCommentAttachments - State Atoms:
issueResolvedMessageSheetAtomissueResolvedCommentAtomissueResolvedCommentAttachmentissueResolvedCommentAttachmentUploadissueResolvedCommentAttachmentReferenceKeys
Bulk Resolve Components
- Modal:
BulkResolvedComment- Comment modal for bulk operations - Attachments:
BulkResolvedCommentAttachments - State Atoms:
bulkResolvedCommentSheetAtombulkResolvedCommentAtombulkResolvedCommentAttachmentAtombulkResolvedCommentAttachmentUploadAtombulkResolvedCommentAttachmentReferenceKeysAtombulkEditIssueIdsAtom- List of issue IDs
State Management
Atoms Location: packages/app/features/issues/details/controllers/details-screen-controller.ts and packages/app/features/issues/controllers/bulk-edit-controller.ts
All modals use Jotai atoms for state management, ensuring:
- Component isolation
- State persistence during navigation
- Clean reset on modal close
API Integration
1. Create Message API
Mutation: useCreateIssueMessage / useBulkCreateIssueMessage
Creates a comment message with attachments:
await createMessage({
issueId: selectedIssue?.issueID,
createdAt: dayjs().format(),
createdBy: user?.data?.userID || "",
createdByName: user?.data?.displayName || "",
message: comment,
messageType: "comment",
attachments: refercenceKeys || [],
// ... other fields
})2. Resolve Issue API
Mutation: useQuickResolveIssue / useUpdateIssueMutation
Updates issue status to resolved:
await quickResolveIssue({
issueID: selectedIssue.issueID,
resolvedBy: authedUserId || "",
triggerNotification: true,
})3. Attachment Upload
Hook: useUploadFileAttachment
Handles file uploads with:
- Retry logic on failure
- Upload progress tracking
- File validation
- Reference key generation
Upload Status:
enum UPLOAD_STATUS {
PENDING = "pending",
UPLOADING = "uploading",
COMPLETED = "completed",
FAILED = "failed",
}Attachment Upload Flow
- User selects file (camera/gallery/document)
- File is converted to
UploadFileIobject - Added to attachments state via
addAttachments([file]) - Upload begins automatically
- Status tracked:
PENDING → UPLOADING → COMPLETED - On completion: Reference key generated and stored
- Submit button enables when all uploads complete
- On submit: Reference keys sent to API
Localization Support
The feature supports 7 languages with full translations:
Supported Languages
| Language | Code | Locale File |
|---|---|---|
| English | en | en/issues/issues.ts |
| Spanish | es | es/issues/issues.ts |
| Indonesian | id | id/issues/issues.ts |
| Khmer | km | km/issues/issues.ts |
| Korean | ko | ko/issues/issues.ts |
| Portuguese | pt | pt/issues/issues.ts |
| Thai | th | th/issues/issues.ts |
Key Translation Strings
Namespace: LL.issue.issues.issueResolvedComment
issueResolvedComment: {
title: 'Resolve Issue',
subtitle: 'Please provide details about the resolution.',
placeholder: 'Enter resolution details',
submit: 'Submit',
submitting: 'Submitting',
attachmentRequired: 'At least one attachment is required',
attachmentOptional: 'Attachments (optional)',
attachmentRequiredLabel: 'Attachments (min. 1 required)',
attachmentInfo: 'Add at least 1 attachment (max. 10)',
attachmentInfoOptional: 'Add maximum 10 attachments (optional)',
}Example Translations
English:
“At least one attachment is required”
Spanish:
“Se requiere al menos un archivo adjunto”
Korean:
“최소 하나의 첨부 파일이 필요합니다”
Thai:
“ต้องมีไฟล์แนบอย่างน้อย 1 ไฟล์”
Code References
Primary Files
| File | Purpose |
|---|---|
| use-issue-resolution-requirements.ts | Core hook for settings logic |
| quick-resolve-issue.tsx | Quick resolve button trigger |
| quick-resolve-comment.tsx | Quick resolve modal |
| quick-resolve-comment-attachment.tsx | Quick resolve attachments |
| issue-status.tsx | Status dropdown trigger |
| issue-resolved-comment.tsx | Status change modal |
| issue-resolved-comment-attachment.tsx | Status change attachments |
| bulkEdit.tsx | Bulk edit trigger |
| bulk-resolved-comment.tsx | Bulk resolve modal |
| bulk-resolved-comment-attachment.tsx | Bulk resolve attachments |
| issue-tracker-settings-extended.ts | Settings type definitions |
Testing Files
| File | Coverage |
|---|---|
| issue-status.test.tsx | Status component tests |
| issue-block-comment.test.tsx | Block comment tests |
| issue-comment-attachments.test.tsx | Attachment component tests |
Related Features
- NPS Triggering: After successful resolution, NPS survey is triggered
- Notifications: Team members mentioned in comments receive notifications
- Issue History: Comments and attachments appear in issue activity timeline
- Offline Support: Comments and attachments queued when offline
Summary
This feature provides a comprehensive solution for enforcing documentation standards when resolving issues. With flexible configuration options, organizations can:
✅ Require explanatory comments ✅ Mandate supporting documentation via attachments ✅ Ensure accountability and traceability ✅ Build a knowledge base of resolutions
The implementation is:
- Consistent: Same experience across 4 different trigger points
- Flexible: Three configuration modes to fit organizational needs
- User-Friendly: Clear validation messages and intuitive UI
- Localized: Support for 7 languages
- Robust: Retry logic, upload tracking, and error handling
Last Updated: October 6, 2025 Version: 2.11.17 Related PR: #982 - Add mandatory comment with attachments when resolving issues