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] 미팅룸 추가 작업 #49

Merged
merged 6 commits into from
Jun 10, 2024
Merged
10 changes: 3 additions & 7 deletions src/api/reservation/getBranchesByDistance.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
import { BranchDistanceResponse } from "../types/branch";

export const getBranchesByDistance = async (latitude: number, longitude: number): Promise<BranchDistanceResponse[]> => {
export const getBranchesByDistance = async (branchId: number): Promise<BranchDistanceResponse[]> => {
const backendUrl = process.env.NEXT_PUBLIC_BASE_URL;
const url = new URL(`${backendUrl}branches/distance`);

// Add latitude and longitude as query parameters
url.searchParams.append('latitude', String(latitude));
url.searchParams.append('longitude', String(longitude));
const url = new URL(`${backendUrl}branches/${branchId}/near`);

const token = document.cookie.replace(/(?:(?:^|.*;\s*)token\s*=\s*([^;]*).*$)|^.*$/, "$1");

Expand Down Expand Up @@ -34,4 +30,4 @@ export const getBranchesByDistance = async (latitude: number, longitude: number)
}

return data.data;
};
};
2 changes: 1 addition & 1 deletion src/api/types/branch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ export interface Branch {
branchAddress: string;
branchLatitude: number;
branchLongitude: number;
branchId?: number;
branchId: number;
}

