diff --git a/src/features/communications/CommunicationsModule.tsx b/src/features/communications/CommunicationsModule.tsx index cb00d71..20671b2 100644 --- a/src/features/communications/CommunicationsModule.tsx +++ b/src/features/communications/CommunicationsModule.tsx @@ -26,6 +26,9 @@ export function CommunicationsModule() { const [connectMode, setConnectMode] = useState<'messenger' | 'email'>('messenger'); const [showEmailTab, setShowEmailTab] = useState(() => localStorage.getItem('krona-show-email') === 'true'); const [showChannelsTab, setShowChannelsTab] = useState(() => localStorage.getItem('krona-show-bot-channels') === 'true'); + const [orgEmailAllowed, setOrgEmailAllowed] = useState(() => localStorage.getItem('krona-org-email-allowed') !== 'false'); + const [orgChannelsAllowed, setOrgChannelsAllowed] = useState(() => localStorage.getItem('krona-org-channels-allowed') !== 'false'); + const [canConnectAccounts, setCanConnectAccounts] = useState(() => localStorage.getItem('krona-org-connect-accounts') !== 'false'); const updateEmailVisibility = (enabled: boolean) => { setShowEmailTab(enabled); @@ -39,6 +42,23 @@ export function CommunicationsModule() { if (!enabled && currentTab === 'channels') handleTabChange('settings'); }; + const updateOrgEmailAllowed = (enabled: boolean) => { + setOrgEmailAllowed(enabled); + localStorage.setItem('krona-org-email-allowed', String(enabled)); + if (!enabled) updateEmailVisibility(false); + }; + + const updateOrgChannelsAllowed = (enabled: boolean) => { + setOrgChannelsAllowed(enabled); + localStorage.setItem('krona-org-channels-allowed', String(enabled)); + if (!enabled) updateChannelsVisibility(false); + }; + + const updateCanConnectAccounts = (enabled: boolean) => { + setCanConnectAccounts(enabled); + localStorage.setItem('krona-org-connect-accounts', String(enabled)); + }; + // Sync tab with URL search param const urlTab = searchParams.get('tab') as CommunicationTab | null; const requestedTab = urlTab && ['messengers', 'email', 'channels', 'contacts', 'settings'].includes(urlTab) ? urlTab : activeTab; @@ -62,9 +82,9 @@ export function CommunicationsModule() { onTabChange={handleTabChange} unreadChats={48} unreadEmails={10} - unreadChannels={4} - showEmailTab={showEmailTab} - showChannelsTab={showChannelsTab} + unreadChannels={4} + showEmailTab={showEmailTab && orgEmailAllowed} + showChannelsTab={showChannelsTab && orgChannelsAllowed} /> @@ -72,12 +92,12 @@ export function CommunicationsModule() {
{currentTab === 'messengers' && ( { setConnectMode('messenger'); setIsConnectChannelOpen(true); }} + onOpenConnectModal={canConnectAccounts ? () => { setConnectMode('messenger'); setIsConnectChannelOpen(true); } : undefined} onOpenAddContactModal={() => setIsAddContactOpen(true)} /> )} {currentTab === 'email' && ( - setIsComposeEmailOpen(true)} onAddMailbox={() => { setConnectMode('email'); setIsConnectChannelOpen(true); }} /> + setIsComposeEmailOpen(true)} onAddMailbox={canConnectAccounts ? () => { setConnectMode('email'); setIsConnectChannelOpen(true); } : undefined} /> )} {currentTab === 'channels' && ( setIsCreateChannelOpen(true)} /> @@ -85,7 +105,7 @@ export function CommunicationsModule() { {currentTab === 'contacts' && ( setIsAddContactOpen(true)} /> )} - {currentTab === 'settings' && } + {currentTab === 'settings' && }
{/* Modals */} diff --git a/src/features/communications/components/EmailView.tsx b/src/features/communications/components/EmailView.tsx index b1178d2..14703c2 100644 --- a/src/features/communications/components/EmailView.tsx +++ b/src/features/communications/components/EmailView.tsx @@ -9,7 +9,7 @@ import { useToast } from '../../../shared/ui'; interface EmailViewProps { onComposeEmail: () => void; - onAddMailbox: () => void; + onAddMailbox?: () => void; } export function EmailView({ onComposeEmail, onAddMailbox }: EmailViewProps) { @@ -61,9 +61,9 @@ export function EmailView({ onComposeEmail, onAddMailbox }: EmailViewProps) { Почтовые ящики - + }
{mailboxes.map((mb) => ( diff --git a/src/features/communications/components/MessengersView.tsx b/src/features/communications/components/MessengersView.tsx index a2d7618..d1d403b 100644 --- a/src/features/communications/components/MessengersView.tsx +++ b/src/features/communications/components/MessengersView.tsx @@ -11,7 +11,7 @@ import { Avatar, Badge, Button, ConnectorPill } from '@krona/ui'; import { useToast, Drawer } from '../../../shared/ui'; interface MessengersViewProps { - onOpenConnectModal: () => void; + onOpenConnectModal?: () => void; onOpenAddContactModal: () => void; } @@ -690,7 +690,7 @@ export function MessengersView({ onOpenConnectModal, onOpenAddContactModal }: Me
- - + }
} diff --git a/src/features/communications/components/SettingsView.tsx b/src/features/communications/components/SettingsView.tsx index aa566f7..820eb6c 100644 --- a/src/features/communications/components/SettingsView.tsx +++ b/src/features/communications/components/SettingsView.tsx @@ -1,5 +1,5 @@ import { useState } from 'react'; -import { RefreshCw, Trash2, Globe } from 'lucide-react'; +import { RefreshCw, Trash2, Globe, UserCog, Bell, Volume2, PanelTop } from 'lucide-react'; import { useCommunicationsStore } from '../services/communicationsService'; import { Button, Badge } from '@krona/ui'; import { useToast } from '../../../shared/ui'; @@ -9,9 +9,15 @@ interface SettingsViewProps { onShowEmailTabChange: (enabled: boolean) => void; showChannelsTab: boolean; onShowChannelsTabChange: (enabled: boolean) => void; + orgEmailAllowed: boolean; + onOrgEmailAllowedChange: (enabled: boolean) => void; + orgChannelsAllowed: boolean; + onOrgChannelsAllowedChange: (enabled: boolean) => void; + canConnectAccounts: boolean; + onCanConnectAccountsChange: (enabled: boolean) => void; } -export function SettingsView({ showEmailTab, onShowEmailTabChange, showChannelsTab, onShowChannelsTabChange }: SettingsViewProps) { +export function SettingsView({ showEmailTab, onShowEmailTabChange, showChannelsTab, onShowChannelsTabChange, orgEmailAllowed, onOrgEmailAllowedChange, orgChannelsAllowed, onOrgChannelsAllowedChange, canConnectAccounts, onCanConnectAccountsChange }: SettingsViewProps) { const { showToast } = useToast(); const { integrations, @@ -25,6 +31,13 @@ export function SettingsView({ showEmailTab, onShowEmailTabChange, showChannelsT const [newTemplateText, setNewTemplateText] = useState(''); const [testingId, setTestingId] = useState(null); + const [settingsScope, setSettingsScope] = useState<'personal' | 'organization'>('personal'); + const [notificationsEnabled, setNotificationsEnabled] = useState(() => localStorage.getItem('krona-user-notifications') !== 'false'); + const [soundsEnabled, setSoundsEnabled] = useState(() => localStorage.getItem('krona-user-sounds') !== 'false'); + const [compactMode, setCompactMode] = useState(() => localStorage.getItem('krona-user-compact') !== 'false'); + + const switchClass = (enabled: boolean) => `relative w-12 h-7 rounded-full transition-colors shrink-0 ${enabled ? 'bg-[var(--krona-primary)]' : 'bg-[var(--krona-surface-muted)]'}`; + const switchKnobClass = (enabled: boolean) => `absolute left-1 top-1 w-5 h-5 rounded-full bg-white shadow-sm transition-transform ${enabled ? 'translate-x-5' : 'translate-x-0'}`; const handleTest = async (id: string) => { setTestingId(id); @@ -51,6 +64,12 @@ export function SettingsView({ showEmailTab, onShowEmailTabChange, showChannelsT return (
+
+ + +
+ + {settingsScope === 'personal' ? <>

Отображение разделов

Показывайте только те способы связи, которыми пользуется организация

@@ -60,8 +79,8 @@ export function SettingsView({ showEmailTab, onShowEmailTabChange, showChannelsT
Email
Почтовые ящики и переписка
-
@@ -74,14 +93,37 @@ export function SettingsView({ showEmailTab, onShowEmailTabChange, showChannelsT role="switch" aria-checked={showChannelsTab} onClick={() => onShowChannelsTabChange(!showChannelsTab)} - className={`relative w-12 h-7 rounded-full transition-colors shrink-0 ${showChannelsTab ? 'bg-[var(--krona-primary)]' : 'bg-[var(--krona-surface-muted)]'}`} + disabled={!orgChannelsAllowed} + className={`${switchClass(showChannelsTab)} disabled:opacity-40`} aria-label="Показывать раздел Каналы" > - +
+
+

Поведение и уведомления

+ {[ + { label: 'Уведомления', hint: 'Новые сообщения и упоминания', icon: Bell, value: notificationsEnabled, set: setNotificationsEnabled, key: 'krona-user-notifications' }, + { label: 'Звуки', hint: 'Звуковой сигнал новых сообщений', icon: Volume2, value: soundsEnabled, set: setSoundsEnabled, key: 'krona-user-sounds' }, + { label: 'Компактный интерфейс', hint: 'Больше диалогов и сообщений на экране', icon: PanelTop, value: compactMode, set: setCompactMode, key: 'krona-user-compact' }, + ].map((item) =>
{item.label}
{item.hint}
)} +
+ : <> +
+

Доступ организации

+

Разрешения действуют для всех пользователей организации

+
+
Разрешить Email
Пользователи смогут подключать и показывать свои ящики
+
Разрешить Каналы
Боты и публичные каналы организации
+
Пользователи подключают аккаунты
Разрешить добавление личных мессенджеров и почты
+
+
+
+

Пользователи и роли

Кто принимает сообщения и управляет подключениями

+
ВикторВладелецВсе права
Мария К.МенеджерЧаты и почта
+
{/* 1. Connected Messengers & Connectors */}
@@ -159,9 +201,7 @@ export function SettingsView({ showEmailTab, onShowEmailTabChange, showChannelsT Обеспечение бесперебойного доступа к международным API Telegram и WhatsApp

- - Туннель активен (14 ms) - +
Туннель активен (14 ms)
@@ -268,6 +308,7 @@ export function SettingsView({ showEmailTab, onShowEmailTabChange, showChannelsT
+ } ); }