Skip to content

Latest commit

Β 

History

History
617 lines (520 loc) Β· 16.7 KB

File metadata and controls

617 lines (520 loc) Β· 16.7 KB

🎨 HelixChain Frontend

Privacy-first genomic verification interface with glass morphism design

🌟 Vision

After the 23andMe breach exposed millions of genetic profiles that can never be secured again, we built HelixChain's frontend to give patients complete control over their genomic data. Our interface ensures that genetic information is shared only when necessary, only what's necessary, and with full patient consentβ€”making permanent genetic data exposure a thing of the past.

🎯 Key Features

  • Three Distinct Portals: Tailored experiences for patients, doctors, and researchers
  • Real-Time Updates: WebSocket-powered live proof generation status
  • Glass Morphism UI: Modern, translucent design with smooth animations
  • Wallet Integration: Seamless Midnight blockchain connection via Lace
  • Responsive Design: Optimized for desktop, tablet, and mobile
  • Accessibility: WCAG 2.1 AA compliant

πŸ—οΈ Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    Component Layer                          β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚  React 18 β”‚ TypeScript 5 β”‚ Vite β”‚ React Router 6          β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                      State Management                       β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚  Zustand Stores β”‚ React Query β”‚ Context Providers          β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                        UI Framework                         β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚  TailwindCSS β”‚ Framer Motion β”‚ Recharts β”‚ React Hook Form β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                    Service Layer                            β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚  Axios β”‚ Socket.io Client β”‚ Crypto-JS β”‚ Web3 Integration   β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

πŸš€ Quick Start

Prerequisites

  • Node.js 20 LTS
  • npm or yarn
  • Modern browser with Web3 support

Installation

# Navigate to frontend
cd frontend

# Install dependencies
npm install

# Set up environment variables
cp .env.example .env
# Edit .env with your configuration

# Start development server
npm run dev
# Open http://localhost:5173

Environment Configuration

# API Configuration
VITE_API_URL=http://localhost:3000
VITE_WS_URL=ws://localhost:3000

# Blockchain
VITE_CONTRACT_ADDRESS=midnight_1758943732128_cwnj0p
VITE_MIDNIGHT_NETWORK=testnet
VITE_MIDNIGHT_RPC=https://testnet.midnight.network/rpc

# Feature Flags
VITE_ENABLE_MOCK_DATA=false
VITE_ENABLE_ANALYTICS=true
VITE_ENABLE_ERROR_TRACKING=true

# UI Configuration
VITE_ANIMATION_DURATION=300
VITE_TOAST_POSITION=top-right

πŸ“ Project Structure

