Untitled
unknown
plain_text
10 months ago
14 kB
14
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