Skip to content

feat: 영수증 인스타그램 스토리 공유 추가 (웹브릿지 + 앱 핸들러) - #429

Open
ychany wants to merge 8 commits into
devfrom
feat/419-instagram-story-share
Open

feat: 영수증 인스타그램 스토리 공유 추가 (웹브릿지 + 앱 핸들러)#429
ychany wants to merge 8 commits into
devfrom
feat/419-instagram-story-share

Conversation

@ychany

@ychany ychany commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

작업 요약

  • 영수증 공유 바텀시트에 인스타그램 스토리 공유를 추가합니다
  • 스토리 공유용 웹브릿지 메시지와 앱 네이티브 핸들러를 구현합니다
  • 인스타그램 미설치 시 설치 안내 토스트를 노출합니다
  • 인스타그램 아이콘을 시안 기준으로 교체합니다
  • 영수증 공유 이미지의 흰 박스 크기를 고정합니다

작업 세부 내용

스토리 공유는 딥링크 + pasteboard(iOS) / 파일 URI(Android)가 필요한 네이티브 동작이라, 웹뷰 → 앱 브릿지로 이미지를 넘기고 결과만 돌려받는 구조로 구현했습니다.

1. 웹브릿지 메시지 (packages/core)

  • WEB_REQ_SHARE_INSTAGRAM_STORY / APP_RES_SHARE_INSTAGRAM_STORY 신규 추가
  • payload: requestId + base64 본문 + mimeType (dataURL prefix 제외)
  • 응답 상태를 success | notInstalled | error 로 정의 — 미설치를 별도 상태로 내려받아 웹에서 설치 안내 토스트를 띄웁니다
  • BRIDGE_GATE 에 신규 2개 등록 (기존 항목 변경 없음). 사용자가 직접 누르는 동작이라 notifyOnBlock: true

success 는 "스토리 편집 화면까지 띄웠다" 까지만 보장합니다. 편집 화면 진입 후 게시/취소는 앱이 알 수 없습니다.

2. 네이티브 핸들러 (apps/app)

  • iOS: pasteboard 에 이미지 등록 후 instagram-stories://share 오픈 (인스타그램이 pasteboard 에서 읽어가므로 딥링크보다 먼저 복사)
  • Android: 캐시 파일 → FileProvider content:// URI → ADD_TO_STORY 인텐트
  • 미설치 시 notInstalled 로 응답
  • LSApplicationQueriesSchemesinstagram-stories 추가
  • Android <queries> 주입 config plugin 신규 (withInstagramQueries.js) — Android 11+ 는 선언하지 않은 패키지가 보이지 않아 canOpenURL 이 항상 false 가 됩니다
  • expo-file-system / expo-intent-launcher / expo-clipboard 추가

3. 웹 UI (apps/web)

  • 앱 환경에서만 스토리 공유 버튼 노출 (useSyncExternalStore 로 hydration mismatch 회피)
  • 앱 응답에 따라 분기
    • notInstalled인스타그램 앱을 설치하면 스토리에 공유할 수 있어요.
    • error스토리 공유에 실패했어요. 잠시 후 다시 시도해주세요.
    • 게이트 차단 → WebBridge 가 이미 업데이트 안내를 띄우므로 조용히 종료
  • 앱 무응답 대비 15초 타임아웃 — 버튼이 영구히 잠기지 않게 처리
  • 버튼이 4개가 되어 간격을 clamp() 로 조정 (좁은 화면 대응)

4. 아이콘

전달받은 SVG 가 마스크만 벡터고 내부는 2497x2497 PNG(10.9MB) 여서 그대로 쓸 수 없었습니다. 로고 패스만 추출하고 시안에서 샘플링한 색으로 그라데이션을 재현했습니다.

  • 10.9MB → 3.4KB
  • 배경은 시안대로 흰색 + 옅은 테두리

5. 영수증 이미지 흰 박스 크기 고정

