|
@@ -1,6 +1,6 @@
|
|
|
-
|
|
|
|
|
-import React, { useState, useEffect, useRef } from 'react';
|
|
|
|
|
-import { useNavigate, useLocation, Link } from 'react-router-dom';
|
|
|
|
|
|
|
+import React, { useState, useEffect, useRef } from "react";
|
|
|
|
|
+import { useNavigate, useLocation, Link } from "react-router-dom";
|
|
|
|
|
+import logo from "../assets/img/getgo.svg";
|
|
|
|
|
|
|
|
const Header: React.FC = () => {
|
|
const Header: React.FC = () => {
|
|
|
const navigate = useNavigate();
|
|
const navigate = useNavigate();
|
|
@@ -11,81 +11,103 @@ const Header: React.FC = () => {
|
|
|
const [isBuySimMegaVisible, setIsBuySimMegaVisible] = useState(false);
|
|
const [isBuySimMegaVisible, setIsBuySimMegaVisible] = useState(false);
|
|
|
const [isGuideMegaVisible, setIsGuideMegaVisible] = useState(false);
|
|
const [isGuideMegaVisible, setIsGuideMegaVisible] = useState(false);
|
|
|
const [isLangMenuOpen, setIsLangMenuOpen] = useState(false);
|
|
const [isLangMenuOpen, setIsLangMenuOpen] = useState(false);
|
|
|
- const [selectedLang, setSelectedLang] = useState<'en' | 'vi'>('en');
|
|
|
|
|
- const [activeDesktopTab, setActiveDesktopTab] = useState<'popular' | 'region'>('popular');
|
|
|
|
|
|
|
+ const [selectedLang, setSelectedLang] = useState<"en" | "vi">("en");
|
|
|
|
|
+ const [activeDesktopTab, setActiveDesktopTab] = useState<
|
|
|
|
|
+ "popular" | "region"
|
|
|
|
|
+ >("popular");
|
|
|
const [isScrolled, setIsScrolled] = useState(false);
|
|
const [isScrolled, setIsScrolled] = useState(false);
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
const langMenuRef = useRef<HTMLDivElement>(null);
|
|
const langMenuRef = useRef<HTMLDivElement>(null);
|
|
|
|
|
|
|
|
const countries = [
|
|
const countries = [
|
|
|
- { name: 'China', flag: 'cn' },
|
|
|
|
|
- { name: 'Hong Kong', flag: 'hk' },
|
|
|
|
|
- { name: 'Japan', flag: 'jp' },
|
|
|
|
|
- { name: 'Singapore', flag: 'sg' },
|
|
|
|
|
- { name: 'South Korea', flag: 'kr' },
|
|
|
|
|
- { name: 'Taiwan', flag: 'tw' },
|
|
|
|
|
- { name: 'Thailand', flag: 'th' },
|
|
|
|
|
- { name: 'United States', flag: 'us' },
|
|
|
|
|
|
|
+ { name: "China", flag: "cn" },
|
|
|
|
|
+ { name: "Hong Kong", flag: "hk" },
|
|
|
|
|
+ { name: "Japan", flag: "jp" },
|
|
|
|
|
+ { name: "Singapore", flag: "sg" },
|
|
|
|
|
+ { name: "South Korea", flag: "kr" },
|
|
|
|
|
+ { name: "Taiwan", flag: "tw" },
|
|
|
|
|
+ { name: "Thailand", flag: "th" },
|
|
|
|
|
+ { name: "United States", flag: "us" },
|
|
|
];
|
|
];
|
|
|
|
|
|
|
|
const regionList = [
|
|
const regionList = [
|
|
|
- "Americas", "Asia", "Asia 11 countries", "Asialink 7 countries",
|
|
|
|
|
- "Australia & New Zealand", "EU 33 countries", "EU 40 countries", "Eurolink",
|
|
|
|
|
- "Europe", "Europe 33 countries", "Hong Kong & Macau", "Middle East and Africa",
|
|
|
|
|
- "North America & Canada", "North America A", "Oceania", "Singapore & Malaysia"
|
|
|
|
|
|
|
+ "Americas",
|
|
|
|
|
+ "Asia",
|
|
|
|
|
+ "Asia 11 countries",
|
|
|
|
|
+ "Asialink 7 countries",
|
|
|
|
|
+ "Australia & New Zealand",
|
|
|
|
|
+ "EU 33 countries",
|
|
|
|
|
+ "EU 40 countries",
|
|
|
|
|
+ "Eurolink",
|
|
|
|
|
+ "Europe",
|
|
|
|
|
+ "Europe 33 countries",
|
|
|
|
|
+ "Hong Kong & Macau",
|
|
|
|
|
+ "Middle East and Africa",
|
|
|
|
|
+ "North America & Canada",
|
|
|
|
|
+ "North America A",
|
|
|
|
|
+ "Oceania",
|
|
|
|
|
+ "Singapore & Malaysia",
|
|
|
];
|
|
];
|
|
|
|
|
|
|
|
const guideItems = [
|
|
const guideItems = [
|
|
|
{ label: "What is eSIM", path: "/support" },
|
|
{ label: "What is eSIM", path: "/support" },
|
|
|
{ label: "Installation instructions", path: "/support" },
|
|
{ label: "Installation instructions", path: "/support" },
|
|
|
{ label: "Support", path: "/support" },
|
|
{ label: "Support", path: "/support" },
|
|
|
- { label: "Order Tracking Search", path: "/support" }
|
|
|
|
|
|
|
+ { label: "Order Tracking Search", path: "/support" },
|
|
|
];
|
|
];
|
|
|
|
|
|
|
|
const languages = [
|
|
const languages = [
|
|
|
- { code: 'en', label: 'English', flag: 'us' },
|
|
|
|
|
- { code: 'vi', label: 'Tiếng Việt', flag: 'vn' }
|
|
|
|
|
|
|
+ { code: "en", label: "English", flag: "us" },
|
|
|
|
|
+ { code: "vi", label: "Tiếng Việt", flag: "vn" },
|
|
|
];
|
|
];
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
useEffect(() => {
|
|
|
const handleScroll = () => {
|
|
const handleScroll = () => {
|
|
|
setIsScrolled(window.scrollY > 300);
|
|
setIsScrolled(window.scrollY > 300);
|
|
|
};
|
|
};
|
|
|
- window.addEventListener('scroll', handleScroll);
|
|
|
|
|
- return () => window.removeEventListener('scroll', handleScroll);
|
|
|
|
|
|
|
+ window.addEventListener("scroll", handleScroll);
|
|
|
|
|
+ return () => window.removeEventListener("scroll", handleScroll);
|
|
|
}, []);
|
|
}, []);
|
|
|
|
|
|
|
|
const handleCountryClick = (c: { name: string; flag: string }) => {
|
|
const handleCountryClick = (c: { name: string; flag: string }) => {
|
|
|
- navigate(`/product/${c.name.toLowerCase()}`, { state: { country: c.name, flag: c.flag } });
|
|
|
|
|
|
|
+ navigate(`/product/${c.name.toLowerCase()}`, {
|
|
|
|
|
+ state: { country: c.name, flag: c.flag },
|
|
|
|
|
+ });
|
|
|
setIsBuySimMegaVisible(false);
|
|
setIsBuySimMegaVisible(false);
|
|
|
setIsMenuOpen(false);
|
|
setIsMenuOpen(false);
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
const handleRegionClick = (region: string) => {
|
|
const handleRegionClick = (region: string) => {
|
|
|
- navigate(`/product/${region.toLowerCase()}`, { state: { country: region, flag: 'un' } });
|
|
|
|
|
|
|
+ navigate(`/product/${region.toLowerCase()}`, {
|
|
|
|
|
+ state: { country: region, flag: "un" },
|
|
|
|
|
+ });
|
|
|
setIsBuySimMegaVisible(false);
|
|
setIsBuySimMegaVisible(false);
|
|
|
setIsMenuOpen(false);
|
|
setIsMenuOpen(false);
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
useEffect(() => {
|
|
|
const handleClickOutside = (event: MouseEvent) => {
|
|
const handleClickOutside = (event: MouseEvent) => {
|
|
|
- if (langMenuRef.current && !langMenuRef.current.contains(event.target as Node)) {
|
|
|
|
|
|
|
+ if (
|
|
|
|
|
+ langMenuRef.current &&
|
|
|
|
|
+ !langMenuRef.current.contains(event.target as Node)
|
|
|
|
|
+ ) {
|
|
|
setIsLangMenuOpen(false);
|
|
setIsLangMenuOpen(false);
|
|
|
}
|
|
}
|
|
|
};
|
|
};
|
|
|
- document.addEventListener('mousedown', handleClickOutside);
|
|
|
|
|
- return () => document.removeEventListener('mousedown', handleClickOutside);
|
|
|
|
|
|
|
+ document.addEventListener("mousedown", handleClickOutside);
|
|
|
|
|
+ return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
|
}, []);
|
|
}, []);
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
useEffect(() => {
|
|
|
const handleResize = () => {
|
|
const handleResize = () => {
|
|
|
if (window.innerWidth >= 1024) setIsMenuOpen(false);
|
|
if (window.innerWidth >= 1024) setIsMenuOpen(false);
|
|
|
};
|
|
};
|
|
|
- window.addEventListener('resize', handleResize);
|
|
|
|
|
- return () => window.removeEventListener('resize', handleResize);
|
|
|
|
|
|
|
+ window.addEventListener("resize", handleResize);
|
|
|
|
|
+ return () => window.removeEventListener("resize", handleResize);
|
|
|
}, []);
|
|
}, []);
|
|
|
|
|
|
|
|
- const currentLangObj = languages.find(l => l.code === selectedLang) || languages[0];
|
|
|
|
|
|
|
+ const currentLangObj =
|
|
|
|
|
+ languages.find((l) => l.code === selectedLang) || languages[0];
|
|
|
|
|
|
|
|
const isActive = (path: string) => location.pathname === path;
|
|
const isActive = (path: string) => location.pathname === path;
|
|
|
|
|
|
|
@@ -97,96 +119,184 @@ const Header: React.FC = () => {
|
|
|
{/* Logo */}
|
|
{/* Logo */}
|
|
|
<Link to="/" className="flex-shrink-0 flex items-center">
|
|
<Link to="/" className="flex-shrink-0 flex items-center">
|
|
|
<div className="flex items-center space-x-1">
|
|
<div className="flex items-center space-x-1">
|
|
|
- <svg className="w-8 h-8 text-[#EE0434]" viewBox="0 0 24 24" fill="currentColor">
|
|
|
|
|
|
|
+ {/* <svg className="w-8 h-8 text-[#EE0434]" viewBox="0 0 24 24" fill="currentColor">
|
|
|
<path d="M12 2L2 7l10 5 10-5-10-5zM2 17l10 5 10-5M2 12l10 5 10-5" />
|
|
<path d="M12 2L2 7l10 5 10-5-10-5zM2 17l10 5 10-5M2 12l10 5 10-5" />
|
|
|
- </svg>
|
|
|
|
|
- <span className="text-2xl font-bold tracking-tighter">
|
|
|
|
|
|
|
+ </svg> */}
|
|
|
|
|
+ <img src={logo} alt="InfiGate Logo" className="w-35" />
|
|
|
|
|
+ {/* <span className="text-2xl font-bold tracking-tighter">
|
|
|
<span className="text-[#EE0434]">Infi</span>
|
|
<span className="text-[#EE0434]">Infi</span>
|
|
|
<span className="text-[#333]">Gate</span>
|
|
<span className="text-[#333]">Gate</span>
|
|
|
- </span>
|
|
|
|
|
|
|
+ </span> */}
|
|
|
</div>
|
|
</div>
|
|
|
</Link>
|
|
</Link>
|
|
|
|
|
|
|
|
{/* Desktop Search on Scroll */}
|
|
{/* Desktop Search on Scroll */}
|
|
|
- <div className={`hidden lg:flex items-center transition-all duration-500 overflow-hidden ${isScrolled ? 'flex-1 max-w-md mx-8 opacity-100' : 'max-w-0 opacity-0 pointer-events-none'}`}>
|
|
|
|
|
- <div className="relative w-full">
|
|
|
|
|
- <input
|
|
|
|
|
- type="text"
|
|
|
|
|
- placeholder="Search country..."
|
|
|
|
|
- className="w-full bg-slate-50 border border-slate-200 rounded-full py-2.5 px-6 pl-12 text-sm focus:outline-none focus:ring-2 focus:ring-red-100 focus:border-[#EE0434] transition-all"
|
|
|
|
|
- />
|
|
|
|
|
- <svg className="absolute left-4 top-1/2 -translate-y-1/2 w-4 h-4 text-slate-400" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2.5} d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"/></svg>
|
|
|
|
|
- </div>
|
|
|
|
|
|
|
+ <div
|
|
|
|
|
+ className={`hidden lg:flex items-center transition-all duration-500 overflow-hidden ${
|
|
|
|
|
+ isScrolled
|
|
|
|
|
+ ? "flex-1 max-w-md mx-8 opacity-100"
|
|
|
|
|
+ : "max-w-0 opacity-0 pointer-events-none"
|
|
|
|
|
+ }`}
|
|
|
|
|
+ >
|
|
|
|
|
+ <div className="relative w-full">
|
|
|
|
|
+ <input
|
|
|
|
|
+ type="text"
|
|
|
|
|
+ placeholder="Search country..."
|
|
|
|
|
+ className="w-full bg-slate-50 border border-slate-200 rounded-full py-2.5 px-6 pl-12 text-sm focus:outline-none focus:ring-2 focus:ring-red-100 focus:border-[#EE0434] transition-all"
|
|
|
|
|
+ />
|
|
|
|
|
+ <svg
|
|
|
|
|
+ className="absolute left-4 top-1/2 -translate-y-1/2 w-4 h-4 text-slate-400"
|
|
|
|
|
+ fill="none"
|
|
|
|
|
+ stroke="currentColor"
|
|
|
|
|
+ viewBox="0 0 24 24"
|
|
|
|
|
+ >
|
|
|
|
|
+ <path
|
|
|
|
|
+ strokeLinecap="round"
|
|
|
|
|
+ strokeLinejoin="round"
|
|
|
|
|
+ strokeWidth={2.5}
|
|
|
|
|
+ d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"
|
|
|
|
|
+ />
|
|
|
|
|
+ </svg>
|
|
|
|
|
+ </div>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
{/* Desktop Nav */}
|
|
{/* Desktop Nav */}
|
|
|
- <nav className={`hidden lg:flex items-center h-full transition-all duration-300 ${isScrolled ? 'space-x-4' : 'space-x-8'}`}>
|
|
|
|
|
- <Link to="/" className={`text-[17px] font-bold ${isActive('/') ? 'text-[#EE0434]' : 'text-slate-700 hover:text-[#EE0434]'}`}>Home</Link>
|
|
|
|
|
-
|
|
|
|
|
- <div
|
|
|
|
|
|
|
+ <nav
|
|
|
|
|
+ className={`hidden lg:flex items-center h-full transition-all duration-300 ${
|
|
|
|
|
+ isScrolled ? "space-x-4" : "space-x-8"
|
|
|
|
|
+ }`}
|
|
|
|
|
+ >
|
|
|
|
|
+ <Link
|
|
|
|
|
+ to="/"
|
|
|
|
|
+ className={`text-[17px] font-bold ${
|
|
|
|
|
+ isActive("/")
|
|
|
|
|
+ ? "text-[#EE0434]"
|
|
|
|
|
+ : "text-slate-700 hover:text-[#EE0434]"
|
|
|
|
|
+ }`}
|
|
|
|
|
+ >
|
|
|
|
|
+ Home
|
|
|
|
|
+ </Link>
|
|
|
|
|
+
|
|
|
|
|
+ <div
|
|
|
className="relative h-full flex items-center"
|
|
className="relative h-full flex items-center"
|
|
|
onMouseEnter={() => setIsBuySimMegaVisible(true)}
|
|
onMouseEnter={() => setIsBuySimMegaVisible(true)}
|
|
|
onMouseLeave={() => setIsBuySimMegaVisible(false)}
|
|
onMouseLeave={() => setIsBuySimMegaVisible(false)}
|
|
|
>
|
|
>
|
|
|
- <Link
|
|
|
|
|
|
|
+ <Link
|
|
|
to="/buy-sim"
|
|
to="/buy-sim"
|
|
|
- className={`flex items-center text-[17px] font-bold transition-colors ${isActive('/buy-sim') ? 'text-[#EE0434]' : 'text-slate-700 hover:text-[#EE0434]'}`}
|
|
|
|
|
|
|
+ className={`flex items-center text-[17px] font-bold transition-colors ${
|
|
|
|
|
+ isActive("/buy-sim")
|
|
|
|
|
+ ? "text-[#EE0434]"
|
|
|
|
|
+ : "text-slate-700 hover:text-[#EE0434]"
|
|
|
|
|
+ }`}
|
|
|
>
|
|
>
|
|
|
- Buy SIM <svg className={`ml-1 w-4 h-4 transition-transform ${isBuySimMegaVisible ? 'rotate-180' : ''}`} fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" /></svg>
|
|
|
|
|
|
|
+ Buy SIM{" "}
|
|
|
|
|
+ <svg
|
|
|
|
|
+ className={`ml-1 w-4 h-4 transition-transform ${
|
|
|
|
|
+ isBuySimMegaVisible ? "rotate-180" : ""
|
|
|
|
|
+ }`}
|
|
|
|
|
+ fill="none"
|
|
|
|
|
+ stroke="currentColor"
|
|
|
|
|
+ viewBox="0 0 24 24"
|
|
|
|
|
+ >
|
|
|
|
|
+ <path
|
|
|
|
|
+ strokeLinecap="round"
|
|
|
|
|
+ strokeLinejoin="round"
|
|
|
|
|
+ strokeWidth={2}
|
|
|
|
|
+ d="M19 9l-7 7-7-7"
|
|
|
|
|
+ />
|
|
|
|
|
+ </svg>
|
|
|
</Link>
|
|
</Link>
|
|
|
|
|
|
|
|
{isBuySimMegaVisible && (
|
|
{isBuySimMegaVisible && (
|
|
|
<div className="absolute top-full left-1/2 -translate-x-1/2 w-[950px] bg-white rounded-[32px] shadow-[0_30px_60px_-15px_rgba(0,0,0,0.15)] border border-slate-100 mt-0 overflow-hidden flex animate-in fade-in slide-in-from-top-2 duration-300">
|
|
<div className="absolute top-full left-1/2 -translate-x-1/2 w-[950px] bg-white rounded-[32px] shadow-[0_30px_60px_-15px_rgba(0,0,0,0.15)] border border-slate-100 mt-0 overflow-hidden flex animate-in fade-in slide-in-from-top-2 duration-300">
|
|
|
<div className="w-[280px] bg-red-50 p-10 flex flex-col">
|
|
<div className="w-[280px] bg-red-50 p-10 flex flex-col">
|
|
|
- <h3 className="text-4xl font-black text-slate-900 mb-4">Buy SIM</h3>
|
|
|
|
|
- <button
|
|
|
|
|
|
|
+ <h3 className="text-4xl font-black text-slate-900 mb-4">
|
|
|
|
|
+ Buy SIM
|
|
|
|
|
+ </h3>
|
|
|
|
|
+ <button
|
|
|
onClick={() => {
|
|
onClick={() => {
|
|
|
- navigate('/buy-sim');
|
|
|
|
|
|
|
+ navigate("/buy-sim");
|
|
|
setIsBuySimMegaVisible(false);
|
|
setIsBuySimMegaVisible(false);
|
|
|
}}
|
|
}}
|
|
|
className="text-[#EE0434] font-bold text-xl flex items-center group mb-8"
|
|
className="text-[#EE0434] font-bold text-xl flex items-center group mb-8"
|
|
|
>
|
|
>
|
|
|
- View all <svg className="ml-2 w-5 h-5 transition-transform group-hover:translate-x-1" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={3} d="M9 5l7 7-7 7" /></svg>
|
|
|
|
|
|
|
+ View all{" "}
|
|
|
|
|
+ <svg
|
|
|
|
|
+ className="ml-2 w-5 h-5 transition-transform group-hover:translate-x-1"
|
|
|
|
|
+ fill="none"
|
|
|
|
|
+ stroke="currentColor"
|
|
|
|
|
+ viewBox="0 0 24 24"
|
|
|
|
|
+ >
|
|
|
|
|
+ <path
|
|
|
|
|
+ strokeLinecap="round"
|
|
|
|
|
+ strokeLinejoin="round"
|
|
|
|
|
+ strokeWidth={3}
|
|
|
|
|
+ d="M9 5l7 7-7 7"
|
|
|
|
|
+ />
|
|
|
|
|
+ </svg>
|
|
|
</button>
|
|
</button>
|
|
|
</div>
|
|
</div>
|
|
|
<div className="flex-1 p-10">
|
|
<div className="flex-1 p-10">
|
|
|
<div className="flex space-x-4 mb-10">
|
|
<div className="flex space-x-4 mb-10">
|
|
|
- <button
|
|
|
|
|
- onClick={() => setActiveDesktopTab('popular')}
|
|
|
|
|
- className={`px-8 py-3 rounded-full text-base font-bold transition-all ${activeDesktopTab === 'popular' ? 'bg-[#EE0434] text-white shadow-lg shadow-red-100' : 'bg-slate-50 text-slate-900 hover:bg-slate-100'}`}
|
|
|
|
|
|
|
+ <button
|
|
|
|
|
+ onClick={() => setActiveDesktopTab("popular")}
|
|
|
|
|
+ className={`px-8 py-3 rounded-full text-base font-bold transition-all ${
|
|
|
|
|
+ activeDesktopTab === "popular"
|
|
|
|
|
+ ? "bg-[#EE0434] text-white shadow-lg shadow-red-100"
|
|
|
|
|
+ : "bg-slate-50 text-slate-900 hover:bg-slate-100"
|
|
|
|
|
+ }`}
|
|
|
>
|
|
>
|
|
|
Most Popular
|
|
Most Popular
|
|
|
</button>
|
|
</button>
|
|
|
- <button
|
|
|
|
|
- onClick={() => setActiveDesktopTab('region')}
|
|
|
|
|
- className={`px-8 py-3 rounded-full text-base font-bold transition-all ${activeDesktopTab === 'region' ? 'bg-[#EE0434] text-white shadow-lg shadow-red-100' : 'bg-slate-50 text-slate-900 hover:bg-slate-100'}`}
|
|
|
|
|
|
|
+ <button
|
|
|
|
|
+ onClick={() => setActiveDesktopTab("region")}
|
|
|
|
|
+ className={`px-8 py-3 rounded-full text-base font-bold transition-all ${
|
|
|
|
|
+ activeDesktopTab === "region"
|
|
|
|
|
+ ? "bg-[#EE0434] text-white shadow-lg shadow-red-100"
|
|
|
|
|
+ : "bg-slate-50 text-slate-900 hover:bg-slate-100"
|
|
|
|
|
+ }`}
|
|
|
>
|
|
>
|
|
|
Region
|
|
Region
|
|
|
</button>
|
|
</button>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
- {activeDesktopTab === 'popular' ? (
|
|
|
|
|
|
|
+ {activeDesktopTab === "popular" ? (
|
|
|
<div className="grid grid-cols-4 gap-y-8 gap-x-4">
|
|
<div className="grid grid-cols-4 gap-y-8 gap-x-4">
|
|
|
{countries.map((c) => (
|
|
{countries.map((c) => (
|
|
|
- <div key={c.name} onClick={() => handleCountryClick(c)} className="flex items-center space-x-3 group cursor-pointer hover:bg-slate-50 p-2 rounded-xl transition-colors">
|
|
|
|
|
|
|
+ <div
|
|
|
|
|
+ key={c.name}
|
|
|
|
|
+ onClick={() => handleCountryClick(c)}
|
|
|
|
|
+ className="flex items-center space-x-3 group cursor-pointer hover:bg-slate-50 p-2 rounded-xl transition-colors"
|
|
|
|
|
+ >
|
|
|
<div className="w-7 h-7 rounded-full overflow-hidden border border-slate-200 shadow-sm shrink-0">
|
|
<div className="w-7 h-7 rounded-full overflow-hidden border border-slate-200 shadow-sm shrink-0">
|
|
|
- <img src={`https://flagcdn.com/w40/${c.flag}.png`} alt={c.name} className="w-full h-full object-cover" />
|
|
|
|
|
|
|
+ <img
|
|
|
|
|
+ src={`https://flagcdn.com/w40/${c.flag}.png`}
|
|
|
|
|
+ alt={c.name}
|
|
|
|
|
+ className="w-full h-full object-cover"
|
|
|
|
|
+ />
|
|
|
</div>
|
|
</div>
|
|
|
- <span className="text-[16px] font-bold text-slate-700 group-hover:text-[#EE0434] transition-colors">{c.name}</span>
|
|
|
|
|
|
|
+ <span className="text-[16px] font-bold text-slate-700 group-hover:text-[#EE0434] transition-colors">
|
|
|
|
|
+ {c.name}
|
|
|
|
|
+ </span>
|
|
|
</div>
|
|
</div>
|
|
|
))}
|
|
))}
|
|
|
</div>
|
|
</div>
|
|
|
) : (
|
|
) : (
|
|
|
<div className="grid grid-cols-4 gap-y-6 gap-x-2">
|
|
<div className="grid grid-cols-4 gap-y-6 gap-x-2">
|
|
|
{regionList.map((region) => (
|
|
{regionList.map((region) => (
|
|
|
- <div
|
|
|
|
|
- key={region}
|
|
|
|
|
- onClick={() => handleRegionClick(region)}
|
|
|
|
|
|
|
+ <div
|
|
|
|
|
+ key={region}
|
|
|
|
|
+ onClick={() => handleRegionClick(region)}
|
|
|
className="flex items-center space-x-3 group cursor-pointer hover:bg-slate-50 p-2 rounded-xl transition-colors min-w-0"
|
|
className="flex items-center space-x-3 group cursor-pointer hover:bg-slate-50 p-2 rounded-xl transition-colors min-w-0"
|
|
|
>
|
|
>
|
|
|
<div className="w-7 h-7 rounded-full bg-red-50 flex items-center justify-center shrink-0 border border-red-100/50">
|
|
<div className="w-7 h-7 rounded-full bg-red-50 flex items-center justify-center shrink-0 border border-red-100/50">
|
|
|
- <svg className="w-4 h-4 text-red-300" fill="currentColor" viewBox="0 0 24 24">
|
|
|
|
|
- <path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-1 17.93c-3.95-.49-7.01-3.55-7.5-7.5H7v-1H3.5c.49-3.95 3.55-7.01 7.5-7.5v3.5h1V3.5c3.95.49 7.01 3.55 7.5 7.5H17v1h3.5c-.49 3.95-3.55-7.01-7.5 7.5v-3.5h-1v3.5z"/>
|
|
|
|
|
|
|
+ <svg
|
|
|
|
|
+ className="w-4 h-4 text-red-300"
|
|
|
|
|
+ fill="currentColor"
|
|
|
|
|
+ viewBox="0 0 24 24"
|
|
|
|
|
+ >
|
|
|
|
|
+ <path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-1 17.93c-3.95-.49-7.01-3.55-7.5-7.5H7v-1H3.5c.49-3.95 3.55-7.01 7.5-7.5v3.5h1V3.5c3.95.49 7.01 3.55 7.5 7.5H17v1h3.5c-.49 3.95-3.55-7.01-7.5 7.5v-3.5h-1v3.5z" />
|
|
|
</svg>
|
|
</svg>
|
|
|
</div>
|
|
</div>
|
|
|
<span className="text-[16px] font-bold text-slate-700 group-hover:text-[#EE0434] transition-colors truncate">
|
|
<span className="text-[16px] font-bold text-slate-700 group-hover:text-[#EE0434] transition-colors truncate">
|
|
@@ -201,24 +311,43 @@ const Header: React.FC = () => {
|
|
|
)}
|
|
)}
|
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
- <div
|
|
|
|
|
|
|
+ <div
|
|
|
className="relative h-full flex items-center"
|
|
className="relative h-full flex items-center"
|
|
|
onMouseEnter={() => setIsGuideMegaVisible(true)}
|
|
onMouseEnter={() => setIsGuideMegaVisible(true)}
|
|
|
onMouseLeave={() => setIsGuideMegaVisible(false)}
|
|
onMouseLeave={() => setIsGuideMegaVisible(false)}
|
|
|
>
|
|
>
|
|
|
- <Link
|
|
|
|
|
|
|
+ <Link
|
|
|
to="/support"
|
|
to="/support"
|
|
|
- className={`flex items-center text-[17px] font-bold transition-colors ${isActive('/support') ? 'text-[#EE0434]' : 'text-slate-700 hover:text-[#EE0434]'}`}
|
|
|
|
|
|
|
+ className={`flex items-center text-[17px] font-bold transition-colors ${
|
|
|
|
|
+ isActive("/support")
|
|
|
|
|
+ ? "text-[#EE0434]"
|
|
|
|
|
+ : "text-slate-700 hover:text-[#EE0434]"
|
|
|
|
|
+ }`}
|
|
|
>
|
|
>
|
|
|
- Guide <svg className={`ml-1 w-4 h-4 transition-transform ${isGuideMegaVisible ? 'rotate-180' : ''}`} fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" /></svg>
|
|
|
|
|
|
|
+ Guide{" "}
|
|
|
|
|
+ <svg
|
|
|
|
|
+ className={`ml-1 w-4 h-4 transition-transform ${
|
|
|
|
|
+ isGuideMegaVisible ? "rotate-180" : ""
|
|
|
|
|
+ }`}
|
|
|
|
|
+ fill="none"
|
|
|
|
|
+ stroke="currentColor"
|
|
|
|
|
+ viewBox="0 0 24 24"
|
|
|
|
|
+ >
|
|
|
|
|
+ <path
|
|
|
|
|
+ strokeLinecap="round"
|
|
|
|
|
+ strokeLinejoin="round"
|
|
|
|
|
+ strokeWidth={2}
|
|
|
|
|
+ d="M19 9l-7 7-7-7"
|
|
|
|
|
+ />
|
|
|
|
|
+ </svg>
|
|
|
</Link>
|
|
</Link>
|
|
|
|
|
|
|
|
{isGuideMegaVisible && (
|
|
{isGuideMegaVisible && (
|
|
|
<div className="absolute top-full left-0 w-[600px] bg-white rounded-[32px] shadow-2xl border border-slate-100 mt-0 overflow-hidden flex animate-in fade-in slide-in-from-top-2 duration-300">
|
|
<div className="absolute top-full left-0 w-[600px] bg-white rounded-[32px] shadow-2xl border border-slate-100 mt-0 overflow-hidden flex animate-in fade-in slide-in-from-top-2 duration-300">
|
|
|
<div className="flex-1 py-10 px-6 flex flex-col">
|
|
<div className="flex-1 py-10 px-6 flex flex-col">
|
|
|
{guideItems.map((item, idx) => (
|
|
{guideItems.map((item, idx) => (
|
|
|
- <button
|
|
|
|
|
- key={item.label}
|
|
|
|
|
|
|
+ <button
|
|
|
|
|
+ key={item.label}
|
|
|
onClick={() => {
|
|
onClick={() => {
|
|
|
navigate(item.path);
|
|
navigate(item.path);
|
|
|
setIsGuideMegaVisible(false);
|
|
setIsGuideMegaVisible(false);
|
|
@@ -233,16 +362,24 @@ const Header: React.FC = () => {
|
|
|
)}
|
|
)}
|
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
- <Link
|
|
|
|
|
|
|
+ <Link
|
|
|
to="/news"
|
|
to="/news"
|
|
|
- className={`text-[17px] font-bold transition-colors ${isActive('/news') ? 'text-[#EE0434]' : 'text-slate-700 hover:text-[#EE0434]'}`}
|
|
|
|
|
|
|
+ className={`text-[17px] font-bold transition-colors ${
|
|
|
|
|
+ isActive("/news")
|
|
|
|
|
+ ? "text-[#EE0434]"
|
|
|
|
|
+ : "text-slate-700 hover:text-[#EE0434]"
|
|
|
|
|
+ }`}
|
|
|
>
|
|
>
|
|
|
News
|
|
News
|
|
|
</Link>
|
|
</Link>
|
|
|
-
|
|
|
|
|
- <Link
|
|
|
|
|
|
|
+
|
|
|
|
|
+ <Link
|
|
|
to="/contact"
|
|
to="/contact"
|
|
|
- className={`text-[17px] font-bold transition-colors ${isActive('/contact') ? 'text-[#EE0434]' : 'text-slate-700 hover:text-[#EE0434]'}`}
|
|
|
|
|
|
|
+ className={`text-[17px] font-bold transition-colors ${
|
|
|
|
|
+ isActive("/contact")
|
|
|
|
|
+ ? "text-[#EE0434]"
|
|
|
|
|
+ : "text-slate-700 hover:text-[#EE0434]"
|
|
|
|
|
+ }`}
|
|
|
>
|
|
>
|
|
|
Contact
|
|
Contact
|
|
|
</Link>
|
|
</Link>
|
|
@@ -250,26 +387,52 @@ const Header: React.FC = () => {
|
|
|
|
|
|
|
|
{/* Icons */}
|
|
{/* Icons */}
|
|
|
<div className="flex items-center space-x-5">
|
|
<div className="flex items-center space-x-5">
|
|
|
- <Link
|
|
|
|
|
|
|
+ <Link
|
|
|
to="/login"
|
|
to="/login"
|
|
|
className="p-2 text-slate-700 hover:text-[#EE0434] transition-colors"
|
|
className="p-2 text-slate-700 hover:text-[#EE0434] transition-colors"
|
|
|
>
|
|
>
|
|
|
- <svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z" /></svg>
|
|
|
|
|
|
|
+ <svg
|
|
|
|
|
+ className="w-6 h-6"
|
|
|
|
|
+ fill="none"
|
|
|
|
|
+ stroke="currentColor"
|
|
|
|
|
+ viewBox="0 0 24 24"
|
|
|
|
|
+ >
|
|
|
|
|
+ <path
|
|
|
|
|
+ strokeLinecap="round"
|
|
|
|
|
+ strokeLinejoin="round"
|
|
|
|
|
+ strokeWidth={2}
|
|
|
|
|
+ d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z"
|
|
|
|
|
+ />
|
|
|
|
|
+ </svg>
|
|
|
</Link>
|
|
</Link>
|
|
|
<button className="hidden sm:flex p-2 text-slate-700 hover:text-[#EE0434] relative">
|
|
<button className="hidden sm:flex p-2 text-slate-700 hover:text-[#EE0434] relative">
|
|
|
- <svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M3 3h2l.4 2M7 13h10l4-8H5.4M7 13L5.4 5M7 13l-2.293 2.293c-.63.63-.184 1.707.707 1.707H17m0 0a2 2 0 100 4 2 2 0 000-4zm-8 2a2 2 0 11-4 0 2 2 0 014 0z" /></svg>
|
|
|
|
|
- <span className="absolute top-1 right-1 w-4 h-4 bg-[#EE0434] text-white text-[10px] flex items-center justify-center rounded-full font-black">0</span>
|
|
|
|
|
|
|
+ <svg
|
|
|
|
|
+ className="w-6 h-6"
|
|
|
|
|
+ fill="none"
|
|
|
|
|
+ stroke="currentColor"
|
|
|
|
|
+ viewBox="0 0 24 24"
|
|
|
|
|
+ >
|
|
|
|
|
+ <path
|
|
|
|
|
+ strokeLinecap="round"
|
|
|
|
|
+ strokeLinejoin="round"
|
|
|
|
|
+ strokeWidth={2}
|
|
|
|
|
+ d="M3 3h2l.4 2M7 13h10l4-8H5.4M7 13L5.4 5M7 13l-2.293 2.293c-.63.63-.184 1.707.707 1.707H17m0 0a2 2 0 100 4 2 2 0 000-4zm-8 2a2 2 0 11-4 0 2 2 0 014 0z"
|
|
|
|
|
+ />
|
|
|
|
|
+ </svg>
|
|
|
|
|
+ <span className="absolute top-1 right-1 w-4 h-4 bg-[#EE0434] text-white text-[10px] flex items-center justify-center rounded-full font-black">
|
|
|
|
|
+ 0
|
|
|
|
|
+ </span>
|
|
|
</button>
|
|
</button>
|
|
|
|
|
|
|
|
<div className="relative" ref={langMenuRef}>
|
|
<div className="relative" ref={langMenuRef}>
|
|
|
- <button
|
|
|
|
|
|
|
+ <button
|
|
|
onClick={() => setIsLangMenuOpen(!isLangMenuOpen)}
|
|
onClick={() => setIsLangMenuOpen(!isLangMenuOpen)}
|
|
|
className="bg-white p-1 rounded-2xl border border-slate-100 shadow-sm hover:shadow-md transition-all flex items-center justify-center"
|
|
className="bg-white p-1 rounded-2xl border border-slate-100 shadow-sm hover:shadow-md transition-all flex items-center justify-center"
|
|
|
>
|
|
>
|
|
|
<div className="w-8 h-8 rounded-full overflow-hidden border border-slate-50">
|
|
<div className="w-8 h-8 rounded-full overflow-hidden border border-slate-50">
|
|
|
- <img
|
|
|
|
|
- src={`https://flagcdn.com/w80/${currentLangObj.flag}.png`}
|
|
|
|
|
- alt={currentLangObj.label}
|
|
|
|
|
|
|
+ <img
|
|
|
|
|
+ src={`https://flagcdn.com/w80/${currentLangObj.flag}.png`}
|
|
|
|
|
+ alt={currentLangObj.label}
|
|
|
className="w-full h-full object-cover"
|
|
className="w-full h-full object-cover"
|
|
|
/>
|
|
/>
|
|
|
</div>
|
|
</div>
|
|
@@ -282,21 +445,29 @@ const Header: React.FC = () => {
|
|
|
<button
|
|
<button
|
|
|
key={lang.code}
|
|
key={lang.code}
|
|
|
onClick={() => {
|
|
onClick={() => {
|
|
|
- setSelectedLang(lang.code as 'en' | 'vi');
|
|
|
|
|
|
|
+ setSelectedLang(lang.code as "en" | "vi");
|
|
|
setIsLangMenuOpen(false);
|
|
setIsLangMenuOpen(false);
|
|
|
}}
|
|
}}
|
|
|
className={`flex items-center space-x-3 px-5 py-4 w-full text-left transition-colors ${
|
|
className={`flex items-center space-x-3 px-5 py-4 w-full text-left transition-colors ${
|
|
|
- selectedLang === lang.code ? 'bg-slate-50' : 'hover:bg-slate-50/50'
|
|
|
|
|
|
|
+ selectedLang === lang.code
|
|
|
|
|
+ ? "bg-slate-50"
|
|
|
|
|
+ : "hover:bg-slate-50/50"
|
|
|
}`}
|
|
}`}
|
|
|
>
|
|
>
|
|
|
<div className="w-7 h-7 rounded-full overflow-hidden border border-slate-100 shadow-sm">
|
|
<div className="w-7 h-7 rounded-full overflow-hidden border border-slate-100 shadow-sm">
|
|
|
- <img
|
|
|
|
|
- src={`https://flagcdn.com/w80/${lang.flag}.png`}
|
|
|
|
|
- alt={lang.label}
|
|
|
|
|
|
|
+ <img
|
|
|
|
|
+ src={`https://flagcdn.com/w80/${lang.flag}.png`}
|
|
|
|
|
+ alt={lang.label}
|
|
|
className="w-full h-full object-cover"
|
|
className="w-full h-full object-cover"
|
|
|
/>
|
|
/>
|
|
|
</div>
|
|
</div>
|
|
|
- <span className={`text-[15px] font-bold ${selectedLang === lang.code ? 'text-slate-900' : 'text-slate-500'}`}>
|
|
|
|
|
|
|
+ <span
|
|
|
|
|
+ className={`text-[15px] font-bold ${
|
|
|
|
|
+ selectedLang === lang.code
|
|
|
|
|
+ ? "text-slate-900"
|
|
|
|
|
+ : "text-slate-500"
|
|
|
|
|
+ }`}
|
|
|
|
|
+ >
|
|
|
{lang.label}
|
|
{lang.label}
|
|
|
</span>
|
|
</span>
|
|
|
</button>
|
|
</button>
|
|
@@ -306,8 +477,23 @@ const Header: React.FC = () => {
|
|
|
)}
|
|
)}
|
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
- <button onClick={() => setIsMenuOpen(true)} className="lg:hidden p-2 text-slate-900">
|
|
|
|
|
- <svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2.5} d="M4 6h16M4 12h16m-7 6h7" /></svg>
|
|
|
|
|
|
|
+ <button
|
|
|
|
|
+ onClick={() => setIsMenuOpen(true)}
|
|
|
|
|
+ className="lg:hidden p-2 text-slate-900"
|
|
|
|
|
+ >
|
|
|
|
|
+ <svg
|
|
|
|
|
+ className="w-6 h-6"
|
|
|
|
|
+ fill="none"
|
|
|
|
|
+ stroke="currentColor"
|
|
|
|
|
+ viewBox="0 0 24 24"
|
|
|
|
|
+ >
|
|
|
|
|
+ <path
|
|
|
|
|
+ strokeLinecap="round"
|
|
|
|
|
+ strokeLinejoin="round"
|
|
|
|
|
+ strokeWidth={2.5}
|
|
|
|
|
+ d="M4 6h16M4 12h16m-7 6h7"
|
|
|
|
|
+ />
|
|
|
|
|
+ </svg>
|
|
|
</button>
|
|
</button>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
@@ -315,12 +501,30 @@ const Header: React.FC = () => {
|
|
|
</header>
|
|
</header>
|
|
|
|
|
|
|
|
{/* Full-Screen Mobile Menu with Slide-Right Transition */}
|
|
{/* Full-Screen Mobile Menu with Slide-Right Transition */}
|
|
|
- <div className={`fixed inset-0 z-[100] lg:hidden transition-all duration-500 ease-in-out ${isMenuOpen ? 'opacity-100 pointer-events-auto' : 'opacity-0 pointer-events-none'}`}>
|
|
|
|
|
- <div className={`absolute inset-0 bg-white flex flex-col transform transition-transform duration-500 ease-out ${isMenuOpen ? 'translate-x-0' : '-translate-x-full'}`}>
|
|
|
|
|
|
|
+ <div
|
|
|
|
|
+ className={`fixed inset-0 z-[100] lg:hidden transition-all duration-500 ease-in-out ${
|
|
|
|
|
+ isMenuOpen
|
|
|
|
|
+ ? "opacity-100 pointer-events-auto"
|
|
|
|
|
+ : "opacity-0 pointer-events-none"
|
|
|
|
|
+ }`}
|
|
|
|
|
+ >
|
|
|
|
|
+ <div
|
|
|
|
|
+ className={`absolute inset-0 bg-white flex flex-col transform transition-transform duration-500 ease-out ${
|
|
|
|
|
+ isMenuOpen ? "translate-x-0" : "-translate-x-full"
|
|
|
|
|
+ }`}
|
|
|
|
|
+ >
|
|
|
{/* Mobile Menu Header */}
|
|
{/* Mobile Menu Header */}
|
|
|
<div className="flex justify-between items-center p-6 border-b border-slate-50">
|
|
<div className="flex justify-between items-center p-6 border-b border-slate-50">
|
|
|
- <Link to="/" onClick={() => setIsMenuOpen(false)} className="flex items-center space-x-1">
|
|
|
|
|
- <svg className="w-7 h-7 text-[#EE0434]" viewBox="0 0 24 24" fill="currentColor">
|
|
|
|
|
|
|
+ <Link
|
|
|
|
|
+ to="/"
|
|
|
|
|
+ onClick={() => setIsMenuOpen(false)}
|
|
|
|
|
+ className="flex items-center space-x-1"
|
|
|
|
|
+ >
|
|
|
|
|
+ <svg
|
|
|
|
|
+ className="w-7 h-7 text-[#EE0434]"
|
|
|
|
|
+ viewBox="0 0 24 24"
|
|
|
|
|
+ fill="currentColor"
|
|
|
|
|
+ >
|
|
|
<path d="M12 2L2 7l10 5 10-5-10-5zM2 17l10 5 10-5M2 12l10 5 10-5" />
|
|
<path d="M12 2L2 7l10 5 10-5-10-5zM2 17l10 5 10-5M2 12l10 5 10-5" />
|
|
|
</svg>
|
|
</svg>
|
|
|
<span className="text-xl font-black tracking-tighter">
|
|
<span className="text-xl font-black tracking-tighter">
|
|
@@ -328,45 +532,97 @@ const Header: React.FC = () => {
|
|
|
<span className="text-[#333]">Gate</span>
|
|
<span className="text-[#333]">Gate</span>
|
|
|
</span>
|
|
</span>
|
|
|
</Link>
|
|
</Link>
|
|
|
- <button onClick={() => setIsMenuOpen(false)} className="p-2 text-slate-400 hover:text-[#EE0434] transition-colors rounded-full hover:bg-slate-100">
|
|
|
|
|
- <svg className="w-8 h-8" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" /></svg>
|
|
|
|
|
|
|
+ <button
|
|
|
|
|
+ onClick={() => setIsMenuOpen(false)}
|
|
|
|
|
+ className="p-2 text-slate-400 hover:text-[#EE0434] transition-colors rounded-full hover:bg-slate-100"
|
|
|
|
|
+ >
|
|
|
|
|
+ <svg
|
|
|
|
|
+ className="w-8 h-8"
|
|
|
|
|
+ fill="none"
|
|
|
|
|
+ stroke="currentColor"
|
|
|
|
|
+ viewBox="0 0 24 24"
|
|
|
|
|
+ >
|
|
|
|
|
+ <path
|
|
|
|
|
+ strokeLinecap="round"
|
|
|
|
|
+ strokeLinejoin="round"
|
|
|
|
|
+ strokeWidth={2}
|
|
|
|
|
+ d="M6 18L18 6M6 6l12 12"
|
|
|
|
|
+ />
|
|
|
|
|
+ </svg>
|
|
|
</button>
|
|
</button>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
<div className="flex-1 overflow-y-auto px-6 py-8 space-y-6">
|
|
<div className="flex-1 overflow-y-auto px-6 py-8 space-y-6">
|
|
|
<div className="flex flex-col items-center space-y-4">
|
|
<div className="flex flex-col items-center space-y-4">
|
|
|
- <Link
|
|
|
|
|
- to="/"
|
|
|
|
|
|
|
+ <Link
|
|
|
|
|
+ to="/"
|
|
|
onClick={() => setIsMenuOpen(false)}
|
|
onClick={() => setIsMenuOpen(false)}
|
|
|
- className={`w-full text-center py-5 px-6 rounded-3xl text-2xl font-black transition-all ${isActive('/') ? 'bg-red-50 text-[#EE0434]' : 'text-slate-800 hover:bg-slate-50'}`}
|
|
|
|
|
|
|
+ className={`w-full text-center py-5 px-6 rounded-3xl text-2xl font-black transition-all ${
|
|
|
|
|
+ isActive("/")
|
|
|
|
|
+ ? "bg-red-50 text-[#EE0434]"
|
|
|
|
|
+ : "text-slate-800 hover:bg-slate-50"
|
|
|
|
|
+ }`}
|
|
|
>
|
|
>
|
|
|
Home
|
|
Home
|
|
|
</Link>
|
|
</Link>
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
<div className="w-full">
|
|
<div className="w-full">
|
|
|
- <button
|
|
|
|
|
|
|
+ <button
|
|
|
onClick={() => setIsBuySimExpanded(!isBuySimExpanded)}
|
|
onClick={() => setIsBuySimExpanded(!isBuySimExpanded)}
|
|
|
- className={`w-full flex items-center justify-center space-x-3 py-5 px-6 rounded-3xl text-2xl font-black transition-all ${isActive('/buy-sim') ? 'bg-red-50 text-[#EE0434]' : 'text-slate-800 hover:bg-slate-50'}`}
|
|
|
|
|
|
|
+ className={`w-full flex items-center justify-center space-x-3 py-5 px-6 rounded-3xl text-2xl font-black transition-all ${
|
|
|
|
|
+ isActive("/buy-sim")
|
|
|
|
|
+ ? "bg-red-50 text-[#EE0434]"
|
|
|
|
|
+ : "text-slate-800 hover:bg-slate-50"
|
|
|
|
|
+ }`}
|
|
|
>
|
|
>
|
|
|
<span>Buy SIM</span>
|
|
<span>Buy SIM</span>
|
|
|
- <svg className={`w-6 h-6 transition-transform duration-300 ${isBuySimExpanded ? 'rotate-180' : ''}`} fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2.5} d="M19 9l-7 7-7-7" /></svg>
|
|
|
|
|
|
|
+ <svg
|
|
|
|
|
+ className={`w-6 h-6 transition-transform duration-300 ${
|
|
|
|
|
+ isBuySimExpanded ? "rotate-180" : ""
|
|
|
|
|
+ }`}
|
|
|
|
|
+ fill="none"
|
|
|
|
|
+ stroke="currentColor"
|
|
|
|
|
+ viewBox="0 0 24 24"
|
|
|
|
|
+ >
|
|
|
|
|
+ <path
|
|
|
|
|
+ strokeLinecap="round"
|
|
|
|
|
+ strokeLinejoin="round"
|
|
|
|
|
+ strokeWidth={2.5}
|
|
|
|
|
+ d="M19 9l-7 7-7-7"
|
|
|
|
|
+ />
|
|
|
|
|
+ </svg>
|
|
|
</button>
|
|
</button>
|
|
|
- <div className={`overflow-hidden transition-all duration-300 ease-in-out ${isBuySimExpanded ? 'max-h-[1000px] opacity-100 mt-4' : 'max-h-0 opacity-0'}`}>
|
|
|
|
|
|
|
+ <div
|
|
|
|
|
+ className={`overflow-hidden transition-all duration-300 ease-in-out ${
|
|
|
|
|
+ isBuySimExpanded
|
|
|
|
|
+ ? "max-h-[1000px] opacity-100 mt-4"
|
|
|
|
|
+ : "max-h-0 opacity-0"
|
|
|
|
|
+ }`}
|
|
|
|
|
+ >
|
|
|
<div className="grid grid-cols-2 gap-3 px-2">
|
|
<div className="grid grid-cols-2 gap-3 px-2">
|
|
|
- <button
|
|
|
|
|
- onClick={() => { navigate('/buy-sim'); setIsMenuOpen(false); }}
|
|
|
|
|
|
|
+ <button
|
|
|
|
|
+ onClick={() => {
|
|
|
|
|
+ navigate("/buy-sim");
|
|
|
|
|
+ setIsMenuOpen(false);
|
|
|
|
|
+ }}
|
|
|
className="col-span-2 text-center py-4 bg-slate-50 rounded-2xl text-[#EE0434] font-black text-sm uppercase tracking-wider shadow-sm"
|
|
className="col-span-2 text-center py-4 bg-slate-50 rounded-2xl text-[#EE0434] font-black text-sm uppercase tracking-wider shadow-sm"
|
|
|
>
|
|
>
|
|
|
View All Destinations →
|
|
View All Destinations →
|
|
|
</button>
|
|
</button>
|
|
|
- {countries.map(c => (
|
|
|
|
|
- <button
|
|
|
|
|
|
|
+ {countries.map((c) => (
|
|
|
|
|
+ <button
|
|
|
key={c.name}
|
|
key={c.name}
|
|
|
onClick={() => handleCountryClick(c)}
|
|
onClick={() => handleCountryClick(c)}
|
|
|
className="flex flex-col items-center justify-center space-y-2 py-5 rounded-2xl bg-white border border-slate-100 shadow-sm active:bg-slate-50"
|
|
className="flex flex-col items-center justify-center space-y-2 py-5 rounded-2xl bg-white border border-slate-100 shadow-sm active:bg-slate-50"
|
|
|
>
|
|
>
|
|
|
- <img src={`https://flagcdn.com/w80/${c.flag}.png`} alt={c.name} className="w-10 h-10 rounded-full object-cover border-2 border-slate-50" />
|
|
|
|
|
- <span className="text-sm font-bold text-slate-700">{c.name}</span>
|
|
|
|
|
|
|
+ <img
|
|
|
|
|
+ src={`https://flagcdn.com/w80/${c.flag}.png`}
|
|
|
|
|
+ alt={c.name}
|
|
|
|
|
+ className="w-10 h-10 rounded-full object-cover border-2 border-slate-50"
|
|
|
|
|
+ />
|
|
|
|
|
+ <span className="text-sm font-bold text-slate-700">
|
|
|
|
|
+ {c.name}
|
|
|
|
|
+ </span>
|
|
|
</button>
|
|
</button>
|
|
|
))}
|
|
))}
|
|
|
</div>
|
|
</div>
|
|
@@ -374,19 +630,46 @@ const Header: React.FC = () => {
|
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
<div className="w-full">
|
|
<div className="w-full">
|
|
|
- <button
|
|
|
|
|
|
|
+ <button
|
|
|
onClick={() => setIsGuideExpanded(!isGuideExpanded)}
|
|
onClick={() => setIsGuideExpanded(!isGuideExpanded)}
|
|
|
- className={`w-full flex items-center justify-center space-x-3 py-5 px-6 rounded-3xl text-2xl font-black transition-all ${isActive('/support') ? 'bg-red-50 text-[#EE0434]' : 'text-slate-800 hover:bg-slate-50'}`}
|
|
|
|
|
|
|
+ className={`w-full flex items-center justify-center space-x-3 py-5 px-6 rounded-3xl text-2xl font-black transition-all ${
|
|
|
|
|
+ isActive("/support")
|
|
|
|
|
+ ? "bg-red-50 text-[#EE0434]"
|
|
|
|
|
+ : "text-slate-800 hover:bg-slate-50"
|
|
|
|
|
+ }`}
|
|
|
>
|
|
>
|
|
|
<span>Guide</span>
|
|
<span>Guide</span>
|
|
|
- <svg className={`w-6 h-6 transition-transform duration-300 ${isGuideExpanded ? 'rotate-180' : ''}`} fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2.5} d="M19 9l-7 7-7-7" /></svg>
|
|
|
|
|
|
|
+ <svg
|
|
|
|
|
+ className={`w-6 h-6 transition-transform duration-300 ${
|
|
|
|
|
+ isGuideExpanded ? "rotate-180" : ""
|
|
|
|
|
+ }`}
|
|
|
|
|
+ fill="none"
|
|
|
|
|
+ stroke="currentColor"
|
|
|
|
|
+ viewBox="0 0 24 24"
|
|
|
|
|
+ >
|
|
|
|
|
+ <path
|
|
|
|
|
+ strokeLinecap="round"
|
|
|
|
|
+ strokeLinejoin="round"
|
|
|
|
|
+ strokeWidth={2.5}
|
|
|
|
|
+ d="M19 9l-7 7-7-7"
|
|
|
|
|
+ />
|
|
|
|
|
+ </svg>
|
|
|
</button>
|
|
</button>
|
|
|
- <div className={`overflow-hidden transition-all duration-300 ease-in-out ${isGuideExpanded ? 'max-h-[400px] opacity-100 mt-4' : 'max-h-0 opacity-0'}`}>
|
|
|
|
|
|
|
+ <div
|
|
|
|
|
+ className={`overflow-hidden transition-all duration-300 ease-in-out ${
|
|
|
|
|
+ isGuideExpanded
|
|
|
|
|
+ ? "max-h-[400px] opacity-100 mt-4"
|
|
|
|
|
+ : "max-h-0 opacity-0"
|
|
|
|
|
+ }`}
|
|
|
|
|
+ >
|
|
|
<div className="flex flex-col space-y-2 px-2">
|
|
<div className="flex flex-col space-y-2 px-2">
|
|
|
- {guideItems.map(item => (
|
|
|
|
|
- <button
|
|
|
|
|
|
|
+ {guideItems.map((item) => (
|
|
|
|
|
+ <button
|
|
|
key={item.label}
|
|
key={item.label}
|
|
|
- onClick={() => { navigate(item.path); setIsMenuOpen(false); }}
|
|
|
|
|
|
|
+ onClick={() => {
|
|
|
|
|
+ navigate(item.path);
|
|
|
|
|
+ setIsMenuOpen(false);
|
|
|
|
|
+ }}
|
|
|
className="w-full text-center py-4 rounded-2xl bg-slate-50 text-slate-600 font-bold hover:text-[#EE0434] active:bg-red-50"
|
|
className="w-full text-center py-4 rounded-2xl bg-slate-50 text-slate-600 font-bold hover:text-[#EE0434] active:bg-red-50"
|
|
|
>
|
|
>
|
|
|
{item.label}
|
|
{item.label}
|
|
@@ -396,42 +679,60 @@ const Header: React.FC = () => {
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
- <Link
|
|
|
|
|
- to="/news"
|
|
|
|
|
|
|
+ <Link
|
|
|
|
|
+ to="/news"
|
|
|
onClick={() => setIsMenuOpen(false)}
|
|
onClick={() => setIsMenuOpen(false)}
|
|
|
- className={`w-full text-center py-5 px-6 rounded-3xl text-2xl font-black transition-all ${isActive('/news') ? 'bg-red-50 text-[#EE0434]' : 'text-slate-800 hover:bg-slate-50'}`}
|
|
|
|
|
|
|
+ className={`w-full text-center py-5 px-6 rounded-3xl text-2xl font-black transition-all ${
|
|
|
|
|
+ isActive("/news")
|
|
|
|
|
+ ? "bg-red-50 text-[#EE0434]"
|
|
|
|
|
+ : "text-slate-800 hover:bg-slate-50"
|
|
|
|
|
+ }`}
|
|
|
>
|
|
>
|
|
|
News
|
|
News
|
|
|
</Link>
|
|
</Link>
|
|
|
-
|
|
|
|
|
- <Link
|
|
|
|
|
- to="/contact"
|
|
|
|
|
|
|
+
|
|
|
|
|
+ <Link
|
|
|
|
|
+ to="/contact"
|
|
|
onClick={() => setIsMenuOpen(false)}
|
|
onClick={() => setIsMenuOpen(false)}
|
|
|
- className={`w-full text-center py-5 px-6 rounded-3xl text-2xl font-black transition-all ${isActive('/contact') ? 'bg-red-50 text-[#EE0434]' : 'text-slate-800 hover:bg-slate-50'}`}
|
|
|
|
|
|
|
+ className={`w-full text-center py-5 px-6 rounded-3xl text-2xl font-black transition-all ${
|
|
|
|
|
+ isActive("/contact")
|
|
|
|
|
+ ? "bg-red-50 text-[#EE0434]"
|
|
|
|
|
+ : "text-slate-800 hover:bg-slate-50"
|
|
|
|
|
+ }`}
|
|
|
>
|
|
>
|
|
|
Contact
|
|
Contact
|
|
|
</Link>
|
|
</Link>
|
|
|
|
|
|
|
|
<div className="w-full pt-4">
|
|
<div className="w-full pt-4">
|
|
|
- <p className="text-center text-slate-400 font-bold text-xs uppercase tracking-widest mb-4">Select Language</p>
|
|
|
|
|
- <div className="flex justify-center space-x-4">
|
|
|
|
|
- {languages.map(lang => (
|
|
|
|
|
- <button
|
|
|
|
|
- key={lang.code}
|
|
|
|
|
- onClick={() => setSelectedLang(lang.code as 'en' | 'vi')}
|
|
|
|
|
- className={`flex items-center space-x-2 px-4 py-2 rounded-2xl transition-all border ${selectedLang === lang.code ? 'bg-red-50 border-[#EE0434] text-[#EE0434]' : 'bg-white border-slate-100 text-slate-500'}`}
|
|
|
|
|
- >
|
|
|
|
|
- <img src={`https://flagcdn.com/w40/${lang.flag}.png`} alt={lang.label} className="w-6 h-6 rounded-full object-cover border border-slate-100" />
|
|
|
|
|
- <span className="font-bold">{lang.label}</span>
|
|
|
|
|
- </button>
|
|
|
|
|
- ))}
|
|
|
|
|
- </div>
|
|
|
|
|
|
|
+ <p className="text-center text-slate-400 font-bold text-xs uppercase tracking-widest mb-4">
|
|
|
|
|
+ Select Language
|
|
|
|
|
+ </p>
|
|
|
|
|
+ <div className="flex justify-center space-x-4">
|
|
|
|
|
+ {languages.map((lang) => (
|
|
|
|
|
+ <button
|
|
|
|
|
+ key={lang.code}
|
|
|
|
|
+ onClick={() => setSelectedLang(lang.code as "en" | "vi")}
|
|
|
|
|
+ className={`flex items-center space-x-2 px-4 py-2 rounded-2xl transition-all border ${
|
|
|
|
|
+ selectedLang === lang.code
|
|
|
|
|
+ ? "bg-red-50 border-[#EE0434] text-[#EE0434]"
|
|
|
|
|
+ : "bg-white border-slate-100 text-slate-500"
|
|
|
|
|
+ }`}
|
|
|
|
|
+ >
|
|
|
|
|
+ <img
|
|
|
|
|
+ src={`https://flagcdn.com/w40/${lang.flag}.png`}
|
|
|
|
|
+ alt={lang.label}
|
|
|
|
|
+ className="w-6 h-6 rounded-full object-cover border border-slate-100"
|
|
|
|
|
+ />
|
|
|
|
|
+ <span className="font-bold">{lang.label}</span>
|
|
|
|
|
+ </button>
|
|
|
|
|
+ ))}
|
|
|
|
|
+ </div>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
<div className="p-8 border-t border-slate-50 bg-slate-50/50">
|
|
<div className="p-8 border-t border-slate-50 bg-slate-50/50">
|
|
|
- <Link
|
|
|
|
|
|
|
+ <Link
|
|
|
to="/login"
|
|
to="/login"
|
|
|
onClick={() => setIsMenuOpen(false)}
|
|
onClick={() => setIsMenuOpen(false)}
|
|
|
className="w-full bg-gradient-to-r from-[#E21c34] to-[#500B28] text-white py-5 rounded-[40px] font-black text-2xl shadow-xl active:scale-[0.98] transition-all flex justify-center"
|
|
className="w-full bg-gradient-to-r from-[#E21c34] to-[#500B28] text-white py-5 rounded-[40px] font-black text-2xl shadow-xl active:scale-[0.98] transition-all flex justify-center"
|