penisularhr-ui / src / routes / app / employee / +page.svelte
+page.svelte
Raw
<script lang="ts">
	import { PUBLIC_BASE_API_URL } from '$env/static/public';
	import {
		Button,
		Input,
		Label,
		P,
		Select,
		Spinner,
		Table,
		TableBody,
		TableBodyCell,
		TableBodyRow,
		TableHead,
		TableHeadCell
	} from 'flowbite-svelte';
	import { ArrowRightSolid, ArrowLeftSolid } from 'flowbite-svelte-icons';
	import type { PageData } from './$types';
	import Form from './Form.svelte';
	import { enhance } from '$app/forms';
	import { onMount } from 'svelte';

	export let data: PageData;

	// Input value
	let formValues: {
		id: null | string;
		name: null | string;
		origin: null | string;
		dateJoin: null | string;
		dateResign: null | string;
		referralBy: null | string;
		referralFeePaidAt: null | string;
		basicSalary: null | number;
		monthlyAllowanceAmount: null | number;
		annualLeave: null | number;
		sickLeave: null | number;
		epfRatePer: null | number;
		shouldDeductSocso: boolean;
		isActive: boolean;
		selection: null | any;
	} = {
		id: null,
		name: null,
		origin: null,
		dateJoin: null,
		basicSalary: null,
		monthlyAllowanceAmount: null,
		annualLeave: null,
		dateResign: null,
		epfRatePer: null,
		referralBy: null,
		referralFeePaidAt: null,
		sickLeave: null,
		isActive: false,
		shouldDeductSocso: false,
		selection: null
	};

	let inputLoading = false;

	const loadDropdown = async () => {
		inputLoading = true;
		const response = await fetch(`${PUBLIC_BASE_API_URL}/report/dropdown?shouldFilter=false`, {
			headers: {
				Authorization: `Bearer ${data.accessToken}`
			}
		});

		inputLoading = false;

		const dataResponse = await response.json();
		return dataResponse;
	};

	async function editFormValue(el: any) {
		formValues = {
			...el,
			selection: formValues.selection,
			dateJoin: new Date(el.dateJoin).toISOString().split('T')[0],
			dateResign: el.dateResign ? new Date(el.dateResign).toISOString().split('T')[0] : null,
			referralFeePaidAt: el.referralFeePaidAt
				? new Date(el.referralFeePaidAt).toISOString().split('T')[0]
				: null
		};
	}

	function resetFormInput() {
		formValues = {
			selection: formValues.selection,
			id: null,
			name: null,
			origin: null,
			dateJoin: null,
			basicSalary: null,
			monthlyAllowanceAmount: null,
			annualLeave: null,
			dateResign: null,
			epfRatePer: null,
			referralBy: null,
			referralFeePaidAt: null,
			isActive: false,
			shouldDeductSocso: false,
			sickLeave: null
		};
	}

	function updateInputLoading(state: boolean) {
		inputLoading = state;
	}

	// Page meta value
	let page = 1;
	let pageCount: number | string = '...';
	let hasPreviousPage = false;
	let hasNextPage = false;

	// Filter page value
	let filterName: string | null = null;
	let filterOrigin: string | null = null;
	let filterReferralBy: string | null = null;
	let filterIsActive: string | null = null;
	let filterReferralFeePaid: string | null = null;
	let tableError: string | null = null;

	let filterIsActiveSelect = [
		{ name: 'All', value: null },
		{ name: 'True', value: true },
		{ name: 'False', value: false }
	];

	let tableLoading = false;
	let tableData: any;

	function handleSubmit({ formData }: { formData: any }) {
		tableLoading = true;

		formData.set('page', page);

		return async ({ result, update }: { result: any; update: any }) => {
			tableLoading = false;
			await update({ reset: false });

			if (result.data.id !== 'tableData') {
				return;
			}

			if (result.type !== 'success') {
				tableError = result.data.message;
				tableData = null;
				pageCount = 1;
				hasPreviousPage = false;
				hasNextPage = false;
				return;
			}

			tableError = null;
			tableData = result.data.returnData;
			pageCount = result.data.pageCount;
			hasPreviousPage = result.data.hasPreviousPage;
			hasNextPage = result.data.hasNextPage;
			return;
		};
	}

	function reloadTable() {
		const form: any = document.getElementById('getTableData'); // Replace with your form ID
		const submitEvent = new Event('submit', { bubbles: true, cancelable: true });

		// Dispatch the submit event on the form element
		form.dispatchEvent(submitEvent);
	}

	onMount(async () => {
		reloadTable();

		formValues.selection = await loadDropdown();
	});

	async function reloadDropdown() {
		formValues.selection = await loadDropdown();
	}
