update timesheet format
This commit is contained in:
@@ -3,6 +3,9 @@
|
|||||||
import StarRating from '$lib/StarRating.svelte';
|
import StarRating from '$lib/StarRating.svelte';
|
||||||
import villaBugisImage from '$lib/images/villa-bugis.png';
|
import villaBugisImage from '$lib/images/villa-bugis.png';
|
||||||
|
|
||||||
|
|
||||||
|
const WEBHOOK_URL = 'https://flow.catalis.app/webhook/vb_feedback_new';
|
||||||
|
|
||||||
let villa_name = '';
|
let villa_name = '';
|
||||||
let customer_name = '';
|
let customer_name = '';
|
||||||
let checkin_date = '';
|
let checkin_date = '';
|
||||||
@@ -40,25 +43,50 @@
|
|||||||
const { data, error } = await supabase
|
const { data, error } = await supabase
|
||||||
.from('vb_feedback')
|
.from('vb_feedback')
|
||||||
.insert([{
|
.insert([{
|
||||||
villa_name,
|
villa_name,
|
||||||
customer_name,
|
customer_name,
|
||||||
checkin_date,
|
checkin_date,
|
||||||
checkout_date,
|
checkout_date,
|
||||||
feedback,
|
feedback,
|
||||||
book_process,
|
book_process,
|
||||||
airport_greet,
|
airport_greet,
|
||||||
arrival_greet,
|
arrival_greet,
|
||||||
bf_service,
|
bf_service,
|
||||||
overal_star,
|
overal_star,
|
||||||
extend_disc,
|
extend_disc,
|
||||||
nextstay_disc,
|
nextstay_disc,
|
||||||
become_sponsor
|
become_sponsor
|
||||||
}]);
|
}]);
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
console.error('Error submitting feedback:', error.message);
|
console.error('Error submitting feedback:', error.message);
|
||||||
errorMessage = 'Failed to submit feedback. Please try again.';
|
errorMessage = 'Failed to submit feedback. Please try again.';
|
||||||
} else {
|
} else {
|
||||||
|
// ✅ Send webhook
|
||||||
|
try {
|
||||||
|
await fetch(WEBHOOK_URL, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({
|
||||||
|
villa_name,
|
||||||
|
customer_name,
|
||||||
|
checkin_date,
|
||||||
|
checkout_date,
|
||||||
|
feedback,
|
||||||
|
book_process,
|
||||||
|
airport_greet,
|
||||||
|
arrival_greet,
|
||||||
|
bf_service,
|
||||||
|
overal_star,
|
||||||
|
extend_disc,
|
||||||
|
nextstay_disc,
|
||||||
|
become_sponsor
|
||||||
|
})
|
||||||
|
});
|
||||||
|
} catch (webhookError) {
|
||||||
|
console.error('Webhook failed:', webhookError);
|
||||||
|
}
|
||||||
|
|
||||||
// Reset form
|
// Reset form
|
||||||
villa_name = '';
|
villa_name = '';
|
||||||
customer_name = '';
|
customer_name = '';
|
||||||
@@ -73,8 +101,9 @@
|
|||||||
extend_disc = false;
|
extend_disc = false;
|
||||||
nextstay_disc = false;
|
nextstay_disc = false;
|
||||||
become_sponsor = false;
|
become_sponsor = false;
|
||||||
|
|
||||||
alert("Feedback submitted successfully!");
|
alert("Feedback submitted successfully!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -1,374 +1,188 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
// This is a placeholder for any script you might want to add
|
import { onMount } from 'svelte';
|
||||||
// For example, you could handle form submission here
|
import { supabase } from '$lib/supabaseClient';
|
||||||
import { onMount } from "svelte";
|
|
||||||
import { supabase } from "$lib/supabaseClient";
|
|
||||||
import { writable } from "svelte/store";
|
|
||||||
|
|
||||||
type TimesheetsInsert = {
|
type TimesheetForm = {
|
||||||
name: string;
|
entered_by: string;
|
||||||
staff_id: string;
|
work_description: string;
|
||||||
date_in: Date;
|
type_of_work: 'Running' | 'Periodic' | 'Irregular';
|
||||||
date_out: Date;
|
category_of_work:
|
||||||
type_of_work: string;
|
| 'Cleaning'
|
||||||
category_of_work: string;
|
| 'Gardening/Pool'
|
||||||
approval: string;
|
| 'Maintenance'
|
||||||
villa_id: string;
|
| 'Supervision'
|
||||||
approved_by: string;
|
| 'Guest Service'
|
||||||
approved_date: Date;
|
| 'Administration'
|
||||||
total_hours_work: number;
|
| 'Non Billable';
|
||||||
remarks: string;
|
villa_id: string;
|
||||||
vacant: boolean;
|
datetime_in: string;
|
||||||
|
datetime_out: string;
|
||||||
|
total_work_hour: number;
|
||||||
|
remarks: string;
|
||||||
|
approval: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
type Timesheets = {
|
|
||||||
id: string;
|
|
||||||
name: string;
|
|
||||||
staff_id: string;
|
|
||||||
date_in: Date;
|
|
||||||
date_out: Date;
|
|
||||||
type_of_work: string;
|
|
||||||
category_of_work: string;
|
|
||||||
approval: string;
|
|
||||||
villa_id: string;
|
|
||||||
approved_by: string;
|
|
||||||
approved_date: Date;
|
|
||||||
total_hours_work: number;
|
|
||||||
remarks: string;
|
|
||||||
vacant: boolean;
|
|
||||||
created_at?: Date;
|
|
||||||
};
|
|
||||||
|
|
||||||
const categoryOfWork = [
|
|
||||||
{ label: "Cleaning", value: "Cleaning" },
|
|
||||||
{ label: "Gardening/Pool", value: "Gardening/Pool" },
|
|
||||||
{ label: "Maintenance", value: "Maintenance" },
|
|
||||||
{ label: "Security", value: "Security" },
|
|
||||||
{ label: "Other", value: "Other" },
|
|
||||||
];
|
|
||||||
|
|
||||||
const typeOfWork = [
|
|
||||||
{ label: "Running", value: "Running" },
|
|
||||||
{ label: "Periodic", value: "Periodic" },
|
|
||||||
{ label: "Irregular", value: "Irregular" },
|
|
||||||
];
|
|
||||||
|
|
||||||
const reportedBy = [
|
|
||||||
{ label: "Admin", value: "Admin" },
|
|
||||||
{ label: "Staff", value: "Staff" },
|
|
||||||
{ label: "Manager", value: "Manager" },
|
|
||||||
{ label: "Guest", value: "Guest" },
|
|
||||||
];
|
|
||||||
|
|
||||||
type Villa = {
|
type Villa = {
|
||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
let dataVilla: Villa[] = [];
|
let villas: Villa[] = [];
|
||||||
|
|
||||||
|
let form: TimesheetForm = {
|
||||||
|
entered_by: '',
|
||||||
|
work_description: '',
|
||||||
|
type_of_work: 'Running',
|
||||||
|
category_of_work: 'Cleaning',
|
||||||
|
villa_id: '',
|
||||||
|
datetime_in: '',
|
||||||
|
datetime_out: '',
|
||||||
|
total_work_hour: 0,
|
||||||
|
remarks: '',
|
||||||
|
approval: false
|
||||||
|
};
|
||||||
|
|
||||||
|
const typeOfWorkOptions: TimesheetForm['type_of_work'][] = ['Running', 'Periodic', 'Irregular'];
|
||||||
|
const categoryOptions: TimesheetForm['category_of_work'][] = [
|
||||||
|
'Cleaning',
|
||||||
|
'Gardening/Pool',
|
||||||
|
'Maintenance',
|
||||||
|
'Supervision',
|
||||||
|
'Guest Service',
|
||||||
|
'Administration',
|
||||||
|
'Non Billable'
|
||||||
|
];
|
||||||
|
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
const { data, error } = await supabase
|
const { data, error } = await supabase
|
||||||
.from("villas")
|
.from('vb_villas')
|
||||||
.select("id, name");
|
.select('id, villa_name, villa_status')
|
||||||
|
.eq('villa_status', 'Active');
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
console.error("Error fetching villas:", error);
|
console.error('Failed to fetch villas:', error.message);
|
||||||
} else if (data) {
|
} else {
|
||||||
dataVilla = data;
|
villas = data.map(v => ({
|
||||||
}
|
id: v.id,
|
||||||
|
name: v.villa_name
|
||||||
|
}));
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
async function handleSubmit(event: Event): Promise<void> {
|
function calculateTotalHours() {
|
||||||
event.preventDefault();
|
if (form.datetime_in && form.datetime_out) {
|
||||||
|
const start = new Date(form.datetime_in);
|
||||||
|
const end = new Date(form.datetime_out);
|
||||||
|
const diffInMs = end.getTime() - start.getTime();
|
||||||
|
|
||||||
const formData = new FormData(event.target as HTMLFormElement);
|
// Convert milliseconds to hours (with decimal), round to 2 decimal places
|
||||||
|
const hours = diffInMs / (1000 * 60 * 60);
|
||||||
|
form.total_work_hour = Math.max(Number(hours.toFixed(2)), 0);
|
||||||
|
} else {
|
||||||
|
form.total_work_hour = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Validate form data
|
|
||||||
if (!validateForm(formData)) {
|
|
||||||
console.error("Form validation failed");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const timesheets: TimesheetsInsert = {
|
async function submitForm() {
|
||||||
name: formData.get("name") as string,
|
calculateTotalHours();
|
||||||
staff_id: formData.get("staff_id") as string,
|
|
||||||
date_in: new Date(formData.get("date_in") as string),
|
const { error } = await supabase.from('timesheet').insert([form]);
|
||||||
date_out: new Date(formData.get("date_out") as string),
|
|
||||||
type_of_work: formData.get("type_of_work") as string,
|
if (error) {
|
||||||
category_of_work: formData.get("category_of_work") as string,
|
alert('Failed to submit timesheet: ' + error.message);
|
||||||
approval: formData.get("approval") as string,
|
} else {
|
||||||
villa_id: formData.get("villa_id") as string,
|
alert('Timesheet submitted successfully!');
|
||||||
approved_by: formData.get("approved_by") as string,
|
form = {
|
||||||
approved_date: new Date(formData.get("approved_date") as string),
|
entered_by: '',
|
||||||
// total_hours_work can be calculated based on date_in and date_out
|
work_description: '',
|
||||||
total_hours_work:
|
type_of_work: 'Running',
|
||||||
Math.abs(
|
category_of_work: 'Cleaning',
|
||||||
new Date(formData.get("date_in") as string).getTime() -
|
villa_id: '',
|
||||||
new Date(formData.get("date_out") as string).getTime(),
|
datetime_in: '',
|
||||||
) /
|
datetime_out: '',
|
||||||
(1000 * 60 * 60), // Convert milliseconds to hours
|
total_work_hour: 0,
|
||||||
remarks: formData.get("remarks") as string,
|
remarks: '',
|
||||||
vacant: formData.get("vacant") === "false" ? false : true,
|
approval: false
|
||||||
};
|
};
|
||||||
|
}
|
||||||
const { data, error } = await supabase
|
|
||||||
.from("timesheets")
|
|
||||||
.insert([timesheets]);
|
|
||||||
|
|
||||||
if (error) {
|
|
||||||
console.error("Error submitting timesheets:", error);
|
|
||||||
} else {
|
|
||||||
console.log("Timesheets submitted successfully:", data);
|
|
||||||
alert("Timesheets submitted successfully!");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
export let formErrors = writable<{ [key: string]: string }>({});
|
|
||||||
|
<form on:submit|preventDefault={submitForm} class="space-y-4 max-w-md mx-auto p-4">
|
||||||
<h2 class="text-xl font-bold mb-4">Timesheet Entry</h2>
|
<h2 class="text-xl font-bold mb-4">Timesheet Entry</h2>
|
||||||
function validateForm(formData: FormData): boolean {
|
|
||||||
const errors: { [key: string]: string } = {};
|
<input
|
||||||
const requiredFields = [
|
class="w-full border p-2 rounded"
|
||||||
"name",
|
bind:value={form.entered_by}
|
||||||
"type_of_work",
|
placeholder="Entered by"
|
||||||
"villa_id",
|
required
|
||||||
"date_out",
|
|
||||||
"reported_by",
|
|
||||||
"category_of_work",
|
|
||||||
"date_in",
|
|
||||||
];
|
|
||||||
/>
|
/>
|
||||||
requiredFields.forEach((field) => {
|
|
||||||
if (!formData.get(field) || formData.get(field) === "") {
|
<textarea
|
||||||
errors[field] = `${field.replace(/_/g, " ")} is required.`;
|
class="w-full border p-2 rounded"
|
||||||
}
|
bind:value={form.work_description}
|
||||||
});
|
placeholder="Work Description"
|
||||||
|
required
|
||||||
></textarea>
|
></textarea>
|
||||||
formErrors.set(errors);
|
|
||||||
return Object.keys(errors).length === 0;
|
<select class="w-full border p-2 rounded" bind:value={form.type_of_work}>
|
||||||
}
|
{#each typeOfWorkOptions as option}
|
||||||
|
<option value={option}>{option}</option>
|
||||||
|
{/each}
|
||||||
</select>
|
</select>
|
||||||
function errorClass(field: string): string {
|
|
||||||
return $formErrors[field] ? "border-red-500" : "border";
|
<select class="w-full border p-2 rounded" bind:value={form.category_of_work}>
|
||||||
}
|
{#each categoryOptions as option}
|
||||||
</script>
|
<option value={option}>{option}</option>
|
||||||
|
{/each}
|
||||||
</select>
|
</select>
|
||||||
<div>
|
|
||||||
<form
|
<select class="w-full border p-2 rounded" bind:value={form.villa_id} required>
|
||||||
class="max-w-6xl mx-auto bg-white p-8 rounded-2xl shadow-xl space-y-8 text-gray-800"
|
<option disabled value="">Select Villa</option>
|
||||||
on:submit|preventDefault={handleSubmit}
|
{#each villas as villa}
|
||||||
|
<option value={villa.id}>{villa.name}</option>
|
||||||
|
{/each}
|
||||||
|
</select>
|
||||||
|
|
||||||
|
|
||||||
|
<label class="block">
|
||||||
|
<span class="text-sm">Date/Time In:</span>
|
||||||
|
<input
|
||||||
|
type="datetime-local"
|
||||||
|
class="w-full border p-2 rounded"
|
||||||
|
bind:value={form.datetime_in}
|
||||||
|
on:change={calculateTotalHours}
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label class="block">
|
||||||
|
<span class="text-sm">Date/Time Out:</span>
|
||||||
|
<input
|
||||||
|
type="datetime-local"
|
||||||
|
class="w-full border p-2 rounded"
|
||||||
|
bind:value={form.datetime_out}
|
||||||
|
on:change={calculateTotalHours}
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<div class="text-sm">
|
||||||
|
Total Work Hours: <strong>{form.total_work_hour}</strong>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<textarea
|
||||||
|
class="w-full border p-2 rounded"
|
||||||
|
bind:value={form.remarks}
|
||||||
|
placeholder="Remarks"
|
||||||
|
></textarea>
|
||||||
|
|
||||||
|
<button
|
||||||
|
type="submit"
|
||||||
class="bg-blue-600 text-white px-4 py-2 rounded hover:bg-blue-700"
|
class="bg-blue-600 text-white px-4 py-2 rounded hover:bg-blue-700"
|
||||||
<!-- logo -->
|
>
|
||||||
<div class="text-center mb-6">
|
Submit Timesheet
|
||||||
<img
|
</button>
|
||||||
src="/src/lib/images/logo.webp"
|
|
||||||
alt="Logo"
|
|
||||||
class="mx-auto"
|
|
||||||
loading="lazy"
|
|
||||||
width="250"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<!-- Title -->
|
|
||||||
<h2 class="text-2xl font-semibold text-center">Timesheet Form</h2>
|
|
||||||
</form>
|
</form>
|
||||||
<!-- 2 Column Grid -->
|
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-8">
|
|
||||||
<!-- Left Column -->
|
|
||||||
<div class="space-y-5">
|
|
||||||
<div>
|
|
||||||
<label class="block text-sm font-medium mb-1"
|
|
||||||
>Work Description<span class="text-red-500">*</span><br
|
|
||||||
/>
|
|
||||||
<span class="text-xs text-gray-500"
|
|
||||||
>Enter detail of work</span
|
|
||||||
>
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
name="name"
|
|
||||||
type="text"
|
|
||||||
placeholder="Tell detail of work"
|
|
||||||
class="w-full border rounded-xl px-4 py-2 focus:outline-none focus:ring-2 focus:ring-purple-400 {errorClass(
|
|
||||||
'name',
|
|
||||||
)}"
|
|
||||||
/>
|
|
||||||
{#if $formErrors.name}
|
|
||||||
<p class="text-sm text-red-500 mt-1">
|
|
||||||
{$formErrors.name}
|
|
||||||
</p>
|
|
||||||
{/if}
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label class="block text-sm font-medium mb-1"
|
|
||||||
>Type of Work<span class="text-red-500">*</span></label
|
|
||||||
>
|
|
||||||
<select
|
|
||||||
name="type_of_work"
|
|
||||||
class={`w-full border rounded-xl px-4 py-2 focus:outline-none focus:ring-2 focus:ring-purple-400 text-gray-600 ${errorClass("type_of_work")}`}
|
|
||||||
>
|
|
||||||
<option value="" disabled selected
|
|
||||||
>Select option...</option
|
|
||||||
>
|
|
||||||
{#each typeOfWork as source}
|
|
||||||
<option value={source.value}>{source.label}</option>
|
|
||||||
{/each}
|
|
||||||
</select>
|
|
||||||
{#if $formErrors.type_of_work}
|
|
||||||
<p class="text-sm text-red-500 mt-1">
|
|
||||||
{$formErrors.type_of_work}
|
|
||||||
</p>
|
|
||||||
{/if}
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label class="block text-sm font-medium mb-1"
|
|
||||||
>Villa Name<span class="text-red-500">*</span></label
|
|
||||||
>
|
|
||||||
<select
|
|
||||||
name="villa_id"
|
|
||||||
class="w-full border rounded-xl px-4 py-2 focus:outline-none focus:ring-2 focus:ring-purple-400 text-gray-600 {errorClass(
|
|
||||||
'villa_name',
|
|
||||||
)}"
|
|
||||||
>
|
|
||||||
<option value="" disabled selected
|
|
||||||
>Select option...</option
|
|
||||||
>
|
|
||||||
{#each dataVilla as villa}
|
|
||||||
<option value={villa.id}>{villa.name}</option>
|
|
||||||
{/each}
|
|
||||||
</select>
|
|
||||||
{#if $formErrors.villa_id}
|
|
||||||
<p class="text-sm text-red-500 mt-1">
|
|
||||||
{$formErrors.villa_id}
|
|
||||||
</p>
|
|
||||||
{/if}
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label class="block text-sm font-medium mb-1"
|
|
||||||
>Date / Time Out<span class="text-red-500">*</span
|
|
||||||
></label
|
|
||||||
>
|
|
||||||
<!-- date and time -->
|
|
||||||
<input
|
|
||||||
name="date_out"
|
|
||||||
type="datetime-local"
|
|
||||||
class="w-full border rounded-xl px-4 py-2 focus:outline-none focus:ring-2 focus:ring-purple-400 {errorClass(
|
|
||||||
'Date / Time Out',
|
|
||||||
)}"
|
|
||||||
/>
|
|
||||||
{#if $formErrors.date_out}
|
|
||||||
<p class="text-sm text-red-500 mt-1">
|
|
||||||
{$formErrors.date_out}
|
|
||||||
</p>
|
|
||||||
{/if}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Right Column -->
|
|
||||||
<div class="space-y-5">
|
|
||||||
<div>
|
|
||||||
<label class="block text-sm font-medium mb-1"
|
|
||||||
>Reported By<span class="text-red-500">*</span>
|
|
||||||
<br />
|
|
||||||
<span class="text-xs text-gray-500"
|
|
||||||
>Who reported this issue?</span
|
|
||||||
>
|
|
||||||
</label>
|
|
||||||
<select
|
|
||||||
name="reported_by"
|
|
||||||
class="w-full border rounded-xl px-4 py-2 focus:outline-none focus:ring-2 text-gray-600 {errorClass(
|
|
||||||
'reported_by',
|
|
||||||
)}"
|
|
||||||
>
|
|
||||||
<option value="" disabled selected
|
|
||||||
>Select option...</option
|
|
||||||
>
|
|
||||||
{#each reportedBy as reporter}
|
|
||||||
<option value={reporter.value}>
|
|
||||||
{reporter.label}
|
|
||||||
</option>
|
|
||||||
{/each}
|
|
||||||
</select>
|
|
||||||
{#if $formErrors.reported_by}
|
|
||||||
<p class="text-sm text-red-500 mt-1">
|
|
||||||
{$formErrors.reported_by}
|
|
||||||
</p>
|
|
||||||
{/if}
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label class="block text-sm font-medium mb-1"
|
|
||||||
>Category of Work<span class="text-red-500">*</span
|
|
||||||
></label
|
|
||||||
>
|
|
||||||
<select
|
|
||||||
name="category_of_work"
|
|
||||||
class="w-full border rounded-xl px-4 py-2 focus:outline-none focus:ring-2 focus:ring-purple-400 text-gray-600 {errorClass(
|
|
||||||
'Category of Work',
|
|
||||||
)}"
|
|
||||||
>
|
|
||||||
<option value="" disabled selected
|
|
||||||
>Select option...</option
|
|
||||||
>
|
|
||||||
{#each categoryOfWork as p}
|
|
||||||
<option value={p.value}>{p.label}</option>
|
|
||||||
{/each}
|
|
||||||
</select>
|
|
||||||
{#if $formErrors.category_of_work}
|
|
||||||
<p class="text-sm text-red-500 mt-1">
|
|
||||||
{$formErrors.category_of_work}
|
|
||||||
</p>
|
|
||||||
{/if}
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label class="block text-sm font-medium mb-1"
|
|
||||||
>Date / Time In<span class="text-red-500">*</span
|
|
||||||
></label
|
|
||||||
>
|
|
||||||
<input
|
|
||||||
name="date_in"
|
|
||||||
type="datetime-local"
|
|
||||||
class="w-full border rounded-xl px-4 py-2 focus:outline-none focus:ring-2 focus:ring-purple-400 {errorClass(
|
|
||||||
'Date / Time In',
|
|
||||||
)}"
|
|
||||||
/>
|
|
||||||
{#if $formErrors.date_in}
|
|
||||||
<p class="text-sm text-red-500 mt-1">
|
|
||||||
{$formErrors.date_in}
|
|
||||||
</p>
|
|
||||||
{/if}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Full Width Fields -->
|
|
||||||
<div class="space-y-6">
|
|
||||||
<div>
|
|
||||||
<label class="block text-sm font-medium mb-1">Remarks</label>
|
|
||||||
<textarea
|
|
||||||
name="remarks"
|
|
||||||
rows="3"
|
|
||||||
placeholder="How you resolve? e.g. 'copy to project'"
|
|
||||||
class="w-full border rounded-xl px-4 py-2 focus:outline-none focus:ring-2 focus:ring-purple-400"
|
|
||||||
></textarea>
|
|
||||||
</div>
|
|
||||||
<div class="flex items-center space-x-2">
|
|
||||||
<input
|
|
||||||
name="vacant"
|
|
||||||
value="false"
|
|
||||||
type="checkbox"
|
|
||||||
id="guest_agreed"
|
|
||||||
class="h-4 w-4 rounded border-gray-300"
|
|
||||||
/>
|
|
||||||
<label for="guest_agreed" class="text-sm">Vacant</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Submit Button -->
|
|
||||||
<div class="text-center pt-4">
|
|
||||||
<button
|
|
||||||
type="submit"
|
|
||||||
class="bg-purple-600 text-white px-8 py-3 rounded-xl hover:bg-purple-700 transition-all font-medium shadow-md"
|
|
||||||
>
|
|
||||||
Submit
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
|
|||||||
Reference in New Issue
Block a user