Skip to content

Conversation

@cywin1018
Copy link
Contributor

@cywin1018 cywin1018 commented Sep 7, 2025

🚀 풀 리퀘스트 제안

  • 기능 추가
  • 기능 삭제
  • 버그 수정
  • 스타일링
  • 의존성, 환경 변수, 빌드 관련 코드 업데이트
  • 기타

✈️ 관련 이슈

📋 작업 내용

📸 스크린샷 (선택 사항)

📄 기타

Summary by CodeRabbit

  • 신기능
    • 카카오톡 공유 지원: 템플릿이 있으면 커스텀 메시지, 없으면 기본 피드로 공유합니다.
    • 공유 실패 시 자동 폴백: Web Share API 활용, 미지원·실패 시 링크를 클립보드로 복사하고 안내합니다.
  • 성능
    • 공유 SDK를 필요 시점에만 로드하여 초기 화면 로딩 속도를 개선했습니다.
  • 버그 수정
    • 오류 처리와 예외 대응을 강화해 공유 성공률과 안정성을 높였습니다.

@coderabbitai
Copy link

coderabbitai bot commented Sep 7, 2025

Warning

Rate limit exceeded

@cywin1018 has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 1 minutes and 43 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 589b765 and 4f5f1be.

📒 Files selected for processing (1)
  • src/common/KakaoShareButton.tsx (2 hunks)

Walkthrough

KakaoShareButton의 클릭 처리 로직을 비동기화하고, Kakao JS SDK를 런타임에 지연 로드하도록 변경. 환경 변수로 SDK 키/템플릿을 읽어 Kakao 공유를 수행하며, 실패 시 Web Share API와 클립보드 복사로 순차 폴백. 컴포넌트의 공개 시그니처는 그대로 유지.

Changes

Cohort / File(s) Summary
Kakao 공유 버튼 동작/로더
src/common/KakaoShareButton.tsx
- 지연 로더 loadKakao(key) 추가: CDN 스크립트 동적 주입, integrity/crossOrigin 설정, 초기화 및 에러 처리
- onClick → async 처리: 사용자 onClick 우선 호출, 이후 환경 변수(VITE_KAKAO_JS_KEY, VITE_KAKAO_TEMPLATE_ID)에 따라 Kakao SDK 로드 및 공유 실행
- 템플릿 ID 있으면 Kakao.Share.sendCustom, 없으면 sendDefault로 피드 공유 구성
- 실패 폴백: Web Share API → 클립보드 복사+알림
- 스타일/레이아웃 변경 없음, 공개 타입/Props 불변

Sequence Diagram(s)

sequenceDiagram
    autonumber
    actor U as User
    participant B as KakaoShareButton
    participant L as loadKakao()
    participant K as Kakao SDK
    participant W as Navigator.share
    participant C as Clipboard

    U->>B: Click
    alt onClick prop 제공됨
      B->>B: 사용자 onClick 실행
      note right of B: 이후 공유 로직 진행
    end

    B->>B: 환경변수 읽기 (VITE_KAKAO_JS_KEY / TEMPLATE_ID)
    alt SDK 키 존재
      B->>L: loadKakao(key)
      L-->>B: SDK 준비 완료 또는 에러
      alt SDK 로드 성공
        alt TEMPLATE_ID 존재
          B->>K: Share.sendCustom(templateId, data)
        else 기본 공유
          B->>K: Share.sendDefault(feed, button)
        end
        K-->>B: 성공/실패
      else SDK 로드 실패
        B->>B: Kakao 공유 생략
      end
    else 키 없음
      B->>B: Kakao 공유 생략
    end

    alt Kakao 공유 실패 또는 미사용
      alt Web Share 지원
        B->>W: navigator.share({title, text, url})
        W-->>B: 성공/실패
      else 미지원/실패
        B->>C: clipboard.writeText(url)
        C-->>B: 완료
        B->>U: alert(복사 안내)
      end
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • Chasyuss

Poem

