Skip to content

[REFACTOR] 템플릿 데이터를 API에서 패칭하도록 수정#426

Merged
i-meant-to-be merged 14 commits intodevelopfrom
refactor/#425
Mar 9, 2026
Merged

[REFACTOR] 템플릿 데이터를 API에서 패칭하도록 수정#426
i-meant-to-be merged 14 commits intodevelopfrom
refactor/#425

Conversation

@i-meant-to-be
Copy link
Contributor

@i-meant-to-be i-meant-to-be commented Feb 25, 2026

🚩 연관 이슈

closed #425

📝 작업 내용

커찬이 작업해 준 기관별 템플릿 API를 구현 및 랜딩 페이지에 적용했어요.

세부 작업 내역

  • 기관별 템플릿 API 사용을 위한 네트워킹 코드 구현 (API 요청, 응답 양식(response body), msw 모방 데이터 등)
  • 랜딩 페이지가 API로 기관별 템플릿을 불러오도록 수정
  • 기존에 사용하던 템플릿 상수 등 불필요한 파일 삭제
  • API 도입에 따라 기존에 사용하던 일부 타입들 변경
  • 새로 추가된 텍스트 문장 1건에 대해 다국어 번역 테이블 갱신

3월 3일 화요일 추가

  • 이제 더 이상 사용하지 않는 기관별 아이콘을 FE에서 모두 삭제 (정부 아이콘만 제외)
  • msw가 정적 이미지 에셋인 템플릿 아이콘에 대한 요청을 가로채도록 핸들러 추가 (BASE_URL/icon/ICON_FILE_NAME의 형태)

🏞️ 스크린샷 (선택)

없음

🗣️ 리뷰 요구사항 (선택)

잘 동작하는지 한 번 랜딩 페이지 열어서 확인해주시면 감사하겠습니다! (참고로 PR 올리는 현 시점 기준으로는 중선관위 사진은 안 보이는 게 정상입니다.)

Summary by CodeRabbit

  • New Features

    • 템플릿이 조직별 데이터로 동적으로 로드되어 조직명·제휴사·아이콘과 함께 그룹별로 표시됩니다.
    • 로딩 상태 표시기와 로드 실패 시 사용자용 오류 UI가 추가되었습니다.
    • 템플릿 공유 URL 생성 방식이 개선되어 공유 경험이 더 일관적입니다.
  • Localization

    • 영어·한국어에 로딩 및 실패 관련 문구가 추가되었습니다.

@i-meant-to-be i-meant-to-be requested a review from useon February 25, 2026 09:22
@i-meant-to-be i-meant-to-be self-assigned this Feb 25, 2026
@i-meant-to-be i-meant-to-be added the refactor 기능 변경 없이 코드만 변경했을 경우 label Feb 25, 2026
@coderabbitai
Copy link

coderabbitai bot commented Feb 25, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 17b9460 and 53214bb.

📒 Files selected for processing (2)
  • src/util/arrayEncoding.test.ts
  • src/util/arrayEncoding.ts

Walkthrough

하드코딩된 DEBATE_TEMPLATE을 제거하고 조직 기반 템플릿 API/타입/훅을 추가했으며 LandingPage 컴포넌트들을 Organization 타입으로 리팩토링하고 MSW 모킹(템플릿·정적 아이콘) 및 공유 URL 유틸 명칭 변경과 로컬라이제이션 문자열을 추가했습니다.

Changes

