mirror of
https://github.com/muerwre/vault-frontend.git
synced 2025-04-25 12:56:41 +07:00
fixed audio attaches
This commit is contained in:
parent
c9d84a4947
commit
b11593c45e
7 changed files with 68 additions and 69 deletions
|
@ -18,7 +18,10 @@ const SortableAudioGrid = SortableContainer(
|
||||||
locked: IUploadStatus[];
|
locked: IUploadStatus[];
|
||||||
onDrop: (file_id: IFile['id']) => void;
|
onDrop: (file_id: IFile['id']) => void;
|
||||||
onTitleChange: (file_id: IFile['id'], title: IFile['metadata']['title']) => void;
|
onTitleChange: (file_id: IFile['id'], title: IFile['metadata']['title']) => void;
|
||||||
}) => (
|
}) => {
|
||||||
|
console.log(locked);
|
||||||
|
|
||||||
|
return (
|
||||||
<div className={styles.grid}>
|
<div className={styles.grid}>
|
||||||
{items
|
{items
|
||||||
.filter(file => file && file.id)
|
.filter(file => file && file.id)
|
||||||
|
@ -34,7 +37,8 @@ const SortableAudioGrid = SortableContainer(
|
||||||
</SortableAudioGridItem>
|
</SortableAudioGridItem>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
export { SortableAudioGrid };
|
export { SortableAudioGrid };
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
import React, { FC, useCallback, KeyboardEventHandler, useEffect, useMemo, memo } from 'react';
|
import React, { FC, KeyboardEventHandler, memo, useCallback, useEffect, useMemo } from 'react';
|
||||||
import { Textarea } from '~/components/input/Textarea';
|
import { Textarea } from '~/components/input/Textarea';
|
||||||
import * as styles from './styles.scss';
|
import * as styles from './styles.scss';
|
||||||
import { Filler } from '~/components/containers/Filler';
|
import { Filler } from '~/components/containers/Filler';
|
||||||
import { Button } from '~/components/input/Button';
|
import { Button } from '~/components/input/Button';
|
||||||
import assocPath from 'ramda/es/assocPath';
|
import assocPath from 'ramda/es/assocPath';
|
||||||
import { InputHandler, IFileWithUUID, IFile } from '~/redux/types';
|
import { IFile, IFileWithUUID, InputHandler } from '~/redux/types';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import * as NODE_ACTIONS from '~/redux/node/actions';
|
import * as NODE_ACTIONS from '~/redux/node/actions';
|
||||||
import { selectNode } from '~/redux/node/selectors';
|
import { selectNode } from '~/redux/node/selectors';
|
||||||
|
@ -233,6 +233,10 @@ const CommentFormUnconnected: FC<IProps> = memo(
|
||||||
|
|
||||||
const placeholder = getRandomPhrase('SIMPLE');
|
const placeholder = getRandomPhrase('SIMPLE');
|
||||||
|
|
||||||
|
const hasImageAttaches = images.length > 0 || locked_images.length > 0;
|
||||||
|
const hasAudioAttaches = audios.length > 0 || locked_audios.length > 0;
|
||||||
|
const hasAttaches = hasImageAttaches || hasAudioAttaches;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form onSubmit={onSubmit} className={styles.wrap}>
|
<form onSubmit={onSubmit} className={styles.wrap}>
|
||||||
<div className={styles.input}>
|
<div className={styles.input}>
|
||||||
|
@ -246,9 +250,9 @@ const CommentFormUnconnected: FC<IProps> = memo(
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{(!!images.length || !!audios.length) && (
|
{hasAttaches && (
|
||||||
<div className={styles.attaches}>
|
<div className={styles.attaches}>
|
||||||
{!!images.length && (
|
{hasImageAttaches && (
|
||||||
<SortableImageGrid
|
<SortableImageGrid
|
||||||
onDrop={onFileDrop}
|
onDrop={onFileDrop}
|
||||||
onSortEnd={onImageMove}
|
onSortEnd={onImageMove}
|
||||||
|
@ -261,7 +265,7 @@ const CommentFormUnconnected: FC<IProps> = memo(
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{(!!audios.length || !!locked_audios.length) && (
|
{hasAudioAttaches && (
|
||||||
<SortableAudioGrid
|
<SortableAudioGrid
|
||||||
items={audios}
|
items={audios}
|
||||||
onDrop={onFileDrop}
|
onDrop={onFileDrop}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import React, { FC, ChangeEventHandler, KeyboardEventHandler, FocusEventHandler } from 'react';
|
import React, { ChangeEventHandler, FC, FocusEventHandler, KeyboardEventHandler } from 'react';
|
||||||
import * as styles from './styles.scss';
|
import * as styles from './styles.scss';
|
||||||
import { ITag } from '~/redux/types';
|
import { ITag } from '~/redux/types';
|
||||||
|
|
||||||
import classNames = require('classnames');
|
import classNames = require('classnames');
|
||||||
|
|
||||||
const getTagFeature = (tag: Partial<ITag>) => {
|
const getTagFeature = (tag: Partial<ITag>) => {
|
||||||
|
@ -14,13 +13,21 @@ interface IProps {
|
||||||
tag: Partial<ITag>;
|
tag: Partial<ITag>;
|
||||||
|
|
||||||
is_hoverable?: boolean;
|
is_hoverable?: boolean;
|
||||||
|
is_editing?: boolean;
|
||||||
|
|
||||||
onInput?: ChangeEventHandler<HTMLInputElement>;
|
onInput?: ChangeEventHandler<HTMLInputElement>;
|
||||||
onKeyUp?: KeyboardEventHandler;
|
onKeyUp?: KeyboardEventHandler;
|
||||||
onBlur?: FocusEventHandler<HTMLInputElement>;
|
onBlur?: FocusEventHandler<HTMLInputElement>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Tag: FC<IProps> = ({ tag, is_hoverable, onInput, onKeyUp, onBlur }) => (
|
const Tag: FC<IProps> = ({ tag, is_hoverable, is_editing, onInput, onKeyUp, onBlur }) => (
|
||||||
<div className={classNames(styles.tag, getTagFeature(tag), { is_hoverable, input: !!onInput })}>
|
<div
|
||||||
|
className={classNames(styles.tag, getTagFeature(tag), {
|
||||||
|
is_hoverable,
|
||||||
|
is_editing,
|
||||||
|
input: !!onInput,
|
||||||
|
})}
|
||||||
|
>
|
||||||
<div className={styles.hole} />
|
<div className={styles.hole} />
|
||||||
<div className={styles.title}>{tag.title}</div>
|
<div className={styles.title}>{tag.title}</div>
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,6 @@
|
||||||
font: $font_14_semibold;
|
font: $font_14_semibold;
|
||||||
align-self: flex-start;
|
align-self: flex-start;
|
||||||
padding: 0 8px 0 0;
|
padding: 0 8px 0 0;
|
||||||
// box-shadow: $shadow_depth_2;
|
|
||||||
margin: 0 $gap $gap 0;
|
margin: 0 $gap $gap 0;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
|
@ -19,6 +18,11 @@
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&:global(.is_editing) {
|
||||||
|
cursor: pointer;
|
||||||
|
background-color: lighten($tag_bg, 10%);
|
||||||
|
}
|
||||||
|
|
||||||
&:global(.red) {
|
&:global(.red) {
|
||||||
background: $red_gradient;
|
background: $red_gradient;
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,9 +77,15 @@ export const Tags: FC<IProps> = ({ tags, is_editable, onTagsChange, ...props })
|
||||||
|
|
||||||
const onSubmit = useCallback(() => {
|
const onSubmit = useCallback(() => {
|
||||||
const title = input && input.trim();
|
const title = input && input.trim();
|
||||||
const items = title ? [...data, { title }] : data;
|
const items = (title ? [...data, { title }] : data)
|
||||||
|
.filter(tag => tag.title.length > 0)
|
||||||
|
.map(tag => ({
|
||||||
|
...tag,
|
||||||
|
title: tag.title.toLowerCase(),
|
||||||
|
}));
|
||||||
|
|
||||||
if (!items.length) return;
|
if (!items.length) return;
|
||||||
|
|
||||||
setData(items);
|
setData(items);
|
||||||
setInput('');
|
setInput('');
|
||||||
onTagsChange(uniq([...tags, ...items]).map(tag => tag.title));
|
onTagsChange(uniq([...tags, ...items]).map(tag => tag.title));
|
||||||
|
@ -100,7 +106,7 @@ export const Tags: FC<IProps> = ({ tags, is_editable, onTagsChange, ...props })
|
||||||
))}
|
))}
|
||||||
|
|
||||||
{data.map(tag => (
|
{data.map(tag => (
|
||||||
<Tag key={tag.title} tag={tag} />
|
<Tag key={tag.title} tag={tag} is_editing />
|
||||||
))}
|
))}
|
||||||
|
|
||||||
{is_editable && (
|
{is_editable && (
|
||||||
|
|
|
@ -240,7 +240,8 @@ function* onCancelCommentEdit({ id }: ReturnType<typeof nodeCancelCommentEdit>)
|
||||||
}
|
}
|
||||||
|
|
||||||
function* onUpdateTags({ id, tags }: ReturnType<typeof nodeUpdateTags>) {
|
function* onUpdateTags({ id, tags }: ReturnType<typeof nodeUpdateTags>) {
|
||||||
yield delay(1000);
|
yield delay(100);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
data: { node },
|
data: { node },
|
||||||
}: IResultWithStatus<{ node: INode }> = yield call(reqWrapper, updateNodeTags, { id, tags });
|
}: IResultWithStatus<{ node: INode }> = yield call(reqWrapper, updateNodeTags, { id, tags });
|
||||||
|
|
|
@ -1,49 +1,37 @@
|
||||||
import {
|
import { takeEvery, all, spawn, call, put, take, fork, race } from 'redux-saga/effects';
|
||||||
takeEvery,
|
import { postUploadFile } from './api';
|
||||||
all,
|
import { UPLOAD_ACTIONS, FILE_MIMES } from '~/redux/uploads/constants';
|
||||||
spawn,
|
|
||||||
call,
|
|
||||||
put,
|
|
||||||
take,
|
|
||||||
fork,
|
|
||||||
race
|
|
||||||
} from "redux-saga/effects";
|
|
||||||
import { postUploadFile } from "./api";
|
|
||||||
import { UPLOAD_ACTIONS, FILE_MIMES } from "~/redux/uploads/constants";
|
|
||||||
import {
|
import {
|
||||||
uploadUploadFiles,
|
uploadUploadFiles,
|
||||||
uploadSetStatus,
|
uploadSetStatus,
|
||||||
uploadAddStatus,
|
uploadAddStatus,
|
||||||
uploadDropStatus,
|
uploadDropStatus,
|
||||||
uploadAddFile
|
uploadAddFile,
|
||||||
} from "./actions";
|
} from './actions';
|
||||||
import { reqWrapper } from "../auth/sagas";
|
import { reqWrapper } 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, IFile, IUploadProgressHandler } from '../types';
|
||||||
|
|
||||||
function* uploadCall({
|
function* uploadCall({
|
||||||
file,
|
file,
|
||||||
temp_id,
|
temp_id,
|
||||||
target,
|
target,
|
||||||
type,
|
type,
|
||||||
onProgress
|
onProgress,
|
||||||
}: IFileWithUUID & { onProgress: IUploadProgressHandler }) {
|
}: IFileWithUUID & { onProgress: IUploadProgressHandler }) {
|
||||||
return yield call(reqWrapper, postUploadFile, {
|
return yield call(reqWrapper, postUploadFile, {
|
||||||
file,
|
file,
|
||||||
temp_id,
|
temp_id,
|
||||||
type,
|
type,
|
||||||
target,
|
target,
|
||||||
onProgress
|
onProgress,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function* onUploadProgress(chan) {
|
function* onUploadProgress(chan) {
|
||||||
while (true) {
|
while (true) {
|
||||||
const {
|
const { progress, temp_id }: { progress: number; temp_id: string } = yield take(chan);
|
||||||
progress,
|
|
||||||
temp_id
|
|
||||||
}: { progress: number; temp_id: string } = yield take(chan);
|
|
||||||
|
|
||||||
yield put(uploadSetStatus(temp_id, { progress }));
|
yield put(uploadSetStatus(temp_id, { progress }));
|
||||||
}
|
}
|
||||||
|
@ -59,10 +47,10 @@ function* uploadCancelWorker(id) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function* uploadWorker({ file, temp_id, target, type }: IFileWithUUID) {
|
function* uploadWorker({ file, temp_id, target, type }: IFileWithUUID) {
|
||||||
const [promise, chan] = createUploader<
|
const [promise, chan] = createUploader<Partial<IFileWithUUID>, Partial<IFileWithUUID>>(
|
||||||
Partial<IFileWithUUID>,
|
uploadCall,
|
||||||
Partial<IFileWithUUID>
|
{ temp_id, target, type }
|
||||||
>(uploadCall, { temp_id, target, type });
|
);
|
||||||
|
|
||||||
yield fork(onUploadProgress, chan);
|
yield fork(onUploadProgress, chan);
|
||||||
|
|
||||||
|
@ -70,23 +58,16 @@ function* uploadWorker({ file, temp_id, target, type }: IFileWithUUID) {
|
||||||
temp_id,
|
temp_id,
|
||||||
file,
|
file,
|
||||||
target,
|
target,
|
||||||
type
|
type,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function* uploadFile({
|
function* uploadFile({ file, temp_id, type, target, onSuccess, onFail }: IFileWithUUID) {
|
||||||
file,
|
if (!file.type || !FILE_MIMES[type] || !FILE_MIMES[type].includes(file.type)) {
|
||||||
temp_id,
|
|
||||||
type,
|
|
||||||
target,
|
|
||||||
onSuccess,
|
|
||||||
onFail
|
|
||||||
}: IFileWithUUID) {
|
|
||||||
if (!file.type || !file.type || !FILE_MIMES[type].includes(file.type)) {
|
|
||||||
return {
|
return {
|
||||||
error: "File_Not_Image",
|
error: 'File_Not_Image',
|
||||||
status: HTTP_RESPONSES.BAD_REQUEST,
|
status: HTTP_RESPONSES.BAD_REQUEST,
|
||||||
data: {}
|
data: {},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,10 +80,9 @@ function* uploadFile({
|
||||||
{
|
{
|
||||||
preview,
|
preview,
|
||||||
is_uploading: true,
|
is_uploading: true,
|
||||||
// type: file.type,
|
|
||||||
temp_id,
|
temp_id,
|
||||||
type,
|
type,
|
||||||
name: file.name
|
name: file.name,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
@ -112,13 +92,9 @@ function* uploadFile({
|
||||||
file,
|
file,
|
||||||
temp_id,
|
temp_id,
|
||||||
target,
|
target,
|
||||||
type
|
type,
|
||||||
}),
|
}),
|
||||||
cancel: call(uploadCancelWorker, temp_id)
|
cancel: call(uploadCancelWorker, temp_id),
|
||||||
// subject_cancel: call(uploadSubjectCancelWorker, subject)
|
|
||||||
// add here CANCEL_UPLOADS worker, that will watch for subject
|
|
||||||
// cancel_editing: take(UPLOAD_ACTIONS.CANCEL_EDITING),
|
|
||||||
// save_inventory: take(INVENTORY_ACTIONS.SAVE_INVENTORY),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (cancel || cancel_editing) {
|
if (cancel || cancel_editing) {
|
||||||
|
@ -126,10 +102,7 @@ function* uploadFile({
|
||||||
return yield put(uploadDropStatus(temp_id));
|
return yield put(uploadDropStatus(temp_id));
|
||||||
}
|
}
|
||||||
|
|
||||||
const {
|
const { data, error }: { data: IFile & { detail: string }; error: string } = result;
|
||||||
data,
|
|
||||||
error
|
|
||||||
}: { data: IFile & { detail: string }; error: string } = result;
|
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
if (onFail) onFail();
|
if (onFail) onFail();
|
||||||
|
@ -138,7 +111,7 @@ function* uploadFile({
|
||||||
uploadSetStatus(temp_id, {
|
uploadSetStatus(temp_id, {
|
||||||
is_uploading: false,
|
is_uploading: false,
|
||||||
error: data.detail || error,
|
error: data.detail || error,
|
||||||
type
|
type,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -152,7 +125,7 @@ function* uploadFile({
|
||||||
type,
|
type,
|
||||||
thumbnail_url: data.full_path,
|
thumbnail_url: data.full_path,
|
||||||
progress: 1,
|
progress: 1,
|
||||||
name: file.name
|
name: file.name,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue