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

[DETAIL] 상점 상세 페이지 URL 복사 및 북마크 구현 #124

Merged
merged 51 commits into from
Dec 14, 2023

Conversation

D0Dam
Copy link
Contributor

@D0Dam D0Dam commented Nov 20, 2023

[#56]

  • URL 복사하기 기능을 구현하였습니다.
    • 토스트로 성공 실패 여부를 확인 할 수 있습니다/
  • 북마크 기능을 구현하였습니다.
    • 우선 연속적으로 요청을 보낼수도 있을 것 같아 요청을 보내고 pending 상태에서는 button을 disabled 하게 두었습니다.
    • 로직이 커져서 별도의 훅으로 분리하였습니다.

Please check if the PR fulfills these requirements

  • It's submitted to develop branch, not the main branch
  • The commit message follows our guidelines
  • There are no warning message when you run yarn lint
  • Docs updated for breaking changes

Screenshot

network 요청과 scrap

실제 PR에서는 스크랩 완료시 '북마크된 장소' 로 버튼의 content 가 바뀌어서 나옵니다.

2023-11-21.12.52.20.mov

url 복사 클릭 시

2023-11-21.12.53.27.mov

commit 776fdea
Author: Minjae Kim <smallkdb@gmail.com>
Date:   Tue Nov 7 17:11:57 2023 +0900

    [Auth] User 타입으로 인한 버그 해결  (#114)

    * refactor: 단어 spell typo 수정

    * refactor: SNSUser 타입 재정의

    * refactor: oauthType 롤백

    * Merge commit '71fedc7ab9189ae649abd567336885b99af3a261'

commit 71fedc7
Merge: a08ef32 12ab91b
Author: 김혜준 <114041848+hyejun0228@users.noreply.github.com>
Date:   Mon Nov 6 16:26:56 2023 +0900

    Merge pull request #115 from BCSDLab/feature/#86

    [HOTFIX] Mock 데이터 삭제로 인한 에러 해결

commit 12ab91b
Author: 김혜준 <alice5855@naver.com>
Date:   Mon Nov 6 00:57:54 2023 +0900

    fix: mock data 추가

commit a08ef32
Merge: 4065df0 3767d38
Author: 김혜준 <114041848+hyejun0228@users.noreply.github.com>
Date:   Mon Nov 6 00:44:54 2023 +0900

    Merge pull request #112 from BCSDLab/feature/#86

    [SEARCH] 검색 결과 페이지 구현

commit 3767d38
Author: 김혜준 <alice5855@naver.com>
Date:   Mon Nov 6 00:44:32 2023 +0900

    remove: mock data 삭제

commit e5e1132
Author: 김혜준 <alice5855@naver.com>
Date:   Sat Nov 4 02:35:12 2023 +0900

    refactor: return 값 재분기 처리

commit 3f82efd
Author: 김혜준 <alice5855@naver.com>
Date:   Sat Nov 4 02:28:00 2023 +0900

    fix: interface 수정

commit 853cf94
Author: 김혜준 <alice5855@naver.com>
Date:   Fri Nov 3 02:36:23 2023 +0900

    refactor: 훅 params 값 수정

commit ab811d5
Author: 김혜준 <alice5855@naver.com>
Date:   Fri Nov 3 02:00:16 2023 +0900

    refactor: 타입선언 통일

commit 2be145c
Author: 김혜준 <alice5855@naver.com>
Date:   Thu Nov 2 15:13:07 2023 +0900

    fix: lint 에러 수정

commit d291ac3
Author: 김혜준 <alice5855@naver.com>
Date:   Thu Nov 2 15:12:01 2023 +0900

    refactor: return 추가 분기처리 및 검색 UI수정

commit c419b19
Author: 김혜준 <alice5855@naver.com>
Date:   Thu Nov 2 14:19:05 2023 +0900

    refator: enterEvent함수 변경

commit 1fc142a
Author: 김혜준 <alice5855@naver.com>
Date:   Thu Nov 2 13:58:11 2023 +0900

    fix: lint 에러 수정

commit 48f514c
Author: 김혜준 <alice5855@naver.com>
Date:   Thu Nov 2 13:40:05 2023 +0900

    refactor: return 값 재분기 처리

commit 2ba0e8c
Author: 김혜준 <alice5855@naver.com>
Date:   Thu Nov 2 02:02:20 2023 +0900

    refator: 불필요한 if 문 삭제

commit aba2f12
Author: 김혜준 <alice5855@naver.com>
Date:   Thu Nov 2 01:30:57 2023 +0900

    refactor: 내부 이벤트함수 외부로 이동

commit 74b638b
Author: 김혜준 <alice5855@naver.com>
Date:   Thu Nov 2 00:31:52 2023 +0900

    refator: useDebounce 타입 수정

commit 5a7413e
Author: 김혜준 <alice5855@naver.com>
Date:   Thu Nov 2 00:16:01 2023 +0900

    refactor: return값 분기처리

commit 91c405f
Author: 김혜준 <alice5855@naver.com>
Date:   Mon Oct 30 02:07:46 2023 +0900

    refactor: 함수명 변경

commit b042d95
Author: 김혜준 <alice5855@naver.com>
Date:   Mon Oct 30 01:45:08 2023 +0900

    fix: 불필요한 콘솔 삭제

commit c56736b
Merge: 2e40c20 4065df0
Author: 김혜준 <alice5855@naver.com>
Date:   Mon Oct 30 01:41:59 2023 +0900

    Merge branch 'develop' into feature/#86

commit 2e40c20
Author: 김혜준 <alice5855@naver.com>
Date:   Mon Oct 30 01:21:32 2023 +0900

    feat: 검색 결과 페이지 구현
Copy link
Contributor

@kimeodml kimeodml left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

첫 리뷰네요! 추가적으로 스크랩의 경우 로그아웃시 불가능하다는 것만 주의해 주시면 될것 같아요. 고생하셨습니다!😊

Comment on lines +2 to +20
content: {
address: string;
category: string;
createdAt: string;
directory: {
createdAt: string;
id: number;
name: string;
scrapCount: number;
updatedAt: string;
};
name: string;
photo: string;
placeId: string;
ratingCount: number;
scrapId: number;
totalRating: number;
updatedAt: string;
}[];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

API 가독성을 위해 밖으로 빼는 것은 어떨까요?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

배열 요소를 외부로 빼면 그래도 살짝은 가독성이 좋아지긴 하겠지만, 이것 때문에 분리하는 것은 살짝 반대입니다..
이 타입 자체에서 명시되어 있듯이 스크랩한 상점의 응답값인 것을 알 수 있기 때문에 어노정도 유추할 수 있다는 생각도 해봅니다..!

그리고 타입을 새로 만들 때는 그래도 외부에서 쓰일 수 있을 때 분리하는 편입니다. 이미 해당 타입에 맞는 정보가 타입으로 정의되어 있는 상태라면 가져다 쓰면 좋겠지만, 쩝박에서는 상점 정보의 타입이 상점 조회, 스크랩된 상점 조회 등에서 다 다른 형식으로 주더라구요. 그러다보니 아직 해당 배열 요소를 특정해서 외부에서 쓰지 않고 있으니 크게 분리의 필요성을 느끼지 못하겠더라구요.. 물론 묶어주고 싶은 그 느낌(?)은 이해합니다..! 추후에 이 요소가 세부적으로 사용될 일이 생기면 그 때 분리를 생각해도 괜찮지 않나 싶습니다!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

넵ㅋㅋㅋ확인했습니다! 설명감사합니다!

Comment on lines +26 to +37
pageable: {
offset: number;
pageNumber: number;
pageSize: number;
paged: boolean;
sort: {
empty: boolean;
sorted: boolean;
unsorted: boolean;
};
unpaged: boolean;
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 부분도 가독성을 위해 따로 빼는 것은 어떻게 생각하시나요?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

위의 코멘트로 대체하겠습니다~!

import { deleteScrapShop, scrapShop } from 'api/scrap';
import { useState } from 'react';

const useScrap = (placeId: string, initialScrapId: number | null) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

저 궁금한 것이 보통 공통으로 사용하는 hooks의 경우 utils/hooks 내부에 놓는 것으로 알고 있습니다. useScrap의 경우 메인페이지에 스크랩 기능이 있어서 두 곳에서 사용해야하는데 이 경우 공통적으로 사용하는 것이 아니기 때문에 옮길 필요가 없는 것일까요? 가끔 공통은 아니지만 부분적인(?) 곳에서 사용하는 hooks들이 많아서 이 경우 파일 위치를 어디에 설정하는지 궁금합니다!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

오우 외부에서 사용하는지는 생각안하고 제 파일에만 만들어놨습니다..
같이 쓰면 외부에 두는 게 맞죠. 그런데 아마 듣기로 상세쪽 빼고 다 된걸로 알고 있었는데, 공용훅에 스크랩 관련 훅이나 api가 없길래 상세에서만 쓰는지 알고 있었어요. 부분적으로 사용하는 부분이 있으면 그 해당 폴더 상위에 두는데, 페이지 두개 이상에서 특정 훅이 사용된다면 utils/hook으로 빼는 것이 맞다고 봅니다!
빼 놓을게요~!

makeToast('error', 'URL을 복사하는데 실패했습니다.');
});
};