상품명 길이에 따라 영수증 높이가 달라져 위아래 여백이 들쭉날쭉했습니다. 영수증 영역을 고정 높이(748px)로 두고, 내용이 넘치면 zoom 을 낮춰 안에 맞추도록 했습니다.

기존에는 justify-center 라 넘친 만큼 위아래로 삐져나가고 있었습니다. 현재 데이터도 이미 20px 초과 상태여서, 이 수정으로 zoom 이 1.28 → 1.2467 로 미세하게 조정됩니다.

검증

  • 웹/앱 타입체크, lint, 웹 빌드 통과
  • e2e 5개 통과 — 웹 브라우저에서는 버튼 숨김 / 웹뷰 UA 에서는 노출 + 미설치 토스트
  • 갤럭시 S24+(Android 16) 실기기에서 빌드·설치 확인

리뷰 포인트

minAppVersion 값 확정이 필요합니다. 새 메시지를 BRIDGE_GATE 에 등록하면서 '1.1.2' 로 넣어뒀는데, 앱 핸들러가 실제 포함되는 릴리즈 버전을 아직 알 수 없어 추정한 값입니다. 릴리즈 후 git tag --contains <sha> 로 확인해 교체해야 합니다.

@expo/plist 수정이 함께 들어있습니다. 인스타그램 기능과 무관한 별개 버그로, 이게 없으면 현재 dev 에서도 iOS prebuild 가 plist.parse is not a function 으로 실패합니다.

스크린샷

인스타그램 스토리 전달
_talkv_dJMcblSTtl0_BKmqonkq3rSIuKmKeBJyrK_talkv_high.mov

연관 이슈

closes #419

Summary by CodeRabbit

  • 새로운 기능

    • 영수증 이미지를 Instagram Stories로 공유할 수 있습니다.
    • iOS와 Android에서 Instagram 설치 여부와 공유 결과를 안내합니다.
    • 지원되지 않는 앱 버전에서는 공유 버튼이 제한됩니다.
    • 공유 중 로딩 상태와 실패·미설치 안내가 제공됩니다.
  • 개선

    • 영수증 캡처 크기에 맞춰 이미지 배율이 자동 조정됩니다.
    • 공유 버튼 배치가 다양한 화면 크기에 맞게 개선되었습니다.
  • 테스트

    • 웹 브라우저와 앱 내 웹뷰 환경에서 공유 기능 및 안내 메시지를 검증했습니다.

@vercel

vercel Bot commented Aug 3, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
piki Ready Ready Preview Aug 6, 2026 5:26am

@coderabbitai

coderabbitai Bot commented Aug 3, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@ychany, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 54 minutes

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: afb3217d-3520-46ab-932c-a67cf9f36863

📥 Commits

Reviewing files that changed from the base of the PR and between 22d01ae and d389c11.

