use-vibes
Version:
Transform any DOM element into an AI-powered micro-app
181 lines • 8.63 kB
JavaScript
import * as React from 'react';
import { useFireproof, ImgFile } from 'use-fireproof';
import { ImgGenFileDrop } from '../ImgGenUtils/ImgGenFileDrop';
import { combineClasses } from '../../utils/style-utils';
import '../ImgGen.css';
/**
* Component for displaying uploaded images and allowing users to:
* 1. Upload more images to the same document
* 2. Enter a prompt to start generation
*/
export function ImgGenUploadWaiting({ document, className, classes, debug, database, onFilesAdded, onDocumentCreated, onPromptSubmit, }) {
const { database: db } = useFireproof(database || 'ImgGen');
const [prompt, setPrompt] = React.useState('');
const [inputFiles, setInputFiles] = React.useState([]);
// Get all input files from the document
React.useEffect(() => {
if (document?._files) {
const inFiles = Object.keys(document._files)
.filter((key) => key.startsWith('in'))
.sort();
setInputFiles(inFiles);
if (debug) {
console.log('[ImgGenUploadWaiting] Found input files:', inFiles);
}
}
}, [document, debug]);
// Clean up any created object URLs when unmounting
React.useEffect(() => {
const objectUrls = [];
return () => {
// Clean up any created object URLs
objectUrls.forEach((url) => URL.revokeObjectURL(url));
};
}, []);
// Handle files being uploaded - two paths: add to existing doc or create new doc
const handleFilesUploaded = async (files) => {
if (!files.length)
return;
// If we already have a document, add files to it
if (document && document._id) {
await addFilesToExistingDocument(files);
}
// Otherwise create a new document
else {
await createNewDocumentWithFiles(files);
}
};
// Create a new document with the uploaded files
const createNewDocumentWithFiles = async (files) => {
try {
// Create new document to hold the uploaded files
const newDoc = {
type: 'image',
createdAt: new Date().toISOString(),
_files: {},
};
// Add files to the document with input file keys
files.forEach((file, index) => {
// Input files are prefixed with 'in' followed by a number
// These are files uploaded by the user, not generated by AI
newDoc._files[`in${index + 1}`] = file;
});
// Save the document to get an ID
const result = await db.put(newDoc);
if (debug) {
console.log('[ImgGenUploadWaiting] Created document for uploads:', result.id);
}
// Notify parent component that files were uploaded and document created
if (onDocumentCreated && result.id) {
onDocumentCreated(result.id);
}
}
catch (error) {
console.error('[ImgGenUploadWaiting] Error creating document for uploads:', error);
}
};
// Add files to an existing document
const addFilesToExistingDocument = async (files) => {
if (!document || !document._id)
return;
try {
// Load existing document
const doc = await db.get(document._id);
if (!doc) {
console.error('[ImgGenUploadWaiting] Document not found:', document._id);
return;
}
// Find highest current input file number
let maxInputNum = 0;
if (doc._files) {
Object.keys(doc._files).forEach((key) => {
if (key.startsWith('in')) {
const num = parseInt(key.substring(2), 10);
if (!isNaN(num) && num > maxInputNum) {
maxInputNum = num;
}
}
});
}
// Add new files with incremented keys
const updatedDoc = { ...doc };
if (!updatedDoc._files)
updatedDoc._files = {};
for (let i = 0; i < files.length; i++) {
const file = files[i];
const fileKey = `in${maxInputNum + i + 1}`;
// Add file to document
updatedDoc._files[fileKey] = file;
if (debug) {
console.log(`[ImgGenUploadWaiting] Adding file to document: ${fileKey}`, file.name);
}
}
// Save updated document
const result = await db.put(updatedDoc);
if (debug) {
console.log('[ImgGenUploadWaiting] Document updated with new files:', result.id);
}
// Refresh the document to get the latest version with new files
const refreshedDoc = await db.get(result.id);
if (refreshedDoc) {
// Update input files state with the new files
const inFiles = Object.keys(refreshedDoc._files || {})
.filter((key) => key.startsWith('in'))
.sort();
setInputFiles(inFiles);
if (debug) {
console.log('[ImgGenUploadWaiting] Refreshed input files:', inFiles);
}
}
// Notify parent about files added
if (onFilesAdded) {
onFilesAdded();
}
}
catch (error) {
console.error('[ImgGenUploadWaiting] Error updating document with new files:', error);
}
};
// Handle prompt submission
const handleSubmit = (e) => {
e.preventDefault();
if (prompt.trim()) {
// Pass both the prompt and document ID to the parent component if we have a document
if (document && document._id) {
if (debug) {
console.log('[ImgGenUploadWaiting] Submitting prompt with document ID:', document._id);
}
onPromptSubmit(prompt.trim(), document._id);
}
else {
// Submit just the prompt if no document is available
if (debug) {
console.log('[ImgGenUploadWaiting] Submitting prompt with no document');
}
onPromptSubmit(prompt.trim());
}
}
};
// We no longer need this function since we're using ImgFile component
// which handles all the file display logic for us
return (React.createElement("div", { className: combineClasses('imggen-upload-waiting', className || '', classes?.uploadWaiting || '') },
React.createElement("div", { className: "imggen-placeholder-content", style: { textAlign: 'center' } },
React.createElement("h3", { style: { margin: '0 0 0.5rem 0', color: '#333' } }, "Image Generator")),
React.createElement("form", { onSubmit: handleSubmit, className: "imggen-prompt-form" },
React.createElement("input", { type: "text", value: prompt, onChange: (e) => setPrompt(e.target.value), placeholder: "Enter a prompt...", className: "imggen-prompt-input" }),
React.createElement("button", { type: "submit", disabled: !prompt.trim(), className: "imggen-prompt-submit" }, "Generate")),
inputFiles.length > 0 && (React.createElement("div", { className: "imggen-uploaded-previews" },
React.createElement("div", { className: "imggen-upload-count" },
inputFiles.length,
" ",
inputFiles.length === 1 ? 'image' : 'images',
" uploaded"),
React.createElement("div", { className: "imggen-thumbnails" },
inputFiles.slice(0, 4).map((fileKey) => (React.createElement("div", { key: fileKey, className: "imggen-thumbnail" }, document?._files && document._files[fileKey] && (React.createElement(ImgFile, { file: document._files[fileKey], alt: `Upload ${fileKey}`, className: "imggen-thumbnail-img" }))))),
inputFiles.length > 4 && (React.createElement("div", { className: "imggen-more-count" },
"+",
inputFiles.length - 4,
" more"))))),
React.createElement(ImgGenFileDrop, { className: classes?.dropZone || '', onFilesDropped: handleFilesUploaded, isActive: true, maxFiles: 10, debug: debug, addFilesMessage: "Drop images or click to upload (optional)" })));
}
//# sourceMappingURL=ImgGenUploadWaiting.js.map