useNaverMap(latitude, longitude);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

useMarker로 위치 표시하는 것은 어떨까요? 축소하니까 위치 파악이 안 되는 것 같아서요!(물론 선택 사항입니닿ㅎㅎ)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이건... 저도 마커를 넣는게 더 좋다고 생각은 했지만, ui 디자인 상에서 마커가 없었기 때문에 일부러 넣지 않았습니다!

그리고 useMarker는 마커를 찍기 위해 상점 이름, 대표사진이 필요해요.(아마 마커를 표시하는데, 상점이름과 이름을 넣어주고 싶었던 거겠죠?)
만약 마커 표시를 하도록 시안이 바뀐다면 이 상세 페이지에서는 마커를 그냥 위치 기반으로 찍어주면 되기 때문에 useMarker에서 위치만 받았을 때의 로직을 재설계 해서 넣어두도록 하겠습니다.

Copy link
Contributor

@junghaesung79 junghaesung79 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

고생하셨습니다! 읽으면서 궁금한 점 적어 놓겠습니다!

Comment on lines 19 to 22
className={cn({
[styles['scrap-button']]: true,
[styles['scrap-button__active']]: scrapId !== null,
})}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

scrap-button--active가 더 어울릴 것 같은데 element로 이어간 이유가 있는 건가요?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bem 방식을 한지 오래되어서 그냥 편한대로 하고 있었는데 딱걸렸네요..ㅎㅎ
@junghaesung79 말대로 scrap-button--active 가 올바른 표현이네요! 수정하겠습니다!

