diff --git a/src/components/layout/AppSidebar.tsx b/src/components/layout/AppSidebar.tsx
index 7e5f5c4..bf50fcf 100644
--- a/src/components/layout/AppSidebar.tsx
+++ b/src/components/layout/AppSidebar.tsx
@@ -1,3 +1,4 @@
+import { openSupportTicketPortal, prefetchSupportUrl } from '@/lib/support'
import { NavLink, useLocation } from 'react-router-dom'
import { Ic, type IconName } from '@/icons'
import {
@@ -28,6 +29,7 @@ function BillingSidebarBadges() {
const { t } = useTranslation()
React.useEffect(() => {
+ prefetchSupportUrl()
fetchCounts()
// Poll every 30 seconds for live updates
const interval = setInterval(fetchCounts, 30000)
@@ -268,6 +270,19 @@ function NavItem({ item }: { item: NavItemConfig }) {
)}
>
)
+ if (item.isExternalSupport) {
+ return (
+
+ openSupportTicketPortal()}
+ className="cursor-pointer text-primary hover:bg-primary/10"
+ >
+ {inner}
+
+
+ )
+ }
return (
diff --git a/src/config/navigation.ts b/src/config/navigation.ts
index a77f530..042840c 100644
--- a/src/config/navigation.ts
+++ b/src/config/navigation.ts
@@ -12,6 +12,7 @@ export interface NavSubItemConfig {
}
export interface NavItemConfig {
+ isExternalSupport?: boolean
title: string
titleKey?: string
to?: string
@@ -127,7 +128,7 @@ export function getNavigationConfig(t: (key: string) => string): NavGroupConfig[
],
},
{ title: t('navigation.costEstimate'), titleKey: 'navigation.costEstimate', to: '/services/cost-estimate', icon: 'calculator' },
- { title: t('navigation.support'), titleKey: 'navigation.support', to: '/services/consultant', icon: 'headset' },
+ { title: t('navigation.support'), titleKey: 'navigation.support', isExternalSupport: true, icon: 'headset' },
{ title: t('navigation.faq'), titleKey: 'navigation.faq', to: '/services/faq', icon: 'helpCircle' },
{ title: t('navigation.settings'), titleKey: 'navigation.settings', to: '/settings', icon: 'settings' },
],
diff --git a/src/lib/support.ts b/src/lib/support.ts
new file mode 100644
index 0000000..ca5b89a
--- /dev/null
+++ b/src/lib/support.ts
@@ -0,0 +1,67 @@
+import { apiFetch } from '@/services/http'
+
+let cachedSupportUrl: string | null = null
+
+function getActiveLanguageAndTheme(): { lang: string; theme: string } {
+ const isDark = document.documentElement.classList.contains('dark') || document.body.classList.contains('dark')
+ const theme = isDark ? 'dark' : 'light'
+
+ const htmlLang = document.documentElement.lang || ''
+ const htmlDir = document.documentElement.dir || ''
+ const storedLang = localStorage.getItem('i18nextLng') || localStorage.getItem('lang') || ''
+
+ let lang = 'fa'
+ if (htmlLang.startsWith('en') || storedLang.startsWith('en')) {
+ lang = 'en'
+ } else if (htmlDir === 'ltr' && !storedLang.startsWith('fa')) {
+ lang = 'en'
+ }
+
+ return { lang, theme }
+}
+
+export function prefetchSupportUrl(): void {
+ if (cachedSupportUrl) return
+ const { lang, theme } = getActiveLanguageAndTheme()
+ apiFetch<{ success: boolean; url: string }>(`/support/ticket-url/?lang=${lang}&theme=${theme}`)
+ .then((data) => {
+ if (data && data.url) {
+ cachedSupportUrl = data.url
+ }
+ })
+ .catch(() => {
+ // Ignore background errors
+ })
+}
+
+export async function openSupportTicketPortal(): Promise {
+ const { lang, theme } = getActiveLanguageAndTheme()
+
+ let baseUrl = cachedSupportUrl
+
+ if (!baseUrl) {
+ try {
+ const data = await apiFetch<{ success: boolean; url: string }>(`/support/ticket-url/?lang=${lang}&theme=${theme}`)
+ if (data && data.url) {
+ cachedSupportUrl = data.url
+ baseUrl = data.url
+ }
+ } catch {
+ // ignore
+ }
+ }
+
+ if (!baseUrl) {
+ baseUrl = 'https://teamby.nwhco.ir/portal/76cb859c-24e3-4309-9d99-504ac2e49268/'
+ }
+
+ try {
+ const urlObj = new URL(baseUrl)
+ urlObj.searchParams.set('lang', lang)
+ urlObj.searchParams.set('theme', theme)
+ window.open(urlObj.toString(), '_blank')
+ } catch {
+ const sep = baseUrl.includes('?') ? '&' : '?'
+ window.open(`${baseUrl}${sep}lang=${lang}&theme=${theme}`, '_blank')
+ }
+}