diff --git a/src/routes/backoffice/timesheets/+page.svelte b/src/routes/backoffice/timesheets/+page.svelte index e42c866..b2bd37f 100644 --- a/src/routes/backoffice/timesheets/+page.svelte +++ b/src/routes/backoffice/timesheets/+page.svelte @@ -88,6 +88,8 @@ ]; let currentUserId: string | null = null; + let currentVillaFilter: string | null = null; + let currentSearchTerm: string | null = null; onMount(async () => { const { @@ -153,7 +155,7 @@ } async function fetchTimeSheets( - filter: string | null = null, + villaNameFilter: string | null = null, searchTerm: string | null = null, sortColumn: string | null = "created_at", sortOrder: "asc" | "desc" = "desc", @@ -165,9 +167,17 @@ .select("*", { count: "exact" }) .order(sortColumn || "created_at", { ascending: sortOrder === "asc", - }); - if (filter) { - query = query.eq("category_of_work", filter); + }); + if (villaNameFilter) { + const { data: villaMatch } = await supabase + .from("vb_villas") + .select("id") + .eq("villa_name", villaNameFilter); + + const matchedId = villaMatch?.[0]?.id; + if (matchedId) { + query = query.eq("villa_id", matchedId); + } } if (searchTerm) { query = query.ilike("work_description", `%${searchTerm}%`); @@ -184,7 +194,6 @@ return; } - // Ambil semua villa_id unik dari issues const villaIds = [ ...new Set(timesheet.map((i: Timesheets) => i.villa_id)), ]; @@ -211,7 +220,8 @@ const { data: staffData, error: staffError } = await supabase .from("vb_employee") .select("id, employee_name") - .eq("employee_status", "Active"); + .eq("employee_status", "Active") + .order("employee_name", { ascending: true }); if (staffError) { console.error("Error fetching staff:", staffError); } else if (staffData) { @@ -221,39 +231,38 @@ })); } - // Gabungkan data villa ke dalam setiap issue - allRows = timesheet.map((issue: Timesheets) => { - const villa = villas.find((v) => v.id === issue.villa_id); + allRows = timesheet.map((tsdata: Timesheets) => { + const villa = villas.find((v) => v.id === tsdata.villa_id); // Map entered_by to staff_id - const staff = reportedBy.find((s) => s.value === issue.entered_by); - const approver = approvers?.find((u) => u.id === issue.approved_by); + const staff = reportedBy.find((s) => s.value === tsdata.entered_by); + const approver = approvers?.find((u) => u.id === tsdata.approved_by); return { - id: issue.id, - name: issue.work_description, // Map work_description to name + id: tsdata.id, + name: tsdata.work_description, // Map work_description to name staff_id: staff?.label, // Map entered_by to staff_id - date_in: new Date(issue.datetime_in), - date_out: new Date(issue.datetime_out), - type_of_work: issue.type_of_work, - category_of_work: issue.category_of_work, + date_in: new Date(tsdata.datetime_in), + date_out: new Date(tsdata.datetime_out), + type_of_work: tsdata.type_of_work, + category_of_work: tsdata.category_of_work, villa_name: villa ? villa.villa_name : "Unknown Villa", approval: - issue.approval == null + tsdata.approval == null ? "PENDING" - : issue.approval + : tsdata.approval ? "APPROVED" : "REJECTED", // or map as needed total_hours_work: Math.abs( - new Date(issue.datetime_out).getTime() - - new Date(issue.datetime_in).getTime(), + new Date(tsdata.datetime_out).getTime() - + new Date(tsdata.datetime_in).getTime(), ) / (1000 * 60 * 60), // Convert milliseconds to hours approved_by: approver?.full_name ?? "Not Approved", - approved_date: issue.approved_date, - remarks: issue.remarks, - created_at: issue.created_at - ? new Date(issue.created_at) + approved_date: tsdata.approved_date, + remarks: tsdata.remarks, + created_at: tsdata.created_at + ? new Date(tsdata.created_at) : undefined, } as TimesheetDisplay; }); @@ -282,7 +291,8 @@ const { data: empData, error: empErr } = await supabase .from("vb_employee") .select("id, employee_name") - .eq("employee_status", "Active"); + .eq("employee_status", "Active") + .order("employee_name", { ascending: true }); if (!empErr && empData) { employees = empData.map((e) => ({ @@ -297,7 +307,8 @@ const { data: villaData, error: villaErr } = await supabase .from("vb_villas") .select("id, villa_name") - .eq("villa_status", "Active"); + .eq("villa_status", "Active") + .order("villa_name", { ascending: true }); if (!villaErr && villaData) { villas = villaData; @@ -318,31 +329,31 @@ let showModal = false; let isEditing = false; let currentEditingId: string | null = null; - let newIssue: Record = {}; + let newTsdata: Record = {}; const excludedKeys = ["id"]; const formColumns = columns.filter( (col) => !excludedKeys.includes(col.key), ); - function openModal(issue?: Record) { - if (issue) { + function openModal(tsdata?: Record) { + if (tsdata) { // Edit mode isEditing = true; - currentEditingId = issue.id; + currentEditingId = tsdata.id; form = { entered_by: - employees.find((e) => e.name === issue.staff_id)?.id || "", - work_description: issue.name, - type_of_work: issue.type_of_work, - category_of_work: issue.category_of_work, + employees.find((e) => e.name === tsdata.staff_id)?.id || "", + work_description: tsdata.name, + type_of_work: tsdata.type_of_work, + category_of_work: tsdata.category_of_work, villa_id: - villas.find((v) => v.villa_name === issue.villa_name)?.id || + villas.find((v) => v.villa_name === tsdata.villa_name)?.id || "", - datetime_in: issue.date_in?.toISOString().slice(0, 16), - datetime_out: issue.date_out?.toISOString().slice(0, 16), + datetime_in: tsdata.date_in?.toISOString().slice(0, 16), + datetime_out: tsdata.date_out?.toISOString().slice(0, 16), total_work_hour: 0, - remarks: issue.remarks, + remarks: tsdata.remarks, approval: null, // leave null or bring in if editing allowed }; calculateTotalHours(); @@ -397,72 +408,14 @@ approval: null, // Default null }; - async function saveIssue(event: Event) { - event.preventDefault(); - - const formData = new FormData(event.target as HTMLFormElement); - - // Validate form data - if (!validateForm(formData)) { - console.error("Form validation failed"); - return; - } - - if (isEditing && currentEditingId) { - const { error } = await supabase - .from("vb_issues") - .update(newIssue) - .eq("id", currentEditingId); - - if (error) { - alert("Error updating issue: " + error.message); - console.error("Error updating issue:", error); - return; - } - } else { - const TimesheetsInsert: TimesheetsInsert = { - entered_by: formData.get("entered_by") as string, - work_description: formData.get("work_description") as string, - type_of_work: formData.get("type_of_work") as - | "Running" - | "Periodic" - | "Irregular", - category_of_work: formData.get("category_of_work") as - | "Cleaning" - | "Gardening/Pool" - | "Maintenance" - | "Supervision" - | "Guest Service" - | "Administration" - | "Non Billable", - villa_id: formData.get("villa_id") as string, - datetime_in: formData.get("date_in") as string, - datetime_out: formData.get("date_out") as string, - total_work_hour: newIssue.total_work_hour ?? 0, - remarks: formData.get("remarks") as string, - approval: null, - }; - - const { error } = await supabase - .from("vb_timesheet") - .insert([TimesheetsInsert]); - if (error) { - console.error("Error adding issue:", error); - return; - } - } - await fetchTimeSheets(); - showModal = false; - } - async function deleteTimesheet(id: string) { - if (confirm("Are you sure you want to delete this issue?")) { + if (confirm("Are you sure you want to delete this Timesheet?")) { const { error } = await supabase .from("vb_timesheet") .delete() .eq("id", id); if (error) { - console.error("Error deleting issue:", error); + console.error("Error deleting Timesheet:", error); return; } await fetchTimeSheets(); @@ -493,10 +446,6 @@ return Object.keys(errors).length === 0; } - function errorClass(field: string): string { - return $formErrors[field] ? "border-red-500" : "border"; - } - async function updateApprovalStatus( id: string, status: string, @@ -592,30 +541,42 @@
{ - const searchTerm = ( - e.target as HTMLInputElement - ).value.toLowerCase(); - fetchTimeSheets(null, searchTerm, "created_at", "desc"); + currentSearchTerm = (e.target as HTMLInputElement).value.toLowerCase(); + fetchTimeSheets(currentVillaFilter, currentSearchTerm); }} />