@D0Dam
Copy link
Contributor Author

D0Dam commented Nov 26, 2023

첫 리뷰네요! 추가적으로 스크랩의 경우 로그아웃시 불가능하다는 것만 주의해 주시면 될것 같아요. 고생하셨습니다!😊

우선... 현재 상세 페이지 자체가 로그인시에만 접근할 수 있습니다! 이건 상세 페이지에 나의 리뷰나 나의 팔로워 리뷰와 같은 항목이 있기 때문입니다.
그리고 api client 가 만들어질 때 axios interceptor 를 통해서 토큰 여부를 확인해주도록 설계해 놨더라구요. 그래서 이 방법을 따라갔습니다!

첫 리뷰 감사드립니다~!

@D0Dam D0Dam requested a review from kimeodml November 26, 2023 08:33
Copy link
Contributor

@kimeodml kimeodml left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

브랜치 최신화한 후에 머지 부탁드립니다~

Comment on lines +2 to +20
content: {
address: string;
category: string;
createdAt: string;
directory: {
createdAt: string;
id: number;
name: string;
scrapCount: number;
updatedAt: string;
};
name: string;
photo: string;
placeId: string;
ratingCount: number;
scrapId: number;
totalRating: number;
updatedAt: string;
}[];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

넵ㅋㅋㅋ확인했습니다! 설명감사합니다!

Comment on lines 4 to 9
export const scrapShop = (shopId: string) =>
scrapApi.post('/scraps', { directoryId: 0, placeId: shopId });

export const getMyScrapShop = () => scrapApi.get<GetMyScrapShopResponse>('/scraps');

export const deleteScrapShop = (scrapId: number) => scrapApi.delete(`/scraps/${scrapId}`);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

scrapShop도 아래와 같이 일관성있게 postScrapShop으로 통일시키지 않아도될까요?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

오호.. 지금보니 그러네요.. 통일시켜 놓을게요~!

