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: 리스트 상세페이지 안쪽 레이아웃 퍼블리싱 #15

Merged
merged 46 commits into from
Feb 5, 2024

Conversation

kanglocal
Copy link
Contributor

개요

  • 개요는 변경 사항 및 관련 이슈에 대해 간단하게 작성해주세요.
  • 해당 PR에 대한 리뷰어와 라벨을 생성해 주세요.

작업 사항

  • 리스트 상세페이지 내부의 UI와 기능을 구현했습니다.
  • KakaotoalShare, SelectComponent, VideoEmbed, LinkPreview 를 공통컴포넌트로 작성했습니다.
  • Toast를 util에 작성했습니다.

참고 사항 (optional)

  • �CORS에러해결을 위해 app라우터를 사용하므로 page폴더가 필요없음에도 추가하였습니다.
    관련 내용: Next.js App Router can't handle proxied requests chimurai/http-proxy-middleware#932

  • 목데이터를 사용하는 경우(외부 이미지url이 포함되어있는 경우) 리스트 이미지로 저장시 CORS에러가 발생합니다.
    (앞으로는 목데이터가 아닌, 저장된 데이터를 사용할것이기 때문에 외부이미지를 사용하는 경우는 제외시켰습니다.)

  • listDetailOuter에서 listDetailInner불러오는 방식
    @Nahyun-Kang
    리스트 상세페이지에서 응답받은 데이터를 아래와 같이 넣어주세요!
    import ListDetailInner from '@/app/[userNickname]/[listId]/_components/ListDetailInner';
    <ListDetailInner data={MockData} />
    image

받고있는 데이터 형식:
image

  • 토스트 사용예시
    image

스크린샷

listyWave_basic
listWave_share
listyWave_etc

리뷰어에게

  • 바쁘신와중에 자세히 들여봐주신다면 정말 감사하겠습니다.
  • 현재 css 중복(예를들면 display:flex, alignItems:center 같은) 것들도 있는데, 다른분들 코드 염탐하며 수정해보겠습니다 👍
  • 작은 개선점이라도 발견하신다면 편하게 말씀주셨으면 좋겠습니다!!

개발중이기에 localhost:3000 으로 적었으나 이후 배포서버도메인으로 수정하겠습니다.
추후 Dropdown 컴포넌트가 생길것으로 예상되어 SelectComponent 로 변경했습니다.
추후 Dropdown 컴포넌트가 생길것으로 예상되어 SelectComponent 로 변경했습니다.
일부 og:url 태그가 없는 경우 링크 이동이 안되는 것을 방지하기 위해 인자로받은 linkUrl 사용하도록 수정
…component

# Conflicts:
#	src/app/[userNickname]/[listId]/_components/BottomSheet/BottomSheet.tsx
#	yarn.lock
Copy link
Contributor

@Nahyun-Kang Nahyun-Kang left a comment

Choose a reason for hiding this comment

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

임베드 구현 하시느라 너무 고생많으셨습니다..! 👍 저는 프록시가 뭔지 아직 잘 모르겠는데..현지님 PR 보면서 공부해보겠습니다 👀 빨리 컴포넌트 합체해서 완전체로 만들고 싶어용🤩 멘션 주신 것처럼 props로 리스트 상세 정보 넘겨드릴게요!

} catch (error) {
console.error(error);
res.status(500).json({ message: '데이터를 가져오는데 실패했습니다.' });
}
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

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.

여기 줄서봅니다,,🙈

Copy link
Contributor Author

Choose a reason for hiding this comment

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

원하시는 시기에 제가 아직 안까먹었으면 설명드리겠습니다!! 👍 👍

let linkType = '';
// 일반url(link), 비디오(video), 지도(map) 로 구분하기. 지금은 비디오랑 링크만 구분.
// TODO: 지도 추가하기
const isVideoLink = link.includes('youtube.com') || link.includes('youtu.be') || link.includes('vimeo.com');
Copy link
Contributor

Choose a reason for hiding this comment

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

