diff --git a/apps/web/src/components/loop/LoopSetupCard.tsx b/apps/web/src/components/loop/LoopSetupCard.tsx index b21fbd4..8971dae 100644 --- a/apps/web/src/components/loop/LoopSetupCard.tsx +++ b/apps/web/src/components/loop/LoopSetupCard.tsx @@ -1,49 +1,176 @@ -import React, { useState } from "react"; +import React, { useEffect, useState } from "react"; import { useAppStore } from "../../store/useAppStore"; import { Card, CardContent, CardHeader, CardTitle } from "../ui/Card"; import { Input } from "../ui/Input"; import { Button } from "../ui/Button"; import { api } from "../../api/client"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { faCircleInfo, faClock, faList, faLock } from "@fortawesome/free-solid-svg-icons"; +import { faCircleInfo, faPen, faPlay, faTrash } from "@fortawesome/free-solid-svg-icons"; +import { + AlertDialog, + AlertDialogAction, + AlertDialogCancel, + AlertDialogContent, + AlertDialogDescription, + AlertDialogFooter, + AlertDialogHeader, + AlertDialogTitle, + AlertDialogTrigger, +} from "../ui/AlertDialog"; +import { useUiStore } from "../../store/useUiStore"; + +interface Profile { + id: string; + name: string; + allowIp: string; + delayMs: number; + targetLoops: number; +} export const LoopSetupCard = () => { const selectedHash = useAppStore((s) => s.selectedHash); - const jobs = useAppStore((s) => s.jobs); const loopForm = useAppStore((s) => s.loopForm); const setLoopForm = useAppStore((s) => s.setLoopForm); - const [dryRun, setDryRun] = useState(null); + const pushAlert = useUiStore((s) => s.pushAlert); - const job = jobs.find((j) => j.torrentHash === selectedHash); + const [profiles, setProfiles] = useState([]); + const [name, setName] = useState(""); + const [allowIp, setAllowIp] = useState(loopForm.allowIp || ""); + const [delayMs, setDelayMs] = useState(loopForm.delayMs ?? 3000); + const [targetLoops, setTargetLoops] = useState(loopForm.targetLoops ?? 3); + const [editingId, setEditingId] = useState(null); - const startLoop = async () => { - if (!selectedHash) { + const loadProfiles = async () => { + const response = await api.get("/api/profiles"); + setProfiles(response.data); + }; + + useEffect(() => { + loadProfiles(); + }, []); + + useEffect(() => { + setAllowIp(loopForm.allowIp || ""); + setDelayMs(loopForm.delayMs ?? 3000); + setTargetLoops(loopForm.targetLoops ?? 3); + }, [loopForm]); + + const saveProfile = async () => { + const payload = { + name: name.trim(), + allowIp: allowIp.trim(), + delayMs, + targetLoops, + }; + if (!payload.name || !payload.allowIp) { + pushAlert({ + title: "Eksik bilgi", + description: "Preset name ve Allow IP zorunlu.", + variant: "warn", + }); return; } - await api.post("/api/loop/start", { - hash: selectedHash, - allowIp: loopForm.allowIp, - targetLoops: loopForm.targetLoops, - delayMs: loopForm.delayMs, + try { + if (editingId) { + const response = await api.put(`/api/profiles/${editingId}`, payload); + setProfiles((prev) => + prev.map((profile) => (profile.id === editingId ? response.data : profile)) + ); + pushAlert({ + title: "Setup güncellendi", + description: "Kaydedilen setup güncellendi.", + variant: "success", + }); + setEditingId(null); + } else { + const response = await api.post("/api/profiles", payload); + setProfiles((prev) => [...prev, response.data]); + pushAlert({ + title: "Setup kaydedildi", + description: "Yeni setup eklendi.", + variant: "success", + }); + } + setLoopForm({ + allowIp: payload.allowIp, + delayMs: payload.delayMs, + targetLoops: payload.targetLoops, + }); + setName(""); + } catch (error) { + pushAlert({ + title: "Kaydedilemedi", + description: "Lütfen bilgileri kontrol edip tekrar deneyin.", + variant: "error", + }); + } + }; + + const startEdit = (profile: Profile) => { + setEditingId(profile.id); + setName(profile.name); + setAllowIp(profile.allowIp); + setDelayMs(profile.delayMs); + setTargetLoops(profile.targetLoops); + setLoopForm({ + allowIp: profile.allowIp, + delayMs: profile.delayMs, + targetLoops: profile.targetLoops, }); }; - const stopLoop = async () => { + const applyProfile = async (profile: Profile) => { if (!selectedHash) { + pushAlert({ + title: "Torrent seçilmedi", + description: "Önce bir torrent seçin.", + variant: "warn", + }); return; } - await api.post("/api/loop/stop-by-hash", { hash: selectedHash }); + try { + await api.post("/api/loop/start", { + hash: selectedHash, + allowIp: profile.allowIp, + targetLoops: profile.targetLoops, + delayMs: profile.delayMs, + }); + setLoopForm({ + allowIp: profile.allowIp, + delayMs: profile.delayMs, + targetLoops: profile.targetLoops, + }); + pushAlert({ + title: "Loop başlatıldı", + description: "Seçilen setup ile loop başlatıldı.", + variant: "success", + }); + } catch (error: any) { + const apiError = error?.response?.data?.error; + pushAlert({ + title: "Loop başlatılamadı", + description: apiError || "Sunucu loglarını kontrol edin.", + variant: "error", + }); + } }; - const runDry = async () => { - if (!selectedHash) { - return; + const removeProfile = async (profileId: string) => { + try { + await api.delete(`/api/profiles/${profileId}`); + setProfiles((prev) => prev.filter((profile) => profile.id !== profileId)); + pushAlert({ + title: "Setup silindi", + description: "Setup listeden kaldırıldı.", + variant: "success", + }); + } catch (error) { + pushAlert({ + title: "Silme başarısız", + description: "Setup silinemedi.", + variant: "error", + }); } - const response = await api.post("/api/loop/dry-run", { - hash: selectedHash, - allowIp: loopForm.allowIp || "127.0.0.1", - }); - setDryRun(JSON.stringify(response.data, null, 2)); }; return ( @@ -56,54 +183,108 @@ export const LoopSetupCard = () => {
-
-
+
-
- { - setLoopForm({ - allowIp: profile.allowIp, - delayMs: profile.delayMs, - targetLoops: profile.targetLoops, - }); - }} - /> -
);