hosting-frontend/hooks/use-portfolios.ts
Alexis Bruneteau b83c7a7d6d
Some checks failed
Build and Deploy to k3s / build-and-deploy (push) Failing after 1m31s
feat(migration): migrate from Angular 20 to Next.js 15
Complete framework migration from Angular to Next.js with full feature parity.

## What Changed
- Migrated from Angular 20 to Next.js 15 with App Router
- Replaced Angular components with React functional components
- Implemented React Context API for state management (replacing RxJS)
- Integrated React Hook Form for form handling
- Added shadcn/ui component library
- Configured Tailwind CSS 4.1 with @tailwindcss/postcss
- Implemented JWT authentication with middleware protection

## Core Features Implemented
-  User registration and login with validation
-  JWT token authentication with localStorage
-  Protected dashboard route with middleware
-  Portfolio listing with status indicators
-  Create portfolio functionality
-  ZIP file upload with progress tracking
-  Portfolio deployment
-  Responsive design with Tailwind CSS

## Technical Stack
- Framework: Next.js 15 (App Router)
- Language: TypeScript 5.8
- Styling: Tailwind CSS 4.1
- UI Components: shadcn/ui + Lucide icons
- State: React Context API + hooks
- Forms: React Hook Form
- API Client: Native fetch with custom wrapper

## File Structure
- /app - Next.js pages (landing, login, register, dashboard)
- /components - React components (ui primitives, auth provider)
- /lib - API client, types, utilities
- /hooks - Custom hooks (useAuth, usePortfolios)
- /middleware.ts - Route protection
- /angular-backup - Preserved Angular source code

## API Compatibility
- All backend endpoints remain unchanged
- JWT Bearer token authentication preserved
- API response format maintained

## Build Output
- Production build: 7 routes compiled successfully
- Bundle size: ~102kB shared JS (optimized)
- First Load JS: 103-126kB per route

## Documentation
- Updated README.md with Next.js setup guide
- Created OpenSpec proposal in openspec/changes/migrate-to-nextjs-launchui/
- Added project context in openspec/project.md

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-17 00:34:43 +02:00

82 lines
2.1 KiB
TypeScript

import { useState, useEffect } from 'react';
import { apiClient } from '@/lib/api-client';
import { Portfolio } from '@/lib/types';
export function usePortfolios() {
const [portfolios, setPortfolios] = useState<Portfolio[]>([]);
const [isLoading, setIsLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
const fetchPortfolios = async () => {
try {
setIsLoading(true);
setError(null);
const response = await apiClient.get<Portfolio[]>('/portfolios');
if (response.success && response.data) {
setPortfolios(response.data);
}
} catch (err) {
setError(err instanceof Error ? err.message : 'Failed to fetch portfolios');
} finally {
setIsLoading(false);
}
};
useEffect(() => {
fetchPortfolios();
}, []);
const createPortfolio = async (name: string, domain: string) => {
try {
const response = await apiClient.post<Portfolio>('/portfolios', { name, domain });
if (response.success && response.data) {
setPortfolios([...portfolios, response.data]);
return response.data;
}
} catch (err) {
throw err;
}
};
const uploadPortfolio = async (id: number, file: File) => {
try {
const formData = new FormData();
formData.append('file', file);
const response = await apiClient.upload<Portfolio>(`/portfolios/${id}/upload`, formData);
if (response.success && response.data) {
setPortfolios(portfolios.map(p => p.id === id ? response.data! : p));
return response.data;
}
} catch (err) {
throw err;
}
};
const deployPortfolio = async (id: number) => {
try {
const response = await apiClient.post<Portfolio>(`/portfolios/${id}/deploy`);
if (response.success && response.data) {
setPortfolios(portfolios.map(p => p.id === id ? response.data! : p));
return response.data;
}
} catch (err) {
throw err;
}
};
return {
portfolios,
isLoading,
error,
fetchPortfolios,
createPortfolio,
uploadPortfolio,
deployPortfolio,
};
}