correct issue data

This commit is contained in:
2025-06-22 23:36:20 +08:00
parent db85b92274
commit bc6839ca07
2 changed files with 430 additions and 390 deletions

View File

@@ -10,48 +10,78 @@
{ label: "Critical", value: "Critical" }, { label: "Critical", value: "Critical" },
]; ];
const issueSource = [ const issueSource = [
{ label: "Email", value: "Email" }, { label: "Guest Assistant", value: "Guest Assistant" },
{ label: "Phone Call", value: "Phone Call" }, { label: "Villa Attendant", value: "Villa Attendant" },
{ label: "In-Person", value: "In-Person" }, { label: "Villa Supervisor", value: "Villa Supervisor" },
{ label: "Online Form", value: "Online Form" }, { label: "Villa Manager", value: "Villa Manager" },
{ label: "Other", value: "Other" }, { label: "Operation Manager", value: "Operation Manager" },
{ label: "Quality Control Manager", value: "Quality Control Manager" },
{ label: "Owner", value: "Owner" },
{ label: "Sales/Reservations", value: "Sales/Reservations" },
{ label: "Guest", value: "Guest" },
{ label: "Agent", value: "Agent" },
]; ];
const issueTypes = [ const issueTypes = [
{ label: "Facilities - Light", value: "Facilities - Light" }, { label: "Facilities - Air Conditioner", value: "Facilities - Air Conditioner" },
{ label: "Facilities - Appliances", value: "Facilities - Appliances" },
{ label: "Facilities - Baby Cot", value: "Facilities - Baby Cot" },
{ label: "Facilities - Bath", value: "Facilities - Bath" },
{ label: "Facilities - Bed", value: "Facilities - Bed" },
{ label: "Facilities - Blender", value: "Facilities - Blender" },
{ label: "Facilities - Cabinet", value: "Facilities - Cabinet" },
{ label: "Facilities - Cable TV", value: "Facilities - Cable TV" },
{ label: "Facilities - CCTV", value: "Facilities - CCTV" },
{ label: "Facilities - Ceiling Fans", value: "Facilities - Ceiling Fans" },
{ label: "Facilities - Coffee Maker", value: "Facilities - Coffee Maker" },
{ label: "Facilities - DVD", value: "Facilities - DVD" },
{ label: "Facilities - Generator", value: "Facilities - Generator" },
{ label: "Facilities - Hairdryer", value: "Facilities - Hairdryer" },
{ label: "Facilities - Home Theatre", value: "Facilities - Home Theatre" },
{ label: "Facilities - Hot Water", value: "Facilities - Hot Water" },
{ label: "Facilities - Internet Connection", value: "Facilities - Internet Connection" },
{ label: "Facilities - Iron/Ironing Board", value: "Facilities - Iron/Ironing Board" },
{ label: "Facilities - Kitchen Equipment", value: "Facilities - Kitchen Equipment" },
{ label: "Facilities - Lights", value: "Facilities - Lights" },
{ label: "Facilities - Linen", value: "Facilities - Linen" }, { label: "Facilities - Linen", value: "Facilities - Linen" },
{ label: "Facilities - Mattress", value: "Facilities - Mattress" },
{ label: "Facilities - Mirror", value: "Facilities - Mirror" },
{ label: "Facilities - Mosquito Net", value: "Facilities - Mosquito Net" },
{ label: "Facilities - Other", value: "Facilities - Other" }, { label: "Facilities - Other", value: "Facilities - Other" },
{ label: "Facilities - Towel", value: "Facilities - Towel" }, { label: "Facilities - Parking", value: "Facilities - Parking" },
{ label: "Facilities - Fan", value: "Facilities - Fan" }, { label: "Facilities - Pool Umbrella", value: "Facilities - Pool Umbrella" },
{ label: "Cleanliness - Other", value: "Cleanliness - Other" }, { label: "Facilities - Safe Deposit Box", value: "Facilities - Safe Deposit Box" },
{ label: "Cleanliness - Floor", value: "Cleanliness - Floor" }, { label: "Facilities - Security", value: "Facilities - Security" },
{ label: "Cleanliness - Kitchen", value: "Cleanliness - Kitchen" }, { label: "Facilities - Shower", value: "Facilities - Shower" },
{ label: "Cleanliness - Bathroom", value: "Cleanliness - Bathroom" }, { label: "Facilities - Sink", value: "Facilities - Sink" },
{ { label: "Facilities - Sunbed and Mattress", value: "Facilities - Sunbed and Mattress" },
label: "Maintenance - Electrical", { label: "Facilities - Swimming Pool", value: "Facilities - Swimming Pool" },
value: "Maintenance - Electrical", { label: "Facilities - Telephone", value: "Facilities - Telephone" },
}, { label: "Facilities - Toaster", value: "Facilities - Toaster" },
{ label: "Facilities - Toilet Bowl", value: "Facilities - Toilet Bowl" },
{ label: "Facilities - Toiletries", value: "Facilities - Toiletries" },
{ label: "Facilities - Towels", value: "Facilities - Towels" },
{ label: "Facilities - TV Unit", value: "Facilities - TV Unit" },
{ label: "Facilities - Wardrobe", value: "Facilities - Wardrobe" },
{ label: "Facilities - Wash Basin", value: "Facilities - Wash Basin" },
{ label: "Facilities - Water Dispenser", value: "Facilities - Water Dispenser" },
{ label: "Maintenance - Civil", value: "Maintenance - Civil" },
{ label: "Maintenance - Electrical", value: "Maintenance - Electrical" },
{ label: "Maintenance - Mechanical", value: "Maintenance - Mechanical" },
{ label: "Maintenance - Painting", value: "Maintenance - Painting" },
{ label: "Maintenance - Plumbing", value: "Maintenance - Plumbing" }, { label: "Maintenance - Plumbing", value: "Maintenance - Plumbing" },
{ label: "Maintenance - HVAC", value: "Maintenance - HVAC" }, { label: "Maintenance - Roof", value: "Maintenance - Roof" },
{ { label: "Other - Accident", value: "Other - Accident" },
label: "Maintenance - Structural", { label: "Other - Animals", value: "Other - Animals" },
value: "Maintenance - Structural", { label: "Other - Booking", value: "Other - Booking" },
}, { label: "Other - Cleanliness", value: "Other - Cleanliness" },
{ label: "Safety Issue", value: "Safety Issue" }, { label: "Other - Crime", value: "Other - Crime" },
{ label: "Security Concern", value: "Security Concern" }, { label: "Other - Food and Beverage", value: "Other - Food and Beverage" },
{ label: "Other", value: "Other" }, { label: "Other - Garden", value: "Other - Garden" },
{ label: "General Inquiry", value: "General Inquiry" }, { label: "Other - Inventory", value: "Other - Inventory" },
{ label: "Feedback", value: "Feedback" }, { label: "Other - Noise", value: "Other - Noise" },
{ label: "Complaint", value: "Complaint" }, { label: "Other - Payment", value: "Other - Payment" },
{ label: "Request", value: "Request" }, { label: "Other - Transport", value: "Other - Transport" },
{ label: "Suggestion", value: "Suggestion" },
{ label: "Booking Issue", value: "Booking Issue" },
{ label: "Payment Issue", value: "Payment Issue" },
{ label: "Cancellation Request", value: "Cancellation Request" },
{ label: "Refund Request", value: "Refund Request" },
{ label: "Reservation Change", value: "Reservation Change" },
{ label: "Check-in Issue", value: "Check-in Issue" },
{ label: "Check-out Issue", value: "Check-out Issue" },
]; ];
const areaOfVilla = [ const areaOfVilla = [
@@ -61,51 +91,52 @@
{ label: "All Villa Areas", value: "All Villa Areas" }, { label: "All Villa Areas", value: "All Villa Areas" },
{ label: "Balcony", value: "Balcony" }, { label: "Balcony", value: "Balcony" },
{ label: "Bathroom (Guest)", value: "Bathroom (Guest)" }, { label: "Bathroom (Guest)", value: "Bathroom (Guest)" },
{ label: "Bathroom Guest House 1", value: "Bathroom Guest House 1" },
{ label: "Bathroom Guest House 2", value: "Bathroom Guest House 2" },
{ label: "Bathroom Guest House 3", value: "Bathroom Guest House 3" },
{ label: "Bathroom (Master)", value: "Bathroom (Master)" }, { label: "Bathroom (Master)", value: "Bathroom (Master)" },
{ label: "Bathroom 1", value: "Bathroom 1" }, { label: "Bathroom 1", value: "Bathroom 1" },
{ label: "Bathroom 2", value: "Bathroom 2" }, { label: "Bathroom 2", value: "Bathroom 2" },
{ label: "Bathroom 3", value: "Bathroom 3" }, { label: "Bathroom 3", value: "Bathroom 3" },
{ label: "Bedroom (Guest)", value: "Bedroom (Guest)" }, { label: "Bathroom 4", value: "Bathroom 4" },
{ label: "Bathroom 5", value: "Bathroom 5" },
{ label: "BBQ Area", value: "BBQ Area" },
{ label: "Bedroom (Master)", value: "Bedroom (Master)" }, { label: "Bedroom (Master)", value: "Bedroom (Master)" },
{ label: "Bedroom 1", value: "Bedroom 1" }, { label: "Bedroom 1", value: "Bedroom 1" },
{ label: "Bedroom 2", value: "Bedroom 2" }, { label: "Bedroom 2", value: "Bedroom 2" },
{ label: "Bedroom 3", value: "Bedroom 3" }, { label: "Bedroom 3", value: "Bedroom 3" },
{ label: "Ceiling", value: "Ceiling" }, { label: "Bedroom 4", value: "Bedroom 4" },
{ label: "Dining Area", value: "Dining Area" }, { label: "Bedroom 5", value: "Bedroom 5" },
{ label: "Door", value: "Door" }, { label: "Boundary Wall", value: "Boundary Wall" },
{ label: "Entrance", value: "Entrance" }, { label: "Carport", value: "Carport" },
{ label: "Dining Room", value: "Dining Room" },
{ label: "Flat Roof", value: "Flat Roof" },
{ label: "Garden", value: "Garden" }, { label: "Garden", value: "Garden" },
{ label: "General", value: "General" }, { label: "Gate", value: "Gate" },
{ label: "Glass", value: "Glass" }, { label: "Gazebo", value: "Gazebo" },
{ label: "Hallway", value: "Hallway" }, { label: "Generator Room", value: "Generator Room" },
{ label: "Guest House 1", value: "Guest House 1" },
{ label: "Guest House 2", value: "Guest House 2" },
{ label: "Guest House 3", value: "Guest House 3" },
{ label: "Guest House 4", value: "Guest House 4" },
{ label: "Kids Room", value: "Kids Room" },
{ label: "Kitchen", value: "Kitchen" }, { label: "Kitchen", value: "Kitchen" },
{ label: "Laundry Area", value: "Laundry Area" }, { label: "Landscape", value: "Landscape" },
{ label: "Living Room", value: "Living Room" }, { label: "Living Room", value: "Living Room" },
{ label: "Outdoor Area", value: "Outdoor Area" }, { label: "Other", value: "Other" },
{ label: "Parking Area", value: "Parking Area" }, { label: "Outdoor Bar", value: "Outdoor Bar" },
{ label: "Pool Area", value: "Pool Area" }, { label: "Outdoor Kitchen", value: "Outdoor Kitchen" },
{ label: "Roof", value: "Roof" }, { label: "Outdoor Shower", value: "Outdoor Shower" },
{ label: "Stairs", value: "Stairs" }, { label: "Outside The Villa", value: "Outside The Villa" },
{ label: "Pool", value: "Pool" },
{ label: "Pump Room", value: "Pump Room" },
{ label: "Staff Room", value: "Staff Room" },
{ label: "Stairs (other)", value: "Stairs (other)" },
{ label: "Stairs (living room)", value: "Stairs (living room)" },
{ label: "Storage", value: "Storage" }, { label: "Storage", value: "Storage" },
{ label: "Terrace", value: "Terrace" }, { label: "Transport", value: "Transport" },
{ label: "Toilet", value: "Toilet" }, { label: "TV Room", value: "TV Room" },
{ label: "Wall", value: "Wall" }, { label: "Water Feature", value: "Water Feature" }
{ label: "Window", value: "Window" },
{ label: "Others", value: "Others" },
];
const inputBy = [
{ label: "Admin", value: "Admin" },
{ label: "Staff", value: "Staff" },
{ label: "Manager", value: "Manager" },
{ label: "Guest", value: "Guest" },
];
const reportedBy = [
{ label: "Admin", value: "Admin" },
{ label: "Staff", value: "Staff" },
{ label: "Manager", value: "Manager" },
{ label: "Guest", value: "Guest" },
]; ];
type Villa = { type Villa = {
@@ -115,7 +146,7 @@
type User = { type User = {
id: string; id: string;
full_name: string; employee_name: string;
}; };
let dataVilla: Villa[] = []; let dataVilla: Villa[] = [];
@@ -124,7 +155,8 @@
onMount(async () => { onMount(async () => {
const { data, error } = await supabase const { data, error } = await supabase
.from("vb_villas") .from("vb_villas")
.select("id, villa_name"); .select("id, villa_name, villa_status")
.eq("villa_status", "Active");
if (error) { if (error) {
console.error("Error fetching villas:", error); console.error("Error fetching villas:", error);
@@ -133,8 +165,9 @@
} }
const { data: userData, error: userError } = await supabase const { data: userData, error: userError } = await supabase
.from("vb_users") .from("vb_employee")
.select("id, full_name"); .select("id, employee_name, employee_status")
.eq("employee_status", "Active");
if (userError) { if (userError) {
console.error("Error fetching users:", userError); console.error("Error fetching users:", userError);
} else if (userData) { } else if (userData) {
@@ -144,7 +177,6 @@
type Issue = { type Issue = {
id: string; id: string;
name: string;
villa_id: string; villa_id: string;
villa_name: string; villa_name: string;
area_of_villa: string; area_of_villa: string;
@@ -160,8 +192,6 @@
input_by: string; input_by: string;
guest_communication: string; guest_communication: string;
resolution: string; resolution: string;
guest_has_aggreed_issue_has_been_resolved: boolean;
follow_up: boolean;
need_approval: boolean; need_approval: boolean;
created_at: string; created_at: string;
updated_by?: string; updated_by?: string;
@@ -169,7 +199,6 @@
}; };
type issueInsert = { type issueInsert = {
name: string;
villa_id: string; villa_id: string;
area_of_villa: string; area_of_villa: string;
priority: string; priority: string;
@@ -182,8 +211,6 @@
input_by: string; input_by: string;
guest_communication: string; guest_communication: string;
resolution: string; resolution: string;
guest_has_aggreed_issue_has_been_resolved: boolean;
follow_up: boolean;
need_approval: boolean; need_approval: boolean;
}; };
@@ -199,7 +226,8 @@
}; };
const columns: columns[] = [ const columns: columns[] = [
{ key: "name", title: "Name" }, { key: "description_of_the_issue", title: "Description of The Issue" },
{ key: "issue_number", title: "Issue Number" },
{ key: "villa_name", title: "Villa Name" }, { key: "villa_name", title: "Villa Name" },
{ key: "villa_id", title: "Villa ID" }, { key: "villa_id", title: "Villa ID" },
{ key: "input_by", title: "Input By" }, { key: "input_by", title: "Input By" },
@@ -208,20 +236,13 @@
{ key: "area_of_villa", title: "Area Of Villa" }, { key: "area_of_villa", title: "Area Of Villa" },
{ key: "priority", title: "Priority" }, { key: "priority", title: "Priority" },
{ key: "issue_type", title: "Issue Type" }, { key: "issue_type", title: "Issue Type" },
{ key: "issue_number", title: "Issue Number" },
{ key: "move_issue", title: "Move Issue" }, { key: "move_issue", title: "Move Issue" },
{ key: "description_of_the_issue", title: "Description of The Issue" },
{ key: "issue_related_image", title: "Issue Related Image" }, { key: "issue_related_image", title: "Issue Related Image" },
{ key: "issue_source", title: "Issue Source" }, { key: "issue_source", title: "Issue Source" },
{ key: "reported_name", title: "Reported By" }, { key: "reported_name", title: "Reported By" },
{ key: "inputed_name", title: "Input By" }, { key: "inputed_name", title: "Input By" },
{ key: "guest_communication", title: "Guest Communication" }, { key: "guest_communication", title: "Guest Communication" },
{ key: "resolution", title: "Resolution" }, { key: "resolution", title: "Resolved How?" },
{
key: "guest_has_aggreed_issue_has_been_resolved",
title: "Guest Has Aggred Issue Has Been Resolved",
},
{ key: "follow_up", title: "Follow Up" },
{ key: "need_approval", title: "Need Approval" }, { key: "need_approval", title: "Need Approval" },
{ key: "created_at", title: "Created At" }, { key: "created_at", title: "Created At" },
{ key: "updated_name", title: "Updated By" }, { key: "updated_name", title: "Updated By" },
@@ -248,7 +269,7 @@
} }
if (search) { if (search) {
query = query.ilike("name", `%${search}%`); query = query.ilike("description_of_the_issue", `%${search}%`);
} }
const { data: issues, error, count } = await query; const { data: issues, error, count } = await query;
@@ -327,7 +348,13 @@
showModal = true; showModal = true;
} }
async function saveIssue(event: Event) { async function saveIssue(event: Event) {
const session = await supabase.auth.getSession();
const userId = session.data.session?.user.id;
newIssue.updated_by = userId;
newIssue.updated_at = new Date().toISOString();
event.preventDefault(); event.preventDefault();
const formData = new FormData(event.target as HTMLFormElement); const formData = new FormData(event.target as HTMLFormElement);
@@ -394,7 +421,6 @@
} }
} else { } else {
const issueInsert: issueInsert = { const issueInsert: issueInsert = {
name: formData.get("name") as string,
villa_id: formData.get("villa_id") as string, villa_id: formData.get("villa_id") as string,
area_of_villa: formData.get("area_of_villa") as string, area_of_villa: formData.get("area_of_villa") as string,
priority: formData.get("priority") as string, priority: formData.get("priority") as string,
@@ -413,15 +439,8 @@
"guest_communication", "guest_communication",
) as string, ) as string,
resolution: formData.get("resolution") as string, resolution: formData.get("resolution") as string,
guest_has_aggreed_issue_has_been_resolved:
formData.get(
"guest_has_aggreed_issue_has_been_resolved",
) === "true"
? true
: false,
follow_up: formData.get("follow_up") === "true" ? true : false,
need_approval: need_approval:
formData.get("need_approval") === "true" ? true : false, formData.get("need_approval") === "false" ? true : false,
}; };
const { error } = await supabase const { error } = await supabase
@@ -476,7 +495,6 @@
function validateForm(formData: FormData): boolean { function validateForm(formData: FormData): boolean {
const errors: { [key: string]: string } = {}; const errors: { [key: string]: string } = {};
const requiredFields = [ const requiredFields = [
"name",
"description_of_the_issue", "description_of_the_issue",
"issue_source", "issue_source",
"villa_id", "villa_id",
@@ -633,7 +651,7 @@
<thead class="bg-gray-100"> <thead class="bg-gray-100">
<tr> <tr>
{#each formColumnsDisplay as col} {#each formColumnsDisplay as col}
{#if col.key === "name"} {#if col.key === "description_of_the_issue"}
<th <th
class="sticky left-0 px-4 py-3 text-left font-semibold text-gray-700 uppercase tracking-wider whitespace-nowrap" class="sticky left-0 px-4 py-3 text-left font-semibold text-gray-700 uppercase tracking-wider whitespace-nowrap"
style="background-color: #f0f8ff; z-index: 10;" style="background-color: #f0f8ff; z-index: 10;"
@@ -654,7 +672,7 @@
{#each allRows as row} {#each allRows as row}
<tr class="hover:bg-gray-50 transition"> <tr class="hover:bg-gray-50 transition">
{#each formColumnsDisplay as col} {#each formColumnsDisplay as col}
{#if col.key === "name"} {#if col.key === "description_of_the_issue"}
<td <td
class="sticky left-0 px-4 py-2 font-medium text-blue-600" class="sticky left-0 px-4 py-2 font-medium text-blue-600"
style="background-color: #f0f8ff; cursor: pointer;" style="background-color: #f0f8ff; cursor: pointer;"
@@ -853,280 +871,251 @@
{#each formColumns as col} {#each formColumns as col}
{#if col.key === "name"} {#if col.key === "name"}
<div class="space-y-1"> <div class="space-y-1">
<label class="block text-sm font-medium text-gray-700" <label class="block text-sm font-medium text-gray-700">
>Customer / Guest Name</label Customer / Guest Name
> <input
<input class="w-full border px-3 py-2 rounded {errorClass(
class="w-full border px-3 py-2 rounded {errorClass( 'name',
'name', )}"
)}" name="name"
name="name" type="text"
type="text" bind:value={newIssue[col.key as keyof Issue]}
bind:value={newIssue[col.key as keyof Issue]} placeholder={col.title}
placeholder={col.title} required
required />
/> {#if $formErrors.name}
{#if $formErrors.name} <p class="text-red-500 text-xs">
<p class="text-red-500 text-xs"> {$formErrors.name}
{$formErrors.name} </p>
</p> {/if}
{/if} </label>
</div>
{:else if col.key === "guest_has_aggreed_issue_has_been_resolved"}
<div class="space-y-1">
<label class="block text-sm font-medium text-gray-700"
>Guest Has Aggred Issue Has Been Resolved</label
>
<select
name="guest_has_aggreed_issue_has_been_resolved"
class="w-full border px-3 py-2 rounded"
bind:value={newIssue[col.key as keyof Issue]}
>
<option value="true">Yes</option>
<option value="false">No</option>
</select>
</div>
{:else if col.key === "follow_up"}
<div class="space-y-1">
<label class="block text-sm font-medium text-gray-700"
>Follow Up</label
>
<select
name="follow_up"
class="w-full border px-3 py-2 rounded"
bind:value={newIssue[col.key as keyof Issue]}
>
<option value="true">Yes</option>
<option value="false">No</option>
</select>
</div> </div>
{:else if col.key === "issue_related_image"} {:else if col.key === "issue_related_image"}
<div class="space-y-1"> <div class="space-y-1">
<label class="block text-sm font-medium text-gray-700"> <label class="block text-sm font-medium text-gray-700">
Issue Related Image Issue Related Image
</label> <input
<input name="issue_related_image"
name="issue_related_image" class="w-full border px-3 py-2 rounded"
class="w-full border px-3 py-2 rounded" type="file"
type="file" accept="image/*"
accept="image/*" on:change={handleFileChange}
on:change={handleFileChange}
/>
<p class="text-xs text-gray-500">
Upload an image related to the issue.
</p>
{#if imagePreviewUrl}
<img
src={imagePreviewUrl}
alt="Preview"
class="mt-2 max-h-48 rounded border"
/> />
{:else if newIssue.issue_related_image} <p class="text-xs text-gray-500">
{#await getPublicUrl(newIssue.issue_related_image) then url} Upload an image related to the issue.
</p>
{#if imagePreviewUrl}
<img <img
src={url} src={imagePreviewUrl}
alt="Preview" alt="Preview"
class="mt-2 max-h-48 rounded border" class="mt-2 max-h-48 rounded border"
/> />
{/await} {:else if newIssue.issue_related_image}
{/if} {#await getPublicUrl(newIssue.issue_related_image) then url}
<img
src={url}
alt="Preview"
class="mt-2 max-h-48 rounded border"
/>
{/await}
{/if}
</label>
</div> </div>
{:else if col.key === "reported_date"} {:else if col.key === "reported_date"}
<div class="space-y-1"> <div class="space-y-1">
<label class="block text-sm font-medium text-gray-700" <label class="block text-sm font-medium text-gray-700">
>Reported Date</label Reported Date
> <input
<input name="reported_date"
name="reported_date" class="w-full border px-3 py-2 rounded {errorClass(
class="w-full border px-3 py-2 rounded {errorClass( 'reported_date',
'reported_date', )}"
)}" type="date"
type="date" bind:value={newIssue[col.key as keyof Issue]}
bind:value={newIssue[col.key as keyof Issue]} />
/> {#if $formErrors.reported_date}
{#if $formErrors.reported_date} <p class="text-red-500 text-xs">
<p class="text-red-500 text-xs"> {$formErrors.reported_date}
{$formErrors.reported_date} </p>
</p> {/if}
{/if} </label>
</div> </div>
{:else if col.key === "need_approval"} {:else if col.key === "need_approval"}
<div class="space-y-1"> <div class="space-y-1">
<label class="block text-sm font-medium text-gray-700" <label class="block text-sm font-medium text-gray-700">
>Need Approval</label Need Approval
> <select
<select name="need_approval"
name="need_approval" class="w-full border px-3 py-2 rounded"
class="w-full border px-3 py-2 rounded" bind:value={newIssue[col.key as keyof Issue]}
bind:value={newIssue[col.key as keyof Issue]} >
> <option value="true">Yes</option>
<option value="true">Yes</option> <option value="false">No</option>
<option value="false">No</option> </select>
</select> </label>
</div> </div>
{:else if col.key === "issue_source"} {:else if col.key === "issue_source"}
<div class="space-y-1"> <div class="space-y-1">
<label class="block text-sm font-medium text-gray-700" <label class="block text-sm font-medium text-gray-700">
>Issue Source</label Issue Source
> <select
<select name="issue_source"
name="issue_source" class="w-full border px-3 py-2 rounded {errorClass(
class="w-full border px-3 py-2 rounded {errorClass( 'issue_source',
'issue_source', )}"
)}" bind:value={newIssue[col.key as keyof Issue]}
bind:value={newIssue[col.key as keyof Issue]}
>
<option value="" disabled selected
>Select Source</option
> >
{#each issueSource as source} <option value="" disabled selected
<option value={source.value} >Select Source</option
>{source.label}</option
> >
{/each} {#each issueSource as source}
</select> <option value={source.value}
{#if $formErrors.issue_source} >{source.label}</option
<p class="text-red-500 text-xs"> >
{$formErrors.issue_source} {/each}
</p> </select>
{/if} {#if $formErrors.issue_source}
<p class="text-red-500 text-xs">
{$formErrors.issue_source}
</p>
{/if}
</label>
</div> </div>
{:else if col.key === "reported_by"} {:else if col.key === "reported_by"}
<div class="space-y-1"> <div class="space-y-1">
<label class="block text-sm font-medium text-gray-700" <label class="block text-sm font-medium text-gray-700">
>Reported By</label Reported By
> <select
<select name="reported_by"
name="reported_by" class="w-full border px-3 py-2 rounded {errorClass(
class="w-full border px-3 py-2 rounded {errorClass( 'reported_by',
'reported_by', )}"
)}" bind:value={newIssue[col.key as keyof Issue]}
bind:value={newIssue[col.key as keyof Issue]}
>
<option value="" disabled selected
>Select Reporter</option
> >
{#each dataUser as reporter} <option value="" disabled selected >Select Reporter</option>
<option value={reporter.id} {#each dataUser as reporter}
>{reporter.full_name}</option <option value={reporter.id}>{reporter.employee_name}</option>
> {/each}
{/each} </select>
</select> {#if $formErrors.reported_by}
{#if $formErrors.reported_by} <p class="text-red-500 text-xs">
<p class="text-red-500 text-xs"> {$formErrors.reported_by}
{$formErrors.reported_by} </p>
</p> {/if}
{/if} </label>
</div> </div>
{:else if col.key === "input_by"} {:else if col.key === "input_by"}
<div class="space-y-1"> <div class="space-y-1">
<label class="block text-sm font-medium text-gray-700" <label class="block text-sm font-medium text-gray-700">
>Input By</label Input By
> <select
<select name="input_by"
name="input_by" class="w-full border px-3 py-2 rounded {errorClass(
class="w-full border px-3 py-2 rounded {errorClass( 'input_by',
'input_by', )}"
)}" bind:value={newIssue[col.key as keyof Issue]}
bind:value={newIssue[col.key as keyof Issue]}
>
<option value="" disabled selected
>Select Input By</option
> >
{#each dataUser as input} <option value="" disabled selected
<option value={input.id} >Select Input By</option
>{input.full_name}</option
> >
{/each} {#each dataUser as input}
</select> <option value={input.id}
{#if $formErrors.input_by} >{input.employee_name}</option
<p class="text-red-500 text-xs"> >
{$formErrors.input_by} {/each}
</p> </select>
{/if} {#if $formErrors.input_by}
<p class="text-red-500 text-xs">
{$formErrors.input_by}
</p>
{/if}
</label>
</div> </div>
{:else if col.key === "area_of_villa"} {:else if col.key === "area_of_villa"}
<div class="space-y-1"> <div class="space-y-1">
<label class="block text-sm font-medium text-gray-700" <label class="block text-sm font-medium text-gray-700">
>Area of Villa</label Area of Villa
> <select
<select name="area_of_villa"
name="area_of_villa" class="w-full border px-3 py-2 rounded {errorClass(
class="w-full border px-3 py-2 rounded {errorClass( 'area_of_villa',
'area_of_villa', )}"
)}" bind:value={newIssue[col.key as keyof Issue]}
bind:value={newIssue[col.key as keyof Issue]}
>
<option value="" disabled selected
>Select Area</option
> >
{#each areaOfVilla as area} <option value="" disabled selected
<option value={area.value}>{area.label}</option> >Select Area</option
{/each} >
</select> {#each areaOfVilla as area}
{#if $formErrors.area_of_villa} <option value={area.value}>{area.label}</option>
<p class="text-red-500 text-xs"> {/each}
{$formErrors.area_of_villa} </select>
</p> {#if $formErrors.area_of_villa}
{/if} <p class="text-red-500 text-xs">
{$formErrors.area_of_villa}
</p>
{/if}
</label>
</div> </div>
{:else if col.key === "issue_type"} {:else if col.key === "issue_type"}
<div class="space-y-1"> <div class="space-y-1">
<label class="block text-sm font-medium text-gray-700" <label class="block text-sm font-medium text-gray-700">
>Issue Type</label Issue Type
> <select
<select name="issue_type"
name="issue_type" class="w-full border px-3 py-2 rounded {errorClass(
class="w-full border px-3 py-2 rounded {errorClass( 'issue_type',
'issue_type', )}"
)}" bind:value={newIssue[col.key as keyof Issue]}
bind:value={newIssue[col.key as keyof Issue]}
>
<option value="" disabled selected
>Select Issue Type</option
> >
{#each issueTypes as type} <option value="" disabled selected
<option value={type.value}>{type.label}</option> >Select Issue Type</option
{/each} >
</select> {#each issueTypes as type}
{#if $formErrors.issue_type} <option value={type.value}>{type.label}</option>
<p class="text-red-500 text-xs"> {/each}
{$formErrors.issue_type} </select>
</p> {#if $formErrors.issue_type}
{/if} <p class="text-red-500 text-xs">
{$formErrors.issue_type}
</p>
{/if}
</label>
</div> </div>
{:else if col.key === "priority"} {:else if col.key === "priority"}
<div class="space-y-1"> <div class="space-y-1">
<label class="block text-sm font-medium text-gray-700" <label class="block text-sm font-medium text-gray-700"
>Priority</label >Priority
> <select
<select name="priority"
name="priority" class="w-full border px-3 py-2 rounded {errorClass(
class="w-full border px-3 py-2 rounded {errorClass( 'priority',
'priority', )}"
)}" bind:value={newIssue[col.key as keyof Issue]}
bind:value={newIssue[col.key as keyof Issue]}
>
<option value="" disabled selected
>Select Priority</option
> >
{#each priority as p} <option value="" disabled selected
<option value={p.value}>{p.label}</option> >Select Priority</option
{/each} >
</select> {#each priority as p}
{#if $formErrors.priority} <option value={p.value}>{p.label}</option>
<p class="text-red-500 text-xs"> {/each}
{$formErrors.priority} </select>
</p> {#if $formErrors.priority}
{/if} <p class="text-red-500 text-xs">
{$formErrors.priority}
</p>
{/if}
</label>
</div> </div>
{:else if col.key === "villa_id"} {:else if col.key === "villa_id"}
<div class="space-y-1"> <div class="space-y-1">
<label class="block text-sm font-medium text-gray-700" <label class="block text-sm font-medium text-gray-700">
>Villa Name</label Villa Name
> <select
<select
name="villa_id" name="villa_id"
class="w-full border px-3 py-2 rounded {errorClass( class="w-full border px-3 py-2 rounded {errorClass(
'villa_id', 'villa_id',
@@ -1147,39 +1136,43 @@
{$formErrors.villa_id} {$formErrors.villa_id}
</p> </p>
{/if} {/if}
</label>
</div> </div>
{:else if col.key === "description_of_the_issue"} {:else if col.key === "description_of_the_issue"}
<div class="space-y-1"> <div class="space-y-1">
<label class="block text-sm font-medium text-gray-700" <label class="block text-sm font-medium text-gray-700">
>Description of The Issue</label Description of The Issue
> <textarea
<textarea name="description_of_the_issue"
name="description_of_the_issue" class="w-full border px-3 py-2 rounded {errorClass(
class="w-full border px-3 py-2 rounded {errorClass( 'description_of_the_issue',
'description_of_the_issue', )}"
)}" bind:value={newIssue[col.key as keyof Issue]}
bind:value={newIssue[col.key as keyof Issue]} placeholder={col.title}
placeholder={col.title} rows="4"
rows="4" ></textarea>
></textarea> {#if $formErrors.description_of_the_issue}
{#if $formErrors.description_of_the_issue} <p class="text-red-500 text-xs">
<p class="text-red-500 text-xs"> {$formErrors.description_of_the_issue}
{$formErrors.description_of_the_issue} </p>
</p> {/if}
{/if} </label>
</div> </div>
{:else} {:else}
<div class="space-y-1"> <div class="space-y-1">
<label class="block text-sm font-medium text-gray-700" <label class="block text-sm font-medium text-gray-700"
>{col.title}</label >{col.title}
> <input
<input
name={col.key} name={col.key}
class="w-full border px-3 py-2 rounded" class="w-full border px-3 py-2 rounded"
type="text" type="text"
bind:value={newIssue[col.key as keyof Issue]} bind:value={newIssue[col.key as keyof Issue]}
placeholder={col.title} placeholder={col.title}
/> />
</label>
</div> </div>
{/if} {/if}
{/each} {/each}

View File

@@ -25,40 +25,65 @@
]; ];
const issueTypes = [ const issueTypes = [
{ label: "Facilities - Light", value: "Facilities - Light" }, { label: "Facilities - Air Conditioner", value: "Facilities - Air Conditioner" },
{ label: "Facilities - Appliances", value: "Facilities - Appliances" },
{ label: "Facilities - Baby Cot", value: "Facilities - Baby Cot" },
{ label: "Facilities - Bath", value: "Facilities - Bath" },
{ label: "Facilities - Bed", value: "Facilities - Bed" },
{ label: "Facilities - Blender", value: "Facilities - Blender" },
{ label: "Facilities - Cabinet", value: "Facilities - Cabinet" },
{ label: "Facilities - Cable TV", value: "Facilities - Cable TV" },
{ label: "Facilities - CCTV", value: "Facilities - CCTV" },
{ label: "Facilities - Ceiling Fans", value: "Facilities - Ceiling Fans" },
{ label: "Facilities - Coffee Maker", value: "Facilities - Coffee Maker" },
{ label: "Facilities - DVD", value: "Facilities - DVD" },
{ label: "Facilities - Generator", value: "Facilities - Generator" },
{ label: "Facilities - Hairdryer", value: "Facilities - Hairdryer" },
{ label: "Facilities - Home Theatre", value: "Facilities - Home Theatre" },
{ label: "Facilities - Hot Water", value: "Facilities - Hot Water" },
{ label: "Facilities - Internet Connection", value: "Facilities - Internet Connection" },
{ label: "Facilities - Iron/Ironing Board", value: "Facilities - Iron/Ironing Board" },
{ label: "Facilities - Kitchen Equipment", value: "Facilities - Kitchen Equipment" },
{ label: "Facilities - Lights", value: "Facilities - Lights" },
{ label: "Facilities - Linen", value: "Facilities - Linen" }, { label: "Facilities - Linen", value: "Facilities - Linen" },
{ label: "Facilities - Mattress", value: "Facilities - Mattress" },
{ label: "Facilities - Mirror", value: "Facilities - Mirror" },
{ label: "Facilities - Mosquito Net", value: "Facilities - Mosquito Net" },
{ label: "Facilities - Other", value: "Facilities - Other" }, { label: "Facilities - Other", value: "Facilities - Other" },
{ label: "Facilities - Towel", value: "Facilities - Towel" }, { label: "Facilities - Parking", value: "Facilities - Parking" },
{ label: "Facilities - Fan", value: "Facilities - Fan" }, { label: "Facilities - Pool Umbrella", value: "Facilities - Pool Umbrella" },
{ label: "Cleanliness - Other", value: "Cleanliness - Other" }, { label: "Facilities - Safe Deposit Box", value: "Facilities - Safe Deposit Box" },
{ label: "Cleanliness - Floor", value: "Cleanliness - Floor" }, { label: "Facilities - Security", value: "Facilities - Security" },
{ label: "Cleanliness - Kitchen", value: "Cleanliness - Kitchen" }, { label: "Facilities - Shower", value: "Facilities - Shower" },
{ label: "Cleanliness - Bathroom", value: "Cleanliness - Bathroom" }, { label: "Facilities - Sink", value: "Facilities - Sink" },
{ { label: "Facilities - Sunbed and Mattress", value: "Facilities - Sunbed and Mattress" },
label: "Maintenance - Electrical", { label: "Facilities - Swimming Pool", value: "Facilities - Swimming Pool" },
value: "Maintenance - Electrical", { label: "Facilities - Telephone", value: "Facilities - Telephone" },
}, { label: "Facilities - Toaster", value: "Facilities - Toaster" },
{ label: "Facilities - Toilet Bowl", value: "Facilities - Toilet Bowl" },
{ label: "Facilities - Toiletries", value: "Facilities - Toiletries" },
{ label: "Facilities - Towels", value: "Facilities - Towels" },
{ label: "Facilities - TV Unit", value: "Facilities - TV Unit" },
{ label: "Facilities - Wardrobe", value: "Facilities - Wardrobe" },
{ label: "Facilities - Wash Basin", value: "Facilities - Wash Basin" },
{ label: "Facilities - Water Dispenser", value: "Facilities - Water Dispenser" },
{ label: "Maintenance - Civil", value: "Maintenance - Civil" },
{ label: "Maintenance - Electrical", value: "Maintenance - Electrical" },
{ label: "Maintenance - Mechanical", value: "Maintenance - Mechanical" },
{ label: "Maintenance - Painting", value: "Maintenance - Painting" },
{ label: "Maintenance - Plumbing", value: "Maintenance - Plumbing" }, { label: "Maintenance - Plumbing", value: "Maintenance - Plumbing" },
{ label: "Maintenance - HVAC", value: "Maintenance - HVAC" }, { label: "Maintenance - Roof", value: "Maintenance - Roof" },
{ { label: "Other - Accident", value: "Other - Accident" },
label: "Maintenance - Structural", { label: "Other - Animals", value: "Other - Animals" },
value: "Maintenance - Structural", { label: "Other - Booking", value: "Other - Booking" },
}, { label: "Other - Cleanliness", value: "Other - Cleanliness" },
{ label: "Safety Issue", value: "Safety Issue" }, { label: "Other - Crime", value: "Other - Crime" },
{ label: "Security Concern", value: "Security Concern" }, { label: "Other - Food and Beverage", value: "Other - Food and Beverage" },
{ label: "Other", value: "Other" }, { label: "Other - Garden", value: "Other - Garden" },
{ label: "General Inquiry", value: "General Inquiry" }, { label: "Other - Inventory", value: "Other - Inventory" },
{ label: "Feedback", value: "Feedback" }, { label: "Other - Noise", value: "Other - Noise" },
{ label: "Complaint", value: "Complaint" }, { label: "Other - Payment", value: "Other - Payment" },
{ label: "Request", value: "Request" }, { label: "Other - Transport", value: "Other - Transport" },
{ label: "Suggestion", value: "Suggestion" },
{ label: "Booking Issue", value: "Booking Issue" },
{ label: "Payment Issue", value: "Payment Issue" },
{ label: "Cancellation Request", value: "Cancellation Request" },
{ label: "Refund Request", value: "Refund Request" },
{ label: "Reservation Change", value: "Reservation Change" },
{ label: "Check-in Issue", value: "Check-in Issue" },
{ label: "Check-out Issue", value: "Check-out Issue" },
]; ];
const areaOfVilla = [ const areaOfVilla = [
@@ -68,30 +93,52 @@
{ label: "All Villa Areas", value: "All Villa Areas" }, { label: "All Villa Areas", value: "All Villa Areas" },
{ label: "Balcony", value: "Balcony" }, { label: "Balcony", value: "Balcony" },
{ label: "Bathroom (Guest)", value: "Bathroom (Guest)" }, { label: "Bathroom (Guest)", value: "Bathroom (Guest)" },
{ label: "Bathroom Guest House 1", value: "Bathroom Guest House 1" },
{ label: "Bathroom Guest House 2", value: "Bathroom Guest House 2" },
{ label: "Bathroom Guest House 3", value: "Bathroom Guest House 3" },
{ label: "Bathroom (Master)", value: "Bathroom (Master)" }, { label: "Bathroom (Master)", value: "Bathroom (Master)" },
{ label: "Bathroom 1", value: "Bathroom 1" }, { label: "Bathroom 1", value: "Bathroom 1" },
{ label: "Bathroom 2", value: "Bathroom 2" }, { label: "Bathroom 2", value: "Bathroom 2" },
{ label: "Bathroom 3", value: "Bathroom 3" }, { label: "Bathroom 3", value: "Bathroom 3" },
{ label: "Bedroom (Guest)", value: "Bedroom (Guest)" }, { label: "Bathroom 4", value: "Bathroom 4" },
{ label: "Bathroom 5", value: "Bathroom 5" },
{ label: "BBQ Area", value: "BBQ Area" },
{ label: "Bedroom (Master)", value: "Bedroom (Master)" }, { label: "Bedroom (Master)", value: "Bedroom (Master)" },
{ label: "Bedroom 1", value: "Bedroom 1" }, { label: "Bedroom 1", value: "Bedroom 1" },
{ label: "Bedroom 2", value: "Bedroom 2" }, { label: "Bedroom 2", value: "Bedroom 2" },
{ label: "Bedroom 3", value: "Bedroom 3" }, { label: "Bedroom 3", value: "Bedroom 3" },
{ label: "Kids Room", value: "Kids Room" }, { label: "Bedroom 4", value: "Bedroom 4" },
{ label: "Bedroom 5", value: "Bedroom 5" },
{ label: "Boundary Wall", value: "Boundary Wall" },
{ label: "Carport", value: "Carport" },
{ label: "Dining Room", value: "Dining Room" },
{ label: "Flat Roof", value: "Flat Roof" },
{ label: "Garden", value: "Garden" }, { label: "Garden", value: "Garden" },
{ label: "Gate", value: "Gate" },
{ label: "Gazebo", value: "Gazebo" },
{ label: "Generator Room", value: "Generator Room" },
{ label: "Guest House 1", value: "Guest House 1" },
{ label: "Guest House 2", value: "Guest House 2" },
{ label: "Guest House 3", value: "Guest House 3" },
{ label: "Guest House 4", value: "Guest House 4" },
{ label: "Kids Room", value: "Kids Room" },
{ label: "Kitchen", value: "Kitchen" }, { label: "Kitchen", value: "Kitchen" },
{ label: "Pump Room", value: "Pump Room" }, { label: "Landscape", value: "Landscape" },
{ label: "Living Room", value: "Living Room" }, { label: "Living Room", value: "Living Room" },
{ label: "Outdoor Area", value: "Outdoor Area" }, { label: "Other", value: "Other" },
{ label: "Parking Area", value: "Parking Area" }, { label: "Outdoor Bar", value: "Outdoor Bar" },
{ label: "Outdoor Kitchen", value: "Outdoor Kitchen" },
{ label: "Outdoor Shower", value: "Outdoor Shower" },
{ label: "Outside The Villa", value: "Outside The Villa" },
{ label: "Pool", value: "Pool" }, { label: "Pool", value: "Pool" },
{ label: "Roof", value: "Roof" }, { label: "Pump Room", value: "Pump Room" },
{ label: "Stairs", value: "Stairs" },
{ label: "Storage", value: "Storage" },
{ label: "Staff Room", value: "Staff Room" }, { label: "Staff Room", value: "Staff Room" },
{ label: "Stairs (other)", value: "Stairs (other)" },
{ label: "Stairs (living room)", value: "Stairs (living room)" },
{ label: "Storage", value: "Storage" },
{ label: "Transport", value: "Transport" }, { label: "Transport", value: "Transport" },
{ label: "Window", value: "Window" }, { label: "TV Room", value: "TV Room" },
{ label: "Others", value: "Others" }, { label: "Water Feature", value: "Water Feature" }
]; ];
//InputBy & reportedBy should dropdown data from active employee, from table vb_employee (field employee_name and employee_status = 'Active') //InputBy & reportedBy should dropdown data from active employee, from table vb_employee (field employee_name and employee_status = 'Active')