Skip to content

Commit

Permalink
Merge pull request #49 from 4bujak-4bujak/feature/meetingroomQA
Browse files Browse the repository at this point in the history
[feat] 미팅룸 추가 작업
  • Loading branch information
jiohjung98 authored Jun 10, 2024
2 parents fdfb3f8 + 481f2c4 commit 0744ff0
Show file tree
Hide file tree
Showing 5 changed files with 256 additions and 25 deletions.
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

0 comments on commit 0744ff0

Please sign in to comment.