mirror of
https://github.com/muerwre/vault-frontend.git
synced 2025-04-25 12:56:41 +07:00
working upload saga?
This commit is contained in:
parent
3872ff5903
commit
d73437d8c6
8 changed files with 153 additions and 42 deletions
|
@ -1,13 +1,13 @@
|
|||
import React, { FC } from 'react';
|
||||
import * as styles from './styles.scss';
|
||||
import { INode } from '~/redux/types';
|
||||
import { INode, IFileWithUUID } from '~/redux/types';
|
||||
|
||||
interface IProps {
|
||||
data: INode;
|
||||
setData: (val: INode) => void;
|
||||
onUpload: (val: File[]) => void;
|
||||
onUpload: (val: IFileWithUUID[]) => void;
|
||||
}
|
||||
|
||||
const EditorPanel: FC<IProps> = ({}) => <div className={styles.panel} />;
|
||||
const EditorPanel: FC<IProps> = () => <div className={styles.panel} />;
|
||||
|
||||
export { EditorPanel };
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
import React, { FC, useCallback, useEffect, useState } from 'react';
|
||||
import React, {
|
||||
FC, useCallback, useEffect, useState
|
||||
} from 'react';
|
||||
import uuid from 'uuid4';
|
||||
import { INode, IFileWithUUID } from '~/redux/types';
|
||||
import * as styles from './styles.scss';
|
||||
import uuid from 'uuid4';
|
||||
|
||||
interface IProps {
|
||||
data: INode;
|
||||
|
@ -14,20 +16,22 @@ const ImageEditor: FC<IProps> = ({ data, setData, onUpload }) => {
|
|||
const [temp, setTemp] = useState([]);
|
||||
|
||||
const onDrop = useCallback(
|
||||
(event: DragEvent) => {
|
||||
(event: React.DragEvent<HTMLFormElement>) => {
|
||||
event.preventDefault();
|
||||
|
||||
if (!event.dataTransfer || !event.dataTransfer.files || !event.dataTransfer.files.length)
|
||||
return;
|
||||
if (!event.dataTransfer || !event.dataTransfer.files || !event.dataTransfer.files.length) return;
|
||||
|
||||
const files: IFileWithUUID[] = Array.from(event.dataTransfer.files).map(
|
||||
(file: File): IFileWithUUID => ({
|
||||
file,
|
||||
temp_id: uuid(),
|
||||
subject: 'editor',
|
||||
subject: 'editor'
|
||||
})
|
||||
);
|
||||
|
||||
const temps = files.map(file => file.temp_id);
|
||||
|
||||
setTemp(temps);
|
||||
onUpload(files);
|
||||
},
|
||||
[onUpload]
|
||||
|
@ -43,10 +47,13 @@ const ImageEditor: FC<IProps> = ({ data, setData, onUpload }) => {
|
|||
(file: File): IFileWithUUID => ({
|
||||
file,
|
||||
temp_id: uuid(),
|
||||
subject: 'editor',
|
||||
subject: 'editor'
|
||||
})
|
||||
);
|
||||
|
||||
const temps = files.map(file => file.temp_id);
|
||||
|
||||
setTemp(temps);
|
||||
onUpload(files);
|
||||
},
|
||||
[onUpload]
|
||||
|
|
|
@ -2,13 +2,13 @@ import { takeEvery, all, spawn, call, put, take, fork, race } from 'redux-saga/e
|
|||
import { UPLOAD_ACTIONS } from '~/redux/uploads/constants';
|
||||
import { uploadUploadFiles, uploadSetStatus, uploadAddStatus, uploadDropStatus } from './actions';
|
||||
import { reqWrapper } from '../auth/sagas';
|
||||
import { createUploader, uploadGetThumb } from '~/utils/uploader';
|
||||
import { createUploader, uploadGetThumb, fakeUploader } from '~/utils/uploader';
|
||||
import { HTTP_RESPONSES } from '~/utils/api';
|
||||
import { VALIDATORS } from '~/utils/validators';
|
||||
import { UUID, IFileWithUUID } from '../types';
|
||||
|
||||
function* uploadCall({ temp_id, onProgress, file }) {
|
||||
return yield call(reqWrapper, console.log, { file, onProgress });
|
||||
return yield call(reqWrapper, fakeUploader, { file: { url: 'some', error: 'cant do this boss' }, onProgress, mustSucceed: true });
|
||||
}
|
||||
|
||||
function* onUploadProgress(chan) {
|
||||
|
@ -41,7 +41,7 @@ function* uploadFile({ file, temp_id }: IFileWithUUID) {
|
|||
|
||||
const preview = yield call(uploadGetThumb, file);
|
||||
|
||||
yield put(
|
||||
yield put(
|
||||
uploadAddStatus(
|
||||
// replace with the one, what adds file upload status
|
||||
temp_id,
|
||||
|
@ -53,7 +53,9 @@ function* uploadFile({ file, temp_id }: IFileWithUUID) {
|
|||
)
|
||||
);
|
||||
|
||||
const { result, cancel, cancel_editing, save_inventory } = yield race({
|
||||
const {
|
||||
result, cancel, cancel_editing, save_inventory,
|
||||
} = yield race({
|
||||
result: call(uploadWorker, file, temp_id),
|
||||
cancel: call(uploadCancelWorker, temp_id),
|
||||
// subject_cancel: call(uploadSubjectCancelWorker, subject)
|
||||
|
|
|
@ -1,11 +1,18 @@
|
|||
import { eventChannel, END } from 'redux-saga';
|
||||
import uuid from 'uuid4';
|
||||
import { eventChannel, END, EventChannel } from 'redux-saga';
|
||||
import { VALIDATORS } from '~/utils/validators';
|
||||
import { IResultWithStatus, IFile } from '~/redux/types';
|
||||
import { HTTP_RESPONSES } from './api';
|
||||
|
||||
export const IMAGE_MIME_TYPES = ['image/jpeg', 'image/png', 'image/gif', 'image/jpg'];
|
||||
|
||||
export function createUploader<T extends {}, R extends {}>
|
||||
(callback: (args: any) => any, payload: R):
|
||||
[(args: T) => (args: T & { onProgress: (current: number, total: number) => void }) => any, EventChannel<any>] {
|
||||
export function createUploader<T extends {}, R extends {}>(
|
||||
callback: (args: any) => any,
|
||||
payload: R
|
||||
): [
|
||||
(args: T) => (args: T & { onProgress: (current: number, total: number) => void }) => any,
|
||||
EventChannel<any>
|
||||
] {
|
||||
let emit;
|
||||
|
||||
const chan = eventChannel(emitter => {
|
||||
|
@ -14,7 +21,9 @@ export function createUploader<T extends {}, R extends {}>
|
|||
});
|
||||
|
||||
const onProgress = (current: number, total: number): void => {
|
||||
emit(current >= total ? END : { ...payload, progress: parseFloat((current / total).toFixed(1)) });
|
||||
emit(
|
||||
current >= total ? END : { ...payload, progress: parseFloat((current / total).toFixed(1)) }
|
||||
);
|
||||
};
|
||||
|
||||
const wrappedCallback = args => callback({ ...args, onProgress });
|
||||
|
@ -31,3 +40,30 @@ export const uploadGetThumb = async file => {
|
|||
reader.readAsDataURL(file);
|
||||
});
|
||||
};
|
||||
|
||||
export const fakeUploader = ({
|
||||
file,
|
||||
onProgress,
|
||||
mustSucceed,
|
||||
}: {
|
||||
file: { url?: string; error?: string };
|
||||
onProgress: (current: number, total: number) => void;
|
||||
mustSucceed: boolean;
|
||||
}): Promise<IResultWithStatus<IFile>> => {
|
||||
const { url, error } = file;
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
setTimeout(() => {
|
||||
onProgress(1, 2);
|
||||
}, 100);
|
||||
|
||||
setTimeout(() => {
|
||||
onProgress(2, 2);
|
||||
if (mustSucceed) {
|
||||
resolve({ status: HTTP_RESPONSES.CREATED, data: { id: uuid() } });
|
||||
} else {
|
||||
reject({ response: { statusText: error } });
|
||||
}
|
||||
}, 500);
|
||||
});
|
||||
};
|
||||
|
|
|
@ -1,28 +1,23 @@
|
|||
import { IMAGE_MIME_TYPES } from '~/utils/uploader';
|
||||
import isValid from 'date-fns/isValid';
|
||||
import { IAddress } from '~/redux/types';
|
||||
import { IMAGE_MIME_TYPES } from '~/utils/uploader';
|
||||
|
||||
const isValidEmail = (email: string): boolean =>
|
||||
!!email &&
|
||||
String(email) &&
|
||||
!!String(email).match(
|
||||
/^[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/,
|
||||
const isValidEmail = (email: string): boolean => !!email
|
||||
&& String(email)
|
||||
&& !!String(email).match(
|
||||
/^[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/
|
||||
);
|
||||
|
||||
const isLikeEmail = (email: string): boolean =>
|
||||
!!email && String(email) && !!String(email).match(/^([^\@]+)@([^\@]+)\.([^\@]+)$$/);
|
||||
const isLikeEmail = (email: string): boolean => !!email && String(email) && !!String(email).match(/^([^\@]+)@([^\@]+)\.([^\@]+)$$/);
|
||||
|
||||
const isNonEmpty = (value: string): boolean => !!value && value.trim().length > 0;
|
||||
const isLikePhone = isNonEmpty;
|
||||
|
||||
const isAtLeast = (length: number, value: string): boolean =>
|
||||
!!value && value.trim().length >= length;
|
||||
const isAtLeast = (length: number, value: string): boolean => !!value && value.trim().length >= length;
|
||||
|
||||
const isMimeOfImage = (mime): boolean => !!mime && IMAGE_MIME_TYPES.indexOf(mime) >= 0;
|
||||
|
||||
const isDate = (val: string): boolean => !!val && isValid(new Date(val));
|
||||
const isStringDate = (val: string): boolean => !!val && !!val.match(/^[\d]{2,4}\-[\d]{2}-[\d]{2}/);
|
||||
const isAddrWithRaw = ({ raw }: Partial<IAddress>): boolean => !!raw && isNonEmpty(raw);
|
||||
|
||||
export const VALIDATORS = {
|
||||
EMAIL: isValidEmail,
|
||||
|
@ -33,7 +28,5 @@ export const VALIDATORS = {
|
|||
IS_IMAGE_MIME: isMimeOfImage,
|
||||
IS_DATE: isDate,
|
||||
IS_STRINGY_DATE: isStringDate,
|
||||
IS_ADDRESS_WITH_RAW: isAddrWithRaw,
|
||||
EVOLVE: (validator: (val: any) => boolean, error: string) => (val: any) =>
|
||||
!val || !validator(val) ? error : null,
|
||||
EVOLVE: (validator: (val: any) => boolean, error: string) => (val: any) => (!val || !validator(val) ? error : null)
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue