Update images across various directories with new versions, including modifications to vehicle images, family and fleet photos, and other assets.
|
|
@ -4,29 +4,47 @@ import nodemailer from "nodemailer"
|
||||||
export async function POST(req: Request) {
|
export async function POST(req: Request) {
|
||||||
try {
|
try {
|
||||||
const body = await req.json()
|
const body = await req.json()
|
||||||
const { name, email, phone, service, message, recaptcha } = body
|
const { name, email, phone, service, message, recaptchaToken, recaptchaAction } = body
|
||||||
|
const recaptchaSecret =
|
||||||
|
process.env.RECAPTCHA_SECRET_KEY ||
|
||||||
|
"6LfqD1osAAAAAEbpEApPkiQUbyjdKYx2OvhY2XTk"
|
||||||
|
const minScore = Number(process.env.RECAPTCHA_MIN_SCORE) || 0.5
|
||||||
|
|
||||||
// 1. Verify reCaptcha
|
if (!recaptchaToken) {
|
||||||
const recaptchaResponse = await fetch(
|
return NextResponse.json({ error: "Missing reCaptcha token" }, { status: 400 })
|
||||||
`https://www.google.com/recaptcha/api/siteverify?secret=${process.env.RECAPTCHA_SECRET_KEY}&response=${recaptcha}`,
|
}
|
||||||
{ method: "POST" }
|
|
||||||
)
|
// 1. Verify reCaptcha v3
|
||||||
|
const verifyBody = new URLSearchParams({
|
||||||
|
secret: recaptchaSecret,
|
||||||
|
response: recaptchaToken,
|
||||||
|
})
|
||||||
|
const recaptchaResponse = await fetch("https://www.google.com/recaptcha/api/siteverify", {
|
||||||
|
method: "POST",
|
||||||
|
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
||||||
|
body: verifyBody.toString(),
|
||||||
|
})
|
||||||
const recaptchaData = await recaptchaResponse.json()
|
const recaptchaData = await recaptchaResponse.json()
|
||||||
|
|
||||||
// For local testing without secret key, we might skip this
|
if (!recaptchaData.success || recaptchaData.action !== recaptchaAction || recaptchaData.score < minScore) {
|
||||||
if (process.env.RECAPTCHA_SECRET_KEY && !recaptchaData.success) {
|
|
||||||
return NextResponse.json({ error: "reCaptcha verification failed" }, { status: 400 })
|
return NextResponse.json({ error: "reCaptcha verification failed" }, { status: 400 })
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. Configure Nodemailer
|
// 2. Configure Nodemailer
|
||||||
// NOTE: In a real environment, you'd use your SMTP credentials (Gmail, SendGrid, etc.)
|
// NOTE: In a real environment, you'd use your SMTP credentials (Gmail, SendGrid, etc.)
|
||||||
|
const smtpUser = process.env.SMTP_USER
|
||||||
|
const smtpPass = process.env.SMTP_PASS
|
||||||
|
if (!smtpUser || !smtpPass) {
|
||||||
|
return NextResponse.json({ error: "SMTP is not configured" }, { status: 500 })
|
||||||
|
}
|
||||||
|
|
||||||
const transporter = nodemailer.createTransport({
|
const transporter = nodemailer.createTransport({
|
||||||
host: process.env.SMTP_HOST || "smtp.gmail.com",
|
host: process.env.SMTP_HOST || "smtp.gmail.com",
|
||||||
port: Number(process.env.SMTP_PORT) || 587,
|
port: Number(process.env.SMTP_PORT) || 587,
|
||||||
secure: false,
|
secure: false,
|
||||||
auth: {
|
auth: {
|
||||||
user: process.env.SMTP_USER,
|
user: smtpUser,
|
||||||
pass: process.env.SMTP_PASS,
|
pass: smtpPass,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
@ -35,58 +53,60 @@ export async function POST(req: Request) {
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||||
<style>
|
<style>
|
||||||
body { font-family: 'Inter', sans-serif; line-height: 1.6; color: #1a1a1a; margin: 0; padding: 0; }
|
body { font-family: "Segoe UI", Arial, sans-serif; line-height: 1.6; color: #1a1a1a; margin: 0; padding: 0; }
|
||||||
.container { max-width: 600px; margin: 40px auto; border: 1px solid #e2e8f0; border-radius: 24px; overflow: hidden; box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1); }
|
.container { max-width: 640px; margin: 24px auto; border: 1px solid #e2e8f0; border-radius: 16px; overflow: hidden; }
|
||||||
.header { background-color: #D9A321; background: linear-gradient(135deg, #D9A321 0%, #1A1A1A 100%); color: white; padding: 40px; text-align: center; }
|
.header { background: #D9A321; color: #111827; padding: 20px 24px; font-weight: 700; }
|
||||||
.header h1 { margin: 0; font-size: 24px; text-transform: uppercase; letter-spacing: 2px; }
|
.section { padding: 20px 24px; border-top: 1px solid #f1f5f9; background: #ffffff; }
|
||||||
.content { padding: 40px; background-color: #ffffff; }
|
.title { font-size: 16px; font-weight: 800; margin: 0 0 12px; }
|
||||||
.field { margin-bottom: 24px; }
|
.label { font-weight: 700; font-size: 12px; text-transform: uppercase; color: #6b7280; margin-top: 12px; }
|
||||||
.label { font-weight: 800; font-size: 12px; text-transform: uppercase; color: #D9A321; display: block; margin-bottom: 4px; }
|
.value { font-size: 14px; color: #111827; background: #f8fafc; padding: 10px 12px; border-radius: 10px; border: 1px solid #f1f5f9; }
|
||||||
.value { font-size: 16px; color: #1e293b; background: #f8fafc; padding: 12px 16px; border-radius: 12px; border: 1px solid #f1f5f9; }
|
.footer { padding: 16px 24px; font-size: 12px; color: #6b7280; background: #f8fafc; }
|
||||||
.footer { background-color: #f8fafc; padding: 20px; text-align: center; font-size: 12px; color: #64748b; }
|
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div className="container">
|
<div class="container">
|
||||||
<div className="header">
|
<div class="header">SkyFly Travel - Uj uzenet / New message</div>
|
||||||
<h1>Új üzenet érkezett</h1>
|
|
||||||
|
<div class="section">
|
||||||
|
<div class="title">Magyar</div>
|
||||||
|
<div class="label">Nev</div>
|
||||||
|
<div class="value">${name}</div>
|
||||||
|
<div class="label">Email</div>
|
||||||
|
<div class="value">${email}</div>
|
||||||
|
<div class="label">Telefonszam</div>
|
||||||
|
<div class="value">${phone || "-"}</div>
|
||||||
|
<div class="label">Szolgaltatas tipusa</div>
|
||||||
|
<div class="value">${service}</div>
|
||||||
|
<div class="label">Uzenet</div>
|
||||||
|
<div class="value" style="white-space: pre-wrap;">${message}</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="content">
|
|
||||||
<div className="field">
|
<div class="section">
|
||||||
<span className="label">Név</span>
|
<div class="title">English</div>
|
||||||
<div className="value">${name}</div>
|
<div class="label">Name</div>
|
||||||
</div>
|
<div class="value">${name}</div>
|
||||||
<div className="field">
|
<div class="label">Email</div>
|
||||||
<span className="label">Email</span>
|
<div class="value">${email}</div>
|
||||||
<div className="value">${email}</div>
|
<div class="label">Phone</div>
|
||||||
</div>
|
<div class="value">${phone || "-"}</div>
|
||||||
<div className="field">
|
<div class="label">Service type</div>
|
||||||
<span className="label">Telefonszám</span>
|
<div class="value">${service}</div>
|
||||||
<div className="value">${phone || "-"}</div>
|
<div class="label">Message</div>
|
||||||
</div>
|
<div class="value" style="white-space: pre-wrap;">${message}</div>
|
||||||
<div className="field">
|
|
||||||
<span className="label">Szolgáltatás típusa</span>
|
|
||||||
<div className="value">${service}</div>
|
|
||||||
</div>
|
|
||||||
<div className="field">
|
|
||||||
<span className="label">Üzenet</span>
|
|
||||||
<div className="value" style="white-space: pre-wrap;">${message}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="footer">
|
|
||||||
© 2026 SkyFly Travel Landing Page System
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="footer">© 2026 SkyFly Travel</div>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
`
|
`
|
||||||
|
|
||||||
// 4. Send Email
|
// 4. Send Email
|
||||||
await transporter.sendMail({
|
await transporter.sendMail({
|
||||||
from: `"SkyFly Web" <${process.env.SMTP_USER}>`,
|
from: `"SkyFly Web" <${process.env.MAIL_FROM || smtpUser}>`,
|
||||||
to: "bognar.szialrd83@gmail.com",
|
to: "bognar.szilard83@gmail.com",
|
||||||
subject: `Weboldal Üzenet: ${name} (${service})`,
|
subject: `Weboldal uzenet / Website message: ${name} (${service})`,
|
||||||
html: htmlEmail,
|
html: htmlEmail,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,29 @@
|
||||||
"use client"
|
"use client"
|
||||||
|
|
||||||
import React, { useState, useRef } from "react"
|
import React, { useEffect, useState } from "react"
|
||||||
import { useLanguage } from "@/lib/language-context"
|
import { useLanguage } from "@/lib/language-context"
|
||||||
import { Button } from "@/components/ui/button"
|
import { Button } from "@/components/ui/button"
|
||||||
import { Input } from "@/components/ui/input"
|
import { Input } from "@/components/ui/input"
|
||||||
import { Textarea } from "@/components/ui/textarea"
|
import { Textarea } from "@/components/ui/textarea"
|
||||||
import { Card } from "@/components/ui/card"
|
import { Card } from "@/components/ui/card"
|
||||||
import { cn } from "@/lib/utils"
|
|
||||||
import ReCAPTCHA from "react-google-recaptcha"
|
|
||||||
import { Send, CheckCircle2, AlertCircle } from "lucide-react"
|
import { Send, CheckCircle2, AlertCircle } from "lucide-react"
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface Window {
|
||||||
|
grecaptcha?: {
|
||||||
|
ready: (cb: () => void) => void
|
||||||
|
execute: (siteKey: string, options: { action: string }) => Promise<string>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export default function ContactForm() {
|
export default function ContactForm() {
|
||||||
const { t } = useLanguage()
|
const { t, language } = useLanguage()
|
||||||
const recaptchaRef = useRef<ReCAPTCHA>(null)
|
const siteKey =
|
||||||
|
process.env.NEXT_PUBLIC_RECAPTCHA_SITE_KEY ||
|
||||||
|
"6LfqD1osAAAAANd6P-3qin0cRdFQSGX92F02A3dE"
|
||||||
|
const recaptchaAction = "contact_form"
|
||||||
|
const [recaptchaReady, setRecaptchaReady] = useState(false)
|
||||||
|
|
||||||
const [status, setStatus] = useState<"idle" | "loading" | "success" | "error">("idle")
|
const [status, setStatus] = useState<"idle" | "loading" | "success" | "error">("idle")
|
||||||
const [formData, setFormData] = useState({
|
const [formData, setFormData] = useState({
|
||||||
|
|
@ -24,6 +35,59 @@ export default function ContactForm() {
|
||||||
consent: false
|
consent: false
|
||||||
})
|
})
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!siteKey) return
|
||||||
|
const scriptId = "recaptcha-v3"
|
||||||
|
const onReady = () => {
|
||||||
|
window.grecaptcha?.ready(() => setRecaptchaReady(true))
|
||||||
|
}
|
||||||
|
|
||||||
|
if (document.getElementById(scriptId)) {
|
||||||
|
onReady()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const script = document.createElement("script")
|
||||||
|
script.id = scriptId
|
||||||
|
script.src = `https://www.google.com/recaptcha/api.js?render=${siteKey}`
|
||||||
|
script.async = true
|
||||||
|
script.defer = true
|
||||||
|
script.onload = onReady
|
||||||
|
script.onerror = () => setRecaptchaReady(false)
|
||||||
|
document.head.appendChild(script)
|
||||||
|
}, [siteKey])
|
||||||
|
|
||||||
|
const waitForRecaptcha = (timeoutMs = 4000) =>
|
||||||
|
new Promise<void>((resolve, reject) => {
|
||||||
|
const started = Date.now()
|
||||||
|
const tick = () => {
|
||||||
|
if (window.grecaptcha) {
|
||||||
|
window.grecaptcha.ready(() => resolve())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (Date.now() - started >= timeoutMs) {
|
||||||
|
reject(new Error("reCAPTCHA not ready"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
setTimeout(tick, 150)
|
||||||
|
}
|
||||||
|
tick()
|
||||||
|
})
|
||||||
|
|
||||||
|
const getRecaptchaToken = async () => {
|
||||||
|
if (!window.grecaptcha) {
|
||||||
|
throw new Error("reCAPTCHA not ready")
|
||||||
|
}
|
||||||
|
return new Promise<string>((resolve, reject) => {
|
||||||
|
window.grecaptcha?.ready(() => {
|
||||||
|
window.grecaptcha
|
||||||
|
?.execute(siteKey, { action: recaptchaAction })
|
||||||
|
.then(resolve)
|
||||||
|
.catch(reject)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
const handleChange = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement>) => {
|
const handleChange = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement>) => {
|
||||||
const { name, value, type } = e.target as any
|
const { name, value, type } = e.target as any
|
||||||
setFormData(prev => ({
|
setFormData(prev => ({
|
||||||
|
|
@ -35,11 +99,15 @@ export default function ContactForm() {
|
||||||
const handleSubmit = async (e: React.FormEvent) => {
|
const handleSubmit = async (e: React.FormEvent) => {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
|
|
||||||
const recaptchaValue = recaptchaRef.current?.getValue()
|
if (!recaptchaReady) {
|
||||||
if (!recaptchaValue) {
|
try {
|
||||||
alert("Please complete the reCaptcha")
|
await waitForRecaptcha()
|
||||||
|
setRecaptchaReady(true)
|
||||||
|
} catch {
|
||||||
|
alert("reCAPTCHA is not ready yet. Please try again.")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!formData.consent) {
|
if (!formData.consent) {
|
||||||
alert("Please accept the privacy policy")
|
alert("Please accept the privacy policy")
|
||||||
|
|
@ -51,16 +119,21 @@ export default function ContactForm() {
|
||||||
try {
|
try {
|
||||||
// In a static export environment, this would hit a PHP script on the server
|
// In a static export environment, this would hit a PHP script on the server
|
||||||
// or an external API. Here we assume an API route for local testing.
|
// or an external API. Here we assume an API route for local testing.
|
||||||
const response = await fetch("/api/contact", {
|
const recaptchaToken = await getRecaptchaToken()
|
||||||
|
const response = await fetch("/contact.php", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: { "Content-Type": "application/json" },
|
headers: { "Content-Type": "application/json" },
|
||||||
body: JSON.stringify({ ...formData, recaptcha: recaptchaValue })
|
body: JSON.stringify({
|
||||||
|
...formData,
|
||||||
|
recaptchaToken,
|
||||||
|
recaptchaAction,
|
||||||
|
language,
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
setStatus("success")
|
setStatus("success")
|
||||||
setFormData({ name: "", email: "", phone: "", service: "REPTÉRI TRANSZFER", message: "", consent: false })
|
setFormData({ name: "", email: "", phone: "", service: "REPTÉRI TRANSZFER", message: "", consent: false })
|
||||||
recaptchaRef.current?.reset()
|
|
||||||
} else {
|
} else {
|
||||||
setStatus("error")
|
setStatus("error")
|
||||||
}
|
}
|
||||||
|
|
@ -192,10 +265,9 @@ export default function ContactForm() {
|
||||||
|
|
||||||
{/* reCaptcha */}
|
{/* reCaptcha */}
|
||||||
<div className="pt-4 flex justify-center md:justify-start">
|
<div className="pt-4 flex justify-center md:justify-start">
|
||||||
<ReCAPTCHA
|
<span className="text-xs text-slate-400">
|
||||||
ref={recaptchaRef}
|
A weboldalt reCAPTCHA v3 védi.
|
||||||
sitekey="6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI" // Place-holder test key
|
</span>
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{status === "error" && (
|
{status === "error" && (
|
||||||
|
|
|
||||||
125
contact.php
|
|
@ -1,11 +1,6 @@
|
||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* SkyFly Travel - Contact Form Backend (PHP Fallback for Static Export)
|
* SkyFly Travel - Contact Form Backend (PHP mail() for Static Export)
|
||||||
*
|
|
||||||
* Instructions:
|
|
||||||
* 1. Upload this file to your server (e.g., as contact.php).
|
|
||||||
* 2. Update the ContactForm.tsx component's fetch URL to point to this script.
|
|
||||||
* 3. Configure your SMTP settings and reCaptcha Secret Key below.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
header("Access-Control-Allow-Origin: *");
|
header("Access-Control-Allow-Origin: *");
|
||||||
|
|
@ -13,48 +8,103 @@ header("Access-Control-Allow-Headers: Content-Type");
|
||||||
header("Content-Type: application/json");
|
header("Content-Type: application/json");
|
||||||
|
|
||||||
// --- CONFIGURATION ---
|
// --- CONFIGURATION ---
|
||||||
$secretKey = "YOUR_RECAPTCHA_SECRET_KEY"; // Replace with your Google reCaptcha Secret Key
|
$secretKey = "6LfqD1osAAAAAEbpEApPkiQUbyjdKYx2OvhY2XTk"; // reCAPTCHA v3 Secret Key
|
||||||
$toEmail = "bognar.szialrd83@gmail.com";
|
$toEmail = "bognar.szilard83@gmail.com";
|
||||||
|
$minScore = 0.5;
|
||||||
|
$expectedAction = "contact_form";
|
||||||
// ---------------------
|
// ---------------------
|
||||||
|
|
||||||
|
function json_error($message, $code = 400, $details = null) {
|
||||||
|
http_response_code($code);
|
||||||
|
$response = ["error" => $message];
|
||||||
|
if (!empty($_GET["debug"]) && $details) {
|
||||||
|
$response["details"] = $details;
|
||||||
|
}
|
||||||
|
echo json_encode($response);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
if ($_SERVER["REQUEST_METHOD"] === "POST") {
|
if ($_SERVER["REQUEST_METHOD"] === "POST") {
|
||||||
$data = json_decode(file_get_contents("php://input"), true);
|
$data = json_decode(file_get_contents("php://input"), true);
|
||||||
|
|
||||||
$name = strip_tags($data["name"]);
|
$name = strip_tags($data["name"] ?? "");
|
||||||
$email = filter_var($data["email"], FILTER_SANITIZE_EMAIL);
|
$email = filter_var($data["email"] ?? "", FILTER_SANITIZE_EMAIL);
|
||||||
$phone = strip_tags($data["phone"]);
|
$phone = strip_tags($data["phone"] ?? "");
|
||||||
$service = strip_tags($data["service"]);
|
$service = strip_tags($data["service"] ?? "");
|
||||||
$message = strip_tags($data["message"]);
|
$message = strip_tags($data["message"] ?? "");
|
||||||
$recaptcha = $data["recaptcha"];
|
$language = $data["language"] ?? "hu";
|
||||||
|
$recaptchaToken = $data["recaptchaToken"] ?? "";
|
||||||
|
$recaptchaAction = $data["recaptchaAction"] ?? "";
|
||||||
|
|
||||||
// 1. Verify reCaptcha
|
if (!$recaptchaToken) {
|
||||||
$verifyResponse = file_get_contents("https://www.google.com/recaptcha/api/siteverify?secret=$secretKey&response=$recaptcha");
|
json_error("Missing reCaptcha token");
|
||||||
$responseData = json_decode($verifyResponse);
|
|
||||||
|
|
||||||
if (!$responseData->success) {
|
|
||||||
http_response_code(400);
|
|
||||||
echo json_encode(["error" => "reCaptcha verification failed"]);
|
|
||||||
exit;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. Prepare HTML Email
|
// 1. Verify reCaptcha v3
|
||||||
$subject = "Weboldal Üzenet: $name ($service)";
|
$verifyResponse = null;
|
||||||
|
if (function_exists("curl_init")) {
|
||||||
|
$ch = curl_init("https://www.google.com/recaptcha/api/siteverify");
|
||||||
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||||
|
curl_setopt($ch, CURLOPT_POST, true);
|
||||||
|
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query([
|
||||||
|
"secret" => $secretKey,
|
||||||
|
"response" => $recaptchaToken,
|
||||||
|
]));
|
||||||
|
$verifyResponse = curl_exec($ch);
|
||||||
|
curl_close($ch);
|
||||||
|
} else {
|
||||||
|
$verifyResponse = file_get_contents(
|
||||||
|
"https://www.google.com/recaptcha/api/siteverify?secret=$secretKey&response=$recaptchaToken"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($verifyResponse === false || !$verifyResponse) {
|
||||||
|
$last = error_get_last();
|
||||||
|
json_error("reCaptcha verification failed", 400, $last ? $last["message"] : "No response");
|
||||||
|
}
|
||||||
|
|
||||||
|
$responseData = json_decode($verifyResponse);
|
||||||
|
if (!$responseData) {
|
||||||
|
json_error("reCaptcha verification failed", 400, "Invalid JSON response");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
!$responseData->success ||
|
||||||
|
$responseData->action !== $expectedAction ||
|
||||||
|
$responseData->score < $minScore
|
||||||
|
) {
|
||||||
|
json_error("reCaptcha verification failed", 400, json_encode($responseData));
|
||||||
|
}
|
||||||
|
|
||||||
|
$isEnglish = $language === "en";
|
||||||
|
$subject = $isEnglish
|
||||||
|
? "Website message: $name ($service)"
|
||||||
|
: "Weboldal uzenet: $name ($service)";
|
||||||
|
|
||||||
|
$title = $isEnglish ? "New message" : "Uj uzenet";
|
||||||
|
$labelName = $isEnglish ? "Name" : "Nev";
|
||||||
|
$labelEmail = $isEnglish ? "Email" : "Email";
|
||||||
|
$labelPhone = $isEnglish ? "Phone" : "Telefonszam";
|
||||||
|
$labelService = $isEnglish ? "Service type" : "Szolgaltatas tipusa";
|
||||||
|
$labelMessage = $isEnglish ? "Message" : "Uzenet";
|
||||||
|
|
||||||
$htmlEmail = "
|
$htmlEmail = "
|
||||||
<html>
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta http-equiv='Content-Type' content='text/html; charset=utf-8' />
|
||||||
|
</head>
|
||||||
<body style='font-family: sans-serif; color: #333;'>
|
<body style='font-family: sans-serif; color: #333;'>
|
||||||
<div style='max-width: 600px; margin: 20px auto; border: 1px solid #ddd; border-radius: 15px; overflow: hidden;'>
|
<div style='max-width: 600px; margin: 20px auto; border: 1px solid #ddd; border-radius: 15px; overflow: hidden;'>
|
||||||
<div style='background: linear-gradient(135deg, #D9A321 0%, #1A1A1A 100%); color: white; padding: 30px; text-align: center;'>
|
<div style='background: #D9A321; color: #111827; padding: 20px 24px; font-weight: 700;'>
|
||||||
<h1 style='margin: 0;'>Új üzenet érkezett</h1>
|
SkyFly Travel - $title
|
||||||
</div>
|
</div>
|
||||||
<div style='padding: 30px;'>
|
<div style='padding: 20px 24px; border-top: 1px solid #eee;'>
|
||||||
<p><strong>Név:</strong> $name</p>
|
<p><strong>$labelName:</strong> $name</p>
|
||||||
<p><strong>Email:</strong> $email</p>
|
<p><strong>$labelEmail:</strong> $email</p>
|
||||||
<p><strong>Telefonszám:</strong> $phone</p>
|
<p><strong>$labelPhone:</strong> $phone</p>
|
||||||
<p><strong>Szolgáltatás:</strong> $service</p>
|
<p><strong>$labelService:</strong> $service</p>
|
||||||
<hr style='border: 0; border-top: 1px solid #eee; margin: 20px 0;'>
|
<p><strong>$labelMessage:</strong></p>
|
||||||
<p><strong>Üzenet:</strong></p>
|
<p style='white-space: pre-wrap; background: #f9f9f9; padding: 12px; border-radius: 8px;'>$message</p>
|
||||||
<p style='white-space: pre-wrap; background: #f9f9f9; padding: 15px; border-radius: 10px;'>$message</p>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
|
|
@ -64,13 +114,16 @@ if ($_SERVER["REQUEST_METHOD"] === "POST") {
|
||||||
$headers = "MIME-Version: 1.0" . "\r\n";
|
$headers = "MIME-Version: 1.0" . "\r\n";
|
||||||
$headers .= "Content-type:text/html;charset=UTF-8" . "\r\n";
|
$headers .= "Content-type:text/html;charset=UTF-8" . "\r\n";
|
||||||
$headers .= "From: <noreply@skyflytravel.hu>" . "\r\n";
|
$headers .= "From: <noreply@skyflytravel.hu>" . "\r\n";
|
||||||
|
if ($email) {
|
||||||
|
$headers .= "Reply-To: $email" . "\r\n";
|
||||||
|
}
|
||||||
|
|
||||||
// 3. Send Email
|
// 3. Send Email
|
||||||
if (mail($toEmail, $subject, $htmlEmail, $headers)) {
|
if (mail($toEmail, $subject, $htmlEmail, $headers)) {
|
||||||
echo json_encode(["success" => true]);
|
echo json_encode(["success" => true]);
|
||||||
} else {
|
} else {
|
||||||
http_response_code(500);
|
$last = error_get_last();
|
||||||
echo json_encode(["error" => "Failed to send email"]);
|
json_error("Failed to send email", 500, $last ? $last["message"] : "mail() returned false");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
|
|
|
||||||
BIN
images/1.jpg
|
Before Width: | Height: | Size: 43 KiB After Width: | Height: | Size: 42 KiB |
BIN
images/1_cut.jpg
|
Before Width: | Height: | Size: 65 KiB After Width: | Height: | Size: 64 KiB |
BIN
images/2.jpg
|
Before Width: | Height: | Size: 55 KiB After Width: | Height: | Size: 54 KiB |
BIN
images/3.jpg
|
Before Width: | Height: | Size: 67 KiB After Width: | Height: | Size: 65 KiB |
|
Before Width: | Height: | Size: 199 KiB After Width: | Height: | Size: 198 KiB |
|
Before Width: | Height: | Size: 134 KiB After Width: | Height: | Size: 134 KiB |
|
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 44 KiB |
|
Before Width: | Height: | Size: 57 KiB After Width: | Height: | Size: 56 KiB |
|
Before Width: | Height: | Size: 50 KiB After Width: | Height: | Size: 50 KiB |
|
Before Width: | Height: | Size: 58 KiB After Width: | Height: | Size: 58 KiB |
|
Before Width: | Height: | Size: 67 KiB After Width: | Height: | Size: 67 KiB |
|
Before Width: | Height: | Size: 58 KiB After Width: | Height: | Size: 57 KiB |
|
Before Width: | Height: | Size: 49 KiB After Width: | Height: | Size: 49 KiB |
|
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 44 KiB |
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
BIN
images/NND.jpg
|
Before Width: | Height: | Size: 155 KiB After Width: | Height: | Size: 154 KiB |
|
Before Width: | Height: | Size: 49 KiB After Width: | Height: | Size: 49 KiB |
|
Before Width: | Height: | Size: 66 KiB After Width: | Height: | Size: 65 KiB |
|
Before Width: | Height: | Size: 95 KiB After Width: | Height: | Size: 94 KiB |
|
Before Width: | Height: | Size: 89 KiB After Width: | Height: | Size: 88 KiB |
|
Before Width: | Height: | Size: 112 KiB After Width: | Height: | Size: 111 KiB |
|
Before Width: | Height: | Size: 157 KiB After Width: | Height: | Size: 156 KiB |
|
Before Width: | Height: | Size: 59 KiB After Width: | Height: | Size: 58 KiB |
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 112 KiB After Width: | Height: | Size: 111 KiB |
|
Before Width: | Height: | Size: 214 KiB After Width: | Height: | Size: 212 KiB |
|
Before Width: | Height: | Size: 210 KiB After Width: | Height: | Size: 209 KiB |
|
Before Width: | Height: | Size: 51 KiB After Width: | Height: | Size: 50 KiB |
|
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 44 KiB |
|
Before Width: | Height: | Size: 154 KiB After Width: | Height: | Size: 154 KiB |
|
Before Width: | Height: | Size: 133 KiB After Width: | Height: | Size: 132 KiB |
|
Before Width: | Height: | Size: 55 KiB After Width: | Height: | Size: 55 KiB |
BIN
images/m0_01.jpg
|
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.9 KiB |
BIN
images/m0_02.jpg
|
Before Width: | Height: | Size: 382 B After Width: | Height: | Size: 379 B |
BIN
images/m0_03.jpg
|
Before Width: | Height: | Size: 368 B After Width: | Height: | Size: 368 B |
BIN
images/m0_04.jpg
|
Before Width: | Height: | Size: 408 B After Width: | Height: | Size: 403 B |
BIN
images/m0_05.jpg
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 1.9 KiB |
BIN
images/m0_06.jpg
|
Before Width: | Height: | Size: 436 B After Width: | Height: | Size: 429 B |
BIN
images/m0_07.jpg
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 1.7 KiB |
BIN
images/m0_08.jpg
|
Before Width: | Height: | Size: 436 B After Width: | Height: | Size: 429 B |
BIN
images/m0_09.jpg
|
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 2.1 KiB |
BIN
images/m0_10.jpg
|
Before Width: | Height: | Size: 436 B After Width: | Height: | Size: 430 B |
BIN
images/m0_11.jpg
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 1.8 KiB |
BIN
images/m0_12.jpg
|
Before Width: | Height: | Size: 436 B After Width: | Height: | Size: 430 B |
BIN
images/m0_13.jpg
|
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 2.6 KiB |
BIN
images/m0_14.jpg
|
Before Width: | Height: | Size: 436 B After Width: | Height: | Size: 430 B |
BIN
images/m1_01.jpg
|
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.9 KiB |
BIN
images/m1_02.jpg
|
Before Width: | Height: | Size: 483 B After Width: | Height: | Size: 473 B |
BIN
images/m1_03.jpg
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.0 KiB |
BIN
images/m1_04.jpg
|
Before Width: | Height: | Size: 483 B After Width: | Height: | Size: 474 B |
BIN
images/m1_05.jpg
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 1.9 KiB |
BIN
images/m1_06.jpg
|
Before Width: | Height: | Size: 483 B After Width: | Height: | Size: 473 B |
BIN
images/m1_07.jpg
|
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 2.2 KiB |
BIN
images/m1_08.jpg
|
Before Width: | Height: | Size: 483 B After Width: | Height: | Size: 467 B |
BIN
images/m1_09.jpg
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.0 KiB |
BIN
images/m1_10.jpg
|
Before Width: | Height: | Size: 483 B After Width: | Height: | Size: 467 B |
BIN
images/m1_11.jpg
|
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 2.7 KiB |
BIN
images/m1_12.jpg
|
Before Width: | Height: | Size: 483 B After Width: | Height: | Size: 467 B |
BIN
images/m1_15.jpg
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 340 B |
|
Before Width: | Height: | Size: 340 B |
|
Before Width: | Height: | Size: 4.3 KiB After Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 5.0 KiB After Width: | Height: | Size: 4.6 KiB |
|
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 5.8 KiB After Width: | Height: | Size: 5.4 KiB |
|
Before Width: | Height: | Size: 5.6 KiB After Width: | Height: | Size: 5.2 KiB |
|
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 3.6 KiB |
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 430 B After Width: | Height: | Size: 430 B |
|
Before Width: | Height: | Size: 4.3 KiB After Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 5.2 KiB After Width: | Height: | Size: 4.9 KiB |
|
Before Width: | Height: | Size: 5.8 KiB After Width: | Height: | Size: 5.4 KiB |
|
Before Width: | Height: | Size: 5.8 KiB After Width: | Height: | Size: 5.4 KiB |
|
Before Width: | Height: | Size: 5.6 KiB After Width: | Height: | Size: 5.2 KiB |
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 44 KiB |
|
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 3.1 KiB |
|
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 3.1 KiB |
|
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 3.0 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 3.7 KiB |
|
Before Width: | Height: | Size: 4.6 KiB After Width: | Height: | Size: 4.5 KiB |
BIN
images/skoda.jpg
|
Before Width: | Height: | Size: 112 KiB After Width: | Height: | Size: 111 KiB |
|
Before Width: | Height: | Size: 79 KiB After Width: | Height: | Size: 78 KiB |
|
Before Width: | Height: | Size: 67 KiB After Width: | Height: | Size: 66 KiB |
|
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 35 KiB |
|
Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 41 KiB |
|
Before Width: | Height: | Size: 54 KiB After Width: | Height: | Size: 53 KiB |
|
Before Width: | Height: | Size: 7.2 KiB After Width: | Height: | Size: 7.0 KiB |
|
Before Width: | Height: | Size: 7.9 KiB After Width: | Height: | Size: 7.6 KiB |
|
Before Width: | Height: | Size: 9.0 KiB After Width: | Height: | Size: 8.7 KiB |
|
Before Width: | Height: | Size: 8.7 KiB After Width: | Height: | Size: 8.2 KiB |
|
Before Width: | Height: | Size: 8.8 KiB After Width: | Height: | Size: 8.5 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 9.7 KiB |
BIN
images/t1_01.jpg
|
Before Width: | Height: | Size: 610 B After Width: | Height: | Size: 605 B |
BIN
images/t1_02.jpg
|
Before Width: | Height: | Size: 331 B After Width: | Height: | Size: 331 B |
BIN
images/t1_03.jpg
|
Before Width: | Height: | Size: 479 B After Width: | Height: | Size: 474 B |