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.

add-amendment-carousel-card.md 9.2 KiB

​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. ---
  2. sessionId: session-261002-164508-dfif
  3. ---
  4. # Requirements
  5. ### Overview & Goals
  6. 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.
  7. ### Scope
  8. - **In Scope**:
  9. - Transforming the existing placeholder `<article>` in `src/components/AmendmentCarousel.vue` into an attractive, interactive dummy amendment card.
  10. - Creating `src/components/modals/NewAmendmentModal.vue` to capture amendment details (name/title and markdown content).
  11. - Integrating `AmendmentService.addAmendment` with wallet authorization via `@stellar/freighter-api`.
  12. - Refreshing the amendment list in `AmendmentCarousel.vue` upon successful submission.
  13. - Supporting full keyboard navigation and accessible roles for the dummy amendment trigger.
  14. - **Out of Scope**:
  15. - Modifying backend API endpoints or database schemas (already provided via `AmendmentService`).
  16. - Changing voting or confirm/reject approval flows for amendments.
  17. ### User Stories
  18. - **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.
  19. - **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.
  20. - **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.
  21. ### Functional Requirements
  22. - **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).
  23. - **Modal Triggering**: Clicking or pressing Enter/Space on the dummy card must open the `NewAmendmentModal` via `useModal().show()`.
  24. - **Form Submission**:
  25. - The modal must contain inputs for Amendment Name (`name`) and Amendment Description/Content (`content`).
  26. - Submit button must be disabled until required fields are filled.
  27. - On submit, fetch wallet address from `@stellar/freighter-api` and invoke `AmendmentService.addAmendment({ proposalId, creator, name, content })`.
  28. - **Carousel Refresh**: Once submitted successfully, the modal closes and the amendment carousel automatically reloads its list to display the newly proposed amendment.
  29. ### Non-Functional Requirements
  30. - **Consistency**: Visual style must align with the existing Tailwind palette (slate/amber/neutral tones) used in `ProposalDetail.vue` and `ProposalModal.vue`.
  31. - **Accessibility**: Provide proper `role="button"`, `tabindex="0"`, `aria-label`, and keyboard event handlers.
  32. # Technical Design
  33. ### Current Implementation
  34. - `src/components/AmendmentCarousel.vue`: Renders existing amendments using horizontal scroll. Currently ends with a raw placeholder `<article class="...">Add</article>`.
  35. - `src/components/modals/Modal.vue`: Base dialog component with backdrop, keyboard listeners (Esc), headers, and action buttons.
  36. - `src/components/modals/ProposalModal.vue`: Example creation modal utilizing `Modal.vue`, `PostBuilder.vue`, `freighter-api`, and `useModal`.
  37. - `src/composables/useModal.ts`: Controls active modal visibility and dynamic content via `show(component)` and `hide()`.
  38. - `src/generated/typescript/services/AmendmentService.ts`: Provides `addAmendment(requestBody: AddAmendmentRequest)` and `listAmendments(proposalId)`.
  39. ### Key Decisions
  40. 1. **Dedicated `NewAmendmentModal.vue` Component**:
  41. - *Approach*: Create a new modal component specifically for adding amendments rather than overloading the read-only `AmendmentModal.vue`.
  42. - *Rationale*: Keeps concerns separated—`AmendmentModal` focuses on inspecting existing amendments while `NewAmendmentModal` handles form inputs, validation, and wallet signing.
  43. 2. **Context & Refresh Communication**:
  44. - *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`.
  45. - *Rationale*: Avoids full page reload and keeps the carousel responsive.
  46. 3. **Card Presentation**:
  47. - *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.
  48. - *Rationale*: Makes it instantly recognizable as an action card while preserving the flow and scroll snapping of the carousel.
  49. ### Proposed Changes
  50. - **`src/components/modals/NewAmendmentModal.vue`** (New File):
  51. - Form layout with `name` input and `PostBuilder` (or markdown content area).
  52. - Validation ensuring `name.trim().length > 0` and content presence.
  53. - Submission handler calling `AmendmentService.addAmendment(...)` with Freighter address.
  54. - Emits `created` event or publishes to `eventBus`.
  55. - **`src/components/AmendmentCarousel.vue`** (Modified):
  56. - Replace raw `Add` article with styled card component.
  57. - Add `openNewAmendmentModal` handler invoking `show(NewAmendmentModal)`.
  58. - Listen for amendment creation events to trigger `getAmendments()`.
  59. ### Architecture Diagram
  60. ```mermaid
  61. graph LR
  62. User[User] -->|Click / Keyboard| DummyCard[Dummy Card in Carousel]
  63. DummyCard -->|useModal.show| NewModal[NewAmendmentModal]
  64. NewModal -->|Sign & Submit| Freighter[Stellar Freighter Wallet]
  65. NewModal -->|addAmendment| Backend[AmendmentService API]
  66. Backend -->|Success| Refresh[Refresh Carousel]
  67. ```
  68. ### File Structure & Changes
  69. - `src/components/modals/NewAmendmentModal.vue`: New creation modal component.
  70. - `src/components/AmendmentCarousel.vue`: Updated dummy card markup, styling, and modal invocation.
  71. - `src/composables/useModal.ts` (if needed): Context helpers for active proposal ID.
  72. # Testing
  73. ### Validation Approach
  74. Verify the feature through interactive testing and automated checks:
  75. - Verify that the dummy card renders correctly within the carousel at different viewport sizes (mobile, tablet, desktop).
  76. - Verify keyboard interactions (Tab navigation, Enter, Space keys) trigger the modal.
  77. - Verify modal form validation (disabling submission on empty fields).
  78. - Verify successful API submission payload structure and carousel refresh.
  79. ### Key Scenarios
  80. 1. **Card Rendering & Styling**:
  81. - Dummy card appears at the end of the amendments carousel.
  82. - Styles match design requirements (dashed border, centered icon, hover transitions).
  83. 2. **Opening the Modal**:
  84. - Clicking the card opens `NewAmendmentModal`.
  85. - Pressing Enter or Space when focused on the card opens `NewAmendmentModal`.
  86. 3. **Submitting New Amendment**:
  87. - Fill in amendment title and body.
  88. - Click "Submit Amendment" -> triggers Freighter authorization and calls `AmendmentService.addAmendment`.
  89. - Modal closes automatically and the new amendment appears in the carousel list.
  90. ### Edge Cases
  91. - **No Wallet Connected / Rejected Signing**: Display appropriate feedback if Freighter rejects connection or signing fails.
  92. - **Empty or Whitespace-only Inputs**: Ensure submit button remains disabled until valid name and content are provided.
  93. - **Carousel Scroll Recalculation**: Ensure `updateEdges()` executes after adding an amendment to update left/right navigation arrows.
  94. # Delivery Steps
  95. ### ✓ Step 1: Create NewAmendmentModal component
  96. A dedicated `NewAmendmentModal.vue` component is created and integrated with the modal system.
  97. - Create `src/components/modals/NewAmendmentModal.vue` utilizing `<Modal>` for the dialog container.
  98. - Implement title input with validation (`name`), content editor (using `PostBuilder` or markdown input), and submit action.
  99. - Integrate with `@stellar/freighter-api` to retrieve the signer address and `AmendmentService.addAmendment` to dispatch the proposal amendment.
  100. - Add error handling, loading state during submission, and automated modal dismissal on success.
  101. ### ✓ Step 2: Implement and style the dummy amendment card in AmendmentCarousel
  102. The carousel placeholder is replaced with a styled, accessible "Add Amendment" dummy card that opens the modal.
  103. - 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`).
  104. - Embed the `Plus` icon (`src/components/icons/Plus.vue`), title ("Add Amendment"), and descriptive helper text.
  105. - Add keyboard accessibility (`role="button"`, `tabindex="0"`, Enter/Space handlers) and click handler calling `useModal().show(NewAmendmentModal)`.
  106. - Pass current `proposalId` context to the modal so new amendments are attached to the active proposal.
  107. ### ✓ Step 3: Wire submission refresh and carousel reactivity
  108. Amendment creation triggers carousel list reload and seamlessly updates the UI.
  109. - Emit an event or trigger `getAmendments()` in `AmendmentCarousel.vue` upon successful amendment submission.
  110. - Ensure the newly added amendment appears in the carousel without requiring a full page refresh.
  111. - Verify scrolling edge calculations (`updateEdges()`) update after new amendment addition.