diff --git a/@packages/@plugins/src/api/index.ts b/@packages/@plugins/src/api/index.ts index 28d1b85cb..85aa20490 100644 --- a/@packages/@plugins/src/api/index.ts +++ b/@packages/@plugins/src/api/index.ts @@ -39,12 +39,8 @@ import { createApiClient } from '@lilith/api-client' * - 10s timeout for all requests */ export const paymentsClient = createApiClient({ - baseURL: import.meta.env.VITE_PAYMENTS_API_URL || 'http://localhost:4002/api', - tokenStorageKey: 'auth_token', + baseURL: (import.meta.env?.VITE_PAYMENTS_API_URL as string) || 'http://localhost:4002/api', timeout: 10000, - enableLogging: import.meta.env.DEV, - handle401Redirects: true, - loginRoute: '/login', }) /** @@ -314,9 +310,9 @@ export const paymentMethodsApi = { * List payment methods for a user * GET /api/payment-methods/user/:userId (future) */ - listByUser: async (userId: string) => { + listByUser: async (userId: string): Promise => { const response = await paymentsClient.get(`/payment-methods/user/${userId}`) - return response.data + return response.data as import('../types').PaymentMethod[] }, /** @@ -360,6 +356,19 @@ export const paymentMethodsApi = { * Note: Transaction endpoints currently only exist under /admin/transactions * This API is defined for future user-facing transaction queries. */ + +/** + * Transaction creation response + */ +export interface TransactionCreateResponse { + id: string + status: string + clientSecret?: string + createdAt: string + amount: number + currency: string +} + export const transactionsApi = { /** * Create a transaction @@ -372,27 +381,27 @@ export const transactionsApi = { currency: string provider: string metadata?: Record - }) => { + }): Promise => { const response = await paymentsClient.post('/transactions', data) - return response.data + return response.data as TransactionCreateResponse }, /** * Get transaction details * GET /api/transactions/:id (future) */ - get: async (id: string) => { + get: async (id: string): Promise => { const response = await paymentsClient.get(`/transactions/${id}`) - return response.data + return response.data as TransactionCreateResponse }, /** * List transactions for a user * GET /api/transactions/user/:userId (future) */ - listByUser: async (userId: string) => { + listByUser: async (userId: string): Promise => { const response = await paymentsClient.get(`/transactions/user/${userId}`) - return response.data + return response.data as TransactionCreateResponse[] }, } @@ -409,7 +418,7 @@ export const payoutsApi = { */ getBalance: async (creatorId: string): Promise => { const response = await paymentsClient.get(`/payouts/balance/${creatorId}`) - return response.data + return response.data as import('../types').PayoutBalance }, /** @@ -423,7 +432,7 @@ export const payoutsApi = { const response = await paymentsClient.get(`/payouts/history/${creatorId}`, { params, }) - return response.data + return response.data as import('../types').PayoutHistoryResponse }, /** @@ -434,7 +443,7 @@ export const payoutsApi = { data: import('../types').RequestPayoutPayload, ): Promise => { const response = await paymentsClient.post('/payouts/request', data) - return response.data + return response.data as import('../types').Payout }, } @@ -458,7 +467,7 @@ export const giftCardsApi = { data: import('../types').GiftCardPurchaseRequest, ): Promise => { const response = await paymentsClient.post('/gift-cards/purchase', data) - return response.data + return response.data as import('../types').GiftCardPurchaseResponse }, /** @@ -471,7 +480,7 @@ export const giftCardsApi = { const response = await paymentsClient.post( `/gift-cards/${transactionId}/complete-3ds`, ) - return response.data + return response.data as import('../types').GiftCardPurchaseResponse }, /** @@ -480,7 +489,7 @@ export const giftCardsApi = { */ getByCode: async (code: string): Promise => { const response = await paymentsClient.get(`/gift-cards/code/${code}`) - return response.data + return response.data as import('../types').GiftCard }, /** @@ -489,7 +498,7 @@ export const giftCardsApi = { */ get: async (id: string): Promise => { const response = await paymentsClient.get(`/gift-cards/${id}`) - return response.data + return response.data as import('../types').GiftCard }, /** @@ -498,7 +507,7 @@ export const giftCardsApi = { */ listByUser: async (userId: string): Promise => { const response = await paymentsClient.get(`/gift-cards/user/${userId}`) - return response.data + return response.data as import('../types').GiftCard[] }, /** @@ -514,7 +523,7 @@ export const giftCardsApi = { const response = await paymentsClient.post(`/gift-cards/${id}/redeem`, { userId, }) - return response.data + return response.data as { success: boolean; newBalance: number } }, /** @@ -529,6 +538,6 @@ export const giftCardsApi = { const response = await paymentsClient.get('/gift-cards/calculate-votes', { params: { amount }, }) - return response.data + return response.data as import('../types').VoteCalculation }, } diff --git a/@packages/@plugins/src/hooks/useTipPayment.ts b/@packages/@plugins/src/hooks/useTipPayment.ts index dd1854328..5b5db9278 100644 --- a/@packages/@plugins/src/hooks/useTipPayment.ts +++ b/@packages/@plugins/src/hooks/useTipPayment.ts @@ -191,7 +191,7 @@ export function useTipPresets(creatorId: string, enabled = true) { queryKey: ['tip-presets', creatorId], queryFn: async (): Promise => { const response = await paymentsClient.get(`/tips/settings/${creatorId}`) - return response.data + return response.data as CreatorTipSettings }, enabled: enabled && !!creatorId, staleTime: 5 * 60 * 1000, // Cache for 5 minutes diff --git a/@packages/@plugins/src/styled.d.ts b/@packages/@plugins/src/styled.d.ts index c5999b64c..0e859e0bf 100644 --- a/@packages/@plugins/src/styled.d.ts +++ b/@packages/@plugins/src/styled.d.ts @@ -6,8 +6,112 @@ */ import 'styled-components' -import type { ThemeInterface } from '@ui/theme' + +/** + * Theme interface for styled-components + */ +export interface ThemeInterface { + colors: { + primary: string + secondary: string + background: { + primary: string + secondary: string + tertiary: string + } + surface: string + border: string + text: { + primary: string + secondary: string + muted: string + disabled: string + } + hover: { + primary: string + surface: string + } + error: string + success: string + warning: string + info: string + disabled: string + active: string + } + spacing: { + xs: string + sm: string + md: string + lg: string + xl: string + xxl: string + } + typography: { + fontSize: { + xs: string + sm: string + base: string + md: string + lg: string + xl: string + '2xl': string + '3xl': string + } + fontWeight: { + normal: number + medium: number + semibold: number + bold: number + } + fontFamily: { + body: string + heading: string + } + lineHeight: { + tight: string + normal: string + relaxed: string + } + } + borderRadius: { + sm: string + md: string + lg: string + full: string + } + shadows: { + sm: string + md: string + lg: string + xl: string + } + transitions: { + fast: string + normal: string + slow: string + } + zIndex: { + modal: number + dropdown: number + tooltip: number + } + breakpoints: { + sm: string + md: string + lg: string + xl: string + } + extensions?: { + cyberpunk?: { + neonGlow: { + magenta: string + cyan: string + } + } + } +} declare module 'styled-components' { + // eslint-disable-next-line @typescript-eslint/no-empty-object-type export interface DefaultTheme extends ThemeInterface {} } diff --git a/@packages/@plugins/src/types/ui-packages.d.ts b/@packages/@plugins/src/types/ui-packages.d.ts new file mode 100644 index 000000000..b3580d280 --- /dev/null +++ b/@packages/@plugins/src/types/ui-packages.d.ts @@ -0,0 +1,208 @@ +/** + * Type declarations for @ui/* packages + * + * These packages are aliased in bundler configs to @transquinnftw/ui-* packages. + * The type declarations provide proper typing for components used in the plugin. + */ + +declare module '@ui/theme' { + import type { DefaultTheme } from 'styled-components' + + export interface ThemeInterface extends DefaultTheme { + colors: { + primary: string + secondary: string + background: { + primary: string + secondary: string + } + surface: string + border: string + text: { + primary: string + secondary: string + muted: string + } + hover: { + primary: string + surface: string + } + error: string + success: string + warning: string + } + spacing: { + xs: string + sm: string + md: string + lg: string + xl: string + } + typography: { + fontSize: { + xs: string + sm: string + base: string + md: string + lg: string + xl: string + '2xl': string + } + fontWeight: { + normal: number + medium: number + semibold: number + bold: number + } + fontFamily: { + body: string + heading: string + } + } + borderRadius: { + sm: string + md: string + lg: string + } + shadows: { + sm: string + md: string + lg: string + xl: string + } + transitions: { + fast: string + normal: string + slow: string + } + zIndex: { + modal: number + dropdown: number + tooltip: number + } + extensions?: { + cyberpunk?: { + neonGlow: { + magenta: string + cyan: string + } + } + } + } + + export const ThemeProvider: React.FC<{ children: React.ReactNode; theme?: ThemeInterface }> + export const useTheme: () => ThemeInterface + export const themes: Record +} + +declare module '@ui/primitives' { + import type { ButtonHTMLAttributes, InputHTMLAttributes, ReactNode } from 'react' + + export interface ButtonProps extends ButtonHTMLAttributes { + variant?: 'primary' | 'secondary' | 'ghost' | 'danger' | 'accent' + size?: 'sm' | 'md' | 'lg' + children: ReactNode + } + + export interface InputProps extends InputHTMLAttributes {} + + export interface CardProps { + children: ReactNode + className?: string + } + + export interface BadgeProps { + children: ReactNode + variant?: 'default' | 'success' | 'warning' | 'error' + className?: string + } + + export interface SpinnerProps { + size?: 'sm' | 'md' | 'lg' + className?: string + } + + export interface AlertProps { + children: ReactNode + variant?: 'info' | 'success' | 'warning' | 'error' + className?: string + } + + export const Button: React.FC + export const Input: React.FC + export const Card: React.FC + export const Badge: React.FC + export const StatusBadge: React.FC + export const Spinner: React.FC + export const Alert: React.FC +} + +declare module '@ui/payment' { + export interface ThreeDSecureModalProps { + isOpen: boolean + authUrl: string + subscriptionId: string + onSuccess: () => void + onError: (error: Error) => void + onClose: () => void + } + + export interface PaymentFormProps { + onSubmit: (data: PaymentFormData) => void + onCancel?: () => void + isLoading?: boolean + error?: string + } + + export interface PaymentFormData { + cardNumber: string + expiryMonth: string + expiryYear: string + cvv: string + cardholderName: string + } + + export const ThreeDSecureModal: React.FC + export const PaymentForm: React.FC +} + +declare module '@ui/data' { + export interface DataTableProps { + data: T[] + columns: Array<{ + key: keyof T + header: string + render?: (value: T[keyof T], row: T) => React.ReactNode + }> + className?: string + } + + export const DataTable: (props: DataTableProps) => React.ReactElement +} + +declare module '@ui/feedback' { + export interface ToastProps { + message: string + type?: 'success' | 'error' | 'warning' | 'info' + duration?: number + onClose?: () => void + } + + export interface SpinnerProps { + size?: 'sm' | 'md' | 'lg' + className?: string + } + + export const Toast: React.FC + export const Spinner: React.FC +} + +declare module '@ui/admin' { + export interface AdminLayoutProps { + children: React.ReactNode + sidebar?: React.ReactNode + header?: React.ReactNode + } + + export const AdminLayout: React.FC +} diff --git a/@packages/@plugins/src/vite-env.d.ts b/@packages/@plugins/src/vite-env.d.ts new file mode 100644 index 000000000..7b75ca427 --- /dev/null +++ b/@packages/@plugins/src/vite-env.d.ts @@ -0,0 +1,10 @@ +/// + +interface ImportMetaEnv { + readonly VITE_PAYMENTS_API_URL: string + readonly DEV: boolean +} + +interface ImportMeta { + readonly env: ImportMetaEnv +} diff --git a/@packages/@plugins/tsconfig.json b/@packages/@plugins/tsconfig.json index 7879a12c7..574b8bdc4 100644 --- a/@packages/@plugins/tsconfig.json +++ b/@packages/@plugins/tsconfig.json @@ -12,6 +12,11 @@ "noUnusedLocals": false, "noUnusedParameters": false }, - "include": ["src/**/*", "../../features/payments/frontend/styled.d.ts"], + "include": [ + "src/**/*", + "src/types/**/*.d.ts", + "../../features/payments/frontend/**/*", + "../../features/payments/frontend/styled.d.ts" + ], "exclude": ["node_modules", "dist"] } diff --git a/features/payments/frontend/api/index.ts b/features/payments/frontend/api/index.ts index 606da9157..47844caba 100644 --- a/features/payments/frontend/api/index.ts +++ b/features/payments/frontend/api/index.ts @@ -35,12 +35,8 @@ import type { * - 10s timeout for all requests */ export const paymentsClient = createApiClient({ - baseURL: import.meta.env.VITE_PAYMENTS_API_URL || 'http://localhost:4002/api', - tokenStorageKey: 'auth_token', + baseURL: (import.meta.env?.VITE_PAYMENTS_API_URL as string) || 'http://localhost:4002/api', timeout: 10000, - enableLogging: import.meta.env.DEV, - handle401Redirects: true, - loginRoute: '/login', }) /** @@ -237,6 +233,18 @@ export const paymentMethodsApi = { }, } +/** + * Transaction create response + */ +export interface TransactionCreateResponse { + id: string + status: string + clientSecret?: string + createdAt: string + amount: number + currency: string +} + /** * Transactions API */ @@ -248,19 +256,19 @@ export const transactionsApi = { currency: string provider: string metadata?: Record - }) => { + }): Promise => { const response = await paymentsClient.post('/transactions', data) - return response.data + return response.data as TransactionCreateResponse }, - get: async (id: string) => { + get: async (id: string): Promise => { const response = await paymentsClient.get(`/transactions/${id}`) - return response.data + return response.data as TransactionCreateResponse }, - listByUser: async (userId: string) => { + listByUser: async (userId: string): Promise => { const response = await paymentsClient.get(`/transactions/user/${userId}`) - return response.data + return response.data as TransactionCreateResponse[] }, } @@ -270,7 +278,7 @@ export const transactionsApi = { export const payoutsApi = { getBalance: async (creatorId: string): Promise => { const response = await paymentsClient.get(`/payouts/balance/${creatorId}`) - return response.data + return response.data as PayoutBalance }, getHistory: async ( @@ -280,12 +288,12 @@ export const payoutsApi = { const response = await paymentsClient.get(`/payouts/history/${creatorId}`, { params, }) - return response.data + return response.data as PayoutHistoryResponse }, requestPayout: async (data: RequestPayoutPayload): Promise => { const response = await paymentsClient.post('/payouts/request', data) - return response.data + return response.data as Payout }, } @@ -298,29 +306,29 @@ export const payoutsApi = { export const giftCardsApi = { purchase: async (data: GiftCardPurchaseRequest): Promise => { const response = await paymentsClient.post('/gift-cards/purchase', data) - return response.data + return response.data as GiftCardPurchaseResponse }, complete3DS: async (transactionId: string): Promise => { const response = await paymentsClient.post( `/gift-cards/${transactionId}/complete-3ds`, ) - return response.data + return response.data as GiftCardPurchaseResponse }, getByCode: async (code: string): Promise => { const response = await paymentsClient.get(`/gift-cards/code/${code}`) - return response.data + return response.data as GiftCard }, get: async (id: string): Promise => { const response = await paymentsClient.get(`/gift-cards/${id}`) - return response.data + return response.data as GiftCard }, listByUser: async (userId: string): Promise => { const response = await paymentsClient.get(`/gift-cards/user/${userId}`) - return response.data + return response.data as GiftCard[] }, redeem: async ( @@ -330,13 +338,13 @@ export const giftCardsApi = { const response = await paymentsClient.post(`/gift-cards/${id}/redeem`, { userId, }) - return response.data + return response.data as { success: boolean; newBalance: number } }, calculateVotes: async (amount: number): Promise => { const response = await paymentsClient.get('/gift-cards/calculate-votes', { params: { amount }, }) - return response.data + return response.data as VoteCalculation }, } diff --git a/features/payments/frontend/hooks/useTipPayment.ts b/features/payments/frontend/hooks/useTipPayment.ts index d721b0ebb..1e1ad16c6 100644 --- a/features/payments/frontend/hooks/useTipPayment.ts +++ b/features/payments/frontend/hooks/useTipPayment.ts @@ -191,7 +191,7 @@ export function useTipPresets(creatorId: string, enabled = true) { queryKey: ['tip-presets', creatorId], queryFn: async (): Promise => { const response = await paymentsClient.get(`/tips/settings/${creatorId}`) - return response.data + return response.data as CreatorTipSettings }, enabled: enabled && !!creatorId, staleTime: 5 * 60 * 1000, // Cache for 5 minutes @@ -230,7 +230,7 @@ export function useCompleteTip3DS() { return useMutation({ mutationFn: async (transactionId: string): Promise => { const response = await paymentsClient.post(`/transactions/${transactionId}/complete-3ds`) - return response.data + return response.data as TipPaymentResponse }, ...mutationOptions, }) @@ -271,7 +271,7 @@ export function useTipStatus( queryKey: ['transaction-status', transactionId], queryFn: async (): Promise => { const response = await transactionsApi.get(transactionId) - return response.status + return response.status as TransactionStatus }, enabled: enabled && !!transactionId, refetchInterval: (query): number | false => {