The frontend component of PuffPastry, meant to interface with the backend, which in turn interfaces with the smart contract.
25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

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.