Skip to content
6 changes: 4 additions & 2 deletions fundamentals/today-i-learned/src/api/graphql/discussions.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
// GitHub Discussions 관련 GraphQL 쿼리 정의

export const GET_DISCUSSIONS_QUERY = `
query GetDiscussions($owner: String!, $repo: String!, $first: Int!, $after: String) {
query GetDiscussions($owner: String!, $repo: String!, $first: Int!, $after: String, $categoryId: ID) {
repository(owner: $owner, name: $repo) {
discussions(
first: $first
after: $after
orderBy: { field: CREATED_AT, direction: DESC }
categoryId: $categoryId
) {
pageInfo {
hasNextPage
Expand Down Expand Up @@ -146,12 +147,13 @@ export const GET_REPOSITORY_INFO_QUERY = `
`;

export const GET_INFINITE_DISCUSSIONS_QUERY = `
query GetInfiniteDiscussions($owner: String!, $repo: String!, $first: Int!, $after: String, $orderBy: DiscussionOrder) {
query GetInfiniteDiscussions($owner: String!, $repo: String!, $first: Int!, $after: String, $orderBy: DiscussionOrder, $categoryId: ID) {
repository(owner: $owner, name: $repo) {
discussions(
first: $first
after: $after
orderBy: $orderBy
categoryId: $categoryId
) {
pageInfo {
hasNextPage
Expand Down
22 changes: 12 additions & 10 deletions fundamentals/today-i-learned/src/api/hooks/useDiscussions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
removeDiscussionReaction,
type DiscussionsApiParams
} from "@/api/remote/discussions";
import { CATEGORY_ID } from "@/constants";

// NOTE: 만약 쿼리 옵션으로 분리된다면 각각의 쿼리 옵션에서 인라인하기 (중앙 집권형 쿼리 키 x)
export const DISCUSSIONS_QUERY_KEYS = {
Expand All @@ -43,14 +44,14 @@ export const DISCUSSIONS_QUERY_KEYS = {
interface UseDiscussionsParams {
owner?: string;
repo?: string;
categoryName?: string;
categoryId?: string;
enabled?: boolean;
}

interface UseInfiniteDiscussionsParams {
owner?: string;
repo?: string;
categoryName?: string;
categoryId?: string;
pageSize?: number;
sortBy?: "latest" | "lastActivity" | "created" | "popularity";
filterBy?: {
Expand All @@ -62,18 +63,18 @@ interface UseInfiniteDiscussionsParams {
export function useAllDiscussionsWithFullData({
owner = ENV_CONFIG.GITHUB_OWNER,
repo = ENV_CONFIG.GITHUB_REPO,
categoryName = "Today I Learned",
categoryId = CATEGORY_ID.TODAY_I_LEARNED,
enabled = true
}: UseDiscussionsParams = {}) {
const { user } = useAuth();

return useQuery({
queryKey: DISCUSSIONS_QUERY_KEYS.list({ owner, repo, categoryName }),
queryKey: DISCUSSIONS_QUERY_KEYS.list({ owner, repo, categoryId }),
queryFn: () =>
fetchAllDiscussions({
owner,
repo,
categoryName,
categoryId,
accessToken: user?.accessToken
}),
enabled,
Expand All @@ -86,7 +87,7 @@ export function useAllDiscussionsWithFullData({
export function useInfiniteDiscussions({
owner = ENV_CONFIG.GITHUB_OWNER,
repo = ENV_CONFIG.GITHUB_REPO,
categoryName,
categoryId = CATEGORY_ID.TODAY_I_LEARNED,
pageSize = 5,
sortBy = "latest",
filterBy,
Expand All @@ -98,14 +99,15 @@ export function useInfiniteDiscussions({
queryKey: DISCUSSIONS_QUERY_KEYS.infinite({
owner,
repo,
categoryName,
categoryId,
sortBy,
filterBy
}),
queryFn: ({ pageParam }) =>
fetchInfiniteDiscussions({
owner,
repo,
categoryId,
first: pageSize,
after: pageParam,
sortBy,
Expand All @@ -125,7 +127,7 @@ export function useWeeklyTopDiscussions({
owner = ENV_CONFIG.GITHUB_OWNER,
repo = ENV_CONFIG.GITHUB_REPO,
limit
}: Omit<UseDiscussionsParams, "categoryName"> & { limit?: number } = {}) {
}: Omit<UseDiscussionsParams, "categoryId"> & { limit?: number } = {}) {
const { user } = useAuth();

return useSuspenseQuery({
Expand All @@ -148,7 +150,7 @@ export function useRepositoryInfo({
owner = ENV_CONFIG.GITHUB_OWNER,
repo = ENV_CONFIG.GITHUB_REPO,
enabled = true
}: Omit<UseDiscussionsParams, "categoryName"> = {}) {
}: Omit<UseDiscussionsParams, "categoryId"> = {}) {
const { user } = useAuth();

return useQuery({
Expand Down Expand Up @@ -217,7 +219,7 @@ export function useMyContributions({
owner = ENV_CONFIG.GITHUB_OWNER,
repo = ENV_CONFIG.GITHUB_REPO,
enabled = true
}: Omit<UseDiscussionsParams, "categoryName"> = {}) {
}: Omit<UseDiscussionsParams, "categoryId"> = {}) {
const { user } = useAuth();

return useQuery({
Expand Down
30 changes: 14 additions & 16 deletions fundamentals/today-i-learned/src/api/remote/discussions.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { graphqlRequest } from "@/api/client";
import { PAGE_SIZE } from "@/constants/github";
import { CATEGORY_ID } from "@/constants";
import {
GET_DISCUSSIONS_QUERY,
CREATE_DISCUSSION_MUTATION,
Expand Down Expand Up @@ -63,13 +64,14 @@ export interface CreatePostResponse extends GitHubDiscussion {}
export interface DiscussionsApiParams {
owner: string;
repo: string;
categoryName?: string;
categoryId?: string;
accessToken?: string;
}

export interface PaginatedDiscussionsParams extends DiscussionsApiParams {
first?: number;
after?: string | null;
categoryId?: string;
}

export interface CreateDiscussionParams {
Expand Down Expand Up @@ -115,6 +117,7 @@ export async function fetchDiscussionsPage({
repo,
first = PAGE_SIZE.DEFAULT,
after,
categoryId,
accessToken
}: PaginatedDiscussionsParams): Promise<{
discussions: GitHubDiscussion[];
Expand All @@ -125,7 +128,7 @@ export async function fetchDiscussionsPage({
}> {
const data = await graphqlRequest(
GET_DISCUSSIONS_QUERY,
{ owner, repo, first, after },
{ owner, repo, first, after, categoryId },
accessToken
);

Expand All @@ -151,7 +154,6 @@ export async function fetchDiscussionsPage({
export async function fetchAllDiscussions({
owner,
repo,
categoryName,
accessToken
}: DiscussionsApiParams): Promise<GitHubDiscussion[]> {
const allDiscussions: GitHubDiscussion[] = [];
Expand All @@ -165,17 +167,11 @@ export async function fetchAllDiscussions({
owner,
repo,
after: cursor,
categoryId: CATEGORY_ID.TODAY_I_LEARNED,
accessToken
});

// 클라이언트 사이드 카테고리 필터링
const filteredDiscussions = categoryName
? discussions.filter(
(discussion) => discussion.category?.name === categoryName
)
: discussions;

allDiscussions.push(...filteredDiscussions);
allDiscussions.push(...discussions);

hasNextPage = pageInfo.hasNextPage;
cursor = pageInfo.endCursor;
Expand All @@ -194,7 +190,7 @@ export async function fetchWeeklyTopDiscussions({
owner,
repo,
accessToken
}: Omit<DiscussionsApiParams, "categoryName">): Promise<GitHubDiscussion[]> {
}: Omit<DiscussionsApiParams, "categoryId">): Promise<GitHubDiscussion[]> {
const oneWeekAgo = new Date();
oneWeekAgo.setDate(oneWeekAgo.getDate() - 7);

Expand Down Expand Up @@ -244,7 +240,7 @@ export async function fetchRepositoryInfo({
owner,
repo,
accessToken
}: Omit<DiscussionsApiParams, "categoryName">): Promise<{
}: Omit<DiscussionsApiParams, "categoryId">): Promise<{
repositoryId: string;
categories: Array<{ id: string; name: string; description?: string }>;
}> {
Expand All @@ -270,13 +266,14 @@ export async function fetchRepositoryInfo({
export async function fetchInfiniteDiscussions({
owner,
repo,
categoryId = CATEGORY_ID.TODAY_I_LEARNED,
first = PAGE_SIZE.INFINITE_SCROLL,
after,
sortBy = "latest",
filterBy,
accessToken
}: InfiniteDiscussionsParams): Promise<DiscussionsResponse> {
// Search API를 사용해야 하는 경우: 라벨 필터링 또는 popularity 정렬
// 라벨 필터링이나 popularity 정렬이 필요한 경우 Search API 사용
if (filterBy?.label || sortBy === "popularity") {
const getSortQuery = (sort: string) => {
switch (sort) {
Expand Down Expand Up @@ -337,7 +334,8 @@ export async function fetchInfiniteDiscussions({
repo,
first,
after: after || null,
orderBy: getOrderBy(sortBy)
orderBy: getOrderBy(sortBy),
categoryId: CATEGORY_ID.TODAY_I_LEARNED
},
accessToken
);
Expand Down Expand Up @@ -368,7 +366,7 @@ export async function fetchMyContributions({
repo,
accessToken,
authorLogin
}: Omit<DiscussionsApiParams, "categoryName"> & {
}: Omit<DiscussionsApiParams, "categoryId"> & {
authorLogin: string;
}): Promise<ContributionData[]> {
const allContributions: ContributionData[] = [];
Expand Down
16 changes: 16 additions & 0 deletions fundamentals/today-i-learned/src/constants/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -167,3 +167,19 @@ export const STORAGE_KEYS = {
USER_PREFERENCES: "til-user-preferences",
DRAFT_POST: "til-draft-post"
} as const;

// === github discussions Category IDs ===
/**
* GitHub Discussion 카테고리 정보
*
* 카테고리 ID는 변경되지 않는 고정값입니다.
*
* 새로운 카테고리 추가 방법:
* 1. 개발 서버 실행: yarn dev
* 2. http://localhost:5173/today-i-learned/dev-tools/category-id 접속
* 3. 카테고리 목록에서 원하는 카테고리의 ID를 복사
* 4. 아래 객체에 새로운 항목 추가
*/
export const CATEGORY_ID = {
TODAY_I_LEARNED: "DIC_kwDONfHk5s4CuCWu"
} as const;
13 changes: 12 additions & 1 deletion fundamentals/today-i-learned/src/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import { TimelinePage } from "./pages/timeline/TimelinePage";
import { QueryProvider } from "./providers/QueryProvider.tsx";
import { ToastProvider } from "./contexts/ToastContext";
import { RootLayout } from "./components/shared/layout/RootLayout.tsx";
import { CategoryIdFinder } from "./pages/dev-tools/CategoryIdFinder";
import { isDevelopment } from "./utils/env.ts";

const router = createBrowserRouter(
[
Expand All @@ -36,7 +38,16 @@ const router = createBrowserRouter(
{
path: "post/:id",
element: <PostDetailPage />
}
},
// 개발 환경에서만 표시
...(isDevelopment()
? [
{
path: "dev-tools/category-id",
element: <CategoryIdFinder />
}
]
: [])
]
}
],
Expand Down
Loading