export interface ModalProps {
Expand Down
20 changes: 18 additions & 2 deletions src/components/home/AvailableRoom.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,15 @@ import React, { useEffect, useState } from 'react';
import { useQuery, useQueryClient } from 'react-query';
import { getAllAvailableCount } from './remote/mainReservation';
import { useRouter } from 'next/router';
import { getSelectedOfficeInfo } from '@/api/map/getSelectedOffice';
import { useBranchStore2 } from '@/store/reserve.store';

const AvailableRoom = () => {
const router = useRouter();
const queryClient = useQueryClient();
const [currentTime, setCurrentTime] = useState(format(new Date(), 'HH:mm'));
const selectedBranch = useBranchStore((state) => state.selectedBranch);
const { setReservedBranch } = useBranchStore2();

const { data } = useQuery(
['AllAvailableCount', selectedBranch?.branchId],
Expand All @@ -32,6 +35,20 @@ const AvailableRoom = () => {
};
}, []);

const handleGoToReservation = async () => {
try {
const data = await getSelectedOfficeInfo(selectedBranch!.branchName);
if (data.data) {
setReservedBranch(data?.data, Date.now());
router.push({
pathname: '/reservation',
});
}
} catch (error) {
console.error('Error updating selected branch:', error);
}
};

if (!data) {
return null;
}
Expand Down Expand Up @@ -122,8 +139,7 @@ const AvailableRoom = () => {

{/* 하단 */}
<div
onClick={() => router.push('reservation')}
className="cursor-pointer mt-8 rounded-lg w-full h-12 border-2 border-space-purple flex justify-center items-center text-space-purple text-[15px] font-semibold">
className="cursor-pointer mt-8 rounded-lg w-full h-12 border-2 border-space-purple flex justify-center items-center text-space-purple text-[15px] font-semibold" onClick={handleGoToReservation}>
예약하기
</div>
</div>
Expand Down
6 changes: 5 additions & 1 deletion src/components/reservation/meetingRoom/DatePickerModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,10 @@ const DatePickerModal: React.FC<DatePickerModalProps> = ({
endDateTime.setHours(endHour);
endDateTime.setMinutes(endMinute);

if (endDateTime <= startDateTime) {
endDateTime.setDate(endDateTime.getDate() + 1);
}

onConfirm(startDateTime, endDateTime, {
meetingRoomTypes:
selectedMeetingRoomTypes.length === 0
Expand Down Expand Up @@ -337,4 +341,4 @@ const DatePickerModal: React.FC<DatePickerModalProps> = ({
);
};

export default DatePickerModal;
export default DatePickerModal;
243 changes: 229 additions & 14 deletions src/components/reservation/meetingRoom/MeetingRoomIndex.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import DatePickerModal from './DatePickerModal';
import { useRouter } from 'next/router';
import { useBranchStore } from '@/store/branch.store';
import { getBranchesByDistance } from '@/api/reservation/getBranchesByDistance';
import { BranchDistanceResponse } from '@/api/types/branch';
import { getSelectedOfficeInfo } from '@/api/map/getSelectedOffice';

const formatDateToCustomString = (date: Date): string => {
const year = date.getFullYear();
Expand Down Expand Up @@ -85,6 +87,12 @@ const MeetingRoomIndex: React.FC = () => {

const [toastType, setToastType] = useState<string | null>(null);
const [activeTabState, setActiveTabState] = useState<string>('');

const [newMeetingRoomsInfo, setNewMeetingRoomsInfo] = useState<BranchDistanceResponse[]>();
const [newMeetingRoomsInfo2, setNewMeetingRoomsInfo2] = useState<BranchDistanceResponse[]>();
const [newMeetingRooms, setNewMeetingRooms] = useState<MeetingRoom[]>([]);
const [newMeetingRooms2, setNewMeetingRooms2] = useState<MeetingRoom[]>([]);


const currentBranch =
updatedTimeSelected && updatedTimeReserved && updatedTimeSelected > updatedTimeReserved
Expand Down Expand Up @@ -266,25 +274,106 @@ const MeetingRoomIndex: React.FC = () => {
setShowModal(true);
};

const fetchBranchesByDistance = async (latitude: number, longitude: number) => {
try {
const branches = await getBranchesByDistance(latitude, longitude);
console.log('Branches by distance:', branches);
} catch (error) {
console.error('Error fetching branches by distance:', error);
const fetchBranchesByDistance = async (branchId: number, existingParams: GetMeetingRoomsParams) => {
try {
const branches = await getBranchesByDistance(branchId);
console.log('Branches by distance:', branches);

if (branches && branches.length > 0) {
const nearestBranch = branches[0];
setNewMeetingRoomsInfo([nearestBranch]);
console.log(newMeetingRoomsInfo);
const newParams = {
...existingParams,
branchName: nearestBranch.branchName
};
const response = await getMeetingRooms(newParams);
const newRooms = response.meetingRoomForListList;
console.log(response);
console.log(newRooms);
setNewMeetingRooms(newRooms);
console.log(newMeetingRooms);

const nearestBranch2 = branches[1];
setNewMeetingRoomsInfo2([nearestBranch2]);
console.log(newMeetingRoomsInfo2);
const newParams2 = {
...existingParams,
branchName: nearestBranch2.branchName
};
const response2 = await getMeetingRooms(newParams2);
const newRooms2 = response2.meetingRoomForListList;
console.log(response2);
console.log(newRooms2);
setNewMeetingRooms2(newRooms2);
console.log(newMeetingRooms2);
}
};
} catch (error) {
console.error('Error fetching branches or meeting rooms:', error);
}
};

const handleNear1Office = async () => {
try {
if (!newMeetingRoomsInfo || newMeetingRoomsInfo.length === 0) {
console.error('newMeetingRoomsInfo is undefined or empty');
return;
}
const data = await getSelectedOfficeInfo(newMeetingRoomsInfo[0].branchName);
console.log(data);
const officeInfo = data.data;
console.log(officeInfo);
router.push({
pathname: `/branches/${encodeURIComponent(newMeetingRoomsInfo[0].branchName)}`,
query: {
name: officeInfo.branchName,
address: officeInfo.branchAddress,
branchPhoneNumber: officeInfo.branchPhoneNumber,
roadFromStation: officeInfo.roadFromStation,
stationToBranch: officeInfo.stationToBranch.join(','),
branchId: officeInfo.branchId
}
}, `/branches/${encodeURIComponent(newMeetingRoomsInfo[0].branchName)}`);
} catch (error) {
console.error('Error fetching office info:', error);
}
};

const handleNear2Office = async () => {
try {
if (!newMeetingRoomsInfo2 || newMeetingRoomsInfo2.length === 0) {
console.error('newMeetingRoomsInfo is undefined or empty');
return;
}
const data = await getSelectedOfficeInfo(newMeetingRoomsInfo2[0].branchName);
console.log(data);
const officeInfo = data.data;
console.log(officeInfo);
router.push({
pathname: `/branches/${encodeURIComponent(newMeetingRoomsInfo2[0].branchName)}`,
query: {
name: officeInfo.branchName,
address: officeInfo.branchAddress,
branchPhoneNumber: officeInfo.branchPhoneNumber,
roadFromStation: officeInfo.roadFromStation,
stationToBranch: officeInfo.stationToBranch.join(','),
branchId: officeInfo.branchId
}
}, `/branches/${encodeURIComponent(newMeetingRoomsInfo2[0].branchName)}`);
} catch (error) {
console.error('Error fetching office info:', error);
}
};


useEffect(() => {
if (meetingRooms.length === 0) {
const latitude = currentBranch!.branchLatitude
const longitude = currentBranch!.branchLongitude
fetchBranchesByDistance(latitude, longitude);
if (meetingRooms.length == 0 && params) {
fetchBranchesByDistance(currentBranch!.branchId, params);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [meetingRooms]);
}, [meetingRooms, params]);



return (
<div className="p-4 h-screen">
<div className='relative'>
Expand Down Expand Up @@ -319,7 +408,17 @@ const MeetingRoomIndex: React.FC = () => {
</div>
</div>
<div className='flex mb-2'>
<><div className="text-indigo-700 text-lg font-bold font-['Pretendard']">바로예약</div><div className="text-black text-lg font-medium font-['Pretendard'] ml-[5px]">가능</div></>
<>
{meetingRooms.length === 0 && newMeetingRooms?.length === 0 && newMeetingRooms2?.length === 0 ? (
<>
<div className="text-indigo-700 text-lg font-bold font-['Pretendard']">바로예약</div><div className="text-black text-lg font-medium font-['Pretendard'] ml-[5px]">불가능</div>
</>
) : (
<>
<div className="text-indigo-700 text-lg font-bold font-['Pretendard']">바로예약</div><div className="text-black text-lg font-medium font-['Pretendard'] ml-[5px]">가능</div>
</>
)}
</>
</div>
<div className="flex mb-2 w-full items-center">
<div className="">총 {meetingRooms.length}개의 공간</div>
Expand Down Expand Up @@ -426,6 +525,122 @@ const MeetingRoomIndex: React.FC = () => {
))}
</div>
)}
<div>
{meetingRooms.length === 0 && (
<div>
<div className="w-full h-[4px] bg-gray-200 mt-[70px] mb-[35px]" />
<div><span className="text-indigo-700 text-lg font-bold font-['Pretendard']">같은 조건</span><span className="text-black/opacity-20 text-lg font-medium font-['Pretendard']">으로</span><span className="text-black/opacity-20 text-lg font-bold font-['Pretendard']"> <br/></span><span className="text-indigo-700 text-lg font-bold font-['Pretendard']">근처 지점</span><span className="text-black/opacity-20 text-lg font-medium font-['Pretendard']">에서 찾아봤어요.</span></div>
{newMeetingRoomsInfo && (
<div className='mt-[30px] mb-[20px]'>
<div className='flex flex-row justify-between'>
<div className="text-black/opacity-20 text-lg font-bold font-['Pretendard'] my-auto">{newMeetingRoomsInfo[0].branchName}</div>
<div className="ml-auto flex cursor-pointer">
<div className="mr-[5px] text-neutral-400 text-sm font-normal font-['Pretendard'] leading-[21px] my-auto" onClick={handleNear1Office}>지점 상세보기</div>
<Image src={'/nextArrow.svg'} width={5} height={11} alt="arrow" className="mr-[6px] mb-[2px]" />
</div>
</div>
<div className='flex flex-row mt-[8px]'>
<img src={"/map/OfficeLocationSmall1.svg"} width={8} height={12} alt="location" className="mr-[6px] mb-[3px]" />
<div className="text-neutral-700 text-sm font-normal font-['Pretendard'] leading-[21px]">현재 지점으로부터 {newMeetingRoomsInfo[0].distance.toFixed(2)}km</div>
</div>
</div>
)}
{newMeetingRooms?.length > 0 ? (
<div style={{ overflowX: 'auto', display: 'flex' }}>
{newMeetingRooms.map((room) => (
<div
key={room.meetingRoomId}
className={`overflow-hidden bg-white text-center ${toastType === 'OVERLAPPING_MEETING_ROOM_EXISTS' ? 'pointer-events-none' : 'cursor-pointer'}`}
onClick={() => handleRoomClick(room.meetingRoomId)}
style={{ minWidth: 160, maxWidth: 160, marginRight: 10 }}
>
<div className="rounded">
<img
src={room.meetingRoomImage || '/meetingRoomImg.svg'}
width={160}
height={124}
alt={room.meetingRoomName}
className="object-cover rounded"
/>
</div>
<div className="flex flex-col">
<div className="text-neutral-700 text-base font-bold font-['Pretendard'] mr-auto mt-[16px]">
{room.meetingRoomName}
</div>
<div className="flex my-[4px] items-center">
<img src={'/floor.svg'} width={14} height={14} alt="floor" className="mr-[6px]" />
<div className="text-stone-500 text-xs font-normal font-['Pretendard'] mr-[12px] mt-auto">
{room.meetingRoomFloor < 0 ? `B${Math.abs(room.meetingRoomFloor)}` : `${room.meetingRoomFloor}`}층
</div>
<img src={'/capacity.svg'} width={14} height={14} alt="capacity" className="mr-[6px]" />
<div className="text-stone-500 text-xs font-normal font-['Pretendard']">최대 {room.meetingRoomCapacity}명</div>
</div>
</div>
</div>
))}
</div>
) : (
<div className="flex justify-center items-center my-[60px] text-center text-neutral-400 text-base font-normal font-['Pretendard']">
조건에 맞는 미팅룸이 없습니다.
</div>
)}
{newMeetingRoomsInfo2 && (
<div className='mt-[30px] mb-[20px]'>
<div className='flex flex-row justify-between'>
<div className="text-black/opacity-20 text-lg font-bold font-['Pretendard'] my-auto">{newMeetingRoomsInfo2[0].branchName}</div>
<div className="ml-auto flex cursor-pointer">
<div className="mr-[5px] text-neutral-400 text-sm font-normal font-['Pretendard'] leading-[21px] my-auto" onClick={handleNear2Office}>지점 상세보기</div>
<Image src={'/nextArrow.svg'} width={5} height={11} alt="arrow" className="mr-[6px] mb-[2px]" />
</div>
</div>
<div className='flex flex-row mt-[8px]'>
<img src={"/map/OfficeLocationSmall1.svg"} width={8} height={12} alt="location" className="mr-[6px] mb-[3px]" />
<div className="text-neutral-700 text-sm font-normal font-['Pretendard'] leading-[21px]">현재 지점으로부터 {newMeetingRoomsInfo2[0].distance.toFixed(2)}km</div>
</div>
</div>
)}
{newMeetingRooms2?.length > 0 ? (
<div style={{ overflowX: 'auto', display: 'flex' }}>
{newMeetingRooms2.map((room) => (
<div
key={room.meetingRoomId}
className={`overflow-hidden bg-white text-center ${toastType === 'OVERLAPPING_MEETING_ROOM_EXISTS' ? 'pointer-events-none' : 'cursor-pointer'}`}
onClick={() => handleRoomClick(room.meetingRoomId)}
style={{ minWidth: 160, maxWidth: 160, marginRight: 10 }}
>
<div className="rounded">
<img
src={room.meetingRoomImage || '/meetingRoomImg.svg'}
width={160}
height={124}
alt={room.meetingRoomName}
className="object-cover rounded"
/>
</div>
<div className="flex flex-col">
<div className="text-neutral-700 text-base font-bold font-['Pretendard'] mr-auto mt-[16px]">
{room.meetingRoomName}
</div>
<div className="flex my-[4px] items-center">
<img src={'/floor.svg'} width={14} height={14} alt="floor" className="mr-[6px]" />
<div className="text-stone-500 text-xs font-normal font-['Pretendard'] mr-[12px] mt-auto">
{room.meetingRoomFloor < 0 ? `B${Math.abs(room.meetingRoomFloor)}` : `${room.meetingRoomFloor}`}층
</div>
<img src={'/capacity.svg'} width={14} height={14} alt="capacity" className="mr-[6px]" />
<div className="text-stone-500 text-xs font-normal font-['Pretendard']">최대 {room.meetingRoomCapacity}명</div>
</div>
</div>
</div>
))}
</div>
) : (
<div className="flex justify-center items-center my-[60px] text-center text-neutral-400 text-base font-normal font-['Pretendard']">
조건에 맞는 미팅룸이 없습니다.
</div>
)}
</div>
)}
</div>
<div className="h-[100px]"></div>
{startTime && endTime && (
<DatePickerModal
Expand Down
Loading