⛔ Files ignored due to path filters (2)
  • apps/web/src/assets/icons/social/instagram.svg is excluded by !**/*.svg
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (16)
  • apps/app/app.json
  • apps/app/app/index.tsx
  • apps/app/package.json
  • apps/app/plugins/withInstagramQueries.js
  • apps/app/plugins/withShareExtensionKeychain.js
  • apps/app/utils/handleInstagramStory.ts
  • apps/web/e2e/specs/tournament/tournamentResult.spec.ts
  • apps/web/src/app/tournament/[id]/result/_components/receipt-share-dialog/ReceiptShareCaptureLayer.tsx
  • apps/web/src/app/tournament/[id]/result/_components/receipt-share-dialog/ReceiptShareDialog.tsx
  • apps/web/src/hooks/useInstagramStoryShare.ts
  • apps/web/src/utils/handleImage.ts
  • packages/core/src/consts/appVersion.ts
  • packages/core/src/consts/webBridge.ts
  • packages/core/src/index.ts
  • packages/core/src/types/instagramStory.ts
  • packages/core/src/types/webBridge.ts
📝 Walkthrough

Walkthrough

영수증 공유 다이얼로그에 Instagram Stories 공유를 추가했습니다. 웹은 WebBridge로 이미지를 앱에 전달하고, 앱은 iOS와 Android에서 Instagram Stories 편집 화면을 엽니다. 지원 버전과 설치 상태를 확인하며, 브라우저와 WebView 동작을 E2E 테스트로 검증합니다.

Changes

Instagram Stories 공유

Layer / File(s) Summary
WebBridge 계약과 버전 게이트
packages/core/src/consts/*, packages/core/src/types/*, packages/core/src/index.ts
Instagram Stories 요청·응답 메시지와 payload 타입을 추가했습니다. 최소 앱 버전 1.1.2 게이트를 등록했습니다.
네이티브 공유 핸들러와 플랫폼 설정
apps/app/app.json, apps/app/app/index.tsx, apps/app/package.json, apps/app/plugins/*, apps/app/utils/handleInstagramStory.ts
iOS는 클립보드와 딥링크를 사용합니다. Android는 캐시 파일과 content:// URI를 사용합니다. 설치 여부와 오류 상태를 WebBridge로 반환합니다.
웹 이미지 변환과 공유 UI
apps/web/src/hooks/useInstagramStoryShare.ts, apps/web/src/utils/handleImage.ts, apps/web/src/app/tournament/[id]/result/_components/receipt-share-dialog/*
Blob을 base64로 변환하고 요청별 응답을 처리합니다. WebView에서만 버튼을 표시하며 공유 상태별 UI를 제공합니다. 영수증 캡처 높이에 맞춰 zoom을 조정합니다.
브라우저·WebView 공유 검증
apps/web/e2e/specs/tournament/tournamentResult.spec.ts
브라우저에서 버튼이 숨겨지는지 확인합니다. WebView에서 버튼 표시와 Instagram 미설치 토스트를 확인합니다.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant ReceiptShareDialog
  participant useInstagramStoryShare
  participant WebBridge
  participant handleShareInstagramStory
  participant Instagram
  ReceiptShareDialog->>useInstagramStoryShare: 영수증 Blob 전달
  useInstagramStoryShare->>WebBridge: base64 공유 요청
  WebBridge->>handleShareInstagramStory: 요청 payload 전달
  handleShareInstagramStory->>Instagram: 이미지와 함께 Stories 편집 화면 실행
  Instagram-->>handleShareInstagramStory: 실행 결과
  handleShareInstagramStory-->>WebBridge: 공유 상태 응답
  WebBridge-->>useInstagramStoryShare: requestId 기반 결과
  useInstagramStoryShare-->>ReceiptShareDialog: 성공 또는 오류 상태
Loading

Possibly related PRs

  • TeamPiKi/client#358: 영수증 공유 UI와 캡처 구성 요소를 함께 수정합니다.
  • TeamPiKi/client#384: BRIDGE_GATE와 WebBridge 버전 게이트를 사용합니다.
  • TeamPiKi/client#418: 영수증 공유 다이얼로그와 캡처 레이어를 확장한 변경과 연결됩니다.

Suggested labels: feature, APP, WEB, test

Suggested reviewers: iodio89, kanghaeun

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Linked Issues check ❓ Inconclusive 검토 가능한 요구사항은 충족하지만 인스타그램 SVG가 필터링되어 벡터 아이콘 추가 여부와 실제 릴리즈 버전 기준을 확인할 수 없습니다. apps/web/src/assets/icons/social/instagram.svg를 !**/*.svg 필터에서 검토하고, BRIDGE_GATE의 minAppVersion이 실제 릴리즈 버전인지 확인하세요.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 제목은 영수증 인스타그램 스토리 공유와 웹브릿지·앱 핸들러 구현이라는 주요 변경을 정확히 설명합니다.
Out of Scope Changes check ✅ Passed 모든 변경은 인스타그램 스토리 공유, 이미지 캡처, iOS prebuild 수정 또는 관련 테스트 요구사항과 연결됩니다.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/419-instagram-story-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.

@ychany

ychany commented Aug 4, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Aug 4, 2026

Copy link
Copy Markdown
✅ Action performed

