diff --git a/frontend/messages/en.json b/frontend/messages/en.json index 3b34cec..f1b8e57 100644 --- a/frontend/messages/en.json +++ b/frontend/messages/en.json @@ -1,6 +1,6 @@ { "common": { - "appName": "DyoLink", + "appName": "Nudentic", "loading": "Loading...", "loadingApp": "Loading app...", "loadingWorkspace": "Loading workspace...", @@ -168,7 +168,7 @@ "featureRealtimeDescription": "Get instant notifications on case status changes.", "featureSecurityTitle": "Secure & Compliant", "featureSecurityDescription": "HIPAA-compliant with enterprise-grade security.", - "footerCopyright": "© 2026 DyoLink. All rights reserved.", + "footerCopyright": "© 2026 Nudentic. All rights reserved.", "termsAndConditions": "Terms & Conditions" }, "accountMenu": { @@ -854,7 +854,7 @@ }, "organizations": { "loadingOrganization": "Loading organization...", - "subtitle": "Search organizations, send connection requests to existing accounts, or invitation links when they are not on DyoLink yet.", + "subtitle": "Search organizations, send connection requests to existing accounts, or invitation links when they are not on Nudentic yet.", "invitationHistory": "Invitation History", "searchPlaceholder": "Search {counterpart} by name, email, or phone...", "backToList": "Back to list", @@ -948,7 +948,7 @@ "passwordChanged": "Password updated. Please sign in again.", "passwordChangeFailed": "Could not update password. Please try again.", "subscriptionsTitle": "Subscriptions", - "subscriptionsSubtitle": "Your DyoLink workspace plan and seats for {orgName}. Clinic and lab income tracking stays under the sidebar Billing tab.", + "subscriptionsSubtitle": "Your Nudentic workspace plan and seats for {orgName}. Clinic and lab income tracking stays under the sidebar Billing tab.", "noSubscriptionNotice": "This organization has no active subscription. Select a plan below to start the purchase process.", "currentPlan": "Current plan", "planPrice": "Plan price", diff --git a/frontend/messages/fa.json b/frontend/messages/fa.json index 1c8f582..44c32f3 100644 --- a/frontend/messages/fa.json +++ b/frontend/messages/fa.json @@ -1,6 +1,6 @@ { "common": { - "appName": "DyoLink", + "appName": "Nudentic", "loading": "در حال بارگذاری...", "loadingApp": "در حال بارگذاری برنامه...", "loadingWorkspace": "در حال بارگذاری فضای کاری...", @@ -168,7 +168,7 @@ "featureRealtimeDescription": "اعلان‌های فوری درباره تغییر وضعیت پرونده‌ها دریافت کنید.", "featureSecurityTitle": "امن و منطبق با استانداردها", "featureSecurityDescription": "منطبق با HIPAA و دارای امنیت در سطح سازمانی.", - "footerCopyright": "© ۲۰۲۶ DyoLink. تمامی حقوق محفوظ است.", + "footerCopyright": "© ۲۰۲۶ Nudentic. تمامی حقوق محفوظ است.", "termsAndConditions": "شرایط و ضوابط" }, "accountMenu": { @@ -855,7 +855,7 @@ }, "organizations": { "loadingOrganization": "در حال بارگذاری سازمان...", - "subtitle": "سازمان‌ها را جستجو کنید، درخواست اتصال به حساب‌های موجود ارسال کنید، یا اگر هنوز در DyoLink نیستند، لینک دعوت ارسال کنید.", + "subtitle": "سازمان‌ها را جستجو کنید، درخواست اتصال به حساب‌های موجود ارسال کنید، یا اگر هنوز در Nudentic نیستند، لینک دعوت ارسال کنید.", "invitationHistory": "تاریخچه دعوت‌نامه‌ها", "searchPlaceholder": "جستجوی {counterpart} بر اساس نام، ایمیل یا تلفن...", "backToList": "بازگشت به لیست", @@ -949,7 +949,7 @@ "passwordChanged": "رمز عبور به‌روزرسانی شد. لطفاً دوباره وارد شوید.", "passwordChangeFailed": "به‌روزرسانی رمز عبور انجام نشد. دوباره تلاش کنید.", "subscriptionsTitle": "اشتراک‌ها", - "subscriptionsSubtitle": "طرح و مجوزهای فضای کاری DyoLink شما برای {orgName}. پیگیری درآمد کلینیک و لابراتوار در برگه صورتحساب در نوار کناری قرار دارد.", + "subscriptionsSubtitle": "طرح و مجوزهای فضای کاری Nudentic شما برای {orgName}. پیگیری درآمد کلینیک و لابراتوار در برگه صورتحساب در نوار کناری قرار دارد.", "noSubscriptionNotice": "این سازمان اشتراک فعالی ندارد. برای شروع فرآیند خرید، یک طرح زیر را انتخاب کنید.", "currentPlan": "طرح فعلی", "planPrice": "قیمت طرح", diff --git a/frontend/messages/nl.json b/frontend/messages/nl.json index 4dbc56b..46c1ecf 100644 --- a/frontend/messages/nl.json +++ b/frontend/messages/nl.json @@ -1,6 +1,6 @@ { "common": { - "appName": "DyoLink", + "appName": "Nudentic", "loading": "Laden...", "loadingApp": "Applicatie laden...", "loadingWorkspace": "Werkruimte laden...", @@ -168,7 +168,7 @@ "featureRealtimeDescription": "Ontvang direct meldingen bij statuswijzigingen van casussen.", "featureSecurityTitle": "Veilig & Conform", "featureSecurityDescription": "HIPAA-conform met beveiliging op ondernemingsniveau.", - "footerCopyright": "© 2026 DyoLink. Alle rechten voorbehouden.", + "footerCopyright": "© 2026 Nudentic. Alle rechten voorbehouden.", "termsAndConditions": "Algemene Voorwaarden" }, "accountMenu": { @@ -854,7 +854,7 @@ }, "organizations": { "loadingOrganization": "Organisatie laden...", - "subtitle": "Zoek organisaties, stuur verbindingsverzoeken naar bestaande accounts, of uitnodigingslinks wanneer ze nog niet op DyoLink staan.", + "subtitle": "Zoek organisaties, stuur verbindingsverzoeken naar bestaande accounts, of uitnodigingslinks wanneer ze nog niet op Nudentic staan.", "invitationHistory": "Uitnodigingsgeschiedenis", "searchPlaceholder": "Zoek {counterpart} op naam, e-mail of telefoon...", "backToList": "Terug naar lijst", @@ -948,7 +948,7 @@ "passwordChanged": "Wachtwoord bijgewerkt. Log opnieuw in.", "passwordChangeFailed": "Wachtwoord kon niet worden bijgewerkt. Probeer het opnieuw.", "subscriptionsTitle": "Abonnementen", - "subscriptionsSubtitle": "Uw DyoLink-werkruimteplan en plaatsen voor {orgName}. Kliniek- en laboratoriuminkomsten blijven onder het tabblad Facturatie in de zijbalk.", + "subscriptionsSubtitle": "Uw Nudentic-werkruimteplan en plaatsen voor {orgName}. Kliniek- en laboratoriuminkomsten blijven onder het tabblad Facturatie in de zijbalk.", "noSubscriptionNotice": "Deze organisatie heeft geen actief abonnement. Selecteer hieronder een abonnement om het aankoopproces te starten.", "currentPlan": "Huidig abonnement", "planPrice": "Abonnementsprijs", diff --git a/frontend/src/app/[locale]/(public)/accept-organization-invite/page.tsx b/frontend/src/app/[locale]/(public)/accept-organization-invite/page.tsx index 7745e07..90dcb3c 100644 --- a/frontend/src/app/[locale]/(public)/accept-organization-invite/page.tsx +++ b/frontend/src/app/[locale]/(public)/accept-organization-invite/page.tsx @@ -10,6 +10,7 @@ import { zodResolver } from '@hookform/resolvers/zod'; import * as z from 'zod'; import { Lock, Mail, User } from 'lucide-react'; import { AuthPageShell } from '@/components/ui/auth/AuthPageShell'; +import { BrandWordmark } from '@/components/ui/shared/BrandWordmark'; import { Button } from '@/components/ui/shared/Button'; import { Input } from '@/components/ui/shared/Input'; import { OrganizationDetailsFields } from '@/components/ui/auth/OrganizationDetailsFields'; @@ -179,9 +180,7 @@ function AcceptOrganizationInviteContent() { header={ <> - - {tCommon('appName')} - +

{t('acceptOrganizationTitle')} diff --git a/frontend/src/app/[locale]/(public)/forgot-password/page.tsx b/frontend/src/app/[locale]/(public)/forgot-password/page.tsx index 1f2aa19..2cefe28 100644 --- a/frontend/src/app/[locale]/(public)/forgot-password/page.tsx +++ b/frontend/src/app/[locale]/(public)/forgot-password/page.tsx @@ -11,6 +11,7 @@ import { authApi } from '@/lib/api/auth'; import { getUserFacingError } from '@/components/shared/formatApiError'; import { useAuth } from '@/lib/hooks/useAuth'; import { AuthPageShell } from '@/components/ui/auth/AuthPageShell'; +import { BrandWordmark } from '@/components/ui/shared/BrandWordmark'; import { Button } from '@/components/ui/shared/Button'; import { Input } from '@/components/ui/shared/Input'; @@ -28,7 +29,6 @@ function normalizeIranMobile(input: string): string { export default function ForgotPasswordPage() { const t = useTranslations('auth'); - const tCommon = useTranslations('common'); const tValidation = useTranslations('validation'); const tErrors = useTranslations('errors'); const router = useRouter(); @@ -128,9 +128,7 @@ export default function ForgotPasswordPage() { header={ <> - - {tCommon('appName')} - +

{t('forgotPasswordTitle')} diff --git a/frontend/src/app/[locale]/(public)/login/page.tsx b/frontend/src/app/[locale]/(public)/login/page.tsx index 35a6cc1..9ecd841 100644 --- a/frontend/src/app/[locale]/(public)/login/page.tsx +++ b/frontend/src/app/[locale]/(public)/login/page.tsx @@ -12,6 +12,7 @@ import { getUserFacingError } from '@/components/shared/formatApiError'; import { useAuth } from '@/lib/hooks/useAuth'; import { getRememberedEmail } from '@/lib/auth/rememberMe'; import { AuthPageShell } from '@/components/ui/auth/AuthPageShell'; +import { BrandWordmark } from '@/components/ui/shared/BrandWordmark'; import { Button } from '@/components/ui/shared/Button'; import { Checkbox } from '@/components/ui/shared/Checkbox'; import { Input } from '@/components/ui/shared/Input'; @@ -91,9 +92,7 @@ function LoginPageContent() { header={ <> - - {tCommon('appName')} - +

{t('signInTitle')} diff --git a/frontend/src/app/[locale]/(public)/page.tsx b/frontend/src/app/[locale]/(public)/page.tsx index 5f620c9..dc998fb 100644 --- a/frontend/src/app/[locale]/(public)/page.tsx +++ b/frontend/src/app/[locale]/(public)/page.tsx @@ -5,20 +5,20 @@ import { Link } from '@/i18n/navigation'; import { useAuth } from '@/lib/hooks/useAuth'; import { Button } from '@/components/ui/shared/Button'; import { TopBarControls } from '@/components/ui/shared/TopBarControls'; +import { BrandWordmark } from '@/components/ui/shared/BrandWordmark'; import { Building2, Beaker, Calendar, Shield, Clock, Users } from 'lucide-react'; export default function HomePage() { const t = useTranslations('landing'); const tAuth = useTranslations('auth'); - const tCommon = useTranslations('common'); const { user, isAuthReady } = useAuth(); return (
- - {tCommon('appName')} + +
diff --git a/frontend/src/app/[locale]/(public)/register/page.tsx b/frontend/src/app/[locale]/(public)/register/page.tsx index 6d17c13..2bb9c52 100644 --- a/frontend/src/app/[locale]/(public)/register/page.tsx +++ b/frontend/src/app/[locale]/(public)/register/page.tsx @@ -11,6 +11,7 @@ import { getUserFacingError } from '@/components/shared/formatApiError'; import { useAuth } from '@/lib/hooks/useAuth'; import { useEnterAppWhenAuthenticated } from '@/lib/hooks/useEnterAppWhenAuthenticated'; import { AuthPageShell } from '@/components/ui/auth/AuthPageShell'; +import { BrandWordmark } from '@/components/ui/shared/BrandWordmark'; import { OrganizationDetailsFields } from '@/components/ui/auth/OrganizationDetailsFields'; import { RegistrationProgressSteps } from '@/components/ui/auth/RegistrationProgressSteps'; import { Button } from '@/components/ui/shared/Button'; @@ -136,9 +137,7 @@ export default function RegisterPage() { header={ <> - - {tCommon('appName')} - +

{t('registerTitle')} diff --git a/frontend/src/app/[locale]/layout.tsx b/frontend/src/app/[locale]/layout.tsx index 5fffee5..9969ef5 100644 --- a/frontend/src/app/[locale]/layout.tsx +++ b/frontend/src/app/[locale]/layout.tsx @@ -13,7 +13,7 @@ import { routing, isRtlLocale, localeHtmlLang } from '@/i18n/routing'; import { LocaleSync } from '@/components/i18n/LocaleSync'; export const metadata: Metadata = { - title: 'DyoLink - Dental Clinic & Lab Communication Hub', + title: 'Nudentic - Dental Clinic & Lab Communication Hub', description: 'Connect dental clinics and laboratories seamlessly', }; diff --git a/frontend/src/components/ui/lab/CaseSheetPrintLayout.tsx b/frontend/src/components/ui/lab/CaseSheetPrintLayout.tsx index 1338d24..70ea09a 100644 --- a/frontend/src/components/ui/lab/CaseSheetPrintLayout.tsx +++ b/frontend/src/components/ui/lab/CaseSheetPrintLayout.tsx @@ -12,6 +12,7 @@ import { formatToothList } from '@/components/treatment/prosthesisTypeDisplay'; import type { LabCaseDetail } from '@/types/cases'; import type { ProsthesisCatalogEntry } from '@/types/treatment-catalog'; import type { FdiToothId } from '@/types/treatment'; +import { BrandWordmark, BRAND_PRIMARY_HEX } from '@/components/ui/shared/BrandWordmark'; export type CaseSheetLabels = { title: string; @@ -89,7 +90,9 @@ export function CaseSheetPrintLayout({ }} >
-

Dyolink

+

+ +

{labels.title}

{labCase.shareUrl ? ( diff --git a/frontend/src/components/ui/shared/BrandWordmark.tsx b/frontend/src/components/ui/shared/BrandWordmark.tsx new file mode 100644 index 0000000..080630a --- /dev/null +++ b/frontend/src/components/ui/shared/BrandWordmark.tsx @@ -0,0 +1,44 @@ +import type { CSSProperties } from 'react'; + +export const BRAND_NAME = 'Nudentic'; + +/** Light-theme primary — use in print/PDF where theme tokens are unsafe. */ +export const BRAND_PRIMARY_HEX = '#009cae'; + +type BrandWordmarkProps = { + className?: string; + style?: CSSProperties; + /** + * i-dot color. Omit to use the theme primary token. + * Pass a hex (e.g. `BRAND_PRIMARY_HEX`) for print/PDF capture. + */ + dotColor?: string; +}; + +function BrandI({ fill }: { fill: string }) { + return ( + + + + + ); +} + +export function BrandWordmark({ className, style, dotColor }: BrandWordmarkProps) { + const tittleFill = dotColor ?? 'var(--color-primary)'; + + return ( + + {BRAND_NAME} + + Nudent + + c + + + ); +} diff --git a/frontend/src/components/ui/shared/Sidebar.tsx b/frontend/src/components/ui/shared/Sidebar.tsx index 027d3a7..c1e79a2 100644 --- a/frontend/src/components/ui/shared/Sidebar.tsx +++ b/frontend/src/components/ui/shared/Sidebar.tsx @@ -21,6 +21,7 @@ import { usePendingConnectionsCount } from '@/lib/hooks/usePendingConnectionsCou import { useTabBadgeCounts } from '@/lib/hooks/useTabBadgeCounts'; import { badgeCountForPath } from '@/lib/tabBadgeUtils'; import { NavBadgePill } from '@/components/ui/shared/NavBadgePill'; +import { BrandWordmark } from '@/components/ui/shared/BrandWordmark'; import { canViewAppointmentsTab, canViewCases, @@ -110,7 +111,9 @@ function Sidebar({ mobileOpen = false, onClose }: SidebarProps) { }`} >
-

{tCommon('appName')}

+

+ +

{onClose ? (