풀잎 흔들, 토끼는 깡충—공유 버튼 딸깍!
구름 속 SDK를 살짝 불러왔닥-탁!
템플릿이면 커스텀, 아니면 기본 딱딱.
웹쉐어 못 오면 클립보드 찰칵.
오늘도 배포 들판에, 링크가 방긋-톡톡. 🥕✨

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch share

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@cywin1018 cywin1018 merged commit 26ee433 into develop Sep 7, 2025
1 check passed
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (3)
src/common/KakaoShareButton.tsx (3)

58-58: onClick이 공유를 완전히 우회합니다 — 의도 확인

현재는 onClick 제공 시 공유 로직이 실행되지 않습니다. 로깅·트래킹 용도라면 onClick을 호출만 하고 공유를 계속 진행하는 편이 자연스럽습니다.

적용 diff:

-        if (onClick) return onClick();
+        onClick?.();

66-66: any 제거: Kakao 전역 최소 타입 선언 제안

전역 any는 회귀를 만들기 쉽습니다. 간단한 타입만 선언해도 사용성/안전성이 좋아집니다.

외부 파일 추가(예: src/types/kakao.d.ts):

declare global {
  interface Window {
    Kakao: {
      isInitialized(): boolean;
      init(key: string): void;
      Share: {
        sendCustom(opts: { templateId: number; templateArgs?: Record<string, string> }): void;
        sendDefault(opts: {
          objectType: 'feed';
          content: {
            title: string;
            description?: string;
            imageUrl?: string;
            link: { mobileWebUrl: string; webUrl: string };
          };
          buttons?: Array<{ title: string; link: { mobileWebUrl: string; webUrl: string } }>;
        }): void;
      };
    };
  }
}
export {};

109-111: UX: alert 대신 비차단형 알림/토스트 고려

alert는 전체 UI를 블로킹합니다. 프로젝트의 공통 토스트 컴포넌트가 있다면 그것을 사용하세요. (위 try/catch 통합 diff에는 최종 수단으로 prompt도 추가했습니다.)

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 258ae22 and 589b765.

📒 Files selected for processing (1)
  • src/common/KakaoShareButton.tsx (2 hunks)
🔇 Additional comments (1)
src/common/KakaoShareButton.tsx (1)

68-90: 카카오 콘솔 화이트리스트/템플릿 변수 검증 필요

  • shareUrl(https://www.dodream.site/landing)과 이미지 호스트가 카카오 플랫폼 도메인에 등록되어 있어야 전송이 성공합니다.
  • sendCustom 사용 시 templateArgs 키(url)가 템플릿 변수명과 일치해야 합니다.

Comment on lines +10 to +36
// Kakao SDK 로더
const loadKakao = (key: string) =>
new Promise<void>((resolve, reject) => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const w = window as any;
if (w.Kakao) {
if (!w.Kakao.isInitialized()) w.Kakao.init(key);
resolve();
return;
}
const s = document.createElement('script');
s.src = 'https://t1.kakaocdn.net/kakao_js_sdk/2.7.6/kakao.min.js';
s.integrity =
'sha384-WAtVcQYcmTO/N+C1N+1m6Gp8qxh+3NlnP7X1U7qP6P5dQY/MsRBNTh+e1ahJrkEm';
s.crossOrigin = 'anonymous';
s.onload = () => {
try {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(window as any).Kakao.init(key);
resolve();
} catch (e) {
reject(e);
}
};
s.onerror = reject;
document.head.appendChild(s);
});
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

SDK 중복 로딩/경합 방지: script ID로 디듀플하고 기존 스크립트에 리스너만 부착하세요

빠른 연속 클릭 시 window.Kakao가 생성되기 전까지 <script>가 중복 삽입될 수 있습니다. 스크립트에 고정 ID를 부여하고, 존재 시에는 기존 태그의 load/error에만 리스너를 추가해 디듀플링하세요.

적용 diff:

