Skip to content

Commit ab083bc

Browse files
committed
feat: seatgrid 적용
1 parent 260d3e0 commit ab083bc

4 files changed

Lines changed: 71 additions & 19 deletions

File tree

src/entities/booking/ui/SeatGrid/index.tsx

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
"use client";
22

33
import { memo, useCallback, useMemo } from "react";
4+
import { useQueryClient } from "@tanstack/react-query";
45
import { cn } from "@/shared/utils/cn";
56
import { Seat, SeatLayout, SECTIONS } from "../../model/types";
67
import { SeatItem } from "../SeatItem";
@@ -14,14 +15,15 @@ export interface SeatGridProps {
1415
}
1516

1617
export const SeatGrid = memo<SeatGridProps>(({ layout, selectedSeat, onSeatSelect, className }) => {
18+
const queryClient = useQueryClient();
19+
1720
const handleSeatSelect = useCallback(
1821
(seat: Seat) => {
1922
onSeatSelect(seat);
2023
},
2124
[onSeatSelect],
2225
);
2326

24-
// 단일 섹션의 좌석 그리드 생성
2527
const seatGrid = useMemo(() => {
2628
if (!layout?.section) return [];
2729

@@ -45,11 +47,10 @@ export const SeatGrid = memo<SeatGridProps>(({ layout, selectedSeat, onSeatSelec
4547
}),
4648
);
4749
}, [layout?.section, layout?.seats]);
48-
49-
// 전체 섹션 그리드 생성 (2x5)
50+
5051
const allSectionsGrid = useMemo(() => {
51-
const sectionsRow1 = SECTIONS.slice(0, 5); // A~E
52-
const sectionsRow2 = SECTIONS.slice(5, 10); // F~J
52+
const sectionsRow1 = SECTIONS.slice(0, 5);
53+
const sectionsRow2 = SECTIONS.slice(5, 10);
5354

5455
return [sectionsRow1, sectionsRow2];
5556
}, []);
@@ -80,11 +81,14 @@ export const SeatGrid = memo<SeatGridProps>(({ layout, selectedSeat, onSeatSelec
8081
);
8182

8283
const renderSectionMiniGrid = (section: (typeof SECTIONS)[number]) => {
84+
const cachedSeats = queryClient.getQueryData<Seat[]>(["seatState", section]);
8385
const sectionLayout = getSeatLayout(section);
8486
const pattern = getSeatPattern(section);
87+
8588
const seatMap = new Map<string, Seat>();
86-
87-
sectionLayout.seats.forEach(seat => {
89+
const seatsToUse = cachedSeats || sectionLayout.seats;
90+
91+
seatsToUse.forEach(seat => {
8892
seatMap.set(seat.seatNumber, seat);
8993
});
9094

src/views/booking/ui/BookingPage/index.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ import SelectSection from "@/widgets/booking/ui/SelectSection";
55
import SeatSection from "@/widgets/booking/ui/SeatSection";
66
import Button from "@/shared/ui/Button";
77
import BackHeader from "@/shared/ui/BackHeader";
8-
import { useSeatSelection } from "@/entities/booking/lib/useSeatSelection";
8+
import { useSeatSelection } from "@/widgets/booking/lib/useSeatSelection";
99
import { SectionType, Seat } from "@/entities/booking/model/types";
10-
import { useSeatBooking } from "@/entities/booking/lib/useSeatBooking";
10+
import { useSeatBooking } from "@/widgets/booking/lib/useSeatBooking";
1111

1212
const BookingPage = () => {
1313
const {

src/widgets/booking/ui/SeatSection/index.tsx

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
"use client";
22

3-
import { memo, useMemo } from "react";
3+
import { memo } from "react";
44
import { cn } from "@/shared/utils/cn";
55
import { Section, Seat, SelectedSeatInfo } from "@/entities/booking/model/types";
66
import { SeatGrid } from "@/entities/booking/ui/SeatGrid";
77
import { SelectedSeatDisplay } from "@/entities/booking/ui/SelectedSeatDisplay";
8+
import { useSectionSeatState } from "@/widgets/booking/lib/useSeatState";
89
import { getSeatLayout } from "@/entities/booking/model/seatLayouts";
10+
import { SEAT_STATUS } from "@/entities/booking/model/types";
911

1012
interface SeatSectionProps {
1113
selectedSection: Section | null;
@@ -17,15 +19,37 @@ interface SeatSectionProps {
1719

1820
export const SeatSection = memo<SeatSectionProps>(
1921
({ selectedSection, selectedSeat, onSeatSelect, selectedSeatInfo, className }) => {
20-
const seatLayout = useMemo(() => {
21-
if (!selectedSection) return null;
22-
return getSeatLayout(selectedSection);
23-
}, [selectedSection]);
22+
const { data: sectionSeats, isLoading, error } = useSectionSeatState(selectedSection!);
23+
24+
const getLayout = () => {
25+
if (selectedSection) {
26+
const getFallbackSeats = () => {
27+
const layout = getSeatLayout(selectedSection);
28+
return layout.seats.map(seat => ({
29+
...seat,
30+
status: SEAT_STATUS.UNAVAILABLE,
31+
}));
32+
};
33+
34+
return {
35+
section: selectedSection,
36+
seats: sectionSeats || getFallbackSeats()
37+
};
38+
}
39+
40+
return null;
41+
};
42+
43+
const layout = getLayout();
2444

2545
return (
2646
<div className={cn("pb-20", className)}>
2747
<div className="h-80">
28-
<SeatGrid layout={seatLayout} selectedSeat={selectedSeat} onSeatSelect={onSeatSelect} />
48+
<SeatGrid
49+
layout={layout}
50+
selectedSeat={selectedSeat}
51+
onSeatSelect={(isLoading || !!error) ? () => {} : onSeatSelect}
52+
/>
2953
</div>
3054

3155
<div className="h-28"></div>

src/widgets/booking/ui/SelectSection/index.tsx

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
"use client";
22

33
import { useState, useCallback, memo, useMemo } from "react";
4+
import { useQueryClient } from "@tanstack/react-query";
45
import { cn } from "@/shared/utils/cn";
56
import { SectionButtons } from "@/entities/booking/ui/SectionButtons";
6-
import { SectionType, Section, SECTIONS, SEAT_INFO } from "@/entities/booking/model/types";
7+
import { SectionType, Section, Seat, SECTIONS, SEAT_INFO, SEAT_STATUS } from "@/entities/booking/model/types";
8+
import { usePrefetchAllSeats } from "@/widgets/booking/lib/useSeatState";
79

810
interface SelectSectionProps {
911
onSectionSelect?: (section: SectionType) => void;
@@ -12,6 +14,9 @@ interface SelectSectionProps {
1214

1315
export const SelectSection = memo<SelectSectionProps>(({ onSectionSelect, className }) => {
1416
const [selectedSection, setSelectedSection] = useState<SectionType>(null);
17+
const queryClient = useQueryClient();
18+
19+
const { isLoading: isPrefetching } = usePrefetchAllSeats();
1520

1621
const handleSectionSelect = useCallback(
1722
(section: SectionType) => {
@@ -23,12 +28,31 @@ export const SelectSection = memo<SelectSectionProps>(({ onSectionSelect, classN
2328

2429
const seatInfoMap = useMemo(() => {
2530
const map: Record<Section, string> = {} as Record<Section, string>;
31+
32+
if (isPrefetching) {
33+
SECTIONS.forEach(section => {
34+
const seatInfo = SEAT_INFO[section];
35+
map[section] = `${seatInfo.occupied}/${seatInfo.total}`;
36+
});
37+
return map;
38+
}
39+
2640
SECTIONS.forEach(section => {
27-
const seatInfo = SEAT_INFO[section];
28-
map[section] = `${seatInfo.occupied}/${seatInfo.total}`;
41+
const total = SEAT_INFO[section].total;
42+
43+
const cachedSeats = queryClient.getQueryData<Seat[]>(["seatState", section]);
44+
45+
if (cachedSeats) {
46+
const occupied = cachedSeats.filter(seat => seat.status === SEAT_STATUS.UNAVAILABLE).length;
47+
map[section] = `${occupied}/${total}`;
48+
} else {
49+
const seatInfo = SEAT_INFO[section];
50+
map[section] = `${seatInfo.occupied}/${seatInfo.total}`;
51+
}
2952
});
53+
3054
return map;
31-
}, []);
55+
}, [isPrefetching, queryClient]);
3256

3357
return (
3458
<div className={cn("w-full", className)}>

0 commit comments

Comments
 (0)