Email Sorter Beta
Ich habe soweit automatisiert the Emails sortieren aber ich muss noch schauen was es fur bugs es gibt wenn die app online ist deswegen wurde ich mit diesen Commit die website veroffentlichen obwohjl es sein konnte das es noch nicht fertig ist und verkaufs bereit
This commit is contained in:
329
client/src/lib/api.ts
Normal file
329
client/src/lib/api.ts
Normal file
@@ -0,0 +1,329 @@
|
||||
const API_BASE = import.meta.env.VITE_API_URL || '/api'
|
||||
|
||||
interface ApiResponse<T> {
|
||||
success?: boolean
|
||||
data?: T
|
||||
error?: {
|
||||
code: string
|
||||
message: string
|
||||
fields?: Record<string, string[]>
|
||||
}
|
||||
}
|
||||
|
||||
async function fetchApi<T>(
|
||||
endpoint: string,
|
||||
options?: RequestInit
|
||||
): Promise<ApiResponse<T>> {
|
||||
try {
|
||||
const response = await fetch(`${API_BASE}${endpoint}`, {
|
||||
...options,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
...options?.headers,
|
||||
},
|
||||
})
|
||||
|
||||
const data = await response.json()
|
||||
|
||||
if (!response.ok || data.success === false) {
|
||||
return {
|
||||
error: data.error || {
|
||||
code: 'UNKNOWN',
|
||||
message: `HTTP ${response.status}`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return { success: true, data: data.data || data }
|
||||
} catch (error) {
|
||||
return {
|
||||
error: {
|
||||
code: 'NETWORK_ERROR',
|
||||
message: error instanceof Error ? error.message : 'Network error'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const api = {
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
// EMAIL ACCOUNTS
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
|
||||
async getEmailAccounts(userId: string) {
|
||||
return fetchApi<Array<{
|
||||
id: string
|
||||
email: string
|
||||
provider: 'gmail' | 'outlook'
|
||||
connected: boolean
|
||||
lastSync?: string
|
||||
}>>(`/email/accounts?userId=${userId}`)
|
||||
},
|
||||
|
||||
async connectEmailAccount(userId: string, provider: 'gmail' | 'outlook', email: string, accessToken: string, refreshToken?: string) {
|
||||
return fetchApi<{ accountId: string }>('/email/connect', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ userId, provider, email, accessToken, refreshToken }),
|
||||
})
|
||||
},
|
||||
|
||||
async disconnectEmailAccount(accountId: string, userId: string) {
|
||||
return fetchApi<{ success: boolean }>(`/email/accounts/${accountId}?userId=${userId}`, {
|
||||
method: 'DELETE',
|
||||
})
|
||||
},
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
// EMAIL STATS & SORTING
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
|
||||
async getEmailStats(userId: string) {
|
||||
return fetchApi<{
|
||||
totalSorted: number
|
||||
todaySorted: number
|
||||
weekSorted: number
|
||||
categories: Record<string, number>
|
||||
timeSaved: number
|
||||
}>(`/email/stats?userId=${userId}`)
|
||||
},
|
||||
|
||||
async sortEmails(userId: string, accountId: string, maxEmails?: number, processAll?: boolean) {
|
||||
return fetchApi<{
|
||||
sorted: number
|
||||
inboxCleared: number
|
||||
categories: Record<string, number>
|
||||
timeSaved: { minutes: number; formatted: string }
|
||||
highlights: Array<{ type: string; count: number; message: string }>
|
||||
suggestions: Array<{ type: string; message: string }>
|
||||
provider?: string
|
||||
isDemo?: boolean
|
||||
}>('/email/sort', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ userId, accountId, maxEmails, processAll }),
|
||||
})
|
||||
},
|
||||
|
||||
// Demo sorting without account (for quick tests)
|
||||
async sortDemo(count: number = 10) {
|
||||
return fetchApi<{
|
||||
sorted: number
|
||||
emails: Array<{
|
||||
from: string
|
||||
subject: string
|
||||
snippet: string
|
||||
category: string
|
||||
categoryName: string
|
||||
confidence?: number
|
||||
reason?: string
|
||||
}>
|
||||
categories: Record<string, number>
|
||||
aiEnabled: boolean
|
||||
}>('/email/sort-demo', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ count }),
|
||||
})
|
||||
},
|
||||
|
||||
// Connect demo account
|
||||
async connectDemoAccount(userId: string) {
|
||||
return fetchApi<{
|
||||
accountId: string
|
||||
email: string
|
||||
provider: string
|
||||
message?: string
|
||||
}>('/email/connect-demo', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ userId }),
|
||||
})
|
||||
},
|
||||
|
||||
// Get categories
|
||||
async getCategories() {
|
||||
return fetchApi<Array<{
|
||||
id: string
|
||||
name: string
|
||||
description: string
|
||||
color: string
|
||||
action: string
|
||||
priority: number
|
||||
}>>('/email/categories')
|
||||
},
|
||||
|
||||
// Get today's digest
|
||||
async getDigest(userId: string) {
|
||||
return fetchApi<{
|
||||
date: string
|
||||
totalSorted: number
|
||||
inboxCleared: number
|
||||
timeSavedMinutes: number
|
||||
stats: Record<string, number>
|
||||
highlights: Array<{ type: string; count: number; message: string }>
|
||||
suggestions: Array<{ type: string; message: string }>
|
||||
hasData: boolean
|
||||
}>(`/email/digest?userId=${userId}`)
|
||||
},
|
||||
|
||||
// Get digest history
|
||||
async getDigestHistory(userId: string, days: number = 7) {
|
||||
return fetchApi<{
|
||||
days: number
|
||||
digests: Array<{
|
||||
date: string
|
||||
totalSorted: number
|
||||
inboxCleared: number
|
||||
timeSavedMinutes: number
|
||||
stats: Record<string, number>
|
||||
}>
|
||||
totals: {
|
||||
totalSorted: number
|
||||
inboxCleared: number
|
||||
timeSavedMinutes: number
|
||||
}
|
||||
}>(`/email/digest/history?userId=${userId}&days=${days}`)
|
||||
},
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
// OAUTH
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
|
||||
async getOAuthUrl(provider: 'gmail' | 'outlook', userId: string) {
|
||||
return fetchApi<{ url: string }>(`/oauth/${provider}/connect?userId=${userId}`)
|
||||
},
|
||||
|
||||
async getOAuthStatus() {
|
||||
return fetchApi<{
|
||||
gmail: { enabled: boolean; scopes: string[] }
|
||||
outlook: { enabled: boolean; scopes: string[] }
|
||||
}>('/oauth/status')
|
||||
},
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
// SUBSCRIPTION
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
|
||||
async getSubscriptionStatus(userId: string) {
|
||||
return fetchApi<{
|
||||
status: string
|
||||
plan: string
|
||||
features: {
|
||||
emailAccounts: number
|
||||
emailsPerDay: number
|
||||
historicalSync: boolean
|
||||
customRules: boolean
|
||||
prioritySupport: boolean
|
||||
}
|
||||
currentPeriodEnd?: string
|
||||
cancelAtPeriodEnd?: boolean
|
||||
}>(`/subscription/status?userId=${userId}`)
|
||||
},
|
||||
|
||||
async createSubscriptionCheckout(plan: string, userId: string, email?: string) {
|
||||
return fetchApi<{ url: string; sessionId: string }>('/subscription/checkout', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ userId, plan, email }),
|
||||
})
|
||||
},
|
||||
|
||||
async createPortalSession(userId: string) {
|
||||
return fetchApi<{ url: string }>('/subscription/portal', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ userId }),
|
||||
})
|
||||
},
|
||||
|
||||
async cancelSubscription(userId: string) {
|
||||
return fetchApi<{ success: boolean }>('/subscription/cancel', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ userId }),
|
||||
})
|
||||
},
|
||||
|
||||
async reactivateSubscription(userId: string) {
|
||||
return fetchApi<{ success: boolean }>('/subscription/reactivate', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ userId }),
|
||||
})
|
||||
},
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
// USER PREFERENCES
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
|
||||
async getUserPreferences(userId: string) {
|
||||
return fetchApi<{
|
||||
vipSenders: Array<{ email: string; name?: string }>
|
||||
blockedSenders: string[]
|
||||
customRules: Array<{ condition: string; category: string }>
|
||||
priorityTopics: string[]
|
||||
}>(`/preferences?userId=${userId}`)
|
||||
},
|
||||
|
||||
async saveUserPreferences(userId: string, preferences: {
|
||||
vipSenders?: Array<{ email: string; name?: string }>
|
||||
blockedSenders?: string[]
|
||||
customRules?: Array<{ condition: string; category: string }>
|
||||
priorityTopics?: string[]
|
||||
}) {
|
||||
return fetchApi<{ success: boolean }>('/preferences', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ userId, ...preferences }),
|
||||
})
|
||||
},
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
// PRODUCTS & QUESTIONS (Legacy)
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
|
||||
async getProducts() {
|
||||
return fetchApi<any[]>('/products')
|
||||
},
|
||||
|
||||
async getQuestions(productSlug: string) {
|
||||
return fetchApi<any[]>(`/questions?productSlug=${productSlug}`)
|
||||
},
|
||||
|
||||
async createSubmission(productSlug: string, answers: Record<string, any>) {
|
||||
return fetchApi<{ submissionId: string }>('/submissions', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ productSlug, answers }),
|
||||
})
|
||||
},
|
||||
|
||||
async createCheckout(submissionId: string) {
|
||||
return fetchApi<{ url: string; sessionId: string }>('/checkout', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ submissionId }),
|
||||
})
|
||||
},
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
// CONFIG
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
|
||||
async getConfig() {
|
||||
return fetchApi<{
|
||||
features: {
|
||||
gmail: boolean
|
||||
outlook: boolean
|
||||
ai: boolean
|
||||
}
|
||||
pricing: {
|
||||
basic: { price: number; currency: string; accounts: number }
|
||||
pro: { price: number; currency: string; accounts: number }
|
||||
business: { price: number; currency: string; accounts: number }
|
||||
}
|
||||
}>('/config')
|
||||
},
|
||||
|
||||
async healthCheck() {
|
||||
return fetchApi<{
|
||||
status: string
|
||||
timestamp: string
|
||||
version: string
|
||||
environment: string
|
||||
uptime: number
|
||||
}>('/health')
|
||||
},
|
||||
}
|
||||
|
||||
export default api
|
||||
Reference in New Issue
Block a user