Cohort / File(s) Summary
API 엔드포인트 및 클라이언트
src/apis/endpoints.ts, src/apis/apis/organization.ts
ApiUrl.organization 추가 및 getOrganizationTemplates() GET 클라이언트 함수 추가.
API 응답 타입
src/apis/responses/organization.ts
GetOrganizationTemplatesResponseType(organizations: Organization[]) 인터페이스 추가.
React Query 훅
src/hooks/query/useGetOrganizationTemplates.ts
useGetOrganizationTemplates 훅 추가(react-query, enabled 옵션, throwOnError: false).
타입 정의 변경
src/type/type.ts
기존 Action/old DebateTemplate 삭제, 새 DebateTemplate { name, data }Organization { organization, affiliation, iconPath, templates } 타입 추가.
하드코딩 템플릿 제거
src/constants/debate_template.ts
DEBATE_TEMPLATE 및 관련 함수/인터페이스 전부 제거.
LandingPage 컴포넌트 리팩토링
src/page/LandingPage/components/TemplateCard.tsx, src/page/LandingPage/components/TemplateList.tsx, src/page/LandingPage/components/TemplateSelection.tsx
컴포넌트 props를 Organization 기반으로 변경, API 데이터 페칭 통합(로딩/에러 처리), TemplateList 사용법 변경, 공유 URL 생성 호출 업데이트.
공유 URL 유틸 변경
src/util/arrayEncoding.ts, src/util/arrayEncoding.test.ts, src/hooks/useTableShare.tsx, src/page/LandingPage/hooks/useLandingPageHandlers.ts, src/components/ShareModal/ShareModal.stories.tsx
createTableShareUrlcreateTableShareUrlFromTable로 리네임, createTableShareUrlFromEncodedData 신규 추가 및 호출 위치 업데이트.
MSW 모킹
src/mocks/handlers/organization.ts, src/mocks/handlers/static_asset.ts, src/mocks/handlers/global.ts
조직 템플릿 핸들러와 정적 아이콘 핸들러 추가 후 allHandlers에 통합.
런타임 로깅 조정
src/main.tsx
MSW 미처리 요청 로깅에서 /icon 경로 예외 조건 추가(조건 변경).
로컬라이제이션
public/locales/en/translation.json, public/locales/ko/translation.json
템플릿 로딩 및 실패 메시지(한/영) 추가, ko 파일의 불필요 공백 제거.

Sequence Diagram(s)

sequenceDiagram
    actor User
    participant Landing as "LandingPage\n(Component)"
    participant Selection as "TemplateSelection\n(Component)"
    participant Hook as "useGetOrganizationTemplates\n(Hook)"
    participant API as "getOrganizationTemplates\n(Client)"
    participant Backend as "Backend\n(API Server)"

    User->>Landing: 방문
    Landing->>Selection: 렌더
    Selection->>Hook: 훅 실행 (enabled)
    Hook->>API: getOrganizationTemplates()
    API->>Backend: GET /organizations/templates
    Backend-->>API: organizations 응답
    API-->>Hook: 응답 전달
    Hook-->>Selection: 데이터/로딩/에러 상태
    Selection->>Selection: organizations 필터링 및 TemplateList/TemplateCard 렌더링
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • jaeml06
  • useon

Poem

🐰 폴짝 템플릿 불러왔네,
API 당근 하나 톡,
하드코딩은 안녕이라,
조직별로 반짝 모여,
페이지에 봄이 왔네 🌱

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 10.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed PR 제목이 주요 변경사항을 명확하게 요약하고 있습니다. 템플릿 데이터를 하드코딩된 상수에서 API 기반으로 변경하는 리팩토링이 핵심 변경입니다.
Linked Issues check ✅ Passed PR의 모든 변경사항이 연결된 이슈 #425의 요구사항을 충족합니다. 템플릿 데이터 API 기반 코드 준비와 API 연결이 완료되었습니다.
Out of Scope Changes check ✅ Passed PR의 모든 변경사항이 템플릿 API 기반으로의 리팩토링과 직접 관련되어 있으며, 범위를 벗어난 변경사항은 없습니다.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch refactor/#425

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.

@gemini-code-assist
Copy link

Summary of Changes

Hello @i-meant-to-be, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

이 PR은 랜딩 페이지에서 토론 템플릿을 불러오는 방식을 근본적으로 개선합니다. 기존에는 하드코딩된 상수 데이터를 사용했지만, 이제는 백엔드 API를 통해 기관별 템플릿 정보를 동적으로 가져와 표시합니다. 이는 데이터의 유연성을 높이고, 새로운 템플릿 추가 및 관리를 용이하게 하며, 사용자에게 최신 정보를 제공할 수 있도록 합니다.

Highlights

  • API 연동: 템플릿 데이터를 기존의 정적 상수에서 API를 통해 동적으로 불러오도록 변경했습니다.
  • 랜딩 페이지 업데이트: 랜딩 페이지의 템플릿 목록이 새로운 API에서 가져온 데이터를 기반으로 렌더링되도록 수정했습니다.
  • 불필요한 파일 제거: API 도입에 따라 더 이상 사용되지 않는 템플릿 관련 상수 파일(debate_template.ts)을 삭제했습니다.
  • 타입 정의 변경: API 응답 구조에 맞춰 템플릿 및 기관 관련 타입 정의를 업데이트했습니다.
  • 다국어 지원 추가: 새로 추가된 로딩 메시지에 대한 다국어 번역을 추가했습니다.
  • MSW 모킹 구현: 개발 환경에서 템플릿 API 호출을 모킹하기 위한 MSW 핸들러를 추가했습니다.