frontend/
β”œβ”€β”€ src/
β”‚   β”œβ”€β”€ main.tsx                 # Application entry
β”‚   β”œβ”€β”€ App.tsx                  # Root component
β”‚   β”œβ”€β”€ LandingPage.tsx          # Public landing
β”‚   β”‚
β”‚   β”œβ”€β”€ app/
β”‚   β”‚   β”œβ”€β”€ pages/              # Page components
β”‚   β”‚   β”‚   β”œβ”€β”€ patient/        # Patient portal
β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ dashboard/  # Patient dashboard
β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ genome/     # Genome management
β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ requests/   # Verification requests
β”‚   β”‚   β”‚   β”‚   └── consent-manager.tsx
β”‚   β”‚   β”‚   β”‚
β”‚   β”‚   β”‚   β”œβ”€β”€ doctor/         # Doctor portal
β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ dashboard/  # Doctor dashboard
β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ patients/   # Patient lookup
β”‚   β”‚   β”‚   β”‚   └── verification/ # Trait verification
β”‚   β”‚   β”‚   β”‚
β”‚   β”‚   β”‚   └── researcher/     # Researcher portal
β”‚   β”‚   β”‚       β”œβ”€β”€ dashboard/  # Research dashboard
β”‚   β”‚   β”‚       β”œβ”€β”€ analysis/   # Data analysis
β”‚   β”‚   β”‚       └── data/       # Cohort builder
β”‚   β”‚   β”‚
β”‚   β”‚   β”œβ”€β”€ components/         # Reusable components
β”‚   β”‚   β”‚   β”œβ”€β”€ genome/
β”‚   β”‚   β”‚   β”‚   └── genome-upload.tsx
β”‚   β”‚   β”‚   β”œβ”€β”€ proof/
β”‚   β”‚   β”‚   β”‚   └── proof-form.tsx
β”‚   β”‚   β”‚   β”œβ”€β”€ doctor/
β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ PatientLookup.tsx
β”‚   β”‚   β”‚   β”‚   └── RequestQueue.tsx
β”‚   β”‚   β”‚   β”œβ”€β”€ researcher/
β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ CohortBuilder.tsx
β”‚   β”‚   β”‚   β”‚   └── ResearcherCharts.tsx
β”‚   β”‚   β”‚   └── shared/
β”‚   β”‚   β”‚       β”œβ”€β”€ role-switcher.tsx
β”‚   β”‚   β”‚       └── wallet-summary.tsx
β”‚   β”‚   β”‚
β”‚   β”‚   β”œβ”€β”€ hooks/              # Custom React hooks
β”‚   β”‚   β”‚   β”œβ”€β”€ useAuth.ts
β”‚   β”‚   β”‚   β”œβ”€β”€ useGenome.ts
β”‚   β”‚   β”‚   β”œβ”€β”€ useProof.ts
β”‚   β”‚   β”‚   β”œβ”€β”€ useWebSocket.ts
β”‚   β”‚   β”‚   └── useWallet.ts
β”‚   β”‚   β”‚
β”‚   β”‚   β”œβ”€β”€ services/           # API services
β”‚   β”‚   β”‚   β”œβ”€β”€ api.ts          # Axios instance
β”‚   β”‚   β”‚   β”œβ”€β”€ auth.service.ts
β”‚   β”‚   β”‚   β”œβ”€β”€ genome.service.ts
β”‚   β”‚   β”‚   β”œβ”€β”€ proof.service.ts
β”‚   β”‚   β”‚   └── research.service.ts
β”‚   β”‚   β”‚
β”‚   β”‚   β”œβ”€β”€ stores/             # Zustand stores
β”‚   β”‚   β”‚   β”œβ”€β”€ authStore.ts
β”‚   β”‚   β”‚   β”œβ”€β”€ genomeStore.ts
β”‚   β”‚   β”‚   β”œβ”€β”€ proofStore.ts
β”‚   β”‚   β”‚   └── uiStore.ts
β”‚   β”‚   β”‚
β”‚   β”‚   β”œβ”€β”€ providers/          # Context providers
β”‚   β”‚   β”‚   β”œβ”€β”€ app-providers.tsx
β”‚   β”‚   β”‚   └── query-client-provider.tsx
β”‚   β”‚   β”‚
β”‚   β”‚   └── layout/             # Layout components
β”‚   β”‚       └── Layout.tsx
β”‚   β”‚
β”‚   β”œβ”€β”€ ui/                     # UI components
β”‚   β”‚   β”œβ”€β”€ AnimatedBackground.tsx
β”‚   β”‚   β”œβ”€β”€ GlassButton.tsx
β”‚   β”‚   β”œβ”€β”€ GlassCard.tsx
β”‚   β”‚   β”œβ”€β”€ SimpleBarChart.tsx
β”‚   β”‚   └── SkeletonLoader.tsx
β”‚   β”‚
β”‚   β”œβ”€β”€ components/             # Shared components
β”‚   β”‚   └── InteractiveDNA.tsx
β”‚   β”‚
β”‚   β”œβ”€β”€ styles/                 # Global styles
β”‚   β”‚   β”œβ”€β”€ index.css
β”‚   β”‚   └── glass-morphism.css
β”‚   β”‚
β”‚   └── utils/                  # Utilities
β”‚       β”œβ”€β”€ constants.ts
β”‚       β”œβ”€β”€ formatters.ts
β”‚       β”œβ”€β”€ validators.ts
β”‚       └── crypto.ts
β”‚
β”œβ”€β”€ public/                     # Static assets
β”œβ”€β”€ dist/                       # Production build
└── package.json               # Dependencies

🎨 Design System

Glass Morphism Theme

/* Glass card component */
.glass-card {
  background: rgba(255, 255, 255, 0.1);
  backdrop-filter: blur(10px);
  border: 1px solid rgba(255, 255, 255, 0.2);
  border-radius: 20px;
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
}

