|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134 |
- ---
- sessionId: session-261002-164508-dfif
- ---
-
- # Requirements
-
- ### Overview & Goals
- The objective of this task is to convert the placeholder `Add` element in `AmendmentCarousel.vue` into a fully styled, accessible "dummy" amendment card. Clicking this card launches a new amendment creation modal, allowing users to propose an amendment to the currently viewed proposal using their connected Stellar Freighter wallet.
-
- ### Scope
- - **In Scope**:
- - Transforming the existing placeholder `<article>` in `src/components/AmendmentCarousel.vue` into an attractive, interactive dummy amendment card.
- - Creating `src/components/modals/NewAmendmentModal.vue` to capture amendment details (name/title and markdown content).
- - Integrating `AmendmentService.addAmendment` with wallet authorization via `@stellar/freighter-api`.
- - Refreshing the amendment list in `AmendmentCarousel.vue` upon successful submission.
- - Supporting full keyboard navigation and accessible roles for the dummy amendment trigger.
- - **Out of Scope**:
- - Modifying backend API endpoints or database schemas (already provided via `AmendmentService`).
- - Changing voting or confirm/reject approval flows for amendments.
-
- ### User Stories
- - **As a contributor**, I want to click an "Add Amendment" card in the carousel so that I can easily propose a revision to the current proposal.
- - **As a keyboard user**, I want to focus and activate the "Add Amendment" card with Enter or Space so that the interface is fully accessible.
- - **As a proposer**, I want a clean modal form to enter the amendment title and body and sign with my wallet so that my submission is properly recorded.
-
- ### Functional Requirements
- - **Card UI & Styling**: The dummy card must match the carousel dimensions (`w-36 md:w-72 lg:w-80 shrink-0`) with styling indicating an actionable create card (e.g. dashed border, centered plus icon, clear typography, and subtle hover animations).
- - **Modal Triggering**: Clicking or pressing Enter/Space on the dummy card must open the `NewAmendmentModal` via `useModal().show()`.
- - **Form Submission**:
- - The modal must contain inputs for Amendment Name (`name`) and Amendment Description/Content (`content`).
- - Submit button must be disabled until required fields are filled.
- - On submit, fetch wallet address from `@stellar/freighter-api` and invoke `AmendmentService.addAmendment({ proposalId, creator, name, content })`.
- - **Carousel Refresh**: Once submitted successfully, the modal closes and the amendment carousel automatically reloads its list to display the newly proposed amendment.
-
- ### Non-Functional Requirements
- - **Consistency**: Visual style must align with the existing Tailwind palette (slate/amber/neutral tones) used in `ProposalDetail.vue` and `ProposalModal.vue`.
- - **Accessibility**: Provide proper `role="button"`, `tabindex="0"`, `aria-label`, and keyboard event handlers.
-
- # Technical Design
-
- ### Current Implementation
- - `src/components/AmendmentCarousel.vue`: Renders existing amendments using horizontal scroll. Currently ends with a raw placeholder `<article class="...">Add</article>`.
- - `src/components/modals/Modal.vue`: Base dialog component with backdrop, keyboard listeners (Esc), headers, and action buttons.
- - `src/components/modals/ProposalModal.vue`: Example creation modal utilizing `Modal.vue`, `PostBuilder.vue`, `freighter-api`, and `useModal`.
- - `src/composables/useModal.ts`: Controls active modal visibility and dynamic content via `show(component)` and `hide()`.
- - `src/generated/typescript/services/AmendmentService.ts`: Provides `addAmendment(requestBody: AddAmendmentRequest)` and `listAmendments(proposalId)`.
-
- ### Key Decisions
- 1. **Dedicated `NewAmendmentModal.vue` Component**:
- - *Approach*: Create a new modal component specifically for adding amendments rather than overloading the read-only `AmendmentModal.vue`.
- - *Rationale*: Keeps concerns separated—`AmendmentModal` focuses on inspecting existing amendments while `NewAmendmentModal` handles form inputs, validation, and wallet signing.
- 2. **Context & Refresh Communication**:
- - *Approach*: Pass proposal context to the modal and utilize an event emitter or bus notification (`eventBus` or direct callback) upon submission to trigger `getAmendments()` in `AmendmentCarousel.vue`.
- - *Rationale*: Avoids full page reload and keeps the carousel responsive.
- 3. **Card Presentation**:
- - *Approach*: Render the dummy card at the end of the carousel item list with dashed border (`border-2 border-dashed border-slate-300 hover:border-amber-400`), a plus icon from `src/components/icons/Plus.vue`, and descriptive text.
- - *Rationale*: Makes it instantly recognizable as an action card while preserving the flow and scroll snapping of the carousel.
-
- ### Proposed Changes
- - **`src/components/modals/NewAmendmentModal.vue`** (New File):
- - Form layout with `name` input and `PostBuilder` (or markdown content area).
- - Validation ensuring `name.trim().length > 0` and content presence.
- - Submission handler calling `AmendmentService.addAmendment(...)` with Freighter address.
- - Emits `created` event or publishes to `eventBus`.
- - **`src/components/AmendmentCarousel.vue`** (Modified):
- - Replace raw `Add` article with styled card component.
- - Add `openNewAmendmentModal` handler invoking `show(NewAmendmentModal)`.
- - Listen for amendment creation events to trigger `getAmendments()`.
-
- ### Architecture Diagram
- ```mermaid
- graph LR
- User[User] -->|Click / Keyboard| DummyCard[Dummy Card in Carousel]
- DummyCard -->|useModal.show| NewModal[NewAmendmentModal]
- NewModal -->|Sign & Submit| Freighter[Stellar Freighter Wallet]
- NewModal -->|addAmendment| Backend[AmendmentService API]
- Backend -->|Success| Refresh[Refresh Carousel]
- ```
-
- ### File Structure & Changes
- - `src/components/modals/NewAmendmentModal.vue`: New creation modal component.
- - `src/components/AmendmentCarousel.vue`: Updated dummy card markup, styling, and modal invocation.
- - `src/composables/useModal.ts` (if needed): Context helpers for active proposal ID.
-
- # Testing
-
- ### Validation Approach
- Verify the feature through interactive testing and automated checks:
- - Verify that the dummy card renders correctly within the carousel at different viewport sizes (mobile, tablet, desktop).
- - Verify keyboard interactions (Tab navigation, Enter, Space keys) trigger the modal.
- - Verify modal form validation (disabling submission on empty fields).
- - Verify successful API submission payload structure and carousel refresh.
-
- ### Key Scenarios
- 1. **Card Rendering & Styling**:
- - Dummy card appears at the end of the amendments carousel.
- - Styles match design requirements (dashed border, centered icon, hover transitions).
- 2. **Opening the Modal**:
- - Clicking the card opens `NewAmendmentModal`.
- - Pressing Enter or Space when focused on the card opens `NewAmendmentModal`.
- 3. **Submitting New Amendment**:
- - Fill in amendment title and body.
- - Click "Submit Amendment" -> triggers Freighter authorization and calls `AmendmentService.addAmendment`.
- - Modal closes automatically and the new amendment appears in the carousel list.
-
- ### Edge Cases
- - **No Wallet Connected / Rejected Signing**: Display appropriate feedback if Freighter rejects connection or signing fails.
- - **Empty or Whitespace-only Inputs**: Ensure submit button remains disabled until valid name and content are provided.
- - **Carousel Scroll Recalculation**: Ensure `updateEdges()` executes after adding an amendment to update left/right navigation arrows.
-
- # Delivery Steps
-
- ### ✓ Step 1: Create NewAmendmentModal component
- A dedicated `NewAmendmentModal.vue` component is created and integrated with the modal system.
-
- - Create `src/components/modals/NewAmendmentModal.vue` utilizing `<Modal>` for the dialog container.
- - Implement title input with validation (`name`), content editor (using `PostBuilder` or markdown input), and submit action.
- - Integrate with `@stellar/freighter-api` to retrieve the signer address and `AmendmentService.addAmendment` to dispatch the proposal amendment.
- - Add error handling, loading state during submission, and automated modal dismissal on success.
-
- ### ✓ Step 2: Implement and style the dummy amendment card in AmendmentCarousel
- The carousel placeholder is replaced with a styled, accessible "Add Amendment" dummy card that opens the modal.
-
- - Update the dummy `<article>` in `src/components/AmendmentCarousel.vue` to match carousel card dimensions (`w-36 md:w-72 lg:w-80`) with dashed border and hover effects (`border-2 border-dashed border-slate-300 hover:border-amber-400 bg-slate-50/50 hover:bg-amber-50/60`).
- - Embed the `Plus` icon (`src/components/icons/Plus.vue`), title ("Add Amendment"), and descriptive helper text.
- - Add keyboard accessibility (`role="button"`, `tabindex="0"`, Enter/Space handlers) and click handler calling `useModal().show(NewAmendmentModal)`.
- - Pass current `proposalId` context to the modal so new amendments are attached to the active proposal.
-
- ### ✓ Step 3: Wire submission refresh and carousel reactivity
- Amendment creation triggers carousel list reload and seamlessly updates the UI.
-
- - Emit an event or trigger `getAmendments()` in `AmendmentCarousel.vue` upon successful amendment submission.
- - Ensure the newly added amendment appears in the carousel without requiring a full page refresh.
- - Verify scrolling edge calculations (`updateEdges()`) update after new amendment addition.
|