From 67365918aecc2c8b8c135e72e38301e9a138f753 Mon Sep 17 00:00:00 2001 From: sepehr Date: Sun, 30 Aug 2026 22:42:29 +0200 Subject: [PATCH] =?UTF-8?q?feat(ui,api):=20wave=203=20=E2=80=94=20editoria?= =?UTF-8?q?l=20pricing,=20real=20cancel,=20server=20history,=20DeepL=20pur?= =?UTF-8?q?ge?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pricing: full editorial redesign — serif card headers with accent pills replace the colored font-black blocks, tone sweep across toggle/metrics/ features/CTAs, PLAN_COLORS removed; one design system app-wide. Translate: decorative titles one step down (CTA hierarchy restored); glossary and image-translation blocks hidden entirely for free users (progressive disclosure — three controls for free). Reviews: XLIFF hint line explains the exchange format; backend errors routed through a friendly mapper (session/not-found/rate-limit/server). Landing: fabricated hero UI cards (fake 'Context Engine' overlay) removed — the photo no longer promises screens that don't exist. Nav: single DashboardNavLinks component shared by sidebar and mobile drawer (was duplicated markup). API: GET /api/v1/translations (user job history, paginated; completed jobs retained 24h) and POST /api/v1/translations/{id}/cancel — cooperative cancellation with worker checkpoints before dispatch and before finalisation, reserved quota released immediately. Translate monitor now offers a real 'Cancel translation' next to 'Back to start'; recent-jobs list reads server history first, localStorage fallback. DeepL purge (backend): provider module, registry registration, config attrs/defaults, dispatch branch, admin settings schema + test branch, legacy availability block, validation rules, plan provider lists, error-code mappings, MCP enums, translator prompt mention, related tests updated/removed. Fallback resolver skips unknown providers, so stale chains containing 'deepl' degrade gracefully. Verified: backend 110 tests passed; frontend build exit 0, vitest 9/9, 0 missing i18n keys, eslint 63 errors (vs 64 at HEAD). --- config.py | 1 - .../src/app/dashboard/DashboardHeader.tsx | 28 +- .../src/app/dashboard/DashboardNavLinks.tsx | 42 + .../src/app/dashboard/DashboardSidebar.tsx | 26 +- .../app/dashboard/reviews/[jobId]/page.tsx | 22 +- frontend/src/app/dashboard/translate/page.tsx | 49 +- frontend/src/app/dashboard/translate/types.ts | 2 + .../translate/useTranslationSubmit.ts | 47 ++ frontend/src/app/pricing/page.tsx | 90 +-- .../src/components/landing/landing-page.tsx | 23 - .../src/lib/i18n/messages/en/reviews.json | 7 +- .../src/lib/i18n/messages/en/translate.json | 11 +- .../src/lib/i18n/messages/fr/reviews.json | 7 +- .../src/lib/i18n/messages/fr/translate.json | 11 +- mcp_server.py | 4 +- middleware/validation.py | 10 +- models/subscription.py | 8 +- routes/admin_routes.py | 23 +- routes/legacy_routes.py | 10 - routes/translate_routes.py | 158 +++- scripts/generate_test_files.py | 2 +- services/providers/__init__.py | 9 +- services/providers/base.py | 2 +- services/providers/config.py | 24 +- services/providers/deepl_provider.py | 757 ------------------ services/providers/fallback.py | 6 +- services/providers/registry.py | 2 +- services/translation_service.py | 68 +- tests/test_download_endpoint.py | 2 +- tests/test_plan_gating.py | 4 +- tests/test_providers/test_deepl_provider.py | 488 ----------- tests/test_story_2_16_url_ingestion.py | 14 +- tests/test_translate_endpoint.py | 6 +- tests/test_translation_cache.py | 2 +- utils/exceptions.py | 5 - 35 files changed, 398 insertions(+), 1572 deletions(-) create mode 100644 frontend/src/app/dashboard/DashboardNavLinks.tsx delete mode 100644 services/providers/deepl_provider.py delete mode 100644 tests/test_providers/test_deepl_provider.py diff --git a/config.py b/config.py index 2c220a8..5509ecf 100644 --- a/config.py +++ b/config.py @@ -13,7 +13,6 @@ load_dotenv() class Config: # ============== Translation Service ============== TRANSLATION_SERVICE = os.getenv("TRANSLATION_SERVICE", "google") - DEEPL_API_KEY = os.getenv("DEEPL_API_KEY", "") # ============== File Upload Configuration ============== diff --git a/frontend/src/app/dashboard/DashboardHeader.tsx b/frontend/src/app/dashboard/DashboardHeader.tsx index abbcf5e..095641d 100644 --- a/frontend/src/app/dashboard/DashboardHeader.tsx +++ b/frontend/src/app/dashboard/DashboardHeader.tsx @@ -2,30 +2,24 @@ import { useState } from 'react'; import Link from 'next/link'; -import { usePathname } from 'next/navigation'; import { Menu, X, LogOut } from 'lucide-react'; -import { cn } from '@/lib/utils'; import { useUser } from './useUser'; import { useLogout } from './useLogout'; -import { baseNavItems } from './constants'; +import { DashboardNavLinks } from './DashboardNavLinks'; import { getInitials, translateTier } from './utils'; import { ThemeToggle } from '@/components/ui/theme-toggle'; import { useI18n } from '@/lib/i18n'; export function DashboardHeader() { const [mobileOpen, setMobileOpen] = useState(false); - const pathname = usePathname(); const { data: user, isLoading } = useUser(); const { logout } = useLogout(); const { t } = useI18n(); - const isPro = ['pro', 'business', 'enterprise'].includes(user?.tier ?? ''); - const navItems = isPro ? baseNavItems : baseNavItems.filter(item => !item.proOnly); - return ( <>
@@ -97,25 +91,7 @@ export function DashboardHeader() { {mobileOpen && (