Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions backend/src/database/seeds/data/mock-data.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
export const FIRST_NAMES = [
'James', 'Mary', 'Robert', 'Patricia', 'John', 'Jennifer', 'Michael', 'Linda',
'William', 'Elizabeth', 'David', 'Barbara', 'Richard', 'Susan', 'Joseph', 'Jessica',
'Thomas', 'Sarah', 'Charles', 'Karen', 'Christopher', 'Nancy', 'Daniel', 'Lisa',
'Matthew', 'Betty', 'Anthony', 'Margaret', 'Mark', 'Sandra', 'Donald', 'Ashley'
];

export const LAST_NAMES = [
'Smith', 'Johnson', 'Williams', 'Brown', 'Jones', 'Garcia', 'Miller', 'Davis',
'Rodriguez', 'Martinez', 'Hernandez', 'Lopez', 'Gonzalez', 'Wilson', 'Anderson',
'Thomas', 'Taylor', 'Moore', 'Jackson', 'Martin', 'Lee', 'Perez', 'Thompson', 'White'
];

export const PET_NAMES = [
'Buddy', 'Bella', 'Charlie', 'Luna', 'Lucy', 'Max', 'Bailey', 'Daisy',
'Cooper', 'Lola', 'Rocky', 'Stella', 'Milo', 'Sadie', 'Bear', 'Molly',
'Toby', 'Sophie', 'Jack', 'Chloe', 'Teddy', 'Penny', 'Duke', 'Ruby',
'Oliver', 'Rosie', 'Bentley', 'Gracie', 'Tucker', 'Lily', 'Jax', 'Mia'
];

export const CITIES = ['New York', 'Los Angeles', 'Chicago', 'Houston', 'Phoenix', 'Philadelphia', 'San Antonio', 'San Diego'];

export const STREETS = ['Main St', 'Oak St', 'Washington St', 'Lakeview Dr', 'Park Ave', 'Broadway', 'Maple Ave', 'Cedar St'];

export const CLINIC_NAMES = [
'City Pet Hospital', 'Healthy Paws Veterinary', 'Green Valley Vet',
'Sunrise Animal Clinic', 'North Star Veterinary Center', 'Riverside Animal Hospital'
];

export const SPECIALIZATIONS = [
'Surgery', 'Dermatology', 'Internal Medicine', 'Cardiology',
'Oncology', 'Ophthalmology', 'Emergency & Critical Care'
];

export const DIAGNOSES = [
'Ear Infection', 'Skin Allergy', 'Dental Disease', 'Arthritis',
'Gastrointestinal Upset', 'Lyme Disease', 'Heartworm', 'Urinary Tract Infection',
'Obesity', 'Vaccination Reaction', 'Minor Laceration', 'Annual Wellness Check'
];

export const TREATMENTS = [
'Prescribed Antibiotics', 'Topical Cream Application', 'Dental Cleaning',
'Anti-inflammatory Medication', 'Prescription Diet Recommended', 'Fluid Therapy',
'Wound Cleaning and Dressing', 'Observation for 24 hours', 'Daily Targeted Exercise'
];
33 changes: 33 additions & 0 deletions backend/src/database/seeds/factories/entity.factory.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { FIRST_NAMES, LAST_NAMES, PET_NAMES, CITIES, STREETS } from '../data/mock-data';

export class EntityFactory {
static getRandomElement<T>(array: T[]): T {
return array[Math.floor(Math.random() * array.length)];
}

static getRandomInt(min: number, max: number): number {
return Math.floor(Math.random() * (max - min + 1)) + min;
}

static generateEmail(firstName: string, lastName: string): string {
const domains = ['gmail.com', 'yahoo.com', 'outlook.com', 'example.com'];
const domain = this.getRandomElement(domains);
return `${firstName.toLowerCase()}.${lastName.toLowerCase()}${this.getRandomInt(1, 999)}@${domain}`;
}

static generatePhone(): string {
return `+1-${this.getRandomInt(200, 999)}-${this.getRandomInt(200, 999)}-${this.getRandomInt(1000, 9999)}`;
}

static generateAddress(): string {
return `${this.getRandomInt(100, 9999)} ${this.getRandomElement(STREETS)}, ${this.getRandomElement(CITIES)}`;
}

static generateDate(yearsBack: number = 0): Date {
const date = new Date();
date.setFullYear(date.getFullYear() - yearsBack);
date.setMonth(this.getRandomInt(0, 11));
date.setDate(this.getRandomInt(1, 28));
return date;
}
}
43 changes: 43 additions & 0 deletions backend/src/modules/users/seeds/users-seeder.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { Injectable, Logger } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { User } from '../entities/user.entity';
import { EntityFactory } from '../../../database/seeds/factories/entity.factory';
import { FIRST_NAMES, LAST_NAMES } from '../../../database/seeds/data/mock-data';