Changelog
  • public/locales/en/translation.json
    • Added a new translation key for 'Loading templates...'.
  • public/locales/ko/translation.json
    • Added a new translation key for '템플릿을 불러오는 중입니다...'.
  • src/apis/apis/organization.ts
    • Added a new API function getOrganizationTemplates to fetch organization-specific templates.
  • src/apis/endpoints.ts
    • Added a new organization endpoint to the API URL configuration.
  • src/apis/responses/organization.ts
    • Defined the GetOrganizationTemplatesResponseType interface for the organization templates API response.
  • src/constants/debate_template.ts
    • Removed the entire file containing static debate template data.
  • src/hooks/query/useGetOrganizationTemplates.ts
    • Added a new React Query hook useGetOrganizationTemplates for asynchronous fetching and caching of organization templates.
  • src/mocks/handlers/global.ts
    • Imported organizationHandlers and included them in the global MSW handlers array.
  • src/mocks/handlers/organization.ts
    • Added new MSW handlers to mock the GET request for /api/organizations/templates, providing sample organization and template data.
  • src/page/LandingPage/components/TemplateCard.tsx
    • Updated component props to accept an Organization object instead of individual template properties.
    • Modified to display organization name, affiliation, and logo dynamically from the organization prop, with logo paths constructed using VITE_API_BASE_URL.
    • Changed template actions to iterate over organization.templates and generate share URLs using a new createTableShareUrl helper function.
    • Relocated createTableShareUrl helper function from debate_template.ts to this file.
  • src/page/LandingPage/components/TemplateList.tsx
    • Updated component props to accept an array of Organization objects.
    • Modified to render TemplateCard components using the new organization prop structure.
  • src/page/LandingPage/components/TemplateSelection.tsx
    • Removed the import of DEBATE_TEMPLATE static data.
    • Integrated useGetOrganizationTemplates hook to fetch template data from the API.
    • Implemented conditional rendering to display a loading spinner and message while templates are being fetched.
    • Modified TemplateList components to receive dynamically fetched and filtered organization data.
  • src/type/type.ts
    • Modified the DebateTemplate type to include name and data fields.
    • Added a new Organization type to define the structure of organization-specific templates, including organization, affiliation, iconPath, and an array of DebateTemplates.
Activity
  • 기관별 템플릿 API 사용을 위한 네트워킹 코드를 구현했습니다 (API 요청, 응답 양식, msw 모방 데이터 등).
  • 랜딩 페이지가 API로 기관별 템플릿을 불러오도록 수정했습니다.
  • 기존에 사용하던 템플릿 상수 등 불필요한 파일을 삭제했습니다.
  • API 도입에 따라 기존에 사용하던 일부 타입들을 변경했습니다.
  • 새로 추가된 텍스트 문장 1건에 대해 다국어 번역 테이블을 갱신했습니다.
  • 리뷰 요청: 랜딩 페이지가 잘 동작하는지 확인 부탁드립니다. (현재 중선관위 사진은 보이지 않는 것이 정상입니다.)
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@github-actions
Copy link

github-actions bot commented Feb 25, 2026

🚀 Preview 배포 완료!

환경 URL
Preview 열기
API Dev 환경

PR이 닫히면 자동으로 정리됩니다.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

안녕하세요. 템플릿 데이터를 하드코딩된 상수에서 API를 통해 가져오도록 리팩터링한 점이 인상 깊습니다. API 연동을 위한 네트워킹 코드, react-query 훅, MSW 목 핸들러까지 꼼꼼하게 구현해주셨네요. 전반적으로 좋은 방향의 개선이지만, 코드 리뷰 중 몇 가지 중요한 문제를 발견했습니다. TemplateSelection.tsx 파일에서 API 응답에 따라 애플리케이션이 중단될 수 있는 치명적인 오류가 있으며, TemplateCard.tsx에서는 공유 URL 생성 로직에 문제가 있어 특정 배포 환경에서 기능이 오작동할 수 있습니다. 자세한 내용은 아래 리뷰 코멘트를 확인해주세요.

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: 5

