feat: Complete production deployment pipeline with admin dashboard
Some checks failed
ParentFlow CI/CD Pipeline / Backend Tests (push) Has been cancelled
ParentFlow CI/CD Pipeline / Frontend Tests (push) Has been cancelled
ParentFlow CI/CD Pipeline / Security Scanning (push) Has been cancelled
ParentFlow CI/CD Pipeline / Build Docker Images (map[context:maternal-app/maternal-app-backend dockerfile:Dockerfile.production name:backend]) (push) Has been cancelled
ParentFlow CI/CD Pipeline / Build Docker Images (map[context:maternal-web dockerfile:Dockerfile.production name:frontend]) (push) Has been cancelled
ParentFlow CI/CD Pipeline / Deploy to Development (push) Has been cancelled
ParentFlow CI/CD Pipeline / Deploy to Production (push) Has been cancelled
CI/CD Pipeline / Lint and Test (push) Has been cancelled
CI/CD Pipeline / E2E Tests (push) Has been cancelled
CI/CD Pipeline / Build Application (push) Has been cancelled
Some checks failed
ParentFlow CI/CD Pipeline / Backend Tests (push) Has been cancelled
ParentFlow CI/CD Pipeline / Frontend Tests (push) Has been cancelled
ParentFlow CI/CD Pipeline / Security Scanning (push) Has been cancelled
ParentFlow CI/CD Pipeline / Build Docker Images (map[context:maternal-app/maternal-app-backend dockerfile:Dockerfile.production name:backend]) (push) Has been cancelled
ParentFlow CI/CD Pipeline / Build Docker Images (map[context:maternal-web dockerfile:Dockerfile.production name:frontend]) (push) Has been cancelled
ParentFlow CI/CD Pipeline / Deploy to Development (push) Has been cancelled
ParentFlow CI/CD Pipeline / Deploy to Production (push) Has been cancelled
CI/CD Pipeline / Lint and Test (push) Has been cancelled
CI/CD Pipeline / E2E Tests (push) Has been cancelled
CI/CD Pipeline / Build Application (push) Has been cancelled
- Add unified deployment script with Node.js 22 installation - Create comprehensive database migration script (28 migrations + admin tables) - Add production start/stop scripts for all services - Integrate admin dashboard (parentflow-admin) into PM2 ecosystem - Configure all services: Backend (3020), Frontend (3030), Admin (3335) - Update ecosystem.config.js with admin dashboard configuration - Add invite codes module for user registration management
This commit is contained in:
183
parentflow-admin/src/lib/api-client.ts
Normal file
183
parentflow-admin/src/lib/api-client.ts
Normal file
@@ -0,0 +1,183 @@
|
||||
import axios from 'axios';
|
||||
|
||||
const API_BASE_URL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:3020/api/v1';
|
||||
|
||||
class ApiClient {
|
||||
private token: string | null = null;
|
||||
private refreshToken: string | null = null;
|
||||
|
||||
constructor() {
|
||||
// Initialize tokens from localStorage if available
|
||||
if (typeof window !== 'undefined') {
|
||||
this.token = localStorage.getItem('admin_access_token');
|
||||
this.refreshToken = localStorage.getItem('admin_refresh_token');
|
||||
}
|
||||
}
|
||||
|
||||
setTokens(accessToken: string, refreshToken: string) {
|
||||
this.token = accessToken;
|
||||
this.refreshToken = refreshToken;
|
||||
if (typeof window !== 'undefined') {
|
||||
localStorage.setItem('admin_access_token', accessToken);
|
||||
localStorage.setItem('admin_refresh_token', refreshToken);
|
||||
}
|
||||
}
|
||||
|
||||
clearTokens() {
|
||||
this.token = null;
|
||||
this.refreshToken = null;
|
||||
if (typeof window !== 'undefined') {
|
||||
localStorage.removeItem('admin_access_token');
|
||||
localStorage.removeItem('admin_refresh_token');
|
||||
}
|
||||
}
|
||||
|
||||
private async request(method: string, endpoint: string, data?: any, options?: any) {
|
||||
const config = {
|
||||
method,
|
||||
url: `${API_BASE_URL}${endpoint}`,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
...(this.token ? { Authorization: `Bearer ${this.token}` } : {}),
|
||||
...options?.headers,
|
||||
},
|
||||
...options,
|
||||
};
|
||||
|
||||
if (data) {
|
||||
config.data = data;
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await axios(config);
|
||||
return response.data;
|
||||
} catch (error: any) {
|
||||
// Handle token refresh
|
||||
if (error.response?.status === 401 && this.refreshToken) {
|
||||
try {
|
||||
const refreshResponse = await axios.post(`${API_BASE_URL}/auth/refresh`, {
|
||||
refreshToken: this.refreshToken,
|
||||
});
|
||||
|
||||
this.setTokens(refreshResponse.data.accessToken, refreshResponse.data.refreshToken);
|
||||
|
||||
// Retry original request
|
||||
config.headers.Authorization = `Bearer ${this.token}`;
|
||||
const response = await axios(config);
|
||||
return response.data;
|
||||
} catch (refreshError) {
|
||||
this.clearTokens();
|
||||
window.location.href = '/login';
|
||||
throw refreshError;
|
||||
}
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
// Auth endpoints
|
||||
async login(email: string, password: string) {
|
||||
const response = await this.request('POST', '/admin/auth/login', { email, password });
|
||||
this.setTokens(response.accessToken, response.refreshToken);
|
||||
return response;
|
||||
}
|
||||
|
||||
async logout() {
|
||||
try {
|
||||
await this.request('POST', '/admin/auth/logout');
|
||||
} finally {
|
||||
this.clearTokens();
|
||||
}
|
||||
}
|
||||
|
||||
async getCurrentAdmin() {
|
||||
return this.request('GET', '/admin/auth/me');
|
||||
}
|
||||
|
||||
// User management endpoints
|
||||
async getUsers(params?: { page?: number; limit?: number; search?: string }) {
|
||||
const queryString = params ? '?' + new URLSearchParams(params as any).toString() : '';
|
||||
return this.request('GET', `/admin/users${queryString}`);
|
||||
}
|
||||
|
||||
async getUserById(id: string) {
|
||||
return this.request('GET', `/admin/users/${id}`);
|
||||
}
|
||||
|
||||
async updateUser(id: string, data: any) {
|
||||
return this.request('PATCH', `/admin/users/${id}`, data);
|
||||
}
|
||||
|
||||
async deleteUser(id: string) {
|
||||
return this.request('DELETE', `/admin/users/${id}`);
|
||||
}
|
||||
|
||||
// Invite code endpoints
|
||||
async getInviteCodes(params?: { page?: number; limit?: number; status?: string }) {
|
||||
const queryString = params ? '?' + new URLSearchParams(params as any).toString() : '';
|
||||
return this.request('GET', `/admin/invite-codes${queryString}`);
|
||||
}
|
||||
|
||||
async createInviteCode(data: {
|
||||
code: string;
|
||||
maxUses?: number;
|
||||
expiresAt?: string;
|
||||
metadata?: any;
|
||||
}) {
|
||||
return this.request('POST', '/admin/invite-codes', data);
|
||||
}
|
||||
|
||||
async updateInviteCode(id: string, data: any) {
|
||||
return this.request('PATCH', `/admin/invite-codes/${id}`, data);
|
||||
}
|
||||
|
||||
async deleteInviteCode(id: string) {
|
||||
return this.request('DELETE', `/admin/invite-codes/${id}`);
|
||||
}
|
||||
|
||||
// Analytics endpoints
|
||||
async getAnalytics(params?: { startDate?: string; endDate?: string }) {
|
||||
const queryString = params ? '?' + new URLSearchParams(params as any).toString() : '';
|
||||
return this.request('GET', `/admin/analytics${queryString}`);
|
||||
}
|
||||
|
||||
async getUserGrowth() {
|
||||
return this.request('GET', '/admin/analytics/user-growth');
|
||||
}
|
||||
|
||||
async getActivityStats() {
|
||||
return this.request('GET', '/admin/analytics/activity-stats');
|
||||
}
|
||||
|
||||
async getSystemHealth() {
|
||||
return this.request('GET', '/admin/analytics/system-health');
|
||||
}
|
||||
|
||||
// Family management
|
||||
async getFamilies(params?: { page?: number; limit?: number; search?: string }) {
|
||||
const queryString = params ? '?' + new URLSearchParams(params as any).toString() : '';
|
||||
return this.request('GET', `/admin/families${queryString}`);
|
||||
}
|
||||
|
||||
async getFamilyById(id: string) {
|
||||
return this.request('GET', `/admin/families/${id}`);
|
||||
}
|
||||
|
||||
// Activity logs
|
||||
async getActivityLogs(params?: { page?: number; limit?: number; userId?: string }) {
|
||||
const queryString = params ? '?' + new URLSearchParams(params as any).toString() : '';
|
||||
return this.request('GET', `/admin/logs${queryString}`);
|
||||
}
|
||||
|
||||
// System settings
|
||||
async getSettings() {
|
||||
return this.request('GET', '/admin/settings');
|
||||
}
|
||||
|
||||
async updateSettings(data: any) {
|
||||
return this.request('PATCH', '/admin/settings', data);
|
||||
}
|
||||
}
|
||||
|
||||
export const apiClient = new ApiClient();
|
||||
export default apiClient;
|
||||
Reference in New Issue
Block a user