Untitled

 avatar
unknown
plain_text
10 months ago
14 kB
15
Indexable
import React, { useEffect, useState } from "react";
import { SelectSeatsInterface, Row, Column, Group } from "../types/Ticket";
import { useTicketMap } from "../hooks/useTicketMap";
import { Minus, Plus, X } from "lucide-react";
import { SkeletonSeats } from "../components/skeleton/seatsSkeleton";
import { ListDetailPriceSeat } from "../components/listDetailPriceSeat";
import { useTranslation } from "../services/translate/index";
import { Button } from "@/components/ui/button";
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "@/components/ui/dropdown-menu";
import { ChevronDown } from "lucide-react";
import idFlag from "../assets/ID.png";
import enFlag from "../assets/en.png";
import "../styles/app.css";
import Logo from "../../exhibitor-dashboard/assets/image/tixcorner_logo.png";
import { formatRupiah } from "../utils/formatRupiah";
import { groups } from "../services/data/seats";

type Language = "id" | "en";

interface LanguageOption {
  code: Language;
  name: string;
  flag: string;
}

const languages: LanguageOption[] = [
  { code: "id", name: "Bahasa Indonesia", flag: idFlag },
  { code: "en", name: "English", flag: enFlag },
];

export const SelectSeats: React.FC = () => {
  const [selectedSeats, setSelectedSeats] = useState<SelectSeatsInterface[]>([]);
  const [total, setTotal] = useState(0);
  const { fetchTicketMap, loadingTicketMap, area, ticket, error } = useTicketMap();
  const [selectedLanguage, setSelectedLanguage] = useState<Language>("en");
  const { t } = useTranslation(selectedLanguage);
  const [isScaled, setIsScaled] = useState(true);

  const [scale, setScale] = useState<number>(1);

  const zoomIn = () => {
    if (isScaled) {
      setScale((prevScale) => Math.min(prevScale + 0.2, 1));
    } else {
      setScale((prevScale) => Math.min(prevScale + 0.2, 1));
    }
  };

  const zoomOut = () => {
    setScale((prevScale) => Math.max(prevScale - 0.2, 0.5)); // Min zoom 0.2x
  };

  const handleLanguageChange = (languageCode: Language) => {
    setSelectedLanguage(languageCode);
  };

  useEffect(() => {
    fetchTicketMap("TWpVMg");
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  const toggleSeat = (seat: SelectSeatsInterface) => {
    setSelectedSeats((prevSeats) => {
      setIsScaled(false);
      const exists = prevSeats.some((s) => s.columnId === seat.columnId && s.columnName === seat.columnName);

      if (exists) {
        return prevSeats.filter((s) => !(s.columnId === seat.columnId && s.columnName === seat.columnName));
      } else {
        return [...prevSeats, seat];
      }
    });
  };

  useEffect(() => {
    let count = 0;
    selectedSeats.forEach((item) => {
      count += item.price!;
    });
    setTotal(count);
  }, [selectedSeats]);

  const sortGroups = (groups: Group[]) => {
    return groups.sort((a, b) => {
      const aRow = a.groupSequence <= 3 ? 0 : 1;
      const bRow = b.groupSequence <= 3 ? 0 : 1;

      if (aRow !== bRow) {
        return aRow - bRow;
      }

      return b.groupSequence - a.groupSequence;
    });
  };
  return (
    <>
      <nav className="sticky py-3 top-0 shadow-xs/05 z-50 w-full text-black bg-white ">
        <div className="container w-full md:w-[90vw] lg:w-[81vw] mx-auto px-4">
          <div className="flex h-16 items-center justify-between">
            {/* Logo/Brand */}
            <div className="flex items-center space-x-2">
              <div>
                <img src={Logo} className="w-[30vw] md:w-[7vw]" alt="" />
              </div>
            </div>

            {/* Language Dropdown */}
            <div className="flex  items-center ">
              <DropdownMenu>
                <DropdownMenuTrigger asChild>
                  <Button size="sm" variant="ghost" className="border-none shadow-none drop-shadow-none ring-0 ring-offset-0 focus-visible:ring-0 focus-visible:ring-offset-0 hover:bg-transparent active:bg-transparent">
                    <img src={languages.find((lang) => lang.code === selectedLanguage)?.flag} alt={selectedLanguage} className="w-6 h-6" />
                    <ChevronDown className="h-4 w-4 text-black" />
                  </Button>
                </DropdownMenuTrigger>
                <DropdownMenuContent align="end" className="w-48">
                  {languages.map((language) => (
                    <DropdownMenuItem key={language.code} onClick={() => handleLanguageChange(language.code)} className={`cursor-pointer ${selectedLanguage === language.code ? "bg-accent text-accent-foreground" : ""}`}>
                      <img src={language.flag} alt={language.name} className="w-6 h-6" />
                      {language.name}
                    </DropdownMenuItem>
                  ))}
                </DropdownMenuContent>
              </DropdownMenu>
            </div>
          </div>
        </div>
      </nav>

      <div className="bg-[#f5f7f9] pt-5">
        <div className="mx-auto md:w-[90vw] xl:w-[79vw]  px-4 md:px-0">
          {loadingTicketMap ? (
            <SkeletonSeats />
          ) : (
            <div className="flex justify-between  gap-x-4 pb-5  flex-col lg:flex-row">
              <div className="lg:w-[70%] bg-white pt-6 py-5 border rounded-md">
                <div className="pt-2 text-center">
                  <div className="h-15 flex justify-center items-center">
                    <p className="text-lg md:text-xl font-bold text-gray-600">{t("Select Your Seats")}</p>
                  </div>
                </div>

                <div className="seat flex flex-col justify-between  h-[50vh]  overflow-y-auto overflow-x-auto">
                  {error ? (
                    <div className="w-full h-[50vh] flex text-xl text-gray-500 font-semibold justify-center items-center">
                      <p>{error}</p>
                    </div>
                  ) : (
                    <div className={`flex md:justify-center transition-transform duration-300 `}>
                      {groups.length > 0 ? (
                        <div className="w-max px-5">
                          <div className="flex bg-gray-200 py-2 rounded-md justify-center w-full bg-red mb-4">
                            <p className=" font-semibold text-gray-500">{t("STAGE")}</p>
                          </div>

                          <div className="grid grid-cols-3 pt-7 gap-x-4 sm:gap-x-8 w-full bg-green-600"   style={{ width: 300, height: 300 }}
  >
                            {sortGroups(groups)?.map((item, indexPos) => (
                              <div key={indexPos} className="flex flex-col">
                                {item?.rows?.map((locationRows: Row, indexRows) => (
                                  <div key={indexRows} className="flex items-center py-1 mb-1">
                                    {indexPos === 0 && <div className="text-xs sm:text-sm font-semibold w-4 text-gray-600 mr-2 flex-shrink-0">{locationRows.rowName}</div>}

                                    <div className="grid grid-cols-6 gap-1">
                                      {locationRows.colums?.map((seat) => (
                                        <div
                                          key={seat.columnId}
                                          className={`
                                          ${selectedSeats ? " text-white bg-red-600" : ""}
                                          ${seat.status !== 0 ? "pointer-events-none opacity-50" : "cursor-pointer hover:opacity-80"}
                                        `}
                                          style={{
                                            backgroundColor: !selectedSeats ? seat.areaColor : undefined,
                                            width: 6,
                                            height: 6,
                                            borderRadius: "50%",
                                            display: "flex",
                                            justifyContent: "center",
                                            alignItems: "center",
                                            fontSize: 1,
                                          }}
                                        >
                                          <span>1</span>
                                        </div>
                                      ))}
                                    </div>
                                  </div>
                                ))}
                              </div>
                            ))}
                          </div>
                        </div>
                      ) : (
                        <div className="w-full h-100 flex items-center justify-center">
                          <p className="text-xl font-medium text-gray-500">Not found seats</p>
                        </div>
                      )}
                    </div>
                  )}

                  <div className="flex justify-end gap-3 p-3">
                    <button onClick={zoomIn} className={`flex items-center gap-2 px-4 py-2 rounded-lg transition-all duration-200 shadow-lg `} disabled={isScaled}>
                      <Plus size={18} />
                    </button>

                    <button
                      onClick={zoomOut}
                      className={`flex items-center gap-2 px-4 py-2 rounded-lg transition-all duration-200 shadow-lg ${
                        isScaled ? "bg-gray-200 text-gray-400 cursor-not-allowed shadow-sm" : "bg-white text-gray-700 hover:shadow-xl hover:bg-gray-50 cursor-pointer"
                      }`}
                      disabled={isScaled}
                    >
                      <Minus size={18} />
                    </button>
                  </div>
                </div>

                {!error && (
                  <div className="mx-5 space-y-6 mb-7">
                    <ListDetailPriceSeat t={t} area={area} ticket={ticket} />
                  </div>
                )}
              </div>

              <div className="lg:w-[29%] pt-5 lg:pt-0 rounded-md">
                <div className="border rounded-md bg-white">
                  {selectedSeats.length > 0 ? (
                    <div data-slot="card-content" className="p-6 pt-10 ">
                      <h3 className="text-lg font-bold mb-4 text-gray-600">{t("Selected Seats")}</h3>
                      <div className="space-y-3">
                        {selectedSeats.map((seat: SelectSeatsInterface, index) => (
                          <div key={index} className="flex justify-between items-center">
                            <span className="text-sm w-[50%] text-foreground">
                              {seat.rowName}
                              {seat.columnName}({seat.areaName})
                            </span>
                            <div className="flex justify-center gap-x-2 items-center">
                              <span className="text-sm font-semibold text-foreground">Rp{formatRupiah(seat.price || 0)}</span>
                              <X
                                size={15}
                                onClick={() => {
                                  toggleSeat({
                                    columnId: seat.columnId,
                                    columnName: seat.columnName,
                                  });
                                }}
                                className="text-red-600 cursor-pointer"
                              />
                            </div>
                          </div>
                        ))}

                        <div className="border-t pt-3 mt-3">
                          <div className="flex justify-between items-center">
                            <span className="font-semibold text-foreground">Total</span>
                            <span className="font-bold text-lg text-foreground">Rp{formatRupiah(total)}</span>
                          </div>
                        </div>
                      </div>

                      <div className="py-5">
                        <button
                          className="inline-flex cursor-pointer items-center justify-center gap-2 whitespace-nowrap text-sm font-medium transition-all w-full text-white py-2 px-4"
                          style={{
                            background: "linear-gradient(to top, #1f60c4 0%, #3a80d6 100%)",
                            borderRadius: "12px",
                          }}
                        >
                          Continue to Booking
                        </button>
                      </div>
                    </div>
                  ) : (
                    <div data-slot="card-content" className="p-6 min-h-40 flex flex-col justify-center">
                      <h3 className="text-lg font-bold mb-4 text-gray-500">{t("Selected Seats")}</h3>
                      <p className="text-muted-foreground text-sm">{t("No seats selected")}</p>
                    </div>
                  )}
                </div>
              </div>
            </div>
          )}
        </div>
      </div>

      <footer className="bg-gray-300 py-8 px-4">
        <div className="max-w-6xl mx-auto">
          <div className="text-center mb-6">
            <p className="text-gray-600 text-sm mb-2">Organiser Customer Support: Email | Whatsapp</p>
          </div>

          <div className="text-center">
            <p className="text-gray-600 text-sm">
              <span className="hover:text-gray-800 cursor-pointer">Kebijakan Privasi</span>
              <span className="mx-2">|</span>
              <span className="hover:text-gray-800 cursor-pointer">Syarat dan Ketentuan</span>
            </p>
          </div>
        </div>
      </footer>
    </>
  );
};

export default SelectSeats;
Editor is loading...
Leave a Comment