183 lines
No EOL
8.3 KiB
TypeScript
183 lines
No EOL
8.3 KiB
TypeScript
import { useState, useEffect } from 'react';
|
|
import styles from './DashboardPromptSet.module.css';
|
|
import { useUserPrompts } from '../../../auth/Hooks/use-user-prompts';
|
|
import { useUserFiles } from '../../../auth/Hooks/use-user-files';
|
|
import { FaEdit, FaRedo, FaChevronRight } from 'react-icons/fa';
|
|
import PromptItemDelete from './PromptItemDelete';
|
|
import PromptItemShare from './PromptItemShare';
|
|
import NewPromptButton from './NewPromptButton';
|
|
import { motion, AnimatePresence } from 'framer-motion';
|
|
import { useSearchParams } from 'react-router-dom';
|
|
import { useFileOperations } from '../../../hooks/use-file-operations';
|
|
import { FileList } from './FileList';
|
|
|
|
const formatPromptText = (text: string) => {
|
|
// Split text at 5 or more consecutive spaces
|
|
const parts = text.split(/\s{4,}/g);
|
|
// Join with line breaks
|
|
return parts.join('\n');
|
|
};
|
|
|
|
function DashboardPromptSet() {
|
|
const { prompts, loading, error, refetch } = useUserPrompts();
|
|
const { files, loading: filesLoading } = useUserFiles();
|
|
const [expandedPrompts, setExpandedPrompts] = useState<Set<string>>(new Set());
|
|
const [searchParams] = useSearchParams();
|
|
const { downloadingFiles, downloadError, handleFileDownload } = useFileOperations();
|
|
|
|
useEffect(() => {
|
|
if (!loading && prompts.length > 0) {
|
|
const expandedPrompt = searchParams.get('expandedPrompt');
|
|
console.log('URL Parameter expandedPrompt:', expandedPrompt);
|
|
console.log('Available prompts:', prompts.map(p => ({ id: p.id, title: p.prompt_title })));
|
|
console.log('Current expandedPrompts:', Array.from(expandedPrompts));
|
|
|
|
if (expandedPrompt) {
|
|
const matchingPrompt = prompts.find(p => p.id.toString() === expandedPrompt.toString());
|
|
console.log('Matching prompt:', matchingPrompt);
|
|
|
|
if (matchingPrompt) {
|
|
console.log('Setting expanded prompt:', matchingPrompt.id);
|
|
setExpandedPrompts(new Set([matchingPrompt.id]));
|
|
}
|
|
}
|
|
}
|
|
}, [searchParams, prompts, loading]);
|
|
|
|
const toggleExpand = (promptId: string) => {
|
|
console.log('Toggling prompt:', promptId);
|
|
setExpandedPrompts(prev => {
|
|
const newSet = new Set(prev);
|
|
if (newSet.has(promptId)) {
|
|
newSet.delete(promptId);
|
|
} else {
|
|
newSet.add(promptId);
|
|
}
|
|
return newSet;
|
|
});
|
|
};
|
|
|
|
const handleDelete = async () => {
|
|
try {
|
|
await refetch(); // Refetch prompts after successful deletion
|
|
} catch (error) {
|
|
console.error('Error deleting prompt:', error);
|
|
}
|
|
};
|
|
|
|
const getPromptFiles = (promptId: string | null) => {
|
|
if (!files || !promptId) return { uploadedFiles: [], downloadFiles: [] };
|
|
|
|
const promptFiles = files.filter(file => {
|
|
// Check if either file.prompt_id or promptId is null
|
|
if (file.prompt_id === null || promptId === null) return false;
|
|
return file.prompt_id.toString() === promptId.toString();
|
|
});
|
|
|
|
return {
|
|
uploadedFiles: promptFiles.filter(file => file.action === 'upload'),
|
|
downloadFiles: promptFiles.filter(file => file.action === 'download')
|
|
};
|
|
};
|
|
|
|
return (
|
|
<div className={styles.container}>
|
|
<NewPromptButton />
|
|
{loading || filesLoading ? (
|
|
<div>Loading...</div>
|
|
) : error ? (
|
|
<div>Error: {error}</div>
|
|
) : (
|
|
<div className={styles.promptList}>
|
|
{prompts.map(prompt => (
|
|
<motion.div
|
|
key={prompt.id}
|
|
className={styles.promptCard}
|
|
initial={{ opacity: 0, y: 20 }}
|
|
animate={{ opacity: 1, y: 0 }}
|
|
exit={{ opacity: 0, y: -20 }}
|
|
transition={{ duration: 0.3 }}
|
|
>
|
|
<div className={styles.promptHeader}>
|
|
<motion.button
|
|
className={styles.expandButton}
|
|
onClick={() => toggleExpand(prompt.id)}
|
|
animate={{
|
|
rotate: expandedPrompts.has(prompt.id) ? 90 : 0
|
|
}}
|
|
transition={{ duration: 0.2 }}
|
|
>
|
|
<FaChevronRight />
|
|
</motion.button>
|
|
<h2 className={styles.promptTitle}>{prompt.prompt_title}</h2>
|
|
<div className={styles.actionButtons}>
|
|
<button className={styles.iconButton} title="Edit">
|
|
<FaEdit />
|
|
</button>
|
|
<PromptItemDelete
|
|
promptId={prompt.id}
|
|
promptTitle={prompt.prompt_title}
|
|
onDelete={handleDelete}
|
|
/>
|
|
<button className={styles.iconButton} title="Repeat">
|
|
<FaRedo />
|
|
</button>
|
|
<PromptItemShare
|
|
promptId={prompt.id}
|
|
promptTitle={prompt.prompt_title}
|
|
/>
|
|
</div>
|
|
</div>
|
|
<AnimatePresence initial={false}>
|
|
{expandedPrompts.has(prompt.id) && (
|
|
<motion.div
|
|
className={styles.promptContentWrapper}
|
|
initial={{ height: 0, opacity: 0, borderTopWidth: 0 }}
|
|
animate={{
|
|
height: "auto",
|
|
opacity: 1,
|
|
borderTopWidth: 1,
|
|
transition: {
|
|
height: { duration: 0.3, ease: "easeOut" },
|
|
opacity: { duration: 0.2, delay: 0.1 },
|
|
borderTopWidth: { duration: 0.2, delay: 0.1 }
|
|
}
|
|
}}
|
|
exit={{
|
|
height: 0,
|
|
opacity: 0,
|
|
borderTopWidth: 0,
|
|
transition: {
|
|
height: { duration: 0.3, ease: "easeIn" },
|
|
opacity: { duration: 0.2 },
|
|
borderTopWidth: { duration: 0.1 }
|
|
}
|
|
}}
|
|
>
|
|
<div className={styles.promptContent}>
|
|
{formatPromptText(prompt.user_prompt).split('\n').map((line, index) => (
|
|
<p key={index}>{line}</p>
|
|
))}
|
|
</div>
|
|
<FileList
|
|
{...getPromptFiles(prompt.id)}
|
|
downloadingFiles={downloadingFiles}
|
|
onFileClick={handleFileDownload}
|
|
/>
|
|
{downloadError && (
|
|
<div className={styles.errorMessage}>
|
|
{downloadError}
|
|
</div>
|
|
)}
|
|
</motion.div>
|
|
)}
|
|
</AnimatePresence>
|
|
</motion.div>
|
|
))}
|
|
</div>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export default DashboardPromptSet;
|