From 5845704f1f0394195c31d48e45c3dc134525fb6f Mon Sep 17 00:00:00 2001 From: Aji Setiaji Date: Thu, 29 May 2025 16:17:21 +0700 Subject: [PATCH] penambahan fitur upload --- src/components/Sidebar.svelte | 10 +- src/routes/backoffice/issue/+page.svelte | 188 ++++- .../{issuemember => issue/view}/+page.svelte | 14 + src/routes/backoffice/project/+page.svelte | 52 +- src/routes/backoffice/timesheets/+page.svelte | 763 ++++++++++++++++++ .../backoffice/timesheets/view/+page.svelte | 364 +++++++++ src/routes/backoffice/vendor/+page.svelte | 132 ++- src/routes/backoffice/villa/+page.svelte | 575 +++++++++++-- 8 files changed, 1979 insertions(+), 119 deletions(-) rename src/routes/backoffice/{issuemember => issue/view}/+page.svelte (98%) create mode 100644 src/routes/backoffice/timesheets/+page.svelte create mode 100644 src/routes/backoffice/timesheets/view/+page.svelte diff --git a/src/components/Sidebar.svelte b/src/components/Sidebar.svelte index 1f3167f..c7e01f3 100644 --- a/src/components/Sidebar.svelte +++ b/src/components/Sidebar.svelte @@ -1,8 +1,9 @@
-
+
-

Issue List

-

+

📝 Issue List

+

Manage and view all issues reported in the system.

