125 lines
4.5 KiB
TypeScript
125 lines
4.5 KiB
TypeScript
"use client";
|
|
|
|
import React, { useEffect, useState } from 'react';
|
|
import { X, Folder, LayoutGrid } from 'lucide-react';
|
|
import { motion, AnimatePresence } from 'framer-motion';
|
|
import Link from 'next/link';
|
|
import { catalogService, CategoryResponse } from '@/services/api/catalogService';
|
|
|
|
interface MobileDrawerProps {
|
|
isOpen: boolean;
|
|
onClose: () => void;
|
|
}
|
|
|
|
export const MobileDrawer: React.FC<MobileDrawerProps> = ({ isOpen, onClose }) => {
|
|
const [categories, setCategories] = useState<CategoryResponse[]>([]);
|
|
|
|
useEffect(() => {
|
|
if (isOpen) {
|
|
catalogService.getCategories().then((res) => {
|
|
if (Array.isArray(res)) setCategories(res);
|
|
});
|
|
}
|
|
}, [isOpen]);
|
|
|
|
React.useEffect(() => {
|
|
if (!isOpen) return;
|
|
const handleKeyDown = (e: KeyboardEvent) => {
|
|
if (e.key === 'Escape') onClose();
|
|
};
|
|
document.addEventListener('keydown', handleKeyDown);
|
|
return () => document.removeEventListener('keydown', handleKeyDown);
|
|
}, [isOpen, onClose]);
|
|
|
|
const links = [
|
|
{ name: 'Home', href: '/' },
|
|
{ name: 'Shop', href: '/shop' },
|
|
{ name: 'Services', href: '/service' },
|
|
{ name: 'Top Deals', href: '/shop' },
|
|
];
|
|
|
|
return (
|
|
<AnimatePresence>
|
|
{isOpen && (
|
|
<>
|
|
{/* Backdrop */}
|
|
<motion.div
|
|
initial={{ opacity: 0 }}
|
|
animate={{ opacity: 0.5 }}
|
|
exit={{ opacity: 0 }}
|
|
onClick={onClose}
|
|
className="fixed inset-0 bg-black z-50 xl:hidden"
|
|
/>
|
|
|
|
{/* Drawer Panel */}
|
|
<motion.div
|
|
initial={{ x: '-100%' }}
|
|
animate={{ x: 0 }}
|
|
exit={{ x: '-100%' }}
|
|
transition={{ type: 'tween', duration: 0.3 }}
|
|
className="fixed top-0 left-0 bottom-0 w-[280px] bg-white z-50 xl:hidden flex flex-col justify-between shadow-xl overflow-y-auto"
|
|
>
|
|
<div>
|
|
{/* Header */}
|
|
<div className="flex items-center justify-between p-4 border-b border-gray-100">
|
|
<span className="text-xl font-extrabold tracking-tight text-gray-900">
|
|
iFix<span className="text-primary">Kart</span>
|
|
</span>
|
|
<button
|
|
onClick={onClose}
|
|
className="p-1.5 text-gray-400 hover:text-gray-650 hover:bg-gray-50 rounded-lg transition-colors"
|
|
>
|
|
<X size={20} />
|
|
</button>
|
|
</div>
|
|
|
|
{/* Navigation Links */}
|
|
<div className="p-4 border-b border-gray-100 text-left">
|
|
<h4 className="text-[11px] font-bold text-gray-400 uppercase tracking-widest mb-3">Navigation</h4>
|
|
<ul className="space-y-3.5">
|
|
{links.map((link) => (
|
|
<li key={link.name}>
|
|
<Link
|
|
href={link.href}
|
|
onClick={onClose}
|
|
className="flex items-center justify-between text-sm font-bold text-gray-700 hover:text-primary transition-colors"
|
|
>
|
|
<span>{link.name}</span>
|
|
</Link>
|
|
</li>
|
|
))}
|
|
</ul>
|
|
</div>
|
|
|
|
{/* Categories */}
|
|
{categories.length > 0 && (
|
|
<div className="p-4 text-left">
|
|
<h4 className="text-[11px] font-bold text-gray-400 uppercase tracking-widest mb-3">Categories</h4>
|
|
<ul className="space-y-3">
|
|
{categories.map((cat) => (
|
|
<li key={cat.category_id}>
|
|
<Link
|
|
href={`/shop?category=${encodeURIComponent(cat.slug)}`}
|
|
onClick={onClose}
|
|
className="flex items-center gap-3 text-sm font-semibold text-gray-650 hover:text-primary transition-colors"
|
|
>
|
|
<Folder size={15} className="text-primary/70" />
|
|
<span>{cat.name}</span>
|
|
</Link>
|
|
</li>
|
|
))}
|
|
</ul>
|
|
</div>
|
|
)}
|
|
</div>
|
|
|
|
{/* Footer */}
|
|
<div className="p-4 border-t border-gray-100 text-xs text-gray-400 text-center font-medium bg-gray-50">
|
|
© {new Date().getFullYear()} iFixKart. All Rights Reserved.
|
|
</div>
|
|
</motion.div>
|
|
</>
|
|
)}
|
|
</AnimatePresence>
|
|
);
|
|
};
|