@Injectable()
export class UsersSeederService {
private readonly logger = new Logger(UsersSeederService.name);

constructor(
@InjectRepository(User)
private readonly userRepository: Repository<User>,
) {}

async seedUsers(count: number = 10): Promise<User[]> {
this.logger.log(`Seeding ${count} users...`);
const users: User[] = [];

for (let i = 0; i < count; i++) {
const firstName = EntityFactory.getRandomElement(FIRST_NAMES);
const lastName = EntityFactory.getRandomElement(LAST_NAMES);

const user = this.userRepository.create({
email: EntityFactory.generateEmail(firstName, lastName),
firstName,
lastName,
phone: EntityFactory.generatePhone(),
address: EntityFactory.generateAddress(),
city: EntityFactory.getRandomElement(['New York', 'Los Angeles', 'Chicago']),
country: 'USA',
emailVerified: true,
phoneVerified: true,
});

users.push(await this.userRepository.save(user));
}

this.logger.log(`Successfully seeded ${users.length} users`);
return users;
}
}
46 changes: 46 additions & 0 deletions backend/src/modules/vets/seeds/vets-seeder.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { Injectable, Logger } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Vet } from '../entities/vet.entity';
import { EntityFactory } from '../../../database/seeds/factories/entity.factory';
import { CLINIC_NAMES, SPECIALIZATIONS } from '../../../database/seeds/data/mock-data';

@Injectable()
export class VetsSeederService {
private readonly logger = new Logger(VetsSeederService.name);

constructor(
@InjectRepository(Vet)
private readonly vetRepository: Repository<Vet>,
) {}

async seedVets(count: number = 5): Promise<Vet[]> {
this.logger.log(`Seeding ${count} vets...`);
const vets: Vet[] = [];

for (let i = 0; i < count; i++) {
const firstName = EntityFactory.getRandomElement(['Dr. James', 'Dr. Mary', 'Dr. Robert', 'Dr. Patricia']);
const lastName = EntityFactory.getRandomElement(['Smith', 'Johnson', 'Williams', 'Brown']);

const vet = this.vetRepository.create({
clinicName: EntityFactory.getRandomElement(CLINIC_NAMES),
vetName: `${firstName} ${lastName}`,
licenseNumber: `VET-${EntityFactory.getRandomInt(10000, 99999)}`,
email: EntityFactory.generateEmail(firstName.replace('Dr. ', ''), lastName),
phone: EntityFactory.generatePhone(),
address: EntityFactory.generateAddress(),
city: 'New York',
state: 'NY',
zipCode: '10001',
specializations: [EntityFactory.getRandomElement(SPECIALIZATIONS)],
latitude: 40.7128,
longitude: -74.0060,
});

vets.push(await this.vetRepository.save(vet));
}

this.logger.log(`Successfully seeded ${vets.length} vets`);
return vets;
}
}
35 changes: 35 additions & 0 deletions wata-board-frontend/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Environment Variables for Wata Board Frontend
# Copy this file to .env and fill in your actual values

# Network Configuration
# Options: testnet, mainnet
VITE_NETWORK=testnet

# API Configuration
# Backend API URL for production (in development, uses proxy)
VITE_API_URL=https://your-api-domain.com

# CORS Configuration
# Frontend URL for CORS (matches your deployment domain)
VITE_FRONTEND_URL=https://your-frontend-domain.com

# Stellar Contract Configuration
# The contract ID for the Wata Board smart contract on Stellar network
# These will be automatically selected based on VITE_NETWORK, but you can override them
VITE_CONTRACT_ID_TESTNET=CDRRJ7IPYDL36YSK5ZQLBG3LICULETIBXX327AGJQNTWXNKY2UMDO4DA
VITE_CONTRACT_ID_MAINNET=MAINNET_CONTRACT_ID_HERE

# Stellar RPC URL
# The RPC endpoint for connecting to the Stellar Soroban network
# These will be automatically selected based on VITE_NETWORK, but you can override them
VITE_RPC_URL_TESTNET=https://soroban-testnet.stellar.org
VITE_RPC_URL_MAINNET=https://soroban.stellar.org

# Network Passphrase
# These will be automatically selected based on VITE_NETWORK, but you can override them
VITE_NETWORK_PASSPHRASE_TESTNET=Test SDF Network ; September 2015
VITE_NETWORK_PASSPHRASE_MAINNET=Public Global Stellar Network ; September 2015

