-
Notifications
You must be signed in to change notification settings - Fork 6
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
Feat: 리스트 상세페이지 안쪽 레이아웃 퍼블리싱 #15
Conversation
(백엔드와 협의 필요)
개발중이기에 localhost:3000 으로 적었으나 이후 배포서버도메인으로 수정하겠습니다.
추후 Dropdown 컴포넌트가 생길것으로 예상되어 SelectComponent 로 변경했습니다.
추후 Dropdown 컴포넌트가 생길것으로 예상되어 SelectComponent 로 변경했습니다.
일부 og:url 태그가 없는 경우 링크 이동이 안되는 것을 방지하기 위해 인자로받은 linkUrl 사용하도록 수정
…component # Conflicts: # src/app/[userNickname]/[listId]/_components/BottomSheet/BottomSheet.tsx # yarn.lock
There was a problem hiding this 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: '데이터를 가져오는데 실패했습니다.' }); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
임베드, 공유하기 기능 구현하면서 설정할 것들이 엄청 많군요...정말 고생많으셨습니다👍 다음에 임베드 기능 구현하게 될 때 참고할게용 최고최고
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
저 나중에 현지님께 프록시로 프론트엔드 서버 설정하는 방법 강의 들어도 될까요?!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
여기 줄서봅니다,,🙈
There was a problem hiding this comment.
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'); |
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
console.log 발견! 👀 혹시 지금 사용중에 있으신가요?!
There was a problem hiding this comment.
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 || '' }} /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
dangerouslySetInnerHTML={{ __html: embedCode || '' }} 도 알아갑니다 🙇♀️
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
전 이게 뭔지 잘 모르겠지만 나현님이라도 알아가셔서 다행이에요!! 👍 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
현지님, 슬쩍 봤지만 엄청난 코드량...!! 진짜 수고 너무 많으셨습니다ㅠㅠ
제가 담당한 파트를 아직 마무리 못해, 코드리뷰는 머지후에 천천히 하겠습니다! 감사합니다🥹🙇♀️
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
현지님!!
아직 1차 MVP 구현 남은게 있어서 완전 각잡고 읽어보고 리뷰드리진 못했습니다.
내일 찬찬히 읽어볼게요!
임베드부분 특히 처음보는것도 많고 어려워보이는데 정말 고생많으셨어요! 👍
const slideIn = keyframes({ | ||
from: { transform: 'translateY(100%)' }, | ||
to: { transform: 'translateY(0)' }, | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
바닐라익스트랙 keyframe 이렇게 쓰는거였군요,,!!!
왜인지 제 드롭다운은 스르륵이 적용 안 됐는데 이제야 이유를 알아갑니다,,🩷
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
나현님께서 구현하신 부분입니다!!! 컨플릭트 없애려고 전전긍긍하다보니 제꺼로 들어와버렸네요...ㅠㅠㅠㅠㅠ
나현님최고!
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'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
코드리뷰로 리뷰드릴건 없고 많이 배워가기만해서 민망하네요 ㅎㅎㅎ
그래도 하나 꼭 남겨야한다면 import 컨벤션정도 인것같습니다!!
- 외부, 라이브러리 먼저
- 내부, 컴포넌트들, 이미지, 타입들은 그 다음
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
앗 놓친게 역시 있었네용..!!ㅎㅎ 감사합니다 수정하겠습니다!!!! 👍 👍 👍
return; | ||
} |
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
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: '데이터를 가져오는데 실패했습니다.' }); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
여기 줄서봅니다,,🙈
…component # Conflicts: # src/app/layout.tsx
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
현지님, 많은 기능 구현하시느라 너무 고생많으셨습니다. 👍 리뷰가 늦어서 죄송합니다.
덕분에 프록시 설정, 임베드 기능에 대해 아주 어렴풋이나마 알게된 것 같습니다.
나중에 프록시 특강 열어주세요🥹📌!! 섬세한 현지님 코드 잘 확인하였습니다. 늘 감사합니다. 🥰
+. 현지님 코드리뷰 2개정도 더 남겼었는데, 코드 refresh 반영을 안해서 최신이 아닌 코드에 대한 리뷰는 사라졌네요,, ㅋㅋㅋ
setEmbedCode( | ||
`<iframe width="100%" height="150px" src="https://player.vimeo.com/video/${videoId}" frameborder="0" allow="autoplay; fullscreen" allowfullscreen></iframe>` | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
임베드코드가 iframe을 넣어서 사용하는 거군요! 👍
return ( | ||
<div className={styles.videoWrapper}> | ||
<div className={styles.videoFrame} dangerouslySetInnerHTML={{ __html: embedCode || '' }} /> |
There was a problem hiding this comment.
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>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
너무 좋은 생각이세요!! 해당 라이브러리 공부해서 적용해보겠습니다!
라이브러리와 예시까지 공유주셔서 감사합니다!!! 👍 👍 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
현지님 해당 부분 먼저 남긴 코드리뷰에 포함했었는데 반영이 안된 것 같아서 다시 남깁니다...🤣
src/lib/utils/copyUrl.ts
Outdated
toasting({ type: 'default', txt: '링크가 복사되었습니다.' }); | ||
} catch (error) { | ||
toasting({ type: 'default', txt: '링크가 복사를 실패했습니다.' }); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
현지님의 모든 코드에서 에러메세지에 대한 처리가 상세하고, 각자 다 달라서 너무 섬세하다고 느꼈습니다. 👍
코드를 읽는 입장에서도 에러가 어떤 에러인지 파악하기 쉬워서 정말 좋다고 느꼈습니다.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
와 덕분에 오타를 발견했어요!! 칭찬도 너무 감사드리고 오타처리도 더움주셔서 감사합니다!! 👍 👍
const response = await fetch(`/api/getOgDataProxy?url=${encodeURIComponent(url)}`); | ||
|
||
const data = await response.json(); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
현지님 혹시 이 부분은 axios 대신 fetch를 사용하신 이유가 궁금합니당!!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
저도 이유가 너무 알고싶은데 이상하게 axios로 하니 에러가 발생하더라구요...ㅠㅠㅠ
나중에 원인을 찾아보겠습니다!!
개요
작업 사항
참고 사항 (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} />
받고있는 데이터 형식:
스크린샷
리뷰어에게