🧹 Nitpick comments (3)
src/mocks/handlers/organization.ts (1)

7-40: Mock 응답은 타입 고정 + 중복 데이터 상수화가 좋겠습니다.

현재는 대형 리터럴/중복 문자열 때문에 스키마 변경 시 누락 위험이 큽니다. 응답 객체를 명시 타입으로 고정하고 공통 payload를 상수로 추출해 주세요.

♻️ 제안 코드
 import { http, HttpResponse } from 'msw';
 import { ApiUrl } from '../../apis/endpoints';
+import type { GetOrganizationTemplatesResponseType } from '../../apis/responses/organization';
+
+const TEMPLATE_DATA =
+  'eJyrVspMUbIytjDXUcrMS8tXsqpWykvMTVWyUjJWKCtWMFZ427b1TXPj27YFrxcueN3T8HZWj8LbGVPfdM9V0lEqqSwAqXQODQ7x9%2FWMcgUKJaan5qUkAgWB7IKi%2FOKQ1MRcP4iBbzasedOyESienJ%2BHLP56wwygwUDx8sSivMy8dKfUnBwlq7TEnOJUHaW0zLzM4gwkoVqgtYlJOUCN0dVKxSWJeckgMwKC%2FIOBJhQXpKYmZ4RAnPVmXivQzUDRpPwKqJCff5Cvow%2FI5Zkgqw2NDICyYLPzSnNyIMIBqUUgx6EJBRekJmYDHQcTLgbxU4sg3FodJKc4%2B%2FsNFqf4uYaGBIEtQXPNhDdzFkCiFMVNIZ6%2BrvFOjsGuLnB3QazA6TBzkLMx3AX2DIkhtHXOm0WtCq83zHkzbQfdAwpr8qG7i2JrAbdLRw0%3D';
+
+const organizationTemplatesMock: GetOrganizationTemplatesResponseType = {
+  organizations: [
+    // ...기존 organizations 구조 유지, data는 TEMPLATE_DATA 재사용
+  ],
+};

 export const organizationHandlers = [
   // GET /api/organizations/templates
   http.get(ApiUrl.organization + '/templates', () => {
-    return HttpResponse.json({
-      organizations: [
-        // ...
-      ],
-    });
+    return HttpResponse.json(organizationTemplatesMock);
   }),
 ];
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/mocks/handlers/organization.ts` around lines 7 - 40, The mock response
uses large inline literals and duplicated template strings; create a typed
response shape (e.g., OrganizationResponse / Organization / Template types) and
extract the repeating template payload string into a shared constant (e.g.,
TEMPLATE_DATA) and reuse it in a single ORGANIZATIONS constant, then return
HttpResponse.json({ organizations: ORGANIZATIONS }); update any handler function
that currently builds the inline object to import/use these constants and the
typed response so the mock is both type-safe and avoids duplication (refer to
the organizations field, templates[].data and HttpResponse.json in the diff).
src/page/LandingPage/components/TemplateCard.tsx (1)

49-50: key에 index 사용은 괜찮으나, template.name이 고유하다면 index 없이도 충분합니다.

만약 같은 organization 내에서 template.name이 중복될 수 있다면 현재 방식이 적절합니다. 다만 API에서 고유한 id가 내려온다면 그것을 사용하는 것이 더 안정적입니다.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/page/LandingPage/components/TemplateCard.tsx` around lines 49 - 50, 현재
TemplateCard.tsx의 organization.templates.map(...)에서 리스트 항목 key를
key={`${template.name}-${index}`}로 설정하고 있는데, 만약 template.name이 고유하다면 index를 제거하고
key={template.name}으로 단순화하세요; 반대로 API가 template.id를 제공한다면 더 안정적인 key인
template.id를 사용하도록 organization.templates.map(...) 내부의 key 할당을 template.id로
바꾸세요.
src/page/LandingPage/components/TemplateSelection.tsx (1)

26-26: 필터 결과가 비어있을 때도 구분선이 항상 표시됩니다.

특정 templates.length 그룹에 해당하는 organization이 없으면 빈 TemplateList와 구분선만 렌더링됩니다. 필터 결과가 비어있을 때 해당 섹션과 구분선을 숨기는 것을 고려해 주세요.

