erp-platform/ui/src/components/layouts/PublicLayout.tsx

434 lines
15 KiB
TypeScript
Raw Normal View History

2025-08-11 06:34:44 +00:00
import View from '@/views'
import React, { useEffect, useState } from 'react'
import { useLocation, Link } from 'react-router-dom'
import {
Menu,
X,
Home,
Info,
Package,
Briefcase,
BookOpen,
Phone,
Facebook,
Twitter,
Linkedin,
Instagram,
MapPin,
Mail,
PlayCircle,
} from 'lucide-react'
import Logo from '@/views/public/Logo'
import { ROUTES_ENUM } from '@/routes/route.constant'
import { useLocalization } from '@/utils/hooks/useLocalization'
import LanguageSelector from '../template/LanguageSelector'
import Demo from '@/views/public/Demo'
import { ScrollContext } from '@/contexts/ScrollContext'
interface NavLink {
resourceKey?: string
name: string
path?: string
action?: () => void
icon?: React.ComponentType<any>
}
const PublicLayout = () => {
const location = useLocation()
const { translate } = useLocalization()
const [isOpen, setIsOpen] = useState(false)
const [scrolled, setScrolled] = useState(false)
const [isDemoOpen, setIsDemoOpen] = useState(false)
const currentYear = new Date().getFullYear()
useEffect(() => {
window.scrollTo(0, 0)
}, [location.pathname])
useEffect(() => {
const handleScroll = () => {
const isScrolled = window.scrollY > 10
if (isScrolled !== scrolled) {
setScrolled(isScrolled)
}
}
window.addEventListener('scroll', handleScroll)
return () => window.removeEventListener('scroll', handleScroll)
}, [scrolled])
const toggleMenu = () => setIsOpen(!isOpen)
const navLinks: NavLink[] = [
{
resourceKey: 'Public.nav.home',
name: translate('::Public.nav.home'),
path: '/home',
icon: Home,
},
{
resourceKey: 'Public.nav.about',
name: translate('::Public.nav.about'),
path: '/about',
icon: Info,
},
{
resourceKey: 'Public.nav.services',
name: translate('::Public.nav.services'),
path: '/services',
icon: Briefcase,
},
{
resourceKey: 'Public.nav.products',
name: translate('::Public.nav.products'),
path: '/products',
icon: Package,
},
{
resourceKey: 'Public.nav.blog',
name: translate('::Public.nav.blog'),
path: '/blog',
icon: BookOpen,
},
{
resourceKey: 'Public.nav.demo',
name: translate('::Public.nav.demo'),
action: () => setIsDemoOpen(true),
icon: PlayCircle,
},
{
resourceKey: 'Public.nav.contact',
name: translate('::Public.nav.contact'),
path: '/contact',
icon: Phone,
},
{ resourceKey: 'Public.nav.giris', name: translate('::Public.nav.giris'), path: '/login' },
]
const getNavItemClass = (resourceKey?: string) => {
switch (resourceKey) {
case 'Public.nav.giris':
return 'bg-blue-600 rounded px-2 py-1'
case 'Public.nav.basket':
return 'bg-green-600 rounded px-2 py-1'
default:
return ''
}
}
return (
<ScrollContext.Provider value={scrolled}>
<div className="flex flex-col min-h-screen">
{/* HEADER */}
<header
className={`fixed w-full z-50 transition-all duration-300 ${
scrolled
? 'bg-gray-900/95 backdrop-blur-sm shadow-md py-2'
: 'bg-gray-900/80 backdrop-blur-sm py-4'
}`}
>
<div className="container mx-auto px-4 flex items-center justify-between">
<Logo mode="dark" />
{/* Desktop Navigation */}
<nav className="hidden md:flex items-center space-x-4">
{navLinks.map((link) =>
link.path ? (
<Link
key={link.path}
to={link.path}
className={`flex items-center gap-1 font-medium text-sm text-white hover:text-blue-400 transition-colors ${getNavItemClass(link.resourceKey)}`}
>
{link.icon && <link.icon size={18} />}
{link.name}
</Link>
) : (
<button
key={link.name}
onClick={link.action}
className={`flex items-center gap-1 font-medium text-sm text-white hover:text-blue-400 transition-colors ${getNavItemClass(link.resourceKey)}`}
>
{link.icon && <link.icon size={18} />}
{link.name}
</button>
),
)}
<LanguageSelector />
</nav>
{/* Mobile Menu Button */}
<button className="md:hidden text-white" onClick={toggleMenu} aria-label="Toggle menu">
{isOpen ? <X size={24} /> : <Menu size={24} />}
</button>
</div>
{/* Mobile Navigation */}
{isOpen && (
<div className="md:hidden bg-gray-900/95 backdrop-blur-sm shadow-lg">
<div className="container mx-auto px-4">
<nav className="flex flex-col space-y-4 py-4">
{navLinks.map((link) =>
link.path ? (
<Link
key={link.path}
to={link.path}
className={`flex items-center gap-1 font-medium text-white hover:text-blue-400 transition-colors ${getNavItemClass(link.resourceKey)}`}
onClick={toggleMenu}
>
{link.icon && <link.icon size={18} />}
{link.name}
</Link>
) : (
<button
key={link.name}
onClick={() => {
link.action?.()
toggleMenu()
}}
className={`flex items-center gap-1 font-medium text-white hover:text-blue-400 transition-colors text-left ${getNavItemClass(link.resourceKey)}`}
>
{link.icon && <link.icon size={18} />}
{link.name}
</button>
),
)}
<LanguageSelector />
</nav>
</div>
</div>
)}
</header>
<main className="flex-grow">
<View />
</main>
<footer className="bg-gray-900 text-white pt-16 pb-8">
<div className="container mx-auto px-4">
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-8">
<div>
<Logo mode="dark" />
<p className="mt-4 text-gray-400 text-sm">
{translate('::Public.footer.companyInfo')}
</p>
<div className="flex space-x-4 mt-6">
<a
href="https://facebook.com/sozsoft"
target="_blank"
rel="noopener noreferrer"
className="text-gray-400 hover:text-white transition-colors"
>
<Facebook size={20} />
</a>
<a
href="https://twitter.com/sozsoft"
target="_blank"
rel="noopener noreferrer"
className="text-gray-400 hover:text-white transition-colors"
>
<Twitter size={20} />
</a>
<a
href="https://linkedin.com/sozsoft"
target="_blank"
rel="noopener noreferrer"
className="text-gray-400 hover:text-white transition-colors"
>
<Linkedin size={20} />
</a>
<a
href="https://instagram.com/sozsoft"
target="_blank"
rel="noopener noreferrer"
className="text-gray-400 hover:text-white transition-colors"
>
<Instagram size={20} />
</a>
</div>
</div>
{/* Quick Links */}
<div>
<h3 className="text-lg font-bold mb-4 text-white">
{translate('::Public.footer.quickLinksTitle')}
</h3>
<ul className="space-y-2">
<li>
<Link
to={ROUTES_ENUM.public.home}
className="text-gray-400 hover:text-white transition-colors"
>
{translate('::Public.nav.home')}
</Link>
</li>
<li>
<Link
to={ROUTES_ENUM.public.products}
className="text-gray-400 hover:text-white transition-colors"
>
{translate('::Public.nav.products')}
</Link>
</li>
<li>
<Link
to={ROUTES_ENUM.public.services}
className="text-gray-400 hover:text-white transition-colors"
>
{translate('::Public.nav.services')}
</Link>
</li>
<li>
<Link
to={ROUTES_ENUM.public.about}
className="text-gray-400 hover:text-white transition-colors"
>
{translate('::Public.nav.about')}
</Link>
</li>
<li>
<Link
to={ROUTES_ENUM.public.blog}
className="text-gray-400 hover:text-white transition-colors"
>
{translate('::Public.nav.blog')}
</Link>
</li>
<li>
<Link
to={ROUTES_ENUM.public.contact}
className="text-gray-400 hover:text-white transition-colors"
>
{translate('::Public.nav.contact')}
</Link>
</li>
</ul>
</div>
{/* Services */}
<div>
<h3 className="text-lg font-bold mb-4 text-white">
{translate('::Public.footer.servicesTitle')}
</h3>
<ul className="space-y-2">
<li>
<Link
to={ROUTES_ENUM.public.services}
className="text-gray-400 hover:text-white transition-colors"
>
{translate('::Public.services.software.title')}
</Link>
</li>
<li>
<Link
to={ROUTES_ENUM.public.services}
className="text-gray-400 hover:text-white transition-colors"
>
{translate('::Public.services.web.title')}
</Link>
</li>
<li>
<Link
to={ROUTES_ENUM.public.services}
className="text-gray-400 hover:text-white transition-colors"
>
{translate('::Public.services.mobile.title')}
</Link>
</li>
<li>
<Link
to={ROUTES_ENUM.public.services}
className="text-gray-400 hover:text-white transition-colors"
>
{translate('::Public.services.database.title')}
</Link>
</li>
<li>
<Link
to={ROUTES_ENUM.public.services}
className="text-gray-400 hover:text-white transition-colors"
>
{translate('::Public.services.integration.title')}
</Link>
</li>
<li>
<Link
to={ROUTES_ENUM.public.services}
className="text-gray-400 hover:text-white transition-colors"
>
{translate('::Public.services.consulting.title')}
</Link>
</li>
</ul>
</div>
{/* Contact Info */}
<div>
<h3 className="text-lg font-bold mb-4 text-white">
{translate('::Public.nav.contact')}
</h3>
<ul className="space-y-3">
<li className="flex items-start space-x-3">
<MapPin size={20} className="text-gray-400 mt-1 flex-shrink-0" />
<span className="text-gray-400">{translate('::Public.footer.address')}</span>
</li>
<li className="flex items-center space-x-3">
<Phone size={20} className="text-gray-400 flex-shrink-0" />
<a
href="tel:+905447697638"
className="text-gray-400 hover:text-white transition-colors"
>
+90 (544) 769 7 638
</a>
</li>
<li className="flex items-center space-x-3">
<Mail size={20} className="text-gray-400 flex-shrink-0" />
<a
href="mailto:destek@sozsoft.com"
className="text-gray-400 hover:text-white transition-colors"
>
destek@sozsoft.com
</a>
</li>
</ul>
</div>
</div>
<div className="border-t border-gray-800 mt-12 pt-8">
<div className="flex flex-col md:flex-row justify-between items-center">
<p className="text-gray-400 text-sm">
&copy; {currentYear} Sözsoft. {translate('::Public.footer.copyright')}
</p>
<div className="mt-4 md:mt-0">
<ul className="flex space-x-6 text-sm">
<li>
<Link
to={ROUTES_ENUM.public.about}
className="text-gray-400 hover:text-white transition-colors"
>
{translate('::Public.footer.privacyPolicy')}
</Link>
</li>
<li>
<Link
to={ROUTES_ENUM.public.about}
className="text-gray-400 hover:text-white transition-colors"
>
{translate('::Public.footer.termsOfUse')}
</Link>
</li>
</ul>
</div>
</div>
</div>
</div>
</footer>
{/* Demo Modal */}
<Demo isOpen={isDemoOpen} onClose={() => setIsDemoOpen(false)} />
</div>
</ScrollContext.Provider>
)
}
export default PublicLayout