mirror of
https://github.com/muerwre/vault-frontend.git
synced 2025-04-25 12:56:41 +07:00
player: renamed apiGetEmbedYoutube
This commit is contained in:
parent
4da55dcd21
commit
7031084b09
7 changed files with 130 additions and 140 deletions
|
@ -1,33 +1,18 @@
|
||||||
import { INode, IResultWithStatus } from '~/redux/types';
|
import { api, cleanResult } from '~/utils/api';
|
||||||
import { api, configWithToken, errorMiddleware, resultMiddleware } from '~/utils/api';
|
|
||||||
import { API } from '~/constants/api';
|
import { API } from '~/constants/api';
|
||||||
|
import {
|
||||||
|
ApiGetNodesOfTagRequest,
|
||||||
|
ApiGetNodesOfTagResult,
|
||||||
|
ApiGetTagSuggestionsRequest,
|
||||||
|
ApiGetTagSuggestionsResult,
|
||||||
|
} from '~/redux/tag/types';
|
||||||
|
|
||||||
export const getTagNodes = ({
|
export const apiGetNodesOfTag = ({ tag, offset, limit }: ApiGetNodesOfTagRequest) =>
|
||||||
access,
|
|
||||||
tag,
|
|
||||||
offset,
|
|
||||||
limit,
|
|
||||||
}: {
|
|
||||||
access: string;
|
|
||||||
tag: string;
|
|
||||||
offset: number;
|
|
||||||
limit: number;
|
|
||||||
}): Promise<IResultWithStatus<{ nodes: INode[]; count: number }>> =>
|
|
||||||
api
|
api
|
||||||
.get(API.TAG.NODES, configWithToken(access, { params: { name: tag, offset, limit } }))
|
.get<ApiGetNodesOfTagResult>(API.TAG.NODES, { params: { name: tag, offset, limit } })
|
||||||
.then(resultMiddleware)
|
.then(cleanResult);
|
||||||
.catch(errorMiddleware);
|
|
||||||
|
|
||||||
export const getTagAutocomplete = ({
|
export const apiGetTagSuggestions = ({ search, exclude }: ApiGetTagSuggestionsRequest) =>
|
||||||
search,
|
|
||||||
exclude,
|
|
||||||
access,
|
|
||||||
}: {
|
|
||||||
access: string;
|
|
||||||
search: string;
|
|
||||||
exclude: string[];
|
|
||||||
}): Promise<IResultWithStatus<{ tags: string[] }>> =>
|
|
||||||
api
|
api
|
||||||
.get(API.TAG.AUTOCOMPLETE, configWithToken(access, { params: { search, exclude } }))
|
.get<ApiGetTagSuggestionsResult>(API.TAG.AUTOCOMPLETE, { params: { search, exclude } })
|
||||||
.then(resultMiddleware)
|
.then(cleanResult);
|
||||||
.catch(errorMiddleware);
|
|
||||||
|
|
|
@ -6,48 +6,43 @@ import {
|
||||||
tagSetAutocomplete,
|
tagSetAutocomplete,
|
||||||
tagSetNodes,
|
tagSetNodes,
|
||||||
} from '~/redux/tag/actions';
|
} from '~/redux/tag/actions';
|
||||||
import { wrap } from '~/redux/auth/sagas';
|
|
||||||
import { selectTagNodes } from '~/redux/tag/selectors';
|
import { selectTagNodes } from '~/redux/tag/selectors';
|
||||||
import { getTagAutocomplete, getTagNodes } from '~/redux/tag/api';
|
import { apiGetTagSuggestions, apiGetNodesOfTag } from '~/redux/tag/api';
|
||||||
import { Unwrap } from '~/redux/types';
|
import { Unwrap } from '~/redux/types';
|
||||||
|
|
||||||
function* loadTagNodes({ tag }: ReturnType<typeof tagLoadNodes>) {
|
function* loadTagNodes({ tag }: ReturnType<typeof tagLoadNodes>) {
|
||||||
yield put(tagSetNodes({ isLoading: true }));
|
yield put(tagSetNodes({ isLoading: true, list: [] }));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const { list }: ReturnType<typeof selectTagNodes> = yield select(selectTagNodes);
|
const { list }: ReturnType<typeof selectTagNodes> = yield select(selectTagNodes);
|
||||||
const { data, error }: Unwrap<typeof getTagNodes> = yield call(wrap, getTagNodes, {
|
const data: Unwrap<typeof apiGetNodesOfTag> = yield call(apiGetNodesOfTag, {
|
||||||
tag,
|
tag,
|
||||||
limit: 18,
|
limit: 18,
|
||||||
offset: list.length,
|
offset: list.length,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (error) throw new Error(error);
|
yield put(tagSetNodes({ list: [...list, ...data.nodes], count: data.count }));
|
||||||
|
} catch {
|
||||||
yield put(tagSetNodes({ isLoading: false, list: [...list, ...data.nodes], count: data.count }));
|
} finally {
|
||||||
} catch (e) {
|
|
||||||
console.log(e);
|
|
||||||
yield put(tagSetNodes({ isLoading: false }));
|
yield put(tagSetNodes({ isLoading: false }));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function* loadAutocomplete({ search, exclude }: ReturnType<typeof tagLoadAutocomplete>) {
|
function* loadAutocomplete({ search, exclude }: ReturnType<typeof tagLoadAutocomplete>) {
|
||||||
if (search.length < 3) return;
|
if (search.length < 2) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
yield put(tagSetAutocomplete({ isLoading: true }));
|
yield put(tagSetAutocomplete({ isLoading: true }));
|
||||||
yield delay(100);
|
yield delay(200);
|
||||||
|
|
||||||
const { data, error }: Unwrap<typeof getTagAutocomplete> = yield call(
|
const data: Unwrap<typeof apiGetTagSuggestions> = yield call(apiGetTagSuggestions, {
|
||||||
wrap,
|
search,
|
||||||
getTagAutocomplete,
|
exclude,
|
||||||
{ search, exclude }
|
});
|
||||||
);
|
|
||||||
|
|
||||||
if (error) throw new Error(error);
|
yield put(tagSetAutocomplete({ options: data.tags }));
|
||||||
|
} catch {
|
||||||
yield put(tagSetAutocomplete({ options: data.tags, isLoading: false }));
|
} finally {
|
||||||
} catch (e) {
|
|
||||||
yield put(tagSetAutocomplete({ isLoading: false }));
|
yield put(tagSetAutocomplete({ isLoading: false }));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
16
src/redux/tag/types.ts
Normal file
16
src/redux/tag/types.ts
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
import { INode } from '~/redux/types';
|
||||||
|
|
||||||
|
export type ApiGetNodesOfTagRequest = {
|
||||||
|
tag: string;
|
||||||
|
offset: number;
|
||||||
|
limit: number;
|
||||||
|
};
|
||||||
|
export type ApiGetNodesOfTagResult = { nodes: INode[]; count: number };
|
||||||
|
|
||||||
|
export type ApiGetTagSuggestionsRequest = {
|
||||||
|
search: string;
|
||||||
|
exclude: string[];
|
||||||
|
};
|
||||||
|
export type ApiGetTagSuggestionsResult = {
|
||||||
|
tags: string[];
|
||||||
|
};
|
|
@ -1,31 +1,20 @@
|
||||||
import {
|
import { api, cleanResult } from '~/utils/api';
|
||||||
IResultWithStatus, IFile, IUploadProgressHandler, IFileWithUUID,
|
|
||||||
} from '~/redux/types';
|
|
||||||
import {
|
|
||||||
api, configWithToken, resultMiddleware, errorMiddleware,
|
|
||||||
} from '~/utils/api';
|
|
||||||
|
|
||||||
import { API } from '~/constants/api';
|
import { API } from '~/constants/api';
|
||||||
|
import { ApiUploadFileRequest, ApiUploadFIleResult } from '~/redux/uploads/types';
|
||||||
|
|
||||||
export const postUploadFile = ({
|
export const apiUploadFile = ({
|
||||||
access,
|
|
||||||
file,
|
file,
|
||||||
target = 'others',
|
target = 'others',
|
||||||
type = 'image',
|
type = 'image',
|
||||||
onProgress,
|
onProgress,
|
||||||
}: IFileWithUUID & {
|
}: ApiUploadFileRequest) => {
|
||||||
access: string;
|
|
||||||
onProgress: IUploadProgressHandler;
|
|
||||||
}): Promise<IResultWithStatus<IFile>> => {
|
|
||||||
const data = new FormData();
|
const data = new FormData();
|
||||||
data.append('file', file);
|
data.append('file', file);
|
||||||
|
|
||||||
return api
|
return api
|
||||||
.post(
|
.post<ApiUploadFIleResult>(API.USER.UPLOAD(target, type), data, {
|
||||||
API.USER.UPLOAD(target, type),
|
onUploadProgress: onProgress,
|
||||||
data,
|
})
|
||||||
configWithToken(access, { onUploadProgress: onProgress })
|
.then(cleanResult);
|
||||||
)
|
|
||||||
.then(resultMiddleware)
|
|
||||||
.catch(errorMiddleware);
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
import { takeEvery, all, spawn, call, put, take, fork, race } from 'redux-saga/effects';
|
import { SagaIterator } from 'redux-saga';
|
||||||
import { postUploadFile } from './api';
|
import { all, call, fork, put, race, spawn, take, takeEvery } from 'redux-saga/effects';
|
||||||
import { UPLOAD_ACTIONS, FILE_MIMES } from '~/redux/uploads/constants';
|
import { apiUploadFile } from './api';
|
||||||
|
import { FILE_MIMES, UPLOAD_ACTIONS } from '~/redux/uploads/constants';
|
||||||
import {
|
import {
|
||||||
uploadUploadFiles,
|
uploadAddFile,
|
||||||
uploadSetStatus,
|
|
||||||
uploadAddStatus,
|
uploadAddStatus,
|
||||||
uploadDropStatus,
|
uploadDropStatus,
|
||||||
uploadAddFile,
|
uploadSetStatus,
|
||||||
|
uploadUploadFiles,
|
||||||
} from './actions';
|
} from './actions';
|
||||||
import { wrap } from '../auth/sagas';
|
|
||||||
import { createUploader, uploadGetThumb } from '~/utils/uploader';
|
import { createUploader, uploadGetThumb } from '~/utils/uploader';
|
||||||
import { HTTP_RESPONSES } from '~/utils/api';
|
import { HTTP_RESPONSES } from '~/utils/api';
|
||||||
import { IFileWithUUID, IFile, IUploadProgressHandler } from '../types';
|
import { IFileWithUUID, IUploadProgressHandler, Unwrap } from '../types';
|
||||||
|
|
||||||
function* uploadCall({
|
function* uploadCall({
|
||||||
file,
|
file,
|
||||||
|
@ -20,13 +20,15 @@ function* uploadCall({
|
||||||
type,
|
type,
|
||||||
onProgress,
|
onProgress,
|
||||||
}: IFileWithUUID & { onProgress: IUploadProgressHandler }) {
|
}: IFileWithUUID & { onProgress: IUploadProgressHandler }) {
|
||||||
return yield call(wrap, postUploadFile, {
|
const data: Unwrap<typeof apiUploadFile> = yield call(apiUploadFile, {
|
||||||
file,
|
file,
|
||||||
temp_id,
|
temp_id,
|
||||||
type,
|
type,
|
||||||
target,
|
target,
|
||||||
onProgress,
|
onProgress,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
function* onUploadProgress(chan) {
|
function* onUploadProgress(chan) {
|
||||||
|
@ -46,7 +48,12 @@ function* uploadCancelWorker(id) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function* uploadWorker({ file, temp_id, target, type }: IFileWithUUID) {
|
function* uploadWorker({
|
||||||
|
file,
|
||||||
|
temp_id,
|
||||||
|
target,
|
||||||
|
type,
|
||||||
|
}: IFileWithUUID): SagaIterator<Unwrap<typeof uploadCall>> {
|
||||||
const [promise, chan] = createUploader<Partial<IFileWithUUID>, Partial<IFileWithUUID>>(
|
const [promise, chan] = createUploader<Partial<IFileWithUUID>, Partial<IFileWithUUID>>(
|
||||||
uploadCall,
|
uploadCall,
|
||||||
{ temp_id, target, type }
|
{ temp_id, target, type }
|
||||||
|
@ -63,77 +70,74 @@ function* uploadWorker({ file, temp_id, target, type }: IFileWithUUID) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function* uploadFile({ file, temp_id, type, target, onSuccess, onFail }: IFileWithUUID) {
|
function* uploadFile({ file, temp_id, type, target, onSuccess, onFail }: IFileWithUUID) {
|
||||||
if (!file.type || !FILE_MIMES[type] || !FILE_MIMES[type].includes(file.type)) {
|
if (!temp_id) return;
|
||||||
return {
|
|
||||||
error: 'File_Not_Image',
|
|
||||||
status: HTTP_RESPONSES.BAD_REQUEST,
|
|
||||||
data: {},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const preview = yield call(uploadGetThumb, file);
|
try {
|
||||||
|
if (!file.type || !FILE_MIMES[type] || !FILE_MIMES[type].includes(file.type)) {
|
||||||
|
return {
|
||||||
|
error: 'File_Not_Image',
|
||||||
|
status: HTTP_RESPONSES.BAD_REQUEST,
|
||||||
|
data: {},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
yield put(
|
const preview: Unwrap<typeof uploadGetThumb> = yield call(uploadGetThumb, file);
|
||||||
uploadAddStatus(
|
|
||||||
// replace with the one, what adds file upload status
|
yield put(
|
||||||
temp_id,
|
uploadAddStatus(temp_id, {
|
||||||
{
|
preview: preview.toString(),
|
||||||
preview,
|
|
||||||
is_uploading: true,
|
is_uploading: true,
|
||||||
temp_id,
|
temp_id,
|
||||||
type,
|
type,
|
||||||
name: file.name,
|
name: file.name,
|
||||||
}
|
})
|
||||||
)
|
);
|
||||||
);
|
|
||||||
|
|
||||||
const { result, cancel, cancel_editing } = yield race({
|
const [result, cancel]: [
|
||||||
result: call(uploadWorker, {
|
Unwrap<typeof uploadCall>,
|
||||||
file,
|
Unwrap<typeof uploadCancelWorker>
|
||||||
temp_id,
|
] = yield race([
|
||||||
target,
|
call(uploadWorker, {
|
||||||
type,
|
file,
|
||||||
}),
|
temp_id,
|
||||||
cancel: call(uploadCancelWorker, temp_id),
|
target,
|
||||||
});
|
type,
|
||||||
|
}),
|
||||||
|
call(uploadCancelWorker, temp_id),
|
||||||
|
]);
|
||||||
|
|
||||||
if (cancel || cancel_editing) {
|
if (cancel || !result) {
|
||||||
if (onFail) onFail();
|
if (onFail) onFail();
|
||||||
return yield put(uploadDropStatus(temp_id));
|
return yield put(uploadDropStatus(temp_id));
|
||||||
}
|
}
|
||||||
|
|
||||||
const { data, error }: { data: IFile & { detail: string }; error: string } = result;
|
yield put(
|
||||||
|
uploadSetStatus(temp_id, {
|
||||||
|
is_uploading: false,
|
||||||
|
error: '',
|
||||||
|
uuid: result.id,
|
||||||
|
url: result.full_path,
|
||||||
|
type,
|
||||||
|
thumbnail_url: result.full_path,
|
||||||
|
progress: 1,
|
||||||
|
name: file.name,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
if (error) {
|
yield put(uploadAddFile(result));
|
||||||
|
|
||||||
|
if (onSuccess) onSuccess(result);
|
||||||
|
} catch (error) {
|
||||||
if (onFail) onFail();
|
if (onFail) onFail();
|
||||||
|
|
||||||
return yield put(
|
return yield put(
|
||||||
uploadSetStatus(temp_id, {
|
uploadSetStatus(temp_id, {
|
||||||
is_uploading: false,
|
is_uploading: false,
|
||||||
error: data.detail || error,
|
error,
|
||||||
type,
|
type,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
yield put(
|
|
||||||
uploadSetStatus(temp_id, {
|
|
||||||
is_uploading: false,
|
|
||||||
error: null,
|
|
||||||
uuid: data.id,
|
|
||||||
url: data.full_path,
|
|
||||||
type,
|
|
||||||
thumbnail_url: data.full_path,
|
|
||||||
progress: 1,
|
|
||||||
name: file.name,
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
yield put(uploadAddFile(data));
|
|
||||||
|
|
||||||
if (onSuccess) onSuccess(data);
|
|
||||||
|
|
||||||
return { error: null, status: HTTP_RESPONSES.CREATED, data: {} }; // add file here as data
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function* uploadFiles({ files }: ReturnType<typeof uploadUploadFiles>) {
|
function* uploadFiles({ files }: ReturnType<typeof uploadUploadFiles>) {
|
||||||
|
|
6
src/redux/uploads/types.ts
Normal file
6
src/redux/uploads/types.ts
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
import { IFile, IFileWithUUID, IUploadProgressHandler } from '~/redux/types';
|
||||||
|
|
||||||
|
export type ApiUploadFileRequest = IFileWithUUID & {
|
||||||
|
onProgress: IUploadProgressHandler;
|
||||||
|
};
|
||||||
|
export type ApiUploadFIleResult = IFile;
|
|
@ -1,7 +1,7 @@
|
||||||
import uuid from 'uuid4';
|
import uuid from 'uuid4';
|
||||||
import { eventChannel, END, EventChannel } from 'redux-saga';
|
import { END, eventChannel, EventChannel } from 'redux-saga';
|
||||||
import { VALIDATORS } from '~/utils/validators';
|
import { VALIDATORS } from '~/utils/validators';
|
||||||
import { IResultWithStatus, IFile } from '~/redux/types';
|
import { IFile, IResultWithStatus } from '~/redux/types';
|
||||||
import { HTTP_RESPONSES } from './api';
|
import { HTTP_RESPONSES } from './api';
|
||||||
import { EMPTY_FILE, FILE_MIMES, UPLOAD_TYPES } from '~/redux/uploads/constants';
|
import { EMPTY_FILE, FILE_MIMES, UPLOAD_TYPES } from '~/redux/uploads/constants';
|
||||||
|
|
||||||
|
@ -33,13 +33,11 @@ export function createUploader<T extends {}, R extends {}>(
|
||||||
export const uploadGetThumb = async file => {
|
export const uploadGetThumb = async file => {
|
||||||
if (!file.type || !VALIDATORS.IS_IMAGE_MIME(file.type)) return '';
|
if (!file.type || !VALIDATORS.IS_IMAGE_MIME(file.type)) return '';
|
||||||
|
|
||||||
const thumb = await new Promise(resolve => {
|
return new Promise<string | ArrayBuffer>(resolve => {
|
||||||
const reader = new FileReader();
|
const reader = new FileReader();
|
||||||
reader.onloadend = () => resolve(reader.result || '');
|
reader.onloadend = () => resolve(reader.result || '');
|
||||||
reader.readAsDataURL(file);
|
reader.readAsDataURL(file);
|
||||||
});
|
});
|
||||||
|
|
||||||
return thumb;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const fakeUploader = ({
|
export const fakeUploader = ({
|
||||||
|
@ -73,9 +71,6 @@ export const fakeUploader = ({
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getFileType = (file: File): keyof typeof UPLOAD_TYPES => {
|
export const getFileType = (file: File): keyof typeof UPLOAD_TYPES | undefined =>
|
||||||
return (
|
(file.type && Object.keys(FILE_MIMES).find(mime => FILE_MIMES[mime].includes(file.type))) ||
|
||||||
(file.type && Object.keys(FILE_MIMES).find(mime => FILE_MIMES[mime].includes(file.type))) ||
|
undefined;
|
||||||
null
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue