vkashti / app / reservations / page.tsx
page.tsx
Raw
// @ts-nocheck
'use client';
import { useState, useEffect, useRef, Suspense } from 'react';
import ReserveForm from '@/components/ui/Reserve';
import { Event, Deal, Tag } from '@/types/types';
import { motion } from 'framer-motion';
import { createClient } from '@/utils/supabase/client';
import { MdLocalOffer, MdAddCircleOutline } from 'react-icons/md';

// Animation variants
const fadeIn = {
  hidden: { opacity: 0, y: 20 },
  visible: { opacity: 1, y: 0, transition: { duration: 0.5, ease: "easeOut" } }
};

const staggerContainer = {
  hidden: { opacity: 0 },
  visible: {
    opacity: 1,
    transition: {
      staggerChildren: 0.1
    }
  }
};

export default function ReservationsPage() {
  const supabase = createClient();
  const [selectedEvent, setSelectedEvent] = useState<Event | undefined>(undefined);
  const [eventType, setEventType] = useState("Резервация");
  const [deals, setDeals] = useState<Deal[]>([]);
  const [filteredDeals, setFilteredDeals] = useState<Deal[]>([]);
  const [tags, setTags] = useState<Tag[]>([]);
  const [dealTags, setDealTags] = useState<Record<number, Tag[]>>({});
  const [persons, setPersons] = useState<string>('');
  const [isLoading, setIsLoading] = useState(true);
  const [additionalDescription, setAdditionalDescription] = useState<string>('');
  
  const reserveFormRef = useRef<any>(null);

  // Check for event data in sessionStorage (from events page)
  useEffect(() => {
    const storedEvent = sessionStorage.getItem('selectedEvent');
    
    if (storedEvent) {
      try {
        const parsedEvent = JSON.parse(storedEvent);
        setSelectedEvent(parsedEvent);
        setEventType(parsedEvent.title || "Резервация");
        // Clear the stored event after retrieving it
        sessionStorage.removeItem('selectedEvent');
      } catch (e) {
        console.error("Error parsing stored event:", e);
      }
    }
    
    // Fetch deals when component mounts
    fetchDeals();
  }, []);

  // Filter deals when persons count changes
  useEffect(() => {
    if (deals.length > 0) {
      filterDealsByPersons();
    }
  }, [persons, deals]);

  const fetchDeals = async () => {
    try {
      setIsLoading(true);
      
      // Fetch deals
      const { data: dealsData, error: dealsError } = await supabase
        .from('deals')
        .select('*');
      
      if (dealsError) throw dealsError;
      setDeals(dealsData || []);
      
      // Fetch tags
      const { data: tagsData, error: tagsError } = await supabase
        .from('tags')
        .select('*');
        
      if (tagsError) throw tagsError;
      setTags(tagsData || []);
      
      // Fetch deal-tag relationships
      const { data: dealTagsData, error: dealTagsError } = await supabase
        .from('deal_tags')
        .select('*');
        
      if (dealTagsError) throw dealTagsError;
      
      // Build map of deal_id -> tags[]
      const tagMap: Record<number, Tag[]> = {};
      
      if (dealTagsData && tagsData) {
        for (const dt of dealTagsData) {
          const tag = tagsData?.find(t => t.id === dt.tag_id);
          if (tag) {
            if (!tagMap[dt.deal_id]) tagMap[dt.deal_id] = [];
            tagMap[dt.deal_id].push(tag);
          }
        }
      }
      
      setDealTags(tagMap);
      
      // Initial filtering (will update when persons changes)
      setFilteredDeals(dealsData || []);
    } catch (err) {
      console.error('Error fetching deals:', err);
    } finally {
      setIsLoading(false);
    }
  };

  const filterDealsByPersons = () => {
    if (!persons || persons === '') {
      // Sort all deals by price in ascending order
      const sortedDeals = [...deals].sort((a, b) => a.price - b.price);
      setFilteredDeals(sortedDeals);
      return;
    }
    
    const personsCount = parseInt(persons, 10);
    
    // Filter deals based on min_group_size and max_group_size
    const filtered = deals.filter(deal => {
      // If no min/max specified, always include
      if (!deal.min_group_size && !deal.max_group_size) return true;
      
      // Check if persons count is within range
      const withinMinRange = !deal.min_group_size || personsCount >= deal.min_group_size;
      const withinMaxRange = !deal.max_group_size || personsCount <= deal.max_group_size;
      
      return withinMinRange && withinMaxRange;
    });
    
    // Sort filtered deals by price in ascending order
    const sortedFilteredDeals = filtered.sort((a, b) => a.price - b.price);
    
    setFilteredDeals(sortedFilteredDeals);
  };

  // Handler for when the persons field changes in the reservation form
  const handlePersonsChange = (value: string) => {
    setPersons(value);
  };

  // Function to add a deal to the description
  const handleAddDeal = (deal: Deal) => {
    const dealInfo = `Добавена оферта: ${deal.title} (${deal.price} лв.)`;
    
    // Update the additional description
    setAdditionalDescription(prev => {
      const newDesc = prev ? `${prev}\n${dealInfo}` : dealInfo;
      
      // If we have access to the reserveFormRef component, update its description
      if (reserveFormRef.current && typeof reserveFormRef.current.updateDescription === 'function') {
        reserveFormRef.current.updateDescription(newDesc);
      }
      
      return newDesc;
    });
  };

  // Deal card component
  const DealCard = ({ deal }: { deal: Deal }) => {
    const dealTagsList = dealTags[deal.id] || [];
    const [expandedBenefits, setExpandedBenefits] = useState(false);
    
    return (
      <motion.div
        variants={fadeIn}
        className="bg-white rounded-xl shadow-md overflow-hidden transform transition-all duration-300 hover:shadow-lg border border-gray-100"
      >
        <div className="p-5">
          <div className="flex justify-between items-center mb-3">
            <h3 className="text-lg font-bold tracking-tight">{deal.title}</h3>
            <div className="flex items-center bg-orange-100 rounded-full overflow-hidden shadow-sm">
              <div className="px-2 py-1">
                <MdLocalOffer className="text-orange-500" />
              </div>
              <div className="px-3 py-1 bg-orange-500 text-white text-sm font-medium">
                {deal.price} лв
              </div>
            </div>
          </div>
          
          <p className="text-gray-600 mb-4 text-sm">{deal.description}</p>
          
          {/* Tags */}
          {dealTagsList.length > 0 && (
            <div className="flex flex-wrap gap-1 mb-4">
              {dealTagsList.map(tag => (
                <span key={tag.id} className="border border-gray-200 text-gray-600 text-xs px-2 py-0.5 rounded-full">
                  {tag.name}
                </span>
              ))}
            </div>
          )}
          
          {deal.benefits && deal.benefits.length > 0 && (
            <>
              <h4 className="font-semibold text-gray-800 mb-2 text-sm">Включва:</h4>
              <ul className="space-y-1 mb-4 text-sm">
                {(expandedBenefits ? deal.benefits : deal.benefits.slice(0, 2)).map((item, index) => (
                  <li key={index} className="flex items-start">
                    <span className="text-orange-500 mr-2"></span>
                    <span className="text-gray-700">{item}</span>
                  </li>
                ))}
                {!expandedBenefits && deal.benefits.length > 2 && (
                  <li 
                    className="text-orange-500 text-xs italic cursor-pointer hover:underline flex items-center" 
                    onClick={() => setExpandedBenefits(true)}
                  >
                    + още {deal.benefits.length - 2}
                  </li>
                )}
                {expandedBenefits && (
                  <li 
                    className="text-orange-500 text-xs italic cursor-pointer hover:underline flex items-center" 
                    onClick={() => setExpandedBenefits(false)}
                  >
                    Скрий
                  </li>
                )}
              </ul>
            </>
          )}
          
          <button 
            className="w-full btn btn-sm btn-outline border-orange-500 text-orange-500 hover:bg-orange-500 hover:text-white"
            onClick={() => handleAddDeal(deal)}
          >
            <MdAddCircleOutline className="mr-1" /> добави
          </button>
        </div>
      </motion.div>
    );
  };

  return (
    <div className="max-w-6xl mx-auto px-6 py-12">
      <motion.div
        initial={{ opacity: 0, y: 20 }}
        animate={{ opacity: 1, y: 0 }}
        transition={{ duration: 0.5 }}
      >
        <h1 className="text-3xl font-bold text-center">
          {selectedEvent ? selectedEvent.title : "Резервация"}
        </h1>
        <div className="h-2" />
        <p className="text-center text-gray-500">{selectedEvent?.description || "Направете онлайн резервация"}</p>
        <div className="h-8" />
        
        <Suspense fallback={<div className="h-[300px] flex items-center justify-center">Зареждане...</div>}>
          <ReserveForm 
            eventType={eventType}
            event={selectedEvent}
            onPersonsChange={handlePersonsChange}
            ref={reserveFormRef}
          />
        </Suspense>
        
        {persons && (
          <div className="mt-12">
            <div className="text-xl font-bold text-center mb-8">
              Специални предложения за <span style={{ fontFamily: 'sans-serif !important' }}>{persons}</span> {parseInt(persons, 10) === 1 ? 'човек' : 'човека'}
            </div>
            
            {isLoading ? (
              <div className="grid grid-cols-1 md:grid-cols-3 gap-6">
                {[1, 2, 3].map(i => (
                  <div key={i} className="bg-gray-100 h-64 rounded-xl animate-pulse"></div>
                ))}
              </div>
            ) : filteredDeals.length > 0 ? (
              <motion.div
                variants={staggerContainer}
                initial="hidden"
                animate="visible"
                className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6"
              >
                {filteredDeals.map(deal => (
                  <DealCard key={deal.id} deal={deal} />
                ))}
              </motion.div>
            ) : (
              <p className="text-center text-gray-500">
                Няма специални предложения за избрания брой гости.
              </p>
            )}
          </div>
        )}
        
        <div className="mt-8 text-center">
          <motion.p 
            className="text-gray-500 text-sm"
            initial={{ opacity: 0 }}
            animate={{ opacity: 1 }}
            transition={{ delay: 0.3, duration: 0.5 }}
          >
            отнема само 20 секунди!
          </motion.p>
        </div>
      </motion.div>
    </div>
  );
}