The frontend component of PuffPastry, meant to interface with the backend, which in turn interfaces with the smart contract.
Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.
 
 
 
 
 

9.2 KiB

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

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.

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.