@@ -325,10 +324,28 @@ export function RealGithubInstallationPanel({
{githubRepositoriesQuery.isSuccess &&
connectedRepositories.length === 0 ? (
-
-
- 아직 팀 스페이스에 등록된 GitHub 저장소가 없어요.
-
+
+
+
+ 등록된 GitHub 저장소가 없어요.
+
+
+ {canManageGithubInstallation
+ ? "연동 설정에서 집계할 저장소를 선택하면 기여도가 표시돼요."
+ : "호스트가 연동 설정에서 집계할 저장소를 선택해야 해요."}
+
+
+ {canManageGithubInstallation ? (
+
+ ) : null}
) : null}
@@ -342,117 +359,258 @@ export function RealGithubInstallationPanel({
))}
-
-
-
-
-
- 저장소 설정
-
-
- GitHub App이 접근할 수 있는 저장소 중 집계할 대상을
- 선택해요.
-
-
-
handleGithubSubtabSelect("integration")}
+ type="button"
+ variant="outline"
>
- {canManageGithubInstallation ? "editable" : "read only"}
-
+
+ 연동 설정
+
+ }
+ description="연동 탭에서 GitHub App 설치와 저장소 선택을 마치면 저장소별 기여도가 표시돼요."
+ icon={GitPullRequest}
+ title="기여도를 보려면 GitHub 연동이 필요해요."
+ />
+ )
+ ) : null}
+
+ {selectedGithubSubtab === "weekly-summary" ? (
+
+ ) : null}
+
+ {selectedGithubSubtab === "integration" ? (
+
+
+
+
+
+
+
+ {showGithubPolicyNotice ?
: null}
+
+
+
+
+ TeamPo GitHub App
+
+
+ {githubStatus?.connected
+ ? "GitHub 조직이 팀 스페이스에 연결되어 있어요."
+ : "호스트가 GitHub App 설치를 시작할 수 있어요."}
+
+
+
- {canManageGithubInstallation ? (
-
- {availableGithubRepositoriesQuery.isLoading ? (
-
}
- message="선택 가능한 저장소를 불러오고 있어요."
- />
- ) : null}
-
- {availableGithubRepositoriesQuery.error ? (
-
- ) : null}
-
- {availableGithubRepositoriesQuery.isSuccess &&
- availableRepositories.length === 0 ? (
-
-
- GitHub App이 접근할 수 있는 저장소가 없어요.
-
-
- ) : null}
-
- {configurableRepositories.map((repository) => {
- const selected = selectedGithubRepositoryIdSet.has(
- repository.githubRepositoryId,
- );
- const available = availableGithubRepositoryIdSet.has(
- repository.githubRepositoryId,
- );
-
- return (
-
+
+
+
+ 저장소 설정
+
+
+ GitHub App이 접근할 수 있는 저장소 중 집계할 대상을
+ 선택해요.
+
+
+
+ {canManageGithubInstallation ? "editable" : "read only"}
+
+
+
+ {canManageGithubInstallation ? (
+
+ {availableGithubRepositoriesQuery.isLoading ? (
+
}
+ message="선택 가능한 저장소를 불러오고 있어요."
/>
- );
- })}
+ ) : null}
-
-
- {selectedGithubRepositoryIds.length}개 저장소 선택됨
-
-
+ );
+ })}
+
+
+
+ {selectedGithubRepositoryIds.length}개 저장소 선택됨
+
+
+
-
- ) : (
-
-
- 호스트만 GitHub 저장소 설정을 변경할 수 있어요.
-
-
- )}
-
+ ) : (
+
+
+ 호스트만 GitHub 저장소 설정을 변경할 수 있어요.
+
+
+ )}
+
+ ) : null}
) : null}
-
-
);
}
+function RealGithubSubtabList({
+ onSelectSubtab,
+ selectedSubtab,
+}: {
+ onSelectSubtab: (subtab: GithubSubtabId) => void;
+ selectedSubtab: GithubSubtabId;
+}) {
+ return (
+
+ {githubSubtabs.map(({ icon: Icon, id, label }) => {
+ const selected = selectedSubtab === id;
+
+ return (
+
+ );
+ })}
+
+ );
+}
+
+function RealGithubSubtabEmptyState({
+ action,
+ description,
+ icon: Icon,
+ title,
+}: {
+ action?: ReactNode;
+ description: string;
+ icon: LucideIcon;
+ title: string;
+}) {
+ return (
+
+
+
+
+
{title}
+
+ {description}
+
+ {action ?
{action}
: null}
+
+ );
+}
+
function RealGithubWeeklySummariesPanel({
isGithubConnected,
members,
diff --git a/src/features/team/lib/github-subtab-preview.ts b/src/features/team/lib/github-subtab-preview.ts
new file mode 100644
index 0000000..c1f45cc
--- /dev/null
+++ b/src/features/team/lib/github-subtab-preview.ts
@@ -0,0 +1,189 @@
+import type { MyProjectGroup } from "@/lib/types/project-group";
+import type {
+ GithubRepository,
+ GithubWeeklySummary,
+} from "@/lib/types/team-space";
+
+export const githubSubtabPreviewProjectGroup = {
+ currentUserId: 1,
+ members: [
+ {
+ admin: true,
+ groupRole: "HOST",
+ level: 3,
+ memberRole: "FRONTEND",
+ nickname: "queue_runner",
+ profileImage: "https://i.pravatar.cc/240?img=12",
+ temperature: 50,
+ userId: 1,
+ },
+ {
+ admin: false,
+ groupRole: "MEMBER",
+ level: 4,
+ memberRole: "BACKEND",
+ nickname: "api_builder",
+ profileImage: null,
+ temperature: 53,
+ userId: 2,
+ },
+ {
+ admin: false,
+ groupRole: "MEMBER",
+ level: 3,
+ memberRole: "FRONTEND",
+ nickname: "pixel_runner",
+ profileImage: null,
+ temperature: 49,
+ userId: 3,
+ },
+ ],
+ projectDescription:
+ "랜덤 팀 매칭 이후 팀이 바로 움직일 수 있도록 규칙과 체크리스트를 정리합니다.",
+ projectGroupId: 10,
+ projectMvp: "매칭 요청, 수락/거절, 팀 스페이스 홈, 첫 체크리스트 운영",
+ projectName: "Blue Sprint",
+ projectTitle: "Team-po 팀 운영 MVP",
+} satisfies MyProjectGroup;
+
+export const githubSubtabPreviewAvailableRepositories: GithubRepository[] = [
+ {
+ fullName: "team-po-labs/client",
+ githubRepositoryId: 100,
+ repoName: "client",
+ },
+ {
+ fullName: "team-po-labs/server",
+ githubRepositoryId: 200,
+ repoName: "server",
+ },
+ {
+ fullName: "team-po-labs/product-notes",
+ githubRepositoryId: 300,
+ repoName: "product-notes",
+ },
+];
+
+export const githubSubtabPreviewConnectedRepositories =
+ githubSubtabPreviewAvailableRepositories.slice(0, 2);
+
+export function createGithubSubtabPreviewContribution(
+ repository: GithubRepository,
+) {
+ const isServerRepository = repository.githubRepositoryId === 200;
+
+ return {
+ contributors: [
+ {
+ additions: isServerRepository ? 1240 : 860,
+ changedFiles: isServerRepository ? 42 : 34,
+ contributionScore: isServerRepository ? 55 : 40,
+ deletions: isServerRepository ? 310 : 190,
+ githubUserId: isServerRepository ? 503 : 501,
+ githubUsername: isServerRepository ? "server-runner" : "dev-a",
+ linkedIssueCount: isServerRepository ? 3 : 2,
+ mergedPrCount: isServerRepository ? 4 : 3,
+ userId: 1,
+ },
+ {
+ additions: 420,
+ changedFiles: 18,
+ contributionScore: 25,
+ deletions: 80,
+ githubUserId: 502,
+ githubUsername: "dev-b",
+ linkedIssueCount: 1,
+ mergedPrCount: 2,
+ userId: 2,
+ },
+ ],
+ fullName: repository.fullName,
+ githubRepositoryId: repository.githubRepositoryId,
+ repoName: repository.repoName,
+ };
+}
+
+export const githubSubtabPreviewWeeklySummaries: Record<
+ number,
+ GithubWeeklySummary
+> = {
+ 1: {
+ periodEnd: "2026-06-16T14:59:59.000Z",
+ periodStart: "2026-06-10T15:00:00.000Z",
+ sourceIssueCount: 4,
+ sourcePrCount: 7,
+ summary: {
+ followUpSuggestions: [
+ "주간 요약 상세 API 응답의 빈 상태를 한 번 더 점검하기",
+ "GitHub App 설치 완료 후 첫 동기화 안내 문구 정리하기",
+ ],
+ issueHighlights: [
+ "팀 스페이스 GitHub 운영 탭 정보 구조 개선",
+ "주간 요약 상세 조회 API 연결",
+ ],
+ mainActivities: [
+ "GitHub 탭을 기여도, 주간 요약, 연동으로 분리",
+ "저장소별 PR 기여도 카드의 정보 밀도 조정",
+ "리뷰 피드백 반영을 위한 프리뷰 라우트 구성",
+ ],
+ pullRequestHighlights: [
+ "feat(team): add github weekly summary detail api",
+ "feat(team): add github panel subtabs",
+ ],
+ summary:
+ "GitHub 운영 화면의 정보 구조를 정리하고, 주간 요약 API와 프리뷰 흐름을 연결했어요.",
+ },
+ weeklyGithubSummaryId: 4101,
+ },
+ 2: {
+ periodEnd: "2026-06-16T14:59:59.000Z",
+ periodStart: "2026-06-10T15:00:00.000Z",
+ sourceIssueCount: 2,
+ sourcePrCount: 4,
+ summary: {
+ followUpSuggestions: [
+ "서버 OpenAPI 변경분과 FE 타입 이름 맞추기",
+ "권한 오류 응답 메시지 케이스 추가 확인하기",
+ ],
+ issueHighlights: [
+ "GitHub weekly summary endpoint 검토",
+ "팀 스페이스 저장소 목록 동기화 확인",
+ ],
+ mainActivities: [
+ "GitHub summary API 계약을 점검",
+ "저장소 연결 상태와 집계 대상 응답을 검증",
+ ],
+ pullRequestHighlights: [
+ "feat(team): expose weekly github summaries",
+ "fix(team): align repository sync response",
+ ],
+ summary:
+ "GitHub 요약과 저장소 연동 API 계약을 맞추고, FE에서 사용할 응답 형태를 정리했어요.",
+ },
+ weeklyGithubSummaryId: 4102,
+ },
+ 3: {
+ periodEnd: "2026-06-16T14:59:59.000Z",
+ periodStart: "2026-06-10T15:00:00.000Z",
+ sourceIssueCount: 1,
+ sourcePrCount: 3,
+ summary: {
+ followUpSuggestions: [
+ "모바일에서 서브탭 전환 간격 확인하기",
+ "기여도 카드 숫자 포맷을 실제 데이터로 다시 점검하기",
+ ],
+ issueHighlights: ["GitHub 탭 과밀도 개선", "로그인 없는 UI 프리뷰 요청"],
+ mainActivities: [
+ "GitHub 내부 서브탭 상호작용을 점검",
+ "프리뷰 화면의 fixture 데이터를 보강",
+ ],
+ pullRequestHighlights: [
+ "feat(team): add github panel subtabs",
+ "fix(team): stabilize github preview route",
+ ],
+ summary:
+ "GitHub 화면을 더 빠르게 훑어볼 수 있도록 탭 구조와 프리뷰 상태를 다듬었어요.",
+ },
+ weeklyGithubSummaryId: 4103,
+ },
+};
diff --git a/src/pages/github-subtabs-preview-page.tsx b/src/pages/github-subtabs-preview-page.tsx
new file mode 100644
index 0000000..0dc681f
--- /dev/null
+++ b/src/pages/github-subtabs-preview-page.tsx
@@ -0,0 +1,24 @@
+import { GithubSubtabsPreviewPanel } from "@/features/team/components/github-subtabs-preview-panel";
+
+export function GithubSubtabsPreviewPage() {
+ return (
+
+
+
+
+ Preview
+
+
+ GitHub 탭 세부 보기
+
+
+ 로그인 없이 GitHub 내부 탭 구조와 각 상태를 확인하는 미리보기
+ 화면입니다.
+
+
+
+
+
+
+ );
+}