Also applies to: 32-33

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/page/LandingPage/components/TemplateSelection.tsx` at line 26, The
divider <div className="mx-auto h-px w-11/12 bg-neutral-200" /> in
TemplateSelection is being rendered even when a group's filtered templates are
empty; update the JSX so that both the TemplateList component and its following
divider are rendered only when the group's templates array (e.g., templates or
filteredTemplates for that group) has length > 0. Locate the group rendering
logic inside TemplateSelection (where TemplateList is used) and wrap both the
<TemplateList ... /> and the divider in a single conditional (templates.length >
0 or filteredTemplates.length > 0); apply the same change to the other divider
occurrence referenced (lines 32–33) so empty groups render nothing.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/page/LandingPage/components/TemplateCard.tsx`:
- Line 15: The current logoUrl construction can produce double slashes or the
string "undefined/..." if the env var or icon path are missing; update the
logoUrl creation (the const logoUrl line) to: normalize VITE_API_BASE_URL and
organization.iconPath first (treat import.meta.env.VITE_API_BASE_URL as empty
string if undefined and organization.iconPath as empty string if undefined),
trim trailing slashes from the base and leading slashes from the path, then join
them with a single '/' so you never produce '//' or 'undefined/...'. Use the
existing symbols VITE_API_BASE_URL, organization.iconPath and logoUrl to locate
and replace the logic.
- Around line 71-75: The createTableShareUrl function omits VITE_BASE_PATH so
share links break when the app is served from a subpath; update
createTableShareUrl to read import.meta.env.VITE_BASE_PATH (or default to '')
and join it with the existing base URL (normalizedBaseUrl) ensuring there is
exactly one slash between base URL and base path before appending
/share?data=...; modify the function that currently named createTableShareUrl to
incorporate VITE_BASE_PATH normalization and concatenation so generated URLs
include the configured base path.

In `@src/page/LandingPage/components/TemplateList.tsx`:
- Around line 13-17: The map in TemplateList.tsx uses organization.organization
as the TemplateCard key which can collide; update the key in the
organizations.map(...) that renders <TemplateCard .../> to a stable composite
key using both organization.organization and organization.affiliation (e.g.
interpolate both values into the key) so keys are unique across items; also note
and consider requesting a unique id from the API for TemplateCard props (or use
that id when available) to further guarantee uniqueness.

In `@src/page/LandingPage/components/TemplateSelection.tsx`:
- Line 9: The hook call currently only reads data from
useGetOrganizationTemplates causing a permanent spinner when the API fails;
update the hook destructure to also get isLoading and isError (e.g., const {
data, isLoading, isError } = useGetOrganizationTemplates()) and change the
render logic to: if (isLoading) show the loading spinner, else if (isError)
render an error message or retry UI, otherwise render the templates using data;
also update the rendering block that maps data (lines ~41-52) to guard on
!isError && !isLoading && Array.isArray(data) before mapping.
- Around line 18-39: The current TemplateSelection uses direct indexing into
data.organizations (e.g., data.organizations[0], [1], [2]) for the key which
will crash if fewer than 3 organizations are returned and also misaligns keys
with the filtered lists; fix by computing each filtered list once (e.g.,
templatesOne = data.organizations.filter(org => org.templates.length === 1),
templatesTwo = ..., templatesThree = ...), only render a TemplateList for a
section if its filtered array is non-empty, and derive the key from the filtered
data (for example a stable identifier from the first item or a concatenation of
the filtered organizations' ids/names) instead of hardcoded indices; update
TemplateList props to use these filtered arrays and remove any direct
data.organizations[index] references in the key.

---

Nitpick comments:
In `@src/mocks/handlers/organization.ts`:
- Around line 7-40: The mock response uses large inline literals and duplicated
template strings; create a typed response shape (e.g., OrganizationResponse /
Organization / Template types) and extract the repeating template payload string
into a shared constant (e.g., TEMPLATE_DATA) and reuse it in a single
ORGANIZATIONS constant, then return HttpResponse.json({ organizations:
ORGANIZATIONS }); update any handler function that currently builds the inline
object to import/use these constants and the typed response so the mock is both
type-safe and avoids duplication (refer to the organizations field,
templates[].data and HttpResponse.json in the diff).

In `@src/page/LandingPage/components/TemplateCard.tsx`:
- Around line 49-50: 현재 TemplateCard.tsx의 organization.templates.map(...)에서 리스트
항목 key를 key={`${template.name}-${index}`}로 설정하고 있는데, 만약 template.name이 고유하다면
index를 제거하고 key={template.name}으로 단순화하세요; 반대로 API가 template.id를 제공한다면 더 안정적인
key인 template.id를 사용하도록 organization.templates.map(...) 내부의 key 할당을 template.id로
바꾸세요.

In `@src/page/LandingPage/components/TemplateSelection.tsx`:
- Line 26: The divider <div className="mx-auto h-px w-11/12 bg-neutral-200" />
in TemplateSelection is being rendered even when a group's filtered templates
are empty; update the JSX so that both the TemplateList component and its
following divider are rendered only when the group's templates array (e.g.,
templates or filteredTemplates for that group) has length > 0. Locate the group
rendering logic inside TemplateSelection (where TemplateList is used) and wrap
both the <TemplateList ... /> and the divider in a single conditional
(templates.length > 0 or filteredTemplates.length > 0); apply the same change to
the other divider occurrence referenced (lines 32–33) so empty groups render
nothing.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d25b2d5 and d1e7b6e.

