Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[feat] 지도, 미팅룸 예약 추가 작업 #41

Merged
merged 13 commits into from
Jun 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added public/branch/branch1-1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/branch/branch1-2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/branch/branch1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/branch/branch2-1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/branch/branch2-2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/branch/branch2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/branch/branch3-1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/branch/branch3-2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/branch/branch3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
11 changes: 11 additions & 0 deletions public/office/check.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/office/focus.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/office/medium1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/office/medium2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/office/medium3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/office/mini1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/office/mini2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/office/mini3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
12 changes: 12 additions & 0 deletions public/office/people.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/office/recharge.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/office/standard1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/office/standard2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/office/standard3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/office/state1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/office/state2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/office/state3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
34 changes: 15 additions & 19 deletions src/components/map/BranchInfo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,22 @@ const BranchInfo: React.FC = () => {
const [urgentNotice, setUrgentNotice] = useState<{ title: string; content: string } | null>(null);

const [currentSlide, setCurrentSlide] = useState(1);
const totalSlides = 3;
const totalSlides = 2;

const branchName = router.query.name as string;
const address = router.query.address as string;
const branchPhoneNumber = router.query.branchPhoneNumber as string;
const roadFromStation = router.query.roadFromStation as string;
const stationToBranch = router.query.stationToBranch as string;
const branchId = router.query.branchId;
const branchImage = router.query.image as string;

const numericBranchId = Array.isArray(branchId) ? parseInt(branchId[0], 10) : parseInt(branchId as string, 10);

const [activeTab, setActiveTab] = useState('meetingRoom');

const imagePrefix = (branchImage || '').replace('.png', '');

console.log(branchId);
console.log(numericBranchId)

Expand Down Expand Up @@ -103,7 +108,10 @@ const BranchInfo: React.FC = () => {
const data = await getSelectedOfficeInfo(branchName);
if (data.data) {
setReservedBranch(data?.data, Date.now());
router.push('/reservation');
router.push({
pathname: '/reservation',
query: { tab: activeTab },
});
}
} catch (error) {
console.error('Error updating selected branch:', error);
Expand Down Expand Up @@ -147,7 +155,7 @@ const BranchInfo: React.FC = () => {
onSlideChange={(swiper) => setCurrentSlide(swiper.realIndex + 1)}>
<SwiperSlide className="flex justify-center items-center h-full relative">
<Image
src="/map/OfficeDefaultImg2.png"
src={`${imagePrefix}-1.png`}
alt="Office Image 1"
width={500}
height={246}
Expand All @@ -159,7 +167,7 @@ const BranchInfo: React.FC = () => {
</SwiperSlide>
<SwiperSlide className="flex justify-center items-center h-full relative">
<Image
src="/map/OfficeDefaultImg2.png"
src={`${imagePrefix}-2.png`}
alt="Office Image 2"
width={500}
height={246}
Expand All @@ -169,18 +177,6 @@ const BranchInfo: React.FC = () => {
{currentSlide} / {totalSlides}
</div>
</SwiperSlide>
<SwiperSlide className="flex justify-center items-center h-full relative">
<Image
src="/map/OfficeDefaultImg2.png"
alt="Office Image 3"
width={500}
height={246}
className="h-[246px] object-cover"
/>
<div className="w-[50px] absolute bottom-2 right-2 bg-black bg-opacity-60 text-white px-2 py-1 rounded text-center">
{currentSlide} / {totalSlides}
</div>
</SwiperSlide>
</Swiper>
</div>
<article className="">
Expand Down Expand Up @@ -250,7 +246,7 @@ const BranchInfo: React.FC = () => {
<div className="text-black/opacity-20 text-lg font-extrabold py-[10px]">
공용 공간 리스트
</div>
<TabSection branchId={numericBranchId} />
<TabSection branchId={numericBranchId} activeTab={activeTab} setActiveTab={setActiveTab} />
</div>
<div className="w-full h-px bg-neutral-200" />
<div className="px-4 py-6">
Expand Down Expand Up @@ -345,9 +341,9 @@ const BranchInfo: React.FC = () => {
<div className="text-black/opacity-20 text-lg font-extrabold">공지사항</div>
</div>
<BranchOffice branchName={branchName} setUrgentNotice={setUrgentNotice} />
<footer className="fixed bottom-0 w-full text-center pb-[30px] bg-white no-box-shadow">
<footer className="fixed bottom-0 left-1/2 transform -translate-x-1/2 w-full max-w-[393px] px-4 text-center pb-[30px] bg-white no-box-shadow">
<button
className="reserveBtn w-[90%] h-12 rounded-lg border border-indigo-700 text-center text-stone-50 text-[15px] font-semibold"
className="reserveBtn w-[100%] mx-auto h-12 rounded-lg border border-indigo-700 text-center text-stone-50 text-[15px] font-semibold"
onClick={handleGoToReservation}>
예약하기
</button>
Expand Down
24 changes: 14 additions & 10 deletions src/components/map/BranchModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ import { useRouter } from 'next/router';
import { getSelectedOfficeInfo } from '@/api/map/getSelectedOffice';
import { useBranchStore2 } from '@/store/reserve.store';

const getBranchImage = (branchName: string): string => {
const hash = Array.from(branchName).reduce((acc: number, char: string) => acc + char.charCodeAt(0), 0);
const imageIndex = (hash % 3) + 1;
return `/branch/branch${imageIndex}.png`;
};

const BranchModal: React.FC<ModalProps> = ({ isOpen, onClose, branchName, branchAddress, branchActiveMeetingRoomCount, branchTotalMeetingRoomCount }) => {
const modalRef = useRef<HTMLDivElement>(null);
Expand All @@ -27,36 +32,35 @@ const BranchModal: React.FC<ModalProps> = ({ isOpen, onClose, branchName, branch
onClose();
}
};

if (isOpen) {
document.addEventListener('mousedown', handleClickOutside);
} else {
document.removeEventListener('mousedown', handleClickOutside);
}

return () => {
document.removeEventListener('mousedown', handleClickOutside);
};
}, [isOpen, onClose]);


if (!isOpen) return null;


const handleOfficeInfo = async () => {
try {
const data = await getSelectedOfficeInfo(branchName);
const officeInfo = data.data;
const data = await getSelectedOfficeInfo(branchName);
const officeInfo = data.data;
console.log(officeInfo);
router.push({
pathname: `/branches/${encodeURIComponent(branchName)}`,
query: {
name: branchName,
query: {
name: branchName,
address: officeInfo.branchAddress,
branchPhoneNumber: officeInfo.branchPhoneNumber,
roadFromStation: officeInfo.roadFromStation,
stationToBranch: officeInfo.stationToBranch.join(','),
branchId: officeInfo.branchId as number,
image: getBranchImage(branchName),
}
}, `/branches/${encodeURIComponent(branchName)}`);
} catch (error) {
Expand All @@ -66,7 +70,7 @@ const BranchModal: React.FC<ModalProps> = ({ isOpen, onClose, branchName, branch

const handleGoToReservation = async () => {
try {
const data = await getSelectedOfficeInfo(branchName);
const data = await getSelectedOfficeInfo(branchName);
if (data.data) {
setReservedBranch(data?.data, Date.now());
router.push('/reservation/');
Expand All @@ -82,7 +86,7 @@ const BranchModal: React.FC<ModalProps> = ({ isOpen, onClose, branchName, branch
<div className='flex'>
<div className="flex-shrink-0 w-[88px] h-[88px] bg-gray-300 rounded-md">
<Image
src="/map/OfficeDefaultImg.png"
src={getBranchImage(branchName)}
alt="Office"
width={88}
height={88}
Expand Down
151 changes: 133 additions & 18 deletions src/components/map/TapSection.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,53 @@
import React, { useState, useEffect } from 'react';
import React, { useState, useEffect, SetStateAction, Dispatch } from 'react';
import { getOfficeMeetingRoomCount } from '@/api/map/getAvailableOffice';
import { OfficeRoomCounts } from '@/api/types/branch';
import Image from 'next/image';

const TabSection = ({ branchId }: { branchId: number }) => {
const [activeTab, setActiveTab] = useState('meetingRoom');
const imagePairs = [
{
mini: '/office/mini1.png',
standard: '/office/standard1.png',
medium: '/office/medium1.png',
state: '/office/state1.png',
},
{
mini: '/office/mini2.png',
standard: '/office/standard2.png',
medium: '/office/medium2.png',
state: '/office/state2.png',
},
{
mini: '/office/mini3.png',
standard: '/office/standard3.png',
medium: '/office/medium3.png',
state: '/office/state3.png',
},
];

const hashCode = (str: string): number => {
let hash = 0;
for (let i = 0; i < str.length; i++) {
const char = str.charCodeAt(i);
hash = (hash << 5) - hash + char;
hash |= 0;
}
return hash;
};

const seededRandom = (seed: number) => {
const x = Math.sin(seed++) * 10000;
return x - Math.floor(x);
};

interface TabSectionProps {
branchId: number;
activeTab: string;
setActiveTab: Dispatch<SetStateAction<string>>;
}

const TabSection: React.FC<TabSectionProps> = ({ branchId, activeTab, setActiveTab }) => {
const [data, setData] = useState<OfficeRoomCounts | null>(null);
const [selectedImages, setSelectedImages] = useState(imagePairs[0]);

useEffect(() => {
const fetchData = async () => {
Expand All @@ -22,25 +65,97 @@ const TabSection = ({ branchId }: { branchId: number }) => {
}
}, [branchId]);

useEffect(() => {
if (branchId) {
const seed = hashCode(branchId.toString());
const randomIndex = Math.floor(seededRandom(seed) * imagePairs.length);
setSelectedImages(imagePairs[randomIndex]);
}
}, [branchId]);

const renderContent = () => {
if (!data) return <div></div>;

switch (activeTab) {
case 'meetingRoom':
return (
<div>
<p>Mini Room Count: {data.miniRoomCount}</p>
<p>Standard Room Count: {data.standardRoomCount}</p>
<p>Medium Room Count: {data.mediumRoomCount}</p>
<p>State Room Count: {data.stateRoomCount}</p>
const meetingRooms = [
{ type: 'mini', label: '미니', capacity: '1~4명', description: '적은 인원 수가 빠르게 회의 진행할 수 있는 공간', count: data.miniRoomCount },
{ type: 'standard', label: '스탠다드', capacity: '5~8명', description: '적은 인원 수가 빠르게 회의 진행할 수 있는 공간', count: data.standardRoomCount },
{ type: 'medium', label: '미디움', capacity: '9~12명', description: '적은 인원 수가 빠르게 회의 진행할 수 있는 공간', count: data.mediumRoomCount },
{ type: 'state', label: '스테이트', capacity: '13~15명', description: '여러 팀의 협업 또는 화상회의가 편한 공간', count: data.stateRoomCount },
] as const;

if (activeTab === 'meetingRoom') {
return (
<div>
{meetingRooms.map((room, index) => (
<div key={index} className="relative flex flex-col h-full rounded mb-[12px]">
<Image src={selectedImages[room.type]} width={361} height={120} alt={`${room.label} Room`} className="object-cover rounded" />
<div className="absolute top-0 left-0 w-full h-full flex flex-col justify-between bg-black bg-opacity-50 text-white p-4 rounded">
<div className='h-full'>
<div className='flex flex-row justify-between'>
<p className="text-white text-base font-semibold font-['Pretendard']">{room.label}</p>
<p className="text-white text-base font-normal font-['Pretendard']">{room.count}개</p>
</div>
<div className='flex flex-row mt-[10px]'>
<Image src="/office/people.svg" alt="people" width={14} height={10} className="" />
<p className="text-white text-xs font-normal font-['Pretendard'] ml-[5px] pt-[2px]">{room.capacity} 수용 가능</p>
</div>
<p className="absolute bottom-0 pb-4 mt-auto text-white text-xs font-normal font-['Pretendard']">{room.description}</p>
</div>
</div>
</div>
))}
</div>
);
}

if (activeTab === 'rechargingRoom') {
return (
<div className="relative flex flex-col h-full rounded mb-[12px]">
<Image src='/office/recharge.png' width={361} height={120} alt="Recharge Room" className="object-cover rounded" />
<div className="absolute top-0 left-0 w-full h-full flex flex-col justify-between bg-black bg-opacity-50 text-white p-4 rounded">
<div className='h-full'>
<div className='flex flex-row justify-between'>
<p className="text-white text-base font-semibold font-['Pretendard']">리차징룸</p>
<p className="text-white text-base font-normal font-['Pretendard']">{data.rechargingRoomCount}개</p>
</div>
<div className='flex flex-row items-center mt-[10px]'>
<Image src="/office/people.svg" alt="people" width={14} height={10} className="" />
<p className="text-white text-xs font-normal font-['Pretendard'] ml-[5px] pt-[2px]">예약 후 이용가능</p>
</div>
<div className='flex flex-row mt-[5px] items-center'>
<Image src="/office/check.svg" alt="check" width={11} height={11} className="" />
<p className="text-white text-xs font-normal font-['Pretendard'] ml-[5px] pt-[2px]">리클라이너</p>
</div>
<p className="absolute bottom-0 pb-4 mt-auto text-white text-xs font-normal font-['Pretendard'] leading-[18px]">휴대폰 고속 충전기 및 리클라이너가 구비되어 있어<br/>업무 중 휴식이 필요할 때 편리하게 이용할 수 있습니다.</p>
</div>
</div>
);
case 'rechargingRoom':
return <div>Recharging Room Count: {data.rechargingRoomCount}</div>;
case 'focusZone':
return <div>Focus Desk Count: {data.focusDeskCount}</div>;
default:
return null;
</div>
);
}

if (activeTab === 'focusZone') {
return (
<div className="relative flex flex-col h-full rounded mb-[12px]">
<Image src='/office/focus.png' width={361} height={120} alt="Focus Zone" className="object-cover rounded" />
<div className="absolute top-0 left-0 w-full h-full flex flex-col justify-between bg-black bg-opacity-50 text-white p-4 rounded">
<div className='h-full'>
<div className='flex flex-row justify-between'>
<p className="text-white text-base font-semibold font-['Pretendard']">포커스존</p>
<p className="text-white text-base font-normal font-['Pretendard']">{data.focusDeskCount}개</p>
</div>
<div className='flex flex-row mt-[10px]'>
<Image src="/office/people.svg" alt="people" width={14} height={10} className="" />
<p className="text-white text-xs font-normal font-['Pretendard'] ml-[5px] pt-[2px]">단독 사용</p>
</div>
<div className='flex flex-row mt-[5px]'>
<Image src="/office/check.svg" alt="check" width={11} height={11} className="" />
<p className="text-white text-xs font-normal font-['Pretendard'] ml-[5px] pt-[2px]">고속 충전기</p>
</div>
<p className="absolute bottom-0 pb-4 mt-auto text-white text-xs font-normal font-['Pretendard'] leading-[18px]">개인 오피스 안에서 업무를 효율적으로 볼 수 있습니다.</p>
</div>
</div>
</div>
);
}
};

Expand Down
19 changes: 17 additions & 2 deletions src/components/reservation/ReservationIndex.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,28 @@
import React, { useState } from 'react';
import React, { useEffect, useState } from 'react';
import CurrentRoom from './shared/CurrentRoom';
import ChangeRoomType from './shared/ChangeRoomType';
import FocuszoneIndex from './focuszone/FocuszoneIndex';
import MeetingRoomIndex from './meetingRoom/MeetingRoomIndex';
import RechargingRoomIndex from './rechargingRoom/RechargingRoomIndex';

const ReservationIndex = () => {
interface ReservationIndexProps {
initialTab: string;
}

const ReservationIndex: React.FC<ReservationIndexProps> = ({ initialTab }) => {
const [currentRoom, setCurrentRoom] = useState('meeting');

useEffect(() => {
if (initialTab) {
const tabMapping: { [key: string]: string } = {
meetingRoom: 'meeting',
rechargingRoom: 'recharging',
focusZone: 'focus'
};
setCurrentRoom(tabMapping[initialTab] || 'meeting');
}
}, [initialTab]);

return (
<div className="mt-[80px] mb-[100px] ">
{/* 현재 지정된 오피스 */}
Expand Down
Loading
Loading