From f7c9e318d51ae936fc011d46f2fbf0ce8fe962a8 Mon Sep 17 00:00:00 2001 From: "Claude (on behalf of broda-spendy)" Date: Fri, 14 Aug 2026 06:26:53 +0000 Subject: [PATCH] docs: resolves issue #45 - add JSDoc comments across all components App/RemittanceForm/RouteList/RouteCard had light or no JSDoc. Adds consistent documentation matching the existing prose + @param style already used in routingEngine.js: - App.jsx: component-level doc explaining why state lives here rather than in a hook (ties back to ADR-0001's reasoning), plus doc on handleSubmit's query shape and its error-handling behavior - RemittanceForm.jsx: full @param docs added to the existing component-level comment (currencies, onSubmit's callback shape), plus a one-line comment on handleSwap - RouteList.jsx: doc covering the deliberate "render nothing before a search has run" behavior, which isn't obvious from the code alone - RouteCard.jsx: doc flagging that route.totalCost is intentionally not displayed (it's a ranking score, not a monetary amount) - a clarification worth having directly in the component that renders the other Route fields but skips this one RouteList/RouteCard reference the Route/Hop typedefs already defined in routingEngine.js via an @param import() type reference, rather than redefining them, so there's one source of truth for the shape. Verified for real (this is a JS/Vite project, not one of the Soroban Rust ones - Node tooling works fine in this sandbox): - npm test: 12/12 pass - npm run build: succeeds Closes #45 --- src/App.jsx | 21 +++++++++++++++++++++ src/components/RemittanceForm.jsx | 8 ++++++++ src/components/RouteCard.jsx | 13 +++++++++++++ src/components/RouteList.jsx | 12 ++++++++++++ 4 files changed, 54 insertions(+) diff --git a/src/App.jsx b/src/App.jsx index c750245..c853faf 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -8,6 +8,16 @@ import './styles.css' // Session-scoped cache: repeated identical queries skip recomputation. const findRoutesCached = createCachedFindRoutes() +/** + * Root component. Owns all query/results state and wires the form to the + * routing engine to the results list — the routing engine itself has no + * React dependency (see routingEngine.js), so all state management lives + * here rather than in a hook. + * + * Phase 1 passes the mocked `mockAnchors` dataset into the engine on every + * search; Phase 2 replaces that with live-fetched anchor data at this same + * call site, without needing to change the engine. + */ export default function App() { const [routes, setRoutes] = useState([]) const [searched, setSearched] = useState(false) @@ -16,6 +26,17 @@ export default function App() { const currencies = availableCurrencies() + /** + * Runs the routing engine for the submitted query and updates all + * derived state. Routing-engine errors (e.g. an invalid `anchors` + * argument) are caught here and surfaced as a form-level error rather + * than crashing the app. + * + * @param {Object} query + * @param {string} query.fromCurrency + * @param {string} query.toCurrency + * @param {number} query.amount + */ function handleSubmit({ fromCurrency, toCurrency, amount }) { setEngineError(null) try { diff --git a/src/components/RemittanceForm.jsx b/src/components/RemittanceForm.jsx index 4f1b1c9..51cfb1e 100644 --- a/src/components/RemittanceForm.jsx +++ b/src/components/RemittanceForm.jsx @@ -4,6 +4,12 @@ import { useState } from 'react' * Currency-pair + amount input. Currencies are populated from whatever * data source is passed in (mock in Phase 1, live in Phase 2) — this * component never hardcodes a currency list. + * + * @param {Object} props + * @param {string[]} props.currencies - Available currency codes to populate both selects. + * @param {(query: { fromCurrency: string, toCurrency: string, amount: number }) => void} props.onSubmit + * Called with a validated query once the form passes its own client-side + * checks (both currencies selected, currencies differ, amount > 0). */ export default function RemittanceForm({ currencies, onSubmit }) { const [fromCurrency, setFromCurrency] = useState(currencies[0] ?? '') @@ -11,6 +17,8 @@ export default function RemittanceForm({ currencies, onSubmit }) { const [amount, setAmount] = useState('100') const [error, setError] = useState(null) + // Swaps the two selected currencies in place, so a user correcting a + // reversed pair doesn't have to re-select both dropdowns. function handleSwap() { setFromCurrency(toCurrency) setToCurrency(fromCurrency) diff --git a/src/components/RouteCard.jsx b/src/components/RouteCard.jsx index 92e0195..f0dba27 100644 --- a/src/components/RouteCard.jsx +++ b/src/components/RouteCard.jsx @@ -1,3 +1,16 @@ +/** + * Displays a single ranked route: its currency path, headline stats + * (output amount, total fee, estimated time), and an expandable per-hop + * breakdown. + * + * Note: `route.totalCost` (the engine's internal ranking score) is + * deliberately not displayed here — it's not a monetary amount, only a + * sort key used to order the route list. + * + * @param {Object} props + * @param {import('../engine/routingEngine').Route} props.route - The route to display. + * @param {number} props.rank - This route's 1-based position in the ranked list, for display (e.g. "#1"). + */ export default function RouteCard({ route, rank }) { const path = [route.hops[0].fromCurrency, ...route.hops.map((h) => h.toCurrency)].join(' → ') diff --git a/src/components/RouteList.jsx b/src/components/RouteList.jsx index 54b7c77..a93497f 100644 --- a/src/components/RouteList.jsx +++ b/src/components/RouteList.jsx @@ -1,5 +1,17 @@ import RouteCard from './RouteCard' +/** + * Renders the ranked list of routes returned by the routing engine, or an + * appropriate empty/no-results state. + * + * Renders nothing at all before a search has run (`searched === false`), + * rather than an empty list, so the UI doesn't imply "no routes exist" + * before the user has actually searched. + * + * @param {Object} props + * @param {import('../engine/routingEngine').Route[]} props.routes - Ranked routes to display, cheapest-first. + * @param {boolean} props.searched - Whether a search has been run yet this session. + */ export default function RouteList({ routes, searched }) { if (!searched) { return null