"use client"; import { IconBrandYoutube } from "@tabler/icons-react"; import { TagInput, type Tag as TagType } from "emblor"; import { Loader2 } from "lucide-react"; import { motion } from "motion/react"; import { useRouter } from "next/navigation"; import { useTranslations } from "next-intl"; import { useState } from "react"; import { toast } from "sonner"; import { Button } from "@/components/ui/button"; import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, } from "@/components/ui/card"; import { Label } from "@/components/ui/label"; import { authenticatedFetch } from "@/lib/auth-utils"; const youtubeRegex = /^(https:\/\/)?(www\.)?(youtube\.com\/watch\?v=|youtu\.be\/)([a-zA-Z0-9_-]{11})$/; interface YouTubeTabProps { searchSpaceId: string; } export function YouTubeTab({ searchSpaceId }: YouTubeTabProps) { const t = useTranslations("add_youtube"); const router = useRouter(); const [videoTags, setVideoTags] = useState([]); const [activeTagIndex, setActiveTagIndex] = useState(null); const [isSubmitting, setIsSubmitting] = useState(false); const [error, setError] = useState(null); const isValidYoutubeUrl = (url: string): boolean => { return youtubeRegex.test(url); }; const extractVideoId = (url: string): string | null => { const match = url.match(/(?:youtube\.com\/watch\?v=|youtu\.be\/)([a-zA-Z0-9_-]{11})/); return match ? match[1] : null; }; const handleSubmit = async () => { if (videoTags.length === 0) { setError(t("error_no_video")); return; } const invalidUrls = videoTags.filter((tag) => !isValidYoutubeUrl(tag.text)); if (invalidUrls.length > 0) { setError(t("error_invalid_urls", { urls: invalidUrls.map((tag) => tag.text).join(", ") })); return; } setError(null); setIsSubmitting(true); try { toast(t("processing_toast"), { description: t("processing_toast_desc"), }); const videoUrls = videoTags.map((tag) => tag.text); const response = await authenticatedFetch( `${process.env.NEXT_PUBLIC_FASTAPI_BACKEND_URL}/api/v1/documents`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ document_type: "YOUTUBE_VIDEO", content: videoUrls, search_space_id: parseInt(searchSpaceId), }), } ); if (!response.ok) { throw new Error("Failed to process YouTube videos"); } await response.json(); toast(t("success_toast"), { description: t("success_toast_desc"), }); router.push(`/dashboard/${searchSpaceId}/documents`); } catch (error: any) { setError(error.message || t("error_generic")); toast(t("error_toast"), { description: `${t("error_toast_desc")}: ${error.message}`, }); } finally { setIsSubmitting(false); } }; const handleAddTag = (text: string) => { if (!isValidYoutubeUrl(text)) { toast(t("invalid_url_toast"), { description: t("invalid_url_toast_desc"), }); return; } if (videoTags.some((tag) => tag.text === text)) { toast(t("duplicate_url_toast"), { description: t("duplicate_url_toast_desc"), }); return; } const newTag: TagType = { id: Date.now().toString(), text: text, }; setVideoTags([...videoTags, newTag]); }; return ( {t("title")} {t("subtitle")}

{t("hint")}

{error && ( {error} )}

{t("tips_title")}

  • {t("tip_1")}
  • {t("tip_2")}
  • {t("tip_3")}
  • {t("tip_4")}
{videoTags.length > 0 && (

{t("preview")}:

{videoTags.map((tag, index) => { const videoId = extractVideoId(tag.text); return videoId ? (