Skip to content

Fix/wallet oracle claim error handling - #1

Open
adetomiwa21 wants to merge 26 commits into
mainfrom
fix/wallet-oracle-claim-error-handling
Open

Fix/wallet oracle claim error handling#1
adetomiwa21 wants to merge 26 commits into
mainfrom
fix/wallet-oracle-claim-error-handling

Conversation

@adetomiwa21

Copy link
Copy Markdown
Owner

Summary

Fixes four related error-handling / data-integrity bugs across the wallet and claims flow, one focused commit per issue.

Changes

Parashield-Protocol#221 — Preserve auth-failure error message
In WalletContext.tsx, the auth-failure catch block now calls disconnect() before setError("Auth failed: …"). Since disconnect() ends with setError(null), the previous order wiped the message instantly. Now matches the network-mismatch branch.

Parashield-Protocol#222 — Clamp rainfall key precision + validate length
buildRainfallKey() clamps coordinates to 4 decimals so keys can't exceed Soroban's 32-char limit, and validate() in BuyPolicyModal.tsx now enforces that limit for the crop and flight categories (previously only disaster/health).

Parashield-Protocol#223 — Colon-containing flight numbers
parseOracleKey() now isolates the date from the last :, so a flight number like AB:12 no longer swallows the date. The flight-number input also strips colons on change and caps its length.

