Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ jobs:
run: |
IMAGE="${{ secrets.DOCKER_USERNAME }}/yamoyo-nginx:prod"
docker build \
--build-arg VITE_BASE_URL=${{ secrets.VITE_BASE_URL }} \
--build-arg VITE_BASE_URL="${{ secrets.VITE_BASE_URL }}" \
--build-arg VITE_KAKAO_JAVASCRIPT_KEY="${{ secrets.VITE_KAKAO_JAVASCRIPT_KEY }}" \
--build-arg VITE_KAKAO_TEMPLATE_ID="${{ secrets.VITE_KAKAO_TEMPLATE_ID }}" \
-t "$IMAGE" .
docker push "$IMAGE"

Expand Down
6 changes: 6 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,14 @@ WORKDIR /app

# 빌드 인자 선언
ARG VITE_BASE_URL
ARG VITE_KAKAO_JAVASCRIPT_KEY
ARG VITE_KAKAO_TEMPLATE_ID
RUN test -n "$VITE_BASE_URL" || (echo "Error: VITE_BASE_URL build-arg is required" >&2 && exit 1)
RUN test -n "$VITE_KAKAO_JAVASCRIPT_KEY" || (echo "Error: VITE_KAKAO_JAVASCRIPT_KEY build-arg is required" >&2 && exit 1)
RUN test -n "$VITE_KAKAO_TEMPLATE_ID" || (echo "Error: VITE_KAKAO_TEMPLATE_ID build-arg is required" >&2 && exit 1)
ENV VITE_BASE_URL=${VITE_BASE_URL}
ENV VITE_KAKAO_JAVASCRIPT_KEY=${VITE_KAKAO_JAVASCRIPT_KEY}
ENV VITE_KAKAO_TEMPLATE_ID=${VITE_KAKAO_TEMPLATE_ID}

# 의존성 설치
COPY package*.json ./
Expand Down
12 changes: 3 additions & 9 deletions src/entities/teamroom/hooks/useTeamRoom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import type {
CreateTeamRoomRequest,
TeamRoomLifecycle,
} from '@/entities/teamroom/api/teamroom-dto';
import { copyText } from '@/shared/lib/copyText';