/* Glass button */
.glass-button {
  background: linear-gradient(135deg,
    rgba(255, 255, 255, 0.1),
    rgba(255, 255, 255, 0.05));
  backdrop-filter: blur(10px);
  transition: all 0.3s ease;
}

.glass-button:hover {
  background: linear-gradient(135deg,
    rgba(255, 255, 255, 0.2),
    rgba(255, 255, 255, 0.1));
  transform: translateY(-2px);
}

Color Palette

const colors = {
  primary: {
    50: '#e6f4ff',
    500: '#1890ff',
    900: '#003a8c'
  },
  success: {
    50: '#f6ffed',
    500: '#52c41a',
    900: '#135200'
  },
  warning: {
    50: '#fffbe6',
    500: '#faad14',
    900: '#613400'
  },
  error: {
    50: '#fff1f0',
    500: '#ff4d4f',
    900: '#5c0011'
  }
};

πŸ“± Pages & Routes

Patient Portal Routes

/patient/dashboard       - Overview & activity
/patient/genome         - Upload & manage genomes
/patient/requests       - Verification requests
/patient/proofs         - Proof history
/patient/consent        - Privacy settings
/patient/profile        - Account settings

Doctor Portal Routes

/doctor/dashboard       - Patient overview
/doctor/patients        - Patient directory
/doctor/verification    - Request verifications
/doctor/results         - View proof results
/doctor/history         - Verification history

Researcher Portal Routes

/researcher/dashboard   - Research overview
/researcher/cohorts     - Build cohorts
/researcher/analysis    - Statistical analysis
/researcher/export      - Export data
/researcher/publications - Research outputs

πŸ”§ Component Examples

Genome Upload Component

import { useState } from 'react';
import { useDropzone } from 'react-dropzone';
import { motion } from 'framer-motion';
import { useGenomeStore } from '@/stores/genomeStore';

export const GenomeUpload: React.FC = () => {
  const [uploading, setUploading] = useState(false);
  const { uploadGenome } = useGenomeStore();

  const { getRootProps, getInputProps, isDragActive } = useDropzone({
    accept: {
      'text/plain': ['.vcf', '.txt'],
      'application/json': ['.json']
    },
    maxSize: 100 * 1024 * 1024, // 100MB
    onDrop: async (files) => {
      setUploading(true);
      try {
        await uploadGenome(files[0]);
        toast.success('Genome uploaded successfully');
      } catch (error) {
        toast.error('Upload failed');
      } finally {
        setUploading(false);
      }
    }
  });

  return (
    <motion.div
      className="glass-card p-8"
      whileHover={{ scale: 1.02 }}
      whileTap={{ scale: 0.98 }}
    >
      <div {...getRootProps()} className="dropzone">
        <input {...getInputProps()} />
        {isDragActive ? (
          <p>Drop your genome file here...</p>
        ) : (
          <p>Drag & drop genome file or click to select</p>
        )}
      </div>
    </motion.div>
  );
};

Proof Status Component

import { useEffect } from 'react';
import { motion } from 'framer-motion';
import { useProofStatus } from '@/hooks/useProof';

export const ProofStatus: React.FC<{ jobId: string }> = ({ jobId }) => {
  const { status, progress, proof } = useProofStatus(jobId);

  return (
    <motion.div
      className="glass-card p-6"
      initial={{ opacity: 0, y: 20 }}
      animate={{ opacity: 1, y: 0 }}
    >
      <h3 className="text-lg font-semibold mb-4">Proof Generation</h3>

      {status === 'processing' && (
        <div className="space-y-2">
          <div className="flex justify-between">
            <span>Generating proof...</span>
            <span>{progress}%</span>
          </div>
          <div className="w-full bg-gray-200 rounded-full h-2">
            <motion.div
              className="bg-blue-500 h-2 rounded-full"
              animate={{ width: `${progress}%` }}
            />
          </div>
        </div>
      )}

      {status === 'completed' && proof && (
        <div className="space-y-2">
          <div className="flex items-center text-green-600">
            <CheckCircle className="mr-2" />
            <span>Proof generated successfully</span>
          </div>
          <pre className="bg-gray-100 p-2 rounded text-xs">
            {JSON.stringify(proof, null, 2)}
          </pre>
        </div>
      )}
    </motion.div>
  );
};

