diff --git a/src/collections/YouTubeContent.ts b/src/collections/YouTubeContent.ts index 2362921..25bf657 100644 --- a/src/collections/YouTubeContent.ts +++ b/src/collections/YouTubeContent.ts @@ -9,6 +9,7 @@ import { } from '../lib/youtubeAccess' import { createTasksOnStatusChange } from '../hooks/youtubeContent/createTasksOnStatusChange' import { downloadThumbnail } from '../hooks/youtubeContent/downloadThumbnail' +import { autoStatusTransitions } from '../hooks/youtubeContent/autoStatusTransitions' // TODO: ScriptSectionBlock causes admin UI rendering issues // import { ScriptSectionBlock } from '../blocks/ScriptSectionBlock' @@ -39,7 +40,7 @@ export const YouTubeContent: CollectionConfig = { delete: isYouTubeManager, }, hooks: { - afterChange: [createTasksOnStatusChange, downloadThumbnail], + afterChange: [createTasksOnStatusChange, downloadThumbnail, autoStatusTransitions], beforeChange: [ // Auto-Slug generieren ({ data }) => { diff --git a/src/hooks/youtubeContent/autoStatusTransitions.ts b/src/hooks/youtubeContent/autoStatusTransitions.ts new file mode 100644 index 0000000..aca9642 --- /dev/null +++ b/src/hooks/youtubeContent/autoStatusTransitions.ts @@ -0,0 +1,77 @@ +import type { CollectionAfterChangeHook } from 'payload' +import { NotificationService } from '@/lib/jobs/NotificationService' + +interface TransitionContext { + currentStatus: string + youtubeVideoId?: string | null + hasAllChecklistsComplete: boolean +} + +/** + * Determines the next status based on current state and conditions + */ +export function getNextStatus(context: TransitionContext): string | null { + const { currentStatus, youtubeVideoId } = context + + // Upload completed → published + if (currentStatus === 'upload_scheduled' && youtubeVideoId) { + return 'published' + } + + return null +} + +/** + * Checks if a manual transition should be suggested + */ +export function shouldTransitionStatus( + status: string, + context: { hasVideoFile?: boolean }, +): boolean { + if (status === 'approved' && context.hasVideoFile) return true + return false +} + +/** + * Hook: Automatische Status-Übergänge nach Änderungen + */ +export const autoStatusTransitions: CollectionAfterChangeHook = async ({ + doc, + previousDoc, + req, + operation, +}) => { + if (operation !== 'update') return doc + + const nextStatus = getNextStatus({ + currentStatus: doc.status, + youtubeVideoId: doc.youtube?.videoId, + hasAllChecklistsComplete: false, + }) + + if (nextStatus && nextStatus !== doc.status) { + console.log(`[autoStatusTransitions] ${doc.id}: ${doc.status} → ${nextStatus}`) + + await req.payload.update({ + collection: 'youtube-content', + id: doc.id, + data: { status: nextStatus }, + depth: 0, + }) + + // Notification + if (doc.assignedTo) { + const assignedToId = typeof doc.assignedTo === 'object' ? doc.assignedTo.id : doc.assignedTo + const notificationService = new NotificationService(req.payload) + await notificationService.createNotification({ + recipientId: assignedToId, + type: 'system', + title: `Video-Status automatisch geändert: ${nextStatus}`, + link: `/admin/collections/youtube-content/${doc.id}`, + relatedVideoId: doc.id, + }) + } + } + + return doc +} diff --git a/tests/unit/youtube/auto-status-transitions.unit.spec.ts b/tests/unit/youtube/auto-status-transitions.unit.spec.ts new file mode 100644 index 0000000..2ac97e3 --- /dev/null +++ b/tests/unit/youtube/auto-status-transitions.unit.spec.ts @@ -0,0 +1,32 @@ +import { describe, it, expect } from 'vitest' +import { getNextStatus, shouldTransitionStatus } from '@/hooks/youtubeContent/autoStatusTransitions' + +describe('Auto Status Transitions', () => { + it('should transition to published when upload is complete', () => { + const result = getNextStatus({ + currentStatus: 'upload_scheduled', + youtubeVideoId: 'VID123', + hasAllChecklistsComplete: false, + }) + expect(result).toBe('published') + }) + + it('should not transition if no video ID on upload_scheduled', () => { + const result = getNextStatus({ + currentStatus: 'upload_scheduled', + youtubeVideoId: null, + hasAllChecklistsComplete: false, + }) + expect(result).toBeNull() + }) + + it('should transition approved to upload_scheduled when video file exists', () => { + const result = shouldTransitionStatus('approved', { hasVideoFile: true }) + expect(result).toBe(true) + }) + + it('should not suggest transition for published status', () => { + const result = shouldTransitionStatus('published', { hasVideoFile: true }) + expect(result).toBe(false) + }) +})