From 6da8ce1cbde312d6c54de8a265ee51a1405c786c Mon Sep 17 00:00:00 2001 From: ANDJ Date: Tue, 27 Jan 2026 21:06:48 +0100 Subject: [PATCH] huhuih hzgjuigik --- APPWRITE_CORS_SETUP.md | 111 + COMMIT_COMMANDS.txt | 6 + COMMIT_MESSAGE.md | 71 + PRODUCTION_SETUP.md | 155 ++ client/FAVICON_SETUP.md | 105 + client/index.html | 71 +- client/public/apple-touch-icon.svg | 24 + client/public/favicon-generator.html | 144 ++ client/public/favicon.svg | 24 + client/public/site.webmanifest | 21 + client/src/App.tsx | 4 + client/src/components/OnboardingProgress.tsx | 87 + client/src/components/PrivacySecurity.tsx | 226 ++ client/src/components/ShareResults.tsx | 101 + client/src/components/UpgradePrompt.tsx | 113 + client/src/components/landing/Features.tsx | 53 +- client/src/components/landing/Footer.tsx | 7 +- client/src/components/landing/Hero.tsx | 24 +- client/src/components/landing/Navbar.tsx | 32 +- client/src/components/ui/badge.tsx | 12 +- client/src/components/ui/button.tsx | 14 +- client/src/components/ui/card.tsx | 6 +- client/src/components/ui/input.tsx | 2 +- client/src/components/ui/side-panel.tsx | 148 ++ client/src/components/ui/slider.tsx | 41 + client/src/components/ui/tabs.tsx | 52 + client/src/hooks/useTheme.ts | 186 ++ client/src/index.css | 140 +- client/src/lib/analytics.ts | 136 +- client/src/lib/api.ts | 136 ++ client/src/pages/Dashboard.tsx | 1138 ++++++---- client/src/pages/Imprint.tsx | 4 +- client/src/pages/Login.tsx | 2 +- client/src/pages/Privacy.tsx | 4 +- client/src/pages/Register.tsx | 31 +- client/src/pages/Settings.tsx | 2082 ++++++++++++++---- client/src/pages/Setup.tsx | 234 +- client/src/types/settings.ts | 50 + git-commit.bat | 16 + git-commit.sh | 54 + run-git-commit.ps1 | 77 + server/bootstrap-v2.mjs | 52 + server/config/index.mjs | 7 + server/index.mjs | 4 +- server/routes/analytics.mjs | 92 +- server/routes/api.mjs | 231 +- server/routes/email.mjs | 317 ++- server/services/ai-sorter.mjs | 115 + server/services/database.mjs | 267 ++- server/utils/response.mjs | 11 + setup-production.ps1 | 142 ++ 51 files changed, 6208 insertions(+), 974 deletions(-) create mode 100644 APPWRITE_CORS_SETUP.md create mode 100644 COMMIT_COMMANDS.txt create mode 100644 COMMIT_MESSAGE.md create mode 100644 PRODUCTION_SETUP.md create mode 100644 client/FAVICON_SETUP.md create mode 100644 client/public/apple-touch-icon.svg create mode 100644 client/public/favicon-generator.html create mode 100644 client/public/favicon.svg create mode 100644 client/public/site.webmanifest create mode 100644 client/src/components/OnboardingProgress.tsx create mode 100644 client/src/components/PrivacySecurity.tsx create mode 100644 client/src/components/ShareResults.tsx create mode 100644 client/src/components/UpgradePrompt.tsx create mode 100644 client/src/components/ui/side-panel.tsx create mode 100644 client/src/components/ui/slider.tsx create mode 100644 client/src/components/ui/tabs.tsx create mode 100644 client/src/hooks/useTheme.ts create mode 100644 git-commit.bat create mode 100644 git-commit.sh create mode 100644 run-git-commit.ps1 create mode 100644 setup-production.ps1 diff --git a/APPWRITE_CORS_SETUP.md b/APPWRITE_CORS_SETUP.md new file mode 100644 index 0000000..ca0018c --- /dev/null +++ b/APPWRITE_CORS_SETUP.md @@ -0,0 +1,111 @@ +# Appwrite CORS Setup - Schritt für Schritt + +## Problem +Appwrite blockiert Requests von `https://emailsorter.webklar.com` weil nur `https://localhost` als Origin erlaubt ist. + +## Lösung: Platform in Appwrite hinzufügen + +### Schritt 1: Appwrite-Konsole öffnen +1. Gehe zu: **https://appwrite.webklar.com** +2. Logge dich ein + +### Schritt 2: Projekt öffnen +1. Klicke auf dein **EmailSorter Projekt** (oder das Projekt, das du verwendest) + +### Schritt 3: Settings öffnen +1. Klicke auf **Settings** im linken Menü +2. Oder suche nach **"Platforms"** oder **"Web"** in den Einstellungen + +### Schritt 4: Platform hinzufügen +1. Klicke auf **"Add Platform"** oder **"Create Platform"** +2. Wähle **"Web"** als Platform-Typ + +### Schritt 5: Platform konfigurieren +Fülle die Felder aus: + +- **Name:** `Production` (oder ein anderer Name) +- **Hostname:** `emailsorter.webklar.com` +- **Origin:** `https://emailsorter.webklar.com` + +**WICHTIG:** +- Verwende **https://** (nicht http://) +- Kein Slash am Ende +- Genau so wie oben geschrieben + +### Schritt 6: Speichern +1. Klicke auf **"Create"** oder **"Save"** +2. Warte 1-2 Minuten (Cache) + +### Schritt 7: Testen +1. Gehe zu https://emailsorter.webklar.com +2. Versuche dich einzuloggen +3. Prüfe die Browser-Konsole (F12) - sollte keine CORS-Fehler mehr geben + +--- + +## Alternative: Mehrere Origins + +Falls du mehrere Domains brauchst (z.B. localhost für Development und Production): + +1. Erstelle **zwei separate Platforms:** + - **Development:** Hostname: `localhost`, Origin: `http://localhost:5173` + - **Production:** Hostname: `emailsorter.webklar.com`, Origin: `https://emailsorter.webklar.com` + +2. Oder verwende **Wildcard** (falls von Appwrite unterstützt): + - Origin: `https://*.webklar.com` + +--- + +## Troubleshooting + +### CORS-Fehler bleibt bestehen +1. **Cache leeren:** Warte 2-3 Minuten nach dem Speichern +2. **Browser-Cache:** Strg+Shift+R (Hard Refresh) +3. **Prüfe Origin:** Muss **genau** `https://emailsorter.webklar.com` sein (kein Slash, kein Port) +4. **Prüfe Appwrite-Version:** Manche Versionen haben die Platform-Einstellungen an einem anderen Ort + +### Platform-Option nicht sichtbar +- In manchen Appwrite-Versionen heißt es **"Web"** statt "Platforms" +- Suche nach **"Client"** oder **"SDK"** in den Settings +- Prüfe die Appwrite-Dokumentation für deine Version + +### 404 oder 403 Fehler +- Prüfe, ob die Appwrite-URL korrekt ist: `https://appwrite.webklar.com` +- Prüfe, ob du die richtigen Berechtigungen hast +- Prüfe, ob das Projekt existiert und aktiv ist + +--- + +## Screenshots (Beispiel) + +Die Platform-Einstellungen sollten etwa so aussehen: + +``` +┌─────────────────────────────────────┐ +│ Add Platform │ +├─────────────────────────────────────┤ +│ Type: [Web ▼] │ +│ │ +│ Name: Production │ +│ Hostname: emailsorter.webklar.com │ +│ Origin: https://emailsorter.webklar │ +│ .com │ +│ │ +│ [Cancel] [Create] │ +└─────────────────────────────────────┘ +``` + +--- + +## Nach dem Setup + +Nachdem du die Platform hinzugefügt hast: + +1. ✅ CORS-Fehler sollten verschwinden +2. ✅ Login/Register sollte funktionieren +3. ✅ API-Calls sollten durchgehen + +**Falls es immer noch nicht funktioniert:** +- Prüfe die Browser-Konsole für genaue Fehlermeldungen +- Prüfe die Appwrite-Logs (falls verfügbar) +- Stelle sicher, dass der Backend-Server läuft (502-Fehler beheben) diff --git a/COMMIT_COMMANDS.txt b/COMMIT_COMMANDS.txt new file mode 100644 index 0000000..455fe37 --- /dev/null +++ b/COMMIT_COMMANDS.txt @@ -0,0 +1,6 @@ +Führe diese Befehle in deinem Git Bash oder Terminal aus: + +cd c:\Users\User\Documents\GitHub\ANDJJJJJJ +git add . +git commit -m "feat: Control Panel Redesign v2.0 - Card-basiertes Layout, Side Panels, Dark Mode Fixes, Volle Breite Layout" +git push diff --git a/COMMIT_MESSAGE.md b/COMMIT_MESSAGE.md new file mode 100644 index 0000000..97b3468 --- /dev/null +++ b/COMMIT_MESSAGE.md @@ -0,0 +1,71 @@ +# Control Panel Redesign & UI Improvements + +## Hauptänderungen + +### 🎨 Control Panel komplettes Redesign (Version 2.0) +- **Card-basiertes Layout**: Kategorien werden jetzt als interaktive Cards in einem Grid-Layout dargestellt (statt endloser Liste) +- **Side Panel Integration**: Click-to-Configure Pattern - Klick auf Category Card öffnet Side Panel für detaillierte Konfiguration +- **Moderne UX**: Dashboard-artiges Design, weniger wie klassische Settings-Seite, mehr wie moderne SaaS-Produkte + +### 🧹 Cleanup Tab Redesign +- **Große Toggle-Cards**: Visuell prominente Cards für "Auto cleanup read emails" und "Delete promotions after X days" +- **Slider-Komponente**: Neue Slider-Komponente für intuitive Tage-Auswahl (statt Number Input) +- **Preset Buttons**: Schnellzugriff auf 7/14/30 Tage für Promotion Cleanup +- **Preview Section**: Zeigt betroffene E-Mails an (wenn Daten vorhanden) +- **Warnungen**: Ruhige Info-Banner bei Delete-Aktionen + +### 🏷️ Labels Tab Redesign +- **Tabellenansicht**: Professionelle Tabelle mit Name, Status, Category und Actions +- **Side Panel Editor**: Label-Erstellung/Bearbeitung in Side Panel statt inline Form +- **Responsive Table**: Spalten werden auf Mobile ausgeblendet, wichtige Info bleibt sichtbar +- **Import/Export**: Buttons für Label-Import/Export + +### 📐 Layout Verbesserungen +- **Volle Breite**: Dashboard und Settings nutzen jetzt die gesamte verfügbare Breite (keine max-width Beschränkung mehr) +- **Responsive Navigation**: Side Panels werden auf Mobile zu Fullscreen-Modals +- **Verbesserte Header**: Humanere Untertitel und bessere Button-Anordnung + +### 🌙 Dark Mode Verbesserungen +- **Privacy & Security**: Alle weißen Felder haben jetzt Dark Mode Varianten (grüne, blaue, rote Info-Boxen) +- **Input-Komponente**: Dark Mode Hintergrund korrigiert (dark:bg-slate-800 statt dark:bg-slate-100) +- **Slider-Komponente**: Dark Mode Styles für Thumb (Webkit & Mozilla) +- **Chevron Icons**: Dark Mode Farben für Advanced Options Toggle +- **Konsistenz**: Alle Komponenten haben jetzt konsistente Dark Mode Unterstützung + +## Neue Komponenten + +### `client/src/components/ui/side-panel.tsx` +- Radix UI Dialog-basierte Side Panel Komponente +- Slide-in Animation von rechts +- Responsive: Fullscreen auf Mobile, 480px auf Desktop +- Dark Mode Support + +### `client/src/components/ui/slider.tsx` +- Range Input Slider Komponente +- Dark Mode Support für Track und Thumb +- Customizable min/max/step Werte + +## Geänderte Dateien + +- `client/src/pages/Settings.tsx` - Control Panel komplett neu strukturiert +- `client/src/components/PrivacySecurity.tsx` - Dark Mode für alle Info-Boxen +- `client/src/components/ui/input.tsx` - Dark Mode Hintergrund korrigiert +- `client/src/pages/Dashboard.tsx` - Volle Breite Layout +- `client/src/types/settings.ts` - Keine Änderungen (nur Whitespace) + +## Technische Details + +- **State Management**: Side Panel State für Category Details und Label Editor +- **Responsive Design**: Grid-Layouts passen sich an (1 Spalte Mobile, 2 Tablet, 3 Desktop) +- **Accessibility**: Keyboard Navigation, ARIA Labels, Focus States +- **Performance**: useMemo für gefilterte/sortierte Listen + +## Design-Prinzipien + +- Viel Whitespace zwischen Cards +- Ruhige Farben (keine grellen Akzente) +- Cards statt Listen +- "Click → Configure" statt sofort sichtbare Controls +- Klare Typografie-Hierarchie +- Icons sparsam aber sinnvoll +- Dark Mode optimiert (nicht zu kontrastreich) diff --git a/PRODUCTION_SETUP.md b/PRODUCTION_SETUP.md new file mode 100644 index 0000000..0778a4c --- /dev/null +++ b/PRODUCTION_SETUP.md @@ -0,0 +1,155 @@ +# Production Setup - emailsorter.webklar.com + +## Probleme und Lösungen + +### 1. Appwrite CORS-Konfiguration + +**Problem:** Appwrite blockiert Requests von `https://emailsorter.webklar.com` weil nur `https://localhost` als Origin erlaubt ist. + +**Lösung:** +1. Gehe zu deiner Appwrite-Konsole: https://appwrite.webklar.com +2. Öffne dein Projekt +3. Gehe zu **Settings** → **Platforms** (oder **Web**) +4. Füge eine neue Platform hinzu oder bearbeite die existierende: + - **Name:** Production + - **Hostname:** `emailsorter.webklar.com` + - **Origin:** `https://emailsorter.webklar.com` +5. Speichere die Änderungen + +**Alternative:** Wenn du mehrere Origins brauchst, kannst du auch in Appwrite die CORS-Einstellungen anpassen, um mehrere Origins zu erlauben. + +--- + +### 2. Backend-Server (502 Fehler) + +**Problem:** Der Backend-Server läuft nicht oder ist nicht erreichbar. + +**Lösung:** + +#### Option A: Server auf demselben Server starten + +1. **SSH zum Server:** + ```bash + ssh user@webklar.com + ``` + +2. **Zum Projekt-Verzeichnis navigieren:** + ```bash + cd /path/to/ANDJJJJJJ/server + ``` + +3. **Environment-Variablen setzen:** + Erstelle oder bearbeite `.env`: + ```env + NODE_ENV=production + PORT=3000 + BASE_URL=https://api.emailsorter.webklar.com + FRONTEND_URL=https://emailsorter.webklar.com + CORS_ORIGIN=https://emailsorter.webklar.com + + APPWRITE_ENDPOINT=https://appwrite.webklar.com/v1 + APPWRITE_PROJECT_ID=deine_projekt_id + APPWRITE_API_KEY=dein_api_key + APPWRITE_DATABASE_ID=email_sorter_db + + # ... weitere Variablen + ``` + +4. **Server starten:** + ```bash + npm install + npm start + ``` + +#### Option B: Mit PM2 (empfohlen für Production) + +```bash +npm install -g pm2 +cd /path/to/ANDJJJJJJ/server +pm2 start index.mjs --name emailsorter-api +pm2 save +pm2 startup +``` + +#### Option C: Reverse Proxy konfigurieren (Nginx) + +Falls der Server auf einem anderen Port läuft, konfiguriere Nginx: + +```nginx +server { + listen 80; + server_name api.emailsorter.webklar.com; + + location / { + proxy_pass http://localhost:3000; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection 'upgrade'; + proxy_set_header Host $host; + proxy_cache_bypass $http_upgrade; + } +} +``` + +--- + +### 3. Frontend Environment-Variablen + +Stelle sicher, dass das Frontend die richtige Backend-URL verwendet: + +1. **Erstelle `client/.env.production`:** + ```env + VITE_APPWRITE_ENDPOINT=https://appwrite.webklar.com/v1 + VITE_APPWRITE_PROJECT_ID=deine_projekt_id + VITE_API_URL=https://api.emailsorter.webklar.com + ``` + +2. **Build das Frontend:** + ```bash + cd client + npm run build + ``` + +3. **Deploy den Build-Ordner** (`client/dist`) zu deinem Web-Server + +--- + +### 4. Checkliste + +- [ ] Appwrite CORS: `https://emailsorter.webklar.com` als Origin hinzugefügt +- [ ] Backend-Server läuft und ist erreichbar +- [ ] Backend `.env` konfiguriert mit Production-URLs +- [ ] Frontend `.env.production` konfiguriert +- [ ] Frontend gebaut und deployed +- [ ] Reverse Proxy (Nginx) konfiguriert (falls nötig) +- [ ] SSL-Zertifikat für beide Domains (Frontend + API) + +--- + +### 5. Testing + +Nach dem Setup, teste: + +1. **Frontend:** https://emailsorter.webklar.com +2. **Backend Health:** https://api.emailsorter.webklar.com/api/health +3. **Login:** Versuche dich einzuloggen und prüfe die Browser-Konsole auf Fehler + +--- + +### Troubleshooting + +**CORS-Fehler weiterhin:** +- Prüfe, ob die Appwrite-Änderungen gespeichert wurden +- Warte 1-2 Minuten (Cache) +- Prüfe Browser-Konsole für genaue Fehlermeldung + +**502 Bad Gateway:** +- Prüfe, ob der Backend-Server läuft: `pm2 list` oder `ps aux | grep node` +- Prüfe Server-Logs: `pm2 logs emailsorter-api` oder `tail -f server.log` +- Prüfe Firewall-Regeln +- Prüfe Reverse Proxy Konfiguration + +**API nicht erreichbar:** +- Prüfe, ob der Port 3000 offen ist +- Prüfe, ob die Domain richtig auf den Server zeigt +- Prüfe DNS-Einträge diff --git a/client/FAVICON_SETUP.md b/client/FAVICON_SETUP.md new file mode 100644 index 0000000..f45332e --- /dev/null +++ b/client/FAVICON_SETUP.md @@ -0,0 +1,105 @@ +# Favicon Setup Anleitung + +Die Favicon-Dateien wurden erstellt. Um alle Formate zu generieren, folge diesen Schritten: + +## Erstellte Dateien + +✅ `favicon.svg` - Modernes SVG Favicon (bereits erstellt) +✅ `apple-touch-icon.svg` - SVG für Apple Touch Icon (bereits erstellt) +✅ `site.webmanifest` - Web App Manifest (bereits erstellt) + +## Noch zu erstellen (PNG/ICO) + +Du musst die folgenden PNG/ICO-Dateien aus dem SVG erstellen: + +### Option 1: Online Converter verwenden + +1. Gehe zu einem dieser Tools: + - https://realfavicongenerator.net/ (Empfohlen - generiert alle Formate) + - https://www.zenlytools.com/svg-to-ico + - https://svg-to-ico.org/ + +2. Lade `favicon.svg` hoch + +3. Generiere folgende Dateien: + - `favicon.ico` (16x16, 32x32, 48x48) + - `favicon-16x16.png` + - `favicon-32x32.png` + - `apple-touch-icon.png` (180x180) + - `favicon-192x192.png` (für Web Manifest) + - `favicon-512x512.png` (für Web Manifest) + +4. Speichere alle generierten Dateien im `client/public/` Ordner + +### Option 2: Mit ImageMagick (Command Line) + +```bash +# Installiere ImageMagick (falls nicht vorhanden) +# Windows: choco install imagemagick +# Mac: brew install imagemagick +# Linux: sudo apt-get install imagemagick + +cd client/public + +# Erstelle PNG-Varianten +magick favicon.svg -resize 16x16 favicon-16x16.png +magick favicon.svg -resize 32x32 favicon-32x32.png +magick apple-touch-icon.svg -resize 180x180 apple-touch-icon.png +magick favicon.svg -resize 192x192 favicon-192x192.png +magick favicon.svg -resize 512x512 favicon-512x512.png + +# Erstelle ICO (mehrere Größen) +magick favicon.svg -define icon:auto-resize=16,32,48 favicon.ico +``` + +### Option 3: Mit Online Favicon Generator (Empfohlen) + +1. Gehe zu: https://realfavicongenerator.net/ +2. Klicke auf "Select your Favicon image" +3. Lade `favicon.svg` hoch +4. Konfiguriere die Optionen: + - iOS: Apple Touch Icon aktivieren + - Android Chrome: Manifest aktivieren + - Windows Metro: Optional +5. Klicke auf "Generate your Favicons and HTML code" +6. Lade das ZIP herunter +7. Extrahiere alle Dateien in `client/public/` +8. Kopiere die generierten `` Tags in `index.html` (falls nötig) + +## Verifizierung + +Nach dem Erstellen aller Dateien: + +1. Starte den Dev-Server: `npm run dev` +2. Öffne die Seite im Browser +3. Prüfe den Browser-Tab - das Favicon sollte angezeigt werden +4. Teste auf Mobile: + - iOS Safari: Zum Home-Bildschirm hinzufügen → Icon sollte erscheinen + - Android Chrome: Installiere als PWA → Icon sollte erscheinen + +## Dateien im public/ Ordner + +Nach Abschluss sollten folgende Dateien vorhanden sein: + +``` +client/public/ +├── favicon.svg ✅ +├── favicon.ico (zu erstellen) +├── favicon-16x16.png (zu erstellen) +├── favicon-32x32.png (zu erstellen) +├── apple-touch-icon.png (zu erstellen) +├── favicon-192x192.png (zu erstellen) +├── favicon-512x512.png (zu erstellen) +├── apple-touch-icon.svg ✅ +└── site.webmanifest ✅ +``` + +## Browser-Kompatibilität + +- **Chrome/Edge**: Verwendet `favicon.svg` oder `favicon.ico` +- **Firefox**: Verwendet `favicon.svg` oder `favicon.ico` +- **Safari (Desktop)**: Verwendet `favicon.ico` oder PNG +- **Safari (iOS)**: Verwendet `apple-touch-icon.png` +- **Android Chrome**: Verwendet Icons aus `site.webmanifest` + +Die aktuelle Konfiguration in `index.html` unterstützt alle modernen Browser! diff --git a/client/index.html b/client/index.html index 3143338..e7901ed 100644 --- a/client/index.html +++ b/client/index.html @@ -2,13 +2,80 @@ - + + + + + + - + + EmailSorter - Your inbox, finally organized + +
diff --git a/client/public/apple-touch-icon.svg b/client/public/apple-touch-icon.svg new file mode 100644 index 0000000..5bc58ca --- /dev/null +++ b/client/public/apple-touch-icon.svg @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + diff --git a/client/public/favicon-generator.html b/client/public/favicon-generator.html new file mode 100644 index 0000000..16a6df6 --- /dev/null +++ b/client/public/favicon-generator.html @@ -0,0 +1,144 @@ + + + + + + Favicon Generator - EmailSorter + + + +
+

