From b1040ac851536707368f700c4c5106cfdc28038e Mon Sep 17 00:00:00 2001 From: arteons Date: Mon, 18 Aug 2025 08:57:32 +0800 Subject: [PATCH] add hr & accounting page --- src/components/Sidebar.svelte | 216 ++- .../backoffice/humanresource/+page.svelte | 0 .../humanresource/employee/+page.svelte | 0 .../backoffice/purchaseorder/+page.svelte | 50 +- .../purchaseorder/accounting/+page.svelte | 0 src/routes/backoffice/task/+page.svelte | 1244 +++++++++++++++++ 6 files changed, 1477 insertions(+), 33 deletions(-) create mode 100644 src/routes/backoffice/humanresource/+page.svelte create mode 100644 src/routes/backoffice/humanresource/employee/+page.svelte create mode 100644 src/routes/backoffice/purchaseorder/accounting/+page.svelte create mode 100644 src/routes/backoffice/task/+page.svelte diff --git a/src/components/Sidebar.svelte b/src/components/Sidebar.svelte index efd7345..fa9a88c 100644 --- a/src/components/Sidebar.svelte +++ b/src/components/Sidebar.svelte @@ -39,16 +39,18 @@ }; let userRole: - | "it" + | "it" //IT + | "finance" // Finance + | "purchasing" // Purchasing + | "opman" // Operations Manager + | "ofman" // Office Manager | "guest" | "accounting" - | "ga" - | "hr" - | "s&m" - | "office" - | "hm" - | "vm" - | "it"; + | "ga" // General Affairs + | "hr" // Human Resources + | "sm" // Sales & Marketing + | "hk" + | "vm"; // Villa Manager export let pageName = ""; const dispatch = createEventDispatcher(); @@ -61,13 +63,16 @@ url: "/backoffice", roles: [ "it", + "finance", + "purchasing", + "opman", + "ofman", "guest", "accounting", "ga", "hr", - "s&m", - "office", - "hm", + "sm", + "hk", "vm", ], }, @@ -75,25 +80,70 @@ name: "Issues", icon: "📂", url: "/backoffice/issue", - roles: ["it", "ga", "office", "hm", "vm", "accounting"], + roles: [ + "it", + "finance", + "purchasing", + "opman", + "ofman", + "guest", + "accounting", + "ga", + "hr", + "sm", + "hk", + "vm", + ], }, { name: "Projects", icon: "📂", - url: "/backoffice/project", - roles: ["it", "ga", "office", "hm", "vm", "accounting"], + url: "/backoffice/project", + roles: [ + "it", + "finance", + "purchasing", + "opman", + "ofman", + "guest", + "accounting", + "ga", + "hr", + "sm", + "hk", + "vm", + ], }, { name: "Purchase Orders", icon: "📦", url: "/backoffice/purchaseorder", - roles: ["it", "guest", "accounting", "ga", "office", "hm", "vm"], + roles: [ + "it", + "finance", + "purchasing", + "opman", + "ofman", + "guest", + "accounting", + "ga", + "hr", + "sm", + "hk", + "vm", + ], sub: [ { name: "PO Item", icon: "📋", url: "/backoffice/purchaseorder/poitem", - roles: ["it", "ga", "office", "hm", "vm", "accounting"], + roles: ["it","finance", "ga", "office", "hm", "vm", "accounting"], + }, + { + name: "Accounting", + icon: "📋", + url: "/backoffice/purchaseorder/accounting", + roles: ["it","finance","accounting"], }, ], }, @@ -101,37 +151,144 @@ name: "Timesheets", icon: "⏰", url: "/backoffice/timesheets", - roles: ["it", "ga", "hr", "office", "hm", "vm"], + roles: [ + "it", + "finance", + "purchasing", + "opman", + "ofman", + "guest", + "accounting", + "ga", + "hr", + "sm", + "hk", + "vm", + ], }, { name: "Vendors", icon: "🏢", url: "/backoffice/vendor", - roles: ["it", "ga", "office", "hm", "vm"], + roles: [ + "it", + "finance", + "purchasing", + "opman", + "ofman", + "guest", + "accounting", + "ga", + "hr", + "sm", + "hk", + "vm", + ], }, { name: "Inventory", icon: "📋", url: "/backoffice/inventory", - roles: ["it", "ga", "s&m", "office", "hm", "vm"], + roles: [ + "it", + "finance", + "purchasing", + "opman", + "ofman", + "guest", + "accounting", + "ga", + "hr", + "sm", + "hk", + "vm", + ], }, { name: "Villa", icon: "🏡", url: "/backoffice/villa", - roles: ["it", "ga", "s&m", "office", "hm", "vm"], + roles: [ + "it", + "finance", + "purchasing", + "opman", + "ofman", + "guest", + "accounting", + "ga", + "hr", + "sm", + "hk", + "vm", + ], }, { name: "Transport", icon: "🚗", url: "/backoffice/transport", - roles: ["it", "ga", "s&m", "office", "hm", "vm"], + roles: [ + "it", + "finance", + "purchasing", + "opman", + "ofman", + "guest", + "accounting", + "ga", + "hr", + "sm", + "hk", + "vm", + ], + }, + + { + name: "Human Resource", + icon: "👥", + url: "/backoffice/humanresource", + roles: [ + "it", + "finance", + "purchasing", + "opman", + "ofman", + "guest", + "accounting", + "ga", + "hr", + "sm", + "hk", + "vm", + ], + sub: + [ + { + name: "Employee", + icon: "👨‍💼", + url: "/backoffice/humanresource/employee", + roles: ["it","finance", "ga", "office", "hm", "hr", "accounting"], + }, + ] }, { name: "Dining", icon: "🍽️", url: "/backoffice/dining", - roles: ["it", "ga", "s&m", "office", "hm", "vm"], + roles: [ + "it", + "finance", + "purchasing", + "opman", + "ofman", + "guest", + "accounting", + "ga", + "hr", + "sm", + "hk", + "vm", + ], }, { name: "Users", @@ -143,7 +300,20 @@ name: "Feedback", icon: "💬", url: "/backoffice/feedback", - roles: ["it", "ga", "s&m", "office", "hm", "vm"], + roles: [ + "it", + "finance", + "purchasing", + "opman", + "ofman", + "guest", + "accounting", + "ga", + "hr", + "sm", + "hk", + "vm", + ], }, ]; diff --git a/src/routes/backoffice/humanresource/+page.svelte b/src/routes/backoffice/humanresource/+page.svelte new file mode 100644 index 0000000..e69de29 diff --git a/src/routes/backoffice/humanresource/employee/+page.svelte b/src/routes/backoffice/humanresource/employee/+page.svelte new file mode 100644 index 0000000..e69de29 diff --git a/src/routes/backoffice/purchaseorder/+page.svelte b/src/routes/backoffice/purchaseorder/+page.svelte index e41314b..03f4abe 100644 --- a/src/routes/backoffice/purchaseorder/+page.svelte +++ b/src/routes/backoffice/purchaseorder/+page.svelte @@ -94,6 +94,7 @@ { key: "payment", title: "Payment" }, { key: "actions", title: "Actions" }, // For edit/delete buttons ]; + const excludedKeys = [ "id", "priority", @@ -320,12 +321,33 @@ let vendors: { id: string; name: string }[] = []; let issues: { id: string; name: string }[] = []; let printingId: string | null = null; + let currentUserRole = ""; // keep if already declared + + // Which roles are allowed to SEE each column (and use its action) + const columnRoleAccess: Record = { + prepared: ["it","purchasing","finance","ofman"], + approved: ["it","ofman","opman","finance"], + acknowledged: ["it","finance","ofman","vm"], + completed: ["it","purchasing","finance","ofman"], + received: ["it","purchasing","finance","ofman","opman"], + payment: ["it","purchasing","finance","ofman"], + }; + + function canSeeColumn(key: string, role: string) { + const allowed = columnRoleAccess[key]; + return !allowed || allowed.includes(role); + } + + // make currentUserRole a reactive dependency by passing it in + $: visibleColumns = columns.filter(c => canSeeColumn(c.key, currentUserRole)); + $: formattedPrice = preparedForm.q1_vendor_price.toLocaleString("id-ID", { style: "currency", currency: "IDR", minimumFractionDigits: 0, }); + // function Sort function toggleSort(column: string) { if (sortColumn === column) { @@ -615,6 +637,8 @@ showPaymentModal = false; await refresh(); } + $: console.log("role:", currentUserRole, "visible:", visibleColumns.map(c=>c.key)); + // Save approval for purchase order async function saveApproval() { const { error } = await supabase @@ -731,13 +755,15 @@ const { data, error } = await supabase .from("vb_users") - .select("full_name") + .select("full_name, role") .eq("id", user.id) .single(); - if (!error && data) { - currentUserFullName = data.full_name; - } + if (!error && data) { + currentUserFullName = data.full_name; + currentUserRole = (data.role || "").toLowerCase(); // 👈 normalize once here + } + console.log('role:', currentUserRole) } } // Save edited purchase order @@ -853,7 +879,9 @@ supabase .from("vb_employee") .select("id, employee_name") - .eq("employee_status", "Active"), + .eq("employee_status", "Active") + .in("job_title", ["Account Receivable", "General Cashier"]) + .order("employee_name", { ascending: true }), supabase.from("vb_po_item").select("id, item_name"), supabase.from("vb_vendor").select("id, name"), ]); @@ -1357,7 +1385,7 @@ - {#each columns as col} + {#each visibleColumns as col} {#if col.key === "purchase_order_number"} - {#each columns as col} + {#each visibleColumns as col} {#if col.key === "requested_date" || col.key === "po_due" || col.key === "updated_at"} {:else}
{#each allRows as row}
{#if row[col.key]} @@ -1546,12 +1574,14 @@ ✏️ Edit - + + {/if} diff --git a/src/routes/backoffice/purchaseorder/accounting/+page.svelte b/src/routes/backoffice/purchaseorder/accounting/+page.svelte new file mode 100644 index 0000000..e69de29 diff --git a/src/routes/backoffice/task/+page.svelte b/src/routes/backoffice/task/+page.svelte new file mode 100644 index 0000000..55c8604 --- /dev/null +++ b/src/routes/backoffice/task/+page.svelte @@ -0,0 +1,1244 @@ + + +
+
+
+

+ 🕒 Timesheet List +

+

+ Manage and track timesheets for staff members. +

+
+
+ { + currentSearchTerm = ( + e.target as HTMLInputElement + ).value.toLowerCase(); + fetchTimeSheets(currentVillaFilter, currentSearchTerm); + }} + /> + + + +
+
+
+ + + + {#each columns as col} + {#if col.key === "villa_name"} + + {:else} + + {/if} + {/each} + + + + {#each allRows as row} + + {#each columns as col} + {#if col.key === "name"} + + {:else if col.key === "approval"} + + {:else if col.key === "approved_by"} + + {:else if col.key === "approved_date"} + + {:else if col.key === "total_hours_work"} + + {:else if col.key === "created_at"} + + {:else if col.key === "villa_name"} + + {:else if col.key === "staff_id"} + + {:else if col.key === "remarks"} + + {:else if col.key === "actions"} + + {:else if col.key === "date_in" || col.key === "date_out"} + + {:else} + + {/if} + {/each} + + {/each} + +
toggleSort(col.key)} + > + {col.title} + {#if sortColumn === col.key} + {sortOrder === "asc" ? " 🔼" : " 🔽"} + {/if} + toggleSort(col.key)} + > + {col.title} + {#if sortColumn === col.key} + {sortOrder === "asc" ? " 🔼" : " 🔽"} + {/if} +
+ {row[col.key]} + + + {row[col.key]} + + {#if row.approval === "PENDING"} + + + {/if} + + {row[col.key] || "Not Approved"} + + {row[col.key] && + !isNaN( + new Date( + row[col.key] as + | string + | number + | Date, + ).getTime(), + ) + ? new Date( + row[col.key] as + | string + | number + | Date, + ).toLocaleString() + : "N/A"} + + {row[col.key].toFixed(2)} hours + + {row[col.key] !== undefined + ? new Date( + row[col.key] as + | string + | number + | Date, + ).toLocaleString() + : "N/A"} + + {row[col.key] || "Unknown Villa"} + + {row[col.key] || "Unknown Staff"} + + {row[col.key] || "No remarks"} + + + + + {row[col.key] + ? new Date( + row[col.key], + ).toLocaleString() + : "N/A"} + + {row[col.key as keyof TimesheetDisplay]} +
+
+ + +
+
+ Showing {(currentPage - 1) * rowsPerPage + 1}– + {Math.min(currentPage * rowsPerPage, totalItems)} of {totalItems} items +
+
+ +
+ + + + + + + + + + +
+
+ + + + {#each pageRange(totalPages, currentPage) as page} + {#if page === "..."} + ... + {:else} + + {/if} + {/each} + +
+
+
+
+ + +{#if showModal} +
+
+
+

+ {isEditing ? "Edit Timesheet" : "New Timesheet Entry"} +

+ +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ +
{form.total_work_hour}
+
+ +
+ + +
+ + +
+
+{/if}