diff --git a/.phase20-state.json b/.phase20-state.json index 78b52bc..f2f5c46 100644 --- a/.phase20-state.json +++ b/.phase20-state.json @@ -1,8 +1,9 @@ { "completed_features": [], - "current_feature": "recurring-time-entries", + "current_feature": "slack-integration-stub", "started_at": "2026-05-23T07:57:43.412201", "attempted_features": [ - "time-budget-per-project" + "time-budget-per-project", + "recurring-time-entries" ] } \ No newline at end of file diff --git a/GENERATION_LOG.md b/GENERATION_LOG.md index 615bfd9..490441b 100644 --- a/GENERATION_LOG.md +++ b/GENERATION_LOG.md @@ -2405,3 +2405,20 @@ src/index.ts(27,25): error TS2769: No overload matches this call. Overload 2 of 3, '(plugin: FastifyPluginAsync<{ limits: { fileSize: number; }; }, RawServerDefault, FastifyTypeProvider, FastifyBaseLogger>, opts?: FastifyRegisterOptions<...> | undefined): FastifyInstance<...> & PromiseLike<...>', gave the following error. Argument of type 'Promise' is not assignable to parameter of type 'FastifyPluginAsync<{ limits: { fileSize: number; }; }, RawServerDefault, FastifyTypeProvider, FastifyBaseLogger>'. Type 'Promise' provides no match for the signature '(instance: FastifyInstance, FastifyBaseLogger, FastifyTy +- `08:02:18` **INFO** Committed feature recurring-time-entries +- `08:02:18` **INFO** Pushed: rc=0 + +## Phase-3 Feature: slack-integration-stub (2026-05-23 08:02:18) + +- `08:02:18` **INFO** Description: Slack-Integration-Stub Card auf Integrations-Page +- `08:02:18` **INFO** Generating apps/web/src/pages/Integrations.tsx (ERWEITERT — die bestehende Slack-Karte bekommt jetzt 'Configure'-Butto…) +- `08:03:38` **INFO** wrote 9473 chars in 80.3s (attempt 1) +- `08:03:38` **INFO** Running tsc --noEmit on api… +- `08:03:40` **WARN** tsc errors: +src/index.ts(27,25): error TS2769: No overload matches this call. + Overload 1 of 3, '(plugin: FastifyPluginCallback<{ limits: { fileSize: number; }; }, RawServerDefault, FastifyTypeProvider, FastifyBaseLogger>, opts?: FastifyRegisterOptions<...> | undefined): FastifyInstance<...> & PromiseLike<...>', gave the following error. + Argument of type 'Promise' is not assignable to parameter of type 'FastifyPluginCallback<{ limits: { fileSize: number; }; }, RawServerDefault, FastifyTypeProvider, FastifyBaseLogger>'. + Type 'Promise' provides no match for the signature '(instance: FastifyInstance, FastifyBaseLogger, FastifyTypeProvider>, opts: { ...; }, done: (err?: Error | undefined) => void): void'. + Overload 2 of 3, '(plugin: FastifyPluginAsync<{ limits: { fileSize: number; }; }, RawServerDefault, FastifyTypeProvider, FastifyBaseLogger>, opts?: FastifyRegisterOptions<...> | undefined): FastifyInstance<...> & PromiseLike<...>', gave the following error. + Argument of type 'Promise' is not assignable to parameter of type 'FastifyPluginAsync<{ limits: { fileSize: number; }; }, RawServerDefault, FastifyTypeProvider, FastifyBaseLogger>'. + Type 'Promise' provides no match for the signature '(instance: FastifyInstance, FastifyBaseLogger, FastifyTy diff --git a/apps/web/src/pages/Integrations.tsx b/apps/web/src/pages/Integrations.tsx index ed6a314..3eb1351 100644 --- a/apps/web/src/pages/Integrations.tsx +++ b/apps/web/src/pages/Integrations.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { useState } from 'react'; import { Link } from '@tanstack/react-router'; import { Slack, @@ -7,7 +7,11 @@ import { Calendar, Mail, ArrowRight, - Lock + Lock, + X, + Send, + Loader2, + CheckCircle2 } from 'lucide-react'; interface Integration { @@ -25,7 +29,7 @@ const INTEGRATIONS: Integration[] = [ name: 'Slack', description: 'Get notifications and updates directly in your Slack channels.', icon: Slack, - status: 'coming-soon', + status: 'available', }, { id: 'discord', @@ -60,6 +64,40 @@ const INTEGRATIONS: Integration[] = [ ]; export default function IntegrationsPage() { + const [isSlackModalOpen, setIsSlackModalOpen] = useState(false); + const [webhookUrl, setWebhookUrl] = useState(''); + const [status, setStatus] = useState<'idle' | 'loading' | 'success' | 'error'>('idle'); + + const handleSaveSlack = async (e: React.FormEvent) => { + e.preventDefault(); + setStatus('loading'); + // Simulate API call to save settings + await new Promise(resolve => setTimeout(resolve, 800)); + setStatus('success'); + setTimeout(() => setStatus('idle'), 2000); + }; + + const handleTestSlack = async () => { + if (!webhookUrl) return; + setStatus('loading'); + try { + const response = await fetch(webhookUrl, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ text: 'Hello from EmberClone! 🚀' }), + }); + if (response.ok) { + setStatus('success'); + } else { + setStatus('error'); + } + } catch (err) { + setStatus('error'); + } finally { + setTimeout(() => setStatus('idle'), 2000); + } + }; + return (
@@ -105,6 +143,14 @@ export default function IntegrationsPage() { > Configure + ) : integration.id === 'slack' ? ( + ) : ( + + {isSlackModalOpen && ( +
+
+
+
+
+ +
+

Slack Integration

+
+ +
+ +
+
+ + setWebhookUrl(e.target.value)} + /> +

+ Create an Incoming Webhook in your Slack App settings to get this URL. +

+
+ +
+ + +
+ + {status === 'success' && ( +
+ + Successfully updated and tested! +
+ )} + {status === 'error' && ( +
+ + Failed to connect. Please check your URL. +
+ )} +
+
+
+ )}
); } \ No newline at end of file