Files
neta/app/(dashboard)/tasks/actions.ts
T
Poyraz Avsever f41815329f feat(tasks): implement task management actions and UI components
- Added actions for creating, updating, completing, and deleting tasks in `actions.ts`.
- Refactored `TasksPage` to fetch tasks from Supabase and display them using the new `TasksClient` component.
- Created `tasks-client.tsx` to handle task listing and Kanban view with filtering capabilities.
- Introduced a dialog for task creation and editing with form validation.
- Enhanced task display with status and priority badges, and added overdue checks.
2026-06-04 15:51:13 +03:00

145 lines
3.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"use server";
import { createClient } from "@/lib/supabase/server";
import { revalidatePath } from "next/cache";
const TASK_STATUSES = ["todo", "in_progress", "done"] as const;
const TASK_PRIORITIES = ["low", "medium", "high", "urgent"] as const;
function cleanText(value: FormDataEntryValue | null) {
const text = typeof value === "string" ? value.trim() : "";
return text.length > 0 ? text : null;
}
function readStatus(value: FormDataEntryValue | null) {
const status = typeof value === "string" ? value : "todo";
return TASK_STATUSES.includes(status as (typeof TASK_STATUSES)[number])
? status
: "todo";
}
function readPriority(value: FormDataEntryValue | null) {
const priority = typeof value === "string" ? value : "medium";
return TASK_PRIORITIES.includes(priority as (typeof TASK_PRIORITIES)[number])
? priority
: "medium";
}
function readMinutes(value: FormDataEntryValue | null) {
const number = Number(value);
return Number.isFinite(number) && number >= 0 ? Math.round(number) : null;
}
async function getCurrentUserId() {
const supabase = await createClient();
const {
data: { user },
error,
} = await supabase.auth.getUser();
if (error || !user) {
throw new Error("Görev işlemi için giriş yapmış kullanıcı bulunamadı.");
}
return { supabase, userId: user.id };
}
function readPayload(formData: FormData) {
return {
title: cleanText(formData.get("title")),
description: cleanText(formData.get("description")),
status: readStatus(formData.get("status")),
priority: readPriority(formData.get("priority")),
client_id: cleanText(formData.get("client_id")),
project_id: cleanText(formData.get("project_id")),
due_at: cleanText(formData.get("due_at")),
estimated_minutes: readMinutes(formData.get("estimated_minutes")),
actual_minutes: readMinutes(formData.get("actual_minutes")),
};
}
export async function createTaskRecord(formData: FormData) {
const { supabase, userId } = await getCurrentUserId();
const payload = readPayload(formData);
if (!payload.title) {
throw new Error("Görev başlığı zorunludur.");
}
const { error } = await supabase.from("tasks").insert({
user_id: userId,
date: payload.due_at || new Date().toISOString(),
...payload,
});
if (error) {
throw new Error(`Görev eklenemedi: ${error.message}`);
}
revalidatePath("/tasks");
}
export async function updateTaskRecord(formData: FormData) {
const { supabase, userId } = await getCurrentUserId();
const id = cleanText(formData.get("id"));
const payload = readPayload(formData);
if (!id || !payload.title) {
throw new Error("Görev güncellemek için başlık ve kayıt kimliği zorunludur.");
}
const { error } = await supabase
.from("tasks")
.update(payload)
.eq("id", id)
.eq("user_id", userId);
if (error) {
throw new Error(`Görev güncellenemedi: ${error.message}`);
}
revalidatePath("/tasks");
}
export async function completeTaskRecord(formData: FormData) {
const { supabase, userId } = await getCurrentUserId();
const id = cleanText(formData.get("id"));
if (!id) {
throw new Error("Tamamlanacak görev bulunamadı.");
}
const { error } = await supabase
.from("tasks")
.update({ status: "done" })
.eq("id", id)
.eq("user_id", userId);
if (error) {
throw new Error(`Görev tamamlanamadı: ${error.message}`);
}
revalidatePath("/tasks");
}
export async function deleteTaskRecord(formData: FormData) {
const { supabase, userId } = await getCurrentUserId();
const id = cleanText(formData.get("id"));
if (!id) {
throw new Error("Silinecek görev bulunamadı.");
}
const { error } = await supabase
.from("tasks")
.delete()
.eq("id", id)
.eq("user_id", userId);
if (error) {
throw new Error(`Görev silinemedi: ${error.message}`);
}
revalidatePath("/tasks");
}