'use client'; import { useState } from 'react'; import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; import { Loader2 } from 'lucide-react'; import { fetchCollaboratorVideos, createCollaborator, updateCollaborator, type Collaborator, type CollaboratorPayload, } from '@/lib/api'; import UsagePanel from './UsagePanel'; import Modal from './Modal'; import f from './FormField.module.css'; export const PLATFORMS = [ { key: 'youtubeLink', prefix: 'https://www.youtube.com/@', display: 'youtube.com/@', label: 'YouTube', urlField: true }, { key: 'twitchLink', prefix: 'https://twitch.tv/', display: 'twitch.tv/', label: 'Twitch', urlField: true }, { key: 'instagramLink', prefix: 'https://instagram.com/', display: 'instagram.com/', label: 'Instagram', urlField: true }, { key: 'tiktokLink', prefix: 'https://tiktok.com/@', display: 'tiktok.com/@', label: 'TikTok', urlField: true }, { key: 'twitterLink', prefix: 'https://x.com/', display: 'x.com/', label: 'Twitter / X', urlField: true }, { key: 'blueskyLink', prefix: 'https://bsky.app/profile/', display: 'bsky.app/profile/', label: 'Bluesky', urlField: true }, { key: 'discordHandle', prefix: '', display: '', label: 'Discord', urlField: false }, ] as const; export type PlatformKey = typeof PLATFORMS[number]['key']; export function toUsername(url: string | null | undefined, prefix: string): string { if (!url) return ''; return prefix ? url.replace(prefix, '').replace(/^\/+/, '') : url; } export function toValue(username: string, prefix: string): string { if (!username.trim()) return ''; return prefix ? prefix + username.trim().replace(/^\/+/, '') : username.trim(); } const EMPTY_FORM: CollaboratorPayload = { name: '', youtubeLink: '', twitchLink: '', instagramLink: '', tiktokLink: '', twitterLink: '', blueskyLink: '', discordHandle: '', aliases: [], notes: '', active: true, }; interface Props { initial?: Collaborator; onClose: () => void; /** Called after a successful create, with the new collaborator id */ onCreated?: (id: string) => void; } export default function CollaboratorModal({ initial, onClose, onCreated }: Props) { const qc = useQueryClient(); const [form, setForm] = useState( initial ? { name: initial.name, youtubeLink: initial.youtubeLink ?? '', twitchLink: initial.twitchLink ?? '', instagramLink: initial.instagramLink ?? '', tiktokLink: initial.tiktokLink ?? '', twitterLink: initial.twitterLink ?? '', blueskyLink: initial.blueskyLink ?? '', discordHandle: initial.discordHandle ?? '', aliases: initial.aliases, notes: initial.notes ?? '', active: initial.active, } : EMPTY_FORM, ); const [aliasInput, setAliasInput] = useState(initial?.aliases.join(', ') ?? ''); const { data: usageVideos = [], isLoading: usageLoading } = useQuery({ queryKey: ['collaborator-videos', initial?.id], queryFn: () => fetchCollaboratorVideos(initial!.id), enabled: !!initial, }); const [usernames, setUsernames] = useState>(() => { const src = initial ?? {} as Collaborator; return Object.fromEntries( PLATFORMS.map((p) => [p.key, toUsername(src[p.key as keyof Collaborator] as string | null, p.prefix)]) ) as Record; }); const setUsername = (key: PlatformKey, val: string) => setUsernames((prev) => ({ ...prev, [key]: val })); const mutation = useMutation({ mutationFn: () => { const platformValues = Object.fromEntries( PLATFORMS.map((p) => [p.key, toValue(usernames[p.key], p.prefix)]) ); const payload: CollaboratorPayload = { ...form, ...platformValues, aliases: aliasInput.split(',').map((a) => a.trim()).filter(Boolean), }; return initial ? updateCollaborator(initial.id, payload) : createCollaborator(payload); }, onSuccess: (saved) => { qc.invalidateQueries({ queryKey: ['collaborators'] }); if (!initial && onCreated) onCreated((saved as Collaborator).id); onClose(); }, }); const set = (key: keyof CollaboratorPayload, val: unknown) => setForm((p) => ({ ...p, [key]: val })); return (
set('name', e.target.value)} placeholder="Full name or channel name" autoFocus />
{([ PLATFORMS.slice(0, 2), PLATFORMS.slice(2, 4), PLATFORMS.slice(4, 6), PLATFORMS.slice(6, 7), ] as const).map((row, ri) => (
{row.map((p) => (
{p.display ? (
{p.display} setUsername( p.key, e.target.value.replace( new RegExp(`^https?://(www\\.)?${p.display.replace(/\//g, '\\/')}`, 'i'), '', ), ) } placeholder="username" />
) : ( setUsername(p.key, e.target.value)} placeholder="username" /> )}
))}
))}
setAliasInput(e.target.value)} placeholder="alias1, alias2" />