1
0
Fork 0
mirror of https://github.com/muerwre/vault-frontend.git synced 2025-04-25 12:56:41 +07:00

fixed pushing tags

This commit is contained in:
Fedor Katurov 2019-10-24 12:43:54 +07:00
parent 6836e00de1
commit 99426172b2
12 changed files with 79 additions and 22 deletions

View file

@ -2,12 +2,14 @@ import React, { FC, HTMLAttributes } from 'react';
import { range } from 'ramda'; import { range } from 'ramda';
import * as styles from './styles.scss'; import * as styles from './styles.scss';
import { Group } from '~/components/containers/Group'; import { Group } from '~/components/containers/Group';
import { INode } from '~/redux/types';
import { getURL } from '~/utils/dom';
type IProps = HTMLAttributes<HTMLDivElement> & {} type IProps = HTMLAttributes<HTMLDivElement> & {
items: Partial<INode>[];
};
const NodeRelated: FC<IProps> = ({ const NodeRelated: FC<IProps> = ({ title, items }) => (
title,
}) => (
<Group className={styles.wrap}> <Group className={styles.wrap}>
<div className={styles.title}> <div className={styles.title}>
<div className={styles.line} /> <div className={styles.line} />
@ -15,9 +17,13 @@ const NodeRelated: FC<IProps> = ({
<div className={styles.line} /> <div className={styles.line} />
</div> </div>
<div className={styles.grid}> <div className={styles.grid}>
{ {items.map(item => (
range(1, 7).map(el => (<div className={styles.item} key={el} />)) <div
} className={styles.item}
key={item.id}
style={{ backgroundImage: `url("${getURL({ url: item.thumbnail })}")` }}
/>
))}
</div> </div>
</Group> </Group>
); );

View file

@ -7,15 +7,20 @@
.grid { .grid {
display: grid; display: grid;
grid-template-columns: repeat(auto-fit, minmax(64px, 1fr)); grid-template-columns: repeat(3, 1fr);
grid-template-rows: auto; grid-template-rows: auto;
grid-auto-rows: auto; grid-auto-rows: auto;
grid-column-gap: $gap; grid-column-gap: $gap;
grid-row-gap: $gap; grid-row-gap: $gap;
@include tablet {
grid-template-columns: repeat(6, 1fr);
}
} }
.item { .item {
background: darken($content_bg, 2%); background: darken($content_bg, 2%) 50% 50% no-repeat;
background-size: cover;
padding-bottom: 100%; padding-bottom: 100%;
border-radius: $cell_radius; border-radius: $cell_radius;
} }

View file

@ -12,6 +12,7 @@ import { TagField } from '~/components/containers/TagField';
import { ITag } from '~/redux/types'; import { ITag } from '~/redux/types';
import { Tag } from '~/components/node/Tag'; import { Tag } from '~/components/node/Tag';
import uniq from 'ramda/es/uniq'; import uniq from 'ramda/es/uniq';
import assocPath from 'ramda/es/assocPath';
type IProps = HTMLAttributes<HTMLDivElement> & { type IProps = HTMLAttributes<HTMLDivElement> & {
tags: Partial<ITag>[]; tags: Partial<ITag>[];
@ -65,9 +66,14 @@ export const Tags: FC<IProps> = ({ tags, is_editable, onTagsChange, ...props })
); );
const onSubmit = useCallback(() => { const onSubmit = useCallback(() => {
if (!data.length) return; const title = input && input.trim();
onTagsChange(uniq([...tags, ...data]).map(tag => tag.title)); const items = title ? [...data, { title }] : data;
}, [tags, data, onTagsChange]);
if (!items.length) return;
setData(items);
setInput('');
onTagsChange(uniq([...tags, ...items]).map(tag => tag.title));
}, [tags, data, onTagsChange, input, setInput]);
useEffect(() => { useEffect(() => {
setData(data.filter(({ title }) => !tags.some(tag => tag.title.trim() === title.trim()))); setData(data.filter(({ title }) => !tags.some(tag => tag.title.trim() === title.trim())));

View file

@ -13,6 +13,7 @@ export const API = {
GET_NODE: (id: number | string) => `/node/${id}`, GET_NODE: (id: number | string) => `/node/${id}`,
COMMENT: (id: INode['id']) => `/node/${id}/comment`, COMMENT: (id: INode['id']) => `/node/${id}/comment`,
RELATED: (id: INode['id']) => `/node/${id}/related`,
UPDATE_TAGS: (id: INode['id']) => `/node/${id}/tags`, UPDATE_TAGS: (id: INode['id']) => `/node/${id}/tags`,
POST_LIKE: (id: INode['id']) => `/node/${id}/like`, POST_LIKE: (id: INode['id']) => `/node/${id}/like`,
POST_STAR: (id: INode['id']) => `/node/${id}/heroic`, POST_STAR: (id: INode['id']) => `/node/${id}/heroic`,

View file

@ -42,7 +42,7 @@ const NodeLayoutUnconnected: FC<IProps> = memo(
match: { match: {
params: { id }, params: { id },
}, },
node: { is_loading, is_loading_comments, comments = [], current: node }, node: { is_loading, is_loading_comments, comments = [], current: node, related },
user, user,
user: { is_user }, user: { is_user },
nodeLoadNode, nodeLoadNode,
@ -123,9 +123,9 @@ const NodeLayoutUnconnected: FC<IProps> = memo(
<Group style={{ flex: 1, minWidth: 0 }}> <Group style={{ flex: 1, minWidth: 0 }}>
<NodeTags is_editable={is_user} tags={node.tags} onChange={onTagsChange} /> <NodeTags is_editable={is_user} tags={node.tags} onChange={onTagsChange} />
<NodeRelated title="First album" /> {related && related.similar && (
<NodeRelated title="ПОХОЖИЕ" items={related.similar} />
<NodeRelated title="Second album" /> )}
</Group> </Group>
</div> </div>
</Group> </Group>

View file

@ -48,6 +48,11 @@ export const nodeSetComments = (comments: IComment[]) => ({
type: NODE_ACTIONS.SET_COMMENTS, type: NODE_ACTIONS.SET_COMMENTS,
}); });
export const nodeSetRelated = (related: INodeState['related']) => ({
related,
type: NODE_ACTIONS.SET_RELATED,
});
export const nodeSetCommentData = (id: number, comment: IComment) => ({ export const nodeSetCommentData = (id: number, comment: IComment) => ({
id, id,
comment, comment,

View file

@ -2,6 +2,7 @@ import { api, configWithToken, resultMiddleware, errorMiddleware } from '~/utils
import { INode, IResultWithStatus, IComment } from '../types'; import { INode, IResultWithStatus, IComment } from '../types';
import { API } from '~/constants/api'; import { API } from '~/constants/api';
import { nodeUpdateTags, nodeLike, nodeStar } from './actions'; import { nodeUpdateTags, nodeLike, nodeStar } from './actions';
import { INodeState } from './reducer';
export const postNode = ({ export const postNode = ({
access, access,
@ -58,12 +59,24 @@ export const getNodeComments = ({
}: { }: {
id: number; id: number;
access: string; access: string;
}): Promise<IResultWithStatus<{ comment: Comment }>> => }): Promise<IResultWithStatus<{ comments: Comment[] }>> =>
api api
.get(API.NODE.COMMENT(id), configWithToken(access)) .get(API.NODE.COMMENT(id), configWithToken(access))
.then(resultMiddleware) .then(resultMiddleware)
.catch(errorMiddleware); .catch(errorMiddleware);
export const getNodeRelated = ({
id,
access,
}: {
id: number;
access: string;
}): Promise<IResultWithStatus<{ related: INodeState['related'] }>> =>
api
.get(API.NODE.RELATED(id), configWithToken(access))
.then(resultMiddleware)
.catch(errorMiddleware);
export const updateNodeTags = ({ export const updateNodeTags = ({
id, id,
tags, tags,

View file

@ -34,6 +34,7 @@ export const NODE_ACTIONS = {
POST_COMMENT: `${prefix}POST_COMMENT`, POST_COMMENT: `${prefix}POST_COMMENT`,
SET_COMMENTS: `${prefix}SET_COMMENTS`, SET_COMMENTS: `${prefix}SET_COMMENTS`,
SET_RELATED: `${prefix}SET_RELATED`,
UPDATE_TAGS: `${prefix}UPDATE_TAGS`, UPDATE_TAGS: `${prefix}UPDATE_TAGS`,
SET_TAGS: `${prefix}SET_TAGS`, SET_TAGS: `${prefix}SET_TAGS`,

View file

@ -11,6 +11,7 @@ import {
nodeSetTags, nodeSetTags,
nodeSetEditor, nodeSetEditor,
nodeSetCoverImage, nodeSetCoverImage,
nodeSetRelated,
} from './actions'; } from './actions';
import { INodeState } from './reducer'; import { INodeState } from './reducer';
@ -36,6 +37,9 @@ const setSendingComment = (
const setComments = (state: INodeState, { comments }: ReturnType<typeof nodeSetComments>) => const setComments = (state: INodeState, { comments }: ReturnType<typeof nodeSetComments>) =>
assocPath(['comments'], comments, state); assocPath(['comments'], comments, state);
const setRelated = (state: INodeState, { related }: ReturnType<typeof nodeSetRelated>) =>
assocPath(['related'], related, state);
const setCommentData = ( const setCommentData = (
state: INodeState, state: INodeState,
{ id, comment }: ReturnType<typeof nodeSetCommentData> { id, comment }: ReturnType<typeof nodeSetCommentData>
@ -59,6 +63,7 @@ export const NODE_HANDLERS = {
[NODE_ACTIONS.SET_CURRENT]: setCurrent, [NODE_ACTIONS.SET_CURRENT]: setCurrent,
[NODE_ACTIONS.SET_SENDING_COMMENT]: setSendingComment, [NODE_ACTIONS.SET_SENDING_COMMENT]: setSendingComment,
[NODE_ACTIONS.SET_COMMENTS]: setComments, [NODE_ACTIONS.SET_COMMENTS]: setComments,
[NODE_ACTIONS.SET_RELATED]: setRelated,
[NODE_ACTIONS.SET_COMMENT_DATA]: setCommentData, [NODE_ACTIONS.SET_COMMENT_DATA]: setCommentData,
[NODE_ACTIONS.SET_TAGS]: setTags, [NODE_ACTIONS.SET_TAGS]: setTags,
[NODE_ACTIONS.SET_EDITOR]: setEditor, [NODE_ACTIONS.SET_EDITOR]: setEditor,

View file

@ -7,6 +7,10 @@ export type INodeState = Readonly<{
editor: INode; editor: INode;
current: INode; current: INode;
comments: IComment[]; comments: IComment[];
related: {
albums: Record<string, Partial<INode[]>>;
similar: Partial<INode[]>;
};
comment_data: Record<number, IComment>; comment_data: Record<number, IComment>;
current_cover_image: IFile; current_cover_image: IFile;
@ -28,6 +32,7 @@ const INITIAL_STATE: INodeState = {
current: { ...EMPTY_NODE }, current: { ...EMPTY_NODE },
comment_data: { 0: { ...EMPTY_COMMENT } }, comment_data: { 0: { ...EMPTY_COMMENT } },
comments: [], comments: [],
related: null,
current_cover_image: null, current_cover_image: null,
is_loading: false, is_loading: false,

View file

@ -1,4 +1,4 @@
import { takeLatest, call, put, select, delay } from 'redux-saga/effects'; import { takeLatest, call, put, select, delay, all } from 'redux-saga/effects';
import { push } from 'connected-react-router'; import { push } from 'connected-react-router';
import { NODE_ACTIONS, EMPTY_NODE, EMPTY_COMMENT, NODE_EDITOR_DATA } from './constants'; import { NODE_ACTIONS, EMPTY_NODE, EMPTY_COMMENT, NODE_EDITOR_DATA } from './constants';
@ -19,6 +19,7 @@ import {
nodeSetEditor, nodeSetEditor,
nodeEdit, nodeEdit,
nodeLike, nodeLike,
nodeSetRelated,
} from './actions'; } from './actions';
import { import {
postNode, postNode,
@ -28,6 +29,7 @@ import {
updateNodeTags, updateNodeTags,
postNodeLike, postNodeLike,
postNodeStar, postNodeStar,
getNodeRelated,
} from './api'; } from './api';
import { reqWrapper } from '../auth/sagas'; import { reqWrapper } from '../auth/sagas';
import { flowSetNodes } from '../flow/actions'; import { flowSetNodes } from '../flow/actions';
@ -112,11 +114,19 @@ function* onNodeLoad({ id, node_type }: ReturnType<typeof nodeLoadNode>) {
// todo: load comments // todo: load comments
const { const {
comments: {
data: { comments }, data: { comments },
} = yield call(reqWrapper, getNodeComments, { id }); },
related: {
data: { related },
},
} = yield all({
comments: call(reqWrapper, getNodeComments, { id }),
related: call(reqWrapper, getNodeRelated, { id }),
});
yield put(nodeSetComments(comments || [])); yield put(nodeSetComments(comments || []));
yield put(nodeSetRelated(related || []));
yield put(nodeSetLoadingComments(false)); yield put(nodeSetLoadingComments(false));
return; return;