/** 팀룸 목록 조회 */
export function useTeamRoomList(lifecycle: TeamRoomLifecycle = 'ACTIVE') {
Expand Down Expand Up @@ -77,14 +76,9 @@ export function useDeleteTeamRoom(onSuccess?: () => void) {
/** 초대 링크 생성 */
export function useCreateInviteLink() {
return useMutation({
mutationFn: (teamRoomId: number) => createInviteLink(teamRoomId),
onSuccess: async (data) => {
const inviteUrl = `${window.location.origin}/invite?token=${data.token}`;
await copyText(inviteUrl);
alert('초대 링크가 복사되었습니다.');
},
onError: () => {
alert('초대 링크 생성에 실패했습니다.');
mutationFn: async (teamRoomId: number) => {
const data = await createInviteLink(teamRoomId);
return data.token;
},
});
}
Expand Down
File renamed without changes.
50 changes: 50 additions & 0 deletions src/shared/lib/kakao/KakaoSdkLoader.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { useEffect } from 'react';

export function KakaoSdkLoader() {
useEffect(() => {
if (typeof window === 'undefined') return;

const KAKAO_JAVASCRIPT_KEY: string = import.meta.env
Comment thread
jaqwe2301 marked this conversation as resolved.
Resolved
?.VITE_KAKAO_JAVASCRIPT_KEY;
Comment thread
jaqwe2301 marked this conversation as resolved.
Resolved
const src = 'https://t1.kakaocdn.net/kakao_js_sdk/2.7.9/kakao.min.js';
const id = 'kakao-js-sdk';

const initKakao = () => {
if (!window.Kakao) return;

// 중복 init 방지
if (!window.Kakao.isInitialized()) {
window.Kakao.init(KAKAO_JAVASCRIPT_KEY);
}

window.Kakao.isInitialized();
Comment thread
jaqwe2301 marked this conversation as resolved.
Resolved
};

// 이미 script가 있으면 로드 완료 여부에 따라 init
const existing = document.getElementById(id) as HTMLScriptElement | null;
if (existing) {
// 이미 로드 완료된 경우 window.Kakao가 있을 수 있음
if (window.Kakao) initKakao();
else existing.addEventListener('load', initKakao);
return;
}

// script 주입
const script = document.createElement('script');
Comment thread
jaqwe2301 marked this conversation as resolved.
Resolved
script.id = id;
script.src = src;
script.async = true;
script.crossOrigin = 'anonymous';
script.integrity =
'sha384-JpLApTkB8lPskhVMhT+m5Ln8aHlnS0bsIexhaak0jOhAkMYedQoVghPfSpjNi9K1';

script.onload = initKakao;
script.onerror = () => {
console.error('[Kakao] SDK load failed');
};

document.head.appendChild(script);
}, []);

return null;
}
2 changes: 1 addition & 1 deletion src/shared/ui/modal/TeamRoomCreatedModal.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useNavigate } from 'react-router-dom';

import LinkCopyIcon from '@/shared/assets/icons/link-copy.svg?react';
import { copyText } from '@/shared/lib/copyText';
import { copyText } from '@/shared/lib/copy/copyText';
import ModalDim from '@/shared/ui/modal/ModalDim';

import { useModalStore } from './model/modal-store';
Expand Down
10 changes: 10 additions & 0 deletions src/vite-env.d.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,12 @@
/// <reference types="vite/client" />
/// <reference types="vite-plugin-svgr/client" />

interface Window {
Kakao?: {
init: (key: string) => void;
isInitialized: () => boolean;
Share: {
sendScrap: (options: { requestUrl: string; templateId?: number }) => void;
};
};
}
111 changes: 68 additions & 43 deletions src/widgets/teamroom/main/ui/AddMemberBottomSheet.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import { useCreateInviteLink } from '@/entities/teamroom/hooks/useTeamRoom';
import LinkCopyIcon from '@/shared/assets/icons/link-copy.svg?react';
// import KaKaoLinkIcon from '@/shared/assets/login/kakao.svg?react';
import KaKaoLinkIcon from '@/shared/assets/login/kakao.svg?react';
import { copyText } from '@/shared/lib/copy/copyText';
import { KakaoSdkLoader } from '@/shared/lib/kakao/KakaoSdkLoader';
import BottomSheet from '@/shared/ui/BottomSheet';

const KAKAO_TEMPLATE_ID: string = import.meta.env?.VITE_KAKAO_TEMPLATE_ID;

interface AddMemberBottomSheetProps {
isOpen: boolean;
onClose: () => void;
Expand Down Expand Up @@ -50,53 +54,74 @@ export default function AddMemberBottomSheet({
onClose,
teamRoomId,
}: AddMemberBottomSheetProps) {
const createInviteLinkMutation = useCreateInviteLink();
const { mutateAsync } = useCreateInviteLink();

const handleCopyLink = async () => {
try {
const token = await mutateAsync(teamRoomId);
const inviteUrl = `${window.location.origin}/invite?token=${token}`;

await copyText(inviteUrl);
alert('초대 링크가 복사되었습니다.');
} catch {
alert('초대 링크 생성에 실패했습니다.');
}
};

const handleCopyLink = () => {
createInviteLinkMutation.mutate(teamRoomId);
const handleKakaoShare = async () => {
Comment thread
jaqwe2301 marked this conversation as resolved.
Resolved
const token = await mutateAsync(teamRoomId);
const inviteUrl = `${window.location.origin}/invite?token=${token}`;

window.Kakao?.Share.sendScrap({
requestUrl: inviteUrl,
templateId: Number(KAKAO_TEMPLATE_ID),
});
};
Comment thread
jaqwe2301 marked this conversation as resolved.
Resolved
Comment thread
jaqwe2301 marked this conversation as resolved.
Resolved

return (
<BottomSheet
isOpen={isOpen}
onClose={onClose}
contentClassName="flex flex-col gap-[20px] px-6 pb-[30px]"
>
<div className="flex flex-col">
<button
onClick={onClose}
className="h-10 w-10 self-end flex-center"
aria-label="모달 닫기"
>
<img
src="/assets/icons/cancel.svg"
width={16}
height={16}
alt=""
draggable="false"
/>
</button>
<h2 className="-mt-[10px] text-title-3 text-tx-default">
함께하고 있는 팀 멤버를 초대하세요
</h2>
</div>
<>
<KakaoSdkLoader />
<BottomSheet
isOpen={isOpen}
onClose={onClose}
contentClassName="flex flex-col gap-[20px] px-6 pb-[30px]"
>
<div className="flex flex-col">
<button
onClick={onClose}
className="h-10 w-10 self-end flex-center"
aria-label="모달 닫기"
>
<img
src="/assets/icons/cancel.svg"
width={16}
height={16}
alt=""
draggable="false"
/>
</button>
<h2 className="-mt-[10px] text-title-3 text-tx-default">
함께하고 있는 팀 멤버를 초대하세요
</h2>
</div>

<ShareButton
icon={
<LinkCopyIcon className="h-[26.67px] w-[26.67px] text-tx-default" />
}
iconBgColor="bg-bg-bt-disabled"
title="링크복사"
description="링크로 팀원과 공유하세요."
onClick={handleCopyLink}
/>
<ShareButton
icon={
<LinkCopyIcon className="h-[26.67px] w-[26.67px] text-tx-default" />
}
iconBgColor="bg-bg-bt-disabled"
title="링크복사"
description="링크로 팀원과 공유하세요."
onClick={handleCopyLink}
/>

{/* <ShareButton
icon={<KaKaoLinkIcon className="h-[33.778px] w-[32px]" />}
iconBgColor="bg-[#F7E115]"
title="카카오톡으로 보내기"
onClick={() => {}}
/> */}
</BottomSheet>
<ShareButton
icon={<KaKaoLinkIcon className="h-[33.778px] w-[32px]" />}
iconBgColor="bg-[#F7E115]"
title="카카오톡으로 보내기"
onClick={handleKakaoShare}
/>
</BottomSheet>
</>
);
}