The frontend component of PuffPastry, meant to interface with the backend, which in turn interfaces with the smart contract.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. ---
  2. sessionId: session-261005-172001-12ux
  3. ---
  4. # Requirements
  5. ### Overview & Goals
  6. The objective is to maximize user engagement and utility by introducing an inline "Add Comment" area within `ProposalDetail.vue`. By enabling direct inline commenting without modal disruptions, users can effortlessly discuss and provide feedback on governance proposals, reducing interaction friction and streamlining the feedback loop.
  7. ### Scope
  8. - **In Scope**:
  9. - Embedding an inline comment input area (textarea and action controls) directly inside the Comments section of `src/components/ProposalDetail.vue`.
  10. - Integrating `CommentService.addComment` from `src/generated/typescript/services/CommentService.ts` to submit comments.
  11. - Form validation (preventing empty/whitespace submissions) and loading/error states.
  12. - Refreshing or updating the comment stream upon successful submission.
  13. - Accessible styling consistent with Tailwind CSS guidelines and the existing proposal layout.
  14. - **Out of Scope**:
  15. - Modal-based comment workflows (explicitly avoided per task specification).
  16. - Editing, deleting, or nesting/threading multi-level comments in this phase.
  17. - Backend schema or API endpoint modifications.
  18. ### User Stories
  19. - **As a stakeholder**, I want to post feedback directly beneath a proposal so that I can contribute to the discussion with minimal friction and no context-switching modals.
  20. - **As a user**, I want visual feedback while my comment is being submitted (e.g., loading state, error alert on failure) so that I know the exact status of my action.
  21. - **As a keyboard user**, I want full keyboard accessibility (tab navigation, clear focus states) so that I can participate efficiently without relying solely on mouse input.
  22. ### Functional Requirements
  23. - **Inline Input Form**:
  24. - A clean, expandable textarea with placeholder text (e.g., "Add to the discussion...") rendered directly within the `<section aria-labelledby="comments-heading">` block.
  25. - An "Add Comment" (or "Post Comment") submit button and optional "Cancel" / "Clear" button.
  26. - **Validation & Form State**:
  27. - Disable the submit button when the textarea is empty, whitespace-only, or while a submission is in flight.
  28. - Display clear error messaging if the network or API call fails.
  29. - **API Dispatch**:
  30. - Construct an `AddCommentRequest` with `proposalId`, `content`, and active/fallback `userId`.
  31. - Invoke `CommentService.addComment(requestBody)`.
  32. - On success, reset the input field and update the comment list so the new comment appears immediately.
  33. ### Non-Functional Requirements
  34. - **Usability & Utility**: Minimal layout shift; smooth transition between idle, submitting, and submitted states.
  35. - **Design Consistency**: Match the Tailwind CSS design language (slate borders, amber accents, clear typography) of `ProposalDetail.vue` and `NewAmendmentModal.vue`.
  36. - **Accessibility**: Semantic HTML `<form>`, `<textarea>`, `<button>`, `<label>` with associated ARIA attributes for screen readers.
  37. # Technical Design
  38. ### Current Implementation
  39. - `src/components/ProposalDetail.vue`: Renders proposal details, amendments via `AmendmentCarousel.vue`, and voting cards. The comments section currently contains static markup with a hidden placeholder (`v-if="false"`).
  40. - `src/generated/typescript/services/CommentService.ts`: Exports `CommentService` with:
  41. - `addComment(requestBody: AddCommentRequest): CancelablePromise<SelectableComment>` (`POST /api/v1/comment/add`)
  42. - `listComments(proposalId: number): CancelablePromise<Array<CommentWithUser>>` (`GET /api/v1/comments/list`)
  43. - `src/generated/typescript/models/AddCommentRequest.ts`: Defines `{ content: string; proposalId: number; userId: number; }`.
  44. - `src/generated/typescript/models/CommentWithUser.ts`: Defines comment shape with author metadata (`id`, `content`, `createdAt`, `username`, `fullName`, `userId`, `proposalId`).
  45. ### Key Decisions
  46. 1. **Inline Placement in ProposalDetail.vue**:
  47. - *Approach*: Integrate the comment box directly below the comments header in `ProposalDetail.vue` instead of launching a modal.
  48. - *Rationale*: Maximizes utility and minimizes UX friction by keeping the proposal text in view while writing feedback.
  49. 2. **Dynamic Comments Fetch & Immediate Refresh**:
  50. - *Approach*: Load comments for `proposal.id` via `CommentService.listComments` and refresh/append on new comment creation.
  51. - *Rationale*: Provides immediate confirmation to the user that their contribution was recorded without necessitating a full page reload.
  52. 3. **Robust Input Validation & Loading States**:
  53. - *Approach*: Use reactive refs (`commentText`, `isSubmitting`, `errorMessage`) to gate form submission and provide actionable feedback.
  54. - *Rationale*: Prevents accidental duplicate requests and ensures users are informed of network or validation issues.
  55. ### Proposed Changes
  56. - **`src/components/ProposalDetail.vue`**:
  57. - Import `CommentService`, `AddCommentRequest`, and `CommentWithUser` from `../generated/typescript`.
  58. - Add reactive state: `newComment`, `isSubmitting`, `submitError`, `comments`, and `loadingComments`.
  59. - Implement `fetchComments(proposalId)` on `onMounted` and on `watch(proposalId)`.
  60. - Implement `handleAddComment()` to call `CommentService.addComment` and reset the form.
  61. - Replace placeholder section with the inline comment submission form and existing comments list.
  62. ### Data Models / Contracts
  63. ```typescript
  64. // Payload sent to CommentService.addComment
  65. const requestBody: AddCommentRequest = {
  66. proposalId: props.proposal.id,
  67. content: commentText.value.trim(),
  68. userId: activeUserId ?? 1, // Fallback/resolved user ID
  69. };
  70. ```
  71. ### Architecture Diagram
  72. ```mermaid
  73. graph TD
  74. User[User] -->|Types comment & clicks Submit| CommentForm[Inline Comment Area in ProposalDetail]
  75. CommentForm -->|addComment| CommentService[CommentService.addComment]
  76. CommentService -->|POST /api/v1/comment/add| BackendAPI[Backend API]
  77. BackendAPI -->|SelectableComment| CommentService
  78. CommentService -->|Success / New Comment| StateUpdate[Update Local Comments State & Reset Form]
  79. StateUpdate -->|Re-render| UI[Updated Discussion Stream]
  80. ```
  81. ### File Structure
  82. - `src/components/ProposalDetail.vue` (Modified): Inline form, reactive state, and `CommentService` integration.
  83. - `src/generated/typescript/services/CommentService.ts` (Referenced): Backend API client for comment actions.
  84. ### Risks & Mitigations
  85. - **Network Failure or 400/500 Errors**: Capture API errors in a dedicated `errorMessage` ref and display an inline alert without losing user input.
  86. - **Double Submissions**: Disable the submit button immediately when `isSubmitting` is true.
  87. # Testing
  88. ### Validation Approach
  89. Verification focuses on maximizing automated and interactive confidence across normal, boundary, and error conditions.
  90. ### Key Scenarios
  91. 1. **Inline Form Rendering**:
  92. - Verify textarea and "Add Comment" button render cleanly within the comments section of `ProposalDetail.vue`.
  93. - Verify placeholder text and accessible labels are present.
  94. 2. **Comment Submission Flow**:
  95. - Enter valid comment text and submit.
  96. - Verify `CommentService.addComment` is invoked with `{ proposalId, content, userId }`.
  97. - Verify textarea is cleared upon successful submission and the discussion stream updates.
  98. 3. **Empty Input Prevention**:
  99. - Ensure the submit button is disabled when the textarea is empty or contains only whitespace.
  100. 4. **Loading & Disabled States**:
  101. - Verify the submit button reflects pending state and prevents concurrent submissions.
  102. ### Edge Cases
  103. - **API Error / Server Failure**: Verify that error messages are displayed prominently inline without clearing the user's drafted text.
  104. - **Proposal ID Changes**: Verify comments state is reset and re-fetched when switching between proposals.
  105. - **Special Characters & Multiline Text**: Verify formatting and line breaks in comments are preserved.
  106. # Delivery Steps
  107. ### ✓ Step 1: Create inline comment form UI and state management
  108. Build the inline comment form UI within the Comments section of `ProposalDetail.vue`.
  109. - Add reactive state variables for comment content (`commentText`), submission loading state (`isSubmitting`), error messages (`commentError`), and comments list (`comments`, `isLoadingComments`).
  110. - Insert an inline form in the comments section with a styled `<textarea>` input, accessible labels, character/input guidance, and action controls (submit and cancel/reset buttons).
  111. - Implement input validation so that empty or whitespace-only submissions are disabled.
  112. - Add comment list rendering within the comments section using `CommentService.listComments(proposal.id)` on mount and when proposal changes, providing immediate visual feedback for existing discussions.
  113. ### ✓ Step 2: Integrate CommentService API submission and discussion refresh
  114. Connect the inline form to `CommentService.addComment` to persist user comments and refresh the discussion stream.
  115. - Implement the `submitComment` async handler calling `CommentService.addComment({ proposalId: proposal.id, content: commentText.value.trim(), userId })`.
  116. - Include robust error handling to display user-friendly inline error alerts if the API request fails.
  117. - Clear the input textarea upon successful comment submission.
  118. - Re-fetch or append the new comment into the local comments list so users immediately see their contribution without a full page reload.
  119. - Verify type checks and build via `vue-tsc -b` to guarantee seamless integration and zero regressions.