Parashield-Protocol#220 — cancelledRef reset on retry
submit() already resets cancelledRef.current = false at its top (landed in Parashield-Protocol#218), which is the fix for the reset() hang. This adds a regression test proving a second failed submit after reset() surfaces an error instead of hanging on "Submitting claim…".

Testing

Full test suite green — 10 files, 85 tests. New tests cover each fix (auth-message persistence, over-length rainfall keys, colon flight-number round-trip, retried submit failure).

Closes Parashield-Protocol#221
Closes Parashield-Protocol#222
Closes Parashield-Protocol#223
Closes Parashield-Protocol#220

Jayy4rl and others added 26 commits July 25, 2026 15:53
…ield-Protocol#266)

- Remove unused usePool() hook from usePools.ts (Parashield-Protocol#249)
- Remove unused constants: HORIZON_URL, USDC_ASSET_CODE, USDC_ISSUER, USDC_ISSUER_TESTNET, ORACLE_CONTRACT_ID (Parashield-Protocol#248)
- Refactor utilizationColor() to extract color name logic, use in pools/page.tsx to eliminate duplication (Parashield-Protocol#247)
- Remove unused formatDuration() function (Parashield-Protocol#246)
… comparison (Parashield-Protocol#267)

- Parashield-Protocol#240: Normalize STELLAR_NETWORK env var (uppercase + trim) so
  'testnet'/'mainnet'/'public' all resolve correctly instead of silently
  falling through to testnet infrastructure.
- Parashield-Protocol#241: Add validateConfig() that checks POLICY/CLAIMS/ORACLE_CONTRACT_ID
  are non-empty and valid Stellar strkeys at app startup, so misconfiguration
  fails fast with a clear error instead of deep in the purchase/claim flow.
- Parashield-Protocol#244: Call api.submitClaim() after invokeSubmitClaim() succeeds in
  useClaim.ts, mirroring the existing buy-policy backend sync pattern
  so submitted claims reach the backend for UI polling/history.
- Parashield-Protocol#245: Remove unused oracleValueUnit() — its logic is already handled by
  formatOracleValue() in format.ts.

Co-authored-by: Dev Jaja <jajak5242@gmail.com>
…ards, add hook tests (Parashield-Protocol#268)

- Remove the unused useProduct(id) hook from useProducts.ts — no product
  detail page consumes it, matching the dead-code pattern already fixed
  elsewhere in the codebase.
- Compute the footer copyright year once via new Date().getFullYear() in
  layout.tsx and reuse it in both the desktop and mobile footers instead of
  the hardcoded "© 2026" literal.
- Wrap PolicyCard, ProductCard, and ClaimHistoryTable in React.memo so
  list/table components rendered inside .map() don't re-render on every
  background poll tick when their own props haven't changed.
- Add vitest coverage for all 8 custom hooks (useClaim, useDebounce,
  useKeyboardShortcut, useOracle, usePolicies, usePools, useProducts,
  useWallet), with dedicated regression tests for the loading/error/
  cancellation and stale-response-guard behavior previously fixed by hand in
  useClaim, usePolicies, and useOracle.

Closes Parashield-Protocol#250, Parashield-Protocol#251, Parashield-Protocol#252, Parashield-Protocol#253
…d-Protocol#289)

- Parashield-Protocol#261: Bump text-gray-500/text-gray-600 to text-gray-400 for WCAG AA contrast
- Parashield-Protocol#260: Extract shared input/label className constants in modals
- Parashield-Protocol#259: Remove unused WalletState type
- Parashield-Protocol#258: Use Comparison type in comparisonSymbol function

Closes Parashield-Protocol#261, closes Parashield-Protocol#260, closes Parashield-Protocol#259, closes Parashield-Protocol#258
* feat(seo): add robots.txt and sitemap for search engine crawling

- Add robots.ts with crawl rules for public routes
- Add sitemap.ts with all public marketing routes
- Disallow dashboard, policies, claims, oracle routes (authenticated)

Closes Parashield-Protocol#262

* feat(pwa): add web app manifest for installability

- Add manifest.ts with app name, icons, theme colors
- Reference manifest from layout.tsx metadata
- Enables Add to Home Screen on mobile devices

Closes Parashield-Protocol#263

* test(buy-policy-modal): add test coverage for BuyPolicyModal

- Test crop-specific inputs (lat, lng, month, year)
- Test flight-specific inputs (flight number, date)
- Test defi fixed oracle key display
- Test manual oracle key input for disaster/health
- Test configure step rendering
- Test modal title with product name

Closes Parashield-Protocol#269

* test(deposit-modal): add test coverage for DepositModal

- Test deposit form rendering with amount input
- Test pool liquidity and APY information display
- Test pool label for each category (crop, flight, defi, disaster, health)
- Test estimated LP shares placeholder

Closes Parashield-Protocol#270
…, and OracleDataWidget components (Parashield-Protocol#292)

Closes Parashield-Protocol#275, Closes Parashield-Protocol#276, Closes Parashield-Protocol#277, Closes Parashield-Protocol#278

Add comprehensive test coverage for four components that previously had
no tests:

- WalletButton: Tests disconnected state, connecting state, className prop,
  and button structure
- ConnectWalletPrompt: Tests default/custom messages, wallet name display,
  button rendering, and lock icon
- NavBar: Tests aria-current=page highlighting for active routes, exact
  / matching, all navigation links, mobile menu toggle, and layout
- OracleDataWidget: Tests loading, error, and no-data states; correct unit
  rendering for rainfall (mm), temperature (°C), flight (min delay), and
  defi (exploit/no exploit); confidence labels (High/Medium/Low); and
  source display
… and Modal components (Parashield-Protocol#309)

- Added tests for CopyButton: clipboard API, fallback, error handling, timer
- Added tests for ToastContext: show, dismiss, auto-dismiss, multiple toasts
- Added tests for Toast component: rendering, dismiss, variants
- Added tests for ErrorBoundary: error catching, fallback, reset
- Added tests for Modal: open/close, keyboard handling, focus management
- Updated vitest config with setup file and installed testing libraries
…ton (Parashield-Protocol#316)

* test: add test coverage for LoadingSpinner component

Covers role/aria-label, default and size-variant classes, custom
className, and the FullPageSpinner wrapper.

Closes Parashield-Protocol#296

* test: add test coverage for Logo component

Covers both Logo and LogoWordmark variants: img alt text, default
and custom size, custom className, and dark/light styling.

Closes Parashield-Protocol#297

* test: add test coverage for NetworkBanner component

Covers banner visibility for TESTNET vs PUBLIC networks, and the
default-to-visible behavior when no network env var is set.

Closes Parashield-Protocol#298

* test: add test coverage for Skeleton component

Covers Skeleton, SkeletonCard, SkeletonTable, and SkeletonText,
verifying the expected placeholder element counts for default and
custom count/rows props.

Closes Parashield-Protocol#299
…iverge from the kit (Parashield-Protocol#312)

src/lib/stellar.ts initialises StellarWalletsKit with allowAllModules(),
so the kit's actual supported-wallet list changes with SDK updates
independent of this component. The static "Use Freighter, xBull,
LOBSTR, or any Stellar-compatible wallet" copy could go stale in
either direction (a supported wallet like Rabet/Hana missing from the
list, or a delisted wallet still advertised). Replaced it with copy
that accurately represents the kit's dynamic nature instead of an
enumerated list, per the issue's first acceptance-criteria option.
"Connect Wallet" behavior (calling connect()) is unchanged.
…n accessible name (Parashield-Protocol#313)

The role="progressbar" element had aria-valuenow/min/max but nothing
tying it to the adjacent label text, so a screen reader announced only
"45%, progress bar" with no indication of what's being measured (e.g.
a pool's "Utilization" card). Added aria-labelledby pointing at the
label span when a label is provided, falling back to a generic
aria-label="Progress" when it isn't.

Co-authored-by: nonsobethel0-dev <nonsobethel0@gmail.com>
… and hide decorative icon (Parashield-Protocol#314)

The input relied on its placeholder as the only accessible-name
signal, which isn't reliable and disappears once text is entered.
Added aria-label={placeholder} to the input, and aria-hidden="true" on
the decorative search-icon span (it was already pointer-events-none
but not hidden from assistive tech).

Co-authored-by: nonsobethel0-dev <nonsobethel0@gmail.com>
… tech (Parashield-Protocol#315)

The static aria-label="Copy {label}" always overrode the visible
button text as the accessible name, so a screen reader announced the
same thing before and after a successful copy even though sighted
users saw the text flip to "✓ Copied". Dropped the static aria-label
so the visible text (Copy / label / "✓ Copied") is the accessible
name, and added an aria-live="polite" region that announces "Copied"
on success without being visually duplicated (sr-only).
* test(hooks): add comprehensive tests for useDebounce hook

Resolves Parashield-Protocol#307

* test(hooks): add comprehensive tests for useProducts hook

Resolves Parashield-Protocol#306

* test(hooks): add comprehensive tests for usePools hook

Resolves Parashield-Protocol#305

* test(hooks): add tests for usePolicy hook

Resolves Parashield-Protocol#304
…sive test coverage for api.ts and contract.ts (Parashield-Protocol#325)

Implements test suites for api.ts (issue Parashield-Protocol#319) and contract.ts (issue Parashield-Protocol#320):

api.test.ts:
- Tests unwrap() throws ApiError on success:false even with HTTP 200 (issue Parashield-Protocol#198)
- Tests withRetry() behavior: retries 5xx errors with exponential backoff, throws immediately on 4xx
- Tests auth interceptor adds Bearer token when session exists
- Tests auth error handler called on 401 responses
- Tests endpoint behavior for 404 handling in fetchClaim() and fetchOracleReading()

contract.test.ts:
- Tests buildBuyPolicyTx() encodes oracle key as {type: 'string'} not {type: 'symbol'} (issue Parashield-Protocol#194 regression)
- Tests simulateContractCall() throws ContractError with sanitized message and raw diagnostic in .details
- Tests transaction building, signing, and submission flows for buyPolicy and claim operations
- Tests poll-for-confirmation timeout handling
- Tests RPC singleton caching for connection pool efficiency (issue Parashield-Protocol#129)
- Tests BuyPolicyResult returns signedXdr for backend verification (issue Parashield-Protocol#195)
…ld-Protocol#318)

- Add eslint + eslint-config-next with a flat config so `yarn lint`
  runs deterministically instead of failing or prompting in CI
  (fixes Parashield-Protocol#235). Also resolves the pre-existing no-explicit-any
  violations that surfaced once linting actually ran.
- Add a request-id guard to usePools/useProducts so an older,
  slower refetch response can no longer overwrite a newer one
  (fixes Parashield-Protocol#234).
- Track the in-flight AbortController for usePolicies' refetch()
  and abort the previous call before starting a new one, so rapid
  "Refresh" clicks can't race (fixes Parashield-Protocol#233).
- Correct signAuthMessage's doc comment: the signature is passed
  through unmodified, not hex-encoded as previously claimed
  (fixes Parashield-Protocol#232).
…eClaim, and useOracle (Parashield-Protocol#300Parashield-Protocol#303) (Parashield-Protocol#326)

* test: add test coverage for TransactionLink component (Parashield-Protocol#300)

- Explorer URL uses testnet by default and switches to public when STELLAR_NETWORK is PUBLIC
- rel=noopener noreferrer attribute is present
- Default label truncates tx hash correctly when no label prop is given
- Links open in a new tab
- Custom className prop is applied

* test: add test coverage for WalletAddressDisplay component (Parashield-Protocol#301)

- Renders shortened address correctly using shortenAddress
- Renders full address when full prop is true
- Returns null when wallet is not connected
- Includes CopyButton with full address for copy affordance
- Custom className prop is applied

* test: add test coverage for useClaim hook (Parashield-Protocol#302)

- submit() transitions through submitting then polling then done on success
- submit() transitions to error state when submission fails
- Failed submission after reset() still surfaces its error (regression for reset bug)
- reset() clears all state back to idle
- Starts in idle state

* test: add test coverage for useOracle hook (Parashield-Protocol#303)

- Loading is true only on initial fetch, not on background polls
- Switching key does not let a stale response overwrite current reading
- Error state is set on fetch failure
- Returns null reading when key is null
…flow

Call disconnect() before setError(`Auth failed: ...`) in the auth-failure
catch block. disconnect() ends with setError(null), so the previous ordering
wiped the message immediately. This matches the network-mismatch branch.

Closes Parashield-Protocol#221
… categories

buildRainfallKey() capped coordinates at 4 decimals so generated keys stay
within Soroban's 32-char limit, and validate() now enforces that limit for the
crop and flight categories (previously only disaster/health were checked).

Closes Parashield-Protocol#222
… parsing

parseOracleKey() now isolates the flight date from the final ':' so a flight
number containing a colon (e.g. "AB:12") no longer swallows the date. The
flight-number input also strips colons at the source and caps its length.

Closes Parashield-Protocol#223
…rashield-Protocol#220)

submit() already resets cancelledRef.current = false at its top (landed in
Parashield-Protocol#218), which is the fix for the reset() hang. This adds a regression test
proving a second failed submit after reset() surfaces an error instead of
leaving the UI stuck on 'Submitting claim…'.

Closes Parashield-Protocol#220
…Protocol#324 Parashield-Protocol#322 Parashield-Protocol#321 Parashield-Protocol#308) (Parashield-Protocol#328)

* feat(pwa): add apple-icon.tsx for iOS home screen (Parashield-Protocol#324)

* feat(types): add WalletState discriminated union and wire into WalletContext (Parashield-Protocol#322)

* test(stellar): add unit tests for stellar.ts helpers (Parashield-Protocol#321)
* ci: add yarn lint step to CI workflow (Parashield-Protocol#257)

* refactor(constants): extract timing constants for CopyButton and useClaim (Parashield-Protocol#255, Parashield-Protocol#256)

* test(lib): add Vitest unit test coverage for api.ts and contract.ts (Parashield-Protocol#254)

* fix(ProgressBar): define labelId with useId hook

---------

Co-authored-by: Mosas2000 <Stellar-privacy@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment