Skip to content

feat: 카카오 알림 발송 연동 및 전송 UX 정합성 개선#192

Merged
p-changki merged 2 commits intodevfrom
feat-ck/kakao-api-v1
Feb 25, 2026
Merged

feat: 카카오 알림 발송 연동 및 전송 UX 정합성 개선#192
p-changki merged 2 commits intodevfrom
feat-ck/kakao-api-v1

Conversation

@p-changki
Copy link
Contributor

@p-changki p-changki commented Feb 25, 2026

🔗 관련 이슈

✨ 작업 단계 및 변경 사항

  • 작업 단계: Phase 2 (API 연동 및 전송 UX 정합성 개선)

  • 변경 사항:

    • 카카오 메모 전송 서비스 추가 (src/services/kakao.service.ts)
    • 카카오 메시지 제한 상수 및 문자열 정규화 유틸 추가 (src/constants/kakao.ts)
    • 클리닉 알림 발송을 실제 카카오 전송으로 연동하고 targetType(학생/학부모/전체) 반영
    • 심플/프리미엄 성적표 발송 훅에서 업로드 후 실제 카카오 전송 호출로 연결
    • 공통 카카오 모달/학생 알림 모달에 메시지 길이 카운터 및 최대 길이 제한 적용
    • 학생 알림 모달 실패 UX 개선(전송 실패 시 모달 유지 + 공통 알럿 노출)

🧪 테스트 방법

리뷰어가 확인해야 할 핵심 포인트입니다.

  • 학생 알림 모달에서 발송 대상(전체/학생/학부모) 변경 시 예상 수신자 수가 연락처 보유 기준으로 계산되는가?
  • 학생 알림 모달에서 연락처가 없는 대상만 선택된 경우 "전송 불가" 알럿이 뜨고 전송이 차단되는가?
  • 학생 알림 모달에서 전송 실패 시 "전송 실패" 알럿이 뜨고 모달이 닫히지 않는가?
  • 클리닉 알림 발송 시 targetType이 제목/내용에 반영되어 전송되는가?
  • 성적표(심플/프리미엄) 발송 시 카카오 전송 완료 알럿이 노출되는가?
  • 메시지 입력이 200자 제한(KAKAO_MESSAGE_LIMITS.DESCRIPTION)으로 동작하는가?

📸 스크린샷 (선택)

  • 이번 PR은 동작/API 연동 중심 변경으로 스크린샷은 생략했습니다.
    (원하면 학생 알림 모달/공통 카카오 모달 화면 캡처 추가 가능)

✅ 체크리스트

  • Phase에 맞는 이슈 체크리스트를 모두 완료했는가?
  • lint / type-check 통과 및 불필요한 console.log 제거
  • 머지 후 이 이슈가 [QA] 컬럼으로 이동함을 인지하고 있는가?

Summary by CodeRabbit

  • New Features

    • Added Kakao message sending across clinics, report exports, and student notifications.
    • Live character counter and enforced message length limits (title 200, description 200).
  • Improvements

    • Unified success alert showing "발송 완료" with consistent post-send messaging.
    • Added targeted recipient options (all, students, parents) and send-state handling to prevent duplicate sends.
  • Documentation

    • Cosmetic README formatting updates.

@p-changki p-changki self-assigned this Feb 25, 2026
@p-changki p-changki added the FE 프런트 생성 label Feb 25, 2026
@p-changki p-changki added FIX 수정사항 API api 연결 labels Feb 25, 2026
@coderabbitai
Copy link

coderabbitai bot commented Feb 25, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0834f4a and 52e04d8.

📒 Files selected for processing (3)
  • README.md
  • src/app/(dashboard)/educators/exams/clinic/_components/ClinicHeader.tsx
  • src/components/common/modals/KakaoNotificationModal.tsx
✅ Files skipped from review due to trivial changes (1)
  • README.md
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/app/(dashboard)/educators/exams/clinic/_components/ClinicHeader.tsx
  • src/components/common/modals/KakaoNotificationModal.tsx

📝 Walkthrough

Walkthrough

Adds Kakao memo support: new constants and service for sending memos, message trimming/limits, and integrations in clinic, report, and notification UIs with character counting, recipient filtering, async send flow, and unified success alerts.

Changes

