| import gradio as gr |
| import sqlite3 |
| import pandas as pd |
| import os |
| import shutil |
| from datetime import datetime |
|
|
| |
| |
| DB_PATH = "/data/raalhu_elite_2026.db" if os.path.exists("/data") else "raalhu_elite_2026.db" |
| ADMIN_PASS = os.getenv("ADMIN_PASSWORD", "raalhu2026") |
|
|
| def init_db(): |
| conn = sqlite3.connect(DB_PATH) |
| c = conn.cursor() |
| |
| c.execute('''CREATE TABLE IF NOT EXISTS inventory |
| (id INTEGER PRIMARY KEY, name TEXT, island TEXT, price REAL, stock INTEGER)''') |
| |
| c.execute('''CREATE TABLE IF NOT EXISTS bookings |
| (id INTEGER PRIMARY KEY, guest TEXT, room_name TEXT, method TEXT, |
| status TEXT, slip_path TEXT, timestamp TEXT)''') |
| |
| |
| c.execute("SELECT count(*) FROM inventory") |
| if c.fetchone()[0] == 0: |
| rooms = [ |
| (1, 'Ocean Palm Suites', 'Maafushi', 1450, 3), |
| (2, 'Manta Retreat', 'Dhigurah', 2100, 1), |
| (3, 'Azure Horizon', 'Ukulhas', 950, 5) |
| ] |
| c.executemany("INSERT INTO inventory VALUES (?,?,?,?,?)", rooms) |
| conn.commit() |
| conn.close() |
|
|
| |
| def get_rooms(): |
| conn = sqlite3.connect(DB_PATH) |
| df = pd.read_sql_query("SELECT * FROM inventory", conn) |
| conn.close() |
| return df |
|
|
| def get_admin_data(): |
| conn = sqlite3.connect(DB_PATH) |
| df = pd.read_sql_query("SELECT * FROM bookings ORDER BY timestamp DESC", conn) |
| conn.close() |
| return df |
|
|
| def handle_booking(guest_name, room_id, method, slip_file): |
| if not guest_name or not room_id: |
| return "β οΈ Error: Please provide your name and select a room." |
| |
| conn = sqlite3.connect(DB_PATH) |
| c = conn.cursor() |
| |
| |
| c.execute("SELECT name, stock FROM inventory WHERE id = ?", (room_id,)) |
| room = c.fetchone() |
| if not room or room[1] <= 0: |
| return "β Sorry, this room just sold out!" |
|
|
| |
| path = "" |
| if method == "Bank Transfer (BML)" and slip_file: |
| os.makedirs("uploads", exist_ok=True) |
| path = f"uploads/{datetime.now().strftime('%m%d%H%M%S')}_{guest_name[:5]}.png" |
| shutil.copy(slip_file.name, path) |
| |
| status = "Confirmed β
" if method == "Credit/Debit Card" else "Pending Review β³" |
| |
| |
| c.execute("UPDATE inventory SET stock = stock - 1 WHERE id = ?", (room_id,)) |
| c.execute("INSERT INTO bookings (guest, room_name, method, status, slip_path, timestamp) VALUES (?,?,?,?,?,?)", |
| (guest_name, room[0], method, status, path, datetime.now().strftime('%Y-%m-%d %H:%M'))) |
| |
| conn.commit() |
| conn.close() |
| return f"β¨ Success! Your booking at {room[0]} is {status}. Receipt sent to WhatsApp." |
|
|
| |
| elite_css = """ |
| .gradio-container { background-color: #F0F9FF !important; } |
| .premium-card { border-radius: 20px; border: 1px solid #E0F2FE; box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1); background: white; padding: 20px; } |
| .admin-header { background: #0F172A; color: white; padding: 15px; border-radius: 12px; } |
| """ |
|
|
| |
| with gr.Blocks() as demo: |
| init_db() |
| |
| gr.HTML("<div style='text-align:center; padding: 20px;'><h1 style='font-size: 40px; font-weight: 900; color: #0369A1;'>raalhu<span style='color:#0EA5E9'>.</span></h1><p style='color:#64748B;'>The Maldives Elite Booking Engine</p></div>") |
|
|
| with gr.Tabs() as main_tabs: |
| |
| |
| with gr.Tab("ποΈ Find a Room"): |
| with gr.Row(): |
| with gr.Column(scale=2): |
| gr.Markdown("### β‘ Live Inventory") |
| room_table = gr.Dataframe(get_rooms, every=10, label="Current Available Rooms") |
| |
| with gr.Column(scale=1, elem_classes="premium-card"): |
| gr.Markdown("### π³ Instant Checkout") |
| guest_name = gr.Textbox(label="Your Name", placeholder="Enter full name") |
| |
| room_list = get_rooms() |
| room_choice = gr.Dropdown( |
| label="Choose Property", |
| choices=[(row['id'], row['name']) for _, row in room_list.iterrows()] |
| ) |
| pay_method = gr.Radio(["Bank Transfer (BML)", "Credit/Debit Card"], label="Payment Method", value="Bank Transfer (BML)") |
| |
| |
| with gr.Column() as bml_section: |
| gr.HTML("<div style='background:#F8FAFC; padding:10px; border-radius:8px; border:1px solid #CBD5E1;'><b>BML: 7730000XXXXXX</b><br>Raalhu Holdings Pvt Ltd</div>") |
| slip_input = gr.File(label="Upload Slip", file_types=["image"]) |
| |
| |
| card_section = gr.Markdown("Redirecting to Secure Gateway on click...", visible=False) |
|
|
| def toggle_payment(m): |
| return gr.update(visible=(m == "Bank Transfer (BML)")), gr.update(visible=(m == "Credit/Debit Card")) |
| |
| pay_method.change(toggle_payment, pay_method, [bml_section, card_section]) |
| |
| book_btn = gr.Button("CONFIRM BOOKING", variant="primary") |
| out_msg = gr.Markdown() |
|
|
| |
| with gr.Tab("π Admin Dashboard"): |
| with gr.Column() as login_screen: |
| password_input = gr.Textbox(label="Enter Secret Password", type="password") |
| login_btn = gr.Button("Login") |
|
|
| with gr.Column(visible=False) as admin_screen: |
| gr.HTML("<div class='admin-header'><h3>Owner Management Panel</h3></div>") |
| admin_table = gr.Dataframe(get_admin_data, label="All Bookings & Slips") |
| refresh_admin = gr.Button("π Refresh Data") |
| |
| with gr.Row(): |
| verify_id = gr.Number(label="Verify Booking ID", precision=0) |
| verify_btn = gr.Button("Approve Payment", variant="primary") |
|
|
| |
| book_btn.click(handle_booking, [guest_name, room_choice, pay_method, slip_input], out_msg) |
| |
| def check_pass(p): |
| if p == ADMIN_PASS: return gr.update(visible=True), gr.update(visible=False) |
| return gr.update(visible=False), gr.update(visible=True) |
|
|
| login_btn.click(check_pass, password_input, [admin_screen, login_screen]) |
| refresh_admin.click(get_admin_data, outputs=admin_table) |
|
|
| |
| demo.launch( |
| css=elite_css, |
| theme=gr.themes.Soft(primary_hue="sky"), |
| show_api=False |
| ) |