Full review finished.


Your included review limit is currently reached under our Fair Usage Limits Policy. This review may still proceed through usage-based billing if eligible. Your next included review will be available in 48 minutes.

@coderabbitai

coderabbitai Bot commented Aug 4, 2026

Copy link
Copy Markdown
✅ Action performed

Full review finished.


Your included review limit is currently reached under our Fair Usage Limits Policy. This review may still proceed through usage-based billing if eligible. Your next included review will be available in 46 minutes.

@iOdiO89

iOdiO89 commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown
✅ Action performed

Full review finished.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (4)
apps/app/utils/handleInstagramStory.ts (1)

1-5: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

type-only import를 분리하고 trailing comma를 추가하십시오.

프로젝트 규칙은 type-only import에 import type 선언을 사용하도록 요구합니다. 현재 declaration은 값과 타입을 혼합합니다. multiline type import의 마지막 항목에도 trailing comma를 추가하십시오.

수정 예시
-import {
-  type ShareInstagramStoryPayloadT,
-  type ShareInstagramStoryStatusT,
-  WEBBRIDGE_MESSAGE_TYPE,
-} from '`@piki/core`';
+import { WEBBRIDGE_MESSAGE_TYPE } from '`@piki/core`';
+import type {
+  ShareInstagramStoryPayloadT,
+  ShareInstagramStoryStatusT,
+} from '`@piki/core`';

As per coding guidelines, type-only imports must use import type, and multiline imports must use ES5 trailing commas.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/app/utils/handleInstagramStory.ts` around lines 1 - 5, Update the
imports in handleInstagramStory.ts to place ShareInstagramStoryPayloadT and
ShareInstagramStoryStatusT in a separate import type declaration, keep
WEBBRIDGE_MESSAGE_TYPE in the value import, and add trailing commas to the
multiline import lists.

Source: Coding guidelines

apps/app/plugins/withInstagramQueries.js (1)

9-10: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

콜백 파라미터 이름이 바깥 파라미터를 가립니다.

바깥 화살표 함수의 configwithAndroidManifest 콜백의 config가 같은 이름입니다. 동작은 정상이지만, 어떤 config를 읽는지 혼동됩니다. 콜백 파라미터를 modConfig로 바꾸면 의도가 명확해집니다.

♻️ 제안 변경
 const withInstagramQueries = config =>
-  withAndroidManifest(config, config => {
-    const manifest = config.modResults.manifest;
+  withAndroidManifest(config, modConfig => {
+    const manifest = modConfig.modResults.manifest;

그리고 26행의 return config;return modConfig; 로 변경하세요.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/app/plugins/withInstagramQueries.js` around lines 9 - 10, Rename the
inner callback parameter of withAndroidManifest in withInstagramQueries from
config to modConfig, and update its corresponding return config statement to
return modConfig.
apps/web/e2e/specs/tournament/tournamentResult.spec.ts (1)

89-107: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

브릿지 메시지 타입을 상수로 주입하세요.

94행과 99행은 와이어 값을 문자열로 직접 적었습니다. 71-72행은 게이트 값을 상수에서 읽는데, 메시지 타입만 하드코딩입니다. WEBBRIDGE_MESSAGE_TYPE의 값이 바뀌면 mock이 early return 합니다. 그러면 응답이 오지 않고 15초 타임아웃 뒤 다른 토스트가 뜹니다. 실패 원인 파악이 어려워집니다.

page.addInitScript는 두 번째 인자로 직렬화 가능한 값을 전달할 수 있습니다. 상수를 인자로 넘기세요.

