design: implement multi-file selection support for research and existing-project onboarding uploaders
This commit is contained in:
@@ -211,9 +211,14 @@ function EntrepResearch({ files = [], brief = "", onChange }) {
|
|||||||
const [progress, setProgress] = useState(0);
|
const [progress, setProgress] = useState(0);
|
||||||
|
|
||||||
const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
const selected = e.target.files?.[0];
|
const selectedFiles = Array.from(e.target.files ?? []);
|
||||||
if (!selected) return;
|
if (selectedFiles.length === 0) return;
|
||||||
setUploading(selected.name);
|
|
||||||
|
const label =
|
||||||
|
selectedFiles.length === 1
|
||||||
|
? selectedFiles[0].name
|
||||||
|
: `${selectedFiles.length} files`;
|
||||||
|
setUploading(label);
|
||||||
setProgress(0);
|
setProgress(0);
|
||||||
|
|
||||||
// Simulate a smooth upload progress bar
|
// Simulate a smooth upload progress bar
|
||||||
@@ -222,14 +227,12 @@ function EntrepResearch({ files = [], brief = "", onChange }) {
|
|||||||
if (p >= 100) {
|
if (p >= 100) {
|
||||||
clearInterval(interval);
|
clearInterval(interval);
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
|
const newFiles = selectedFiles.map((f) => ({
|
||||||
|
name: f.name,
|
||||||
|
size: `${(f.size / 1024).toFixed(1)} KB`,
|
||||||
|
}));
|
||||||
onChange({
|
onChange({
|
||||||
files: [
|
files: [...files, ...newFiles],
|
||||||
...files,
|
|
||||||
{
|
|
||||||
name: selected.name,
|
|
||||||
size: `${(selected.size / 1024).toFixed(1)} KB`,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
});
|
||||||
setUploading(null);
|
setUploading(null);
|
||||||
}, 300);
|
}, 300);
|
||||||
@@ -287,6 +290,7 @@ function EntrepResearch({ files = [], brief = "", onChange }) {
|
|||||||
<input
|
<input
|
||||||
type="file"
|
type="file"
|
||||||
onChange={handleFileChange}
|
onChange={handleFileChange}
|
||||||
|
multiple
|
||||||
style={{ display: "none" }}
|
style={{ display: "none" }}
|
||||||
/>
|
/>
|
||||||
{uploading ? (
|
{uploading ? (
|
||||||
@@ -473,8 +477,9 @@ function EntrepExisting({ checklist = {}, onChange }) {
|
|||||||
key: "designs" | "code",
|
key: "designs" | "code",
|
||||||
e: React.ChangeEvent<HTMLInputElement>,
|
e: React.ChangeEvent<HTMLInputElement>,
|
||||||
) => {
|
) => {
|
||||||
const selected = e.target.files?.[0];
|
const selectedFiles = Array.from(e.target.files ?? []);
|
||||||
if (!selected) return;
|
if (selectedFiles.length === 0) return;
|
||||||
|
|
||||||
setUploading(key);
|
setUploading(key);
|
||||||
setProgress(0);
|
setProgress(0);
|
||||||
|
|
||||||
@@ -484,16 +489,14 @@ function EntrepExisting({ checklist = {}, onChange }) {
|
|||||||
clearInterval(interval);
|
clearInterval(interval);
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
const currentFiles = checklist[`${key}Files`] || [];
|
const currentFiles = checklist[`${key}Files`] || [];
|
||||||
|
const newFiles = selectedFiles.map((f) => ({
|
||||||
|
name: f.name,
|
||||||
|
size: `${(f.size / 1024).toFixed(1)} KB`,
|
||||||
|
}));
|
||||||
onChange({
|
onChange({
|
||||||
checklist: {
|
checklist: {
|
||||||
...checklist,
|
...checklist,
|
||||||
[`${key}Files`]: [
|
[`${key}Files`]: [...currentFiles, ...newFiles],
|
||||||
...currentFiles,
|
|
||||||
{
|
|
||||||
name: selected.name,
|
|
||||||
size: `${(selected.size / 1024).toFixed(1)} KB`,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
setUploading(null);
|
setUploading(null);
|
||||||
@@ -546,6 +549,7 @@ function EntrepExisting({ checklist = {}, onChange }) {
|
|||||||
<input
|
<input
|
||||||
type="file"
|
type="file"
|
||||||
onChange={(e) => handleFileChange(key, e)}
|
onChange={(e) => handleFileChange(key, e)}
|
||||||
|
multiple
|
||||||
style={{ display: "none" }}
|
style={{ display: "none" }}
|
||||||
/>
|
/>
|
||||||
{uploading === key ? (
|
{uploading === key ? (
|
||||||
|
|||||||
Reference in New Issue
Block a user