📒 Files selected for processing (13)
  • public/locales/en/translation.json
  • public/locales/ko/translation.json
  • src/apis/apis/organization.ts
  • src/apis/endpoints.ts
  • src/apis/responses/organization.ts
  • src/constants/debate_template.ts
  • src/hooks/query/useGetOrganizationTemplates.ts
  • src/mocks/handlers/global.ts
  • src/mocks/handlers/organization.ts
  • src/page/LandingPage/components/TemplateCard.tsx
  • src/page/LandingPage/components/TemplateList.tsx
  • src/page/LandingPage/components/TemplateSelection.tsx
  • src/type/type.ts
💤 Files with no reviewable changes (1)
  • src/constants/debate_template.ts

Copy link
Contributor

@useon useon left a comment

Choose a reason for hiding this comment

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

숀 ~!! 템플릿 데이터를 api를 통해 페칭하도록 수정된 것 확인했습니다!!! 코멘트 조금 달았는데 확인해 주시면 감사하겠습니다 ^_^!!!

Comment on lines +71 to +76
function createTableShareUrl(encodeData: string): string {
const baseUrl = import.meta.env.VITE_SHARE_BASE_URL || window.location.origin;
const normalizedBaseUrl = baseUrl.replace(/\/+$/, '');
const basePath = import.meta.env.VITE_BASE_PATH;
const pathPrefix = basePath && basePath !== '/' ? basePath : '';
return `${normalizedBaseUrl}${pathPrefix}/share?data=${encodeData}`;
Copy link
Contributor

Choose a reason for hiding this comment

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

src/util/arrayEncoding.ts에 있는 같은 이름의 살짝 다른 역할을 하는 함수가 있어요!

export function createTableShareUrl(
  baseUrl: string | undefined,
  data: DebateTableData,
): string {
  const encoded = encodeDebateTableData(data);
  const resolvedBaseUrl =
    baseUrl && baseUrl.trim() !== '' ? baseUrl : window.location.origin;
  const normalizedBaseUrl = resolvedBaseUrl.replace(/\/+$/, '');
  const basePath = import.meta.env.VITE_BASE_PATH;
  const pathPrefix = basePath && basePath !== '/' ? basePath : '';
  return `${normalizedBaseUrl}${pathPrefix}/share?data=${encoded}`;
}

해당 함수와 이름은 같지만 살짝 다른 차이가 존재하는 것 같네요.
이미 인코딩 되어 있는 것을 그대로 붙이거나 아니면 인코딩이 필요하기 때문에 인코딩 처리를 하고 난 다음에 붙이는 차이인 것 같아요.

같은 곳에서 함께 관리하고 사용처에서 불러와 사용하는 방식은 어떨까요?
현재 두 함수의 이름이 같으니까 쓰임에 따라

  1. createTableShareUrlFromData(baseUrl, data):
    DebateTableData를 받아 내부에서 인코딩 후 URL 생성
  2. createTableShareUrlFromEncodedData(baseUrl, encodedData):
    이미 인코딩된 문자열을 받아 URL만 조립
    요런 식으로 수정해 볼 수도 있겠네요!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

그러네요. 두 함수 응집도가 상당한 편이네요. 의견 남겨주신 대로 두 함수를 다른 이름으로 분리했구요, 두 함수의 응집도가 상당한 만큼 원래는 TemplateCard.tsx에 있었던 함수 본문 역시 arrayEncoding.ts 파일에 함께 합쳐 두었습니다. 좋은 의견 감삼다 🔥

{
organization: '한앎',
affiliation: '한양대',
iconPath: '/icons/icon1.png',
Copy link
Contributor

Choose a reason for hiding this comment

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

mock 상이라 임의 확인을 위해서 iconPath도 임의로 작성된 것이죠??

Copy link
Contributor Author

Choose a reason for hiding this comment

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

원래는 말씀하신 것처럼 대충 확인하려는 생각에 간단히 작성했는데요. 코드 추가하는 게 그렇게 큰 작업은 아닐 것 같아 정적 에셋(정확히는 템플릿 아이콘에 대한 요청만)에 대한 요청도 모방하도록 msw 핸들러를 개선해 두었습니다.

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: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/main.tsx (1)

19-28: ⚠️ Potential issue | 🟡 Minor

Dismissed 로그와 실제 동작이 불일치합니다.

현재는 비 /api·/icon 요청도 결국 print.warning()이 실행되어, 실제로 dismiss되지 않습니다. 의도대로 무시하려면 early return이 필요합니다.

수정 예시
         onUnhandledRequest: (request, print) => {
-          // Let worker dismiss non-api calls by check whether url includes '/api'
-          if (!request.url.includes('/api') && !request.url.includes('/icon')) {
-            console.log(
-              "Dismissed request that doesn't include /api/: " + request.url,
-            );
-          }
-
-          print.warning();
+          const { pathname } = new URL(request.url);
+          if (!pathname.includes('/api') && !pathname.includes('/icon')) {
+            return;
+          }
+          print.warning();
         },
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main.tsx` around lines 19 - 28, The onUnhandledRequest handler currently
logs non-/api and non-/icon requests but still calls print.warning(), so they
are not actually dismissed; update the onUnhandledRequest function to
early-return after the console.log for requests where
!request.url.includes('/api') && !request.url.includes('/icon') so that
print.warning() is not executed for those dismissed requests (i.e., keep the
existing condition, the console.log call, then return from the handler to skip
calling print.warning()).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/mocks/handlers/static_asset.ts`:
- Around line 7-29: The handler currently ignores params.iconFileName and always
returns sampleLogo; update the http.get handler to validate and map iconFileName
to a known set of local assets (e.g., a lookup map keyed by iconFileName) and
return a 404 HttpResponse when there is no match, and when fetching the mapped
asset check the fetch response (response.ok) before calling arrayBuffer — if
fetch returns non-ok, log the response status and return a 502/500 HttpResponse;
keep using HttpResponse.arrayBuffer with Content-Type and Cache-Control for
successful responses and ensure errors fall through to the catch path that
returns an appropriate error status.

---

Outside diff comments:
In `@src/main.tsx`:
- Around line 19-28: The onUnhandledRequest handler currently logs non-/api and
non-/icon requests but still calls print.warning(), so they are not actually
dismissed; update the onUnhandledRequest function to early-return after the
console.log for requests where !request.url.includes('/api') &&
!request.url.includes('/icon') so that print.warning() is not executed for those
dismissed requests (i.e., keep the existing condition, the console.log call,
then return from the handler to skip calling print.warning()).

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between db05b23 and 86b8065.

⛔ Files ignored due to path filters (13)
  • src/assets/template_logo/han_alm.png is excluded by !**/*.png
  • src/assets/template_logo/hantomak.png is excluded by !**/*.png
  • src/assets/template_logo/igam.png is excluded by !**/*.png
  • src/assets/template_logo/jungseonto.png is excluded by !**/*.png
  • src/assets/template_logo/kogito.png is excluded by !**/*.png
  • src/assets/template_logo/kondae_time.png is excluded by !**/*.png
  • src/assets/template_logo/mcu.png is excluded by !**/*.png
  • src/assets/template_logo/nogotte.png is excluded by !**/*.png
  • src/assets/template_logo/osansi.png is excluded by !**/*.png
  • src/assets/template_logo/seobangjeongto.png is excluded by !**/*.png
  • src/assets/template_logo/todallae.png is excluded by !**/*.png
  • src/assets/template_logo/visual.png is excluded by !**/*.png
  • src/assets/template_logo/yuppm_law_track.png is excluded by !**/*.png
📒 Files selected for processing (4)
  • src/main.tsx
  • src/mocks/handlers/global.ts
  • src/mocks/handlers/organization.ts
  • src/mocks/handlers/static_asset.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/mocks/handlers/global.ts
  • src/mocks/handlers/organization.ts

@i-meant-to-be i-meant-to-be requested a review from useon March 3, 2026 10:07
@i-meant-to-be
Copy link
Contributor Author

/noti

@useon 리뷰에 승인 남겨주셨으나, 추가된 커밋이 더 있어서 리뷰 요청을 다시 드립니다. 바쁘시겠으나 여유 있으실 때 잠깐 다시 확인해주시면 정말 감사하겠습니다!

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: 1

🧹 Nitpick comments (1)
src/util/arrayEncoding.test.ts (1)

3-7: 신규 공개 함수(createTableShareUrlFromEncodedData) 테스트도 추가해두면 좋겠습니다.

현재는 createTableShareUrlFromTable 중심으로만 검증되고 있어, 신규 함수의 base URL 정규화/쿼리 조합 회귀를 놓칠 수 있습니다.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/util/arrayEncoding.test.ts` around lines 3 - 7, Add unit tests that
exercise the new public function createTableShareUrlFromEncodedData (in addition
to existing createTableShareUrlFromTable tests) to ensure base URL normalization
and correct query composition: test with bases having/omitting trailing slashes
and existing query params, confirm the encoded data is appended as the expected
query param, and verify round-trip decoding via extractTableShareUrl and
decodeDebateTableData (or that decodeDebateTableData of the extracted value
equals the original encodeDebateTableData output). Include cases that mirror
current encodeDebateTableData/decodeDebateTableData behavior so future
regressions in query joining or base URL handling are caught.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/util/arrayEncoding.ts`:
- Around line 36-41: The createTableShareUrlFromEncodedData function currently
uses "import.meta.env.VITE_SHARE_BASE_URL || window.location.origin" which does
not treat all-whitespace env values as empty; update its baseUrl handling to
match the normalization used earlier in this file (lines near the other helper):
read VITE_SHARE_BASE_URL, trim it and treat empty/whitespace-only values as
missing, then fallback to window.location.origin, then apply the same
trailing-slash strip (normalizedBaseUrl = baseUrl.replace(/\/+$/, '')) and keep
the existing basePath/pathPrefix logic so the final URL is correct; reference
the function name createTableShareUrlFromEncodedData when making this change.

---

Nitpick comments:
In `@src/util/arrayEncoding.test.ts`:
- Around line 3-7: Add unit tests that exercise the new public function
createTableShareUrlFromEncodedData (in addition to existing
createTableShareUrlFromTable tests) to ensure base URL normalization and correct
query composition: test with bases having/omitting trailing slashes and existing
query params, confirm the encoded data is appended as the expected query param,
and verify round-trip decoding via extractTableShareUrl and
decodeDebateTableData (or that decodeDebateTableData of the extracted value
equals the original encodeDebateTableData output). Include cases that mirror
current encodeDebateTableData/decodeDebateTableData behavior so future
regressions in query joining or base URL handling are caught.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 86b8065 and 17b9460.

📒 Files selected for processing (6)
  • src/components/ShareModal/ShareModal.stories.tsx
  • src/hooks/useTableShare.tsx
  • src/page/LandingPage/components/TemplateCard.tsx
  • src/page/LandingPage/hooks/useLandingPageHandlers.ts
  • src/util/arrayEncoding.test.ts
  • src/util/arrayEncoding.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/page/LandingPage/components/TemplateCard.tsx

Copy link
Contributor

@useon useon left a comment

Choose a reason for hiding this comment

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

숀 !!! 리뷰 반영해 주시고 파싱도 더 안전하게 바꾸셨네요 최고입니다 .. ! 꼼꼼하게 작업해 주셔서 감사하니다 어프루브 !!!!

@i-meant-to-be i-meant-to-be merged commit 3fe83d1 into develop Mar 9, 2026
3 checks passed
@i-meant-to-be i-meant-to-be deleted the refactor/#425 branch March 9, 2026 06:59
@github-actions
Copy link

github-actions bot commented Mar 9, 2026

🧹 Preview 배포가 정리되었습니다.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

refactor 기능 변경 없이 코드만 변경했을 경우

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

[REFACTOR] 템플릿 데이터를 API에서 패칭하도록 수정

2 participants