diff --git a/app/[lang]/dashboard/settings/page.tsx b/app/[lang]/dashboard/settings/page.tsx new file mode 100644 index 0000000..8775203 --- /dev/null +++ b/app/[lang]/dashboard/settings/page.tsx @@ -0,0 +1,163 @@ +"use client"; + +import { useState, useEffect } from "react"; +import { useDictionary } from "@/components/DictionaryContext"; +import { useSession } from "next-auth/react"; + +export default function SettingsPage() { + const { data: session } = useSession(); + const [profile, setProfile] = useState(null); + const [waStatus, setWaStatus] = useState(null); + const [loading, setLoading] = useState(true); + const [saving, setSaving] = useState(false); + const dict = useDictionary(); + + useEffect(() => { + fetchProfile(); + fetchWaStatus(); + + // Check WA status every 5 seconds if not connected + const interval = setInterval(() => { + fetchWaStatus(); + }, 5000); + + return () => clearInterval(interval); + }, []); + + const fetchProfile = async () => { + const res = await fetch("/api/users/profile"); + const data = await res.json(); + setProfile(data); + setLoading(false); + }; + + const fetchWaStatus = async () => { + try { + const res = await fetch("/api/whatsapp/status"); + const data = await res.json(); + setWaStatus(data); + } catch (e) { + console.error(e); + } + }; + + const handleSave = async (e: React.FormEvent) => { + e.preventDefault(); + setSaving(true); + try { + await fetch("/api/users/profile", { + method: "PATCH", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify(profile) + }); + alert("Ayarlar kaydedildi!"); + } catch (e) { + console.error(e); + } finally { + setSaving(false); + } + }; + + if (loading) return
; + + return ( + <> +
+
+

Bildirim Ayarları

+

Telegram ve WhatsApp bildirimlerinizi buradan yönetin.

+
+
+ +
+
+
+

+ Telegram Bildirimleri +

+
+ setProfile({...profile, telegramEnabled: e.target.checked})} + /> + +
+
+ + setProfile({...profile, telegramId: e.target.value})} + placeholder="Örn: 5009005027" + /> +

+ Botu başlatın ve ID'nizi buraya yazın. +

+
+
+ +
+

+ WhatsApp Bildirimleri +

+
+ setProfile({...profile, whatsappEnabled: e.target.checked})} + /> + +
+ +
+
+ + setProfile({...profile, whatsappNumber: e.target.value})} + placeholder="90554XXXXXXX" + /> +
+ +
+ + {waStatus?.status === 'connected' ? ( +
+
+ Bağlı +
+ ) : ( +
+
+
+ Bağlı Değil +
+ {waStatus?.qr && ( +
+ QR Code +

WhatsApp'tan okutun

+
+ )} +
+ )} +
+
+
+ +
+ +
+ +
+ + ); +} + +function TelegramIcon() { return ; } +function WhatsAppIcon() { return ; } diff --git a/app/api/users/profile/route.ts b/app/api/users/profile/route.ts new file mode 100644 index 0000000..091b976 --- /dev/null +++ b/app/api/users/profile/route.ts @@ -0,0 +1,38 @@ +import { NextResponse } from "next/server"; +import { auth } from "@/auth"; +import { prisma } from "@/lib/prisma"; + +export async function GET() { + const session = await auth(); + if (!session) return NextResponse.json({ error: "Unauthorized" }, { status: 401 }); + + const user = await prisma.user.findUnique({ + where: { id: session.user.id } + }); + + return NextResponse.json(user); +} + +export async function PATCH(req: Request) { + const session = await auth(); + if (!session) return NextResponse.json({ error: "Unauthorized" }, { status: 401 }); + + try { + const body = await req.json(); + const { telegramId, telegramEnabled, whatsappNumber, whatsappEnabled } = body; + + const user = await prisma.user.update({ + where: { id: session.user.id }, + data: { + telegramId, + telegramEnabled, + whatsappNumber, + whatsappEnabled + } + }); + + return NextResponse.json(user); + } catch (error: any) { + return NextResponse.json({ error: error.message }, { status: 500 }); + } +} diff --git a/app/api/webhooks/mail-signal/route.ts b/app/api/webhooks/mail-signal/route.ts index 8254995..93e8e97 100644 --- a/app/api/webhooks/mail-signal/route.ts +++ b/app/api/webhooks/mail-signal/route.ts @@ -67,20 +67,27 @@ export async function POST(request: Request) { }; // 3. Bildirim Gönder (Telegram) - const notificationResult = await sendTelegramNotification( - mapping.userId, - to, - mailData.from, - mailData.subject, - "" // Analiz bilgisini kaldırdık - ); + let tgStatus = 'SKIPPED'; + if (mapping.user.telegramEnabled && mapping.user.telegramId) { + const tgResult = await sendTelegramNotification( + mapping.userId, + to, + mailData.from, + mailData.subject, + "" + ); + tgStatus = tgResult.status; + } // 4. Bildirim Gönder (WhatsApp) - // Şu an için varsayılan numaraya gönderiyoruz, ilerde User modeline alan eklenebilir. - const waNumber = process.env.DEFAULT_WHATSAPP_NUMBER || '905543765103'; - const waMessage = `📩 *Yeni E-posta*\n\n*Gönderen:* ${mailData.from}\n*Konu:* ${mailData.subject}\n*Alıcı:* ${to}\n\n_AyrisMail Central_`; - - await sendWA(waNumber, waMessage); + let waStatus = 'SKIPPED'; + if (mapping.user.whatsappEnabled && (mapping.user.whatsappNumber || process.env.DEFAULT_WHATSAPP_NUMBER)) { + const waNumber = mapping.user.whatsappNumber || process.env.DEFAULT_WHATSAPP_NUMBER; + const waMessage = `📩 *Yeni E-posta*\n\n*Gönderen:* ${mailData.from}\n*Konu:* ${mailData.subject}\n*Alıcı:* ${to}\n\n_AyrisMail Central_`; + + const waResult = await sendWA(waNumber, waMessage, mapping.userId); + waStatus = waResult.success ? 'SENT' : 'FAILED'; + } // 5. Bildirim Logu await prisma.notificationLog.create({ @@ -88,9 +95,9 @@ export async function POST(request: Request) { mailbox: to, sender: mailData.from, subject: mailData.subject, - status: notificationResult.status, + status: tgStatus === 'SENT' || waStatus === 'SENT' ? 'SENT' : 'FAILED', userId: mapping.userId, - error: notificationResult.error + error: tgStatus === 'FAILED' ? 'TG Failed' : (waStatus === 'FAILED' ? 'WA Failed' : null) } }); diff --git a/app/api/whatsapp/status/route.ts b/app/api/whatsapp/status/route.ts new file mode 100644 index 0000000..25beea6 --- /dev/null +++ b/app/api/whatsapp/status/route.ts @@ -0,0 +1,19 @@ +import { NextResponse } from "next/server"; +import { auth } from "@/auth"; + +export async function GET() { + const session = await auth(); + if (!session) return NextResponse.json({ error: "Unauthorized" }, { status: 401 }); + + const userId = session.user.id; + const workerUrl = process.env.WHATSAPP_WORKER_URL; + const secret = process.env.WHATSAPP_SECRET; + + try { + const res = await fetch(`${workerUrl}/status?userId=${userId}&secret=${secret}`); + const data = await res.json(); + return NextResponse.json(data); + } catch (error: any) { + return NextResponse.json({ status: 'error', error: error.message }); + } +} diff --git a/components/Sidebar.tsx b/components/Sidebar.tsx index e875d6f..8c7ece3 100644 --- a/components/Sidebar.tsx +++ b/components/Sidebar.tsx @@ -18,6 +18,7 @@ export default function Sidebar({ dict, lang }: { dict: any; lang: string }) { items: [ { href: `/${lang}/dashboard`, label: dict.dashboard?.title || "Dashboard", icon: HomeIcon, roles: ["SUPER_ADMIN", "DOMAIN_ADMIN"] }, { href: `/${lang}/dashboard/mail`, label: dict.sidebar?.mailClient || "Mail Client", icon: InboxIcon, roles: ["SUPER_ADMIN", "DOMAIN_ADMIN"] }, + { href: `/${lang}/dashboard/settings`, label: "Ayarlar", icon: SettingsIcon, roles: ["SUPER_ADMIN", "DOMAIN_ADMIN"] }, ], }, { @@ -176,3 +177,12 @@ function ListIcon() { ); } + +function SettingsIcon() { + return ( + + + + + ); +} diff --git a/prisma/schema.prisma b/prisma/schema.prisma index d090f50..fea82b8 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -18,6 +18,9 @@ model User { role String @default("DOMAIN_ADMIN") // SUPER_ADMIN or DOMAIN_ADMIN domains String[] @default([]) // ["*"] or list of domains telegramId String? + telegramEnabled Boolean @default(true) + whatsappNumber String? + whatsappEnabled Boolean @default(false) mailboxMappings MailboxMapping[] notificationConfigs NotificationConfig[] notificationLogs NotificationLog[]