#PetAd Frontend πΎ
A modern, responsive web application for pet adoption and temporary custody management, powered by blockchain-backed trust guarantees (Stellar trust layer integration).
##Overview
PetAd Frontend is the client-side application for the PetAd platform, enabling users to browse pets, initiate adoption processes, and manage temporary custody arrangements. The application communicates exclusively with the PetAd backend API and does not directly interact with blockchain infrastructure.
Note: Includes REST fallback and backfill paths for notifications via notificationService.ts to support offline usage and initial loading.
- π Pet Browsing & Search - Discover available pets with advanced filtering
- β€οΈ Adoption Workflows - Streamlined adoption process from inquiry to completion
- β° Temporary Custody - Request and manage short-term pet care arrangements
- π€ User Profiles - Personalized dashboards for pet seekers and caretakers
- π Document Management - Secure upload and verification of required documents
- π Real-time Updates - Live status notifications for adoption and custody requests (close #C9)
- βοΈ Dispute Management - Comprehensive tracking and resolution pathways for administrative and user disputes
- π¬ In-app Messaging - Conversations with optimistic send, attachments, infinite-scroll history and live delivery (guide)
Each domain has a guide with its file map, routes and hook usage snippets:
| Feature | What it covers | Guide |
|---|---|---|
| β Approval | Multi-party approve/reject decisions on adoptions, approval queues, quorum, expiry | docs/features/approval.md |
| βοΈ Dispute | Raising disputes with evidence, SLA badges, admin resolution (escrow split) | docs/features/dispute.md |
| π Custody | Temporary custody requests, lifecycle, timeline with on-chain links | docs/features/custody.md |
| π Notifications | Bell/dropdown, unread badge, preferences, deep links, WebSocket push | docs/features/notifications.md |
How data flows between these layers is in docs/architecture.md.
| Technology | Purpose |
|---|---|
| React 18+ | UI library |
| TypeScript | Type-safe development |
| Vite | Build tool and dev server |
| Tailwind CSS | Utility-first styling |
| TanStack Query | Server state management |
| React Router | Client-side routing |
| Zod | Schema validation |
New to the project? Start here β docs/local-dev.md
It covers how to choose between the offline MSW mocks (VITE_MSW=true) and a real staging backend
(VITE_MSW=false VITE_API_URL=β¦), and what is and isn't testable in each mode.
pnpm install
pnpm dev # http://localhost:4321 β offline, MSW mocksOther docs:
docs/local-dev.mdβ local dev vs. staging backend workflowdocs/guest-mode.mdβ guest browsing mode and auth gatingdocs/notifications.mdβ real-time notification transport decisionsdocs/architecture.mdβ request flow, realtime, auth/session, cache invalidation, frontend/blockchain boundarydocs/features/β per-feature guides (approval, dispute, custody, notifications)
Before you begin, ensure you have the following installed:
- Node.js
>= 20.0.0 - npm
>= 10.0.0or pnpm>= 8.0.0
Check your versions:
node --version
npm --version- Clone the repository
git clone https://github.com/amina69/PetAd-Frontend.git
cd petad-frontend- Install dependencies
npm installOr using pnpm:
pnpm installCreate a .env file in the project root:
VITE_API_URL=http://localhost:3000
VITE_MSW=falseNote:
VITE_API_URLshould point to your PetAd backend API instance.VITE_MSWmust stayfalsefor production builds β enabling the mock service worker in a production bundle is blocked by CI (see Mock API (MSW)).
Optional environment variables:
VITE_APP_NAME=PetAd
VITE_ENABLE_ANALYTICS=false
VITE_ANALYTICS_ENDPOINT=See .env.example for the full list (WebSocket URL, Stellar network, β¦).
Privacy: analytics and error reporting are off unless
VITE_ENABLE_ANALYTICSis exactlytrue; when off, the app makes no analytics network calls. When on, only allow-listed events with non-free-text values are sent (src/lib/analytics.ts) and error reports are scrubbed of PII. Useloggerfromsrc/lib/logger.tsinstead ofconsole.*:debug/infoare silent in production andwarn/errorare redacted. Never log request bodies, headers or cookies.
Start the development server:
npm run devThe application will be available at:
http://localhost:5173
src/
βββ api/ # Service layer: one object per domain
β βββ adoptionService.ts, approvalService.ts, authService.ts
β βββ custodyService.ts, disputes.ts, documentService.ts, escrowService.ts
β βββ notificationService.ts, petService.ts
βββ assets/ # Images and static media
βββ components/ # UI, grouped by domain
β βββ adoption/ approval/ auth/ badges/ blockchain/ custody/
β βββ dispute/ disputes/ escrow/ filters/ home/ icons/ layout/
β βββ listings/ loaders/ modals/ notifications/ toast/ wallet/
β βββ shared/ # Cross-domain primitives (ResponsiveImage, Pagination)
β βββ ui/ # Generic widgets (PetCard, Skeleton, badges, upload zones)
βββ context/ # AuthGateContext, NotificationSocketContext
βββ features/ # Domain modules (api Β· hooks Β· schemas Β· types)
β βββ approval/ # approval queue + decisions
β βββ custody/ # custody types + zod schemas
β βββ dispute/ # legacy dispute module (superseded by disputes/)
β βββ disputes/ # dispute creation, schemas, status config
β βββ notifications/ # preferences, unread count, mark-read, socket hook
βββ hooks/ # Shared and cross-feature hooks (useAuth, useDisputes, β¦)
βββ lib/ # Core infrastructure
β βββ api-client.ts # ApiClient (Bearer token, ApiError, 401 handling)
β βββ api-errors.ts, query-client.ts
β βββ logger.ts, analytics.ts, scrub.ts # privacy-safe logging & analytics
β βββ stellar.ts # explorer URL helpers (read-only)
β βββ hooks/ # Polling, custody, escrow and count hooks
β βββ realtime/ # Framework-agnostic notification WebSocket manager
βββ mocks/ # MSW mock API (dev + test)
β βββ browser.ts # Browser ServiceWorker setup
β βββ server.ts # Node server for Vitest
β βββ handlers/ # One file per domain
β βββ adoption.ts, approval.ts, auth.ts, custody.ts, dispute.ts
β βββ escrow.ts, files.ts, listings.ts, notify.ts, status.ts
βββ pages/ # Route-level components (+ adoption/, disputes/, settings/)
βββ test/ # Global test setup (+ msw/)
βββ types/ # Global TypeScript types
βββ utils/ # Pure helpers (csv, query params, β¦)
βββ main.tsx # Entry point (providers, MSW bootstrap, analytics init)
βββ App.tsx # Routes and guards
Documents, profile and auth are not separate
features/folders: documents live inapi/documentService.ts,components/ui/Document*andcomponents/modals/; profile inpages/ProfilePage.tsx; auth incomponents/auth/,hooks/useAuth.ts,context/AuthGateContext.tsxandapi/authService.ts.
Key Directories:
api/- Centralized API communication layerfeatures/- Feature modules (approval, custody, disputes, notifications)components/- Reusable, presentational components grouped by domainlib/- ApiClient, error classes, logger/analytics, realtime socket manager, shared hooksmocks/- MSW handlers for offline development and testshooks/- Custom React hooks for shared logicpages/- Top-level route components
- Use feature-based architecture for scalability
- Keep components small and focused (single responsibility)
- Validate all forms with Zod schemas
- Handle loading and error states explicitly
- Use TypeScript strict mode (no implicit any)
// features/pets/components/PetCard.tsx
import { Pet } from '@/types/pet';
interface PetCardProps {
pet: Pet;
onAdopt: (petId: string) => void;
}
export function PetCard({ pet, onAdopt }: PetCardProps) {
return (
<div className="rounded-lg border p-4">
<h3 className="font-semibold">{pet.name}</h3>
<p className="text-sm text-gray-600">{pet.breed}</p>
<button
onClick={() => onAdopt(pet.id)}
className="mt-2 rounded bg-blue-500 px-4 py-2 text-white"
>
Adopt Me
</button>
</div>
);
}import { z } from 'zod';
const adoptionFormSchema = z.object({
fullName: z.string().min(2, 'Name must be at least 2 characters'),
email: z.string().email('Invalid email address'),
phone: z.string().regex(/^\+?[1-9]\d{1,14}$/, 'Invalid phone number'),
reason: z.string().min(50, 'Please provide more details'),
});
type AdoptionFormData = z.infer<typeof adoptionFormSchema>;| Command | Description |
|---|---|
npm run dev |
Start development server (hot reload enabled) |
npm run build |
Build optimized production bundle |
npm run preview |
Preview production build locally |
npm run lint |
Run ESLint checks |
npm run test |
Run unit tests with Vitest |
npm run e2e |
Run Playwright end-to-end tests |
npm run check:msw |
Fail if a production build resolves VITE_MSW=true |
Important: Ensure environment variables are configured in your deployment platform:
VITE_API_URL- Backend API endpoint
This project uses Mock Service Worker (MSW) to intercept API requests during development and Vitest tests, so the frontend can be developed without the backend running.
VITE_MSW=true npm run devLook for [MSW] Mocking enabled. in the browser console to confirm it is active.
| Domain | File | Status |
|---|---|---|
| Escrow | src/mocks/handlers/escrow.ts |
β Matches backend |
| Adoption status | src/mocks/handlers/status.ts |
β Matches backend |
| Documents | src/mocks/handlers/files.ts |
β Matches backend |
| Approval | src/mocks/handlers/approval.ts |
β Matches backend |
| Dispute | src/mocks/handlers/dispute.ts |
β Matches backend |
| Notifications | src/mocks/handlers/notify.ts |
β Matches backend |
| Custody | src/mocks/handlers/custody.ts |
β Matches backend |
To run the app against the shared staging API instead of these mocks, follow
docs/local-dev.md (Mode C). Set VITE_MSW=false and
VITE_API_URL to the staging base URL, including the /api prefix, then
restart npm run dev.
VITE_MSW=true must never be resolved by a production build. The
scripts/check-msw-production.mjs guard runs as part of npm run build
(via npm run check:msw) and as a CI step. It fails the build when the
resolved environment for a production target enables MSW, and it is
self-tested in CI against a deliberately misconfigured environment.
Append ?delay=<ms> to any request to simulate network latency:
curl "http://localhost:5173/api/notifications?delay=2000"import { server } from '../mocks/server';
import { http, HttpResponse } from 'msw';
it('shows disputed state', async () => {
server.use(
http.get('/api/escrow/:id', () =>
HttpResponse.json({ status: 'DISPUTED' }),
),
);
// ... rest of test
});The frontend communicates with the PetAd backend API for all operations, including:
- User authentication
- Pet listings and details
- Adoption applications
- Custody requests
- Document uploads
Security:
- The frontend never holds private keys
- All blockchain transactions are processed server-side
- The auth token is a Bearer token kept in browser storage (
auth_token) and sent in theAuthorizationheader; see Auth and session flow
Example API Call:
import { useQuery } from '@tanstack/react-query';
import { petService } from '@/api/petService';
export function usePets() {
return useQuery({
queryKey: ['pets'],
queryFn: () => petService.getAll(),
staleTime: 5 * 60 * 1000, // 5 minutes
});
}This project follows a comprehensive design system documented in Figma. Please refer to the design files when implementing new features or components to ensure consistency.
π Figma Design File: PetAd Design System
The design includes:
- π¨ Complete UI component library
- π± Responsive layouts for mobile, tablet, and desktop
- π Color palette and typography specifications
- π User flow diagrams for adoption and custody workflows
- βΏ Accessibility guidelines
Note for Developers: Always check the Figma design before building new components. Maintain pixel-perfect implementations where possible, and consult with the design team for any deviations.
Contributions are welcome! Please follow these steps:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
Before submitting:
- fix any issues
- Ensure
npm run lint,npm run buildandnpm testpass - Add tests for new features
- Update documentation if needed
This project is licensed under the MIT License - see the LICENSE file for details.
- Built with β€οΈ for pet lovers everywhere
- Powered by blockchain technology for transparent, trustworthy pet adoption
Made with πΎ by the PetAd Team