deleteScrap(scrapId);
setScrapId(null);
} else {
postScrap(placeId as string);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

placeId 가 이미 string 타입으로 들어오는데 여기서 다시 타입을 강제해야하는 이유가 있나요?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

호거걱.. 없습니다. 따로 훅으로 분리하면서 놓쳤나보네요! 감사합니다!

<button
type="button"
onClick={toggleScrap}
disabled={isPending}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pending 상태일때 disabled로 동작을 막는 디테일은 생각해보지 못했네요.. 배워갑니다ㅎㅎ

Comment on lines +24 to +40
number: number;
numberOfElements: number;
pageable: {
offset: number;
pageNumber: number;
pageSize: number;
paged: boolean;
sort: {
empty: boolean;
sorted: boolean;
unsorted: boolean;
};
unpaged: boolean;
};
size: number;
sort: {
empty: boolean;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

아마 이런 페이지 관련 프로퍼티들은 서버에서도 동일한 DTO로 사용중일텐데,
클라이언트에서도 재사용하기 좋게끔 PaginationableResponse 정도의 이름으로 모아두면 extends를 적절히 활용해 쓰기 좋게 만들 수 있을 것 같아여
공지사항쪽에도 동일한 프로퍼티를 봤던 것 같은 느낌이 있네여

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

저도 인지를 어느정도 하고 있긴 합니다만.. 바꾸려고 보니 이미 관련 타입들을 동일하게 여러개 만들어두고 사용하고 있더라구요.

ex) InquiryPageable, PostPageable

그래서 이 타입을 따로 분리한다면 위 타입들까지 포함해서 전부 바꿔주고 싶은데, 그러기에는 너무 많은 파일들을 건드려서 일단 두었습니다. 이 부분은 가능하면 따로 이슈를 파서 작업을 해보는 방향으로 가볼게요!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

쪼아영 타입들 한번 싹 손대기 고고

import type { GetMyScrapShopResponse } from './entity';

export const scrapShop = (shopId: string) =>
scrapApi.post('/scraps', { directoryId: 0, placeId: shopId });
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

directoryId: 0 인 이유를 주석이나 PR 코멘트에 추가되어있으면 좋을 것 같아요~

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

으흠.. 주석을 웬만하면 정말 안쓰려고 하다보니 살짝 낯서네요 ㅎㅎ.. 한 번 추가해볼게요~!

navigator.clipboard.writeText(urlToCopy).then(() => {
makeToast('success', 'URL을 클립보드에 복사하였습니다.');
}).catch(() => {
makeToast('error', 'URL을 복사하는데 실패했습니다.');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

사용하는 입장에서는 실패했으니 어떻게 하라는거지? 정도의 텐션을 보이기때문에
실패한 원인에 대한 해결책을 제시해주거나, 사용자 입장에서 납득할 만한 태도를 보이는것도
프론트도 도울 수 있는 UX 향상이 가능한 부분이예요ㅎ

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

너무 지당한 말입니다. 사실 어느정도의 ux 를 포기했습니다 허허..
사실 그 정도의 에러에 대한 ux 를 맞춰주려고 할 때에는 저는 백엔드와 에러코드 정도를 맞춰 둔 정도의 레벨에서 고려를 했었거든요.
물론 지금 더 프론트가 도울 수 있는 ux 측면이 있는 것은 확실하지만, 일단.. 우선순위에서는 차후로 두겠습니다.
다른 것까지 다 하고 좀 더 고도화 해볼게요!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

간단한 방법으로는 대부분의 크롬 버전 / 브라우저에서 지원될 테니깐 간단하게 현재 브라우저 버전에서는 지원하지 않는 기능입니다. 최신 버전의 Chrome을 사용해주세요. 정도면 UI공수없이 적절할 것 같네여 ㅋㅋ

useNaverMap(latitude, longitude);

return (
<section className={styles.container}>
<SectionHeader
title="지도"
description={formattedAddress}
button={{ content: 'URL 복사', onClick: () => {} }}
button={{ content: 'URL 복사', onClick: copyURL }}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

요건 좀 익숙하지 않은 인터페이스네요.. ㄷㄷ
onButtonClick 정도의 인터페이스로 두거나, 아예 조합 컴포넌트로 바꾸는것도 좋아보이는데
사실 그렇게 중요한 부분은 아니니 마이너한 리뷰로 봐주세영

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

저도 조합을 좀 생각하기는 했는데(사실 지금도 조합이 좀 고프지만..)
이 정도 까지는 하나의 컴포넌트로 만들어도 괜찮겠다 생각이 들어서요.
더이상 디자인 이외에 확장되는 기능이 나오기 힘들다라고 봤거든요. 그렇다고 그렇게 복잡도가 높은 컴포넌트도 아니어서, 혹여 진짜 나중에 확장할 필요가 있다고 하면 조합으로 함 써보고 싶네요. 이 김에 컴파운드 패턴을 좀 다시 복기 해볼까..

}

function ScrapButton({ placeId, initialScrapId = null }: Props) {
const { scrapId, toggleScrap, isPending } = useScrap(placeId, initialScrapId);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

scrapId를 받는 인터페이스도 특이한 것 같은데,
스크랩중인 여부를 불린값으로 반환하지 못하는 이유가 있나요??

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

스크랩중인 여부 라는 게 isPending 을 말하는 걸까요? 아니면 그 initialScrapId 를 number | null 대신 isScrap과 같은 props를 만들어 boolean 값으로 받을 수는 없을까 일까요?

초기에 음식점 상세 데이터를 불러오면 scrap 여부를 number | null 형식으로 주더라구요. 그래서 데이터 형식을 좀 일관화 하고 싶어서, 이걸 그대로 따라갔습니다.
그렇다고 boolean 여부를 생각 안해본 것은 아닌데, 이렇게 되면 button 에 data attribute를 사용해서 비제어 형식으로는 만들어 볼 수 있겠지만 코드량도 늘고 비제어 형식보다는 제어 형식으로 작성한게 깔끔하다고 느낌을 받아서 이렇게 구상을 했습니다~!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isScrap등의 불린값으로 써야한다고 생각했고,
이런 프로퍼티의 정보는 서버에서 갖고있어야 한다고 생각해요.
북마크의 id가 클라이언트에서 필요한 정보도 아닐 뿐더러, 저희가 필요한 정보는 해당 상점을 등록했는지 / 내가 어떤 상점들을 등록했는지 뿐이니깐 정보의 위치가 불편하다는 느낌이 드네영

Comment on lines 8 to 17
const { mutate: postScrap, isPending: postPending } = useMutation({
mutationFn: scrapShop,
onSuccess: (res) => setScrapId(res.data.id),
});

const { mutate: deleteScrap, isPending: deletePending } = useMutation({
mutationFn: deleteScrapShop,
});

const toggleScrap = () => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

toggle 자체를 mutationFn으로 만드는 방법도 괜찮았을 것 같아요.
isLoading 1개로 잔잔하게 사용할 수 있고, delete와 post만 따로 활용될 일도 없으니 쓰는쪽에서는 �북마크 여부 / 상태 토글 만 관리하는것도?? 할만한 관점이었을듯!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

어... 나중에 스크랩 창에서 스크랩 삭제하기나 스크랩 추가하기가 있기 때문에 두 함수는 필요할 것 같아요..!
그런데 토글 자체의 mutation을 만든다는 의견은 좋은 것 같습니다! 다른 곳에서 써먹어 보고 싶네요 ㅎㅎ

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

아니면 여기에서 그냥 또 toggle을 mutataionFn 으로 만드는건.. 어떨 것 같나요?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ㅋㅋㅋㅋㅋㅋㅋ 아아 둘이 나눠져야할 필요가 있다면 어쩔 수 없져
반환값이 너무 복잡해질 수 있으니, 지금의 인터페이스도 괜찮은 것 같네요.
다만 그렇다면 반환을 isPending으로 붙여서 하는게 아닌, post - Delete 따로 해줘야할 것 같네요

Comment on lines 7 to 9
"cSpell.words": [
"tanstack"
],
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 설정은 먼가여?? vsCode공용설정에 이런친구도 있던가

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

앗.. 영어 오타 잡아주는 확장 프로그램인데 workspace로 들어가버렸네요. 허허
지워놓을게요!

@D0Dam D0Dam merged commit 4cd2e4d into develop Dec 14, 2023
1 check passed
LUNA-KK added a commit that referenced this pull request Jan 10, 2024
[SETTING] 설정 페이지 이슈 수정
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants