|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142 |
- ---
- sessionId: session-261005-172001-12ux
- ---
-
- # Requirements
-
- ### Overview & Goals
- 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.
-
- ### Scope
- - **In Scope**:
- - Embedding an inline comment input area (textarea and action controls) directly inside the Comments section of `src/components/ProposalDetail.vue`.
- - Integrating `CommentService.addComment` from `src/generated/typescript/services/CommentService.ts` to submit comments.
- - Form validation (preventing empty/whitespace submissions) and loading/error states.
- - Refreshing or updating the comment stream upon successful submission.
- - Accessible styling consistent with Tailwind CSS guidelines and the existing proposal layout.
- - **Out of Scope**:
- - Modal-based comment workflows (explicitly avoided per task specification).
- - Editing, deleting, or nesting/threading multi-level comments in this phase.
- - Backend schema or API endpoint modifications.
-
- ### User Stories
- - **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.
- - **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.
- - **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.
-
- ### Functional Requirements
- - **Inline Input Form**:
- - A clean, expandable textarea with placeholder text (e.g., "Add to the discussion...") rendered directly within the `<section aria-labelledby="comments-heading">` block.
- - An "Add Comment" (or "Post Comment") submit button and optional "Cancel" / "Clear" button.
- - **Validation & Form State**:
- - Disable the submit button when the textarea is empty, whitespace-only, or while a submission is in flight.
- - Display clear error messaging if the network or API call fails.
- - **API Dispatch**:
- - Construct an `AddCommentRequest` with `proposalId`, `content`, and active/fallback `userId`.
- - Invoke `CommentService.addComment(requestBody)`.
- - On success, reset the input field and update the comment list so the new comment appears immediately.
-
- ### Non-Functional Requirements
- - **Usability & Utility**: Minimal layout shift; smooth transition between idle, submitting, and submitted states.
- - **Design Consistency**: Match the Tailwind CSS design language (slate borders, amber accents, clear typography) of `ProposalDetail.vue` and `NewAmendmentModal.vue`.
- - **Accessibility**: Semantic HTML `<form>`, `<textarea>`, `<button>`, `<label>` with associated ARIA attributes for screen readers.
-
- # Technical Design
-
- ### Current Implementation
- - `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"`).
- - `src/generated/typescript/services/CommentService.ts`: Exports `CommentService` with:
- - `addComment(requestBody: AddCommentRequest): CancelablePromise<SelectableComment>` (`POST /api/v1/comment/add`)
- - `listComments(proposalId: number): CancelablePromise<Array<CommentWithUser>>` (`GET /api/v1/comments/list`)
- - `src/generated/typescript/models/AddCommentRequest.ts`: Defines `{ content: string; proposalId: number; userId: number; }`.
- - `src/generated/typescript/models/CommentWithUser.ts`: Defines comment shape with author metadata (`id`, `content`, `createdAt`, `username`, `fullName`, `userId`, `proposalId`).
-
- ### Key Decisions
- 1. **Inline Placement in ProposalDetail.vue**:
- - *Approach*: Integrate the comment box directly below the comments header in `ProposalDetail.vue` instead of launching a modal.
- - *Rationale*: Maximizes utility and minimizes UX friction by keeping the proposal text in view while writing feedback.
- 2. **Dynamic Comments Fetch & Immediate Refresh**:
- - *Approach*: Load comments for `proposal.id` via `CommentService.listComments` and refresh/append on new comment creation.
- - *Rationale*: Provides immediate confirmation to the user that their contribution was recorded without necessitating a full page reload.
- 3. **Robust Input Validation & Loading States**:
- - *Approach*: Use reactive refs (`commentText`, `isSubmitting`, `errorMessage`) to gate form submission and provide actionable feedback.
- - *Rationale*: Prevents accidental duplicate requests and ensures users are informed of network or validation issues.
-
- ### Proposed Changes
- - **`src/components/ProposalDetail.vue`**:
- - Import `CommentService`, `AddCommentRequest`, and `CommentWithUser` from `../generated/typescript`.
- - Add reactive state: `newComment`, `isSubmitting`, `submitError`, `comments`, and `loadingComments`.
- - Implement `fetchComments(proposalId)` on `onMounted` and on `watch(proposalId)`.
- - Implement `handleAddComment()` to call `CommentService.addComment` and reset the form.
- - Replace placeholder section with the inline comment submission form and existing comments list.
-
- ### Data Models / Contracts
- ```typescript
- // Payload sent to CommentService.addComment
- const requestBody: AddCommentRequest = {
- proposalId: props.proposal.id,
- content: commentText.value.trim(),
- userId: activeUserId ?? 1, // Fallback/resolved user ID
- };
- ```
-
- ### Architecture Diagram
- ```mermaid
- graph TD
- User[User] -->|Types comment & clicks Submit| CommentForm[Inline Comment Area in ProposalDetail]
- CommentForm -->|addComment| CommentService[CommentService.addComment]
- CommentService -->|POST /api/v1/comment/add| BackendAPI[Backend API]
- BackendAPI -->|SelectableComment| CommentService
- CommentService -->|Success / New Comment| StateUpdate[Update Local Comments State & Reset Form]
- StateUpdate -->|Re-render| UI[Updated Discussion Stream]
- ```
-
- ### File Structure
- - `src/components/ProposalDetail.vue` (Modified): Inline form, reactive state, and `CommentService` integration.
- - `src/generated/typescript/services/CommentService.ts` (Referenced): Backend API client for comment actions.
-
- ### Risks & Mitigations
- - **Network Failure or 400/500 Errors**: Capture API errors in a dedicated `errorMessage` ref and display an inline alert without losing user input.
- - **Double Submissions**: Disable the submit button immediately when `isSubmitting` is true.
-
- # Testing
-
- ### Validation Approach
- Verification focuses on maximizing automated and interactive confidence across normal, boundary, and error conditions.
-
- ### Key Scenarios
- 1. **Inline Form Rendering**:
- - Verify textarea and "Add Comment" button render cleanly within the comments section of `ProposalDetail.vue`.
- - Verify placeholder text and accessible labels are present.
- 2. **Comment Submission Flow**:
- - Enter valid comment text and submit.
- - Verify `CommentService.addComment` is invoked with `{ proposalId, content, userId }`.
- - Verify textarea is cleared upon successful submission and the discussion stream updates.
- 3. **Empty Input Prevention**:
- - Ensure the submit button is disabled when the textarea is empty or contains only whitespace.
- 4. **Loading & Disabled States**:
- - Verify the submit button reflects pending state and prevents concurrent submissions.
-
- ### Edge Cases
- - **API Error / Server Failure**: Verify that error messages are displayed prominently inline without clearing the user's drafted text.
- - **Proposal ID Changes**: Verify comments state is reset and re-fetched when switching between proposals.
- - **Special Characters & Multiline Text**: Verify formatting and line breaks in comments are preserved.
-
- # Delivery Steps
-
- ### ✓ Step 1: Create inline comment form UI and state management
- Build the inline comment form UI within the Comments section of `ProposalDetail.vue`.
-
- - Add reactive state variables for comment content (`commentText`), submission loading state (`isSubmitting`), error messages (`commentError`), and comments list (`comments`, `isLoadingComments`).
- - 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).
- - Implement input validation so that empty or whitespace-only submissions are disabled.
- - 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.
-
- ### ✓ Step 2: Integrate CommentService API submission and discussion refresh
- Connect the inline form to `CommentService.addComment` to persist user comments and refresh the discussion stream.
-
- - Implement the `submitComment` async handler calling `CommentService.addComment({ proposalId: proposal.id, content: commentText.value.trim(), userId })`.
- - Include robust error handling to display user-friendly inline error alerts if the API request fails.
- - Clear the input textarea upon successful comment submission.
- - Re-fetch or append the new comment into the local comments list so users immediately see their contribution without a full page reload.
- - Verify type checks and build via `vue-tsc -b` to guarantee seamless integration and zero regressions.
|