WebSocket Hook

import { useEffect } from 'react';
import { io, Socket } from 'socket.io-client';
import { useAuthStore } from '@/stores/authStore';

export const useWebSocket = () => {
  const { token } = useAuthStore();
  const [socket, setSocket] = useState<Socket | null>(null);

  useEffect(() => {
    if (!token) return;

    const newSocket = io(import.meta.env.VITE_WS_URL, {
      auth: { token }
    });

    newSocket.on('connect', () => {
      console.log('WebSocket connected');
    });

    newSocket.on('proof:status', (data) => {
      // Handle proof status updates
    });

    newSocket.on('verification:new', (request) => {
      // Handle new verification requests
    });

    setSocket(newSocket);

    return () => {
      newSocket.disconnect();
    };
  }, [token]);

  return socket;
};

πŸ§ͺ Testing

Unit Tests

# Run tests
npm test

# Run with coverage
npm run test:coverage

# Watch mode
npm run test:watch

E2E Tests

# Install Playwright
npm install -D @playwright/test

# Run E2E tests
npm run test:e2e

# Run in UI mode
npm run test:e2e:ui

Component Testing

# Test individual component
npm test GenomeUpload

# Test with React Testing Library
npm run test:rtl

πŸš€ Build & Deployment

Production Build

# Build for production
npm run build

# Preview production build
npm run preview

Optimization

# Analyze bundle size
npm run analyze

# Build with source maps
npm run build:sourcemap

Docker Deployment

# Multi-stage build
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

FROM nginx:alpine
COPY --from=builder /app/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/nginx.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

CDN Deployment

# Build and deploy to Vercel
vercel --prod

# Deploy to Netlify
netlify deploy --prod

# Deploy to AWS S3 + CloudFront
aws s3 sync dist/ s3://helix-frontend --delete
aws cloudfront create-invalidation --distribution-id XXX --paths "/*"

🎯 Performance Optimization

Code Splitting

// Lazy load heavy components
const ResearcherCharts = lazy(() =>
  import('./components/researcher/ResearcherCharts')
);

// Route-based splitting
const PatientDashboard = lazy(() =>
  import('./pages/patient/dashboard')
);

Image Optimization

// Use WebP with fallback
<picture>
  <source srcSet="hero.webp" type="image/webp" />
  <img src="hero.jpg" alt="Hero" loading="lazy" />
</picture>

Bundle Optimization

// vite.config.ts
export default defineConfig({
  build: {
    rollupOptions: {
      output: {
        manualChunks: {
          vendor: ['react', 'react-dom'],
          charts: ['recharts'],
          animations: ['framer-motion']
        }
      }
    }
  }
});

πŸ“Š Analytics & Monitoring

User Analytics

// Track user actions
analytics.track('Genome Uploaded', {
  userId: user.id,
  genomeSize: file.size,
  uploadDuration: duration
});

Error Tracking

// Sentry integration
Sentry.init({
  dsn: import.meta.env.VITE_SENTRY_DSN,
  environment: import.meta.env.MODE,
  tracesSampleRate: 1.0
});

Performance Monitoring

// Web Vitals tracking
import { getCLS, getFID, getFCP, getLCP, getTTFB } from 'web-vitals';

getCLS(console.log);
getFID(console.log);
getFCP(console.log);
getLCP(console.log);
getTTFB(console.log);

πŸ” Security Best Practices

Content Security Policy

<meta http-equiv="Content-Security-Policy"
      content="default-src 'self';
               script-src 'self' 'unsafe-inline';
               style-src 'self' 'unsafe-inline';
               connect-src 'self' wss://localhost:3000;">

Input Validation

// Validate all user inputs
const genomeSchema = z.object({
  file: z.instanceof(File),
  encryptionKey: z.string().min(32),
  metadata: z.object({
    sequencingDate: z.date(),
    sequencer: z.string()
  })
});

XSS Prevention

// Sanitize user content
import DOMPurify from 'dompurify';

const sanitized = DOMPurify.sanitize(userInput);

🀝 Contributing

See CONTRIBUTING.md for development guidelines.

πŸ“„ License

MIT License - see LICENSE for details.


Built with privacy-first principles after 6.9 million genomes were exposed forever

Your genome, your control, always