generated from fahricansecer/boilerplate-fe
This commit is contained in:
+288
-17
@@ -1,22 +1,293 @@
|
||||
import { clientMap } from '@/lib/api/client-map';
|
||||
import { Method } from 'axios';
|
||||
import { createApiClient } from './create-api-client';
|
||||
|
||||
interface ApiRequestOptions {
|
||||
const API_URL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:3000/api';
|
||||
|
||||
export const apiClient = createApiClient(API_URL);
|
||||
|
||||
// ── Type Definitions ─────────────────────────────────────────────────
|
||||
|
||||
export interface Project {
|
||||
id: string;
|
||||
title: string;
|
||||
description?: string;
|
||||
prompt: string;
|
||||
status: ProjectStatus;
|
||||
progress: number;
|
||||
language: string;
|
||||
aspectRatio: string;
|
||||
videoStyle: string;
|
||||
targetDuration: number;
|
||||
creditsUsed: number;
|
||||
thumbnailUrl?: string;
|
||||
finalVideoUrl?: string;
|
||||
errorMessage?: string;
|
||||
scriptJson?: ScriptJson;
|
||||
scriptVersion: number;
|
||||
scenes?: Scene[];
|
||||
renderJobs?: RenderJob[];
|
||||
sourceType?: 'MANUAL' | 'X_TWEET' | 'YOUTUBE';
|
||||
sourceTweetData?: Record<string, unknown>;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
completedAt?: string;
|
||||
}
|
||||
|
||||
export type ProjectStatus =
|
||||
| 'DRAFT'
|
||||
| 'GENERATING_SCRIPT'
|
||||
| 'PENDING'
|
||||
| 'GENERATING_MEDIA'
|
||||
| 'RENDERING'
|
||||
| 'COMPLETED'
|
||||
| 'FAILED';
|
||||
|
||||
export interface Scene {
|
||||
id: string;
|
||||
order: number;
|
||||
title?: string;
|
||||
narrationText: string;
|
||||
visualPrompt: string;
|
||||
subtitleText?: string;
|
||||
duration: number;
|
||||
transitionType: string;
|
||||
mediaAssets?: MediaAsset[];
|
||||
}
|
||||
|
||||
export interface MediaAsset {
|
||||
id: string;
|
||||
type: string;
|
||||
url?: string;
|
||||
fileName?: string;
|
||||
mimeType?: string;
|
||||
sizeBytes?: number;
|
||||
durationMs?: number;
|
||||
aiProvider?: string;
|
||||
}
|
||||
|
||||
export interface RenderJob {
|
||||
id: string;
|
||||
status: string;
|
||||
currentStage?: string;
|
||||
attemptNumber: number;
|
||||
processingTimeMs?: number;
|
||||
errorMessage?: string;
|
||||
finalVideoUrl?: string;
|
||||
createdAt: string;
|
||||
startedAt?: string;
|
||||
completedAt?: string;
|
||||
logs?: RenderLog[];
|
||||
}
|
||||
|
||||
export interface RenderLog {
|
||||
id: string;
|
||||
stage: string;
|
||||
level: string;
|
||||
message: string;
|
||||
durationMs?: number;
|
||||
createdAt: string;
|
||||
}
|
||||
|
||||
export interface ScriptJson {
|
||||
metadata: {
|
||||
title: string;
|
||||
description: string;
|
||||
totalDurationSeconds: number;
|
||||
language: string;
|
||||
hashtags: string[];
|
||||
};
|
||||
seo?: {
|
||||
title: string;
|
||||
description: string;
|
||||
keywords: string[];
|
||||
hashtags: string[];
|
||||
schemaMarkup: Record<string, unknown>;
|
||||
};
|
||||
scenes: Array<{
|
||||
order: number;
|
||||
title?: string;
|
||||
narrationText: string;
|
||||
visualPrompt: string;
|
||||
subtitleText: string;
|
||||
durationSeconds: number;
|
||||
transitionType: string;
|
||||
}>;
|
||||
musicPrompt: string;
|
||||
voiceStyle: string;
|
||||
socialContent?: {
|
||||
youtubeTitle: string;
|
||||
youtubeDescription: string;
|
||||
tiktokCaption: string;
|
||||
instagramCaption: string;
|
||||
twitterText: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface PaginatedResponse<T> {
|
||||
data: T[];
|
||||
meta: {
|
||||
total: number;
|
||||
page: number;
|
||||
limit: number;
|
||||
totalPages: number;
|
||||
};
|
||||
}
|
||||
|
||||
export interface CreateProjectPayload {
|
||||
title: string;
|
||||
description?: string;
|
||||
prompt: string;
|
||||
language?: string;
|
||||
aspectRatio?: string;
|
||||
videoStyle?: string;
|
||||
targetDuration?: number;
|
||||
seoKeywords?: string[];
|
||||
referenceUrl?: string;
|
||||
}
|
||||
|
||||
export interface CreditBalance {
|
||||
balance: number;
|
||||
monthlyUsed: number;
|
||||
monthlyLimit: number;
|
||||
}
|
||||
|
||||
export interface Template {
|
||||
id: string;
|
||||
title: string;
|
||||
description?: string;
|
||||
thumbnailUrl?: string;
|
||||
previewVideoUrl?: string;
|
||||
category: string;
|
||||
tags: string[];
|
||||
language: string;
|
||||
usageCount: number;
|
||||
rating: number;
|
||||
isFeatured: boolean;
|
||||
}
|
||||
|
||||
export interface DashboardStats {
|
||||
totalProjects: number;
|
||||
completedVideos: number;
|
||||
totalCreditsUsed: number;
|
||||
creditsRemaining: number;
|
||||
activeRenderJobs: number;
|
||||
recentProjects: Project[];
|
||||
}
|
||||
|
||||
// Tweet Types
|
||||
export interface TweetAuthor {
|
||||
id: string;
|
||||
name: string;
|
||||
username: string;
|
||||
avatarUrl: string;
|
||||
followersCount: number;
|
||||
verified: boolean;
|
||||
}
|
||||
|
||||
export interface TweetMetrics {
|
||||
replies: number;
|
||||
retweets: number;
|
||||
likes: number;
|
||||
views: number;
|
||||
engagementRate: number;
|
||||
}
|
||||
|
||||
export interface TweetMedia {
|
||||
type: 'photo' | 'video' | 'gif';
|
||||
url: string;
|
||||
client: keyof typeof clientMap;
|
||||
method?: Method;
|
||||
data?: any;
|
||||
params?: Record<string, any>;
|
||||
thumbnailUrl?: string;
|
||||
width: number;
|
||||
height: number;
|
||||
}
|
||||
|
||||
export async function apiRequest<T = any>(options: ApiRequestOptions): Promise<T> {
|
||||
const { url, client, method = 'get', data, params } = options;
|
||||
const clientInstance = clientMap[client];
|
||||
|
||||
if (!url || !clientInstance) {
|
||||
throw new Error(`Invalid API request: ${client} - ${url}`);
|
||||
}
|
||||
|
||||
const response = await clientInstance.request<T>({ method, url, data, params });
|
||||
return response.data;
|
||||
export interface ParsedTweet {
|
||||
id: string;
|
||||
url: string;
|
||||
text: string;
|
||||
createdAt: string;
|
||||
author: TweetAuthor;
|
||||
metrics: TweetMetrics;
|
||||
media: TweetMedia[];
|
||||
quotedTweet?: ParsedTweet;
|
||||
isThread: boolean;
|
||||
threadTweets?: ParsedTweet[];
|
||||
}
|
||||
|
||||
export interface TweetPreview {
|
||||
tweet: ParsedTweet;
|
||||
suggestedTitle: string;
|
||||
suggestedPrompt: string;
|
||||
viralScore: number;
|
||||
contentType: 'tweet' | 'thread' | 'quote_tweet';
|
||||
estimatedDuration: number;
|
||||
}
|
||||
|
||||
export interface CreateFromTweetPayload {
|
||||
tweetUrl: string;
|
||||
title?: string;
|
||||
language?: string;
|
||||
aspectRatio?: string;
|
||||
videoStyle?: string;
|
||||
targetDuration?: number;
|
||||
}
|
||||
|
||||
// ── API Functions ────────────────────────────────────────────────────
|
||||
|
||||
export const projectsApi = {
|
||||
list: (params?: { page?: number; limit?: number; status?: string }) =>
|
||||
apiClient.get<PaginatedResponse<Project>>('/projects', { params }).then((r) => r.data),
|
||||
|
||||
get: (id: string) =>
|
||||
apiClient.get<Project>(`/projects/${id}`).then((r) => r.data),
|
||||
|
||||
create: (data: CreateProjectPayload) =>
|
||||
apiClient.post<Project>('/projects', data).then((r) => r.data),
|
||||
|
||||
update: (id: string, data: Partial<CreateProjectPayload>) =>
|
||||
apiClient.patch<Project>(`/projects/${id}`, data).then((r) => r.data),
|
||||
|
||||
delete: (id: string) =>
|
||||
apiClient.delete(`/projects/${id}`).then((r) => r.data),
|
||||
|
||||
generateScript: (id: string) =>
|
||||
apiClient.post<Project>(`/projects/${id}/generate-script`).then((r) => r.data),
|
||||
|
||||
approveAndQueue: (id: string) =>
|
||||
apiClient.post<{ projectId: string; renderJobId: string; bullJobId: string }>(
|
||||
`/projects/${id}/approve-and-queue`,
|
||||
).then((r) => r.data),
|
||||
|
||||
createFromTweet: (data: CreateFromTweetPayload) =>
|
||||
apiClient.post<Project>('/projects/from-tweet', data).then((r) => r.data),
|
||||
};
|
||||
|
||||
export const creditsApi = {
|
||||
getBalance: () =>
|
||||
apiClient.get<CreditBalance>('/credits/balance').then((r) => r.data),
|
||||
|
||||
getHistory: (params?: { page?: number; limit?: number }) =>
|
||||
apiClient.get('/credits/history', { params }).then((r) => r.data),
|
||||
};
|
||||
|
||||
export const templatesApi = {
|
||||
list: (params?: { category?: string; language?: string; page?: number; limit?: number }) =>
|
||||
apiClient.get<PaginatedResponse<Template>>('/templates', { params }).then((r) => r.data),
|
||||
|
||||
get: (id: string) =>
|
||||
apiClient.get<Template>(`/templates/${id}`).then((r) => r.data),
|
||||
|
||||
clone: (id: string) =>
|
||||
apiClient.post<Project>(`/templates/${id}/clone`).then((r) => r.data),
|
||||
};
|
||||
|
||||
export const dashboardApi = {
|
||||
getStats: () =>
|
||||
apiClient.get<DashboardStats>('/dashboard/stats').then((r) => r.data),
|
||||
};
|
||||
|
||||
export const xTwitterApi = {
|
||||
preview: (tweetUrl: string) =>
|
||||
apiClient.post<TweetPreview>('/x-twitter/preview', { tweetUrl }).then((r) => r.data),
|
||||
|
||||
fetch: (tweetUrl: string) =>
|
||||
apiClient.post<ParsedTweet>('/x-twitter/fetch', { tweetUrl }).then((r) => r.data),
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user