Skip to content

Commit

Permalink
Merge pull request #453 from boostcampwm-2024/development
Browse files Browse the repository at this point in the history
v0.0.1 배포
  • Loading branch information
happyhyep authored Dec 6, 2024
2 parents 5618cc7 + 8026973 commit 5361f9b
Show file tree
Hide file tree
Showing 39 changed files with 1,042 additions and 229 deletions.
23 changes: 23 additions & 0 deletions backend/src/controllers/channelController.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {
addGuestService,
createChannelService,
deleteChannelService,
getChannelByIdService,
getChannelGuestInfoService,
getUserChannels,
Expand Down Expand Up @@ -109,3 +110,25 @@ export const getUserChannelsController = async (req, res) => {
return res.status(500).json(new ErrorResponseDto({ message: 'Server error occurred' }));
}
};

/**
* @description 채널 삭제 컨트롤러
*/
export const deleteChannelController = async (req, res) => {
const { id } = req.params;

try {
const result = await deleteChannelService(id);

if (!result) {
return res.status(404).json(new ErrorResponseDto({ message: 'Channel not found' }));
}

return res
.status(200)
.json(new ResponseDto({ resultMsg: 'Channel deleted successfully', data: { id } }));
} catch (err) {
console.error(err);
return res.status(500).json(new ErrorResponseDto({ message: 'Server error occurred' }));
}
};
14 changes: 14 additions & 0 deletions backend/src/repositories/channelRepository.js
Original file line number Diff line number Diff line change
Expand Up @@ -155,3 +155,17 @@ export const getChannelsByUserIdFromDB = async userId => {
throw error;
}
};

export const deleteChannelByIdFromDB = async id => {
try {
const query = 'DELETE FROM "main"."channel" WHERE id = $1 RETURNING id';
const values = [id];

const result = await pool.query(query, values);

return result.rowCount > 0;
} catch (error) {
console.error('Database error:', error);
throw error;
}
};
33 changes: 33 additions & 0 deletions backend/src/routes/channelRouter.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { body, param } from 'express-validator';
import {
addGuestController,
createChannelController,
deleteChannelController,
getChannelGuestInfoController,
getChannelInfoController,
getUserChannelsController,
Expand Down Expand Up @@ -190,3 +191,35 @@ channelRouter.get(
validationMiddleware,
getUserChannelsController,
);

// 채널 삭제 API 경로
/**
* @swagger
* paths:
* /channel/{id}:
* delete:
* summary: '채널 삭제 API'
* description: '채널 ID를 사용하여 특정 채널을 삭제합니다.'
* tags: [Channel]
* parameters:
* - name: 'id'
* in: 'path'
* required: true
* schema:
* type: 'string'
* description: '삭제할 채널의 고유 ID'
* responses:
* 200:
* description: '채널 삭제 성공'
* 404:
* description: '채널을 찾을 수 없음'
* 500:
* description: '서버 오류'
*/
channelRouter.delete(
'/:id',
[param('id').notEmpty().withMessage('Channel ID is required')],
authenticateJWT,
validationMiddleware,
deleteChannelController,
);
14 changes: 14 additions & 0 deletions backend/src/services/channelService.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {
createChannelInDB,
deleteChannelByIdFromDB,
getChannelInfoByIdInDB,
getChannelsByUserIdFromDB,
getChannelWithGuestsByIdFromDB,
Expand Down Expand Up @@ -105,3 +106,16 @@ export const getUserChannels = async userId => {
throw new Error('Failed to fetch channels', error);
}
};

/**
* @description 채널 삭제 서비스
* @param {string} id - 삭제할 채널의 ID
* @returns {boolean} 삭제 성공 여부
*/
export const deleteChannelService = async id => {
try {
return await deleteChannelByIdFromDB(id);
} catch (error) {
throw new Error('Failed to delete channel', error);
}
};
8 changes: 8 additions & 0 deletions frontend/src/App.css
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,14 @@
font-family: Pretendard, 'Pretendard Variable', sans-serif !important;
}

@supports (-webkit-touch-callout: none) {
#root {
touch-action: manipulation; /* Safari 호환 옵션 */
overscroll-behavior: none;
}
}


.logo {
height: 6em;
padding: 1.5em;
Expand Down
25 changes: 25 additions & 0 deletions frontend/src/api/channel.api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
getChannelResEntity,
getUserChannelsResEntity,
getGuestResEntity,
deleteChannelResEntity,
} from '@/api/dto/channel.dto.ts';
import { getApiClient } from '@/api/client.api.ts';

Expand Down Expand Up @@ -136,3 +137,27 @@ export const getGuestInfo = (
};
return new Promise(promiseFn);
};

export const deleteChannel = (channelId: string): Promise<ResponseDto<deleteChannelResEntity>> => {
const promiseFn = (
fnResolve: (value: ResponseDto<deleteChannelResEntity>) => void,
fnReject: (reason?: any) => void,
) => {
const apiClient = getApiClient();
apiClient
.delete(`/channel/${channelId}`)
.then(res => {
if (res.status !== 200) {
console.error(res);
fnReject(`msg.${res}`);
} else {
fnResolve(new ResponseDto<deleteChannelResEntity>(res.data));
}
})
.catch(err => {
console.error(err);
fnReject('msg.RESULT_FAILED');
});
};
return new Promise(promiseFn);
};
4 changes: 4 additions & 0 deletions frontend/src/api/dto/channel.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,3 +113,7 @@ export class getGuestResEntity {

guest: guestEntity | undefined;
}

