penambahan route protection

This commit is contained in:
aji@catalis.app
2025-06-13 19:36:53 +07:00
parent 9668e3ace3
commit 7be6168330
8 changed files with 365 additions and 223 deletions

View File

@@ -258,6 +258,7 @@
console.error("Logout failed:", error.message);
} else {
localStorage.removeItem("user");
goto("/login");
}
}

View File

@@ -1,12 +1,12 @@
import { redirect } from '@sveltejs/kit';
import type { LayoutServerLoad } from './$types';
// import { redirect } from '@sveltejs/kit';
// import type { LayoutServerLoad } from './$types';
export const load: LayoutServerLoad = async ({ locals }) => {
if (!locals.user) {
throw redirect(303, '/login');
}
// export const load: LayoutServerLoad = async ({ locals }) => {
// if (!locals.user) {
// throw redirect(303, '/login');
// }
return {
user: locals.user
};
};
// return {
// user: locals.user
// };
// };

View File

@@ -1,13 +1,44 @@
<script>
<script lang="ts">
import { writable } from "svelte/store";
import Sidebar from "../../components/Sidebar.svelte";
import { onMount } from "svelte";
import { supabase } from "$lib/supabaseClient";
import { goto } from "$app/navigation";
import type { Session } from "@supabase/supabase-js";
export let data;
let notifications = 3; // Contoh jumlah notifikasi
let notifications = 3;
let user = {
name: "John Doe",
avatar: "https://i.pravatar.cc/40", // Avatar placeholder
avatar: "https://i.pravatar.cc/40",
};
let userdata: any = null;
const session = writable<Session | null>(null);
onMount(async () => {
const {
data: { session: currentSession },
} = await supabase.auth.getSession();
session.set(currentSession || null);
supabase.auth.onAuthStateChange((event, sessionValue) => {
session.set(sessionValue);
if (!sessionValue) goto("/login");
});
const userStr = localStorage.getItem("user");
if (userStr) {
userdata = JSON.parse(userStr);
} else {
goto("/login");
}
user.name = userdata.full_name || "Guest";
user.avatar = userdata.profile_picture || "https://i.pravatar.cc/40";
});
</script>
<div class="flex h-screen">

View File

