| type | Feature |
|---|---|
| title | Persist wallet connection across reloads with a WalletProvider context |
| labels | type:feature, area:wallet, stack:nextjs, stack:react, stack:typescript, priority:high, MAYBE REWARDED, GRANTFOX OSS, OFFICIAL CAMPAIGN |
| assignees |
components/WalletStatus.jsx keeps walletState/walletData in local component state, so the connection is lost on every navigation or page refresh and cannot be read by other components (e.g. a future "Fund this invoice" button or the Invoices page header). This issue introduces a WalletProvider React context that owns the wallet state, rehydrates it from storage on mount, and exposes a useWallet() hook.
- Repository scope: Liquifact/Liquifact-frontend only.
- Create
components/WalletProvider.jsxexportingWalletProviderand auseWallet()hook returning{ state, walletData, connect, disconnect }, reusing the existingWALLET_STATESenum fromcomponents/WalletStatus.jsx. - Persist a minimal, non-sensitive snapshot (connection intent + truncated address + network) via
localStorageand rehydrate on mount; never persist secrets or full balances. - Refactor
WalletStatusto consumeuseWallet()instead of its internaluseState, keeping all existing accessibility regions and toast calls intact. - Mount
WalletProvideronce inapp/layout.jsinside the existingToastProvider. - Guard against SSR by reading storage only after mount (no
windowaccess during render).
- Fork the repo and create a branch
git checkout -b feature/wallet-01-walletprovider-persistence- Implement changes
- Write code in: create
components/WalletProvider.jsx; updatecomponents/WalletStatus.jsxandapp/layout.js. - Write comprehensive tests in: create
components/WalletProvider.test.tsxβ assert rehydration, disconnect clears storage, anduseWalletthrows outside the provider. - Add documentation: document
WalletProvider/useWalletinREADME.mdand cross-referenceWALLET_INTEGRATION_CONTRACT.md. - Add JSDoc to the hook and provider props.
- Validate security: never persist private keys or full balances; sanitize values read back from storage.
- Write code in: create
- Test and commit
- Run
npm run lint,npm test, andnpm run build. - Cover edge cases: corrupt storage payload, SSR render, and rehydrate-then-disconnect.
- Include the full
npm testoutput and a note on what is persisted.
feat: persist wallet connection via a shared walletprovider context
- Minimum 95 percent test coverage for impacted modules.
- Clear, reviewer-focused documentation.
- Timeframe: 96 hours.
- π¬ Join the Liquifact community on Discord for questions, reviews, and faster merges: https://discord.gg/JrGPH4V3
- β This is a GrantFox OSS / Official Campaign task and may be rewarded. When your PR is merged you'll be prompted to rate the project β if this issue and the maintainers helped you ship, we'd be grateful for a 5-star rating. Clear questions in Discord and tidy, well-tested PRs are the fastest path to a merge and a reward. ++++++
type: Feature title: "Add a client-side search box to filter the Invest marketplace by issuer" labels: type:feature, area:invest, stack:nextjs, stack:react, stack:typescript, priority:medium, MAYBE REWARDED, GRANTFOX OSS, OFFICIAL CAMPAIGN assignees: ''
The marketplace list in app/invest/page.js renders every loaded invoice with no way to find a specific issuer; as the list grows beyond the three mock entries this becomes unusable. This issue adds a debounced search input that filters the rendered invoices by issuer name and keeps the polite aria-live announcement accurate.
- Repository scope: Liquifact/Liquifact-frontend only.
- Add a labelled search
<input type="search">above the list that filtersinvoicesby case-insensitive substring match onissuer. - Debounce the input (e.g. 200ms) so filtering does not thrash on every keystroke.
- Update
getInvoiceLoadAnnouncementusage so the status region announces the filtered count (e.g. "2 of 3 invoices match"), and show a distinct "no matches" state separate from the empty-marketplace state. - Preserve the loading/error/empty branches and the slate/cyan styling; clearing the field restores the full list.
- Fork the repo and create a branch
git checkout -b feature/invest-02-issuer-search- Implement changes
- Write code in: update
app/invest/page.js; optionally extract acomponents/InvoiceSearch.jsx. - Write comprehensive tests in: extend
app/invest/page.test.jsxand/or createcomponents/InvoiceSearch.test.tsxβ assert filtering, debounce, no-match state, and clear. - Add documentation: note the search behaviour in
README.md. - Add JSDoc on any extracted search component.
- Validate a11y: the input has an associated label and the filtered count is announced politely.
- Write code in: update
- Test and commit
- Run
npm run lint,npm test, andnpm run build. - Cover edge cases: empty query, no matches, whitespace-only query, and rapid typing.
- Include the full
npm testoutput.
feat: add issuer search box to the invest marketplace
- Minimum 95 percent test coverage for impacted modules.
- Clear, reviewer-focused documentation.
- Timeframe: 96 hours.
- π¬ Join the Liquifact community on Discord for questions, reviews, and faster merges: https://discord.gg/JrGPH4V3
- β This is a GrantFox OSS / Official Campaign task and may be rewarded. When your PR is merged you'll be prompted to rate the project β if this issue and the maintainers helped you ship, we'd be grateful for a 5-star rating. Clear questions in Discord and tidy, well-tested PRs are the fastest path to a merge and a reward. ++++++
type: Feature title: "Add pagination or load-more to the Invest marketplace list" labels: type:feature, area:invest, stack:nextjs, stack:react, stack:typescript, priority:medium, MAYBE REWARDED, GRANTFOX OSS, OFFICIAL CAMPAIGN assignees: ''
app/invest/page.js maps the entire invoice array into a single <ul> with no paging or windowing, so a real backend returning hundreds of invoices would render an unbounded DOM and a long, unscannable list. This issue adds page-size-bounded rendering with an accessible "Load more" (or numbered pages) control.
- Repository scope: Liquifact/Liquifact-frontend only.
- Render at most
PAGE_SIZE(e.g. 10) invoices at a time and expose a "Load more" button (or prev/next page controls) that reveals the next batch. - Keep the polite status region accurate ("Showing N of M invoices"); announce when more results are appended.
- Reset paging when filters/search change (coordinate with the existing list rendering so the change is non-breaking if those features land later).
- Preserve loading/empty/error branches and keyboard focus on the control after each load.
- Fork the repo and create a branch
git checkout -b feature/invest-03-marketplace-pagination- Implement changes
- Write code in: update
app/invest/page.js; optionally extract acomponents/Pagination.jsx. - Write comprehensive tests in: extend
app/invest/page.test.jsxβ assert initial page size, load-more appends, and the count announcement. - Add documentation: note paging behaviour in
README.md. - Add JSDoc on any pagination helper/component.
- Validate a11y: the control has a clear accessible name and focus is managed after load.
- Write code in: update
- Test and commit
- Run
npm run lint,npm test, andnpm run build. - Cover edge cases: fewer items than a page, exact page boundary, and last page.
- Include the full
npm testoutput.
feat: paginate the invest marketplace invoice list
- Minimum 95 percent test coverage for impacted modules.
- Clear, reviewer-focused documentation.
- Timeframe: 96 hours.
- π¬ Join the Liquifact community on Discord for questions, reviews, and faster merges: https://discord.gg/JrGPH4V3
- β This is a GrantFox OSS / Official Campaign task and may be rewarded. When your PR is merged you'll be prompted to rate the project β if this issue and the maintainers helped you ship, we'd be grateful for a 5-star rating. Clear questions in Discord and tidy, well-tested PRs are the fastest path to a merge and a reward. ++++++
type: Feature title: "Show a determinate progress bar during invoice upload in UploadZone" labels: type:enhancement, area:upload, stack:nextjs, stack:react, stack:typescript, priority:medium, MAYBE REWARDED, GRANTFOX OSS, OFFICIAL CAMPAIGN assignees: ''
components/UploadZone.jsx only shows an indeterminate spinner with "Uploading invoice..." during the uploading status; the user gets no sense of how far along a large (up to 10 MB) PDF upload is. This issue adds a determinate progress bar driven by upload progress events, with proper ARIA so screen-reader users hear progress too.
- Repository scope: Liquifact/Liquifact-frontend only.
- Render a
role="progressbar"element witharia-valuemin/aria-valuemax/aria-valuenowand a visible percentage during theuploadingstatus. - Accept an injectable
onProgress-style callback (or progress prop) so the bar can be driven by a realXMLHttpRequest/fetch-stream progress source later and tested deterministically now. - Fall back to the existing indeterminate spinner when progress is unknown; keep the
tokenizingandsuccesscopy unchanged so the e2e spec intests/toast.spec.jsxstill passes. - Respect
prefers-reduced-motionfor any bar transition.
- Fork the repo and create a branch
git checkout -b enhancement/upload-04-progress-bar- Implement changes
- Write code in: update
components/UploadZone.jsx; optionally extract acomponents/ProgressBar.jsx. - Write comprehensive tests in: extend
components/UploadZone.test.jsxβ assert progressbar ARIA values update and the indeterminate fallback. - Add documentation: note the progress UI in
README.md. - Add JSDoc on the progress prop/callback.
- Validate a11y: progressbar exposes value text and does not steal focus.
- Write code in: update
- Test and commit
- Run
npm run lint,npm test,npm run build, andnpm run test:e2e. - Cover edge cases: 0%, 100%, unknown-progress fallback, and reduced motion.
- Include the full
npm testoutput and confirmation the toast e2e still passes.
feat: add accessible upload progress bar to uploadzone
- Minimum 95 percent test coverage for impacted modules.
- Clear, reviewer-focused documentation.
- Timeframe: 96 hours.
- π¬ Join the Liquifact community on Discord for questions, reviews, and faster merges: https://discord.gg/JrGPH4V3
- β This is a GrantFox OSS / Official Campaign task and may be rewarded. When your PR is merged you'll be prompted to rate the project β if this issue and the maintainers helped you ship, we'd be grateful for a 5-star rating. Clear questions in Discord and tidy, well-tested PRs are the fastest path to a merge and a reward. ++++++
type: Feature title: "Allow resetting UploadZone to upload another invoice after success" labels: type:enhancement, area:upload, stack:nextjs, stack:react, stack:typescript, priority:medium, MAYBE REWARDED, GRANTFOX OSS, OFFICIAL CAMPAIGN assignees: ''
After a successful submission components/UploadZone.jsx stays in the success status with the previous file still selected, and the submit button relabels to "Upload & Tokenize Invoice" while still pointing at the already-submitted file β there is no clean way to start a fresh upload without reloading the page. This issue adds an explicit reset that clears the file, error, and status back to idle.
- Repository scope: Liquifact/Liquifact-frontend only.
- Add an "Upload another invoice" button shown in the
successstate that resetsfile,error, andstatusto their initial values and clears the file<input>. - Move focus to the dropzone after reset so keyboard users can immediately start again.
- Keep the existing status copy and
role="status"/role="alert"regions; the success message should clear on reset. - Do not change the disabled/
aria-disabledlogic on#invoice-upload-btnfor the idle/processing states.
- Fork the repo and create a branch
git checkout -b enhancement/upload-05-reset-flow- Implement changes
- Write code in: update
components/UploadZone.jsx. - Write comprehensive tests in: extend
components/UploadZone.test.jsxβ assert reset clears file/status and restores focus. - Add documentation: note the reset flow in
README.md. - Add comments explaining the focus-management choice.
- Validate a11y: focus lands on a sensible target after reset.
- Write code in: update
- Test and commit
- Run
npm run lint,npm test, andnpm run build. - Cover edge cases: reset after success, reset clears stale error, and re-upload after reset.
- Include the full
npm testoutput.
feat: add upload-another reset flow to uploadzone
- Minimum 95 percent test coverage for impacted modules.
- Clear, reviewer-focused documentation.
- Timeframe: 96 hours.
- π¬ Join the Liquifact community on Discord for questions, reviews, and faster merges: https://discord.gg/JrGPH4V3
- β This is a GrantFox OSS / Official Campaign task and may be rewarded. When your PR is merged you'll be prompted to rate the project β if this issue and the maintainers helped you ship, we'd be grateful for a 5-star rating. Clear questions in Discord and tidy, well-tested PRs are the fastest path to a merge and a reward. ++++++
type: Feature title: "Cap the toast stack and de-duplicate repeated messages in ToastProvider" labels: type:enhancement, area:toast, stack:nextjs, stack:react, stack:typescript, priority:medium, MAYBE REWARDED, GRANTFOX OSS, OFFICIAL CAMPAIGN assignees: ''
components/ToastProvider.jsx prepends every new toast to an unbounded array ([toast, ...current]) with no limit and no de-duplication, so a retry loop or rapid wallet errors (see the random-outcome flow in components/WalletStatus.jsx) can stack dozens of identical toasts and cover the viewport. This issue caps the visible stack and collapses duplicates.
- Repository scope: Liquifact/Liquifact-frontend only.
- Add a
MAX_TOASTSlimit (e.g. 3); when exceeded, drop the oldest toast and clear its timer intimers. - De-duplicate by
variant + title + message: if an identical toast is already visible, refresh its auto-dismiss timer instead of adding a new one. - Preserve the public
success/error/infoAPI, theAUTO_DISMISS_MSbehaviour, and pause/resume on hover. - Keep the
role="status"/aria-live="polite"live region and ensure timer cleanup remains leak-free.
- Fork the repo and create a branch
git checkout -b enhancement/toast-06-cap-and-dedupe- Implement changes
- Write code in: update
components/ToastProvider.jsx. - Write comprehensive tests in: create
components/ToastProvider.dedupe.test.tsxusing fake timers β assert cap eviction, duplicate collapse, and no timer leaks. - Add documentation: note the queue limits in
README.md. - Add JSDoc/comments on
MAX_TOASTSand the dedupe key. - Validate a11y: stacked toasts remain individually dismissible.
- Write code in: update
- Test and commit
- Run
npm run lint,npm test, andnpm run build. - Cover edge cases: burst of identical toasts, cap eviction during hover-pause, and unmount mid-timer.
- Include the full
npm testoutput.
feat: cap toast stack and de-duplicate repeated messages
- Minimum 95 percent test coverage for impacted modules.
- Clear, reviewer-focused documentation.
- Timeframe: 96 hours.
- π¬ Join the Liquifact community on Discord for questions, reviews, and faster merges: https://discord.gg/JrGPH4V3
- β This is a GrantFox OSS / Official Campaign task and may be rewarded. When your PR is merged you'll be prompted to rate the project β if this issue and the maintainers helped you ship, we'd be grateful for a 5-star rating. Clear questions in Discord and tidy, well-tested PRs are the fastest path to a merge and a reward. ++++++
type: Feature title: "Make the marketplace error state retryable with a working ErrorBanner action" labels: type:enhancement, area:invest, stack:nextjs, stack:react, stack:typescript, priority:medium, MAYBE REWARDED, GRANTFOX OSS, OFFICIAL CAMPAIGN assignees: ''
When loadInvoices rejects, app/invest/page.js renders an ErrorBanner with only title/description/previewLabel β but components/ErrorBanner.jsx already supports actionLabel/onAction, which is unused here. The user has no way to recover except a full page reload. This issue adds a "Try again" action that re-runs the load.
- Repository scope: Liquifact/Liquifact-frontend only.
- Refactor
InvestMarketplaceso the load logic is callable on demand (e.g. areload()that resets state to loading and re-invokesloadInvoices). - Pass
actionLabel="Try again"andonAction={reload}to theErrorBannerso the existing action button is used. - Reset
loadError, setinvoicesback tonull(loading), and re-announce via the polite status region on retry. - Continue to honour the
AbortController/isActivecancellation so a retry does not race a stale request.
- Fork the repo and create a branch
git checkout -b enhancement/invest-07-retryable-error- Implement changes
- Write code in: update
app/invest/page.js. - Write comprehensive tests in: extend
app/invest/page.test.jsxβ fail then succeed on retry, assert the loading skeleton reappears and the list renders. - Add documentation: note the retry behaviour in
README.md. - Add comments on the reload/abort interaction.
- Validate a11y: the retry button has a clear accessible name and focus is sensible after retry.
- Write code in: update
- Test and commit
- Run
npm run lint,npm test, andnpm run build. - Cover edge cases: retry-after-failure success, retry-then-failure, and rapid double retry.
- Include the full
npm testoutput.
feat: add retry action to the invest marketplace error state
- Minimum 95 percent test coverage for impacted modules.
- Clear, reviewer-focused documentation.
- Timeframe: 96 hours.
- π¬ Join the Liquifact community on Discord for questions, reviews, and faster merges: https://discord.gg/JrGPH4V3
- β This is a GrantFox OSS / Official Campaign task and may be rewarded. When your PR is merged you'll be prompted to rate the project β if this issue and the maintainers helped you ship, we'd be grateful for a 5-star rating. Clear questions in Discord and tidy, well-tested PRs are the fastest path to a merge and a reward. ++++++
type: Feature title: "Add a responsive mobile navigation menu to the app header" labels: type:feature, area:navigation, stack:nextjs, stack:react, stack:typescript, priority:medium, MAYBE REWARDED, GRANTFOX OSS, OFFICIAL CAMPAIGN assignees: ''
The headers in app/page.js, app/invoices/page.js, and app/invest/page.js place the brand and a "Connect Wallet" button in a single flex row with no links to the Invoices/Invest sections and no mobile menu β on narrow viewports there is no navigation affordance at all. This issue adds an accessible responsive nav with a disclosure menu on mobile.
- Repository scope: Liquifact/Liquifact-frontend only.
- Create
components/NavMenu.jsxwith links to Home, Invoices (/invoices), and Invest (/invest), rendered inline on desktop and behind an accessible toggle button (aria-expanded,aria-controls) on mobile. - Mark the current route as
aria-current="page". - Close the menu on
Escapeand on navigation, and trap/return focus appropriately when open. - Keep the existing slate/cyan styling and the brand wordmark/back-link semantics; do not duplicate the static Connect Wallet button (reference the wallet UI rather than re-adding dead buttons).
- Fork the repo and create a branch
git checkout -b feature/navigation-08-responsive-nav- Implement changes
- Write code in: create
components/NavMenu.jsx; update the page headers inapp/page.js,app/invoices/page.js, andapp/invest/page.js. - Write comprehensive tests in: create
components/NavMenu.test.tsxβ assert toggle,aria-expanded, Escape-to-close, andaria-current. - Add documentation: document
NavMenuinREADME.md. - Add JSDoc on the component props.
- Validate a11y: menu is keyboard-operable with no
jest-axeviolations.
- Write code in: create
- Test and commit
- Run
npm run lint,npm test, andnpm run build. - Cover edge cases: open/close, Escape, current-route marking, and focus return.
- Include the full
npm testoutput.
feat: add responsive mobile navigation menu to the header
- Minimum 95 percent test coverage for impacted modules.
- Clear, reviewer-focused documentation.
- Timeframe: 96 hours.
- π¬ Join the Liquifact community on Discord for questions, reviews, and faster merges: https://discord.gg/JrGPH4V3
- β This is a GrantFox OSS / Official Campaign task and may be rewarded. When your PR is merged you'll be prompted to rate the project β if this issue and the maintainers helped you ship, we'd be grateful for a 5-star rating. Clear questions in Discord and tidy, well-tested PRs are the fastest path to a merge and a reward. ++++++
type: Feature title: "Externalize copy into a typed i18n dictionary and remove inline strings" labels: type:refactor, area:i18n, stack:nextjs, stack:react, stack:typescript, priority:medium, MAYBE REWARDED, GRANTFOX OSS, OFFICIAL CAMPAIGN assignees: ''
app/copy/en.js holds some strings, but many user-facing strings are still inlined: the marketplace yield disclaimer and filter labels in app/invest/page.js, the upload status copy in components/UploadZone.jsx, and the wallet helper texts in components/WalletStatus.jsx. This drift makes copy edits and future localization error-prone. This issue moves all visible strings into the dictionary and gives it a typed shape.
- Repository scope: Liquifact/Liquifact-frontend only.
- Extend
app/copy/en.jswith keys for the upload statuses, wallet states/helper texts, marketplace filter labels, and the yield disclaimer. - Replace the inline literals in the components/pages above with dictionary lookups.
- Add a JSDoc
@typedef(or acopy.types.js) describing the dictionary shape so missing keys are catchable. - No visible copy or behaviour change β strings must render identically.
- Fork the repo and create a branch
git checkout -b refactor/i18n-09-externalize-copy- Implement changes
- Write code in: update
app/copy/en.js,app/invest/page.js,components/UploadZone.jsx,components/WalletStatus.jsx. - Write comprehensive tests in: create
app/copy/en.test.tsxasserting key presence, and snapshot-check a couple of components for unchanged text. - Add documentation: document the copy/i18n convention in
README.md. - Add a JSDoc typedef for the dictionary.
- Validate: grep confirms no remaining inline user-facing strings in the touched files.
- Write code in: update
- Test and commit
- Run
npm run lint,npm test, andnpm run build. - Cover edge cases: every referenced key exists; rendered text is byte-identical.
- Include the full
npm testoutput and a before/after string inventory.
refactor: externalize ui copy into a typed dictionary
- Minimum 95 percent test coverage for impacted modules.
- Clear, reviewer-focused documentation.
- Timeframe: 96 hours.
- π¬ Join the Liquifact community on Discord for questions, reviews, and faster merges: https://discord.gg/JrGPH4V3
- β This is a GrantFox OSS / Official Campaign task and may be rewarded. When your PR is merged you'll be prompted to rate the project β if this issue and the maintainers helped you ship, we'd be grateful for a 5-star rating. Clear questions in Discord and tidy, well-tested PRs are the fastest path to a merge and a reward. ++++++
type: Feature title: "Lazy-load WalletStatus to keep wallet code off the initial bundle" labels: type:refactor, area:performance, stack:nextjs, stack:react, stack:typescript, priority:low, MAYBE REWARDED, GRANTFOX OSS, OFFICIAL CAMPAIGN assignees: ''
components/WalletStatus.jsx is a client component that will soon pull in the Stellar/Freighter SDK, yet once mounted in the shared header it would ship in the first-load JS of every route β including the static home page that does not need wallet logic immediately. This issue lazy-loads the wallet UI so it is fetched on demand without blocking initial render.
- Repository scope: Liquifact/Liquifact-frontend only.
- Use
next/dynamicto loadWalletStatus(withssr: falsewhere appropriate) behind a small static placeholder that matches its dimensions to avoid layout shift. - Keep the exported
WALLET_STATESimport path stable for tests. - Ensure the accessible status region still mounts once the chunk loads and that no hydration warnings appear.
- Document the measured first-load JS impact (before/after) using
npm run buildoutput.
- Fork the repo and create a branch
git checkout -b refactor/performance-10-lazy-walletstatus- Implement changes
- Write code in: update the header/consumer that renders
WalletStatus(e.g.app/page.js) to use a dynamic import wrapper. - Write comprehensive tests in: create
components/WalletStatus.lazy.test.tsxβ assert the placeholder renders then the wallet UI appears. - Add documentation: note the code-splitting decision in
README.mdwith before/after bundle numbers. - Add comments explaining the
ssr/placeholder choice. - Validate: no CLS from the placeholder swap.
- Write code in: update the header/consumer that renders
- Test and commit
- Run
npm run lint,npm test, andnpm run build. - Cover edge cases: placeholder dimensions, hydration, and lazy mount.
- Include the
npm run buildfirst-load JS comparison.
perf: lazy-load walletstatus to reduce initial bundle
- Minimum 95 percent test coverage for impacted modules.
- Clear, reviewer-focused documentation.
- Timeframe: 96 hours.
- π¬ Join the Liquifact community on Discord for questions, reviews, and faster merges: https://discord.gg/JrGPH4V3
- β This is a GrantFox OSS / Official Campaign task and may be rewarded. When your PR is merged you'll be prompted to rate the project β if this issue and the maintainers helped you ship, we'd be grateful for a 5-star rating. Clear questions in Discord and tidy, well-tested PRs are the fastest path to a merge and a reward. ++++++
type: Feature title: "Extract a shared Button component to unify variants and focus styles" labels: type:refactor, area:components, stack:nextjs, stack:react, stack:typescript, priority:medium, MAYBE REWARDED, GRANTFOX OSS, OFFICIAL CAMPAIGN assignees: ''
Button styling is copy-pasted across the app with subtly different focus rings: the cyan pill in app/page.js, the disabled filter buttons in app/invest/page.js, the submit button and Spinner in components/UploadZone.jsx, the variant switch in components/WalletStatus.jsx, and the action button in components/ErrorBanner.jsx. They diverge (focus:ring vs focus-visible:outline), which is exactly the inconsistency a shared component prevents. This issue introduces a single Button.
- Repository scope: Liquifact/Liquifact-frontend only.
- Create
components/Button.jsxsupportingvariant(primary/secondary/warning/external/danger),loading(renders the shared spinner),disabled, and forwarded props/ref. - Apply one consistent
focus-visibleoutline across all variants. - Migrate the buttons in the files above to use
Buttonwithout visual regressions. - Export the shared
SpinnerfromButton(or acomponents/Spinner.jsx) and stop redefining the inline SVG inWalletStatus/UploadZone.
- Fork the repo and create a branch
git checkout -b refactor/components-11-shared-button- Implement changes
- Write code in: create
components/Button.jsx(and optionallycomponents/Spinner.jsx); update the consumers listed above. - Write comprehensive tests in: create
components/Button.test.tsxβ assert variants, disabled/loading, and focus styles. - Add documentation: document
ButtoninREADME.mdUI section. - Add JSDoc on the props.
- Validate a11y: focus-visible outline meets contrast; loading sets
aria-busy.
- Write code in: create
- Test and commit
- Run
npm run lint,npm test, andnpm run build. - Cover edge cases: each variant, loading state, and disabled state.
- Include the full
npm testoutput and a before/after note confirming no visual change.
refactor: extract shared button and spinner components
- Minimum 95 percent test coverage for impacted modules.
- Clear, reviewer-focused documentation.
- Timeframe: 96 hours.
- π¬ Join the Liquifact community on Discord for questions, reviews, and faster merges: https://discord.gg/JrGPH4V3
- β This is a GrantFox OSS / Official Campaign task and may be rewarded. When your PR is merged you'll be prompted to rate the project β if this issue and the maintainers helped you ship, we'd be grateful for a 5-star rating. Clear questions in Discord and tidy, well-tested PRs are the fastest path to a merge and a reward. ++++++
type: Feature title: "Add behavioral unit tests for the ErrorBanner component" labels: type:test, area:error-banner, stack:nextjs, stack:react, stack:typescript, priority:medium, MAYBE REWARDED, GRANTFOX OSS, OFFICIAL CAMPAIGN assignees: ''
components/ErrorBanner.jsx has only an a11y smoke test in components/__tests__/ErrorBanner.a11y.test.jsx; its variant label switch (server vs validation), conditional details, and the actionLabel/onAction button are not behaviorally tested. This issue adds full coverage of its rendering contract.
- Repository scope: Liquifact/Liquifact-frontend only.
- Assert
variantLabelrenders "Server error" forserver/default and "Validation error" forvalidation. - Assert
title/description/previewLabelrender, thatdetailsonly renders when provided, and that the action button appears only whenactionLabelis set and callsonActionon click. - Assert the
role="alert"/aria-live="assertive"container is present. - Use
@testing-library/user-eventfor the action click.
- Fork the repo and create a branch
git checkout -b test/error-banner-12-behavioral-coverage- Implement changes
- Write code in: no source change unless a bug is found in
components/ErrorBanner.jsx. - Write comprehensive tests in: create
components/ErrorBanner.test.tsx. - Add documentation: none beyond test comments.
- Add comments documenting the variant matrix.
- Validate a11y: keep an axe check alongside the behavioral assertions.
- Write code in: no source change unless a bug is found in
- Test and commit
- Run
npm run lint,npm test, andnpm run build. - Cover edge cases: missing
details, missingactionLabel, and both variants. - Include the full
npm testoutput with ErrorBanner coverage.
test: cover errorbanner variants and action behaviour
- Minimum 95 percent test coverage for impacted modules.
- Clear, reviewer-focused documentation.
- Timeframe: 96 hours.
- π¬ Join the Liquifact community on Discord for questions, reviews, and faster merges: https://discord.gg/JrGPH4V3
- β This is a GrantFox OSS / Official Campaign task and may be rewarded. When your PR is merged you'll be prompted to rate the project β if this issue and the maintainers helped you ship, we'd be grateful for a 5-star rating. Clear questions in Discord and tidy, well-tested PRs are the fastest path to a merge and a reward. ++++++
type: Feature title: "Add unit tests for the getInvoiceLoadAnnouncement helper and InvestMarketplace states" labels: type:test, area:invest, stack:nextjs, stack:react, stack:typescript, priority:medium, MAYBE REWARDED, GRANTFOX OSS, OFFICIAL CAMPAIGN assignees: ''
app/invest/page.js exports getInvoiceLoadAnnouncement and an injectable InvestMarketplace, but app/invest/page.test.jsx does not cover the helper's branches directly nor the abort/unmount path in the effect. This issue adds focused coverage for the pure helper and the loading/empty/error/non-array states.
- Repository scope: Liquifact/Liquifact-frontend only.
- Unit-test
getInvoiceLoadAnnouncementfor: non-array input, empty array, and N>0 (assert exact strings "No invoices available" / "N investable invoices loaded"). - Test
InvestMarketplacewith injected loaders that resolve to a list, an empty array, a non-array (coerced to[]), and a rejected promise (error banner + announcement). - Assert the skeleton renders while the loader is pending and that unmount during a pending load does not throw or set state (the
isActiveguard). - Reuse the injectable
loadInvoicesprop already used by the existing test.
- Fork the repo and create a branch
git checkout -b test/invest-13-announcement-and-states- Implement changes
- Write code in: no source change unless a bug is found in
app/invest/page.js. - Write comprehensive tests in: extend
app/invest/page.test.jsxor createapp/invest/announcement.test.tsx. - Add documentation: none beyond test comments.
- Add comments explaining the unmount-during-fetch assertion.
- Validate a11y: assert the polite status region content for each state.
- Write code in: no source change unless a bug is found in
- Test and commit
- Run
npm run lint,npm test, andnpm run build. - Cover edge cases: non-array, empty, populated, rejected, and unmount-mid-load.
- Include the full
npm testoutput with invest coverage.
test: cover getinvoiceloadannouncement and marketplace load states
- Minimum 95 percent test coverage for impacted modules.
- Clear, reviewer-focused documentation.
- Timeframe: 96 hours.
- π¬ Join the Liquifact community on Discord for questions, reviews, and faster merges: https://discord.gg/JrGPH4V3
- β This is a GrantFox OSS / Official Campaign task and may be rewarded. When your PR is merged you'll be prompted to rate the project β if this issue and the maintainers helped you ship, we'd be grateful for a 5-star rating. Clear questions in Discord and tidy, well-tested PRs are the fastest path to a merge and a reward. ++++++
type: Feature title: "Add unit tests for the InvoiceListSkeleton row count and loading semantics" labels: type:test, area:loading-states, stack:nextjs, stack:react, stack:typescript, priority:low, MAYBE REWARDED, GRANTFOX OSS, OFFICIAL CAMPAIGN assignees: ''
components/InvoiceListSkeleton.jsx renders rows placeholder list items with aria-busy="true" and an "Loading investable invoices" label, but components/InvoiceListSkeleton.test.jsx is thin. This issue ensures the row count, default, and loading semantics are locked in so the skeleton stays in sync with the real card layout.
- Repository scope: Liquifact/Liquifact-frontend only.
- Assert the component renders exactly
rows<li>items and falls back to the documented default whenrowsis omitted. - Assert the list carries
aria-busy="true"and thearia-label"Loading investable invoices". - Assert each row contains the issuer/status and amount/yield/maturity placeholder blocks so a future card refactor cannot silently drop columns.
- Cover
rows={0}(no items, list still present).
- Fork the repo and create a branch
git checkout -b test/loading-states-14-skeleton-coverage- Implement changes
- Write code in: no source change unless a bug is found in
components/InvoiceListSkeleton.jsx. - Write comprehensive tests in: extend
components/InvoiceListSkeleton.test.jsxor createcomponents/InvoiceListSkeleton.contract.test.tsx. - Add documentation: none beyond test comments.
- Add comments clarifying the placeholder-structure assertions.
- Validate a11y: assert
aria-busyand the loading label.
- Write code in: no source change unless a bug is found in
- Test and commit
- Run
npm run lint,npm test, andnpm run build. - Cover edge cases: default rows, custom rows, and
rows={0}. - Include the full
npm testoutput.
test: cover invoicelistskeleton row count and loading semantics
- Minimum 95 percent test coverage for impacted modules.
- Clear, reviewer-focused documentation.
- Timeframe: 96 hours.
- π¬ Join the Liquifact community on Discord for questions, reviews, and faster merges: https://discord.gg/JrGPH4V3
- β This is a GrantFox OSS / Official Campaign task and may be rewarded. When your PR is merged you'll be prompted to rate the project β if this issue and the maintainers helped you ship, we'd be grateful for a 5-star rating. Clear questions in Discord and tidy, well-tested PRs are the fastest path to a merge and a reward. ++++++
type: Feature title: "Add unit tests for the Invoices page upload integration and header" labels: type:test, area:invoices, stack:nextjs, stack:react, stack:typescript, priority:medium, MAYBE REWARDED, GRANTFOX OSS, OFFICIAL CAMPAIGN assignees: ''
app/invoices/page.js renders the title, subtext, back link, a Connect Wallet button, and an <UploadZone />, but has no unit test, so a broken copy key, a missing UploadZone mount, or a regressed back-link focus-visible style would go unnoticed. This issue adds coverage for the page composition.
- Repository scope: Liquifact/Liquifact-frontend only.
- Assert the heading and subtext from
copy.invoicesrender and the "β LiquiFact" link points to/. - Assert the
UploadZoneform mounts (e.g. the#invoice-file-inputand#invoice-upload-btnare present). - Assert the back link carries the
focus-visibleoutline classes that distinguish this page from the others. - Keep the test resilient to
UploadZoneinternals by querying roles/ids rather than implementation details.
- Fork the repo and create a branch
git checkout -b test/invoices-15-page-coverage- Implement changes
- Write code in: no source change unless a bug is found in
app/invoices/page.js. - Write comprehensive tests in: create
app/invoices/page.test.tsx. - Add documentation: none beyond test comments.
- Add comments on how UploadZone is queried.
- Validate a11y: optional
jest-axesmoke check on the page.
- Write code in: no source change unless a bug is found in
- Test and commit
- Run
npm run lint,npm test, andnpm run build. - Cover edge cases: copy rendering, UploadZone mount, and back-link target.
- Include the full
npm testoutput.
test: cover the invoices page composition and uploadzone wiring
- Minimum 95 percent test coverage for impacted modules.
- Clear, reviewer-focused documentation.
- Timeframe: 96 hours.
- π¬ Join the Liquifact community on Discord for questions, reviews, and faster merges: https://discord.gg/JrGPH4V3
- β This is a GrantFox OSS / Official Campaign task and may be rewarded. When your PR is merged you'll be prompted to rate the project β if this issue and the maintainers helped you ship, we'd be grateful for a 5-star rating. Clear questions in Discord and tidy, well-tested PRs are the fastest path to a merge and a reward. ++++++
type: Feature title: "Make WalletStatus open the wallet install page safely via rel=noopener" labels: type:security, area:wallet, stack:nextjs, stack:react, stack:typescript, priority:medium, MAYBE REWARDED, GRANTFOX OSS, OFFICIAL CAMPAIGN assignees: ''
In the NO_WALLET state, components/WalletStatus.jsx opens the install page with window.open('https://www.stellar.org/wallets', '_blank') β without the noopener,noreferrer window features, the opened tab can access window.opener (reverse-tabnabbing), and an untrusted URL would flow straight through. This issue makes the external navigation safe and centralizes the allowed destination.
- Repository scope: Liquifact/Liquifact-frontend only.
- Pass
'noopener,noreferrer'as thewindow.openfeatures argument and null the returned reference'sopeneras a defensive fallback. - Move the install URL into a single trusted constant (or
app/copy/en.js) and validate it is anhttps:origin before opening. - Preserve the
WALLET_STATES.NO_WALLETbutton behaviour and accessibility. - Audit any other
window.open/external anchors introduced here for the same protection.
- Fork the repo and create a branch
git checkout -b security/wallet-16-safe-external-open- Implement changes
- Write code in: update
components/WalletStatus.jsx; add the URL constant where appropriate. - Write comprehensive tests in: create
components/WalletStatus.external.test.tsxβ mockwindow.openand assert the features string and URL. - Add documentation: note the external-link policy in
README.md. - Add comments explaining the tabnabbing mitigation.
- Validate security: confirm
noopeneris set and onlyhttps:URLs are opened.
- Write code in: update
- Test and commit
- Run
npm run lint,npm test, andnpm run build. - Cover edge cases: correct features argument and rejected non-https URL.
- Include the full
npm testoutput and a short threat note.
fix: open wallet install page with noopener to prevent tabnabbing
- Minimum 95 percent test coverage for impacted modules.
- Clear, reviewer-focused documentation.
- Timeframe: 96 hours.
- π¬ Join the Liquifact community on Discord for questions, reviews, and faster merges: https://discord.gg/JrGPH4V3
- β This is a GrantFox OSS / Official Campaign task and may be rewarded. When your PR is merged you'll be prompted to rate the project β if this issue and the maintainers helped you ship, we'd be grateful for a 5-star rating. Clear questions in Discord and tidy, well-tested PRs are the fastest path to a merge and a reward. ++++++
type: Feature title: "Bound and safely render the backend health JSON on the home page" labels: type:security, area:home, stack:nextjs, stack:react, stack:typescript, priority:medium, MAYBE REWARDED, GRANTFOX OSS, OFFICIAL CAMPAIGN assignees: ''
app/page.js takes whatever the backend returns from /health and dumps it via JSON.stringify(health, null, 2) into a <pre> with overflow-auto β an attacker-controlled or compromised backend could return an enormous payload (DoS via giant render) or deeply nested data that bloats the page. While React escapes text, the size and shape are unbounded. This issue bounds and sanitizes what is rendered.
- Repository scope: Liquifact/Liquifact-frontend only.
- Cap the rendered payload size (e.g. truncate the stringified output to a max length with an explicit "β¦(truncated)" marker) and limit object depth before display.
- Render a small set of recognized fields (e.g.
status,message,version) in a structured way and keep the raw payload behind a collapsible<details>rather than always-expanded. - Never render the response as HTML; keep it as text content only.
- Coordinate gracefully with the health-check helper if present, without duplicating fetch logic.
- Fork the repo and create a branch
git checkout -b security/home-17-bounded-health-render- Implement changes
- Write code in: update
app/page.js; optionally add alib/format/safeJson.jshelper. - Write comprehensive tests in: create
app/page.health-render.test.tsxand/orlib/format/safeJson.test.tsxβ assert truncation, depth limit, and recognized-field rendering. - Add documentation: note the bounded rendering in
README.md. - Add JSDoc on the formatting helper.
- Validate security: confirm large/nested payloads cannot blow up the DOM.
- Write code in: update
- Test and commit
- Run
npm run lint,npm test, andnpm run build. - Cover edge cases: huge string, deep nesting, and a normal healthy payload.
- Include the full
npm testoutput and a short note on the limits chosen.
fix: bound and safely render backend health json on the home page
- Minimum 95 percent test coverage for impacted modules.
- Clear, reviewer-focused documentation.
- Timeframe: 96 hours.
- π¬ Join the Liquifact community on Discord for questions, reviews, and faster merges: https://discord.gg/JrGPH4V3
- β This is a GrantFox OSS / Official Campaign task and may be rewarded. When your PR is merged you'll be prompted to rate the project β if this issue and the maintainers helped you ship, we'd be grateful for a 5-star rating. Clear questions in Discord and tidy, well-tested PRs are the fastest path to a merge and a reward. ++++++
type: Feature title: "Add a Dependabot config and lockfile-integrity check for the frontend" labels: type:security, area:dependencies, stack:nextjs, stack:react, stack:typescript, priority:low, MAYBE REWARDED, GRANTFOX OSS, OFFICIAL CAMPAIGN assignees: ''
The repo pins next, react, and a set of dev tooling in package.json with a committed package-lock.json, but there is no .github/dependabot.yml and CI (.github/workflows/ci.yml) runs npm ci without verifying the lockfile is in sync. Without automated updates, security patches for Next.js/React/Playwright land late. This issue adds Dependabot and a lockfile-drift guard.
- Repository scope: Liquifact/Liquifact-frontend only.
- Add
.github/dependabot.ymlconfiguring weeklynpmecosystem updates (andgithub-actionsecosystem) grouped sensibly to limit PR noise. - Add a CI step asserting
package-lock.jsonis in sync (e.g.npm cifails on drift, or an explicitnpm install --package-lock-onlydiff check) so PRs cannot merge with a stale lockfile. - Keep existing lint/test jobs intact.
- Document how to review and merge Dependabot PRs against the campaign workflow.
- Fork the repo and create a branch
git checkout -b security/dependencies-18-dependabot-lockfile- Implement changes
- Write code in: create
.github/dependabot.yml; update.github/workflows/ci.yml. - Write comprehensive tests in: validate via a CI run on the PR; add a documented local lockfile-drift command.
- Add documentation: add a "Dependency updates" subsection to
README.md. - Add comments in the workflow explaining the lockfile gate.
- Validate security: ensure the config does not auto-merge without review.
- Write code in: create
- Test and commit
- Run
npm run lint,npm test,npm run build, andnpm cilocally. - Cover edge cases: clean lockfile passes; an intentionally drifted lockfile fails CI.
- Include the CI run link/output.
ci: add dependabot config and lockfile-integrity check
- Minimum 95 percent test coverage for impacted modules.
- Clear, reviewer-focused documentation.
- Timeframe: 96 hours.
- π¬ Join the Liquifact community on Discord for questions, reviews, and faster merges: https://discord.gg/JrGPH4V3
- β This is a GrantFox OSS / Official Campaign task and may be rewarded. When your PR is merged you'll be prompted to rate the project β if this issue and the maintainers helped you ship, we'd be grateful for a 5-star rating. Clear questions in Discord and tidy, well-tested PRs are the fastest path to a merge and a reward. ++++++
type: Feature title: "Fix the inaccurate README project structure, component props, and design tokens" labels: type:docs, area:readme, stack:nextjs, stack:react, stack:typescript, priority:medium, MAYBE REWARDED, GRANTFOX OSS, OFFICIAL CAMPAIGN assignees: ''
README.md is out of sync with the code in several places: the "Project structure" tree omits components/, app/copy/, and the test/Playwright setup; the CI/CD section lists "Lint" and "Build" but the workflow actually runs lint and npm test (accessibility), not build; the WalletStatus props are documented as a status prop it does not accept; ErrorBanner props are wrong (it has variant/title/description/details/actionLabel/onAction/previewLabel, not message); and the Design Tokens claim Geist is imported via @fontsource/geist when app/layout.js uses next/font/google. This issue makes the README accurate.
- Repository scope: Liquifact/Liquifact-frontend only.
- Update the project-structure tree to reflect real folders/files (
components/,app/copy/en.js,tests/,jest.config.js,playwright.config.mjs,next.config.mjs). - Fix the CI/CD section to match
.github/workflows/ci.yml(lint + accessibility tests). - Correct the
WalletStatusandErrorBannerprop docs against their real signatures. - Fix the Design Tokens section: Geist via
next/font/google, and reconcile the listed color hexes with the actual slate/cyan palette.
- Fork the repo and create a branch
git checkout -b docs/readme-19-accuracy-fixes- Implement changes
- Write code in: docs-only.
- Write comprehensive tests in: not applicable; cross-check every claim against source.
- Add documentation: update
README.md. - Add a short "last verified against commit" note.
- Validate accuracy by diffing each statement against the corresponding file.
- Test and commit
- Run
npm run lintandnpm run buildto confirm nothing breaks. - Cover edge cases: every documented prop/path exists in the code.
- Include a rendered preview of the corrected sections.
docs: correct readme structure, component props, and design tokens
- Minimum 95 percent test coverage for impacted modules.
- Clear, reviewer-focused documentation.
- Timeframe: 96 hours.
- π¬ Join the Liquifact community on Discord for questions, reviews, and faster merges: https://discord.gg/JrGPH4V3
- β This is a GrantFox OSS / Official Campaign task and may be rewarded. When your PR is merged you'll be prompted to rate the project β if this issue and the maintainers helped you ship, we'd be grateful for a 5-star rating. Clear questions in Discord and tidy, well-tested PRs are the fastest path to a merge and a reward. ++++++
type: Feature title: "Add an accessibility statement documenting the app's a11y commitments" labels: type:docs, area:accessibility, stack:nextjs, stack:react, stack:typescript, priority:low, MAYBE REWARDED, GRANTFOX OSS, OFFICIAL CAMPAIGN assignees: ''
The codebase invests heavily in accessibility β jest-axe wired in jest.setup.js, role="status"/aria-live regions in components/UploadZone.jsx, components/WalletStatus.jsx, and app/invest/page.js, and a CI step literally named "Test Accessibility" in .github/workflows/ci.yml β but there is no document explaining the standards targeted, the testing approach, or the known gaps (e.g. disabled filter buttons, motion handling). This issue writes an accessibility statement.
- Repository scope: Liquifact/Liquifact-frontend only.
- Create
docs/accessibility.mdstating the target standard (WCAG 2.1 AA), the keyboard/screen-reader patterns used, and howjest-axeis run in CI. - List known limitations and link to the relevant components/issues (disabled "Soon" filters, reduced-motion handling, focus styles).
- Provide a contributor checklist for keeping new UI accessible (labels, landmarks, focus, live regions, contrast).
- Link the statement from
README.md.
- Fork the repo and create a branch
git checkout -b docs/accessibility-20-a11y-statement- Implement changes
- Write code in: docs-only.
- Write comprehensive tests in: not applicable; ensure referenced patterns exist in code.
- Add documentation: create
docs/accessibility.mdand link fromREADME.md. - Add a maintenance note on updating the statement when a11y issues close.
- Validate accuracy against the current components and CI.
- Test and commit
- Run
npm run lintandnpm run build. - Cover edge cases: every referenced pattern and CI step is accurate.
- Include a rendered preview of the new doc.
docs: add accessibility statement and contributor checklist
- Minimum 95 percent test coverage for impacted modules.
- Clear, reviewer-focused documentation.
- Timeframe: 96 hours.
- π¬ Join the Liquifact community on Discord for questions, reviews, and faster merges: https://discord.gg/JrGPH4V3
- β This is a GrantFox OSS / Official Campaign task and may be rewarded. When your PR is merged you'll be prompted to rate the project β if this issue and the maintainers helped you ship, we'd be grateful for a 5-star rating. Clear questions in Discord and tidy, well-tested PRs are the fastest path to a merge and a reward. ++++++
type: Feature title: "Document environment variables and add the missing test/test:e2e to the README scripts" labels: type:docs, area:configuration, stack:nextjs, stack:react, stack:typescript, priority:low, MAYBE REWARDED, GRANTFOX OSS, OFFICIAL CAMPAIGN assignees: ''
.env.local.example defines NEXT_PUBLIC_API_URL (and a commented NEXT_PUBLIC_STELLAR_NETWORK), but README.md only mentions NEXT_PUBLIC_API_URL in passing and its Development command table omits npm test even though package.json defines it (and CI runs it). This issue creates a clear environment-variable reference and aligns the documented scripts with the real ones.
- Repository scope: Liquifact/Liquifact-frontend only.
- Add an "Environment variables" table to
README.mdlisting each var, whether it is required, its default, and what reads it (link toapp/page.jsfor the API URL andWALLET_INTEGRATION_CONTRACT.mdfor the network). - Add
npm test(Jest/jsdom) to the Development command table alongsidetest:e2e. - Ensure
.env.local.exampleand the README stay consistent (same var names/defaults). - Note that
NEXT_PUBLIC_*values are exposed to the client and must not hold secrets.
- Fork the repo and create a branch
git checkout -b docs/configuration-21-env-and-scripts- Implement changes
- Write code in: docs-only; optionally clarify comments in
.env.local.example. - Write comprehensive tests in: not applicable; verify documented defaults match the code fallbacks.
- Add documentation: update
README.mdand.env.local.example. - Add a security note on
NEXT_PUBLIC_exposure. - Validate accuracy against
package.jsonscripts and the env reads in code.
- Write code in: docs-only; optionally clarify comments in
- Test and commit
- Run
npm run lint,npm test, andnpm run build. - Cover edge cases: documented defaults match
app/page.js; every script in the table exists. - Include a rendered preview of the env section.
docs: document environment variables and align readme scripts
- Minimum 95 percent test coverage for impacted modules.
- Clear, reviewer-focused documentation.
- Timeframe: 96 hours.
- π¬ Join the Liquifact community on Discord for questions, reviews, and faster merges: https://discord.gg/JrGPH4V3
- β This is a GrantFox OSS / Official Campaign task and may be rewarded. When your PR is merged you'll be prompted to rate the project β if this issue and the maintainers helped you ship, we'd be grateful for a 5-star rating. Clear questions in Discord and tidy, well-tested PRs are the fastest path to a merge and a reward. ++++++
type: Feature title: "Give the toast close button reliable Escape-to-dismiss and focus handling" labels: type:a11y, area:toast, stack:nextjs, stack:react, stack:typescript, priority:medium, MAYBE REWARDED, GRANTFOX OSS, OFFICIAL CAMPAIGN assignees: ''
Toasts in components/ToastProvider.jsx can only be dismissed by clicking "Close" or waiting for the timer; there is no keyboard shortcut to dismiss, and hovering pauses the timer but focusing (keyboard equivalent of hover) does not β so a keyboard user reading a toast can have it disappear mid-read. This issue adds keyboard parity: pause on focus, dismiss on Escape, and sensible focus return.
- Repository scope: Liquifact/Liquifact-frontend only.
- Pause/resume the auto-dismiss timer on
focus/blurof the toast (mirroring the existingmouseenter/mouseleavepause/resume) so focusing a toast does not let it vanish. - Allow
Escapeto dismiss the focused toast. - Ensure the "Close" button and toast are reachable in a sensible tab order and that focus moves to a safe element after dismissal (no focus loss to
body). - Keep the
role="status"/aria-live="polite"region and all existing variant styling.
- Fork the repo and create a branch
git checkout -b a11y/toast-22-keyboard-dismiss- Implement changes
- Write code in: update
components/ToastProvider.jsx. - Write comprehensive tests in: create
components/ToastProvider.keyboard.test.tsxusinguser-eventand fake timers β assert focus pauses the timer, Escape dismisses, and focus return. - Add documentation: note the keyboard behaviour in
README.md. - Add comments on the focus/blur pause parity.
- Validate a11y: no
jest-axeviolations and keyboard-operable dismissal.
- Write code in: update
- Test and commit
- Run
npm run lint,npm test, andnpm run build. - Cover edge cases: focus-pause, Escape dismiss, and focus return after close.
- Include the full
npm testoutput.
fix: add escape-to-dismiss and focus pause to toast notifications
- Minimum 95 percent test coverage for impacted modules.
- Clear, reviewer-focused documentation.
- Timeframe: 96 hours.
- π¬ Join the Liquifact community on Discord for questions, reviews, and faster merges: https://discord.gg/JrGPH4V3
- β This is a GrantFox OSS / Official Campaign task and may be rewarded. When your PR is merged you'll be prompted to rate the project β if this issue and the maintainers helped you ship, we'd be grateful for a 5-star rating. Clear questions in Discord and tidy, well-tested PRs are the fastest path to a merge and a reward. ++++++
type: Feature title: "Consolidate the duplicate WalletProvider and WalletContext into a single wallet module" labels: type:refactor, area:wallet, stack:nextjs, stack:react, stack:typescript, priority:high, MAYBE REWARDED, GRANTFOX OSS, OFFICIAL CAMPAIGN assignees: ''
The repo ships two separate, incompatible wallet context implementations: components/WalletProvider.jsx exposes useWallet() returning { state, walletData, connect, disconnect } with localStorage rehydration, while components/WalletContext.jsx exposes useWallet() returning { walletState, walletData, error, connectWallet, disconnectWallet }. app/layout.js mounts WalletProvider from WalletContext, but consumers like app/invest/[id]/page.js destructure walletState/connectWallet. Having two providers with the same hook name is a latent footgun. This issue consolidates them into one canonical module.
- Repository scope: Liquifact/Liquifact-frontend only.
- Pick one canonical file (keep the persistence-capable
WalletProvider.jsximplementation) and delete or re-export the other so only oneuseWallet()/WALLET_STATESexists. - Settle on a single hook shape and update every consumer (
app/invest/[id]/page.js,app/layout.js, and any@/components/WalletContextimport) to match. - Preserve localStorage rehydration, toast side effects, and
WALLET_STATES. - Update all imports app-wide; no dangling references to the removed file.
- Fork the repo and create a branch
git checkout -b refactor/wallet-01-consolidate-providers- Implement changes
- Write code in: keep
components/WalletProvider.jsx; remove/redirectcomponents/WalletContext.jsx; updateapp/layout.jsandapp/invest/[id]/page.js. - Write comprehensive tests in: create
components/WalletProvider.consolidation.test.tsxβ assert a single hook shape and that all consumers resolve it. - Add documentation: update
README.mdandWALLET_INTEGRATION_CONTRACT.mdto reference one provider. - Add JSDoc on the canonical hook/provider.
- Validate: grep confirms no
WalletContextimports remain.
- Write code in: keep
- Test and commit
- Run
npm run lint,npm test, andnpm run build. - Cover edge cases: every consumer compiles and the hook returns one stable shape.
- Include the full
npm testoutput and a before/after import inventory.
refactor: consolidate duplicate wallet providers into one module
- Minimum 95 percent test coverage for impacted modules.
- Clear, reviewer-focused documentation.
- Timeframe: 96 hours.
- π¬ Join the Liquifact community on Discord for questions, reviews, and faster merges: https://discord.gg/JrGPH4V3
- β This is a GrantFox OSS / Official Campaign task and may be rewarded. When your PR is merged you'll be prompted to rate the project β if this issue and the maintainers helped you ship, we'd be grateful for a 5-star rating. Clear questions in Discord and tidy, well-tested PRs are the fastest path to a merge and a reward. ++++++
type: Feature title: "Fix WalletStatus to import Button and use the correct getStateConfig keys" labels: type:refactor, area:wallet, stack:nextjs, stack:react, stack:typescript, priority:high, MAYBE REWARDED, GRANTFOX OSS, OFFICIAL CAMPAIGN assignees: ''
components/WalletStatus.jsx renders <Button variant={config.variant} loading={config.loading} ...> but (1) never imports Button from components/Button.jsx, and (2) getStateConfig returns buttonVariant/buttonText keys, not variant/loading β so config.variant and config.loading are always undefined. The component as written would throw at runtime. This issue wires the import and aligns the prop names so the wallet button renders the right variant and loading state.
- Repository scope: Liquifact/Liquifact-frontend only.
- Add
import Button from './Button';(and remove the leftover inline spinner SVG now thatButtonrenders its ownSpinnervialoading). - Map
getStateConfig'sbuttonVariantto theButtonvariantprop and deriveloadingfrom theconnectingstate. - Reconcile
WalletStatus's localWALLET_STATES/mock with the canonical wallet provider once consolidated (coordinate with the provider-unification work). - Keep the
sr-onlyrole="status"live region andaria-describedbyhelper text intact.
- Fork the repo and create a branch
git checkout -b refactor/wallet-02-fix-button-config- Implement changes
- Write code in: update
components/WalletStatus.jsx. - Write comprehensive tests in: extend
components/WalletStatus.test.tsxβ assert each state renders the correct Button variant and loading spinner. - Add documentation: note the fix in
README.mdUI section. - Add JSDoc/comments on the config-to-prop mapping.
- Validate a11y: connecting state sets
aria-busyvia Button.
- Write code in: update
- Test and commit
- Run
npm run lint,npm test, andnpm run build. - Cover edge cases: every
WALLET_STATESvariant and the connecting spinner. - Include the full
npm testoutput.
fix: import button and align getstateconfig keys in walletstatus
- Minimum 95 percent test coverage for impacted modules.
- Clear, reviewer-focused documentation.
- Timeframe: 96 hours.
- π¬ Join the Liquifact community on Discord for questions, reviews, and faster merges: https://discord.gg/JrGPH4V3
- β This is a GrantFox OSS / Official Campaign task and may be rewarded. When your PR is merged you'll be prompted to rate the project β if this issue and the maintainers helped you ship, we'd be grateful for a 5-star rating. Clear questions in Discord and tidy, well-tested PRs are the fastest path to a merge and a reward. ++++++
type: Feature title: "Repair the broken Invest page: undefined filter state and missing InvoiceSearch import" labels: type:refactor, area:invest, stack:nextjs, stack:react, stack:typescript, priority:high, MAYBE REWARDED, GRANTFOX OSS, OFFICIAL CAMPAIGN assignees: ''
app/invest/page.js is currently broken in several ways: getInvoiceLoadAnnouncement references filterActive and filteredCount that are never defined; the JSX renders <InvoiceSearch /> without importing it; and the file both import { loadMockInvoices } from "./lib" and redefines a local loadMockInvoices plus a duplicate MOCK_INVOICES. This issue cleans up the merge artifacts so the page compiles and the search wiring actually works.
- Repository scope: Liquifact/Liquifact-frontend only.
- Remove the duplicate local
MOCK_INVOICESandloadMockInvoices; rely solely on the imports fromapp/invest/lib.js. - Import
InvoiceSearchfromcomponents/InvoiceSearch.jsx. - Fix
getInvoiceLoadAnnouncementso it does not reference undefinedfilterActive/filteredCount; either pass the filter state in or compute the filtered count fromsearchQuery/debouncedQueryalready in state. - Actually apply
debouncedQueryto filtervisibleInvoicesby issuer (the state exists but is unused), and keep the polite status announcement accurate.
- Fork the repo and create a branch
git checkout -b refactor/invest-03-fix-broken-page- Implement changes
- Write code in: update
app/invest/page.js. - Write comprehensive tests in: extend
app/invest/page.test.jsxβ assert search filters the list and the announcement reports the filtered count. - Add documentation: note the search/announcement behaviour in
README.md. - Add comments explaining the announcement signature.
- Validate a11y: filtered count announced via the polite region.
- Write code in: update
- Test and commit
- Run
npm run lint,npm test, andnpm run build. - Cover edge cases: no matches, cleared query, and full list.
- Include the full
npm testoutput.
fix: repair undefined filter state and missing imports on invest page
- Minimum 95 percent test coverage for impacted modules.
- Clear, reviewer-focused documentation.
- Timeframe: 96 hours.
- π¬ Join the Liquifact community on Discord for questions, reviews, and faster merges: https://discord.gg/JrGPH4V3
- β This is a GrantFox OSS / Official Campaign task and may be rewarded. When your PR is merged you'll be prompted to rate the project β if this issue and the maintainers helped you ship, we'd be grateful for a 5-star rating. Clear questions in Discord and tidy, well-tested PRs are the fastest path to a merge and a reward. ++++++
type: Feature title: "Fix the missing NavMenu import on the home page" labels: type:refactor, area:home, stack:nextjs, stack:react, stack:typescript, priority:high, MAYBE REWARDED, GRANTFOX OSS, OFFICIAL CAMPAIGN assignees: ''
app/page.js renders <NavMenu /> at the top of the layout but never imports it, so the home page throws a NavMenu is not defined ReferenceError at render. This issue adds the missing import and verifies the home page mounts the shared navigation.
- Repository scope: Liquifact/Liquifact-frontend only.
- Add
import NavMenu from "../components/NavMenu";(matching the path style already used byapp/invoices/page.js). - Confirm
NavMenuis the single header for the home page and there is no leftover duplicate header markup. - Keep the existing hero, CTA cards, and API-status panel intact.
- Verify no hydration warnings from the lazy
WalletStatusLazyinsideNavMenu.
- Fork the repo and create a branch
git checkout -b refactor/home-04-fix-navmenu-import- Implement changes
- Write code in: update
app/page.js. - Write comprehensive tests in: create
app/page.navmenu.test.tsxβ assert the navigation landmark renders and links to Home/Invoices/Invest exist. - Add documentation: note the home page header composition in
README.md. - Add a comment referencing the shared NavMenu.
- Validate a11y: a single
<nav>/<header>landmark with an accessible name.
- Write code in: update
- Test and commit
- Run
npm run lint,npm test, andnpm run build. - Cover edge cases: NavMenu mounts, links resolve.
- Include the full
npm testoutput.
fix: import navmenu on the home page
- Minimum 95 percent test coverage for impacted modules.
- Clear, reviewer-focused documentation.
- Timeframe: 96 hours.
- π¬ Join the Liquifact community on Discord for questions, reviews, and faster merges: https://discord.gg/JrGPH4V3
- β This is a GrantFox OSS / Official Campaign task and may be rewarded. When your PR is merged you'll be prompted to rate the project β if this issue and the maintainers helped you ship, we'd be grateful for a 5-star rating. Clear questions in Discord and tidy, well-tested PRs are the fastest path to a merge and a reward. ++++++
type: Feature title: "Fix the Invoices page: missing Link import and replace the dead static Connect Wallet button" labels: type:refactor, area:invoices, stack:nextjs, stack:react, stack:typescript, priority:high, MAYBE REWARDED, GRANTFOX OSS, OFFICIAL CAMPAIGN assignees: ''
app/invoices/page.js imports NavMenu but never renders it, instead hand-rolling a header that uses <Link> without importing it (a Link is not defined ReferenceError) and a static "Connect Wallet" <button> that does nothing. This issue fixes the broken import and replaces the dead header with the shared NavMenu.
- Repository scope: Liquifact/Liquifact-frontend only.
- Replace the bespoke header with the imported
<NavMenu />so the page uses the same navigation and real wallet UI as the home page. - Remove the dead static "Connect Wallet" button (it uses
copy.invoices.connectWalletand has no handler). - If the bespoke header is kept for any reason, add the missing
import Link from "next/link";. - Preserve the page title/subtext and the
<UploadZone />mount.
- Fork the repo and create a branch
git checkout -b refactor/invoices-05-fix-header- Implement changes
- Write code in: update
app/invoices/page.js. - Write comprehensive tests in: extend
app/invoices/page.test.tsxβ assert NavMenu renders and no stray static Connect Wallet button remains. - Add documentation: note the unified header in
README.md. - Add a comment referencing NavMenu reuse.
- Validate a11y: one header landmark; back link is keyboard focusable.
- Write code in: update
- Test and commit
- Run
npm run lint,npm test, andnpm run build. - Cover edge cases: header renders, UploadZone mounts, no dead button.
- Include the full
npm testoutput.
fix: use navmenu and import link on the invoices page
- Minimum 95 percent test coverage for impacted modules.
- Clear, reviewer-focused documentation.
- Timeframe: 96 hours.
- π¬ Join the Liquifact community on Discord for questions, reviews, and faster merges: https://discord.gg/JrGPH4V3
- β This is a GrantFox OSS / Official Campaign task and may be rewarded. When your PR is merged you'll be prompted to rate the project β if this issue and the maintainers helped you ship, we'd be grateful for a 5-star rating. Clear questions in Discord and tidy, well-tested PRs are the fastest path to a merge and a reward. ++++++
type: Feature title: "Fix ErrorBanner so it honors actionLabel and the error variant label" labels: type:refactor, area:error-banner, stack:nextjs, stack:react, stack:typescript, priority:high, MAYBE REWARDED, GRANTFOX OSS, OFFICIAL CAMPAIGN assignees: ''
components/ErrorBanner.jsx accepts an actionLabel prop but the action button hard-codes the text "Retry", ignoring actionLabel entirely. Its variantLabel only special-cases "validation", so callers passing variant="error" (e.g. app/invest/page.js and app/invest/[id]/page.js) get the misleading label "Server error". This issue fixes both so the component renders what callers ask for.
- Repository scope: Liquifact/Liquifact-frontend only.
- Render
{actionLabel}(not the literal "Retry") inside the actionButton, keepingonActionwired. - Map
variantto a correct label, including an"error"case, so the displayed label matches the caller's intent (or document the allowed variant set). - Keep
previewLabel,role="alert"/aria-live="assertive", and conditionaldetailsbehaviour unchanged. - Audit existing callers and adjust any that now show a different (correct) label.
- Fork the repo and create a branch
git checkout -b refactor/error-banner-06-actionlabel-variant- Implement changes
- Write code in: update
components/ErrorBanner.jsx. - Write comprehensive tests in: create
components/ErrorBanner.action.test.tsxβ assert the rendered button text equalsactionLabeland the variant label matrix. - Add documentation: document the variant set in
COMPONENTS.md. - Add JSDoc on the props.
- Validate a11y: action button has an accessible name from
actionLabel.
- Write code in: update
- Test and commit
- Run
npm run lint,npm test, andnpm run build. - Cover edge cases: custom actionLabel, no actionLabel, server/validation/error variants.
- Include the full
npm testoutput.
fix: render actionlabel and correct variant label in errorbanner
- Minimum 95 percent test coverage for impacted modules.
- Clear, reviewer-focused documentation.
- Timeframe: 96 hours.
- π¬ Join the Liquifact community on Discord for questions, reviews, and faster merges: https://discord.gg/JrGPH4V3
- β This is a GrantFox OSS / Official Campaign task and may be rewarded. When your PR is merged you'll be prompted to rate the project β if this issue and the maintainers helped you ship, we'd be grateful for a 5-star rating. Clear questions in Discord and tidy, well-tested PRs are the fastest path to a merge and a reward. ++++++
type: Feature title: "Define the missing API_URL constant in UploadZone before the upload fetch" labels: type:refactor, area:upload, stack:nextjs, stack:react, stack:typescript, priority:high, MAYBE REWARDED, GRANTFOX OSS, OFFICIAL CAMPAIGN assignees: ''
handleSubmit in components/UploadZone.jsx calls fetch(${API_URL}/invoices, ...), but API_URL is never imported or declared in the module, so submitting an invoice throws API_URL is not defined. Other files (e.g. app/page.js) read process.env.NEXT_PUBLIC_API_URL with a localhost fallback. This issue defines the base URL consistently so the upload request actually fires.
- Repository scope: Liquifact/Liquifact-frontend only.
- Derive the base URL from
process.env.NEXT_PUBLIC_API_URLwith thehttp://localhost:3001fallback, matching the home page, ideally via a shared helper inlib/api. - Keep the multipart
FormDatabody, the!res.okerror mapping, thetokenizingβsuccesstransition, and existing status copy unchanged. - Ensure the e2e toast spec in
tests/toast.spec.jsxstill passes (mock the network where needed). - Add an
AbortControllerso an unmount mid-upload does not set state on an unmounted component.
- Fork the repo and create a branch
git checkout -b refactor/upload-07-define-api-url- Implement changes
- Write code in: update
components/UploadZone.jsx; optionally add a shared base-URL helper inlib/api. - Write comprehensive tests in: extend
components/UploadZone.test.jsxβ mockfetch, assert the request URL and success/error transitions. - Add documentation: note the env var usage in
README.md. - Add JSDoc/comments on the URL source.
- Validate security: only the configured origin is used for the request.
- Write code in: update
- Test and commit
- Run
npm run lint,npm test,npm run build, andnpm run test:e2e. - Cover edge cases: success, non-2xx, network error, and unmount mid-upload.
- Include the full
npm testoutput and e2e confirmation.
fix: define api_url base in uploadzone submit handler
- Minimum 95 percent test coverage for impacted modules.
- Clear, reviewer-focused documentation.
- Timeframe: 96 hours.
- π¬ Join the Liquifact community on Discord for questions, reviews, and faster merges: https://discord.gg/JrGPH4V3
- β This is a GrantFox OSS / Official Campaign task and may be rewarded. When your PR is merged you'll be prompted to rate the project β if this issue and the maintainers helped you ship, we'd be grateful for a 5-star rating. Clear questions in Discord and tidy, well-tested PRs are the fastest path to a merge and a reward. ++++++
type: Feature title: "Align the invoice-detail Fund button with the consolidated wallet hook API" labels: type:refactor, area:invest, stack:nextjs, stack:react, stack:typescript, priority:high, MAYBE REWARDED, GRANTFOX OSS, OFFICIAL CAMPAIGN assignees: ''
app/invest/[id]/page.js destructures { walletState, connectWallet } from useWallet(), but the canonical persistence-capable provider in components/WalletProvider.jsx returns { state, walletData, connect, disconnect }. Depending on which provider is mounted, walletState/connectWallet are undefined, so the "Fund this invoice" gating and the connect call silently break. This issue aligns the detail page with one hook shape.
- Repository scope: Liquifact/Liquifact-frontend only.
- Destructure the hook fields that actually exist on the canonical provider and update
handleFund/isFundingDisabledaccordingly. - Import
WALLET_STATESfrom the same module that backsuseWallet()(avoid mixing@/components/WalletContextandWalletProvider). - Keep the disabled-while-connecting and disconnected-prompts-connect behaviour and the educational disclaimer.
- Coordinate with the provider-consolidation work so the import path is stable.
- Fork the repo and create a branch
git checkout -b refactor/invest-08-detail-wallet-hook- Implement changes
- Write code in: update
app/invest/[id]/page.js. - Write comprehensive tests in: extend
app/invest/[id]/page.test.tsxβ assert the Fund button prompts connect when disconnected and disables while connecting. - Add documentation: note the funding-intent flow in
README.md. - Add comments on the wallet gating.
- Validate a11y: the Fund button keeps a clear accessible name.
- Write code in: update
- Test and commit
- Run
npm run lint,npm test, andnpm run build. - Cover edge cases: disconnected, connecting, connected, and no-wallet states.
- Include the full
npm testoutput.
fix: align invoice-detail fund button with the wallet hook api
- Minimum 95 percent test coverage for impacted modules.
- Clear, reviewer-focused documentation.
- Timeframe: 96 hours.
- π¬ Join the Liquifact community on Discord for questions, reviews, and faster merges: https://discord.gg/JrGPH4V3
- β This is a GrantFox OSS / Official Campaign task and may be rewarded. When your PR is merged you'll be prompted to rate the project β if this issue and the maintainers helped you ship, we'd be grateful for a 5-star rating. Clear questions in Discord and tidy, well-tested PRs are the fastest path to a merge and a reward. ++++++
type: Feature title: "Remove duplicated MOCK_INVOICES by sourcing all mock data from app/invest/lib.js" labels: type:refactor, area:invest, stack:nextjs, stack:react, stack:typescript, priority:medium, MAYBE REWARDED, GRANTFOX OSS, OFFICIAL CAMPAIGN assignees: ''
The same MOCK_INVOICES array and a loadMockInvoices helper are defined twice β in app/invest/lib.js (the canonical, test-aware version reading window.__TEST_MOCK_INVOICES__) and again inline in app/invest/page.js. Duplicated fixtures drift apart over time and the detail-by-id lookup in lib.js already depends on the canonical array. This issue removes the inline copy so there is one source of truth.
- Repository scope: Liquifact/Liquifact-frontend only.
- Delete the inline
MOCK_INVOICES/loadMockInvoices/DEV_DELAYfromapp/invest/page.jsand use only the exports fromapp/invest/lib.js. - Confirm
getInvoiceByIdinlib.jsresolves the detail route against the same array. - No behaviour change to the rendered marketplace or the test hook
window.__TEST_MOCK_INVOICES__. - Add a short comment marking
lib.jsas the single mock-data source until the API client lands.
- Fork the repo and create a branch
git checkout -b refactor/invest-09-dedupe-mock-data- Implement changes
- Write code in: update
app/invest/page.js; keepapp/invest/lib.jscanonical. - Write comprehensive tests in: extend
app/invest/page.test.jsxβ assert the list renders from the shared fixture. - Add documentation: note the single mock source in
docs/api-integration.md. - Add comments on the test hook.
- Validate: grep confirms only one
MOCK_INVOICESdefinition.
- Write code in: update
- Test and commit
- Run
npm run lint,npm test, andnpm run build. - Cover edge cases: list render, detail lookup, and the test hook override.
- Include the full
npm testoutput.
refactor: single-source mock invoices from app/invest/lib.js
- Minimum 95 percent test coverage for impacted modules.
- Clear, reviewer-focused documentation.
- Timeframe: 96 hours.
- π¬ Join the Liquifact community on Discord for questions, reviews, and faster merges: https://discord.gg/JrGPH4V3
- β This is a GrantFox OSS / Official Campaign task and may be rewarded. When your PR is merged you'll be prompted to rate the project β if this issue and the maintainers helped you ship, we'd be grateful for a 5-star rating. Clear questions in Discord and tidy, well-tested PRs are the fastest path to a merge and a reward. ++++++
type: Feature title: "Migrate WalletStatus and remaining buttons to the shared Button focus-visible styles" labels: type:refactor, area:components, stack:nextjs, stack:react, stack:typescript, priority:medium, MAYBE REWARDED, GRANTFOX OSS, OFFICIAL CAMPAIGN assignees: ''
A shared components/Button.jsx exists with a unified focus-visible:outline treatment, yet several buttons still use the older divergent focus:ring pattern: the home API-status button in app/page.js, the Fund button in app/invest/[id]/page.js, the disabled filter buttons in app/invest/page.js, and the inline getButtonStyles in components/WalletStatus.jsx. This issue completes the migration so focus styling is consistent everywhere.
- Repository scope: Liquifact/Liquifact-frontend only.
- Replace the remaining hand-styled buttons with
<Button>(or its variants), deletinggetButtonStylesfromWalletStatus. - Ensure every interactive button uses the cyan
focus-visible:outlinefromButtonrather thanfocus:ring. - No visual regression beyond the intentional focus-style unification; preserve disabled/loading semantics.
- Keep the disabled filter buttons' "coming soon" affordance (coordinate with any a11y work on those controls).
- Fork the repo and create a branch
git checkout -b refactor/components-10-finish-button-migration- Implement changes
- Write code in: update
app/page.js,app/invest/[id]/page.js,app/invest/page.js,components/WalletStatus.jsx. - Write comprehensive tests in: extend
components/Button.test.tsxand add focus-style assertions where buttons were migrated. - Add documentation: update
COMPONENTS.mdButton section. - Add comments where a bespoke button was replaced.
- Validate a11y: focus outline meets contrast across variants.
- Write code in: update
- Test and commit
- Run
npm run lint,npm test, andnpm run build. - Cover edge cases: each variant, disabled, loading, and focus visibility.
- Include the full
npm testoutput and a before/after note.
refactor: migrate remaining buttons to the shared button component
- Minimum 95 percent test coverage for impacted modules.
- Clear, reviewer-focused documentation.
- Timeframe: 96 hours.
- π¬ Join the Liquifact community on Discord for questions, reviews, and faster merges: https://discord.gg/JrGPH4V3
- β This is a GrantFox OSS / Official Campaign task and may be rewarded. When your PR is merged you'll be prompted to rate the project β if this issue and the maintainers helped you ship, we'd be grateful for a 5-star rating. Clear questions in Discord and tidy, well-tested PRs are the fastest path to a merge and a reward. ++++++
type: Feature title: "Add an aria-label and screen-reader title to the UploadZone Spinner SVG" labels: type:a11y, area:upload, stack:nextjs, stack:react, stack:typescript, priority:low, MAYBE REWARDED, GRANTFOX OSS, OFFICIAL CAMPAIGN assignees: ''
The Spinner components in components/UploadZone.jsx, components/Spinner.jsx, and the inline SVG fallback are marked aria-hidden="true". That is fine when wrapped in a role="status" text region, but the submit button renders a bare <Spinner /> next to text with no status text of its own, so assistive tech announces only the static button label during processing. This issue ensures the loading state is consistently perceivable.
- Repository scope: Liquifact/Liquifact-frontend only.
- Confirm every spinner usage is paired with an
aria-busyhost or arole="status"text node; where a spinner stands alone, add an accessible loading label. - Keep decorative spinners
aria-hiddenonly when their loading meaning is conveyed elsewhere. - Do not introduce double announcements (avoid both
aria-busyand a redundant live region announcing simultaneously). - Respect
prefers-reduced-motionalready handled globally.
- Fork the repo and create a branch
git checkout -b a11y/upload-11-spinner-label- Implement changes
- Write code in: update
components/UploadZone.jsxandcomponents/Spinner.jsxas needed. - Write comprehensive tests in: extend
components/UploadZone.test.jsxβ assert a loading state is announced duringuploading/tokenizing. - Add documentation: note the spinner a11y pattern in
docs/accessibility.md. - Add comments on the chosen pattern.
- Validate a11y with
jest-axeon a loading render.
- Write code in: update
- Test and commit
- Run
npm run lint,npm test, andnpm run build. - Cover edge cases: standalone spinner and spinner-in-status-region.
- Include the full
npm testoutput.
fix: give loading spinners an accessible name
- Minimum 95 percent test coverage for impacted modules.
- Clear, reviewer-focused documentation.
- Timeframe: 96 hours.
- π¬ Join the Liquifact community on Discord for questions, reviews, and faster merges: https://discord.gg/JrGPH4V3
- β This is a GrantFox OSS / Official Campaign task and may be rewarded. When your PR is merged you'll be prompted to rate the project β if this issue and the maintainers helped you ship, we'd be grateful for a 5-star rating. Clear questions in Discord and tidy, well-tested PRs are the fastest path to a merge and a reward.