Cohort / File(s) Summary
Kakao constants & service
src/constants/kakao.ts, src/services/kakao.service.ts
New KAKAO_MESSAGE_LIMITS and trimKakaoMessage(); sendKakaoMemo() service added with payload normalization and POST to /kakao/memo.
Notification modals / UI
src/components/common/modals/KakaoNotificationModal.tsx, src/app/(dashboard)/educators/students/_components/modal/TalkNotificationModal.tsx
Add live character count, enforce maxLength, dynamic color, recipient stats filtering, isSending state, async submit with alerts, and disabled/send-state button UI.
Clinic header integration
src/app/(dashboard)/educators/exams/clinic/_components/ClinicHeader.tsx
Wires sendKakaoMemo into handleSend(...); adds NotificationTargetType filtering (all/student/parent) and composes recipient list before sending; calls onSendNotification after success.
Report hooks
src/app/(dashboard)/educators/exams/report/_hooks/usePremiumReportTemplateActions.tsx, src/app/(dashboard)/educators/exams/report/_hooks/useSimpleReportTemplateActions.tsx
After generating report PDF, call sendKakaoMemo with title/description/image/webUrl; simplify post-send alert to a consistent "발송 완료" message.
Docs
README.md
Cosmetic formatting edits (spacing, badges, team table) with no behavior changes.

Sequence Diagram

sequenceDiagram
    actor User
    participant UI as Educator UI Component
    participant Service as Kakao Service
    participant API as Backend API

    User->>UI: Trigger send (clinic/report/notification)
    UI->>UI: Compose payload (title, description, image, webUrl)
    UI->>Service: sendKakaoMemo(payload)
    Service->>Service: normalize/trim fields (KAKAO_MESSAGE_LIMITS)
    Service->>API: POST /kakao/memo
    API-->>Service: Success/Error
    Service-->>UI: Resolve/Reject
    UI->>User: Update UI (alerts, reset/close, send-state)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested labels

feature, Modal

Suggested reviewers

  • play-ancora-gyungmin
  • rklpoi5678
  • yoorrll

Poem

🐇 I bounced a memo, crisp and bright,
Trimmed my words to just the right bite,
Counts on the side, recipients near,
Reports and clinics — messages clear,
Hop! — Kakao sent, educators cheer.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

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.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title accurately describes the main changes: implementing Kakao notification sending and improving UX consistency for message transmission across multiple components.
Linked Issues check ✅ Passed The PR fulfills the scope of issue #191 by integrating Kakao API into frontend flows (student management, clinic, grade-report sending) with proper UI components and validation logic.
Out of Scope Changes check ✅ Passed README.md formatting changes are minor cosmetic updates unrelated to the main Kakao API integration scope, but they do not detract from the primary objectives.

✏️ 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 feat-ck/kakao-api-v1

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.

Copy link
Contributor

@yoorrll yoorrll left a comment

Choose a reason for hiding this comment

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

LGTM 넘 고생하셨씁니다 !!! 진짜 첨부파일 수정 기능 제외하면 다 했네요...!!!! 짱이다

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 (2)
src/app/(dashboard)/educators/students/_components/modal/TalkNotificationModal.tsx (1)

109-113: ⚠️ Potential issue | 🟠 Major

전송 중 모달 종료를 막아야 상태 꼬임을 줄일 수 있습니다.

현재는 전송 중에도 닫기 동작이 가능해서, 요청 진행 중 폼/선택 상태가 먼저 초기화될 수 있습니다. 전송 중에는 닫기 경로를 차단하는 편이 안전합니다.

💡 Proposed fix
     <Dialog
       open={isOpen}
       onOpenChange={(open) => {
-        if (!open) handleClose();
+        if (!open && isSending) return;
+        if (!open) handleClose();
       }}
     >
...
             <Button
               className="cursor-pointer h-[48px] px-[28px] py-[12px] rounded-[12px] bg-white border border-neutral-200 hover:bg-neutral-50 text-label-normal shadow-none"
               type="button"
               variant="outline"
               onClick={handleClose}
+              disabled={isSending}
             >
               취소
             </Button>

Also applies to: 264-269

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

In
`@src/app/`(dashboard)/educators/students/_components/modal/TalkNotificationModal.tsx
around lines 109 - 113, The Dialog currently allows closing while a send is in
progress which can reset form/state; update the onOpenChange handler to ignore
close events when the send flag is true (e.g., if (!open && isSending) return;
else handleClose()), and apply the same guard to the other Dialog instance
referenced (lines ~264-269). Also ensure any explicit close controls call
handleClose only when not isSending so the modal cannot be dismissed mid-send.
src/components/common/modals/KakaoNotificationModal.tsx (1)