export class deleteChannelResEntity {
id: string | undefined;
}
6 changes: 5 additions & 1 deletion frontend/src/assets/footprint.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 5 additions & 1 deletion frontend/src/component/authmodal/AuthModal.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useState } from 'react';
import React, { useEffect, useState } from 'react';
import { Modal } from '@/component/common/modal/Modal';
import { doLogin, doRegister } from '@/api/auth.api.ts';
import { saveLocalData } from '@/utils/common/manageLocalData.ts';
Expand Down Expand Up @@ -91,6 +91,10 @@ export const AuthModal = (props: IAuthModalProps) => {
});
};

useEffect(() => {
if (!props.isOpen) switchToLogin();
}, [props.isOpen]);

return (
<Modal isOpen={props.isOpen}>
{modalType === 'login' ? (
Expand Down
99 changes: 74 additions & 25 deletions frontend/src/component/bottomsheet/BottomSheet.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
import React, { useState, useRef } from 'react';
import { MdClear } from 'react-icons/md';
import classNames from 'classnames';
import { SetCurrentLocationButton } from '../setCurrentLocationButton/SetCurrentLocationButton';

interface IBottomSheetProps {
map: naver.maps.Map | null;
lat: number | null;
lng: number | null;
minHeight: number;
maxHeight: number;
backgroundColor: string;
children: React.ReactNode;
}

export const BottomSheet = ({
map,
lat,
lng,
minHeight,
maxHeight,
backgroundColor,
Expand Down Expand Up @@ -52,37 +59,79 @@ export const BottomSheet = ({
window.addEventListener('mouseup', handleMouseUp);
};

const handleClose = () => {
setSheetHeight(minHeight);
const [, setScrollPosition] = useState(0);
const [touchStartY, setTouchStartY] = useState<number | null>(null);

const handleContentTouchStart = (e: React.TouchEvent<HTMLDivElement>) => {
setTouchStartY(e.touches[0].clientY);
};

const handleContentTouchMove = (e: React.TouchEvent<HTMLDivElement>) => {
if (touchStartY !== null) {
const deltaY = e.touches[0].clientY - touchStartY;

const scrollableElement = e.currentTarget; // 현재 스크롤이 가능한 요소
const newScrollPosition = scrollableElement.scrollTop - deltaY;

scrollableElement.scrollTop = newScrollPosition;

setTouchStartY(e.touches[0].clientY);

setScrollPosition(newScrollPosition);
}
};

const handleContentTouchEnd = () => {
setTouchStartY(null);
};

return (
<div
className="transition-height absolute bottom-0 left-0 right-0 rounded-t-2xl bg-white shadow-lg duration-700 ease-out"
style={{
backgroundColor: `${backgroundColor}`,
height: `${sheetHeight * 100}vh`,
}}
>
<>
<div
className="flex items-center justify-center pb-6 pt-2"
onTouchStart={handleTouchStart}
onTouchMove={handleTouchMove}
onMouseDown={handleMouseDown}
className={classNames('absolute bottom-14')}
style={{
height: `${sheetHeight * 100}vh`,
transition: 'height 0.3s ease-out',
}}
>
<div className="h-1.5 w-12 rounded-full bg-gray-300" />
<SetCurrentLocationButton map={map} lat={lat} lng={lng} isMain />
</div>

<div className="absolute right-2 top-2">
<button
onClick={handleClose}
className="flex h-[30px] w-[30px] items-center justify-center rounded-full bg-gray-200"
<div
className="transition-height absolute bottom-0 left-0 right-0 overflow-hidden rounded-t-2xl bg-white shadow-lg duration-700 ease-out"
style={{
backgroundColor: `${backgroundColor}`,
height: `${sheetHeight * 100}vh`,
}}
onTouchStart={e => e.stopPropagation()}
onTouchMove={e => e.stopPropagation()}
onTouchEnd={e => e.stopPropagation()}
>
<div
className="transition-height absolute bottom-0 left-0 right-0 overflow-hidden rounded-t-2xl bg-white shadow-lg duration-700 ease-out"
style={{
backgroundColor: `${backgroundColor}`,
height: `${sheetHeight * 100}vh`,
}}
>
<MdClear size={18} color="grayscale-850" />
</button>
</div>
<div
className="flex items-center justify-center pb-6 pt-2"
onTouchStart={handleTouchStart}
onTouchMove={handleTouchMove}
onMouseDown={handleMouseDown}
>
<div className="h-1.5 w-12 rounded-full bg-gray-300" />
</div>

<div className="h-[calc(100%-60px)] overflow-auto pb-5">{children}</div>
</div>
<div
className="h-[calc(100%-60px)] overflow-auto pb-5"
onTouchStart={handleContentTouchStart}
onTouchMove={handleContentTouchMove}
onMouseDown={handleContentTouchEnd}
>
{children}
</div>
</div>
</div>
</>
);
};
Loading

0 comments on commit 5361f9b

Please sign in to comment.