-
Notifications
You must be signed in to change notification settings - Fork 1
feat: 공유하기 모달 구현 #212
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
The head ref may contain hidden characters: "feature/\uACF5\uC720\uD558\uAE30-\uBAA8\uB2EC-\uAD6C\uD604"
feat: 공유하기 모달 구현 #212
Changes from 7 commits
4812cd9
d15ba03
c210f14
803a5ae
3d712ae
369adf4
0a63f0a
59b7318
1c8c4bf
d8f24eb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,52 @@ | ||
| import { useEffect } from "react"; | ||
|
|
||
| interface KakoShareButtonProps { | ||
| title: string; | ||
| description: string; | ||
| imageUrl: string; | ||
| } | ||
|
|
||
| const KakaoShareButton = ({ | ||
| title, | ||
| description, | ||
| imageUrl | ||
| }: KakoShareButtonProps) => { | ||
| useEffect(() => { | ||
| // 카카오톡 SDK 초기화 | ||
| if (window.Kakao && !window.Kakao.isInitialized()) { | ||
| window.Kakao.init("a4816c8b85267871796431d92ed23451"); | ||
| } | ||
| }, []); | ||
|
|
||
| const handleShare = () => { | ||
| if (window.Kakao) { | ||
| // 카카오톡 공유 기능 호출 | ||
| window.Kakao.Share.sendDefault({ | ||
| objectType: "feed", | ||
| content: { | ||
| title: title, | ||
| description: description, | ||
| imageUrl: imageUrl, | ||
| link: { | ||
| mobileWebUrl: window.location.href, | ||
| webUrl: window.location.href | ||
| } | ||
| } | ||
| }); | ||
| } | ||
| }; | ||
| return ( | ||
| <div> | ||
| <button onClick={handleShare}> | ||
| <img | ||
| src="/icon/kakaotalk.svg" | ||
| alt="카카오통 공유하기 버튼" | ||
|
||
| width={72} | ||
| height={72} | ||
| /> | ||
| </button> | ||
| </div> | ||
| ); | ||
| }; | ||
|
|
||
| export default KakaoShareButton; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| const TwitterShareButton = ({ title }: { title: string }) => { | ||
| const currentUrl = window.location.href; | ||
|
|
||
| return ( | ||
| <a | ||
| href={`https://twitter.com/intent/tweet?text=${title}&url=${currentUrl}`} | ||
| className="flex flex-col items-center gap-1" | ||
| > | ||
| {/* 디자인 시안 나오면 고칠 예정 -> 4.17 정준영 */} | ||
| <img src="/icon/twitter.svg" alt="트위터 아이콘" width={76} height={76} /> | ||
| <p className="text-md text-gray-800">트위터</p> | ||
| </a> | ||
| ); | ||
| }; | ||
|
|
||
| export default TwitterShareButton; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| import UrlCopyButton from "./UrlCopyButton"; | ||
|
||
|
|
||
| const UrlCopyBar = () => { | ||
| const currentUrl = window.location.href; | ||
|
|
||
| return ( | ||
| <div className="flex h-[54px] w-full max-w-[420px] items-center justify-between rounded-lg border border-gray-100 px-4 py-[15px]"> | ||
| <span className="text-lg ">{currentUrl}</span> | ||
| <UrlCopyButton currentUrl={currentUrl} /> | ||
| </div> | ||
| ); | ||
| }; | ||
|
|
||
| export default UrlCopyBar; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| const UrlCopyButton = ({currentUrl} : {currentUrl : string}) => { | ||
| const handleCopy = () => { | ||
| navigator.clipboard | ||
| .writeText(currentUrl) | ||
| .then(() => { | ||
| alert("URL이 복사되었습니다!"); // toast로 바꾸어야 함 -> 4.10 정준영 | ||
| }) | ||
| .catch((err) => { | ||
| console.error("URL 복사 실패:", err); | ||
| }); | ||
| }; | ||
|
|
||
| return ( | ||
| <button | ||
| onClick={handleCopy} | ||
| className="bg-primary-normal h-8 text-white flex items-center justify-center rounded-[20px] px-4 py-2" | ||
| > | ||
| 복사 | ||
| </button> | ||
| ); | ||
| }; | ||
|
|
||
| export default UrlCopyButton; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,66 @@ | ||
| import { useEffect, useState } from "react"; | ||
| import UrlCopyBar from "@/components/button/UrlCopyBar"; | ||
| import KakaoShareButton from "../button/KakaoShareButton"; | ||
|
||
| import TwitterShareButton from "@/components/button/TwitterShareButton"; | ||
|
|
||
| interface ShareModalProps { | ||
| closeModal: React.Dispatch<React.SetStateAction<boolean>>; | ||
| } | ||
|
|
||
| const ShareModal = ({ closeModal }: ShareModalProps) => { | ||
| const [metaData, setMetaData] = useState({ | ||
| title: "", | ||
| description: "", | ||
| imageUrl: "" | ||
| }); | ||
|
|
||
| useEffect(() => { | ||
| // 메타 데이터를 가져오는 로직 | ||
| const title = | ||
| document | ||
| .querySelector("meta[property='og:title']") | ||
| ?.getAttribute("content") || document.title; | ||
| const description = | ||
| document | ||
| .querySelector("meta[property='og:description']") | ||
| ?.getAttribute("content") || ""; | ||
| const imageUrl = | ||
| document | ||
| .querySelector("meta[property='og:image']") | ||
| ?.getAttribute("content") || ""; | ||
|
|
||
| setMetaData({ title, description, imageUrl }); | ||
| }, []); | ||
|
|
||
| return ( | ||
| <div className="fixed inset-0 z-50 flex items-center justify-center bg-black/50"> | ||
| <main className="relative z-51 flex h-[310px] flex-col justify-center rounded-[20px] bg-white"> | ||
| <h2 className="w-full border-b-gray-100 text-center text-xl font-bold "> | ||
| 게시글 공유 | ||
| </h2> | ||
| <div className="mt-10 flex justify-center gap-10"> | ||
| <KakaoShareButton | ||
| title={metaData.title} | ||
| description={metaData.description} | ||
| imageUrl={metaData.imageUrl} | ||
| /> | ||
| <TwitterShareButton title={metaData.title} /> | ||
| </div> | ||
| <button onClick={() => closeModal((isOpen) => !isOpen)}> | ||
| <img | ||
| src="/icon/close.svg" | ||
| alt="닫기 버튼" | ||
| width={24} | ||
| height={24} | ||
| className="absolute top-[14px] right-[14px]" | ||
| /> | ||
| </button> | ||
| <div className="mt-10 flex w-full justify-center"> | ||
| <UrlCopyBar /> | ||
| </div> | ||
| </main> | ||
| </div> | ||
| ); | ||
| }; | ||
|
|
||
| export default ShareModal; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| // TypeScript 사용 시에는 TypeScript 가 window객체에 존재하는 Kakao객체를 인식할 수 있도록 src내에 global.d.ts를 설정해줘야 오류가 발생하지 않는다. | ||
| interface Window { | ||
| Kakao: any; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,7 +1,6 @@ | ||
| import { StrictMode } from "react"; | ||
| import { createRoot } from "react-dom/client"; | ||
| import "./index.css"; | ||
| import App from "./App"; | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 이건 왜 제거되었을까요,,? |
||
|
|
||
| createRoot(document.getElementById("root")!).render( | ||
| <StrictMode> | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| export interface VirtualFriend { | ||
| virtualFriendId: number; | ||
| conversationId: number; | ||
| mbti: string; | ||
| virtualFriendName: string; | ||
| virtualFriendAge: number; | ||
| virtualFriendSex: string; | ||
| virtualFriendRelationship: string; | ||
| } |
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.
추가적으로 환경변수는 api쪽이 아니라 저희 쪽에서도 등록 가능합니다!