# Application Settings (Optional)
# VITE_APP_NAME=Wata-Board
# VITE_APP_VERSION=1.0.0
24 changes: 24 additions & 0 deletions wata-board-frontend/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*

node_modules
dist
dist-ssr
*.local

# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
55 changes: 55 additions & 0 deletions wata-board-frontend/Dockerfile.prod
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# Production Dockerfile for Wata-Board Frontend
# Multi-stage build for optimized production image

# Build stage
FROM node:18-alpine AS builder

WORKDIR /app

# Copy package files
COPY package*.json ./

# Install dependencies
RUN npm ci --only=production && npm cache clean --force

# Copy the rest of the application
COPY . .

# Build the application
RUN npm run build

# Production stage
FROM nginx:alpine AS production

# Install security updates
RUN apk update && apk upgrade && \
apk add --no-cache curl && \
rm -rf /var/cache/apk/*

# Copy built application from builder stage
COPY --from=builder /app/dist /var/www/wata-board-frontend/dist

# Copy Nginx configuration
COPY nginx.conf /etc/nginx/conf.d/default.conf

# Create non-root user for security
RUN addgroup -g 1001 -S nginx && \
adduser -S nginx -u 1001 -G nginx

# Create logs directory
RUN mkdir -p /var/log/nginx && \
chown -R nginx:nginx /var/log/nginx && \
chown -R nginx:nginx /var/www/wata-board-frontend

# Switch to non-root user
USER nginx

# Expose ports
EXPOSE 80 443

# Health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD curl -f http://localhost/health || exit 1

# Start Nginx
CMD ["nginx", "-g", "daemon off;"]
101 changes: 101 additions & 0 deletions wata-board-frontend/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
# Wata-Board Frontend

Frontend UI for **Wata-Board** — a decentralized utility payment platform on **Stellar / Soroban**.

This is a **React + TypeScript + Vite** app styled with **Tailwind** and wired to **Freighter Wallet** for signing transactions.

## Prerequisites

- **Node.js** (v18+ LTS recommended)
- **Freighter Wallet** browser extension
- Stellar testnet account with XLM

## Quick Start

```bash
# Install dependencies
npm install

# Run development server
npm run dev

# Open http://localhost:5173
```

## Available Scripts

| Script | Description |
|--------|-------------|
| `npm run dev` | Start Vite dev server with hot reload |
| `npm run build` | Create production build with type checking |
| `npm run lint` | Run ESLint on all files |
| `npm run preview` | Preview production build locally |

## Project Structure

```
src/
├── App.tsx # Main payment interface
├── contracts/ # Soroban contract bindings
│ ├── src/index.ts # Generated client code
│ ├── package.json
│ └── tsconfig.json
├── main.tsx # React entry point
├── index.css # Global styles
└── assets/ # Static assets
```

## Smart Contract Integration

- **Contract ID**: `CDRRJ7IPYDL36YSK5ZQLBG3LICULETIBXX327AGJQNTWXNKY2UMDO4DA`
- **Network**: Stellar Testnet
- **RPC**: `https://soroban-testnet.stellar.org`

## Features

- **Meter Payment**: Enter meter ID and amount to pay utility bills
- **Freighter Integration**: Sign transactions with browser wallet
- **Real-time Status**: Track transaction progress and results
- **Testnet Ready**: Pre-configured for Stellar testnet

## Environment Variables

Create `.env` in the project root:

```env
VITE_CONTRACT_ID=CDRRJ7IPYDL36YSK5ZQLBG3LICULETIBXX327AGJQNTWXNKY2UMDO4DA
VITE_RPC_URL=https://soroban-testnet.stellar.org
```

## Freighter Setup

1. Install [Freighter Wallet](https://www.freighter.app/) extension
2. Create or import an account
3. Switch to **Testnet** in settings
4. Fund account with testnet XLM from [Stellar Laboratory](https://laboratory.stellar.org/#account-creator?network=test)

## Troubleshooting

| Issue | Solution |
|-------|----------|
| "Freighter not found" | Install extension and refresh page |
| "Transaction failed" | Check testnet XLM balance |
| "Build errors" | Run `npm install` to update deps |

## Notes

- The app is currently configured for **Stellar Testnet** only
- Contract bindings in `src/contracts/` are auto-generated from Soroban CLI
- Amount must be a positive whole number

## Dependencies

- **React** 19.2.0
- **Stellar SDK** 14.5.0
- **Freighter API** 6.0.1
- **Tailwind CSS** 4.1.18
- **Vite** 8.0.0-beta.13

## License

ISC
Loading