Penyebab menu pencarian tidak muncul disebabkan oleh dua hal utama pada kode
penyederhanaan sebelumnya:
1. Variabel $footer Belum Diinisialisasi (Undefined Variable): Saat bagian
Villa dihapus, baris PHP yang bertugas memuat konfigurasi footer ($footer)
dari file JSON tidak sengaja ikut terhapus. Hal ini memicu Fatal Error di
PHP 8+ atau Warning yang menghentikan proses rendering halaman di tengah
jalan.
2. Tirai Loading (Preloader) Tersangkut: Karena PHP mengalami error sebelum
halaman selesai dimuat, kode JavaScript di bagian bawah tidak sempat
dieksekusi. Akibatnya, elemen tirai hitam (#intro-curtain) terus menutupi
layar dan menghalangi visual menu pencarian.
Berikut adalah kode yang telah diperbaiki dengan mengembalikan inisialisasi
$footer secara aman, serta menambahkan pengaman agar sistem tidak crash jika
koneksi database di file config.php mengalami kendala:
[]]);
exit;
}
$url = "https://api.duffel.com/places/suggestions?query=" . $query;
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_ENCODING, '');
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"Accept: application/json",
"Duffel-Version: v2",
"Authorization: Bearer " . $apiKey
]);
$ajaxResponse = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode === 200) {
echo $ajaxResponse;
} else {
echo json_encode(["data" => []]);
}
exit;
}
// ==========================================
// Memasukkan konfigurasi database untuk penanganan diskon
$pdo = null;
if (file_exists('config.php')) {
include_once 'config.php';
}
// ----------------------------------------------------------------------
// PROTEKSI PENGAMAN: MEMASTIKAN FUNGSI DISKON ADA (Mencegah Halaman Stuck)
// ----------------------------------------------------------------------
if (!function_exists('get_active_flight_discounts')) {
function get_active_flight_discounts($pdo) {
if (!$pdo) {
return [];
}
try {
$stmt = $pdo->query("SELECT * FROM flight_discounts WHERE is_active = 1");
$discounts = $stmt->fetchAll();
$discount_map = [];
foreach ($discounts as $disc) {
$discount_map[$disc['airline_code']] = [
'type' => $disc['discount_type'],
'value' => floatval($disc['discount_value'])
];
}
return $discount_map;
} catch (\PDOException $e) {
error_log("Tabel flight_discounts belum siap atau bermasalah: " . $e->getMessage());
return [];
}
}
}
if (!function_exists('calculate_discounted_price')) {
function calculate_discounted_price($original_price, $airline_code, $discount_map) {
$applied_discount = 0;
if (isset($discount_map[$airline_code])) {
$rule = $discount_map[$airline_code];
}
elseif (isset($discount_map['ALL'])) {
$rule = $discount_map['ALL'];
}
else {
return [
'final_price' => $original_price,
'discount_amount' => 0,
'has_discount' => false
];
}
if ($rule['type'] === 'percentage') {
$applied_discount = $original_price * ($rule['value'] / 100);
} else {
$applied_discount = $rule['value'];
}
$final_price = max(0, $original_price - $applied_discount);
return [
'final_price' => $final_price,
'discount_amount' => $applied_discount,
'has_discount' => $applied_discount > 0
];
}
}
// ----------------------------------------------------------------------
// LOAD / INISIALISASI KONFIGURASI HERO SLIDES (JSON)
// ----------------------------------------------------------------------
$slides_file = 'slides_config.json';
$default_slides = [
["image_url" => "https://images.unsplash.com/photo-1436491865332-7a61a109cc05?auto=format&fit=crop&w=1200&q=80"],
["image_url" => "https://images.unsplash.com/photo-1540555700478-4be289fbecef?auto=format&fit=crop&w=1200&q=80"],
["image_url" => "https://images.unsplash.com/photo-1507525428034-b723cf961d3e?auto=format&fit=crop&w=1200&q=80"],
["image_url" => "https://images.unsplash.com/photo-1476514525535-07fb3b4ae5f1?auto=format&fit=crop&w=1200&q=80"]
];
if (file_exists($slides_file)) {
$slides = json_decode(file_get_contents($slides_file), true);
if (!$slides) {
$slides = $default_slides;
}
} else {
$slides = $default_slides;
}
// ----------------------------------------------------------------------
// LOAD / INISIALISASI KONFIGURASI LOGO SITUS (JSON)
// ----------------------------------------------------------------------
$site_config_file = 'site_config.json';
$default_site_config = [
"site_logo_url" => "",
"site_title" => "Go Fly Travelia"
];
if (file_exists($site_config_file)) {
$site_config = json_decode(file_get_contents($site_config_file), true);
if (!$site_config) {
$site_config = $default_site_config;
}
} else {
$site_config = $default_site_config;
}
// ----------------------------------------------------------------------
// LOAD / SINKRONISASI KONFIGURASI FOOTER (JSON)
// ----------------------------------------------------------------------
$footer_config_file = 'footer_config.json';
$default_footer_config = [
"bg_color" => "#090d16",
"text_color" => "#94a3b8",
"accent_color" => "#d4af37",
"bg_video_url" => "",
"address" => "Jl. Premium Luxury No. 88, Kuta, Bali",
"phone" => "+62 812-3456-7890",
"email" => "info@goflytravelia.com",
"copyright" => "© 2026 Go Fly Travelia. All rights reserved.",
"layout" => ["about", "links", "contact", "custom_html"],
"custom_widgets" => [],
"columns" => [
"about" => [
"title" => "Tentang Kami",
"content" => "Go Fly Travelia adalah penyedia layanan perjalanan udara premium dengan kenyamanan kelas dunia."
],
"links" => [
"title" => "Tautan Penting",
"items" => [
["label" => "Cari Penerbangan", "url" => "flights.php"],
["label" => "Tentang Kami", "url" => "about.php"],
["label" => "Kontak Kami", "url" => "contact.php"]
]
],
"contact" => [
"title" => "Hubungi Kami"
],
"custom_html" => [
"title" => "Aset Widget",
"html" => "
"
]
]
];
if (file_exists($footer_config_file)) {
$footer = json_decode(file_get_contents($footer_config_file), true);
if (!$footer) {
$footer = $default_footer_config;
}
} else {
$footer = $default_footer_config;
}
// ----------------------------------------------------------------------
// PERSYARATAN FUNGSI DAN PARAMETER PENCARIAN PENERBANGAN DUFFEL API
// ----------------------------------------------------------------------
$journeyType = "return";
$origin = "CGK";
$origin_name = "Soekarno-Hatta International Airport (CGK)";
$destination = "SIN";
$destination_name = "Changi Airport (SIN)";
$departureDate = date('Y-m-d', strtotime('+30 days'));
$returnDate = date('Y-m-d', strtotime('+37 days'));
$adults = 1;
$children = 0;
$passengers = 1;
$cabinClass = "economy";
$depTakeoffFrom = $_GET['dep_takeoff_from'] ?? "00:00";
$depTakeoffTo = $_GET['dep_takeoff_to'] ?? "23:59";
$depLandingFrom = $_GET['dep_landing_from'] ?? "00:00";
$depLandingTo = $_GET['dep_landing_to'] ?? "23:59";
$retTakeoffFrom = $_GET['ret_takeoff_from'] ?? "00:00";
$retTakeoffTo = $_GET['ret_takeoff_to'] ?? "23:59";
$retLandingFrom = $_GET['ret_landing_from'] ?? "00:00";
$retLandingTo = $_GET['ret_landing_to'] ?? "23:59";
$showResults = false;
$offers = [];
$httpStatusCode = 200;
$responseJson = "";
$errorMessage = "";
if (isset($_GET['search'])) {
$journeyType = $_GET['journey_type'] ?? 'one_way';
$origin = strtoupper(trim($_GET['origin'] ?? ''));
$origin_name = trim($_GET['origin_name'] ?? '');
$destination = strtoupper(trim($_GET['destination'] ?? ''));
$destination_name = trim($_GET['destination_name'] ?? '');
$departureDate = trim($_GET['departure_date'] ?? '');
$returnDate = trim($_GET['return_date'] ?? '');
$adults = (int)($_GET['adults'] ?? 1);
$children = (int)($_GET['children'] ?? 0);
if (isset($_GET['passengers']) && !isset($_GET['adults'])) {
$passengers = (int)$_GET['passengers'];
$adults = $passengers;
$children = 0;
} else {
if ($adults < 1) $adults = 1;
$passengers = $adults + $children;
}
$cabinClass = $_GET['cabin_class'] ?? 'economy';
if (!empty($origin) && !empty($destination) && !empty($departureDate)) {
$showResults = true;
$depSlice = [
"origin" => $origin,
"destination" => $destination,
"departure_date" => $departureDate
];
if ($depTakeoffFrom !== "00:00" || $depTakeoffTo !== "23:59") {
$depSlice["departure_time"] = ["from" => $depTakeoffFrom, "to" => $depTakeoffTo];
}
if ($depLandingFrom !== "00:00" || $depLandingTo !== "23:59") {
$depSlice["arrival_time"] = ["from" => $depLandingFrom, "to" => $depLandingTo];
}
$slices = [$depSlice];
if ($journeyType === 'return' && !empty($returnDate)) {
$retSlice = [
"origin" => $destination,
"destination" => $origin,
"departure_date" => $returnDate
];
if ($retTakeoffFrom !== "00:00" || $retTakeoffTo !== "23:59") {
$retSlice["departure_time"] = ["from" => $retTakeoffFrom, "to" => $retTakeoffTo];
}
if ($retLandingFrom !== "00:00" || $retLandingTo !== "23:59") {
$retSlice["arrival_time"] = ["from" => $retLandingFrom, "to" => $retLandingTo];
}
$slices[] = $retSlice;
}
$passengersPayload = [];
for ($i = 0; $i < $adults; $i++) {
$passengersPayload[] = ["type" => "adult"];
}
for ($i = 0; $i < $children; $i++) {
$passengersPayload[] = ["type" => "child"];
}
$payload = [
"data" => [
"slices" => $slices,
"passengers" => $passengersPayload,
"cabin_class" => $cabinClass
]
];
$jsonPayload = json_encode($payload);
$url = "https://api.duffel.com/air/offer_requests?return_offers=true";
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $jsonPayload);
curl_setopt($ch, CURLOPT_ENCODING, '');
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"Content-Type: application/json",
"Accept: application/json",
"Duffel-Version: v2",
"Authorization: Bearer " . $apiKey
]);
$responseJson = curl_exec($ch);
$httpStatusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if (curl_errno($ch)) {
$errorMessage = "Koneksi Error: " . curl_error($ch);
} else {
$response = json_decode($responseJson, true);
$offers = $response['data']['offers'] ?? [];
}
curl_close($ch);
}
}
$is_searched = $showResults;
function formatDuration($isoDuration) {
return trim(str_replace(['PT', 'H', 'M'], ['', 'j ', 'm'], $isoDuration));
}
function convertToIdr($amount, $fromCurrency) {
$fromCurrency = strtoupper($fromCurrency);
if ($fromCurrency === 'IDR') return $amount;
$fallbackRates = ['USD' => 16300, 'SGD' => 12100, 'EUR' => 17600, 'IDR' => 1];
if (!isset($_SESSION['exchange_rates'])) {
$ctx = stream_context_create(['http' => ['timeout' => 2.5]]);
$ratesJson = @file_get_contents("https://open.er-api.com/v6/latest/USD", false, $ctx);
if ($ratesJson) {
$ratesData = json_decode($ratesJson, true);
if (isset($ratesData['rates'])) {
$_SESSION['exchange_rates'] = $ratesData['rates'];
}
}
}
$rates = $_SESSION['exchange_rates'] ?? $fallbackRates;
$idrRate = $rates['IDR'] ?? 16300;
if ($fromCurrency === 'USD') {
return $amount * $idrRate;
}
$fromRate = $rates[$fromCurrency] ?? null;
if ($fromRate) {
return ($amount / $fromRate) * $idrRate;
}
return $amount * ($fallbackRates[$fromCurrency] ?? 1);
}
?>
Pencarian Tiket Pesawat Premium -
= 400): ?>
Terjadi Kendala Pencarian:
$errorMessage";
} else {
$response = json_decode($responseJson, true);
if (isset($response['errors'])) {
foreach ($response['errors'] as $error) {
echo "
" . htmlspecialchars($error['title']) . " : " . htmlspecialchars($error['message']) . "
";
}
}
}
?>
Hasil Pencarian
Penerbangan dari ke
|
Tanggal Pergi:
' . date('d M Y', strtotime($returnDate)) . '' : ''; ?>
| Penerbangan Ditemukan
Tidak ada jadwal penerbangan yang tersedia saat ini.
0):
$firstSegment = $segments[0];
$lastSegment = $segments[$segmentCount - 1];
$depTime = isset($firstSegment['departing_at']) ? date('H:i', strtotime($firstSegment['departing_at'])) : '--:--';
$depDate = isset($firstSegment['departing_at']) ? date('d M Y', strtotime($firstSegment['departing_at'])) : '';
$depIata = $firstSegment['origin']['iata_code'] ?? '???';
$arrTime = isset($lastSegment['arriving_at']) ? date('H:i', strtotime($lastSegment['arriving_at'])) : '--:--';
$arrDate = isset($lastSegment['arriving_at']) ? date('d M Y', strtotime($lastSegment['arriving_at'])) : '';
$arrIata = $lastSegment['destination']['iata_code'] ?? '???';
$duration = formatDuration($slice['duration'] ?? '');
$transitStatus = ($segmentCount === 1) ? "Langsung" : ($segmentCount - 1) . " Transit";
$statusClass = ($segmentCount === 1) ? "status-direct" : "status-transit";
if ($sliceIndex === 1) {
$firstSliceDepTime = $depTime;
$firstSliceArrTime = $arrTime;
$firstSliceDuration = $duration;
$firstSliceDepDate = $depDate;
$firstSliceDepIata = $depIata;
$firstSliceArrIata = $arrIata;
} elseif ($sliceIndex === 2) {
$retSliceDepTime = $depTime;
$retSliceArrTime = $arrTime;
$retSliceDuration = $duration;
$retSliceDepDate = $depDate;
$retSliceDepIata = $depIata;
$retSliceArrIata = $arrIata;
}
?>
0): ?>
Ketentuan Bagasi Real-Time
Live
Bagasi Kabin (Carry-on)
• Jumlah: 1 Unit tas kabin per penumpang.
• Berat Maksimal: kg / tas.
• Status: Gratis (Termasuk Tarif)
Bagasi Terdaftar (Checked)
0): ?>
• Jumlah: Bagasi per penumpang.
• Berat per Bagasi: kg .
• Total Berat / Pax: kg .
• Berat Total ( Pax): kg .
• Tidak Termasuk Bagasi Terdaftar Gratis.
Anda dapat memesan berat tambahan saat pengisian data penumpang (checkout).
• Estimasi Berat: kg per penumpang.
• Ketentuan: Sesuai dengan batas standar maskapai untuk penerbangan kelas .
Layanan Makanan & Minuman (In-flight Meals)
• Penerbangan ini sudah termasuk makanan utama (makanan hangat/piring saji gratis), air mineral, teh, atau jus selama perjalanan di udara.
()
$seg):
if ($segIdx > 0 && $prevArrivingAt):
$layoverTime = strtotime($seg['departing_at']) - strtotime($prevArrivingAt);
$lHours = floor($layoverTime / 3600);
$lMinutes = floor(($layoverTime % 3600) / 60);
$layoverStr = ($lHours > 0 ? $lHours . "j " : "") . $lMinutes . "m";
$layoverAirport = $seg['origin']['name'] ?? $seg['origin']['iata_code'];
?>
Transit di () selama
$firstSliceDepIata,
'destination' => $firstSliceArrIata,
'dep_date' => $firstSliceDepDate,
'carrier_name' => $airlineName,
'carrier_logo' => $airlineLogoUrl,
'dep_time' => $firstSliceDepTime,
'arr_time' => $firstSliceArrTime,
'duration' => $firstSliceDuration,
'price' => $has_discount ? $finalIdr : $originalIdr,
'currency' => 'IDR',
'cabin' => $cabinClass,
'passengers' => $passengers,
'adults' => $adults,
'children' => $children,
'offer_id' => $offerId
];
if (!empty($retSliceDepIata)) {
$bookingParams['ret_origin'] = $retSliceDepIata;
$bookingParams['ret_destination'] = $retSliceArrIata;
$bookingParams['ret_dep_date'] = $retSliceDepDate;
$bookingParams['ret_dep_time'] = $retSliceDepTime;
$bookingParams['ret_arr_time'] = $retSliceArrTime;
$bookingParams['ret_duration'] = $retSliceDuration;
}
$bookingUrl = "fare_options.php?" . http_build_query($bookingParams);
?>
GO FLY TRAVELIA
Komentar
Posting Komentar