- + +
+ { + const searchTerm = ( + e.target as HTMLInputElement + ).value.toLowerCase(); + fetchIssues(null, searchTerm, "created_at", "desc"); + }} + /> + + + +
@@ -494,7 +576,7 @@ - {#each paginatedRows as row} + {#each allRows as row} {#each columns as col} {#if col.key === "name"} @@ -566,6 +648,38 @@ ❌ {/if} + {:else if col.key === "issue_related_image"} + + {:else if col.key === "reported_date"} + {:else if col.key === "need_approval"} - {:else if col.key === "project_picture_link"} + {:else if col.key === "picture_link"} - {#each paginatedRows as vendor} + {#each allRowsVendor as vendor} handleVendorClick(vendor.id)} diff --git a/src/routes/backoffice/villa/+page.svelte b/src/routes/backoffice/villa/+page.svelte index 837ce0c..cd1c5b5 100644 --- a/src/routes/backoffice/villa/+page.svelte +++ b/src/routes/backoffice/villa/+page.svelte @@ -1,6 +1,7 @@
-
+
-

Villa List

-

+

🏡 Villa List

+

Manage and track villas efficiently

- +
+ { + const searchTerm = ( + e.target as HTMLInputElement + ).value.toLowerCase(); + fetchVillas(searchTerm, "created_at", "desc", limit, 0); + }} + /> + + + + +
+
+ {#if typeof row[col.key as keyof Issue] === "string" && row[col.key as keyof Issue]} + {#await getPublicUrl(row[col.key as keyof Issue] as string) then publicUrl} + View Picture + {:catch} + Error loading image + {/await} + {:else} + No Picture + {/if} + + {typeof row[col.key as keyof Issue] === + "string" || + typeof row[col.key as keyof Issue] === + "number" + ? new Date( + row[col.key as keyof Issue] as + | string + | number, + ).toLocaleDateString("en-US") + : ""} + {#if row[col.key as keyof Issue]} @@ -716,6 +830,14 @@ alt="Preview" class="mt-2 max-h-48 rounded border" /> + {:else if newIssue.issue_related_image} + {#await getPublicUrl(newIssue.issue_related_image) then url} + Preview + {/await} {/if} {:else if col.key === "reported_date"} diff --git a/src/routes/backoffice/issuemember/+page.svelte b/src/routes/backoffice/issue/view/+page.svelte similarity index 98% rename from src/routes/backoffice/issuemember/+page.svelte rename to src/routes/backoffice/issue/view/+page.svelte index 9a04eec..413a1b4 100644 --- a/src/routes/backoffice/issuemember/+page.svelte +++ b/src/routes/backoffice/issue/view/+page.svelte @@ -179,6 +179,20 @@ return; } + // Upload issue image if provided + if (issueImageFile) { + const { data, error } = await supabase.storage + .from("villabugis") + .upload(`issue/${issueImageFile.name}`, issueImageFile); + + if (error) { + console.error("Error uploading image:", error); + return; + } + + issueImageUrl = data.path; // Assuming data.Key contains the URL or path to the uploaded image + } + const issue: Issue = { name: formData.get("name") as string, villa_name: formData.get("villa_name") as string, diff --git a/src/routes/backoffice/project/+page.svelte b/src/routes/backoffice/project/+page.svelte index bd6b751..8d1207d 100644 --- a/src/routes/backoffice/project/+page.svelte +++ b/src/routes/backoffice/project/+page.svelte @@ -279,9 +279,29 @@ } } + // function get public URL for image supabase + async function getPublicUrl(path: string): Promise { + const { data } = supabase.storage.from("villabugis").getPublicUrl(path); + return data.publicUrl; + } + async function saveProject(event: Event) { const formData = new FormData(event.target as HTMLFormElement); + // Upload image if selected + if (selectedFile) { + const { data, error } = await supabase.storage + .from("villabugis") + .upload(`project/${selectedFile.name}`, selectedFile); + + if (error) { + console.error("Error uploading image:", error); + return; + } + + imagePreviewUrl = data?.path; + } + const projectUpdate: insetProject = { issue_id: formData.get("issue_id") as string, input_by: formData.get("input_by") as string, @@ -439,15 +459,21 @@ ❌ {/if} {#if row.picture_link} - View Picture + {#await getPublicUrl(row.picture_link) then publicUrl} + View Picture + {:catch} + Error loading image + {/await} {:else} No Picture {/if} @@ -556,6 +582,18 @@ alt="Preview" class="mt-2 max-h-48 rounded border" /> + {:else if newProjects.picture_link} + {#await getPublicUrl(newProjects.picture_link) then url} + Preview + {/await} + {:else} +

+ No image selected or uploaded. +

{/if} {:else} diff --git a/src/routes/backoffice/timesheets/+page.svelte b/src/routes/backoffice/timesheets/+page.svelte new file mode 100644 index 0000000..7a4b177 --- /dev/null +++ b/src/routes/backoffice/timesheets/+page.svelte @@ -0,0 +1,763 @@ + + +
+
+
+

Timesheet List

+

+ Manage and track timesheets for staff members. +

+
+ +
+
+ + + + {#each columns as col} + {#if col.key === "name"} + + {:else} + + {/if} + {/each} + + + + {#each paginatedRows as row} + + {#each columns as col} + {#if col.key === "name"} + + {:else if col.key === "actions"} + + {:else if col.key === "approval"} + {#if row[col.key as keyof Timesheets] === "APPROVED"} + + {:else if row[col.key as keyof Timesheets] === "PENDING"} + + {:else if row[col.key as keyof Timesheets] === "REJECTED"} + + {:else} + + + {/if} + {:else if col.key === "vacant"} + + {:else} + + {/if} + {/each} + + {/each} + +
+ {col.title} + + {col.title} +
+ {row[col.key]} + + + + + ✅ Approved + + ⏳ Pending + + ❌ Rejected + + + + {#if row[col.key as keyof Timesheets]} + ✅ Vacant + {:else} + ❌ Not Vacant + {/if} + + {row[col.key as keyof Timesheets]} +
+
+ + +
+
+ Showing {(currentPage - 1) * rowsPerPage + 1}– + {Math.min(currentPage * rowsPerPage, allRows.length)} of {allRows.length} +
+
+ + {#each Array(totalPages) + .fill(0) + .map((_, i) => i + 1) as page} + + {/each} + +
+
+
+ + +{#if showModal} +
+
+

+ {isEditing ? "Edit Issue" : "Add New Issue"} +

+ {#each formColumns as col} + {#if col.key === "name"} +
+ + + {#if $formErrors.name} +

+ {$formErrors.name} +

+ {/if} +
+ {:else if col.key === "vacant"} +
+ + +
+ {:else if col.key === "reported_by"} +
+ + + {#if $formErrors.reported_by} +

+ {$formErrors.reported_by} +

+ {/if} +
+ {:else if col.key === "villa_name"} +
+ + + {#if $formErrors.villa_name} +

+ {$formErrors.villa_name} +

+ {/if} +
+ {:else if col.key === "remarks"} +
+ + + {#if $formErrors.remarks} +

+ {$formErrors.remarks} +

+ {/if} +
+ {:else if col.key === "date_in"} +
+ + + {#if $formErrors.date_in} +

+ {$formErrors.date_in} +

+ {/if} +
+ {:else if col.key === "date_out"} +
+ + + {#if $formErrors.date_out} +

+ {$formErrors.date_out} +

+ {/if} +
+ {:else if col.key === "type_of_work"} +
+ + + {#if $formErrors.type_of_work} +

+ {$formErrors.type_of_work} +

+ {/if} +
+ {:else if col.key === "category_of_work"} +
+ + +
+ {#if $formErrors.category_of_work} +

+ {$formErrors.category_of_work} +

+ {/if} + {:else} +
+ + +
+ {/if} + {/each} +
+ + +
+
+
+{/if} diff --git a/src/routes/backoffice/timesheets/view/+page.svelte b/src/routes/backoffice/timesheets/view/+page.svelte new file mode 100644 index 0000000..7a1d021 --- /dev/null +++ b/src/routes/backoffice/timesheets/view/+page.svelte @@ -0,0 +1,364 @@ + + +
+
+ +

Timesheet Form

+ + +
+ +
+
+ + + {#if $formErrors.name} +

+ {$formErrors.name} +

+ {/if} +
+
+ + + {#if $formErrors.type_of_work} +

+ {$formErrors.type_of_work} +

+ {/if} +
+
+ + + {#if $formErrors.villa_id} +

+ {$formErrors.villa_id} +

+ {/if} +
+
+ + + + {#if $formErrors.date_out} +

+ {$formErrors.date_out} +

+ {/if} +
+
+ + +
+
+ + + {#if $formErrors.reported_by} +

+ {$formErrors.reported_by} +

+ {/if} +
+
+ + + {#if $formErrors.category_of_work} +

+ {$formErrors.category_of_work} +

+ {/if} +
+
+ + + {#if $formErrors.date_in} +

+ {$formErrors.date_in} +

+ {/if} +
+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+ +
+
+
diff --git a/src/routes/backoffice/vendor/+page.svelte b/src/routes/backoffice/vendor/+page.svelte index 2378e59..d6536f4 100644 --- a/src/routes/backoffice/vendor/+page.svelte +++ b/src/routes/backoffice/vendor/+page.svelte @@ -1,6 +1,7 @@ -
-
-

Vendor List

-

Manage your vendor and contact data

-
- +
+

🏡 Vendor List

+

+ Manage your vendors and their contact information here. +

+
+
+ { + const searchTerm = ( + e.target as HTMLInputElement + ).value.toLowerCase(); + fetchVendor(searchTerm, "created_at", "desc", limit, 0); + }} + /> + + + + + +
+
@@ -310,7 +380,7 @@
@@ -196,7 +370,7 @@ - {#each paginatedRows as row} + {#each allRows as row} {#each columns as col} {#if col.key === "name"} @@ -206,6 +380,138 @@ > {row[col.key]} + {:else if col.key === "created_at"} + + {:else if col.key === "villa_status"} + + + {:else if col.key === "villa_condition"} + + {:else if col.key === "villa_manager"} + + {:else if col.key === "villa_location"} + + {:else if col.key === "no_of_bedrooms"} + + {:else if col.key === "created_by"} + + {:else if col.key === "villa_email_address"} + + {:else if col.key === "owner_portal_username"} + + {:else if col.key === "owner_portal_password"} + + {:else if col.key === "closeable_living_room"} + + {:else if col.key === "monthly_rental_pre_approved_status"} + + {:else if col.key === "long_term_rental_pre_approval"} + + {:else if col.key === "pet_allowed_pre_approval_status"} + + {:else if col.key === "session_1_rate"} + + {:else if col.key === "session_2_rate"} + + {:else if col.key === "session_3_rate"} + + {:else if col.key === "session_4_rate"} + + {:else if col.key === "session_5_rate"} + + {:else if col.key === "session_6_rate"} + + {:else if col.key === "session_7_rate"} + {:else if col.key === "actions"}
+ {new Date(row[col.key]).toLocaleDateString( + "en-US", + { + year: "numeric", + month: "short", + day: "numeric", + }, + )} + + + + + + {row[col.key] || "N/A"} + + {row[col.key] || "N/A"} + + {row[col.key] || "N/A"} + + {row[col.key] || "N/A"} + + {row[col.key] || "N/A"} + + {row[col.key] || "N/A"} + + {row[col.key] || "N/A"} + + {row[col.key] ? "✔️ Yes" : "❌ No"} + + {row[col.key] ? "✔️ Yes" : "❌ No"} + + {row[col.key] ? "✔️ Yes" : "❌ No"} + + {row[col.key] ? "✔️ Yes" : "❌ No"} + + {row[col.key] || "N/A"} + + {row[col.key] || "N/A"} + + {row[col.key] || "N/A"} + + {row[col.key] || "N/A"} + + {row[col.key] || "N/A"} + + {row[col.key] || "N/A"} + + {row[col.key] || "N/A"} + - + {/if}