mobile: Optimizations for Maps Drawer, Legend, and Customer Profile Tabs
This commit is contained in:
+97
-18
@@ -1,11 +1,14 @@
|
||||
import React, { useEffect, useRef } from 'react';
|
||||
import Chatbot from '../components/Chatbot';
|
||||
import { useAuth } from '../context/AuthContext';
|
||||
import { ArrowRight, CheckCircle2, Home, Star, ShieldCheck, Clock, Award, TrendingDown, Users, MapPin, Phone, Mail, Instagram, Twitter, Youtube } from 'lucide-react';
|
||||
import { useTheme } from '../context/ThemeContext'; // Import useTheme
|
||||
import { ArrowRight, CheckCircle2, Home, Star, ShieldCheck, Clock, Award, TrendingDown, Users, MapPin, Phone, Mail, Instagram, Twitter, Youtube, Sun, Moon, LogOut, LayoutDashboard, User, Menu, X } from 'lucide-react';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
import { SpotlightCard } from '../components/SpotlightCard';
|
||||
import { ComparisonSlider } from '../components/ComparisonSlider';
|
||||
import Services from '../components/Services';
|
||||
import IntelligenceMap from '../components/IntelligenceMap';
|
||||
import gsap from 'gsap';
|
||||
import { ScrollTrigger } from 'gsap/ScrollTrigger';
|
||||
import Logo from '../assets/images/LynkedUp_Pro_F_logo_Y.png';
|
||||
@@ -19,9 +22,11 @@ gsap.registerPlugin(ScrollTrigger);
|
||||
|
||||
const Landing = () => {
|
||||
const { user } = useAuth();
|
||||
const { theme, toggleTheme } = useTheme();
|
||||
const heroRef = useRef(null);
|
||||
const textRef = useRef(null);
|
||||
const sectionsRef = useRef([]);
|
||||
const [isMobileMenuOpen, setIsMobileMenuOpen] = React.useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
// Console Signature (Info level to persist in prod)
|
||||
@@ -69,30 +74,98 @@ const Landing = () => {
|
||||
<nav className="border-b border-zinc-200 dark:border-white/5 backdrop-blur-xl sticky top-0 z-40 bg-white/70 dark:bg-black/50">
|
||||
<div className="max-w-7xl mx-auto px-6 h-20 flex items-center justify-between">
|
||||
<div className="flex items-center space-x-2">
|
||||
<img src={Logo} alt="LynkedUp Pro" className="w-10 h-10 object-contain" />
|
||||
<span className="text-xl font-bold tracking-tight">LynkedUp Pro</span>
|
||||
<img src={Logo} alt="LynkedUp Pro" className="h-16 w-auto object-contain" />
|
||||
{/* <span className="text-xl font-bold tracking-tight">LynkedUp Pro</span> */}
|
||||
</div>
|
||||
<div className="flex items-center space-x-4">
|
||||
|
||||
{/* Desktop Nav */}
|
||||
<div className="hidden md:flex items-center space-x-4">
|
||||
<button
|
||||
onClick={toggleTheme}
|
||||
className="p-2 rounded-full hover:bg-zinc-100 dark:hover:bg-zinc-800 transition-colors text-zinc-600 dark:text-zinc-400"
|
||||
aria-label="Toggle Theme"
|
||||
>
|
||||
{theme === 'dark' ? <Sun size={20} /> : <Moon size={20} />}
|
||||
</button>
|
||||
|
||||
{!user ? (
|
||||
<Link to="/login" className="px-5 py-2 rounded-full text-xs font-bold uppercase tracking-wider bg-zinc-100 dark:bg-zinc-900 border hover:bg-zinc-200 dark:hover:bg-zinc-800 transition-colors">
|
||||
Sign In
|
||||
</Link>
|
||||
) : (
|
||||
<Link to={user.role === 'customer' ? '/' : '/emp/fa/dashboard'} className="px-5 py-2 rounded-full text-xs font-bold uppercase tracking-wider bg-black dark:bg-white text-white dark:text-black hover:opacity-80 transition-colors">
|
||||
Dashboard
|
||||
</Link>
|
||||
<div className="flex items-center gap-2">
|
||||
<Link
|
||||
to={user.role === 'CUSTOMER' ? '/portal/profile' : '/emp/fa/dashboard'}
|
||||
className="px-5 py-2 rounded-full text-xs font-bold uppercase tracking-wider bg-black dark:bg-white text-white dark:text-black hover:opacity-80 transition-colors"
|
||||
>
|
||||
{user.role === 'CUSTOMER' ? 'My Profile' : 'Dashboard'}
|
||||
</Link>
|
||||
<button
|
||||
onClick={useAuth().logout}
|
||||
className="p-2 rounded-full hover:bg-red-50 dark:hover:bg-red-900/20 text-zinc-400 hover:text-red-500 transition-colors"
|
||||
title="Sign Out"
|
||||
>
|
||||
<LogOut size={20} />
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Mobile Menu Toggle */}
|
||||
<button
|
||||
className="md:hidden p-2 text-zinc-600 dark:text-zinc-400"
|
||||
onClick={() => setIsMobileMenuOpen(!isMobileMenuOpen)}
|
||||
>
|
||||
{isMobileMenuOpen ? <X size={24} /> : <Menu size={24} />}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Mobile Nav Dropdown */}
|
||||
{isMobileMenuOpen && (
|
||||
<div className="md:hidden absolute top-20 left-0 right-0 bg-white dark:bg-black border-b border-zinc-200 dark:border-white/5 p-4 flex flex-col space-y-4 shadow-xl animate-in slide-in-from-top-4">
|
||||
<button
|
||||
onClick={() => { toggleTheme(); setIsMobileMenuOpen(false); }}
|
||||
className="flex items-center space-x-3 p-3 rounded-xl bg-zinc-100 dark:bg-zinc-900"
|
||||
>
|
||||
{theme === 'dark' ? <Sun size={20} /> : <Moon size={20} />}
|
||||
<span className="font-bold">{theme === 'dark' ? 'Light Mode' : 'Dark Mode'}</span>
|
||||
</button>
|
||||
|
||||
{!user ? (
|
||||
<Link
|
||||
to="/login"
|
||||
onClick={() => setIsMobileMenuOpen(false)}
|
||||
className="w-full text-center py-3 rounded-xl font-bold uppercase tracking-wider bg-blue-600 text-white"
|
||||
>
|
||||
Sign In
|
||||
</Link>
|
||||
) : (
|
||||
<>
|
||||
<Link
|
||||
to={user.role === 'CUSTOMER' ? '/portal/profile' : '/emp/fa/dashboard'}
|
||||
onClick={() => setIsMobileMenuOpen(false)}
|
||||
className="w-full text-center py-3 rounded-xl font-bold uppercase tracking-wider bg-black dark:bg-white text-white dark:text-black"
|
||||
>
|
||||
{user.role === 'CUSTOMER' ? 'My Profile' : 'Dashboard'}
|
||||
</Link>
|
||||
<button
|
||||
onClick={() => { useAuth().logout(); setIsMobileMenuOpen(false); }}
|
||||
className="w-full text-center py-3 rounded-xl font-bold uppercase tracking-wider bg-red-50 dark:bg-red-900/20 text-red-600 dark:text-red-400"
|
||||
>
|
||||
Sign Out
|
||||
</button>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</nav>
|
||||
|
||||
{/* HERO SECTION */}
|
||||
<div className="relative pt-32 pb-40 overflow-hidden" ref={heroRef}>
|
||||
<div className="relative min-h-[90vh] flex items-center justify-center pt-32 pb-40 overflow-hidden" ref={heroRef}>
|
||||
{/* Background Image with Overlay */}
|
||||
<div className="absolute inset-0 z-0">
|
||||
<img src={HeroImg} alt="Modern Roof" className="w-full h-full object-cover opacity-20 dark:opacity-40" />
|
||||
<div className="absolute inset-0 bg-gradient-to-b from-transparent via-zinc-50/80 to-zinc-50 dark:via-[#050505]/80 dark:to-[#050505]"></div>
|
||||
<img src={HeroImg} alt="Modern Roof" className="w-full h-full object-cover object-[center_35%] scale-110 opacity-20 dark:opacity-40" />
|
||||
<div className="absolute inset-0 bg-gradient-to-b from-transparent via-zinc-50/50 to-zinc-50 dark:via-[#050505]/50 dark:to-[#050505]"></div>
|
||||
</div>
|
||||
|
||||
<div className="max-w-7xl mx-auto px-6 relative z-10 text-center" ref={textRef}>
|
||||
@@ -103,7 +176,7 @@ const Landing = () => {
|
||||
|
||||
<h1 className="text-6xl md:text-9xl font-black tracking-tighter mb-6 leading-[0.9]">
|
||||
ROOFING <br />
|
||||
<span className="text-transparent bg-clip-text bg-gradient-to-b from-blue-700 to-red-600 dark:from-blue-400 dark:to-red-400">REVOLUTIONIZED</span>
|
||||
<span className="text-transparent bg-clip-text bg-gradient-to-b from-blue-700 to-red-600 dark:from-blue-400 dark:to-red-400 text-4xl md:text-9xl">REVOLUTIONIZED</span>
|
||||
</h1>
|
||||
|
||||
<p className="text-xl md:text-2xl text-zinc-500 dark:text-zinc-400 max-w-2xl mx-auto mb-12 font-medium">
|
||||
@@ -114,12 +187,12 @@ const Landing = () => {
|
||||
|
||||
<div className="flex flex-col sm:flex-row items-center justify-center gap-4 mb-12">
|
||||
<Link to="/login" className="px-8 py-4 rounded-full bg-blue-700 hover:bg-blue-800 text-white font-bold transition-all flex items-center shadow-lg shadow-blue-600/20 hover:scale-105 ring-4 ring-blue-500/10 dark:ring-blue-400/10">
|
||||
Get Free Estimate
|
||||
Schedule Demo
|
||||
<ArrowRight size={18} className="ml-2" />
|
||||
</Link>
|
||||
<button className="px-8 py-4 rounded-full bg-zinc-100 dark:bg-white/5 border border-zinc-200 dark:border-white/10 hover:bg-zinc-200 dark:hover:bg-white/10 font-semibold transition-colors">
|
||||
<a href="https://www.youtube.com/watch?v=dQw4w9WgXcQ" target="_blank" rel="noopener noreferrer" className="px-8 py-4 rounded-full bg-zinc-100 dark:bg-white/5 border border-zinc-200 dark:border-white/10 hover:bg-zinc-200 dark:hover:bg-white/10 font-semibold transition-colors">
|
||||
See The Process
|
||||
</button>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
{/* Patriotic Discount Banner */}
|
||||
@@ -133,8 +206,8 @@ const Landing = () => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Satisfaction Badges */}
|
||||
<div className="mt-12 flex items-center justify-center gap-8 opacity-70 grayscale hover:grayscale-0 transition-all duration-500">
|
||||
{/* Satisfaction Badges REMOVED */}
|
||||
{/* <div className="mt-12 flex items-center justify-center gap-8 opacity-70 grayscale hover:grayscale-0 transition-all duration-500">
|
||||
<div className="flex items-center space-x-2">
|
||||
<div className="flex -space-x-2">
|
||||
<div className="w-8 h-8 rounded-full bg-gray-300 border-2 border-white dark:border-black"></div>
|
||||
@@ -147,7 +220,7 @@ const Landing = () => {
|
||||
<ShieldCheck size={16} />
|
||||
<span className="text-xs font-bold">Licensed & Insured</span>
|
||||
</div>
|
||||
</div>
|
||||
</div> */}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -217,7 +290,7 @@ const Landing = () => {
|
||||
<div className="w-12 h-12 rounded-full bg-zinc-900 dark:bg-white text-white dark:text-black flex items-center justify-center font-black text-xl mb-6">03</div>
|
||||
<h3 className="text-3xl font-bold mb-4">The Resolution.</h3>
|
||||
<p className="text-lg text-zinc-500 dark:text-zinc-400 leading-relaxed mb-6">
|
||||
Armed with precise data, our certified ground team executes the repair cheaply and effectively. Homeowners are assured and relaxed, knowing they are getting the best of the best.
|
||||
Generate property assessment reports and repair estimates within minutes of inspection. AI-verified analysis documents visible damage using clear, objective evidence. Reports can be shared with property owners or used in insurance discussions. All findings are based on measurable data, not opinions. Our goal is simple: equip field representatives with the latest technology and verified evidence so they can operate with confidence, gain a competitive edge, and ensure all parties work from the same factual record.
|
||||
</p>
|
||||
<div className="flex gap-4">
|
||||
<span className="px-3 py-1 bg-red-100 dark:bg-red-900/20 text-red-600 dark:text-red-400 text-xs font-bold uppercase rounded-md">Cost Efficient</span>
|
||||
@@ -234,6 +307,12 @@ const Landing = () => {
|
||||
<ComparisonSlider />
|
||||
</div>
|
||||
|
||||
{/* NEW SERVICES SECTION */}
|
||||
<Services />
|
||||
|
||||
{/* NEW INTELLIGENCE MAP SECTION */}
|
||||
<IntelligenceMap />
|
||||
|
||||
{/* FACT CHECK & STATS */}
|
||||
<div className="py-24 bg-zinc-900 text-white relative overflow-hidden" ref={addToRefs}>
|
||||
<div className="absolute inset-0 bg-[url('https://www.transparenttextures.com/patterns/carbon-fibre.png')] opacity-10"></div>
|
||||
|
||||
Reference in New Issue
Block a user