♻️ 제안 변경
-    await page.addInitScript(() => {
+    await page.addInitScript(
+      ({ reqType, resType }) => {
       Object.defineProperty(window, 'ReactNativeWebView', {
         value: {
           postMessage: (raw: string) => {
             const message = JSON.parse(raw);
-            if (message.type !== 'WEB_REQ_SHARE_INSTAGRAM_STORY') return;
+            if (message.type !== reqType) return;
 
             window.dispatchEvent(
               new MessageEvent('message', {
                 data: JSON.stringify({
-                  type: 'APP_RES_SHARE_INSTAGRAM_STORY',
+                  type: resType,
                   payload: { requestId: message.payload.requestId, status: 'notInstalled' },
                 }),
               })
             );
           },
         },
       });
-    });
+      },
+      {
+        reqType: WEBBRIDGE_MESSAGE_TYPE.WEB_REQ_SHARE_INSTAGRAM_STORY,
+        resType: WEBBRIDGE_MESSAGE_TYPE.APP_RES_SHARE_INSTAGRAM_STORY,
+      }
+    );
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/web/e2e/specs/tournament/tournamentResult.spec.ts` around lines 89 -
107, Update the page.addInitScript mock to receive WEBBRIDGE_MESSAGE_TYPE
through its serializable argument instead of hardcoding the bridge message
strings. Use the injected constant for both the request-type early-return check
and the response message type, preserving the existing requestId and
notInstalled payload behavior.
apps/web/src/app/tournament/[id]/result/_components/receipt-share-dialog/ReceiptShareDialog.tsx (1)

84-88: 🚀 Performance & Scalability | 🔵 Trivial | 💤 Low value

useSyncExternalStore 인자를 모듈 스코프로 올리세요.

subscribegetSnapshot 인자를 렌더마다 새로 만듭니다. React는 subscribe 참조가 바뀔 때마다 재구독합니다. 동작은 정상이지만 불필요한 작업이 반복됩니다. 두 함수를 모듈 스코프 상수로 정의하면 참조가 고정됩니다. 이 패턴은 다른 화면에서도 쓸 수 있으므로 공용 훅으로 빼는 방법도 있습니다.

♻️ 제안 변경
+const subscribeNoop = () => () => {};
+const getIsWebviewSnapshot = () => isWebview();
+const getIsWebviewServerSnapshot = () => false;
+
 function ReceiptShareDialog({
-  const isAppEnvironment = useSyncExternalStore(
-    () => () => {},
-    () => isWebview(),
-    () => false
-  );
+  const isAppEnvironment = useSyncExternalStore(
+    subscribeNoop,
+    getIsWebviewSnapshot,
+    getIsWebviewServerSnapshot
+  );
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@apps/web/src/app/tournament/`[id]/result/_components/receipt-share-dialog/ReceiptShareDialog.tsx
around lines 84 - 88, Move the subscribe and getSnapshot callbacks used by
isAppEnvironment in useSyncExternalStore to module-scope constants, keeping the
existing server snapshot behavior unchanged. Update the hook call to reuse those
stable references on every render; do not alter the isWebview detection
behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/web/src/hooks/useInstagramStoryShare.ts`:
- Around line 65-70: Move requestId generation and setIsSharing(true) inside the
try block of shareToStory so failures from crypto.randomUUID() are handled by
the existing error/finally flow. Preserve the hook’s non-throwing contract and
ensure isSharing is reset when any setup or sharing operation fails.

---

Nitpick comments:
In `@apps/app/plugins/withInstagramQueries.js`:
- Around line 9-10: Rename the inner callback parameter of withAndroidManifest
in withInstagramQueries from config to modConfig, and update its corresponding
return config statement to return modConfig.

In `@apps/app/utils/handleInstagramStory.ts`:
- Around line 1-5: Update the imports in handleInstagramStory.ts to place
ShareInstagramStoryPayloadT and ShareInstagramStoryStatusT in a separate import
type declaration, keep WEBBRIDGE_MESSAGE_TYPE in the value import, and add
trailing commas to the multiline import lists.

In `@apps/web/e2e/specs/tournament/tournamentResult.spec.ts`:
- Around line 89-107: Update the page.addInitScript mock to receive
WEBBRIDGE_MESSAGE_TYPE through its serializable argument instead of hardcoding
the bridge message strings. Use the injected constant for both the request-type
early-return check and the response message type, preserving the existing
requestId and notInstalled payload behavior.

In
`@apps/web/src/app/tournament/`[id]/result/_components/receipt-share-dialog/ReceiptShareDialog.tsx:
- Around line 84-88: Move the subscribe and getSnapshot callbacks used by
isAppEnvironment in useSyncExternalStore to module-scope constants, keeping the
existing server snapshot behavior unchanged. Update the hook call to reuse those
stable references on every render; do not alter the isWebview detection
behavior.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 7311e4ee-229c-48c4-8da5-168507e97620

📥 Commits

Reviewing files that changed from the base of the PR and between dd1f79c and 5b169de.

⛔ Files ignored due to path filters (2)
  • apps/web/src/assets/icons/social/instagram.svg is excluded by !**/*.svg
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (16)
  • apps/app/app.json
  • apps/app/app/index.tsx
  • apps/app/package.json
  • apps/app/plugins/withInstagramQueries.js
  • apps/app/plugins/withShareExtensionKeychain.js
  • apps/app/utils/handleInstagramStory.ts
  • apps/web/e2e/specs/tournament/tournamentResult.spec.ts
  • apps/web/src/app/tournament/[id]/result/_components/receipt-share-dialog/ReceiptShareCaptureLayer.tsx
  • apps/web/src/app/tournament/[id]/result/_components/receipt-share-dialog/ReceiptShareDialog.tsx
  • apps/web/src/hooks/useInstagramStoryShare.ts
  • apps/web/src/utils/handleImage.ts
  • packages/core/src/consts/appVersion.ts
  • packages/core/src/consts/webBridge.ts
  • packages/core/src/index.ts
  • packages/core/src/types/instagramStory.ts
  • packages/core/src/types/webBridge.ts

Comment thread apps/web/src/hooks/useInstagramStoryShare.ts
ychany added 7 commits August 6, 2026 14:21
WEB_REQ_SHARE_INSTAGRAM_STORY / APP_RES_SHARE_INSTAGRAM_STORY 를 정의하고
BRIDGE_GATE 에 등록한다. 미설치(notInstalled) 를 별도 상태로 내려받아
웹에서 설치 안내 토스트를 띄울 수 있게 했다.
- iOS: pasteboard 에 이미지 등록 후 instagram-stories://share 오픈
- Android: 캐시 파일의 content:// URI 를 ADD_TO_STORY 인텐트로 전달
- 미설치 시 notInstalled 로 응답해 웹이 설치 안내 토스트를 띄우게 함
- iOS LSApplicationQueriesSchemes, Android queries 에 인스타그램 등록
앱 환경에서만 노출하고, 앱 응답에 따라 미설치·실패를 토스트로 안내한다.
인스타그램 아이콘은 벡터로 새로 작성했다.
@expo/plist 0.4.8 이 export 를 default 아래로 옮기면서
plist.parse 가 undefined 가 돼 prebuild 가 실패했다.
전달받은 SVG 는 마스크만 벡터고 내부는 2497x2497 PNG(10.9MB) 라 사용할 수 없어,
로고 패스만 추출하고 시안에서 샘플링한 색으로 그라데이션을 재현했다 (3.4KB).
아이콘 자체에 색이 있어 배경은 다른 액션과 동일한 회색으로 통일.
- 웹 브라우저에서는 스토리 공유 버튼이 노출되지 않는지 검증
- 웹뷰 UA 에서는 버튼이 노출되고, notInstalled 응답 시 설치 안내 토스트를 띄우는지 검증
상품명 길이에 따라 영수증 높이가 달라져 위아래 여백이 들쭉날쭉했다.
영수증 영역을 고정 높이(748px)로 두고, 내용이 넘치면 zoom 을 낮춰 안에 맞춘다.
@ychany
ychany force-pushed the feat/419-instagram-story-share branch from 5b169de to d873f4b Compare August 6, 2026 05:22
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.

feat: 영수증 인스타그램 스토리 공유 추가 (웹브릿지 + 앱 핸들러)

2 participants