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:
2026-01-22 19:32:12 +01:00
parent 95349af50b
commit abf761db07
596 changed files with 56405 additions and 51231 deletions

329
client/src/lib/api.ts Normal file
View 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