94-97: ⚠️ Potential issue | 🟠 Major

전송 실패 시 사용자 피드백이 누락됩니다.

onSend 실패 시 콘솔 로그만 남기고 종료되어 사용자 입장에서 실패 원인이 보이지 않습니다. 모달 유지는 좋지만 실패 알럿은 반드시 노출하는 편이 안전합니다.

💡 Proposed fix
       } catch (error) {
         console.error("Failed to send notification:", error);
-        // Keep modal open on failure
+        await showAlert({
+          title: mode === "prepare" ? "준비 실패" : "전송 실패",
+          description:
+            mode === "prepare"
+              ? "카카오톡 발송 준비 중 오류가 발생했습니다."
+              : "카카오톡 전송 중 오류가 발생했습니다.",
+        });
+        // Keep modal open on failure
       } finally {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/common/modals/KakaoNotificationModal.tsx` around lines 94 -
97, The catch block in KakaoNotificationModal's onSend handler only logs to
console and leaves the user unaware of failure; update the catch to present a
user-facing error (e.g., call the project's toast/error-notification helper or
set a local error state that renders an inline alert) with a clear message
including the error detail, keep the modal open, and still log the error for
debugging (preserve console.error). Target the catch inside the onSend function
of KakaoNotificationModal and use the existing UI feedback mechanism
(toast.error, showAlert, or setError state) to surface the failure to the user.
🤖 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/app/`(dashboard)/educators/exams/clinic/_components/ClinicHeader.tsx:
- Around line 63-84: When targetType is "all" the title uses
deliverableRecipients.length (one per student) but the UI expects total contact
count (students + parents); update the logic that builds the title before
calling sendKakaoMemo: compute a recipientCount variable where if targetType ===
"all" you sum for each recipient the number of available contacts
(Boolean(r.phone) + Boolean(r.parentPhone)), otherwise set recipientCount =
deliverableRecipients.length; then use recipientCount in the title (`[클리닉 알림]
${recipientCount}명 대상 (${targetLabel})`) and keep the existing
deliverableRecipients/nameList logic for the description and validation.

---

Outside diff comments:
In
`@src/app/`(dashboard)/educators/students/_components/modal/TalkNotificationModal.tsx:
- Around line 109-113: The Dialog currently allows closing while a send is in
progress which can reset form/state; update the onOpenChange handler to ignore
close events when the send flag is true (e.g., if (!open && isSending) return;
else handleClose()), and apply the same guard to the other Dialog instance
referenced (lines ~264-269). Also ensure any explicit close controls call
handleClose only when not isSending so the modal cannot be dismissed mid-send.

In `@src/components/common/modals/KakaoNotificationModal.tsx`:
- Around line 94-97: The catch block in KakaoNotificationModal's onSend handler
only logs to console and leaves the user unaware of failure; update the catch to
present a user-facing error (e.g., call the project's toast/error-notification
helper or set a local error state that renders an inline alert) with a clear
message including the error detail, keep the modal open, and still log the error
for debugging (preserve console.error). Target the catch inside the onSend
function of KakaoNotificationModal and use the existing UI feedback mechanism
(toast.error, showAlert, or setError state) to surface the failure to the user.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ba825a0 and 0834f4a.

📒 Files selected for processing (7)
  • src/app/(dashboard)/educators/exams/clinic/_components/ClinicHeader.tsx
  • src/app/(dashboard)/educators/exams/report/_hooks/usePremiumReportTemplateActions.tsx
  • src/app/(dashboard)/educators/exams/report/_hooks/useSimpleReportTemplateActions.tsx
  • src/app/(dashboard)/educators/students/_components/modal/TalkNotificationModal.tsx
  • src/components/common/modals/KakaoNotificationModal.tsx
  • src/constants/kakao.ts
  • src/services/kakao.service.ts

@github-actions
Copy link

⚡️ Lighthouse Report

🏠 URL: http://localhost:3000/

Category Score
🔴 Performance 42
🟢 Accessibility 96
🟢 Best practices 93
🟢 SEO 100

상세 리포트는 하단의 lhci/url Checks 내 Details 링크를 확인해주세요! 🚀

@p-changki p-changki merged commit 3d53e19 into dev Feb 25, 2026
4 checks passed
@p-changki p-changki deleted the feat-ck/kakao-api-v1 branch February 25, 2026 08:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

API api 연결 FE 프런트 생성 FIX 수정사항

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

[FE] [Phase 1] [Task ID: api-kakao] kakao api

2 participants