Next.js web app for secure freelance payments using blockchain technology. Includes a dashboard and Stellar wallet integration.
- Node.js 18+
- npm or yarn
# Clone and enter the repo
git clone <your-repo-url>
cd talenttrust-frontend
# Install dependencies
npm install
# Run dev server
npm run devOpen http://localhost:3000.
| Script | Description |
|---|---|
npm run dev |
Start dev server (3000) |
npm run build |
Production build |
npm start |
Start production server |
npm run lint |
Run ESLint |
npm test |
Run Jest tests |
The app includes a global accessible toast system for transient feedback:
ToastProvideris mounted in the root layout so notifications work across the app.- Use
useToast()in client components to triggershowSuccess(...)andshowError(...). - Success messages announce through a polite
aria-liveregion. - Error messages announce through an assertive
aria-liveregion.
To improve security on shared or public machines, the WalletProvider includes an optional idle auto-disconnect safeguard.
- Configurable Timeout: Pass an
idleTimeoutprop (in milliseconds) toWalletProviderinsrc/app/layout.tsx. - Activity Monitoring: The timer resets on user activity (pointer moves, key presses, clicks, etc.).
- Auto-Disconnect: Once the idle period expires, the wallet is automatically disconnected and a notification is shown.
- Default Behaviour: The safeguard is disabled by default (
idleTimeout={0}). Recommended value for production is 15 minutes (900000ms).
Example:
<WalletProvider idleTimeout={900000}>
{children}
</WalletProvider>To ensure the app provides first-class support for search engine crawlers using Next.js metadata routes.
/robots.txt: Generated bysrc/app/robots.ts, allows all crawlers and points to the sitemap./sitemap.xml: Generated bysrc/app/sitemap.ts, lists all public static routes with a sensiblelastModifiedtimestamp.
Set NEXT_PUBLIC_SITE_URL in .env or your deployment environment to point to your production domain. Falls back to http://localhost:3000 when not set.
Example:
# .env.local
NEXT_PUBLIC_SITE_URL=https://talenttrust.appExample:
'use client';
import { useToast } from '@/components/toast/toast-provider';
export function ReleaseButton() {
const { showSuccess, showError } = useToast();
async function handleRelease() {
try {
showSuccess({ title: 'Milestone released' });
} catch {
showError({ title: 'Wallet not connected' });
}
}
return <button onClick={handleRelease}>Release milestone</button>;
}The homepage contains an accessible, fully validated sign-in form:
- Validation logic: Form validation is extracted to a pure, isolated helper (
src/lib/validateLogin.ts) that enforces required checks and format policies (email structure, minimum length of 8 for password). - Error Summary: If validation fails, an
ErrorSummarycomponent is rendered at the top of the form. It usesrole="alert"and automatically gains focus via standard DOM ref to announce form errors immediately to screen reader users. The items in the list act as anchor links to directly jump focus to the respective input field. - Form Fields & Inputs: Individual fields are wrapped in
FormFieldto handle accessibility connections. It automatically assigns:- An associative
<label>linked byid. aria-invalid="true"to denote inputs that contain errors.aria-describedbypointing to the helper text and error message paragraph elements so screen readers read the context when targeting the inputs.
- An associative
- Success notification: Upon valid submission, the
useToasthook triggers a success notification instead of standard browser alerts.
- Fork the repo and create a branch from
main. - Install deps, run tests and build:
npm install && npm test && npm run build. - Open a pull request. CI runs lint, build, and tests on push/PR to
main.
The /milestones route renders a typed Milestone[] list with a status filter:
- Status filter — an accessible
radiogroup(fieldset+legend) lets users narrow results by All, Pending, Completed, Paid, or Disputed. - Empty state — when no items match the active filter, a contextual
EmptyStateis shown with a prompt to add a milestone. - Accessible result announcement — an
aria-live="polite"region announces the filtered count (e.g. "Showing 2 pending milestones") to assistive-technology users. - Currency formatting — payouts are formatted via
formatAmountfromsrc/lib/preferences.tsx, respecting the user's chosen locale and currency preference.
GitHub Actions runs on push and pull requests to main:
- Install dependencies
- Lint (
npm run lint) - Build (
npm run build) - Tests (
npm test) - Dependency audit (
npm audit --audit-level=high --production)
Ensure these pass locally before pushing.
The pipeline runs npm audit --audit-level=high --production after tests. Any high or critical advisory blocks the merge.
Triage a finding
- Run
npm auditlocally to read the advisory details and affected package. - Check whether a patched version exists:
npm audit fix(add--forceonly if you accept semver-major bumps and have reviewed the changelog). - If no fix is available and the advisory is a false positive or cannot be exploited in this context, document the reason and add the advisory ID to a
.nsprc/audit-resolve.jsonfile (npm ≥ 10:npm audit --ignore <id>).
Waiving an advisory in CI
Add the --ignore <advisory-id> flag to the audit step in .github/workflows/ci.yml and leave a comment explaining the waiver, the expected fix date, and a link to the advisory. Example:
# Advisory 1234567 – lodash prototype pollution, not reachable in production
# Revisit when lodash@5 is released (tracked in #123).
run: npm audit --audit-level=high --production --ignore 1234567MIT
Centralized domain types (Contract, Milestone, Reputation) are defined and re-exported from src/types/domain.ts to ensure strict type safety across pages and components.