randomize file name
This commit is contained in:
@@ -211,9 +211,22 @@
|
|||||||
|
|
||||||
if (selectedFile) {
|
if (selectedFile) {
|
||||||
// Upload file to Supabase Storage
|
// Upload file to Supabase Storage
|
||||||
|
const oldFilePath = newUser.profile_picture
|
||||||
|
? newUser.profile_picture.split("/").pop()
|
||||||
|
: null;
|
||||||
|
if (oldFilePath) {
|
||||||
|
await supabase.storage
|
||||||
|
.from("villabugis")
|
||||||
|
.remove([`profile_pictures/${oldFilePath}`]);
|
||||||
|
}
|
||||||
|
|
||||||
|
const fileName = selectedFile.name;
|
||||||
|
const fileExtension = fileName.split(".").pop();
|
||||||
|
const randomFileName = `${crypto.randomUUID()}.${fileExtension}`;
|
||||||
|
|
||||||
const { data, error } = await supabase.storage
|
const { data, error } = await supabase.storage
|
||||||
.from("villabugis")
|
.from("villabugis")
|
||||||
.upload(`profile_pictures/${selectedFile.name}`, selectedFile);
|
.upload(`profile_pictures/${randomFileName}`, selectedFile);
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
console.error("Error uploading file:", error);
|
console.error("Error uploading file:", error);
|
||||||
|
|||||||
@@ -340,12 +340,26 @@
|
|||||||
|
|
||||||
//upload image if selected
|
//upload image if selected
|
||||||
if (selectedFile) {
|
if (selectedFile) {
|
||||||
|
//delete previous image
|
||||||
|
const oldFilePath = newIssue.issue_related_image
|
||||||
|
? newIssue.issue_related_image.split("/").pop()
|
||||||
|
: null;
|
||||||
|
if (oldFilePath) {
|
||||||
|
const { error: deleteError } = await supabase.storage
|
||||||
|
.from("villabugis")
|
||||||
|
.remove([`issues/${oldFilePath}`]);
|
||||||
|
if (deleteError) {
|
||||||
|
console.error("Error deleting old image:", deleteError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const fileName = selectedFile.name;
|
||||||
|
const fileExtension = fileName.split(".").pop();
|
||||||
|
const randomFileName = `${crypto.randomUUID()}.${fileExtension}`;
|
||||||
|
|
||||||
const { data, error } = await supabase.storage
|
const { data, error } = await supabase.storage
|
||||||
.from("villabugis")
|
.from("villabugis")
|
||||||
.upload(
|
.upload(`issues/${randomFileName}`, selectedFile);
|
||||||
`issues/${Date.now()}_${selectedFile.name}`,
|
|
||||||
selectedFile,
|
|
||||||
);
|
|
||||||
|
|
||||||
console.log("Image upload data:", data);
|
console.log("Image upload data:", data);
|
||||||
|
|
||||||
@@ -389,7 +403,9 @@
|
|||||||
"description_of_the_issue",
|
"description_of_the_issue",
|
||||||
) as string,
|
) as string,
|
||||||
reported_date: formData.get("reported_date") as string,
|
reported_date: formData.get("reported_date") as string,
|
||||||
issue_related_image: imagePreviewUrl || "",
|
issue_related_image: newIssue.issue_related_image
|
||||||
|
? newIssue.issue_related_image
|
||||||
|
: (formData.get("issue_related_image") as string),
|
||||||
issue_source: formData.get("issue_source") as string,
|
issue_source: formData.get("issue_source") as string,
|
||||||
reported_by: formData.get("reported_by") as string,
|
reported_by: formData.get("reported_by") as string,
|
||||||
input_by: formData.get("input_by") as string,
|
input_by: formData.get("input_by") as string,
|
||||||
@@ -419,6 +435,11 @@
|
|||||||
|
|
||||||
await fetchIssues();
|
await fetchIssues();
|
||||||
showModal = false;
|
showModal = false;
|
||||||
|
|
||||||
|
//clear form data
|
||||||
|
newIssue = {};
|
||||||
|
|
||||||
|
selectedFile = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// function get public URL for image supabase
|
// function get public URL for image supabase
|
||||||
@@ -1165,7 +1186,12 @@
|
|||||||
<div class="flex justify-end gap-2 mt-4">
|
<div class="flex justify-end gap-2 mt-4">
|
||||||
<button
|
<button
|
||||||
class="px-4 py-2 text-sm rounded bg-gray-200 hover:bg-gray-300"
|
class="px-4 py-2 text-sm rounded bg-gray-200 hover:bg-gray-300"
|
||||||
on:click={() => (showModal = false)}
|
on:click={() => (
|
||||||
|
(showModal = false),
|
||||||
|
(newIssue = {}),
|
||||||
|
(selectedFile = null),
|
||||||
|
(imagePreviewUrl = null)
|
||||||
|
)}
|
||||||
>
|
>
|
||||||
Cancel
|
Cancel
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { onMount } from "svelte";
|
import { onMount } from "svelte";
|
||||||
import { supabase } from "$lib/supabaseClient";
|
import { supabase } from "$lib/supabaseClient";
|
||||||
|
import { getSessionAuthId } from "$lib/utils/authUtil";
|
||||||
|
|
||||||
type User = {
|
type User = {
|
||||||
id: string;
|
id: string;
|
||||||
@@ -83,14 +84,28 @@
|
|||||||
async function uploadProfilePicture() {
|
async function uploadProfilePicture() {
|
||||||
if (!file) return;
|
if (!file) return;
|
||||||
|
|
||||||
const filePath = `profile_pictures/${user.id}-${file.name}`;
|
// delete file lama if exists
|
||||||
|
if (user.profile_picture) {
|
||||||
|
const oldFilePath = user.profile_picture.split("/").pop();
|
||||||
|
if (oldFilePath) {
|
||||||
|
await supabase.storage
|
||||||
|
.from("villabugis")
|
||||||
|
.remove([`profile_pictures/${oldFilePath}`]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const fileName = file.name;
|
||||||
|
const fileExtension = fileName.split(".").pop();
|
||||||
|
const randomFileName = `${crypto.randomUUID()}.${fileExtension}`;
|
||||||
|
|
||||||
|
const filePath = `profile_pictures/${user.id}-${randomFileName}`;
|
||||||
const { error } = await supabase.storage
|
const { error } = await supabase.storage
|
||||||
.from("profile")
|
.from("villabugis")
|
||||||
.upload(filePath, file, { upsert: true });
|
.upload(filePath, file, { upsert: true });
|
||||||
|
|
||||||
if (!error) {
|
if (!error) {
|
||||||
const { data: publicUrlData } = supabase.storage
|
const { data: publicUrlData } = supabase.storage
|
||||||
.from("profile")
|
.from("villabugis")
|
||||||
.getPublicUrl(filePath);
|
.getPublicUrl(filePath);
|
||||||
user.profile_picture = publicUrlData.publicUrl;
|
user.profile_picture = publicUrlData.publicUrl;
|
||||||
} else {
|
} else {
|
||||||
@@ -100,11 +115,19 @@
|
|||||||
|
|
||||||
async function updateProfile() {
|
async function updateProfile() {
|
||||||
loading = true;
|
loading = true;
|
||||||
|
|
||||||
|
const sessionId = await getSessionAuthId();
|
||||||
|
if (!sessionId) {
|
||||||
|
message = "Anda harus login terlebih dahulu";
|
||||||
|
loading = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (file) await uploadProfilePicture();
|
if (file) await uploadProfilePicture();
|
||||||
|
|
||||||
user.last_updated = new Date().toISOString();
|
user.last_updated = new Date().toISOString();
|
||||||
user.last_updated_by = user.email;
|
user.last_updated_by = user.id;
|
||||||
|
|
||||||
const { error } = await supabase
|
const { error } = await supabase
|
||||||
.from("vb_users")
|
.from("vb_users")
|
||||||
|
|||||||
@@ -349,9 +349,26 @@
|
|||||||
|
|
||||||
// Upload image if selected
|
// Upload image if selected
|
||||||
if (selectedFile) {
|
if (selectedFile) {
|
||||||
|
const oldFilePath = formData.get("picture_link") as string;
|
||||||
|
if (oldFilePath) {
|
||||||
|
// Delete old file if it exists
|
||||||
|
const { error: deleteError } = await supabase.storage
|
||||||
|
.from("villabugis")
|
||||||
|
.remove([`project/${oldFilePath}`]);
|
||||||
|
|
||||||
|
if (deleteError) {
|
||||||
|
console.error("Error deleting old image:", deleteError);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//randomize file name uuid
|
||||||
|
const fileName = selectedFile.name;
|
||||||
|
const fileExtension = fileName.split(".").pop();
|
||||||
|
const randomFileName = `${crypto.randomUUID()}.${fileExtension}`;
|
||||||
|
|
||||||
const { data, error } = await supabase.storage
|
const { data, error } = await supabase.storage
|
||||||
.from("villabugis")
|
.from("villabugis")
|
||||||
.upload(`project/${selectedFile.name}`, selectedFile);
|
.upload(`project/${randomFileName}`, selectedFile);
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
console.error("Error uploading image:", error);
|
console.error("Error uploading image:", error);
|
||||||
@@ -403,6 +420,12 @@
|
|||||||
|
|
||||||
await fetchProjects();
|
await fetchProjects();
|
||||||
showModal = false;
|
showModal = false;
|
||||||
|
|
||||||
|
isEditing = false;
|
||||||
|
currentEditingId = null;
|
||||||
|
newProjects = {};
|
||||||
|
imagePreviewUrl = null;
|
||||||
|
selectedFile = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function deleteProject(id: string) {
|
async function deleteProject(id: string) {
|
||||||
|
|||||||
@@ -284,6 +284,9 @@
|
|||||||
"updated_by",
|
"updated_by",
|
||||||
"updated_name",
|
"updated_name",
|
||||||
"inputed_name",
|
"inputed_name",
|
||||||
|
"approved_name",
|
||||||
|
"acknowledged_name",
|
||||||
|
"received_name",
|
||||||
];
|
];
|
||||||
const formColumns = columns.filter(
|
const formColumns = columns.filter(
|
||||||
(col) => !excludedKeys.includes(col.key),
|
(col) => !excludedKeys.includes(col.key),
|
||||||
|
|||||||
@@ -5,18 +5,19 @@
|
|||||||
import { supabase } from "$lib/supabaseClient";
|
import { supabase } from "$lib/supabaseClient";
|
||||||
import { writable } from "svelte/store";
|
import { writable } from "svelte/store";
|
||||||
import { on } from "svelte/events";
|
import { on } from "svelte/events";
|
||||||
|
import logo from "$lib/images/logo.webp";
|
||||||
|
|
||||||
type villa = {
|
type villa = {
|
||||||
id: string;
|
id: string;
|
||||||
name: string;
|
villa_name: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
const villas = writable<villa[]>([]);
|
const villas = writable<villa[]>([]);
|
||||||
|
|
||||||
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");
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
console.error("Error fetching villas:", error);
|
console.error("Error fetching villas:", error);
|
||||||
@@ -406,10 +407,10 @@
|
|||||||
.insert([dinningData]);
|
.insert([dinningData]);
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
console.error("Error submitting transport:", error);
|
console.error("Error submitting order:", error);
|
||||||
} else {
|
} else {
|
||||||
console.log("Transport submitted successfully:", data);
|
console.log("You order submitted successfully:", data);
|
||||||
alert("Transport submitted successfully!");
|
alert("You order submitted successfully!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -448,7 +449,7 @@
|
|||||||
<!-- logo -->
|
<!-- logo -->
|
||||||
<div class="text-center mb-6">
|
<div class="text-center mb-6">
|
||||||
<img
|
<img
|
||||||
src="/src/lib/images/logo.webp"
|
src={logo}
|
||||||
alt="Logo"
|
alt="Logo"
|
||||||
class="mx-auto"
|
class="mx-auto"
|
||||||
loading="lazy"
|
loading="lazy"
|
||||||
@@ -469,7 +470,7 @@
|
|||||||
>
|
>
|
||||||
<option value="" disabled selected>Select Villa</option>
|
<option value="" disabled selected>Select Villa</option>
|
||||||
{#each $villas as villa}
|
{#each $villas as villa}
|
||||||
<option value={villa.id}>{villa.name}</option>
|
<option value={villa.id}>{villa.villa_name}</option>
|
||||||
{/each}
|
{/each}
|
||||||
</select>
|
</select>
|
||||||
{#if $formErrors.villa_id}
|
{#if $formErrors.villa_id}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
// For example, you could handle form submission here
|
// For example, you could handle form submission here
|
||||||
import { onMount } from "svelte";
|
import { onMount } from "svelte";
|
||||||
import { supabase } from "$lib/supabaseClient";
|
import { supabase } from "$lib/supabaseClient";
|
||||||
|
import logo from "$lib/images/logo.webp";
|
||||||
|
|
||||||
const priority = [
|
const priority = [
|
||||||
{ label: "Low", value: "Low" },
|
{ label: "Low", value: "Low" },
|
||||||
@@ -33,10 +34,16 @@
|
|||||||
{ label: "Cleanliness - Floor", value: "Cleanliness - Floor" },
|
{ label: "Cleanliness - Floor", value: "Cleanliness - Floor" },
|
||||||
{ label: "Cleanliness - Kitchen", value: "Cleanliness - Kitchen" },
|
{ label: "Cleanliness - Kitchen", value: "Cleanliness - Kitchen" },
|
||||||
{ label: "Cleanliness - Bathroom", value: "Cleanliness - Bathroom" },
|
{ label: "Cleanliness - Bathroom", value: "Cleanliness - Bathroom" },
|
||||||
{ label: "Maintenance - Electrical", value: "Maintenance - Electrical",},
|
{
|
||||||
|
label: "Maintenance - Electrical",
|
||||||
|
value: "Maintenance - Electrical",
|
||||||
|
},
|
||||||
{ label: "Maintenance - Plumbing", value: "Maintenance - Plumbing" },
|
{ label: "Maintenance - Plumbing", value: "Maintenance - Plumbing" },
|
||||||
{ label: "Maintenance - HVAC", value: "Maintenance - HVAC" },
|
{ label: "Maintenance - HVAC", value: "Maintenance - HVAC" },
|
||||||
{ label: "Maintenance - Structural", value: "Maintenance - Structural" },
|
{
|
||||||
|
label: "Maintenance - Structural",
|
||||||
|
value: "Maintenance - Structural",
|
||||||
|
},
|
||||||
{ label: "Safety Issue", value: "Safety Issue" },
|
{ label: "Safety Issue", value: "Safety Issue" },
|
||||||
{ label: "Security Concern", value: "Security Concern" },
|
{ label: "Security Concern", value: "Security Concern" },
|
||||||
{ label: "Other", value: "Other" },
|
{ label: "Other", value: "Other" },
|
||||||
@@ -86,7 +93,7 @@
|
|||||||
{ label: "Window", value: "Window" },
|
{ label: "Window", value: "Window" },
|
||||||
{ label: "Others", value: "Others" },
|
{ label: "Others", value: "Others" },
|
||||||
];
|
];
|
||||||
//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')
|
||||||
|
|
||||||
const followUp = [
|
const followUp = [
|
||||||
{ label: "Communication Needed by Reservation", value: "true" },
|
{ label: "Communication Needed by Reservation", value: "true" },
|
||||||
@@ -103,7 +110,9 @@
|
|||||||
const target = event.target as HTMLInputElement;
|
const target = event.target as HTMLInputElement;
|
||||||
if (target.files && target.files.length > 0) {
|
if (target.files && target.files.length > 0) {
|
||||||
const file = target.files[0];
|
const file = target.files[0];
|
||||||
if (!["image/jpeg", "image/png", "image/webp"].includes(file.type)) {
|
if (
|
||||||
|
!["image/jpeg", "image/png", "image/webp"].includes(file.type)
|
||||||
|
) {
|
||||||
alert("Only JPG, PNG, or WEBP images are allowed.");
|
alert("Only JPG, PNG, or WEBP images are allowed.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -183,12 +192,16 @@
|
|||||||
reported_by: formData.get("reported_by") as string,
|
reported_by: formData.get("reported_by") as string,
|
||||||
input_by: formData.get("input_by") as string,
|
input_by: formData.get("input_by") as string,
|
||||||
resolution: formData.get("resloution") as string,
|
resolution: formData.get("resloution") as string,
|
||||||
guest_has_aggreed_issue_has_been_resolved: formData.get("guest_has_aggreed_issue_has_been_resolved") as string,
|
guest_has_aggreed_issue_has_been_resolved: formData.get(
|
||||||
|
"guest_has_aggreed_issue_has_been_resolved",
|
||||||
|
) as string,
|
||||||
follow_up: formData.get("follow_up") as string,
|
follow_up: formData.get("follow_up") as string,
|
||||||
guest_communication: formData.get("guest_communication") as string,
|
guest_communication: formData.get(
|
||||||
|
"guest_communication",
|
||||||
|
) as string,
|
||||||
issue_related_image: issueImageUrl,
|
issue_related_image: issueImageUrl,
|
||||||
url_drive: formData.get("url_drive") as string,
|
url_drive: formData.get("url_drive") as string,
|
||||||
created_at: new Date().toISOString()
|
created_at: new Date().toISOString(),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Insert into Supabase
|
// Insert into Supabase
|
||||||
@@ -204,7 +217,7 @@
|
|||||||
await fetch("https://flow.catalis.app/webhook/vb-issuecreate", {
|
await fetch("https://flow.catalis.app/webhook/vb-issuecreate", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: { "Content-Type": "application/json" },
|
headers: { "Content-Type": "application/json" },
|
||||||
body: JSON.stringify(issue)
|
body: JSON.stringify(issue),
|
||||||
});
|
});
|
||||||
|
|
||||||
alert("Issue submitted successfully!");
|
alert("Issue submitted successfully!");
|
||||||
@@ -244,7 +257,7 @@
|
|||||||
<!-- logo -->
|
<!-- logo -->
|
||||||
<div class="text-center mb-6">
|
<div class="text-center mb-6">
|
||||||
<img
|
<img
|
||||||
src="/src/lib/images/logo.webp"
|
src={logo}
|
||||||
alt="Logo"
|
alt="Logo"
|
||||||
class="mx-auto"
|
class="mx-auto"
|
||||||
loading="lazy"
|
loading="lazy"
|
||||||
@@ -271,12 +284,21 @@
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label class="block text-sm font-medium mb-1">Issue Source
|
<label class="block text-sm font-medium mb-1"
|
||||||
|
>Issue Source
|
||||||
<span class="text-red-500">*</span>
|
<span class="text-red-500">*</span>
|
||||||
<select name="issue_source" class="w-full border rounded-xl px-4 py-2 focus:outline-none focus:ring-2 focus:ring-purple-400 text-gray-600" required>
|
<select
|
||||||
<option value="" disabled selected>Select option...</option>
|
name="issue_source"
|
||||||
|
class="w-full border rounded-xl px-4 py-2 focus:outline-none focus:ring-2 focus:ring-purple-400 text-gray-600"
|
||||||
|
required
|
||||||
|
>
|
||||||
|
<option value="" disabled selected
|
||||||
|
>Select option...</option
|
||||||
|
>
|
||||||
{#each issueSource as source}
|
{#each issueSource as source}
|
||||||
<option value={source.value}>{source.label}</option>
|
<option value={source.value}
|
||||||
|
>{source.label}</option
|
||||||
|
>
|
||||||
{/each}
|
{/each}
|
||||||
</select>
|
</select>
|
||||||
</label>
|
</label>
|
||||||
@@ -287,10 +309,16 @@
|
|||||||
<span class="text-red-500">*</span>
|
<span class="text-red-500">*</span>
|
||||||
<select
|
<select
|
||||||
name="villa_name"
|
name="villa_name"
|
||||||
class="w-full border rounded-xl px-4 py-2 focus:outline-none focus:ring-2 focus:ring-purple-400 text-gray-600" required>
|
class="w-full border rounded-xl px-4 py-2 focus:outline-none focus:ring-2 focus:ring-purple-400 text-gray-600"
|
||||||
<option value="" disabled selected>Select option...</option>
|
required
|
||||||
|
>
|
||||||
|
<option value="" disabled selected
|
||||||
|
>Select option...</option
|
||||||
|
>
|
||||||
{#each dataVilla as villa}
|
{#each dataVilla as villa}
|
||||||
<option value={villa.id}>{villa.villa_name}</option>
|
<option value={villa.id}
|
||||||
|
>{villa.villa_name}</option
|
||||||
|
>
|
||||||
{/each}
|
{/each}
|
||||||
</select>
|
</select>
|
||||||
</label>
|
</label>
|
||||||
@@ -298,7 +326,9 @@
|
|||||||
<div>
|
<div>
|
||||||
<label class="block text-sm font-medium mb-1">
|
<label class="block text-sm font-medium mb-1">
|
||||||
Issue related image
|
Issue related image
|
||||||
<div class="w-full border-2 border-dashed rounded-xl px-4 py-10 text-center text-gray-400 cursor-pointer hover:bg-gray-50 transition relative">
|
<div
|
||||||
|
class="w-full border-2 border-dashed rounded-xl px-4 py-10 text-center text-gray-400 cursor-pointer hover:bg-gray-50 transition relative"
|
||||||
|
>
|
||||||
<input
|
<input
|
||||||
name="issue_related_image"
|
name="issue_related_image"
|
||||||
type="file"
|
type="file"
|
||||||
@@ -318,7 +348,9 @@
|
|||||||
</div>
|
</div>
|
||||||
{#if issueImageUrl}
|
{#if issueImageUrl}
|
||||||
<div class="mt-4">
|
<div class="mt-4">
|
||||||
<p class="text-sm text-gray-600 mb-2">Preview:</p>
|
<p class="text-sm text-gray-600 mb-2">
|
||||||
|
Preview:
|
||||||
|
</p>
|
||||||
<img
|
<img
|
||||||
src={issueImageUrl}
|
src={issueImageUrl}
|
||||||
alt="Issue preview"
|
alt="Issue preview"
|
||||||
@@ -349,7 +381,9 @@
|
|||||||
class="w-full border rounded-xl px-4 py-2 focus:outline-none focus:ring-2 text-gray-600"
|
class="w-full border rounded-xl px-4 py-2 focus:outline-none focus:ring-2 text-gray-600"
|
||||||
required
|
required
|
||||||
>
|
>
|
||||||
<option value="" disabled selected>Select option...</option>
|
<option value="" disabled selected
|
||||||
|
>Select option...</option
|
||||||
|
>
|
||||||
{#each dataUser as reporter}
|
{#each dataUser as reporter}
|
||||||
<option value={reporter.id}>
|
<option value={reporter.id}>
|
||||||
{reporter.employee_name}
|
{reporter.employee_name}
|
||||||
@@ -359,7 +393,8 @@
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label class="block text-sm font-medium mb-1">URLDrive
|
<label class="block text-sm font-medium mb-1"
|
||||||
|
>URLDrive
|
||||||
<input
|
<input
|
||||||
name="url_drive"
|
name="url_drive"
|
||||||
type="url"
|
type="url"
|
||||||
@@ -380,7 +415,9 @@
|
|||||||
class="w-full border rounded-xl px-4 py-2 focus:outline-none focus:ring-2 focus:ring-purple-400 text-gray-600"
|
class="w-full border rounded-xl px-4 py-2 focus:outline-none focus:ring-2 focus:ring-purple-400 text-gray-600"
|
||||||
required
|
required
|
||||||
>
|
>
|
||||||
<option value="" disabled selected>Select option...</option>
|
<option value="" disabled selected
|
||||||
|
>Select option...</option
|
||||||
|
>
|
||||||
{#each priority as p}
|
{#each priority as p}
|
||||||
<option value={p.value}>{p.label}</option>
|
<option value={p.value}>{p.label}</option>
|
||||||
{/each}
|
{/each}
|
||||||
@@ -395,7 +432,9 @@
|
|||||||
class="w-full border rounded-xl px-4 py-2 focus:outline-none focus:ring-2 focus:ring-purple-400 text-gray-600"
|
class="w-full border rounded-xl px-4 py-2 focus:outline-none focus:ring-2 focus:ring-purple-400 text-gray-600"
|
||||||
required
|
required
|
||||||
>
|
>
|
||||||
<option value="" disabled selected>Select option...</option>
|
<option value="" disabled selected
|
||||||
|
>Select option...</option
|
||||||
|
>
|
||||||
{#each issueTypes as type}
|
{#each issueTypes as type}
|
||||||
<option value={type.value}>{type.label}</option>
|
<option value={type.value}>{type.label}</option>
|
||||||
{/each}
|
{/each}
|
||||||
@@ -410,7 +449,9 @@
|
|||||||
class="w-full border rounded-xl px-4 py-2 focus:outline-none focus:ring-2 focus:ring-purple-400 text-gray-600"
|
class="w-full border rounded-xl px-4 py-2 focus:outline-none focus:ring-2 focus:ring-purple-400 text-gray-600"
|
||||||
required
|
required
|
||||||
>
|
>
|
||||||
<option value="" disabled selected>Select option...</option>
|
<option value="" disabled selected
|
||||||
|
>Select option...</option
|
||||||
|
>
|
||||||
{#each areaOfVilla as area}
|
{#each areaOfVilla as area}
|
||||||
<option value={area.value}>{area.label}</option>
|
<option value={area.value}>{area.label}</option>
|
||||||
{/each}
|
{/each}
|
||||||
@@ -427,7 +468,6 @@
|
|||||||
class="w-full border rounded-xl px-4 py-2 focus:outline-none focus:ring-2 focus:ring-purple-400"
|
class="w-full border rounded-xl px-4 py-2 focus:outline-none focus:ring-2 focus:ring-purple-400"
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label class="block text-sm font-medium mb-1">
|
<label class="block text-sm font-medium mb-1">
|
||||||
@@ -451,7 +491,9 @@
|
|||||||
>Select option...</option
|
>Select option...</option
|
||||||
>
|
>
|
||||||
{#each dataUser as input}
|
{#each dataUser as input}
|
||||||
<option value={input.id}>{input.employee_name}</option>
|
<option value={input.id}
|
||||||
|
>{input.employee_name}</option
|
||||||
|
>
|
||||||
{/each}
|
{/each}
|
||||||
</select>
|
</select>
|
||||||
</label>
|
</label>
|
||||||
@@ -467,7 +509,9 @@
|
|||||||
>Select option...</option
|
>Select option...</option
|
||||||
>
|
>
|
||||||
{#each followUp as follow}
|
{#each followUp as follow}
|
||||||
<option value={follow.value}>{follow.label}</option>
|
<option value={follow.value}
|
||||||
|
>{follow.label}</option
|
||||||
|
>
|
||||||
{/each}
|
{/each}
|
||||||
</select>
|
</select>
|
||||||
</label>
|
</label>
|
||||||
@@ -500,7 +544,8 @@
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-center space-x-2">
|
<div class="flex items-center space-x-2">
|
||||||
<label class="text-sm">Guest has agreed issue has been resolved
|
<label class="text-sm"
|
||||||
|
>Guest has agreed issue has been resolved
|
||||||
<input
|
<input
|
||||||
name="guest_has_aggreed_issue_has_been_resolved"
|
name="guest_has_aggreed_issue_has_been_resolved"
|
||||||
value="false"
|
value="false"
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { onMount } from "svelte";
|
import { onMount } from "svelte";
|
||||||
import { supabase } from "$lib/supabaseClient";
|
import { supabase } from "$lib/supabaseClient";
|
||||||
|
import logo from "$lib/images/logo.webp";
|
||||||
|
|
||||||
type TimesheetForm = {
|
type TimesheetForm = {
|
||||||
entered_by: string;
|
entered_by: string;
|
||||||
@@ -140,6 +141,8 @@
|
|||||||
on:submit|preventDefault={submitForm}
|
on:submit|preventDefault={submitForm}
|
||||||
class="w-full max-w-lg bg-white p-6 rounded-2xl shadow-xl space-y-4"
|
class="w-full max-w-lg bg-white p-6 rounded-2xl shadow-xl space-y-4"
|
||||||
>
|
>
|
||||||
|
<img src={logo} alt="Villa Logo" class="mx-auto mb-6" width="250" />
|
||||||
|
|
||||||
<h2 class="text-2xl font-bold text-center mb-6">Timesheet Entry</h2>
|
<h2 class="text-2xl font-bold text-center mb-6">Timesheet Entry</h2>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
import { onMount } from "svelte";
|
import { onMount } from "svelte";
|
||||||
import { supabase } from "$lib/supabaseClient";
|
import { supabase } from "$lib/supabaseClient";
|
||||||
import { writable } from "svelte/store";
|
import { writable } from "svelte/store";
|
||||||
|
import logo from "$lib/images/logo.webp";
|
||||||
|
|
||||||
const area = [
|
const area = [
|
||||||
{ label: "Laksamana", value: "Laksamana" },
|
{ label: "Laksamana", value: "Laksamana" },
|
||||||
@@ -115,7 +116,7 @@
|
|||||||
<!-- logo -->
|
<!-- logo -->
|
||||||
<div class="text-center mb-6">
|
<div class="text-center mb-6">
|
||||||
<img
|
<img
|
||||||
src="/src/lib/images/logo.webp"
|
src={logo}
|
||||||
alt="Logo"
|
alt="Logo"
|
||||||
class="mx-auto"
|
class="mx-auto"
|
||||||
loading="lazy"
|
loading="lazy"
|
||||||
|
|||||||
Reference in New Issue
Block a user