현지님 덕분에 youtu.be 라는 youtube 링크 단축 서비스가 있는지 알아갑니다..! 단축 url도 신경쓰시다니 역시👍

}
function DetailList({ listData }: RankListProps) {
return listData.map((item, index) => {
console.log(index);
Copy link
Contributor

Choose a reason for hiding this comment

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

console.log 발견! 👀 혹시 지금 사용중에 있으신가요?!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

헉 수정하겠습니다!!! 발견해주셔서 감사합니다!! 👍 👍


return (
<div className={styles.videoWrapper}>
<div className={styles.videoFrame} dangerouslySetInnerHTML={{ __html: embedCode || '' }} />
Copy link
Contributor

Choose a reason for hiding this comment

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

dangerouslySetInnerHTML={{ __html: embedCode || '' }} 도 알아갑니다 🙇‍♀️

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

@seoyoung-min seoyoung-min left a comment

Choose a reason for hiding this comment

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

현지님, 슬쩍 봤지만 엄청난 코드량...!! 진짜 수고 너무 많으셨습니다ㅠㅠ
제가 담당한 파트를 아직 마무리 못해, 코드리뷰는 머지후에 천천히 하겠습니다! 감사합니다🥹🙇‍♀️

Copy link
Contributor

@Eugene-A-01 Eugene-A-01 left a comment

Choose a reason for hiding this comment

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

현지님!!
아직 1차 MVP 구현 남은게 있어서 완전 각잡고 읽어보고 리뷰드리진 못했습니다.
내일 찬찬히 읽어볼게요!
임베드부분 특히 처음보는것도 많고 어려워보이는데 정말 고생많으셨어요! 👍

Comment on lines +33 to +36
const slideIn = keyframes({
from: { transform: 'translateY(100%)' },
to: { transform: 'translateY(0)' },
});
Copy link
Contributor

Choose a reason for hiding this comment

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

바닐라익스트랙 keyframe 이렇게 쓰는거였군요,,!!!
왜인지 제 드롭다운은 스르륵이 적용 안 됐는데 이제야 이유를 알아갑니다,,🩷

Copy link
Contributor Author

Choose a reason for hiding this comment

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

나현님께서 구현하신 부분입니다!!! 컨플릭트 없애려고 전전긍긍하다보니 제꺼로 들어와버렸네요...ㅠㅠㅠㅠㅠ
나현님최고!

Comment on lines 3 to 14
import * as styles from './Footer.css';
import CollectIcon from '/public/icons/collect.svg';
import ShareIcon from '/public/icons/share.svg';
import EtcIcon from '/public/icons/etc.svg';
import BottomSheet from '@/app/[userNickname]/[listId]/_components/BottomSheet/BottomSheet';
import { MouseEvent, useState } from 'react';
import ModalPortal from '@/components/ModalPortal';
import copyUrl from '@/lib/utils/copyUrl';
import saveImageFromHtml from '@/lib/utils/saveImageFromHtml';
import kakaotalkShare from '@/components/KakaotalkShare/kakaotalkShare';
import { useParams, useRouter } from 'next/navigation';
import toasting from '@/lib/utils/toasting';
Copy link
Contributor

Choose a reason for hiding this comment

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

코드리뷰로 리뷰드릴건 없고 많이 배워가기만해서 민망하네요 ㅎㅎㅎ
그래도 하나 꼭 남겨야한다면 import 컨벤션정도 인것같습니다!!

  • 외부, 라이브러리 먼저
  • 내부, 컴포넌트들, 이미지, 타입들은 그 다음

Copy link
Contributor Author

Choose a reason for hiding this comment

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

앗 놓친게 역시 있었네용..!!ㅎㅎ 감사합니다 수정하겠습니다!!!! 👍 👍 👍

Comment on lines +76 to +77
return;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

if문-fast 리턴 패턴 너무 편안하고 좋아요 ㅎㅎ

export default function TempLayout({ children }: { children: ReactNode }) {
function kakaoInit() {
window.Kakao.init(process.env.NEXT_PUBLIC_KAKAO_API_KEY);
Copy link
Contributor

Choose a reason for hiding this comment

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

머지되기 전에 env kakao api key 공유 부탁드려요 !! ㅎㅎ

} catch (error) {
console.error(error);
res.status(500).json({ message: '데이터를 가져오는데 실패했습니다.' });
}
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

@ParkSohyunee ParkSohyunee left a comment

Choose a reason for hiding this comment

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

현지님, 많은 기능 구현하시느라 너무 고생많으셨습니다. 👍 리뷰가 늦어서 죄송합니다.
덕분에 프록시 설정, 임베드 기능에 대해 아주 어렴풋이나마 알게된 것 같습니다.
나중에 프록시 특강 열어주세요🥹📌!! 섬세한 현지님 코드 잘 확인하였습니다. 늘 감사합니다. 🥰

+. 현지님 코드리뷰 2개정도 더 남겼었는데, 코드 refresh 반영을 안해서 최신이 아닌 코드에 대한 리뷰는 사라졌네요,, ㅋㅋㅋ

Comment on lines +43 to +45
setEmbedCode(
`<iframe width="100%" height="150px" src="https://player.vimeo.com/video/${videoId}" frameborder="0" allow="autoplay; fullscreen" allowfullscreen></iframe>`
);
Copy link
Contributor

Choose a reason for hiding this comment

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

임베드코드가 iframe을 넣어서 사용하는 거군요! 👍

Comment on lines +64 to +66
return (
<div className={styles.videoWrapper}>
<div className={styles.videoFrame} dangerouslySetInnerHTML={{ __html: embedCode || '' }} />
Copy link
Contributor

Choose a reason for hiding this comment

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

현지님, 나중에 리팩토링 하실 때 이 부분은 html태그를 직접 삽입하기 때문에 보안상 이슈(XSS공격)로 처리를 한번 해주는게 좋을 것 같다는 생각이 드는데 현지님 생각은 어떠신가용?

+. 제가 알고있는 라이브러리는 Dompurify (https://www.npmjs.com/package/dompurify)로, 해당 라이브러리를 적용하여 안정성을 확보할 수 있을 것 같습니다.

<div className={styles.videoFrame} dangerouslySetInnerHTML={{
			__html: Dompurify.sanitize(embedCode || ''))
		}} />
</div>

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

@ParkSohyunee ParkSohyunee 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 7 to 10
toasting({ type: 'default', txt: '링크가 복사되었습니다.' });
} catch (error) {
toasting({ type: 'default', txt: '링크가 복사를 실패했습니다.' });
}
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.

와 덕분에 오타를 발견했어요!! 칭찬도 너무 감사드리고 오타처리도 더움주셔서 감사합니다!! 👍 👍

Comment on lines +6 to +9
const response = await fetch(`/api/getOgDataProxy?url=${encodeURIComponent(url)}`);

const data = await response.json();

Copy link
Contributor

Choose a reason for hiding this comment

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

현지님 혹시 이 부분은 axios 대신 fetch를 사용하신 이유가 궁금합니당!!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

저도 이유가 너무 알고싶은데 이상하게 axios로 하니 에러가 발생하더라구요...ㅠㅠㅠ
나중에 원인을 찾아보겠습니다!!

@kanglocal kanglocal merged commit c3b990f into 8-Sprinters:dev Feb 5, 2024
1 check passed
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