Release v1.1.0: Add Telegram and Todoist integrations UI
All checks were successful
Build and Push Docker Image / build-and-push (push) Successful in 57s
All checks were successful
Build and Push Docker Image / build-and-push (push) Successful in 57s
- Add telegram_integrations table to store bot token and chat_id - Add Integrations tab with Todoist and Telegram integration screens - Remove TELEGRAM_BOT_TOKEN and TELEGRAM_CHAT_ID from env variables - All Telegram configuration now done through UI - Telegram webhook registration happens when user saves bot token - Rename TELEGRAM_WEBHOOK_BASE_URL to WEBHOOK_BASE_URL
This commit is contained in:
@@ -7,6 +7,7 @@ import AddWords from './components/AddWords'
|
||||
import TestConfigSelection from './components/TestConfigSelection'
|
||||
import AddConfig from './components/AddConfig'
|
||||
import TestWords from './components/TestWords'
|
||||
import Integrations from './components/Integrations'
|
||||
|
||||
// API endpoints (используем относительные пути, проксирование настроено в nginx/vite)
|
||||
const CURRENT_WEEK_API_URL = '/playlife-feed'
|
||||
@@ -24,6 +25,7 @@ function App() {
|
||||
'test-config': false,
|
||||
'add-config': false,
|
||||
test: false,
|
||||
integrations: false,
|
||||
})
|
||||
|
||||
// Отслеживаем, какие табы уже были загружены (для предотвращения повторных загрузок)
|
||||
@@ -36,6 +38,7 @@ function App() {
|
||||
'test-config': false,
|
||||
'add-config': false,
|
||||
test: false,
|
||||
integrations: false,
|
||||
})
|
||||
|
||||
// Параметры для навигации между вкладками
|
||||
@@ -74,7 +77,7 @@ function App() {
|
||||
|
||||
try {
|
||||
const savedTab = window.localStorage?.getItem('activeTab')
|
||||
const validTabs = ['current', 'priorities', 'full', 'words', 'add-words', 'test-config', 'add-config', 'test']
|
||||
const validTabs = ['current', 'priorities', 'full', 'words', 'add-words', 'test-config', 'add-config', 'test', 'integrations']
|
||||
if (savedTab && validTabs.includes(savedTab)) {
|
||||
setActiveTab(savedTab)
|
||||
setLoadedTabs(prev => ({ ...prev, [savedTab]: true }))
|
||||
@@ -184,6 +187,7 @@ function App() {
|
||||
'test-config': false,
|
||||
'add-config': false,
|
||||
test: false,
|
||||
integrations: false,
|
||||
})
|
||||
|
||||
// Используем ref для отслеживания кеша (чтобы не зависеть от состояния в useCallback)
|
||||
@@ -471,6 +475,12 @@ function App() {
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{loadedTabs.integrations && (
|
||||
<div className={activeTab === 'integrations' ? 'block' : 'hidden'}>
|
||||
<Integrations onNavigate={handleNavigate} />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -519,6 +529,26 @@ function App() {
|
||||
<div className="absolute top-0 left-0 right-0 h-1 bg-gradient-to-r from-indigo-500 to-purple-500"></div>
|
||||
)}
|
||||
</button>
|
||||
<button
|
||||
onClick={() => handleTabChange('integrations')}
|
||||
className={`min-w-max whitespace-nowrap px-4 py-4 transition-all duration-300 relative ${
|
||||
activeTab === 'integrations'
|
||||
? 'text-indigo-700 bg-white/50'
|
||||
: 'text-gray-600 hover:text-indigo-600 hover:bg-white/30'
|
||||
}`}
|
||||
title="Интеграции"
|
||||
>
|
||||
<span className="relative z-10 flex items-center justify-center">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
||||
<path d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z"></path>
|
||||
<polyline points="3.27 6.96 12 12.01 20.73 6.96"></polyline>
|
||||
<line x1="12" y1="22.08" x2="12" y2="12"></line>
|
||||
</svg>
|
||||
</span>
|
||||
{activeTab === 'integrations' && (
|
||||
<div className="absolute top-0 left-0 right-0 h-1 bg-gradient-to-r from-indigo-500 to-purple-500"></div>
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user