-    const s = document.createElement('script');
-    s.src = 'https://t1.kakaocdn.net/kakao_js_sdk/2.7.6/kakao.min.js';
-    s.integrity =
-      'sha384-WAtVcQYcmTO/N+C1N+1m6Gp8qxh+3NlnP7X1U7qP6P5dQY/MsRBNTh+e1ahJrkEm';
-    s.crossOrigin = 'anonymous';
-    s.onload = () => {
-      try {
-        // eslint-disable-next-line @typescript-eslint/no-explicit-any
-        (window as any).Kakao.init(key);
-        resolve();
-      } catch (e) {
-        reject(e);
-      }
-    };
-    s.onerror = reject;
-    document.head.appendChild(s);
+    const existing = document.getElementById('kakao-sdk') as HTMLScriptElement | null;
+    if (existing) {
+      existing.addEventListener('load', () => {
+        try {
+          // eslint-disable-next-line @typescript-eslint/no-explicit-any
+        (window as any).Kakao.init(key);
+          resolve();
+        } catch (e) {
+          reject(e);
+        }
+      }, { once: true });
+      existing.addEventListener('error', reject, { once: true });
+      return;
+    }
+    const s = document.createElement('script');
+    s.id = 'kakao-sdk';
+    s.src = 'https://t1.kakaocdn.net/kakao_js_sdk/2.7.6/kakao.min.js';
+    s.integrity =
+      'sha384-WAtVcQYcmTO/N+C1N+1m6Gp8qxh+3NlnP7X1U7qP6P5dQY/MsRBNTh+e1ahJrkEm';
+    s.crossOrigin = 'anonymous';
+    s.onload = () => {
+      try {
+        // eslint-disable-next-line @typescript-eslint/no-explicit-any
+        (window as any).Kakao.init(key);
+        resolve();
+      } catch (e) {
+        reject(e);
+      }
+    };
+    s.onerror = reject;
+    document.head.appendChild(s);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Kakao SDK 로더
const loadKakao = (key: string) =>
new Promise<void>((resolve, reject) => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const w = window as any;
if (w.Kakao) {
if (!w.Kakao.isInitialized()) w.Kakao.init(key);
resolve();
return;
}
const s = document.createElement('script');
s.src = 'https://t1.kakaocdn.net/kakao_js_sdk/2.7.6/kakao.min.js';
s.integrity =
'sha384-WAtVcQYcmTO/N+C1N+1m6Gp8qxh+3NlnP7X1U7qP6P5dQY/MsRBNTh+e1ahJrkEm';
s.crossOrigin = 'anonymous';
s.onload = () => {
try {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(window as any).Kakao.init(key);
resolve();
} catch (e) {
reject(e);
}
};
s.onerror = reject;
document.head.appendChild(s);
});
// Kakao SDK 로더
const loadKakao = (key: string) =>
new Promise<void>((resolve, reject) => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const w = window as any;
if (w.Kakao) {
if (!w.Kakao.isInitialized()) w.Kakao.init(key);
resolve();
return;
}
const existing = document.getElementById('kakao-sdk') as HTMLScriptElement | null;
if (existing) {
existing.addEventListener(
'load',
() => {
try {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(window as any).Kakao.init(key);
resolve();
} catch (e) {
reject(e);
}
},
{ once: true }
);
existing.addEventListener('error', reject, { once: true });
return;
}
const s = document.createElement('script');
s.id = 'kakao-sdk';
s.src = 'https://t1.kakaocdn.net/kakao_js_sdk/2.7.6/kakao.min.js';
s.integrity =
'sha384-WAtVcQYcmTO/N+C1N+1m6Gp8qxh+3NlnP7X1U7qP6P5dQY/MsRBNTh+e1ahJrkEm';
s.crossOrigin = 'anonymous';
s.onload = () => {
try {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(window as any).Kakao.init(key);
resolve();
} catch (e) {
reject(e);
}
};
s.onerror = reject;
document.head.appendChild(s);
});
🤖 Prompt for AI Agents
In src/common/KakaoShareButton.tsx around lines 10 to 36, the loader can append
duplicate <script> tags on rapid calls causing race conditions; add a fixed id
to the script, check document.getElementById(id) first, and if the element
exists attach onload/onerror listeners to that existing element
(resolving/rejecting appropriately) instead of creating a new tag; if it doesn't
exist create the script with that id, attach listeners, append once, and ensure
window.Kakao is only initialized once (guard with isInitialized) and that all
callers get resolved/rejected from the same event handlers.

