Skip to content

Commit 6cf6bfc

Browse files
committed
[FEAT]: Improve Dropzone upload functionallity and add imageUrl prop to File Item
1 parent 83bc4cb commit 6cf6bfc

28 files changed

Lines changed: 1594 additions & 373 deletions

src/components/dropzone/components/Dropzone/Dropzone.tsx

Lines changed: 96 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
customValidateFile,
77
FileValidated,
88
FileValidator,
9+
UPLOADSTATUS,
910
validateFile,
1011
} from "../utils/validation.utils";
1112
import { DropzoneProps, DropzonePropsDefault } from "./DropzoneProps";
@@ -15,8 +16,15 @@ import DropzoneFooter from "../DropzoneFooter.tsx/DropzoneFooter";
1516
import { FileItemContainer } from "../../../../components/file-item";
1617
import { FileItemContainerProps } from "../../../file-item/components/FileItemContainer/FileItemContainerProps";
1718
import DropzoneLabel from "../DropzoneLabel/DropzoneLabel";
18-
import { uploadPromiseAxios } from "../utils/dropzone-ui.upload.utils";
19-
import { DropzoneLocalizerSelector } from "../../../../localization";
19+
import {
20+
FileDuiResponse,
21+
uploadPromiseAxios,
22+
UploadPromiseAxiosResponse,
23+
} from "../utils/dropzone-ui.upload.utils";
24+
import {
25+
DropzoneLocalizerSelector,
26+
ValidateErrorLocalizerSelector,
27+
} from "../../../../localization";
2028
import {
2129
FunctionLabel,
2230
LocalLabels,
@@ -47,6 +55,8 @@ const Dropzone: React.FC<DropzoneProps> = (props: DropzoneProps) => {
4755
url,
4856
config,
4957
value,
58+
onUploadStart,
59+
onUploadFinish,
5060
// onUploading,
5161
uploadingMessage,
5262
onChange,
@@ -58,6 +68,8 @@ const Dropzone: React.FC<DropzoneProps> = (props: DropzoneProps) => {
5868

5969
const DropzoneLocalizer: LocalLabels =
6070
DropzoneLocalizerSelector(localization);
71+
const ValidationErrorLocalizer: LocalLabels =
72+
ValidateErrorLocalizerSelector(localization);
6173
//console.log("color:", color);
6274
//ref to the hidden input tag
6375
const inputRef = useRef<HTMLInputElement>(null);
@@ -70,12 +82,12 @@ const Dropzone: React.FC<DropzoneProps> = (props: DropzoneProps) => {
7082
const [localMessage, setLocalMessage] = useState<string>("");
7183
//const [filesUploading, setFilesUploading] = useState<FileValidated[]>([]);
7284
//ClassName for dynamic style
73-
const [onUploadStart, setOnUploadStart] = useState<boolean>(false);
85+
const [onUploadingStart, setOnUploadingStart] = useState<boolean>(false);
7486
// const [queueFiles, setQueueFiles] = useState<FileValidated[]>([]);
7587
const classNameCreated: string = useDropzoneStyles(
7688
color,
7789
backgroundColor,
78-
maxHeight,
90+
maxHeight
7991
);
8092
const finalClassName: string = `dropzone-ui${classNameCreated}${
8193
isDragging ? ` drag` : ``
@@ -106,29 +118,44 @@ const Dropzone: React.FC<DropzoneProps> = (props: DropzoneProps) => {
106118

107119
/**
108120
* Method for uploading Files
109-
* It will set all odd file id's as valid
121+
* It will set valid or not valid in a radom way
110122
* @param files
111123
*/
112-
const fakeUpload = (file: FileValidated): Promise<FileValidated> => {
124+
const fakeUpload = (
125+
file: FileValidated
126+
): Promise<UploadPromiseAxiosResponse> => {
113127
return new Promise((resolve, reject) => {
114128
setTimeout(() => {
115-
if (file.id % 2 === 0) {
129+
const randomNumber = Math.floor(Math.random()*10);
130+
if (randomNumber % 2 === 0) {
131+
const status = true;
132+
const message = DropzoneLocalizer.fakeuploadsuccess as string;
133+
const payload = { url: "" };
116134
resolve({
117-
...file,
118-
uploadStatus: "success",
119-
uploadMessage: DropzoneLocalizer.fakeuploadsuccess as string,
120-
/* localization === "ES-es"
121-
? "EL archivo se subió correctamente"
122-
: "File was succesfully uploaded", */
135+
uploadedFile: {
136+
...file,
137+
uploadStatus: UPLOADSTATUS.success,
138+
uploadMessage: message,
139+
},
140+
serverResponse: {
141+
id: file.id,
142+
serverResponse: { status, message, payload },
143+
},
123144
});
124145
} else {
146+
const status = false;
147+
const message = DropzoneLocalizer.fakeUploadError as string;
148+
const payload = {};
125149
resolve({
126-
...file,
127-
uploadStatus: "error",
128-
uploadMessage: DropzoneLocalizer.fakeUploadError as string,
129-
/* localization === "ES-es"
130-
? "Erro al subir el archivo"
131-
: "Error on Uploading", */
150+
uploadedFile: {
151+
...file,
152+
uploadStatus: UPLOADSTATUS.error,
153+
uploadMessage: message,
154+
},
155+
serverResponse: {
156+
id: file.id,
157+
serverResponse: { status, message, payload },
158+
},
132159
});
133160
}
134161
}, 1500);
@@ -141,47 +168,52 @@ const Dropzone: React.FC<DropzoneProps> = (props: DropzoneProps) => {
141168
const uploadFiles = async (files: FileValidated[]) => {
142169
const totalNumber = files.length;
143170
const missingUpload = files.filter(
144-
(x) => x.valid && x.uploadStatus !== "success",
171+
(x) => x.valid && x.uploadStatus !== "success"
145172
).length;
146173
let totalRejected: number = 0;
147174
let currentCountUpload: number = 0;
148175
const uploadingMessenger: FunctionLabel =
149176
DropzoneLocalizer.uploadingMessage as FunctionLabel;
150177

151-
setOnUploadStart(true);
178+
setOnUploadingStart(true);
152179
if (missingUpload > 0 && url) {
153180
setLocalMessage(
154-
uploadingMessenger(`${missingUpload}/${totalNumber}`),
181+
uploadingMessenger(`${missingUpload}/${totalNumber}`)
155182
/* localization === "ES-es"
156183
? `Subiendo ${missingUpload}/${totalNumber} archivos`
157184
: `uploading ${missingUpload}/${totalNumber} files`, */
158185
);
159186

160187
let uploadStartFiles: FileValidated[] = files.map((f: FileValidated) => {
161-
if (f.uploadStatus !== "success" && f.valid) {
162-
return { ...f, uploadStatus: "uploading" };
188+
if (f.uploadStatus !== UPLOADSTATUS.success && f.valid) {
189+
return { ...f, uploadStatus: UPLOADSTATUS.uploading };
163190
} else return f;
164191
});
165192

166193
//make all uploading
167194
onChange?.(uploadStartFiles);
168195
///////
169196
let updatedList: FileValidated[] = uploadStartFiles;
197+
let serverResponses: FileDuiResponse[] = [];
198+
onUploadStart?.(
199+
uploadStartFiles.filter(
200+
(f) => f.uploadStatus === UPLOADSTATUS.uploading
201+
)
202+
);
170203
for (let i = 0; i < uploadStartFiles.length; i++) {
171204
let currentFile: FileValidated = uploadStartFiles[i];
172-
if (currentFile.uploadStatus === "uploading") {
205+
if (currentFile.uploadStatus === UPLOADSTATUS.uploading) {
173206
setLocalMessage(
174-
uploadingMessenger(`${++currentCountUpload}/${missingUpload}`),
175-
176-
/* localization === "ES-es"
177-
? `Subiendo ${++currentCountUpload}/${missingUpload} archivos`
178-
: `Uploading ${++currentCountUpload}/${missingUpload} files...`, */
207+
uploadingMessenger(`${++currentCountUpload}/${missingUpload}`)
179208
);
180-
// const uploadedFile = await fakeUpload(currentFile);
181209

182-
const uploadedFile: FileValidated = fakeUploading
183-
? await fakeUpload(currentFile)
184-
: await uploadPromiseAxios(currentFile, url, method, config);
210+
const { serverResponse, uploadedFile }: UploadPromiseAxiosResponse =
211+
fakeUploading
212+
? await fakeUpload(currentFile)
213+
: await uploadPromiseAxios(currentFile, url, method, config);
214+
215+
serverResponses.push(serverResponse);
216+
185217
if (uploadedFile.uploadStatus === "error") {
186218
totalRejected++;
187219
}
@@ -195,29 +227,31 @@ const Dropzone: React.FC<DropzoneProps> = (props: DropzoneProps) => {
195227
onChange?.(updatedList);
196228
}
197229
}
230+
198231
// upload group finished :D
232+
onUploadFinish?.(serverResponses);
199233
const finishUploadMessenger: FunctionLabel =
200234
DropzoneLocalizer.uploadFinished as FunctionLabel;
201235
setLocalMessage(
202-
finishUploadMessenger(missingUpload - totalRejected, totalRejected),
236+
finishUploadMessenger(missingUpload - totalRejected, totalRejected)
203237
/* localization === "ES-es"
204238
? `Archivos subidos: ${missingUpload - totalRejected}, Rechazados: ${totalRejected}`
205239
: `Uloaded files: ${missingUpload - totalRejected}, Rejected: ${totalRejected}`,
206240
*/
207241
);
208242
setTimeout(() => {
209-
setOnUploadStart(false);
243+
setOnUploadingStart(false);
210244
}, 2300);
211245
//console.log("queueFiles files:", queueFiles);
212246
} else {
213247
setLocalMessage(
214-
DropzoneLocalizer.noFilesMessage as string,
248+
DropzoneLocalizer.noFilesMessage as string
215249
/* localization === "ES-es"
216250
? `No hay archivos válidos pendientes por subir`
217251
: `There is not any missing valid file for uploading`, */
218252
);
219253
setTimeout(() => {
220-
setOnUploadStart(false);
254+
setOnUploadingStart(false);
221255
}, 2300);
222256
}
223257
};
@@ -238,19 +272,19 @@ const Dropzone: React.FC<DropzoneProps> = (props: DropzoneProps) => {
238272
* @param evt
239273
*/
240274
const kamui: React.DragEventHandler<HTMLDivElement> = async (
241-
evt: React.DragEvent<HTMLDivElement>,
275+
evt: React.DragEvent<HTMLDivElement>
242276
): Promise<void> => {
243277
evt.stopPropagation();
244278
evt.preventDefault();
245-
if (onUploadStart) {
279+
if (onUploadingStart) {
246280
setIsDragging(false);
247281
return;
248282
}
249283
let fileList: FileList = evt.dataTransfer.files;
250284
const remainingValids: number = (maxFiles || 7) - numberOfValidFiles;
251285
const output: FileValidated[] = fileListvalidator(
252286
fileList,
253-
remainingValids,
287+
remainingValids
254288
);
255289
if (!disableRipple) {
256290
createRipple(evt, color as string);
@@ -260,34 +294,44 @@ const Dropzone: React.FC<DropzoneProps> = (props: DropzoneProps) => {
260294
};
261295

262296
const handleOnChangeInput: React.ChangeEventHandler<HTMLInputElement> = (
263-
evt: React.ChangeEvent<HTMLInputElement>,
297+
evt: React.ChangeEvent<HTMLInputElement>
264298
): void => {
265-
if (onUploadStart) {
299+
if (onUploadingStart) {
266300
return;
267301
}
268302
let fileList: FileList = evt.target.files as FileList;
269303
const remainingValids: number = (maxFiles || 7) - numberOfValidFiles;
270304
const output: FileValidated[] = fileListvalidator(
271305
fileList,
272-
remainingValids,
306+
remainingValids
273307
);
274308
handleFilesChange(output);
275309
};
276310

277311
//local function validator
278312
const fileListvalidator = (
279313
preValidatedFiles: FileList,
280-
remainingValids: number,
314+
remainingValids: number
281315
): FileValidated[] => {
282316
const output: FileValidated[] = [];
283317
let countdown: number = remainingValids;
284318
for (let i = 0, f: File; (f = preValidatedFiles[i]); i++) {
285319
let validatedFile: FileValidated = validator
286320
? customValidateFile(f, validator)
287-
: validateFile(f, localValidator);
288-
321+
: validateFile(f, localValidator, ValidationErrorLocalizer);
322+
//console.log("=>", validateFile);
289323
if (validatedFile.valid) {
290-
validatedFile.valid = countdown > 0;
324+
//not valid due to file count limit
325+
const valid = countdown > 0;
326+
validatedFile.valid = valid;
327+
//add error about amount
328+
if (!valid) {
329+
const MaxFileErrorMessenger: FunctionLabel =
330+
ValidationErrorLocalizer.maxFileCount as FunctionLabel;
331+
validatedFile.errors = validatedFile.errors
332+
? [...validatedFile.errors, MaxFileErrorMessenger(maxFiles || 7)]
333+
: [MaxFileErrorMessenger(maxFiles || 7)];
334+
}
291335
countdown--;
292336
}
293337
output.push(validatedFile);
@@ -301,23 +345,23 @@ const Dropzone: React.FC<DropzoneProps> = (props: DropzoneProps) => {
301345
}
302346
};
303347
const handleDragEnter: React.DragEventHandler<HTMLDivElement> = (
304-
evt: React.DragEvent<HTMLDivElement>,
348+
evt: React.DragEvent<HTMLDivElement>
305349
): void => {
306350
evt.stopPropagation();
307351
evt.preventDefault();
308352
evt.dataTransfer.dropEffect = "link";
309353
setIsDragging(true);
310354
};
311355
const handleDragLeave: React.DragEventHandler<HTMLDivElement> = (
312-
evt: React.DragEvent<HTMLDivElement>,
356+
evt: React.DragEvent<HTMLDivElement>
313357
): void => {
314358
evt.stopPropagation();
315359
evt.preventDefault();
316360
evt.dataTransfer.dropEffect = "link";
317361
setIsDragging(false);
318362
};
319363
function handleClick<T extends HTMLDivElement>(
320-
e: React.MouseEvent<T, MouseEvent>,
364+
e: React.MouseEvent<T, MouseEvent>
321365
): void {
322366
let referenceInput = inputRef.current;
323367
referenceInput?.click();
@@ -371,7 +415,7 @@ const Dropzone: React.FC<DropzoneProps> = (props: DropzoneProps) => {
371415
{footer && (
372416
<DropzoneFooter
373417
accept={accept}
374-
message={onUploadStart ? localMessage : undefined}
418+
message={onUploadingStart ? localMessage : undefined}
375419
localization={localization}
376420
/>
377421
)}

0 commit comments

Comments
 (0)