1
0
Fork 0
mirror of https://github.com/muerwre/vault-frontend.git synced 2025-04-24 20:36:40 +07:00

fixed uploads with real data

This commit is contained in:
muerwre 2019-08-20 12:05:50 +07:00
parent db0a94b581
commit 38d56838f2
5 changed files with 127 additions and 58 deletions

View file

@ -1,5 +1,5 @@
import React, {
FC, useState, useCallback, useEffect
FC, useState, useCallback, useEffect,
} from 'react';
import { connect } from 'react-redux';
import assocPath from 'ramda/es/assocPath';
@ -20,6 +20,7 @@ import { moveArrItem } from '~/utils/fn';
import { IFile, IFileWithUUID } from '~/redux/types';
import * as UPLOAD_ACTIONS from '~/redux/uploads/actions';
import { selectUploads } from '~/redux/uploads/selectors';
import { UPLOAD_TARGETS, UPLOAD_TYPES, UPLOAD_SUBJECTS } from '~/redux/uploads/constants';
const mapStateToProps = (state) => {
const { editor } = selectNode(state);
@ -35,19 +36,29 @@ const mapDispatchToProps = {
type IProps = IDialogProps & ReturnType<typeof mapStateToProps> & typeof mapDispatchToProps & {};
const EditorDialogUnconnected: FC<IProps> = ({
onRequestClose, editor, uploadUploadFiles, files, statuses
onRequestClose,
editor,
uploadUploadFiles,
files,
statuses,
}) => {
const [data, setData] = useState(editor);
const eventPreventer = useCallback(event => event.preventDefault(), []);
const [temp, setTemp] = useState([]);
const onFileMove = useCallback((old_index: number, new_index: number) => {
setData(assocPath(['files'], moveArrItem(old_index, new_index, data.files), data));
}, [data, setData]);
const onFileMove = useCallback(
(old_index: number, new_index: number) => {
setData(assocPath(['files'], moveArrItem(old_index, new_index, data.files), data));
},
[data, setData]
);
const onFileAdd = useCallback((file: IFile) => {
setData(assocPath(['files'], append(file, data.files), data));
}, [data, setData]);
const onFileAdd = useCallback(
(file: IFile) => {
setData(assocPath(['files'], append(file, data.files), data));
},
[data, setData]
);
const onDrop = useCallback(
(event: React.DragEvent<HTMLFormElement>) => {
@ -59,7 +70,9 @@ const EditorDialogUnconnected: FC<IProps> = ({
(file: File): IFileWithUUID => ({
file,
temp_id: uuid(),
subject: 'editor'
subject: UPLOAD_SUBJECTS.EDITOR,
target: UPLOAD_TARGETS.NODES,
type: UPLOAD_TYPES.IMAGE,
})
);
@ -81,7 +94,9 @@ const EditorDialogUnconnected: FC<IProps> = ({
(file: File): IFileWithUUID => ({
file,
temp_id: uuid(),
subject: 'editor'
subject: UPLOAD_SUBJECTS.EDITOR,
target: UPLOAD_TARGETS.NODES,
type: UPLOAD_TYPES.IMAGE,
})
);
@ -124,11 +139,7 @@ const EditorDialogUnconnected: FC<IProps> = ({
const buttons = (
<Padder style={{ position: 'relative' }}>
<EditorPanel
data={data}
setData={setData}
onUpload={onInputChange}
/>
<EditorPanel data={data} setData={setData} onUpload={onInputChange} />
<Group horizontal>
<InputText title="Название" value={data.title} handler={setTitle} />

View file

@ -1,5 +1,5 @@
import {
call, put, takeLatest, select
call, put, takeLatest, select,
} from 'redux-saga/effects';
import { SagaIterator } from 'redux-saga';
import { push } from 'connected-react-router';
@ -15,10 +15,14 @@ import { IResultWithStatus } from '../types';
import { IUser } from './types';
export function* reqWrapper(requestAction, props = {}): ReturnType<typeof requestAction> {
const { access } = yield select(selectToken);
const access = yield select(selectToken);
console.log('firing reqWrapper');
const result = yield call(requestAction, { access, ...props });
console.log('at reqWrapper', { result });
if (result && result.status === 401) {
yield put(push(URLS.BASE));
yield put(modalShowDialog(DIALOGS.LOGIN));
@ -26,15 +30,29 @@ export function* reqWrapper(requestAction, props = {}): ReturnType<typeof reques
return result;
}
console.log('reqWrapper will return');
return result;
}
function* sendLoginRequestSaga({ username, password }: ReturnType<typeof ActionCreators.userSendLoginRequest>) {
function* sendLoginRequestSaga({
username,
password,
}: ReturnType<typeof ActionCreators.userSendLoginRequest>) {
if (!username || !password) return;
const { error, data: { token, user } }: IResultWithStatus<{ token: string; user: IUser }> = yield call(apiUserLogin, { username, password });
const {
error,
data: { token, user },
}: IResultWithStatus<{ token: string; user: IUser }> = yield call(apiUserLogin, {
username,
password,
});
if (error) { yield put(userSetLoginError(error)); return; }
if (error) {
yield put(userSetLoginError(error));
return;
}
yield put(authSetToken(token));
yield put(authSetUser({ ...user, is_user: true }));

View file

@ -7,8 +7,8 @@ export interface ITag {
}
export type IInputTextProps = DetailedHTMLProps<
InputHTMLAttributes<HTMLInputElement>,
HTMLInputElement
InputHTMLAttributes<HTMLInputElement>,
HTMLInputElement
> & {
wrapperClassName?: string;
handler?: (value: string) => void;
@ -46,6 +46,8 @@ export interface IResultWithStatus<T> {
export type UUID = string;
export type IUploadType = 'image' | 'text' | 'audio' | 'video' | 'other';
export interface IFile {
id?: UUID;
temp_id?: UUID;
@ -58,7 +60,7 @@ export interface IFile {
url: string;
size: number;
type: 'image' | 'text' | 'audio' | 'video';
type: IUploadType;
mime: string;
createdAt?: string;
@ -68,6 +70,7 @@ export interface IFile {
export interface IFileWithUUID {
temp_id?: UUID;
file: File;
subject?: string;
target: string;
type: string;
}

View file

@ -1,4 +1,4 @@
import { IFile } from '~/redux/types';
import { IFile, IUploadType } from '~/redux/types';
import { IUploadState, IUploadStatus } from './reducer';
const prefix = 'UPLOAD.';
@ -11,7 +11,7 @@ export const UPLOAD_ACTIONS = {
DROP_STATUS: `${prefix}DROP_STATUS`,
SET_STATUS: `${prefix}SET_STATUS`,
ADD_FILE: `${prefix}ADD_FILE`
ADD_FILE: `${prefix}ADD_FILE`,
};
export const EMPTY_FILE: IFile = {
@ -25,7 +25,7 @@ export const EMPTY_FILE: IFile = {
url: 'https://cdn.arstechnica.net/wp-content/uploads/2017/09/mario-collage-800x450.jpg',
size: 2400000,
type: 'image',
mime: 'image/jpeg'
mime: 'image/jpeg',
};
export const EMPTY_UPLOAD_STATUS: IUploadStatus = {
@ -37,5 +37,26 @@ export const EMPTY_UPLOAD_STATUS: IUploadStatus = {
progress: 0,
thumbnail_url: null,
type: null,
temp_id: null
temp_id: null,
};
// for targeted cancellation
export const UPLOAD_SUBJECTS = {
EDITOR: 'editor',
COMMENT: 'comment',
AVATAR: 'avatar',
};
export const UPLOAD_TARGETS = {
NODES: 'nodes',
COMMENTS: 'comments',
PROFILES: 'profiles',
OTHER: 'other',
};
export const UPLOAD_TYPES: Record<string, IUploadType> = {
IMAGE: 'image',
AUDIO: 'audio',
VIDEO: 'video',
OTHER: 'other',
};

View file

@ -1,28 +1,35 @@
import { takeEvery, all, spawn, call, put, take, fork, race } from 'redux-saga/effects';
import {
takeEvery, all, spawn, call, put, take, fork, race,
} from 'redux-saga/effects';
import { postUploadFile } from './api';
import { UPLOAD_ACTIONS } from '~/redux/uploads/constants';
import {
uploadUploadFiles, uploadSetStatus, uploadAddStatus, uploadDropStatus, uploadAddFile
uploadUploadFiles,
uploadSetStatus,
uploadAddStatus,
uploadDropStatus,
uploadAddFile,
} from './actions';
import { reqWrapper } from '../auth/sagas';
import { createUploader, uploadGetThumb, fakeUploader } from '~/utils/uploader';
import { createUploader, uploadGetThumb } from '~/utils/uploader';
import { HTTP_RESPONSES } from '~/utils/api';
import { VALIDATORS } from '~/utils/validators';
import { UUID, IFileWithUUID, IFile, IUploadProgressHandler } from '../types';
import { IFileWithUUID, IFile, IUploadProgressHandler } from '../types';
function* uploadCall({ file, temp_id, target, type, onProgress }: IFileWithUUID & { onProgress: IUploadProgressHandler }) {
// return yield call(reqWrapper, fakeUploader, { file: { url: 'some', error: 'cant do this boss' }, onProgress, mustSucceed: true });
return yield call(
reqWrapper,
postUploadFile,
{
file,
temp_id,
type,
target,
onProgress,
}
);
function* uploadCall({
file,
temp_id,
target,
type,
onProgress,
}: IFileWithUUID & { onProgress: IUploadProgressHandler }) {
return yield call(reqWrapper, postUploadFile, {
file,
temp_id,
type,
target,
onProgress,
});
}
function* onUploadProgress(chan) {
@ -43,18 +50,26 @@ function* uploadCancelWorker(id) {
}
function* uploadWorker({
file, temp_id, target, type,
file, temp_id, target, type,
}: IFileWithUUID) {
const [promise, chan] = createUploader<Partial<IFileWithUUID>, Partial<IFileWithUUID>>(uploadCall, { temp_id, target, type });
const [promise, chan] = createUploader<Partial<IFileWithUUID>, Partial<IFileWithUUID>>(
uploadCall,
{ temp_id, target, type }
);
yield fork(onUploadProgress, chan);
fork(onUploadProgress, chan);
return yield call(promise, {
temp_id, file, target, type,
temp_id,
file,
target,
type,
});
}
function* uploadFile({ file, temp_id, type, target }: IFileWithUUID) {
function* uploadFile({
file, temp_id, type, target, subject,
}: IFileWithUUID) {
if (!file.type || !VALIDATORS.IS_IMAGE_MIME(file.type)) {
return { error: 'File_Not_Image', status: HTTP_RESPONSES.BAD_REQUEST, data: {} };
}
@ -74,10 +89,13 @@ function* uploadFile({ file, temp_id, type, target }: IFileWithUUID) {
)
);
const {
result, cancel, cancel_editing, save_inventory,
} = yield race({
result: call(uploadWorker, { file, temp_id, target, type }),
const { result, cancel, cancel_editing } = yield race({
result: call(uploadWorker, {
file,
temp_id,
target,
type,
}),
cancel: call(uploadCancelWorker, temp_id),
// subject_cancel: call(uploadSubjectCancelWorker, subject)
// add here CANCEL_UPLOADS worker, that will watch for subject
@ -85,7 +103,7 @@ function* uploadFile({ file, temp_id, type, target }: IFileWithUUID) {
// save_inventory: take(INVENTORY_ACTIONS.SAVE_INVENTORY),
}) as any;
if (cancel || cancel_editing || save_inventory) {
if (cancel || cancel_editing) {
return yield put(uploadDropStatus(temp_id));
}
@ -97,8 +115,6 @@ function* uploadFile({ file, temp_id, type, target }: IFileWithUUID) {
);
}
console.log('upload', data);
yield put(
uploadSetStatus(temp_id, {
is_uploading: false,