@@ -1,8 +1,11 @@
import { supabase } from "$lib/supabaseClient";
import { redirect } from "@sveltejs/kit";
export const load = async (event) => {
import type { RequestEvent } from "@sveltejs/kit";
export const load = async (event: RequestEvent & { locals: { user?: any } }) => {
if (!event.locals.user) {
console.log(event.url)
}
}

View File

@@ -90,7 +90,6 @@
{ label: "Guest", value: "Guest" },
];
let currentUserId: string | null = null;
onMount(async () => {
@@ -226,8 +225,6 @@
: issue.approval
? "APPROVED"
: "REJECTED", // or map as needed
approved_by: issue.approved_by ?? null,
approved_date: issue.approved_date ? new Date(issue.approved_date) : null,
total_hours_work:
Math.abs(
new Date(issue.datetime_out).getTime() -
@@ -721,7 +718,9 @@
>Select Villa</option
>
{#each dataVilla as villa}
<option value={villa.id}>{villa.villa_name}</option>
<option value={villa.id}
>{villa.villa_name}</option
>
{/each}
</select>
{#if $formErrors[col.key]}

View File

@@ -1,22 +1,21 @@
<script>
import { supabase } from '$lib/supabaseClient';
import StarRating from '$lib/StarRating.svelte';
import villaBugisImage from '$lib/images/villa-bugis.png';
import { supabase } from "$lib/supabaseClient";
import StarRating from "$lib/StarRating.svelte";
import villaBugisImage from "$lib/images/villa-bugis.png";
const WEBHOOK_URL = "https://flow.catalis.app/webhook/vb_feedback_new";
const WEBHOOK_URL = 'https://flow.catalis.app/webhook/vb_feedback_new';
let villa_name = '';
let customer_name = '';
let checkin_date = '';
let checkout_date = '';
let feedback = '';
let errorMessage = '';
let book_process = '';
let airport_greet = '';
let arrival_greet = '';
let maintenance_proc = '';
let bf_service = '';
let villa_name = "";
let customer_name = "";
let checkin_date = "";
let checkout_date = "";
let feedback = "";
let errorMessage = "";
let book_process = "";
let airport_greet = "";
let arrival_greet = "";
let maintenance_proc = "";
let bf_service = "";
// Star ratings (1-5)
let overal_star = 0;
@@ -27,23 +26,22 @@
let become_sponsor = false;
async function handleSubmit() {
errorMessage = '';
errorMessage = "";
if (!villa_name.trim() || !customer_name.trim() || !feedback.trim()) {
errorMessage = 'Villa, Name, and feedback are required.';
errorMessage = "Villa, Name, and feedback are required.";
return;
}
if (new Date(checkout_date) <= new Date(checkin_date)) {
errorMessage = 'Check-out date must be after check-in date.';
errorMessage = "Check-out date must be after check-in date.";
return;
}
const user = (await supabase.auth.getUser()).data.user;
const { data, error } = await supabase
.from('vb_feedback')
.insert([{
const { data, error } = await supabase.from("vb_feedback").insert([
{
villa_name,
customer_name,
checkin_date,
@@ -57,17 +55,18 @@
maintenance_proc,
extend_disc,
nextstay_disc,
become_sponsor
}]);
become_sponsor,
},
]);
if (error) {
console.error('Error submitting feedback:', error.message);
errorMessage = 'Failed to submit feedback. Please try again.';
console.error("Error submitting feedback:", error.message);
errorMessage = "Failed to submit feedback. Please try again.";
} else {
try {
await fetch(WEBHOOK_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
villa_name,
customer_name,
@@ -82,24 +81,24 @@
overal_star,
extend_disc,
nextstay_disc,
become_sponsor
})
become_sponsor,
}),
});
} catch (webhookError) {
console.error('Webhook failed:', webhookError);
console.error("Webhook failed:", webhookError);
}
// Reset form
villa_name = '';
customer_name = '';
checkin_date = '';
checkout_date = '';
feedback = '';
book_process = '';
airport_greet = '';
arrival_greet = '';
maintenance_proc = '';
bf_service = '';
villa_name = "";
customer_name = "";
checkin_date = "";
checkout_date = "";
feedback = "";
book_process = "";
airport_greet = "";
arrival_greet = "";
maintenance_proc = "";
bf_service = "";
overal_star = 0;
extend_disc = false;
nextstay_disc = false;
@@ -130,89 +129,180 @@
</div>
</div>
<form on:submit|preventDefault={handleSubmit} class="flex flex-col gap-4 max-w-xl mx-auto p-6 bg-white rounded-xl shadow-md">
<form
on:submit|preventDefault={handleSubmit}
class="flex flex-col gap-4 max-w-xl mx-auto p-6 bg-white rounded-xl shadow-md"
>
{#if errorMessage}
<div class="text-red-600 font-semibold">{errorMessage}</div>
{/if}
<label for="fb_villaname" class="flex flex-col">Villa Name</label>
<input id="fb_villaname" type="text" bind:value={villa_name} placeholder="Villa Name" required class="p-2 border rounded-md" />
<input
id="fb_villaname"
type="text"
bind:value={villa_name}
placeholder="Villa Name"
required
class="p-2 border rounded-md"
/>
<label for="fb_gn" class="flex flex-col">Name</label>
<input id="fb_gn" type="text" bind:value={customer_name} placeholder="Customer Name" required class="p-2 border rounded-md" />
<input
id="fb_gn"
type="text"
bind:value={customer_name}
placeholder="Customer Name"
required
class="p-2 border rounded-md"
/>
<label for="fb_cid" class="flex flex-col">Checkin Date</label>
<input id="fb_cid" type="date" bind:value={checkin_date} required class="p-2 border rounded-md" />
<input
id="fb_cid"
type="date"
bind:value={checkin_date}
required
class="p-2 border rounded-md"
/>
<label for="fb_cod" class="flex flex-col">Checkout Date</label>
<input id="fb_cod" type="date" bind:value={checkout_date} required class="p-2 border rounded-md" />
<input
id="fb_cod"
type="date"
bind:value={checkout_date}
required
class="p-2 border rounded-md"
/>
<!-- Star Ratings -->
<label class="flex flex-col">
Booking Process:
<small class="text-sm text-gray-500 mb-1">Please highlights of the booking process (anything neglected by the staff or something done well by the staff)</small>
<textarea bind:value={book_process} placeholder="Write your feedback here..." required class="p-2 border rounded-md min-h-[120px]"></textarea>
<small class="text-sm text-gray-500 mb-1"
>Please highlights of the booking process (anything neglected by the staff
or something done well by the staff)</small
>
<textarea
bind:value={book_process}
placeholder="Write your feedback here..."
required
class="p-2 border rounded-md min-h-[120px]"
></textarea>
</label>
<label class="flex flex-col">
Airport Greeting and Transportation:
<small class="text-sm text-gray-500 mb-1">Please highlights of the airport transfer experience (anything neglected by the staff or something done well by the staff)</small>
<textarea bind:value={airport_greet} placeholder="Write your feedback here..." required class="p-2 border rounded-md min-h-[120px]"></textarea>
<small class="text-sm text-gray-500 mb-1"
>Please highlights of the airport transfer experience (anything neglected
by the staff or something done well by the staff)</small
>
<textarea
bind:value={airport_greet}
placeholder="Write your feedback here..."
required
class="p-2 border rounded-md min-h-[120px]"
></textarea>
</label>
<label class="flex flex-col">
Arrival & Check-in:
<small class="text-sm text-gray-500 mb-1">Please highlights of the arrival and check-in process(anything neglected by the staff or something done well by the staff)</small>
<textarea bind:value={arrival_greet} placeholder="Write your feedback here..." required class="p-2 border rounded-md min-h-[120px]"></textarea>
<small class="text-sm text-gray-500 mb-1"
>Please highlights of the arrival and check-in process(anything neglected
by the staff or something done well by the staff)</small
>
<textarea
bind:value={arrival_greet}
placeholder="Write your feedback here..."
required
class="p-2 border rounded-md min-h-[120px]"
></textarea>
</label>
<label class="flex flex-col">
Breakfast Service or other food and beverage service utilized:
<small class="text-sm text-gray-500 mb-1">Please highlighs of the breakfast service(anything neglected by the staff or something done well by the staff)</small>
<textarea bind:value={bf_service} placeholder="Write your feedback here..." required class="p-2 border rounded-md min-h-[120px]"></textarea>
<small class="text-sm text-gray-500 mb-1"
>Please highlighs of the breakfast service(anything neglected by the staff
or something done well by the staff)</small
>
<textarea
bind:value={bf_service}
placeholder="Write your feedback here..."
required
class="p-2 border rounded-md min-h-[120px]"
></textarea>
</label>
<label class="flex flex-col">
Housekeeping and Maintenance:
<small class="text-sm text-gray-500 mb-1">Please highlighs of the housekeeping and maintenance service(anything neglected by the staff or something done well by the staff)</small>
<textarea bind:value={maintenance_proc} placeholder="Write your feedback here..." required class="p-2 border rounded-md min-h-[120px]"></textarea>
<small class="text-sm text-gray-500 mb-1"
>Please highlighs of the housekeeping and maintenance service(anything
neglected by the staff or something done well by the staff)</small
>
<textarea
bind:value={maintenance_proc}
placeholder="Write your feedback here..."
required
class="p-2 border rounded-md min-h-[120px]"
></textarea>
</label>
<label class="flex flex-col">
What did you think of the villa in General:
<small class="text-sm text-gray-500 mb-1">Did you have any other issue of area you would like to highligh during stay? Please let us know any other comments you have - the good, the bad, and the ugly</small>
<textarea bind:value={feedback} placeholder="Write your feedback here..." required class="p-2 border rounded-md min-h-[120px]"></textarea>
<small class="text-sm text-gray-500 mb-1"
>Did you have any other issue of area you would like to highligh during
stay? Please let us know any other comments you have - the good, the bad,
and the ugly</small
>
<textarea
bind:value={feedback}
placeholder="Write your feedback here..."
required
class="p-2 border rounded-md min-h-[120px]"
></textarea>
</label>
<!-- Centered big star-->
<div class="text-center mt-6">
<small class="text-sm text-gray-500 block mb-2">
Overall Stay Please rate your overall stay. 5 stars = a great stay!<br />
Overall Stay Please rate your overall stay. 5 stars = a great stay!<br
/>
We aim to provide 5-star services to you!
</small>
<div class="flex justify-center">
<StarRating bind:value={overal_star} name="Overall Satisfaction" size="xl" />
<StarRating
bind:value={overal_star}
name="Overall Satisfaction"
size="xl"
/>
</div>
</div>
<!-- Checkboxes -->
<label class="flex flex-col">
<span class="flex items-center gap-2">
<input type="checkbox" bind:checked={extend_disc} />
<small class="text-sm text-gray-500 mb-1">I would like to discuss extending my stay for 30% off!</small>
<small class="text-sm text-gray-500 mb-1"
>I would like to discuss extending my stay for 30% off!</small
>
</span>
</label>
<label class="flex flex-col">
<span class="flex items-center gap-2">
<input type="checkbox" bind:checked={nextstay_disc} />
<small class="text-sm text-gray-500 mb-1">I would like to discuss booking my next stayto receive an extra discount!</small>
<small class="text-sm text-gray-500 mb-1"
>I would like to discuss booking my next stayto receive an extra
discount!</small
>
</span>
</label>
<label class="flex flex-col">
<span class="flex items-center gap-2">
<input type="checkbox" bind:checked={become_sponsor} />
<small class="text-sm text-gray-500 mb-1">I would like to know more about sponsoring a Balinese child with Damara (for only AU$150 a year!)(100% of the AU$150 goes to the childs schooling - there are no overheads with Damara!)</small>
<small class="text-sm text-gray-500 mb-1"
>I would like to know more about sponsoring a Balinese child with Damara
(for only AU$150 a year!)(100% of the AU$150 goes to the childs
schooling - there are no overheads with Damara!)</small
>
</span>
</label>
<!-- Submit Button -->
<button type="submit" class="bg-blue-600 text-white py-2 px-4 rounded-md hover:bg-blue-700 transition">
<button
type="submit"
class="bg-blue-600 text-white py-2 px-4 rounded-md hover:bg-blue-700 transition"
>
Submit Feedback
</button>
</form>

View File

@@ -1,6 +1,7 @@
<script lang="ts">
import { supabase } from "$lib/supabaseClient";
import { goto } from "$app/navigation";
import logo from "$lib/images/villa.png";
let email = "";
let password = "";
@@ -38,11 +39,7 @@
>
<!-- Ilustrasi -->
<div class="hidden md:flex w-1/2 justify-center items-center">
<img
src="/src/lib/images/villa.png"
alt="Login Illustration"
class="w-full max-w-sm"
/>
<img src={logo} alt="Login Illustration" class="w-full max-w-sm" />
</div>
<!-- Form Login -->

View File

@@ -0,0 +1,21 @@
<script>
// Tambahkan script jika ingin menambahkan interaktivitas di masa depan
</script>
<div
class="min-h-screen flex items-center justify-center bg-gradient-to-br from-red-100 to-red-300"
>
<div class="bg-white rounded-xl shadow-lg p-8 max-w-md w-full text-center">
<div class="text-6xl mb-4">🚫</div>
<h1 class="text-2xl font-bold text-red-600 mb-2">Akses Ditolak</h1>
<p class="text-gray-700 mb-6">
Anda tidak memiliki izin untuk mengakses halaman ini.
</p>
<a
href="/login"
class="inline-block px-6 py-2 rounded-lg bg-red-500 text-white font-semibold hover:bg-red-600 transition"
>
Kembali ke Login
</a>
</div>
</div>