</script>

<div>
	<Form
		{reloadTable}
		{formValues}
		{resetFormInput}
		{updateInputLoading}
		{inputLoading}
		{reloadDropdown}
	/>

	<div class="mt-10 flex flex-col">
		<form method="post" id="getTableData" action="?/getTableData" use:enhance={handleSubmit}>
			<div class="mb-5 flex gap-3">
				<div>
					<Label for="filterName" class="mb-2">Employee</Label>
					<Input id="filterName" type="text" name="filterName" bind:value={filterName} />
				</div>
				<div>
					<Label for="filterOrigin" class="mb-2">Origin</Label>
					<Input id="filterOrigin" type="text" name="filterOrigin" bind:value={filterOrigin} />
				</div>
				<div>
					<Label for="filterReferralBy" class="mb-2">Referral By</Label>
					<Input
						type="text"
						id="filterReferralBy"
						name="filterReferralBy"
						bind:value={filterReferralBy}
					/>
				</div>
				<div>
					<Label>
						Is Active
						<Select
							class="mt-2"
							items={filterIsActiveSelect}
							bind:value={filterIsActive}
							name="filterIsActive"
						/>
					</Label>
				</div>
				<div>
					<Label>
						Referral Fee Paid
						<Select
							class="mt-2"
							items={filterIsActiveSelect}
							bind:value={filterReferralFeePaid}
							name="filterReferralFeePaid"
						/>
					</Label>
				</div>
				<Button
					color="alternative"
					class="h-fit place-self-end"
					on:click={() => {
						filterName = null;
						filterOrigin = null;
						filterIsActive = null;
						filterReferralBy = null;
						filterReferralFeePaid = null;
					}}>Reset</Button
				>
				<Button type="submit" class="h-fit place-self-end">Filter</Button>
			</div>
		</form>

		{#if tableLoading}
			<Spinner />
			<p>loading...</p>
		{/if}

		{#if tableError}
			<p>{tableError}</p>
		{/if}

		{#if tableData}
			<Table hoverable={true}>
				<TableHead>
					{#each Object.keys(tableData[0]) as header}
						<TableHeadCell class="normal-case text-sm text-center">{header}</TableHeadCell>
					{/each}
				</TableHead>

				<TableBody>
					{#each tableData as el}
						<TableBodyRow>
							{#each Object.keys(el) as keys}
								<TableBodyCell class="font-normal text-center"
									>{el[keys] === null || el[keys] === 0 ? '-' : el[keys]}</TableBodyCell
								>
							{/each}
							<TableBodyCell class="font-normal text-center">
								<button
									class="font-medium text-primary-600 hover:underline dark:text-primary-500 cursor-pointer"
									on:click={editFormValue.bind(null, el)}
								>
									Edit
								</button></TableBodyCell
							>
						</TableBodyRow>
					{/each}
				</TableBody>
			</Table>
		{/if}
	</div>

	<div class="flex gap-3 mt-5">
		<Button
			size="xs"
			disabled={!hasPreviousPage}
			on:click={async () => {
				page--;
				tableError = null;
				reloadTable();
			}}
		>
			<ArrowLeftSolid size="sm" />
		</Button>
		<P size="base" class="self-center">{page}/{pageCount}</P>
		<Button
			size="xs"
			disabled={!hasNextPage}
			on:click={async () => {
				page++;
				tableError = null;
				reloadTable();
			}}
		>
			<ArrowRightSolid size="sm" />
		</Button>
	</div>
</div>