📧 EmailSorter Favicon Generator

+

Diese Seite hilft dir beim Erstellen der Favicon-Dateien.

+ +
+
+ Favicon SVG + SVG (64x64)
+ Modern, skalierbar +
+
+ Apple Touch Icon + Apple Touch (180x180)
+ iOS Home Screen +
+
+ +
+

📋 Anleitung: Favicon-Dateien erstellen

+
    +
  1. Gehe zu einem Favicon-Generator: + +
  2. +
  3. Lade die SVG-Datei hoch: +
      +
    • Klicke auf "Select your Favicon image"
    • +
    • Wähle favicon.svg aus dem public/ Ordner
    • +
    +
  4. +
  5. Konfiguriere die Optionen: +
      +
    • ✅ iOS: Apple Touch Icon aktivieren
    • +
    • ✅ Android Chrome: Manifest aktivieren
    • +
    • ✅ Windows Metro: Optional
    • +
    +
  6. +
  7. Generiere und lade herunter: +
      +
    • Klicke auf "Generate your Favicons"
    • +
    • Lade das ZIP-Archiv herunter
    • +
    • Extrahiere alle Dateien in den client/public/ Ordner
    • +
    +
  8. +
  9. Verifiziere: +
      +
    • Starte den Dev-Server neu
    • +
    • Prüfe den Browser-Tab - das Favicon sollte erscheinen
    • +
    +
  10. +