Comment on lines +21 to +24
s.src = 'https://t1.kakaocdn.net/kakao_js_sdk/2.7.6/kakao.min.js';
s.integrity =
'sha384-WAtVcQYcmTO/N+C1N+1m6Gp8qxh+3NlnP7X1U7qP6P5dQY/MsRBNTh+e1ahJrkEm';
s.crossOrigin = 'anonymous';
Copy link

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

SDK 버전/무결성(SRI) 해시 최신 여부 확인

고정 버전(2.7.6)과 SRI 해시가 실제 배포 파일과 불일치하면 로드가 실패합니다. 최신 권장 버전과 해시를 확인해 주세요. 또한 변경 시 반드시 해시도 같이 갱신해야 합니다.


🌐 Web query:

Kakao JavaScript SDK의 최신 안정 버전은 무엇인가요? 또한 https://t1.kakaocdn.net/kakao_js_sdk/2.7.6/kakao.min.js 의 공식 SRI 해시가 무엇인지 확인해 주세요.

💡 Result:

요약:

  • 최신 안정 버전: 2.7.8 (배포일: 2025-09-03). [1]
  • https://t1.kakaocdn.net/kakao_js_sdk/2.7.6/kakao.min.js 의 공식 SRI 값은 카카오 개발자 문서의 다운로드 페이지에서 제공되지만(각 버전 항목의 "Copy Integrity Value"), 제가 해당 CDN 파일이나 페이지의 복사 버튼을 직접 조회하지 못해 현재 공식 SRI 해시를 바로 가져오지 못했습니다. 다운로드 페이지에서 2.7.6 항목의 "Copy Integrity Value"를 클릭하면 integrity 속성 값을 복사할 수 있습니다. [1]

