diff --git a/src/components/routes/create-plan/PlanTagSearchInput.tsx b/src/components/routes/create-plan/PlanTagSearchInput.tsx index be0606d1..18aec25c 100644 --- a/src/components/routes/create-plan/PlanTagSearchInput.tsx +++ b/src/components/routes/create-plan/PlanTagSearchInput.tsx @@ -1,14 +1,20 @@ import { useEffect, useRef, useState } from "react"; -import { IoMdClose } from "react-icons/io"; +import { IoMdAdd, IoMdClose } from "react-icons/io"; import { useDebounce } from "use-debounce"; import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import { toast } from "sonner"; import { Input } from "@/components/ui/atoms/input"; +import { Textarea } from "@/components/ui/atoms/textarea"; +import { Button } from "@/components/ui/atoms/button"; +import { Pecha } from "@/components/ui/shadimport"; +import { PLAN_LANGUAGE } from "@/lib/constant"; +import type { LanguageCode } from "@/schema/SeriesSchema"; import { createTag, fetchTags, type PlanTagSummary, type Tag, + type TagMetadataInput, } from "@/components/routes/tags/api/tagsApi"; interface PlanTagSearchInputProps { @@ -24,6 +30,11 @@ const SEARCH_DEBOUNCE_MS = 400; const normalizeName = (name: string) => name.trim().toLowerCase(); +interface LanguageData { + name: string; + description: string; +} + const PlanTagSearchInput = ({ value = [], onChange, @@ -39,6 +50,13 @@ const PlanTagSearchInput = ({ const [tagLabels, setTagLabels] = useState>(() => Object.fromEntries(initialTags.map((tag) => [tag.id, tag.name])), ); + const [showCreateDialog, setShowCreateDialog] = useState(false); + const [activeLanguages, setActiveLanguages] = useState(["EN"]); + const [languageData, setLanguageData] = useState>({ + EN: { name: "", description: "" }, + BO: { name: "", description: "" }, + ZH: { name: "", description: "" }, + }); useEffect(() => { if (!initialTags.length) return; @@ -56,10 +74,9 @@ const PlanTagSearchInput = ({ }); const createTagMutation = useMutation({ - mutationFn: (name: string) => + mutationFn: (metadata: TagMetadataInput[]) => createTag({ - name: name.trim(), - description: null, + metadata, image_key: null, plan_ids: planId ? [planId] : [], }), @@ -69,6 +86,8 @@ const PlanTagSearchInput = ({ addTag(tag); setInputValue(""); setShowSuggestions(false); + setShowCreateDialog(false); + resetCreateForm(); toast.success(`Tag "${tag.name}" created`); }, onError: () => { @@ -106,9 +125,63 @@ const PlanTagSearchInput = ({ setShowSuggestions(false); }; + const resetCreateForm = () => { + setActiveLanguages(["EN"]); + setLanguageData({ + EN: { name: "", description: "" }, + BO: { name: "", description: "" }, + ZH: { name: "", description: "" }, + }); + }; + + const openCreateDialog = () => { + resetCreateForm(); + setLanguageData((prev) => ({ + ...prev, + EN: { name: trimmedInput, description: "" }, + })); + setShowCreateDialog(true); + setShowSuggestions(false); + }; + const handleCreateTag = () => { - if (!trimmedInput || createTagMutation.isPending) return; - createTagMutation.mutate(trimmedInput); + const metadata: TagMetadataInput[] = []; + for (const lang of activeLanguages) { + const data = languageData[lang]; + if (!data.name.trim()) { + toast.error(`Name is required for ${PLAN_LANGUAGE.find(l => l.value === lang)?.label}`); + return; + } + metadata.push({ + language: lang, + name: data.name.trim(), + description: data.description.trim() || null, + }); + } + createTagMutation.mutate(metadata); + }; + + const addLanguage = (langCode: LanguageCode) => { + setActiveLanguages([...activeLanguages, langCode]); + }; + + const removeLanguage = (langCode: LanguageCode) => { + if (activeLanguages.length === 1) { + toast.error("At least one language is required"); + return; + } + setActiveLanguages(activeLanguages.filter((l) => l !== langCode)); + }; + + const updateLanguageField = ( + lang: LanguageCode, + field: keyof LanguageData, + value: string + ) => { + setLanguageData((prev) => ({ + ...prev, + [lang]: { ...prev[lang], [field]: value }, + })); }; const handleKeyDown = (e: React.KeyboardEvent) => { @@ -124,7 +197,7 @@ const PlanTagSearchInput = ({ return; } if (showCreateOption) { - handleCreateTag(); + openCreateDialog(); } } else if (e.key === "Escape") { setShowSuggestions(false); @@ -207,7 +280,7 @@ const PlanTagSearchInput = ({ type="button" className="w-full px-3 py-2 text-left text-sm text-[#A51C21] hover:bg-muted/50 cursor-pointer font-medium border-b" onMouseDown={(e) => e.preventDefault()} - onClick={handleCreateTag} + onClick={openCreateDialog} disabled={createTagMutation.isPending} > {createTagMutation.isPending @@ -241,6 +314,102 @@ const PlanTagSearchInput = ({ )} + + {/* Multi-language Create Tag Dialog */} + + + + Create New Tag + +
+
+
+ + {PLAN_LANGUAGE.filter((lang) => !activeLanguages.includes(lang.value as LanguageCode)).length > 0 && ( + + + + + + {PLAN_LANGUAGE.filter((lang) => !activeLanguages.includes(lang.value as LanguageCode)).map((lang) => ( + addLanguage(lang.value as LanguageCode)} + > + {lang.label} + + ))} + + + )} +
+ {activeLanguages.map((lang) => { + const langLabel = PLAN_LANGUAGE.find((l) => l.value === lang)?.label || lang; + return ( +
+ {activeLanguages.length > 1 && ( + + )} +
{langLabel}
+
+ + updateLanguageField(lang, "name", e.target.value)} + placeholder="Tag name" + required + className="bg-white dark:bg-[#181818]" + /> +
+
+ +