feat: 일정 참석자 알림(지정/수정/삭제)
일정 CRUD 시 참석자에게 인앱 알림 발송(기존 NotificationService + SSE 재사용). - 생성: 참석자로 지정된 사용자에게 schedule.invited (전 직원 일정은 개별 알림 생략) - 수정: 신규 참석자 → schedule.invited, 기존 참석자 → schedule.updated - 삭제: 참석자에게 schedule.removed (삭제 전 참석자 확보) - 행위자 본인은 자동 제외, payload(actorName/eventTitle/start), 클릭 시 /schedule 이동 - NotificationType(백/프론트) 3종 추가 + notification.store 렌더 케이스 런타임 검증: 지정/수정/삭제 알림이 참석자에게만 정상 도달. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -27,6 +27,8 @@ function toView(n: ApiNotification): NotificationView {
|
||||
projectId && taskSeq !== null
|
||||
? `/projects/${projectId}/tasks/${taskSeq}`
|
||||
: null
|
||||
// 일정 알림용
|
||||
const eventTitle = escapeHtml(pstr(p, 'eventTitle'))
|
||||
|
||||
let tone = ''
|
||||
let html = '새 알림'
|
||||
@@ -95,6 +97,21 @@ function toView(n: ApiNotification): NotificationView {
|
||||
to = projectId ? `/projects/${projectId}` : null
|
||||
html = `<b>${actor}</b>님이 <b>${projectName}</b> 프로젝트에서 회원님을 제외했습니다`
|
||||
break
|
||||
case 'schedule.invited':
|
||||
tone = 'accent'
|
||||
to = '/schedule'
|
||||
html = `<b>${actor}</b>님이 <b>${eventTitle}</b> 일정에 회원님을 참석자로 지정했습니다`
|
||||
break
|
||||
case 'schedule.updated':
|
||||
tone = 'blue'
|
||||
to = '/schedule'
|
||||
html = `<b>${actor}</b>님이 참석 일정 <b>${eventTitle}</b>을(를) 수정했습니다`
|
||||
break
|
||||
case 'schedule.removed':
|
||||
tone = 'red'
|
||||
to = '/schedule'
|
||||
html = `<b>${actor}</b>님이 참석 일정 <b>${eventTitle}</b>을(를) 삭제했습니다`
|
||||
break
|
||||
}
|
||||
return { id: n.id, read: n.read, tone, html, time: relativeTimeKo(n.createdAt), to }
|
||||
}
|
||||
|
||||
@@ -17,6 +17,9 @@ export type NotificationType =
|
||||
| 'member.invited'
|
||||
| 'member.role_changed'
|
||||
| 'member.removed'
|
||||
| 'schedule.invited'
|
||||
| 'schedule.updated'
|
||||
| 'schedule.removed'
|
||||
|
||||
// 알림(API 원시) — 표시 문구/링크는 프론트가 type+payload 로 조립
|
||||
export interface ApiNotification {
|
||||
|
||||
Reference in New Issue
Block a user