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

- 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:
poignatov
2025-12-31 19:11:28 +03:00
parent 63af6bf4ed
commit 7398918bc0
20 changed files with 721 additions and 100 deletions

View File

@@ -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>
)}