원문 참조:

  1. Kakao Developers — JavaScript SDK 다운로드 (버전 목록 및 "Copy Integrity Value" 안내). [https://developers.kakao.com/docs/latest/ko/javascript/download] [https://developers.kakao.com/docs/latest/en/javascript/download]

🏁 Script executed:

#!/bin/bash
# Fetch Kakao JS SDK v2.7.8 and compute its official sha384 SRI hash
curl -s https://t1.kakaocdn.net/kakao_js_sdk/2.7.8/kakao.min.js \
  | openssl dgst -sha384 -binary \
  | openssl base64 -A \
  | sed 's/^/sha384-/'

Length of output: 91


🏁 Script executed:

#!/bin/bash
# Python으로 Kakao JS SDK v2.7.6 및 v2.7.8의 sha384 SRI 해시 계산
python3 - << 'EOF'
import hashlib, base64, urllib.request

def calc_sri(version):
    url = f'https://t1.kakaocdn.net/kakao_js_sdk/{version}/kakao.min.js'
    data = urllib.request.urlopen(url).read()
    h = hashlib.sha384(data).digest()
    print(version, 'sha384-' + base64.b64encode(h).decode())

for v in ['2.7.6', '2.7.8']:
    calc_sri(v)
EOF

Length of output: 2620


🏁 Script executed:

#!/bin/bash
# Python으로 SSL 인증 무시하고 Kakao JS SDK v2.7.6 및 v2.7.8의 sha384 SRI 해시 계산
python3 - << 'EOF'
import hashlib, base64, urllib.request, ssl

ctx = ssl._create_unverified_context()

def calc_sri(version):
    url = f'https://t1.kakaocdn.net/kakao_js_sdk/{version}/kakao.min.js'
    data = urllib.request.urlopen(url, context=ctx).read()
    h = hashlib.sha384(data).digest()
    print(version, 'sha384-' + base64.b64encode(h).decode())

for v in ['2.7.6', '2.7.8']:
    calc_sri(v)
EOF

Length of output: 155


Kakao JS SDK를 v2.7.8로 업데이트하고 SRI 해시도 갱신하세요
현재 2.7.6(sha384-WAtVcQYcmTO/N+C1N+1m6Gp8qxh+3NlnP7X1U7qP6P5dQY/MsRBNTh+e1ahJrkEm)을 사용 중인데, 최신 안정 버전은 2.7.8(2025-09-03 배포)이므로 아래와 같이 변경해야 로드 실패를 방지할 수 있습니다.

- s.src       = 'https://t1.kakaocdn.net/kakao_js_sdk/2.7.6/kakao.min.js';
- s.integrity = 'sha384-WAtVcQYcmTO/N+C1N+1m6Gp8qxh+3NlnP7X1U7qP6P5dQY/MsRBNTh+e1ahJrkEm';
+ s.src       = 'https://t1.kakaocdn.net/kakao_js_sdk/2.7.8/kakao.min.js';
+ s.integrity = 'sha384-WUSirVbD0ASvo37f3qQZuDap8wy76aJjmGyXKOYgPL/NdAs8HhgmPlk9dz2XQsNv';

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In src/common/KakaoShareButton.tsx around lines 21–24, the included Kakao JS SDK
version and its SRI hash are outdated (2.7.6); update the script src to v2.7.8
and replace the integrity attribute with the official sha384 SRI for the 2.7.8
release (fetch the exact hash from the provider/CDN or the Kakao release notes),
keeping crossOrigin='anonymous' intact so the script loads with the correct
subresource integrity.

Comment on lines 57 to 116
onClick={async () => {
if (onClick) return onClick();
const jsKey = import.meta.env.VITE_KAKAO_JS_KEY as string;
if (!jsKey) {
console.warn('VITE_KAKAO_JS_KEY is not set.');
return;
}
await loadKakao(jsKey);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const Kakao = (window as any).Kakao;
const templateId = Number(import.meta.env.VITE_KAKAO_TEMPLATE_ID);
const shareUrl = 'https://www.dodream.site/landing';
try {
if (templateId) {
Kakao.Share.sendCustom({
templateId,
templateArgs: { url: shareUrl },
});
} else {
Kakao.Share.sendDefault({
objectType: 'feed',
content: {
title: '두드림 – 내게 딱 맞는 직업 찾기',
description: '직업/학원/구직 정보를 한 곳에서!',
imageUrl: 'https://www.dodream.site/og-image.png',
link: { mobileWebUrl: shareUrl, webUrl: shareUrl },
},
buttons: [
{
title: '두드림 열기',
link: { mobileWebUrl: shareUrl, webUrl: shareUrl },
},
],
});
}
} catch (e) {
console.error('Kakao share failed', e);
// Fallback: Web Share API or clipboard copy
try {
if (navigator.share) {
await navigator.share({
title: '두드림 – 내게 딱 맞는 직업 찾기',
text: '직업/학원/구직 정보를 한 곳에서!',
url: shareUrl,
});
return;
}
} catch {
// ignore and continue to clipboard
}
try {
await navigator.clipboard.writeText(shareUrl);
alert(
'카카오 공유가 불가능하여 링크를 클립보드에 복사했습니다. 붙여넣기로 공유해 주세요.'
);
} catch (err) {
console.error('Clipboard write failed', err);
}
}
}}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

loadKakao 실패 시 폴백 미작동 — try/catch 범위를 전체 Kakao 흐름으로 확장 필요

현재 try/catch가 공유 호출 부분에만 적용되어 SDK 로드 실패(네트워크, SRI mismatch 등) 시 폴백(Web Share/클립보드)이 실행되지 않습니다. 로드+공유 전체를 한 번의 try/catch로 감싸고, 키 미설정 시에도 폴백을 타도록 수정하세요.

적용 diff:

-        const jsKey = import.meta.env.VITE_KAKAO_JS_KEY as string;
-        if (!jsKey) {
-          console.warn('VITE_KAKAO_JS_KEY is not set.');
-          return;
-        }
-        await loadKakao(jsKey);
-        // eslint-disable-next-line @typescript-eslint/no-explicit-any
-        const Kakao = (window as any).Kakao;
-        const templateId = Number(import.meta.env.VITE_KAKAO_TEMPLATE_ID);
-        const shareUrl = 'https://www.dodream.site/landing';
-        try {
-          if (templateId) {
-            Kakao.Share.sendCustom({
-              templateId,
-              templateArgs: { url: shareUrl },
-            });
-          } else {
-            Kakao.Share.sendDefault({
-              objectType: 'feed',
-              content: {
-                title: '두드림 – 내게 딱 맞는 직업 찾기',
-                description: '직업/학원/구직 정보를 한 곳에서!',
-                imageUrl: 'https://www.dodream.site/og-image.png',
-                link: { mobileWebUrl: shareUrl, webUrl: shareUrl },
-              },
-              buttons: [
-                {
-                  title: '두드림 열기',
-                  link: { mobileWebUrl: shareUrl, webUrl: shareUrl },
-                },
-              ],
-            });
-          }
-        } catch (e) {
-          console.error('Kakao share failed', e);
-          // Fallback: Web Share API or clipboard copy
-          try {
-            if (navigator.share) {
-              await navigator.share({
-                title: '두드림 – 내게 딱 맞는 직업 찾기',
-                text: '직업/학원/구직 정보를 한 곳에서!',
-                url: shareUrl,
-              });
-              return;
-            }
-          } catch {
-            // ignore and continue to clipboard
-          }
-          try {
-            await navigator.clipboard.writeText(shareUrl);
-            alert(
-              '카카오 공유가 불가능하여 링크를 클립보드에 복사했습니다. 붙여넣기로 공유해 주세요.'
-            );
-          } catch (err) {
-            console.error('Clipboard write failed', err);
-          }
-        }
+        const jsKey = import.meta.env.VITE_KAKAO_JS_KEY as string;
+        const shareUrl = 'https://www.dodream.site/landing';
+        try {
+          if (jsKey) {
+            await loadKakao(jsKey);
+            // eslint-disable-next-line @typescript-eslint/no-explicit-any
+            const Kakao = (window as any).Kakao;
+            const templateId = Number(import.meta.env.VITE_KAKAO_TEMPLATE_ID);
+            if (templateId) {
+              Kakao.Share.sendCustom({
+                templateId,
+                templateArgs: { url: shareUrl },
+              });
+            } else {
+              Kakao.Share.sendDefault({
+                objectType: 'feed',
+                content: {
+                  title: '두드림 – 내게 딱 맞는 직업 찾기',
+                  description: '직업/학원/구직 정보를 한 곳에서!',
+                  imageUrl: 'https://www.dodream.site/og-image.png',
+                  link: { mobileWebUrl: shareUrl, webUrl: shareUrl },
+                },
+                buttons: [
+                  {
+                    title: '두드림 열기',
+                    link: { mobileWebUrl: shareUrl, webUrl: shareUrl },
+                  },
+                ],
+              });
+            }
+            return;
+          }
+          throw new Error('VITE_KAKAO_JS_KEY is not set.');
+        } catch (e) {
+          console.error('Kakao share failed', e);
+          try {
+            if (navigator.share) {
+              await navigator.share({
+                title: '두드림 – 내게 딱 맞는 직업 찾기',
+                text: '직업/학원/구직 정보를 한 곳에서!',
+                url: shareUrl,
+              });
+              return;
+            }
+          } catch {
+            // ignore and continue to clipboard
+          }
+          try {
+            await navigator.clipboard.writeText(shareUrl);
+            alert(
+              '카카오 공유가 불가능하여 링크를 클립보드에 복사했습니다. 붙여넣기로 공유해 주세요.'
+            );
+          } catch (err) {
+            console.error('Clipboard write failed', err);
+            window.prompt('링크 복사에 실패했습니다. 아래 링크를 복사해 주세요.', shareUrl);
+          }
+        }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
onClick={async () => {
if (onClick) return onClick();
const jsKey = import.meta.env.VITE_KAKAO_JS_KEY as string;
if (!jsKey) {
console.warn('VITE_KAKAO_JS_KEY is not set.');
return;
}
await loadKakao(jsKey);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const Kakao = (window as any).Kakao;
const templateId = Number(import.meta.env.VITE_KAKAO_TEMPLATE_ID);
const shareUrl = 'https://www.dodream.site/landing';
try {
if (templateId) {
Kakao.Share.sendCustom({
templateId,
templateArgs: { url: shareUrl },
});
} else {
Kakao.Share.sendDefault({
objectType: 'feed',
content: {
title: '두드림 – 내게 딱 맞는 직업 찾기',
description: '직업/학원/구직 정보를 한 곳에서!',
imageUrl: 'https://www.dodream.site/og-image.png',
link: { mobileWebUrl: shareUrl, webUrl: shareUrl },
},
buttons: [
{
title: '두드림 열기',
link: { mobileWebUrl: shareUrl, webUrl: shareUrl },
},
],
});
}
} catch (e) {
console.error('Kakao share failed', e);
// Fallback: Web Share API or clipboard copy
try {
if (navigator.share) {
await navigator.share({
title: '두드림 – 내게 딱 맞는 직업 찾기',
text: '직업/학원/구직 정보를 한 곳에서!',
url: shareUrl,
});
return;
}
} catch {
// ignore and continue to clipboard
}
try {
await navigator.clipboard.writeText(shareUrl);
alert(
'카카오 공유가 불가능하여 링크를 클립보드에 복사했습니다. 붙여넣기로 공유해 주세요.'
);
} catch (err) {
console.error('Clipboard write failed', err);
}
}
}}
onClick={async () => {
if (onClick) return onClick();
const jsKey = import.meta.env.VITE_KAKAO_JS_KEY as string;
const shareUrl = 'https://www.dodream.site/landing';
try {
if (jsKey) {
await loadKakao(jsKey);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const Kakao = (window as any).Kakao;
const templateId = Number(import.meta.env.VITE_KAKAO_TEMPLATE_ID);
if (templateId) {
Kakao.Share.sendCustom({
templateId,
templateArgs: { url: shareUrl },
});
} else {
Kakao.Share.sendDefault({
objectType: 'feed',
content: {
title: '두드림 – 내게 딱 맞는 직업 찾기',
description: '직업/학원/구직 정보를 한 곳에서!',
imageUrl: 'https://www.dodream.site/og-image.png',
link: { mobileWebUrl: shareUrl, webUrl: shareUrl },
},
buttons: [
{
title: '두드림 열기',
link: { mobileWebUrl: shareUrl, webUrl: shareUrl },
},
],
});
}
return;
}
throw new Error('VITE_KAKAO_JS_KEY is not set.');
} catch (e) {
console.error('Kakao share failed', e);
try {
if (navigator.share) {
await navigator.share({
title: '두드림 – 내게 딱 맞는 직업 찾기',
text: '직업/학원/구직 정보를 한 곳에서!',
url: shareUrl,
});
return;
}
} catch {
// ignore and continue to clipboard
}
try {
await navigator.clipboard.writeText(shareUrl);
alert(
'카카오 공유가 불가능하여 링크를 클립보드에 복사했습니다. 붙여넣기로 공유해 주세요.'
);
} catch (err) {
console.error('Clipboard write failed', err);
window.prompt('링크 복사에 실패했습니다. 아래 링크를 복사해 주세요.', shareUrl);
}
}
}}

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.

2 participants