https://shell-kitty-d11.notion.site/ELECOSYS-COM-T-P-QU-N-L-PROMP-D-NH-CHO-MARKETING-NG-NH-GI-O-D-C-99da6ec5fd3a4b2a8abc8efc15e64719?pvs=4
import React, { useState, useRef, useEffect } from “react”
import { Card, CardContent, CardHeader, CardFooter } from “@/components/ui/card”
import { Button } from “@/components/ui/button”
import { Input } from “@/components/ui/input”
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger } from “@/components/ui/dialog”
import { Label } from “@/components/ui/label”
import { ScrollArea } from “@/components/ui/scroll-area”
import { Search, LayoutGrid, List, Plus, FolderPlus, Trash2, Copy, ChevronDown, ChevronRight, Upload } from “lucide-react”
import { useToast } from “@/components/ui/use-toast”
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from “@/components/ui/select”
import { Popover, PopoverContent, PopoverTrigger } from “@/components/ui/popover”
import Papa from ‘papaparse’
type Comment = {
id: number
name: string
content: string
date: string
}
type Prompt = {
id: number
title: string
systemRole: string
instruction: string
category: string
subCategory?: string
skill?: string
tags: string[]
comments: Comment[]
}
type Category = {
name: string
subCategories: {
name: string
skills: string[]
}[]
}
const initialCategories: Category[] = [
{
name: “Prompt for Highschool Teachers”,
subCategories: [
{
name: “English Grade 11”,
skills: [“Writing”, “Grammar”, “Listening & Speaking”]
},
{
name: “Mathematics Grade 12”,
skills: [“Algebra”, “Calculus”]
},
]
},
{
name: “Content Marketing”,
subCategories: [
{
name: “Social Media”,
skills: [“Facebook”, “Instagram”, “Twitter”]
},
{
name: “Blog Writing”,
skills: [“SEO”, “Storytelling”]
}
]
}
]
const initialPrompts: Prompt[] = [
{
id: 1,
title: “English Writing Exercise”,
category: “Prompt for Highschool Teachers”,
subCategory: “English Grade 11”,
skill: “Writing”,
systemRole: “Trợ lý học tập cá nhân hóa, giúp học sinh lớp 11 tối ưu hóa kết quả học tập ở môn tiếng Anh.”,
instruction: “Hãy giúp tôi lập kế hoạch học tập trong 4 tuần để cải thiện kỹ năng viết tiếng Anh của mình, chuẩn bị cho kỳ thi [IELTS/TOEFL]. Kế hoạch nên bao gồm các bài tập viết hằng ngày, từ vựng cần học và cách tôi có thể tự đánh giá bài viết của mình.”,
tags: [“Grade11”, “English”, “Writing”],
comments: []
},
{
id: 2,
title: “Math Problem Solving”,
category: “Prompt for Highschool Teachers”,
subCategory: “Mathematics Grade 12”,
skill: “Problem Solving”,
systemRole: “Trợ lý học tập cá nhân hóa, giúp học sinh lớp 12 phát triển kỹ năng giải quyết vấn đề trong môn Toán.”,
instruction: “Hãy tạo một bộ 5 bài toán thử thách về hình học không gian, kèm theo hướng dẫn giải từng bước. Mỗi bài toán nên tập trung vào một khía cạnh khác nhau của hình học không gian.”,
tags: [“Grade12”, “Math”, “Geometry”],
comments: []
},
]
const categoryColors = {
“Prompt for Highschool Teachers”: “bg-indigo-500 hover:bg-indigo-600”,
“Content Marketing”: “bg-emerald-500 hover:bg-emerald-600”,
}
const PRESET_PASSWORD = “Elecosys@2024”
export default function AdvancedPromptManager() {
const [prompts, setPrompts] = useState
(initialPrompts)
const [categories, setCategories] = useState(initialCategories)
const [editingField, setEditingField] = useState<{ id: number | null, field: keyof Prompt | null }>({ id: null, field: null })
const [newPrompt, setNewPrompt] = useState({ id: 0, title: “”, category: “”, subCategory: “”, skill: “”, systemRole: “”, instruction: “”, tags: [], comments: [] })
const [isAddNewOpen, setIsAddNewOpen] = useState(false)
const [selectedCategory, setSelectedCategory] = useState(null)
const [selectedSubCategory, setSelectedSubCategory] = useState(null)
const [selectedSkill, setSelectedSkill] = useState(null)
const [password, setPassword] = useState(“”)
const [isPasswordDialogOpen, setIsPasswordDialogOpen] = useState(false)
const [currentAction, setCurrentAction] = useState<() => void>(() => {})
const [viewMode, setViewMode] = useState<"grid" | "list">(“grid”)
const [searchTerm, setSearchTerm] = useState(“”)
const [sortBy, setSortBy] = useState<"title" | "category">(“title”)
const [isAddCategoryOpen, setIsAddCategoryOpen] = useState(false)
const [newCategory, setNewCategory] = useState({ name: “”, subCategories: [{ name: “”, skills: [“”] }] })
const [isImportDialogOpen, setIsImportDialogOpen] = useState(false)
const editInputRef = useRef(null)
const fileInputRef = useRef(null)
const { toast } = useToast()
useEffect(() => {
if (editingField.id !== null && editingField.field !== null && editInputRef.current) {
editInputRef.current.focus()
}
}, [editingField])
const handleAddComment = (promptId: number, name: string, content: string) => {
if (name && content) {
const newComment: Comment = {
id: Date.now(),
name,
content,
date: new Date().toLocaleString()
}
setPrompts(prompts.map(prompt =>
prompt.id === promptId
? { …prompt, comments: […prompt.comments, newComment] }
: prompt
))
}
}
const handleEditStart = (id: number, field: keyof Prompt) => {
setCurrentAction(() => () => {
setEditingField({ id, field })
})
setIsPasswordDialogOpen(true)
}
const handleEditComplete = (id: number, field: keyof Prompt, value: string) => {
setPrompts(prompts.map(prompt =>
prompt.id === id ? { …prompt, [field]: value } : prompt
))
setEditingField({ id: null, field: null })
}
const handleAddNew = () => {
if (newPrompt.title && newPrompt.category && newPrompt.subCategory && newPrompt.skill && newPrompt.systemRole && newPrompt.instruction) {
setPrompts([…prompts, { …newPrompt, id: Date.now() }])
setIsAddNewOpen(false)
setNewPrompt({ id: 0, title: “”, category: “”, subCategory: “”, skill: “”, systemRole: “”, instruction: “”, tags: [], comments: [] })
}
}
const handleDelete = (id: number) => {
setCurrentAction(() => () => {
setPrompts(prompts.filter(prompt => prompt.id !== id))
})
setIsPasswordDialogOpen(true)
}
const handlePasswordSubmit = () => {
if (password === PRESET_PASSWORD) {
currentAction()
setIsPasswordDialogOpen(false)
setPassword(“”)
toast({
title: “Action completed”,
description: “The requested action has been performed successfully.”,
})
} else {
toast({
title: “Incorrect password”,
description: “Action not performed.”,
variant: “destructive”,
})
}
}
const handleCopy = (prompt: Prompt) => {
const textToCopy = `Title: ${prompt.title}
Category: ${prompt.category}
Sub-category: ${prompt.subCategory}
Skill: ${prompt.skill}
System Role: ${prompt.systemRole}
Instruction: ${prompt.instruction}
Tags: ${prompt.tags.join(‘, ‘)}`
navigator.clipboard.writeText(textToCopy)
.then(() => toast({ title: “Copied to clipboard!”, description: “Prompt details have been copied.” }))
.catch(err => {
console.error(‘Failed to copy: ‘, err)
toast({ title: “Failed to copy”, description: “An error occurred while copying to clipboard.”, variant: “destructive” })
})
}
const handleAddCategory = () => {
if (newCategory.name && newCategory.subCategories.length > 0) {
setCategories([…categories, newCategory])
setIsAddCategoryOpen(false)
setNewCategory({ name: “”, subCategories: [{ name: “”, skills: [“”] }] })
}
}
const handleImportPrompts = (file: File) => {
Papa.parse(file, {
complete: (results) => {
const importedPrompts: Prompt[] = results.data.slice(1).map((row: any, index: number) => ({
id: Date.now() + index,
title: row[0],
category: row[1],
subCategory: row[2],
skill: row[3],
systemRole: row[4],
instruction: row[5],
tags: row[6] ? row[6].split(‘,’).map((tag: string) => tag.trim()) : [],
comments: []
}))
setPrompts([…prompts, …importedPrompts])
setIsImportDialogOpen(false)
toast({
title: “Import successful”,
description: `${importedPrompts.length} prompts have been imported.`,
})
},
header: true,
skipEmptyLines: true,
})
}
const filteredPrompts = prompts
.filter(prompt =>
(!selectedCategory || prompt.category === selectedCategory) &&
(!selectedSubCategory || prompt.subCategory === selectedSubCategory) &&
(!selectedSkill || prompt.skill === selectedSkill)
)
.filter(prompt =>
prompt.title.toLowerCase().includes(searchTerm.toLowerCase()) ||
(prompt.instruction && prompt.instruction.toLowerCase().includes(searchTerm.toLowerCase())) ||
(prompt.systemRole && prompt.systemRole.toLowerCase().includes(searchTerm.toLowerCase())) ||
prompt.tags.some(tag => tag.toLowerCase().includes(searchTerm.toLowerCase()))
)
.sort((a, b) => {
if (sortBy === “title”) {
return a.title.localeCompare(b.title)
} else {
return a.category.localeCompare(b.category)
}
})
const allTags = Array.from(new Set(prompts.flatMap(prompt => prompt.tags)))
const renderCategoryFilters = () => (
{
setSelectedCategory(null)
setSelectedSubCategory(null)
setSelectedSkill(null)
}}
>
All
{categories.map((category) => (
{category.name}
{category.subCategories.map((subCategory) => (
setSelectedSubCategory(subCategory.name)}
>
{subCategory.name}
{subCategory.skills.map((skill) => (
{
setSelectedCategory(category.name)
setSelectedSubCategory(subCategory.name)
setSelectedSkill(skill)
}}
>
{skill}
))}
))}
))}
)
return (
{allTags.map((tag) => (
setSearchTerm(tag)}
>
#{tag}
))}
Add Prompt
Add New Prompt
Add Prompt
Add Category
Add New Category
Category Name
setNewCategory({…newCategory, name: e.target.value})} />
{newCategory.subCategories.map((subCat, index) => (
))}
setNewCategory({…newCategory, subCategories: […newCategory.subCategories, { name: “”, skills: [“”] }]})}
className=”ml-auto”
>
Add Sub-category
Add Category
Category
setSortBy(value)}>
Sort by Title
Sort by Category
setViewMode(“grid”)}
className={`rounded-none ${viewMode === “grid” ? “bg-[#003a75] text-white” : “text-white border-[#003a75]”}`}
>
setViewMode(“list”)}
className={`rounded-none ${viewMode === “list” ? “bg-[#003a75] text-white” : “text-white border-[#003a75]”}`}
>
{renderCategoryFilters()}
{viewMode === “grid” ? (
{filteredPrompts.map(prompt => (
handleEditStart(prompt.id, ‘title’)}
>
{editingField.id === prompt.id && editingField.field === ‘title’ ? (
handleEditComplete(prompt.id, ‘title’, e.target.value)}
onBlur={() => setEditingField({ id: null, field: null })}
className=”text-xl font-bold bg-[#001f3f] text-white rounded-none”
/>
) : prompt.title}
handleDelete(prompt.id)}>
{prompt.category} > {prompt.subCategory} > {prompt.skill}
{prompt.tags.map(tag => (
#{tag}
))}
Comments:
{prompt.comments.map(comment => (
{comment.name}
{comment.date}
{comment.content}
))}
{
const nameInput = document.getElementById(`name-${prompt.id}`) as HTMLInputElement;
const commentInput = document.getElementById(`comment-${prompt.id}`) as HTMLInputElement;
handleAddComment(prompt.id, nameInput.value, commentInput.value);
nameInput.value = ”;
commentInput.value = ”;
}}
className=”bg-[#003a75] hover:bg-[#004a95] text-white rounded-none”
>
Add
))}
) : (
Title
Category
Sub-category
Skill
System Role
Instruction
Actions
{filteredPrompts.map((prompt) => (
handleEditStart(prompt.id, ‘title’)}>
{editingField.id === prompt.id && editingField.field === ‘title’ ? (
handleEditComplete(prompt.id, ‘title’, e.target.value)}
onBlur={() => setEditingField({ id: null, field: null })}
className=”rounded-none bg-[#001f3f] text-white”
/>
) : {prompt.title} }
{prompt.category}
{prompt.subCategory}
{prompt.skill}
handleEditStart(prompt.id, ‘systemRole’)}>
{editingField.id === prompt.id && editingField.field === ‘systemRole’ ? (
handleEditComplete(prompt.id, ‘systemRole’, e.target.value)}
onBlur={() => setEditingField({ id: null, field: null })}
className=”rounded-none bg-[#001f3f] text-white”
/>
) : {prompt.systemRole} }
handleEditStart(prompt.id, ‘instruction’)}>
{editingField.id === prompt.id && editingField.field === ‘instruction’ ? (
handleEditComplete(prompt.id, ‘instruction’, e.target.value)}
onBlur={() => setEditingField({ id: null, field: null })}
className=”rounded-none bg-[#001f3f] text-white”
/>
) : {prompt.instruction} }
handleCopy(prompt)} className=”mr-2″>
handleDelete(prompt.id)}>
))}
)}
Enter Password
Submit
)
}
Phản hồi