+
+ +

📁 Benötigte Dateien

+

Nach der Konvertierung sollten folgende Dateien im public/ Ordner sein:

+ + +

🔗 Nützliche Links

+

+ Favicon Generator öffnen +

+
+ + diff --git a/client/public/favicon.svg b/client/public/favicon.svg new file mode 100644 index 0000000..0b126fb --- /dev/null +++ b/client/public/favicon.svg @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + diff --git a/client/public/site.webmanifest b/client/public/site.webmanifest new file mode 100644 index 0000000..b29fd0a --- /dev/null +++ b/client/public/site.webmanifest @@ -0,0 +1,21 @@ +{ + "name": "EmailSorter", + "short_name": "EmailSorter", + "description": "AI-powered email sorting for maximum productivity", + "icons": [ + { + "src": "/favicon-192x192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "/favicon-512x512.png", + "sizes": "512x512", + "type": "image/png" + } + ], + "theme_color": "#22c55e", + "background_color": "#ffffff", + "display": "standalone", + "start_url": "/" +} diff --git a/client/src/App.tsx b/client/src/App.tsx index b84db5f..f3f4bec 100644 --- a/client/src/App.tsx +++ b/client/src/App.tsx @@ -2,6 +2,7 @@ import { BrowserRouter, Routes, Route, Navigate } from 'react-router-dom' import { AuthProvider, useAuth } from '@/context/AuthContext' import { usePageTracking } from '@/hooks/useAnalytics' import { initAnalytics } from '@/lib/analytics' +import { useTheme } from '@/hooks/useTheme' import { Home } from '@/pages/Home' import { Login } from '@/pages/Login' import { Register } from '@/pages/Register' @@ -142,6 +143,9 @@ function AppRoutes() { } function App() { + // Initialize theme detection + useTheme() + return ( diff --git a/client/src/components/OnboardingProgress.tsx b/client/src/components/OnboardingProgress.tsx new file mode 100644 index 0000000..223ffa9 --- /dev/null +++ b/client/src/components/OnboardingProgress.tsx @@ -0,0 +1,87 @@ +import { Button } from '@/components/ui/button' +import { X, Check } from 'lucide-react' + +interface OnboardingProgressProps { + currentStep: string + completedSteps: string[] + totalSteps: number + onSkip: () => void +} + +const stepLabels: Record = { + 'not_started': 'Not started', + 'connect': 'Connect email', + 'first_rule': 'Create first rule', + 'see_results': 'See results', + 'auto_schedule': 'Enable automation', + 'completed': 'Completed', +} + +export function OnboardingProgress({ currentStep, completedSteps, totalSteps, onSkip }: OnboardingProgressProps) { + const stepIndex = ['connect', 'first_rule', 'see_results', 'auto_schedule'].indexOf(currentStep) + const currentStepNumber = stepIndex >= 0 ? stepIndex + 1 : 0 + const progress = totalSteps > 0 ? (completedSteps.length / totalSteps) * 100 : 0 + + if (currentStep === 'completed' || currentStep === 'not_started') { + return null + } + + return ( +
+
+
+

Getting started

+

Step {currentStepNumber} of {totalSteps}

+
+ +
+ + {/* Progress bar */} +
+
+
+ + {/* Step indicators */} +
+ {['connect', 'first_rule', 'see_results', 'auto_schedule'].map((step, idx) => { + const isCompleted = completedSteps.includes(step) + const isCurrent = currentStep === step + + return ( +
+
+ {isCompleted ? ( + + ) : ( + {idx + 1} + )} +
+ + {idx < 3 && ( +
+ )} +
+ ) + })} +
+
+ ) +} diff --git a/client/src/components/PrivacySecurity.tsx b/client/src/components/PrivacySecurity.tsx new file mode 100644 index 0000000..fef57e3 --- /dev/null +++ b/client/src/components/PrivacySecurity.tsx @@ -0,0 +1,226 @@ +import { Button } from '@/components/ui/button' +import { Card, CardContent, CardHeader, CardTitle, CardDescription } from '@/components/ui/card' +import { Shield, Lock, Trash2, X, Check, AlertTriangle } from 'lucide-react' +import { useState } from 'react' + +interface PrivacySecurityProps { + onDisconnect?: (accountId: string) => void + onDeleteAccount?: () => void + connectedAccounts?: Array<{ id: string; email: string; provider: string }> +} + +export function PrivacySecurity({ onDisconnect, onDeleteAccount, connectedAccounts = [] }: PrivacySecurityProps) { + const [showDeleteConfirm, setShowDeleteConfirm] = useState(false) + + return ( +
+ {/* What data is accessed */} + + + + + What data is accessed + + We only access what's necessary for sorting + + +
+ +
+

Email headers and metadata

+

+ We read: sender, subject, date, labels/categories. This is all we need to categorize emails. +

+
+
+
+ +
+

Email preview/snippet

+

+ We read the first few lines to help AI understand the email content. +

+
+
+
+
+ + {/* What is stored */} + + + + + What is stored + + Your data stays secure + + +
+ +
+

Your preferences

+

+ VIP senders, category settings, company labels, sorting rules. +

+
+
+
+ +
+

Statistics

+

+ Counts of sorted emails, categories, time saved. No email content. +

+
+
+
+ +
+

Account connection tokens

+

+ Encrypted OAuth tokens to access your email (required for sorting). +

+
+
+
+
+ + {/* What is never stored */} + + + + + What is never stored + + Your privacy is protected + + +
+ +
+

Email bodies/content

+

+ We never store the full content of your emails. +

+
+
+
+ +
+

Attachments

+

+ We never access or store file attachments. +

+
+
+
+ +
+

Passwords

+

+ We use OAuth - we never see or store your email passwords. +

+
+
+
+
+ + {/* How to disconnect */} + {connectedAccounts.length > 0 && ( + + + Disconnect email accounts + Remove access to your email accounts + + + {connectedAccounts.map((account) => ( +
+
+

{account.email}

+

{account.provider}

+
+ {onDisconnect && ( + + )} +
+ ))} +
+
+ )} + + {/* Delete account */} + {onDeleteAccount && ( + + + + + Delete my data + + Permanently delete all your data and account + + + {!showDeleteConfirm ? ( +
+
+

+ + This action cannot be undone +

+

+ This will delete all your preferences, statistics, connected accounts, and subscription data. +

+
+ +
+ ) : ( +
+
+

Are you absolutely sure?

+

+ This will permanently delete: +

+
    +
  • All your email account connections
  • +
  • All sorting statistics
  • +
  • All preferences and settings
  • +
  • Your subscription (if active)
  • +
+
+
+ + +
+
+ )} +
+
+ )} +
+ ) +} diff --git a/client/src/components/ShareResults.tsx b/client/src/components/ShareResults.tsx new file mode 100644 index 0000000..fe86028 --- /dev/null +++ b/client/src/components/ShareResults.tsx @@ -0,0 +1,101 @@ +import { Button } from '@/components/ui/button' +import { Share2, Copy, Check } from 'lucide-react' +import { useState } from 'react' +import { trackReferralShared } from '@/lib/analytics' +import { useAuth } from '@/context/AuthContext' + +interface ShareResultsProps { + sortedCount: number + referralCode?: string +} + +export function ShareResults({ sortedCount, referralCode }: ShareResultsProps) { + const [copied, setCopied] = useState(false) + const { user } = useAuth() + + const shareText = `I cleaned up ${sortedCount} emails with EmailSorter${referralCode ? `! Use code ${referralCode} for a bonus.` : '!'}` + const shareUrl = referralCode + ? `${window.location.origin}?ref=${referralCode}` + : window.location.origin + + const handleCopy = async () => { + const text = `${shareText}\n${shareUrl}` + try { + await navigator.clipboard.writeText(text) + setCopied(true) + setTimeout(() => setCopied(false), 2000) + } catch (err) { + console.error('Failed to copy:', err) + } + } + + const handleShare = async () => { + if (navigator.share) { + try { + await navigator.share({ + title: 'EmailSorter - Clean Inbox', + text: shareText, + url: shareUrl, + }) + if (user?.$id && referralCode) { + trackReferralShared(user.$id, referralCode) + } + } catch (err) { + // User cancelled or error + console.error('Share failed:', err) + } + } else { + // Fallback to copy + handleCopy() + } + } + + if (sortedCount < 10) { + return null // Don't show for small results + } + + return ( +
+
+
+ +
+
+

Share your success!

+

+ {shareText} +

+
+
+
+ {typeof navigator !== 'undefined' && 'share' in navigator && typeof navigator.share === 'function' && ( + + )} + +
+
+ ) +} diff --git a/client/src/components/UpgradePrompt.tsx b/client/src/components/UpgradePrompt.tsx new file mode 100644 index 0000000..78bafd6 --- /dev/null +++ b/client/src/components/UpgradePrompt.tsx @@ -0,0 +1,113 @@ +import { Button } from '@/components/ui/button' +import { X, Sparkles, Zap, Infinity } from 'lucide-react' +import { useNavigate } from 'react-router-dom' +import { trackUpgradeClicked } from '@/lib/analytics' +import { useAuth } from '@/context/AuthContext' + +interface UpgradePromptProps { + title?: string + benefits?: string[] + source: 'after_sort' | 'limit_reached' | 'auto_schedule' | 'after_rules' + onDismiss: () => void +} + +const defaultBenefits: Record = { + after_sort: [ + 'Sort unlimited emails automatically', + 'Set up auto-schedule for hands-free organization', + 'Access all premium features', + ], + limit_reached: [ + 'Unlimited email sorting', + 'No monthly limits', + 'Priority support', + ], + auto_schedule: [ + 'Auto-schedule available in Pro plan', + 'Set it and forget it', + 'Keep your inbox clean automatically', + ], + after_rules: [ + 'Automate with Pro plan', + 'Unlimited rules and customizations', + 'Advanced AI features', + ], +} + +export function UpgradePrompt({ + title = 'Keep your inbox clean automatically', + benefits, + source, + onDismiss, +}: UpgradePromptProps) { + const navigate = useNavigate() + const { user } = useAuth() + const promptBenefits = benefits || defaultBenefits[source] || defaultBenefits.after_sort + + // Check if this prompt was already shown in this session + const sessionKey = `upgrade_prompt_shown_${source}` + const wasShown = sessionStorage.getItem(sessionKey) === 'true' + + if (wasShown) { + return null + } + + const handleUpgrade = () => { + if (user?.$id) { + trackUpgradeClicked(user.$id, source) + } + navigate('/settings?tab=subscription') + } + + const handleDismiss = () => { + sessionStorage.setItem(sessionKey, 'true') + onDismiss() + } + + return ( +
+
+
+
+ +
+
+

{title}

+
+
+ +
+ +
    + {promptBenefits.map((benefit, idx) => ( +
  • + + {benefit} +
  • + ))} +
+ +
+ + +
+
+ ) +} diff --git a/client/src/components/landing/Features.tsx b/client/src/components/landing/Features.tsx index 16d3162..56641b0 100644 --- a/client/src/components/landing/Features.tsx +++ b/client/src/components/landing/Features.tsx @@ -3,7 +3,6 @@ import { Zap, Shield, Clock, - Tags, Settings, Inbox, Filter @@ -11,39 +10,42 @@ import { const features = [ { - icon: Brain, - title: "AI-powered categorization", - description: "Our AI automatically recognizes whether an email is an invoice, newsletter, or important message.", - color: "from-violet-500 to-purple-600" + icon: Inbox, + title: "Stop drowning in emails", + description: "Clear inbox, less stress. Automatically sort newsletters, promotions, and social updates away from what matters.", + color: "from-violet-500 to-purple-600", + highlight: true, }, { icon: Zap, - title: "Real-time sorting", - description: "New emails are categorized instantly. Your inbox arrives already sorted.", - color: "from-amber-500 to-orange-600" + title: "One-click smart rules", + description: "AI suggests, you approve. Create smart rules in seconds and apply them with one click.", + color: "from-amber-500 to-orange-600", + highlight: true, }, { - icon: Tags, - title: "Smart labels", - description: "Automatic labels for VIP, clients, invoices, newsletters, social media and more.", - color: "from-blue-500 to-cyan-600" + icon: Settings, + title: "Automation that keeps working", + description: "Set it and forget it. Your inbox stays organized automatically, day after day.", + color: "from-blue-500 to-cyan-600", + highlight: true, + }, + { + icon: Brain, + title: "AI-powered smart sorting", + description: "Our AI automatically recognizes whether an email is an invoice, newsletter, or important message.", + color: "from-green-500 to-emerald-600" }, { icon: Shield, title: "GDPR compliant", description: "Your data stays secure. We only read email headers and metadata for sorting.", - color: "from-green-500 to-emerald-600" + color: "from-pink-500 to-rose-600" }, { icon: Clock, title: "Save time", description: "Average 2 hours per week less on email organization. More time for what matters.", - color: "from-pink-500 to-rose-600" - }, - { - icon: Settings, - title: "Fully customizable", - description: "Define your own rules, VIP contacts, and categories based on your needs.", color: "from-indigo-500 to-blue-600" }, ] @@ -119,18 +121,23 @@ interface FeatureCardProps { description: string color: string index: number + highlight?: boolean } -function FeatureCard({ icon: Icon, title, description, color, index }: FeatureCardProps) { +function FeatureCard({ icon: Icon, title, description, color, index, highlight }: FeatureCardProps) { return (
-
+
-

{title}

+

{title}

{description}

) diff --git a/client/src/components/landing/Footer.tsx b/client/src/components/landing/Footer.tsx index fdab605..d97e5dd 100644 --- a/client/src/components/landing/Footer.tsx +++ b/client/src/components/landing/Footer.tsx @@ -13,7 +13,7 @@ export function Footer() {
- EmailSorter + E-Mail-Sorter

@@ -132,6 +132,11 @@ export function Footer() { Privacy Policy +

  • + + Privacy & Security + +
  • Impressum diff --git a/client/src/components/landing/Hero.tsx b/client/src/components/landing/Hero.tsx index 221f033..c4e0f65 100644 --- a/client/src/components/landing/Hero.tsx +++ b/client/src/components/landing/Hero.tsx @@ -37,35 +37,35 @@ export function Hero() {

    - Your inbox. + Clean inbox automatically
    - Finally organized. + in minutes.

    - EmailSorter uses AI to automatically categorize your emails. - Newsletters, invoices, important contacts – everything lands - exactly where it belongs. + Create smart rules, apply in one click, keep it clean with automation. + Stop drowning in emails and start focusing on what matters.

    diff --git a/client/src/components/landing/Navbar.tsx b/client/src/components/landing/Navbar.tsx index c5dce71..0447d7b 100644 --- a/client/src/components/landing/Navbar.tsx +++ b/client/src/components/landing/Navbar.tsx @@ -28,7 +28,7 @@ export function Navbar() { }, [location.pathname, navigate]) return ( -