perbaikan data HR dengan BENEFITS
This commit is contained in:
@@ -54,6 +54,17 @@
|
||||
created_at?: Date;
|
||||
};
|
||||
|
||||
type EmployeeBenefits = {
|
||||
id: string;
|
||||
employee_id: string;
|
||||
basic_salary: number;
|
||||
position_allowance: number;
|
||||
meal_allowance: number;
|
||||
transportation_allowance: number;
|
||||
created_at: Date;
|
||||
updated_at: Date;
|
||||
};
|
||||
|
||||
const EmployeeStatus = {
|
||||
Active: "Active",
|
||||
Inactive: "Inactive",
|
||||
@@ -110,7 +121,10 @@
|
||||
{ key: "temporary_address", title: "Temporary Address" },
|
||||
{ key: "job_title", title: "Job Title" },
|
||||
{ key: "emergency_contact_name", title: "Emergency Contact Name" },
|
||||
{ key: "emergency_contact_relation", title: "Emergency Contact Relation" },
|
||||
{
|
||||
key: "emergency_contact_relation",
|
||||
title: "Emergency Contact Relation",
|
||||
},
|
||||
{ key: "emergency_contact_phone", title: "Emergency Contact Phone" },
|
||||
{ key: "bank_account", title: "Bank Account" },
|
||||
{ key: "bank_account_name", title: "Employee Bank Account Name" },
|
||||
@@ -130,10 +144,20 @@
|
||||
{ key: "child_2", title: "Child 2" },
|
||||
{ key: "child_3", title: "Child 3" },
|
||||
{ key: "document", title: "Document" },
|
||||
{ key: "benefits", title: "Benefits" },
|
||||
{ key: "created_at", title: "Created At" },
|
||||
{ key: "actions", title: "Actions" },
|
||||
];
|
||||
|
||||
const columnBenefits: columns[] = [
|
||||
{ key: "basic_salary", title: "Basic Salary" },
|
||||
{ key: "position_allowance", title: "Position Allowance" },
|
||||
{ key: "meal_allowance", title: "Meal Allowance" },
|
||||
{ key: "transportation_allowance", title: "Transportation Allowance" },
|
||||
{ key: "created_at", title: "Created At" },
|
||||
{ key: "updated_at", title: "Updated At" },
|
||||
];
|
||||
|
||||
let currentPage = offset + 1;
|
||||
let rowsPerPage = 10;
|
||||
let totalItems = 0;
|
||||
@@ -177,6 +201,21 @@
|
||||
console.log("Total Items:", totalItems);
|
||||
}
|
||||
|
||||
async function fetchEmployeeBenefits(employeeId: string) {
|
||||
const { data, error } = await supabase
|
||||
.from("vb_benefits")
|
||||
.select("*")
|
||||
.eq("employee_id", employeeId)
|
||||
.single();
|
||||
|
||||
if (error) {
|
||||
console.error("Error fetching Employee Benefits:", error);
|
||||
return null;
|
||||
}
|
||||
|
||||
return data as EmployeeBenefits;
|
||||
}
|
||||
|
||||
$: totalPages = Math.ceil(totalItems / rowsPerPage);
|
||||
|
||||
function goToPage(page: number) {
|
||||
@@ -185,7 +224,13 @@
|
||||
currentPage = page;
|
||||
offset = (currentPage - 1) * rowsPerPage;
|
||||
|
||||
fetchEmployee(search, "created_at", "desc", currentPage - 1, rowsPerPage);
|
||||
fetchEmployee(
|
||||
search,
|
||||
"created_at",
|
||||
"desc",
|
||||
currentPage - 1,
|
||||
rowsPerPage,
|
||||
);
|
||||
}
|
||||
|
||||
function pageRange(
|
||||
@@ -220,7 +265,13 @@
|
||||
currentPage = page;
|
||||
offset = (currentPage - 1) * rowsPerPage;
|
||||
|
||||
fetchEmployee(search, "created_at", "desc", currentPage - 1, rowsPerPage);
|
||||
fetchEmployee(
|
||||
search,
|
||||
"created_at",
|
||||
"desc",
|
||||
currentPage - 1,
|
||||
rowsPerPage,
|
||||
);
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
@@ -231,6 +282,7 @@
|
||||
$: currentPage = 1;
|
||||
|
||||
let showModal = false;
|
||||
let showModalBenefits = false;
|
||||
let isEditing = false;
|
||||
let currentEditingId: string | null = null;
|
||||
let newEmployeeInsert: EmployeeItem = {
|
||||
@@ -282,21 +334,68 @@
|
||||
created_at: new Date(),
|
||||
};
|
||||
|
||||
let newEmployeeBenefits: EmployeeBenefits = {
|
||||
id: "",
|
||||
employee_id: "",
|
||||
basic_salary: 0,
|
||||
position_allowance: 0,
|
||||
meal_allowance: 0,
|
||||
transportation_allowance: 0,
|
||||
created_at: new Date(),
|
||||
updated_at: new Date(),
|
||||
};
|
||||
|
||||
let employeeBenefits: EmployeeBenefits = {
|
||||
id: "",
|
||||
employee_id: "",
|
||||
basic_salary: 0,
|
||||
position_allowance: 0,
|
||||
meal_allowance: 0,
|
||||
transportation_allowance: 0,
|
||||
created_at: new Date(),
|
||||
updated_at: new Date(),
|
||||
}
|
||||
|
||||
const excludedKeys = ["id", "actions", "created_at", "no"];
|
||||
const formColumns = columns.filter(
|
||||
(col) => !excludedKeys.includes(col.key),
|
||||
);
|
||||
|
||||
function openModal(newEmployeeItem?: EmployeeItem) {
|
||||
if (newEmployeeItem) {
|
||||
console.log("Editing Employee:", newEmployeeItem);
|
||||
const excludedKeysBenefits = [
|
||||
"id",
|
||||
"employee_id",
|
||||
"created_at",
|
||||
"updated_at",
|
||||
];
|
||||
const formColumnsBenefits = columnBenefits.filter(
|
||||
(col) => !excludedKeysBenefits.includes(col.key),
|
||||
);
|
||||
|
||||
function openModal(newEmployeeItem?: EmployeeItem, emp?: number) {
|
||||
if (newEmployeeItem) {
|
||||
isEditing = true;
|
||||
currentEditingId = newEmployeeItem.id;
|
||||
console.log("Current Editing ID:", currentEditingId);
|
||||
|
||||
// Copy data to avoid direct mutation
|
||||
newEmployeeInsert = { ...newEmployeeItem };
|
||||
|
||||
// Fetch and populate benefits data
|
||||
fetchEmployeeBenefits(newEmployeeItem.id).then((benefits) => {
|
||||
if (benefits) {
|
||||
newEmployeeBenefits = benefits;
|
||||
} else {
|
||||
newEmployeeBenefits = {
|
||||
id: "",
|
||||
employee_id: newEmployeeItem.id,
|
||||
basic_salary: newEmployeeItem.salary || 0,
|
||||
position_allowance: 0,
|
||||
meal_allowance: 0,
|
||||
transportation_allowance: 0,
|
||||
created_at: new Date(),
|
||||
updated_at: new Date(),
|
||||
};
|
||||
}
|
||||
});
|
||||
} else {
|
||||
isEditing = false;
|
||||
currentEditingId = null;
|
||||
@@ -349,10 +448,42 @@
|
||||
place_of_birth: "",
|
||||
created_at: new Date(),
|
||||
};
|
||||
|
||||
newEmployeeBenefits = {
|
||||
id: "",
|
||||
employee_id: "",
|
||||
basic_salary: 0,
|
||||
position_allowance: 0,
|
||||
meal_allowance: 0,
|
||||
transportation_allowance: 0,
|
||||
created_at: new Date(),
|
||||
updated_at: new Date(),
|
||||
};
|
||||
}
|
||||
showModal = true;
|
||||
}
|
||||
|
||||
async function openModalBenefits(employee: EmployeeItem) {
|
||||
const benefits = await fetchEmployeeBenefits(employee.id);
|
||||
|
||||
if (benefits) {
|
||||
employeeBenefits = benefits;
|
||||
} else {
|
||||
employeeBenefits = {
|
||||
id: "",
|
||||
employee_id: employee.id,
|
||||
basic_salary: employee.salary || 0,
|
||||
position_allowance: 0,
|
||||
meal_allowance: 0,
|
||||
transportation_allowance: 0,
|
||||
created_at: new Date(),
|
||||
updated_at: new Date(),
|
||||
};
|
||||
}
|
||||
|
||||
showModalBenefits = true;
|
||||
}
|
||||
|
||||
async function saveEmployee(event: Event) {
|
||||
event.preventDefault();
|
||||
|
||||
@@ -372,9 +503,50 @@
|
||||
alert("Error updating Employee: " + error.message);
|
||||
console.error("Error updating Employee:", error);
|
||||
return;
|
||||
} else {
|
||||
alert("Employee updated successfully!");
|
||||
}
|
||||
// cek apakah data vb_benefits sudah ada
|
||||
const { data: existingBenefits, error: checkError } = await supabase
|
||||
.from("vb_benefits")
|
||||
.select("id")
|
||||
.eq("employee_id", currentEditingId)
|
||||
.maybeSingle();
|
||||
|
||||
if (checkError) {
|
||||
console.error("Error checking vb_benefits:", checkError);
|
||||
}
|
||||
|
||||
if (existingBenefits) {
|
||||
// update jika ada
|
||||
const { error: benefitsError } = await supabase
|
||||
.from("vb_benefits")
|
||||
.update(newEmployeeBenefits)
|
||||
.eq("employee_id", currentEditingId);
|
||||
|
||||
if (benefitsError) {
|
||||
console.error("Error updating vb_benefits:", benefitsError);
|
||||
}
|
||||
} else {
|
||||
|
||||
const idBenefit = uuidv4();
|
||||
newEmployeeBenefits.id = idBenefit;
|
||||
newEmployeeBenefits.employee_id = currentEditingId;
|
||||
|
||||
// insert jika belum ada
|
||||
const { error: benefitsInsertError } = await supabase
|
||||
.from("vb_benefits")
|
||||
.insert({
|
||||
...newEmployeeBenefits,
|
||||
});
|
||||
|
||||
if (benefitsInsertError) {
|
||||
console.error(
|
||||
"Error inserting vb_benefits:",
|
||||
benefitsInsertError,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
alert("Employee Updated successfully!");
|
||||
} else {
|
||||
newEmployeeInsert.id = uuidv4(); // Generate a new UUID for the ID
|
||||
|
||||
@@ -386,6 +558,21 @@
|
||||
alert("Error creating New Employee: " + error.message);
|
||||
console.error("Error creating New Employee:", error);
|
||||
return;
|
||||
}
|
||||
|
||||
newEmployeeBenefits.id = uuidv4();
|
||||
newEmployeeBenefits.employee_id = newEmployeeInsert.id;
|
||||
|
||||
const { error: benefitsError } = await supabase
|
||||
.from("vb_employee_benefits")
|
||||
.insert(newEmployeeBenefits);
|
||||
|
||||
if (benefitsError) {
|
||||
console.error(
|
||||
"Error creating Employee Benefits:",
|
||||
benefitsError,
|
||||
);
|
||||
return;
|
||||
} else {
|
||||
alert("New Employee created successfully!");
|
||||
}
|
||||
@@ -467,9 +654,7 @@
|
||||
placeholder="🔍 Search by item name..."
|
||||
class="border border-gray-300 focus:ring-2 focus:ring-blue-500 focus:outline-none px-4 py-2 rounded-xl text-sm w-64 transition"
|
||||
on:input={(e) => {
|
||||
search = (
|
||||
e.target as HTMLInputElement
|
||||
).value.toLowerCase();
|
||||
search = (e.target as HTMLInputElement).value.toLowerCase();
|
||||
|
||||
if (search !== "" && search.length > 3) {
|
||||
fetchEmployee(search, "created_at", "desc", 0, 10);
|
||||
@@ -575,7 +760,9 @@
|
||||
<td class="px-4 py-2">
|
||||
{#if row[col.key as keyof EmployeeItem]}
|
||||
<a
|
||||
href={row[col.key as keyof EmployeeItem] as string}
|
||||
href={row[
|
||||
col.key as keyof EmployeeItem
|
||||
] as string}
|
||||
target="_blank"
|
||||
class="text-blue-600 hover:underline"
|
||||
>View</a
|
||||
@@ -597,7 +784,7 @@
|
||||
)
|
||||
: "N/A"}
|
||||
</td>
|
||||
{:else if col.key === "contract_start" || col.key === "end_of_contract" || col.key === "date_of_birth"}
|
||||
{:else if col.key === "contract_start" || col.key === "end_of_contract" || col.key === "date_of_birth" || col.key === "hire_date" || col.key === "leaving_date"}
|
||||
<td class="px-4 py-2">
|
||||
{row[col.key as keyof EmployeeItem]
|
||||
? new Date(
|
||||
@@ -607,6 +794,15 @@
|
||||
).toLocaleDateString()
|
||||
: "N/A"}
|
||||
</td>
|
||||
{:else if col.key === "benefits"}
|
||||
<td class="px-4 py-2">
|
||||
<button
|
||||
class="inline-flex items-center gap-1 rounded bg-green-600 px-3 py-1.5 text-white text-xs font-medium hover:bg-green-700"
|
||||
on:click={() => openModalBenefits(row)}
|
||||
>
|
||||
💼 View Benefits
|
||||
</button>
|
||||
</td>
|
||||
{:else if col.key === "created_at"}
|
||||
<td class="px-4 py-2">
|
||||
{row[col.key as keyof EmployeeItem]
|
||||
@@ -681,6 +877,7 @@
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
{#if showModal}
|
||||
@@ -756,7 +953,9 @@
|
||||
col.key,
|
||||
)}"
|
||||
>
|
||||
<option value="" disabled>Select marital status</option>
|
||||
<option value="" disabled
|
||||
>Select marital status</option
|
||||
>
|
||||
{#each Object.entries(MaritalStatus) as [key, value]}
|
||||
<option value={key}>{value}</option>
|
||||
{/each}
|
||||
@@ -784,6 +983,38 @@
|
||||
</div>
|
||||
{/each}
|
||||
|
||||
<h3 class="text-lg font-semibold mb-2">Benefits</h3>
|
||||
|
||||
{#each formColumnsBenefits as col}
|
||||
<div class="mb-4">
|
||||
<label
|
||||
for={col.key}
|
||||
class="block text-sm font-medium text-gray-700 mb-1"
|
||||
>
|
||||
{col.title}
|
||||
</label>
|
||||
{#if col.key === "basic_salary"}
|
||||
<input
|
||||
type="number"
|
||||
id={col.key}
|
||||
bind:value={newEmployeeBenefits[col.key]}
|
||||
class="w-full px-3 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||
/>
|
||||
{:else}
|
||||
<input
|
||||
type="number"
|
||||
id={col.key}
|
||||
bind:value={
|
||||
newEmployeeBenefits[
|
||||
col.key as keyof EmployeeBenefits
|
||||
]
|
||||
}
|
||||
class="w-full px-3 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||
/>
|
||||
{/if}
|
||||
</div>
|
||||
{/each}
|
||||
|
||||
<div class="flex justify-end space-x-2">
|
||||
<button
|
||||
type="button"
|
||||
@@ -803,3 +1034,59 @@
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if showModalBenefits}
|
||||
<div
|
||||
class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50"
|
||||
>
|
||||
<div
|
||||
class="bg-white rounded-lg shadow-lg p-6 w-full max-w-md max-h-[90vh] overflow-y-auto"
|
||||
>
|
||||
<h2 class="text-xl font-semibold mb-4">Employee Benefits</h2>
|
||||
|
||||
<div class="space-y-4">
|
||||
{#each formColumnsBenefits as col}
|
||||
<div class="mb-4">
|
||||
<label
|
||||
for={col.key}
|
||||
class="block text-sm font-medium text-gray-700 mb-1"
|
||||
>
|
||||
{col.title}
|
||||
</label>
|
||||
{#if col.key === "basic_salary"}
|
||||
<input
|
||||
type="number"
|
||||
id={col.key}
|
||||
bind:value={employeeBenefits[col.key]}
|
||||
class="w-full px-3 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||
readonly
|
||||
/>
|
||||
{:else}
|
||||
<input
|
||||
type="number"
|
||||
id={col.key}
|
||||
bind:value={
|
||||
employeeBenefits[
|
||||
col.key as keyof EmployeeBenefits
|
||||
]
|
||||
}
|
||||
class="w-full px-3 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||
readonly
|
||||
/>
|
||||
{/if}
|
||||
</div>
|
||||
{/each}
|
||||
|
||||
<div class="flex justify-end">
|
||||
<button
|
||||
type="button"
|
||||
class="px-4 py-2 bg-gray-200 text-gray-700 rounded-xl hover:bg-gray-300"
|
||||
on:click={() => (showModalBenefits = false)}
|
||||
>
|
||||
Close
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
Reference in New Issue
Block a user