diff --git a/.env.local b/.env.local index 8e3e9501..7d506bf3 100644 --- a/.env.local +++ b/.env.local @@ -1,6 +1,6 @@ -NEXT_PUBLIC_API_HOST=https://pig.staging.vault48.org/ -NEXT_PUBLIC_REMOTE_CURRENT=https://pig.staging.vault48.org/static/ -# NEXT_PUBLIC_API_HOST=http://localhost:8888/ -# NEXT_PUBLIC_REMOTE_CURRENT=http://localhost:8888/static/ +# NEXT_PUBLIC_API_HOST=https://pig.staging.vault48.org/ +# NEXT_PUBLIC_REMOTE_CURRENT=https://pig.staging.vault48.org/static/ +NEXT_PUBLIC_API_HOST=http://localhost:7777/ +NEXT_PUBLIC_REMOTE_CURRENT=http://localhost:7777/static/ # NEXT_PUBLIC_API_HOST=https://pig.vault48.org/ # NEXT_PUBLIC_REMOTE_CURRENT=https://pig.vault48.org/static/ diff --git a/.eslintrc.js b/.eslintrc.js index ccf0b863..25092ae2 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -23,6 +23,18 @@ module.exports = { pathGroupsExcludedImportTypes: ['react'], }, ], + 'no-restricted-imports': [ + 'error', + { + paths: [ + { + name: 'ramda', + message: + 'import from \'~/utils/ramda\' instead', + }, + ], + }, + ] }, parserOptions: { ecmaVersion: 7, diff --git a/package.json b/package.json index bf70f4f4..e79a5ab7 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,7 @@ "mobx": "^6.3.10", "mobx-persist-store": "^1.0.4", "mobx-react-lite": "^3.2.3", - "next": "^12.1.0", + "next": "^12.3.0", "photoswipe": "^4.1.3", "raleway-cyrillic": "^4.0.2", "ramda": "^0.26.1", @@ -76,8 +76,8 @@ ] }, "devDependencies": { - "@next/bundle-analyzer": "^12.0.8", - "@next/eslint-plugin-next": "^12.0.8", + "@next/bundle-analyzer": "^12.3.0", + "@next/eslint-plugin-next": "^12.3.0", "@types/marked": "^4.0.1", "@types/node": "^11.13.22", "@types/ramda": "^0.26.33", diff --git a/src/api/auth/index.ts b/src/api/auth/index.ts index 175bb08f..06a46c75 100644 --- a/src/api/auth/index.ts +++ b/src/api/auth/index.ts @@ -15,6 +15,7 @@ import { ApiLoginWithSocialResult, ApiRestoreCodeRequest, ApiRestoreCodeResult, + ApiUpdatePhotoRequest, ApiUpdateUserRequest, ApiUpdateUserResult, ApiUserLoginRequest, @@ -28,44 +29,72 @@ export const apiUserLogin = ({ username, password }: ApiUserLoginRequest) => .post(API.USER.LOGIN, { username, password }) .then(cleanResult); -export const apiAuthGetUser = () => api.get(API.USER.ME).then(cleanResult); +export const apiAuthGetUser = () => + api.get(API.USER.ME).then(cleanResult); -export const apiAuthGetUserProfile = ({ username }: ApiAuthGetUserProfileRequest) => - api.get(API.USER.PROFILE(username)).then(cleanResult); - -export const apiAuthGetUpdates = ({ exclude_dialogs, last }: ApiAuthGetUpdatesRequest) => +export const apiAuthGetUserProfile = ({ + username, +}: ApiAuthGetUserProfileRequest) => api - .get(API.USER.GET_UPDATES, { params: { exclude_dialogs, last } }) + .get(API.USER.PROFILE(username)) + .then(cleanResult); + +export const apiAuthGetUpdates = ({ + exclude_dialogs, + last, +}: ApiAuthGetUpdatesRequest) => + api + .get(API.USER.GET_UPDATES, { + params: { exclude_dialogs, last }, + }) .then(cleanResult); export const apiUpdateUser = ({ user }: ApiUpdateUserRequest) => api.patch(API.USER.ME, user).then(cleanResult); +export const apiUpdatePhoto = ({ file }: ApiUpdatePhotoRequest) => + api.post(API.USER.UPDATE_PHOTO, file).then(cleanResult); + +export const apiUpdateCover = ({ file }: ApiUpdatePhotoRequest) => + api.post(API.USER.UPDATE_COVER, file).then(cleanResult); + export const apiRequestRestoreCode = (field: string) => api .post<{ field: string }>(API.USER.REQUEST_CODE(), { field }) .then(cleanResult); export const apiCheckRestoreCode = ({ code }: ApiCheckRestoreCodeRequest) => - api.get(API.USER.REQUEST_CODE(code)).then(cleanResult); + api + .get(API.USER.REQUEST_CODE(code)) + .then(cleanResult); export const apiRestoreCode = ({ code, password }: ApiRestoreCodeRequest) => api - .post(API.USER.REQUEST_CODE(code), { password }) + .put(API.USER.REQUEST_CODE(code), { password }) .then(cleanResult); export const apiGetSocials = () => api.get(API.USER.GET_SOCIALS).then(cleanResult); export const apiDropSocial = ({ id, provider }: ApiDropSocialRequest) => - api.delete(API.USER.DROP_SOCIAL(provider, id)).then(cleanResult); + api + .delete(API.USER.DROP_SOCIAL(provider, id)) + .then(cleanResult); export const apiAttachSocial = ({ token }: ApiAttachSocialRequest) => api .post(API.USER.ATTACH_SOCIAL, { token }) .then(cleanResult); -export const apiLoginWithSocial = ({ token, username, password }: ApiLoginWithSocialRequest) => +export const apiLoginWithSocial = ({ + token, + username, + password, +}: ApiLoginWithSocialRequest) => api - .post(API.USER.LOGIN_WITH_SOCIAL, { token, username, password }) + .put(API.USER.LOGIN_WITH_SOCIAL, { + token, + username, + password, + }) .then(cleanResult); diff --git a/src/api/auth/types.ts b/src/api/auth/types.ts index 7a0c17d5..2bb1a355 100644 --- a/src/api/auth/types.ts +++ b/src/api/auth/types.ts @@ -1,4 +1,4 @@ -import { INotification } from '~/types'; +import { IFile, INotification } from '~/types'; import { ISocialAccount, IUser } from '~/types/auth'; export type ApiUserLoginRequest = Record<'username' | 'password', string>; @@ -8,7 +8,13 @@ export type ApiAuthGetUserResult = { user: IUser }; export type ApiUpdateUserRequest = { user: Partial; }; -export type ApiUpdateUserResult = { user: IUser; errors: Record, string> }; +export type ApiUpdatePhotoRequest = { + file: IFile; +}; +export type ApiUpdateUserResult = { + user: IUser; + errors: Record, string>; +}; export type ApiAuthGetUserProfileRequest = { username: string }; export type ApiAuthGetUserProfileResult = { user: IUser }; export type ApiAuthGetUpdatesRequest = { @@ -25,7 +31,7 @@ export type ApiRestoreCodeRequest = { code: string; password: string }; export type ApiRestoreCodeResult = { token: string; user: IUser }; export type ApiGetSocialsResult = { accounts: ISocialAccount[] }; export type ApiDropSocialRequest = { id: string; provider: string }; -export type ApiDropSocialResult = { accounts: ISocialAccount[] }; +export type ApiDropSocialResult = {}; export type ApiAttachSocialRequest = { token: string }; export type ApiAttachSocialResult = { account: ISocialAccount }; export type ApiLoginWithSocialRequest = { diff --git a/src/api/flow/index.ts b/src/api/flow/index.ts index 4b14e5cb..db2fe935 100644 --- a/src/api/flow/index.ts +++ b/src/api/flow/index.ts @@ -5,10 +5,16 @@ import { api, cleanResult } from '~/utils/api'; export const postCellView = ({ id, flow }: PostCellViewRequest) => api - .post(API.NODE.SET_CELL_VIEW(id), { flow }) + .post(API.NODES.SET_CELL_VIEW(id), { flow }) .then(cleanResult); -export const getSearchResults = ({ text, skip, take }: GetSearchResultsRequest) => +export const getSearchResults = ({ + text, + skip, + take, +}: GetSearchResultsRequest) => api - .get(API.SEARCH.NODES, { params: { text, skip, take } }) + .get(API.SEARCH.NODES, { + params: { text, skip, take }, + }) .then(cleanResult); diff --git a/src/api/node/index.ts b/src/api/node/index.ts index cc34d0c6..820143eb 100644 --- a/src/api/node/index.ts +++ b/src/api/node/index.ts @@ -38,10 +38,13 @@ export type ApiGetNodeCommentsRequest = { take?: number; skip?: number; }; -export type ApiGetNodeCommentsResponse = { comments: IComment[]; comment_count: number }; +export type ApiGetNodeCommentsResponse = { + comments: IComment[]; + comment_count: number; +}; export const apiPostNode = ({ node }: ApiPostNodeRequest) => - api.post(API.NODE.SAVE, node).then(cleanResult); + api.post(API.NODES.SAVE, node).then(cleanResult); export const getNodeDiff = ({ start, @@ -53,7 +56,7 @@ export const getNodeDiff = ({ with_valid, }: GetNodeDiffRequest) => api - .get(API.NODE.GET_DIFF, { + .get(API.NODES.LIST, { params: { start, end, @@ -66,17 +69,20 @@ export const getNodeDiff = ({ }) .then(cleanResult); -export const apiGetNode = ({ id }: ApiGetNodeRequest, config?: AxiosRequestConfig) => +export const apiGetNode = ( + { id }: ApiGetNodeRequest, + config?: AxiosRequestConfig, +) => api - .get(API.NODE.GET_NODE(id), config) + .get(API.NODES.GET(id), config) .then(cleanResult) - .then(data => ({ node: data.node, last_seen: data.last_seen })); + .then((data) => ({ node: data.node, last_seen: data.last_seen })); export const apiGetNodeWithCancel = ({ id }: ApiGetNodeRequest) => { const cancelToken = axios.CancelToken.source(); return { request: api - .get(API.NODE.GET_NODE(id), { + .get(API.NODES.GET(id), { cancelToken: cancelToken.token, }) .then(cleanResult), @@ -85,7 +91,7 @@ export const apiGetNodeWithCancel = ({ id }: ApiGetNodeRequest) => { }; export const apiPostComment = ({ id, data }: ApiPostCommentRequest) => - api.post(API.NODE.COMMENT(id), data).then(cleanResult); + api.post(API.NODES.COMMENT(id), data).then(cleanResult); export const apiGetNodeComments = ({ id, @@ -93,32 +99,44 @@ export const apiGetNodeComments = ({ skip = 0, }: ApiGetNodeCommentsRequest) => api - .get(API.NODE.COMMENT(id), { params: { take, skip } }) + .get(API.NODES.COMMENT(id), { + params: { take, skip }, + }) .then(cleanResult); export const apiGetNodeRelated = ({ id }: ApiGetNodeRelatedRequest) => - api.get(API.NODE.RELATED(id)).then(cleanResult); + api.get(API.NODES.RELATED(id)).then(cleanResult); export const apiPostNodeTags = ({ id, tags }: ApiPostNodeTagsRequest) => api - .post(API.NODE.UPDATE_TAGS(id), { tags }) + .post(API.NODES.UPDATE_TAGS(id), { tags }) .then(cleanResult); export const apiDeleteNodeTag = ({ id, tagId }: ApiDeleteNodeTagsRequest) => - api.delete(API.NODE.DELETE_TAG(id, tagId)).then(cleanResult); + api + .delete(API.NODES.DELETE_TAG(id, tagId)) + .then(cleanResult); export const apiPostNodeLike = ({ id }: ApiPostNodeLikeRequest) => - api.post(API.NODE.POST_LIKE(id)).then(cleanResult); + api.post(API.NODES.LIKE(id)).then(cleanResult); export const apiPostNodeHeroic = ({ id }: ApiPostNodeHeroicRequest) => - api.post(API.NODE.POST_HEROIC(id)).then(cleanResult); + api.post(API.NODES.HEROIC(id)).then(cleanResult); export const apiLockNode = ({ id, is_locked }: ApiLockNodeRequest) => api - .post(API.NODE.POST_LOCK(id), { is_locked }) + .delete(API.NODES.DELETE(id), { params: { is_locked } }) .then(cleanResult); -export const apiLockComment = ({ id, isLocked, nodeId }: ApiLockCommentRequest) => +export const apiLockComment = ({ + id, + isLocked, + nodeId, +}: ApiLockCommentRequest) => api - .post(API.NODE.LOCK_COMMENT(nodeId, id), { is_locked: isLocked }) + .delete(API.NODES.LOCK_COMMENT(nodeId, id), { + params: { + is_locked: isLocked, + }, + }) .then(cleanResult); diff --git a/src/components/comment/CommentAvatar/index.tsx b/src/components/comment/CommentAvatar/index.tsx index abeddbb5..26aaa9d3 100644 --- a/src/components/comment/CommentAvatar/index.tsx +++ b/src/components/comment/CommentAvatar/index.tsx @@ -1,7 +1,7 @@ import React, { FC } from 'react'; import { Avatar } from '~/components/common/Avatar'; -import { MenuButton } from '~/components/menu'; +import { MenuButton } from '~/components/menu/MenuButton'; import { ProfileQuickInfo } from '~/containers/profile/ProfileQuickInfo'; import { IUser } from '~/types/auth'; import { path } from '~/utils/ramda'; @@ -16,7 +16,11 @@ const CommentAvatar: FC = ({ user, className }) => { + } > diff --git a/src/components/comment/CommentFormAttachButtons/index.tsx b/src/components/comment/CommentFormAttachButtons/index.tsx index a2888a5e..adc275c8 100644 --- a/src/components/comment/CommentFormAttachButtons/index.tsx +++ b/src/components/comment/CommentFormAttachButtons/index.tsx @@ -10,26 +10,32 @@ interface IProps { const CommentFormAttachButtons: FC = ({ onUpload }) => { const onInputChange = useCallback( - event => { + (event) => { event.preventDefault(); - const files = Array.from(event.target?.files as File[]).filter((file: File) => - COMMENT_FILE_TYPES.includes(file.type) + const files = Array.from(event.target?.files as File[]).filter( + (file: File) => COMMENT_FILE_TYPES.includes(file.type), ); if (!files || !files.length) return; onUpload(files); }, - [onUpload] + [onUpload], ); return ( - - diff --git a/src/components/comment/CommentFormAttaches/index.tsx b/src/components/comment/CommentFormAttaches/index.tsx index e23b3965..927e464c 100644 --- a/src/components/comment/CommentFormAttaches/index.tsx +++ b/src/components/comment/CommentFormAttaches/index.tsx @@ -1,6 +1,7 @@ import React, { FC, useCallback } from 'react'; -import { SortableAudioGrid, SortableImageGrid } from '~/components/sortable'; +import { SortableAudioGrid } from '~/components/sortable/SortableAudioGrid'; +import { SortableImageGrid } from '~/components/sortable/SortableImageGrid'; import { COMMENT_FILE_TYPES } from '~/constants/uploads'; import { useFileDropZone } from '~/hooks'; import { IFile } from '~/types'; @@ -27,34 +28,36 @@ const CommentFormAttaches: FC = () => { const onImageMove = useCallback( (newFiles: IFile[]) => { - setFiles([...filesAudios, ...newFiles.filter(it => it)]); + setFiles([...filesAudios, ...newFiles.filter((it) => it)]); }, - [setFiles, filesImages, filesAudios] + [setFiles, filesImages, filesAudios], ); const onAudioMove = useCallback( (newFiles: IFile[]) => { setFiles([...filesImages, ...newFiles]); }, - [setFiles, filesImages, filesAudios] + [setFiles, filesImages, filesAudios], ); const onFileDelete = useCallback( (fileId: IFile['id']) => { - setFiles(files.filter(file => file.id !== fileId)); + setFiles(files.filter((file) => file.id !== fileId)); }, - [files, setFiles] + [files, setFiles], ); const onAudioTitleChange = useCallback( (fileId: IFile['id'], title: string) => { setFiles( - files.map(file => - file.id === fileId ? { ...file, metadata: { ...file.metadata, title } } : file - ) + files.map((file) => + file.id === fileId + ? { ...file, metadata: { ...file.metadata, title } } + : file, + ), ); }, - [files, setFiles] + [files, setFiles], ); if (!hasAttaches) return null; diff --git a/src/components/editors/AudioGrid/index.tsx b/src/components/editors/AudioGrid/index.tsx index 7233a82e..6900a847 100644 --- a/src/components/editors/AudioGrid/index.tsx +++ b/src/components/editors/AudioGrid/index.tsx @@ -1,6 +1,6 @@ import React, { FC, useCallback } from 'react'; -import { SortableAudioGrid } from '~/components/sortable'; +import { SortableAudioGrid } from '~/components/sortable/SortableAudioGrid'; import { UploadStatus } from '~/store/uploader/UploaderStore'; import { IFile } from '~/types'; @@ -15,25 +15,27 @@ const AudioGrid: FC = ({ files, setFiles, locked }) => { (newFiles: IFile[]) => { setFiles(newFiles); }, - [setFiles, files] + [setFiles, files], ); const onDrop = useCallback( (remove_id: IFile['id']) => { - setFiles(files.filter(file => file && file.id !== remove_id)); + setFiles(files.filter((file) => file && file.id !== remove_id)); }, - [setFiles, files] + [setFiles, files], ); const onTitleChange = useCallback( (changeId: IFile['id'], title: string) => { setFiles( - files.map(file => - file && file.id === changeId ? { ...file, metadata: { ...file.metadata, title } } : file - ) + files.map((file) => + file && file.id === changeId + ? { ...file, metadata: { ...file.metadata, title } } + : file, + ), ); }, - [setFiles, files] + [setFiles, files], ); return ( diff --git a/src/components/editors/ImageGrid/index.tsx b/src/components/editors/ImageGrid/index.tsx index 9768d3a9..2556ee2a 100644 --- a/src/components/editors/ImageGrid/index.tsx +++ b/src/components/editors/ImageGrid/index.tsx @@ -1,6 +1,6 @@ import React, { FC, useCallback } from 'react'; -import { SortableImageGrid } from '~/components/sortable'; +import { SortableImageGrid } from '~/components/sortable/SortableImageGrid'; import { useWindowSize } from '~/hooks/dom/useWindowSize'; import { UploadStatus } from '~/store/uploader/UploaderStore'; import { IFile } from '~/types'; @@ -16,14 +16,14 @@ const ImageGrid: FC = ({ files, setFiles, locked }) => { const onMove = useCallback( (newFiles: IFile[]) => { - setFiles(newFiles.filter(it => it)); + setFiles(newFiles.filter((it) => it)); }, [setFiles, files], ); const onDrop = useCallback( (id: IFile['id']) => { - setFiles(files.filter(file => file && file.id !== id)); + setFiles(files.filter((file) => file && file.id !== id)); }, [setFiles, files], ); diff --git a/src/components/menu/index.ts b/src/components/menu/index.ts deleted file mode 100644 index b4bd97b4..00000000 --- a/src/components/menu/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -export * from './VerticalMenu'; -export * from './HorizontalMenu'; -export * from './MenuButton'; -export * from './MenuItemWithIcon'; -export * from './SeparatedMenu'; diff --git a/src/components/node/MenuButton/index.tsx b/src/components/node/MenuButton/index.tsx deleted file mode 100644 index 0ccbe2ce..00000000 --- a/src/components/node/MenuButton/index.tsx +++ /dev/null @@ -1,38 +0,0 @@ -import React, { FC } from 'react'; - -import { Filler } from '~/components/containers/Filler'; -import { Group } from '~/components/containers/Group'; - -import styles from './styles.module.scss'; - -interface IProps { - title: string; - description?: string; - icon: string; -} - -const MenuButton: FC = ({ - title, - icon, - description, -}) => ( -
- -
- - - - -
- - -
{title}
- { description &&
{description}
} -
-
-
-); - -export { MenuButton }; diff --git a/src/components/node/MenuButton/styles.module.scss b/src/components/node/MenuButton/styles.module.scss deleted file mode 100644 index e407f5f5..00000000 --- a/src/components/node/MenuButton/styles.module.scss +++ /dev/null @@ -1,29 +0,0 @@ -@import 'src/styles/variables'; - -.button { - fill: white; - height: 48px; - display: flex; - align-items: center; -} - -.icon { - flex: 0 0 38px; - align-items: center; - justify-content: center; - display: flex; -} - -.title { - font: $font_16_semibold; - text-transform: uppercase; - margin-bottom: 2px; - white-space: nowrap; - flex: 1; -} - -.description { - font: $font_12_regular; - color: $gray_75; - white-space: nowrap; -} diff --git a/src/components/node/NodeEditMenu/index.tsx b/src/components/node/NodeEditMenu/index.tsx index c7edb676..dff702bd 100644 --- a/src/components/node/NodeEditMenu/index.tsx +++ b/src/components/node/NodeEditMenu/index.tsx @@ -3,7 +3,9 @@ import React, { VFC } from 'react'; import Tippy from '@tippyjs/react'; import { Icon } from '~/components/input/Icon'; -import { MenuButton, MenuItemWithIcon, SeparatedMenu } from '~/components/menu'; +import { MenuButton } from '~/components/menu/MenuButton'; +import { MenuItemWithIcon } from '~/components/menu/MenuItemWithIcon'; +import { SeparatedMenu } from '~/components/menu/SeparatedMenu'; import { useWindowSize } from '~/hooks/dom/useWindowSize'; import styles from './styles.module.scss'; diff --git a/src/components/node/NodeTitle/index.tsx b/src/components/node/NodeTitle/index.tsx index cc821ee8..d33a4bab 100644 --- a/src/components/node/NodeTitle/index.tsx +++ b/src/components/node/NodeTitle/index.tsx @@ -3,7 +3,7 @@ import React, { memo, VFC } from 'react'; import classNames from 'classnames'; import { Icon } from '~/components/input/Icon'; -import { SeparatedMenu } from '~/components/menu'; +import { SeparatedMenu } from '~/components/menu/SeparatedMenu'; import { NodeEditMenu } from '~/components/node/NodeEditMenu'; import { Placeholder } from '~/components/placeholders/Placeholder'; import { getPrettyDate } from '~/utils/dom'; @@ -35,7 +35,6 @@ interface IProps { const NodeTitle: VFC = memo( ({ - id, title, username, createdAt, @@ -69,7 +68,9 @@ const NodeTitle: VFC = memo( {isLoading ? ( ) : ( - `~${username.toLocaleLowerCase()}, ${getPrettyDate(createdAt)}` + `~${username.toLocaleLowerCase()}, ${getPrettyDate( + createdAt, + )}` )} )} @@ -90,7 +91,9 @@ const NodeTitle: VFC = memo( {canLike && (
{isLiked ? ( @@ -107,7 +110,7 @@ const NodeTitle: VFC = memo(
); - } + }, ); export { NodeTitle }; diff --git a/src/components/sortable/SortableGrid/index.tsx b/src/components/sortable/SortableGrid/index.tsx index 8aec86ec..68b4c4ae 100644 --- a/src/components/sortable/SortableGrid/index.tsx +++ b/src/components/sortable/SortableGrid/index.tsx @@ -5,7 +5,7 @@ import { rectSortingStrategy, SortableContext } from '@dnd-kit/sortable'; import classNames from 'classnames'; import { DragOverlayItem } from '~/components/sortable/DragOverlayItem'; -import { useSortableActions } from '~/hooks/sortable'; +import { useSortableActions } from '~/hooks/sortable/useSortableActions'; import { DivProps } from '~/utils/types'; import { SortableItem } from '../SortableItem'; @@ -16,7 +16,7 @@ interface SortableGridProps< ItemRendererProps extends {}, LockedRendererProps extends {}, Item extends {}, - Locked extends {} + Locked extends {}, > { items: Item[]; locked: Locked[]; @@ -44,18 +44,18 @@ const SortableGrid = ({ onSortEnd, size, }: SortableGridProps) => { - const { sensors, onDragEnd, onDragStart, draggingItem, ids } = useSortableActions( - items, - getID, - onSortEnd - ); + const { sensors, onDragEnd, onDragStart, draggingItem, ids } = + useSortableActions(items, getID, onSortEnd); const gridStyle = useMemo( () => size - ? { gridTemplateColumns: size && `repeat(auto-fill, minmax(${size}px, 1fr))` } + ? { + gridTemplateColumns: + size && `repeat(auto-fill, minmax(${size}px, 1fr))`, + } : undefined, - [size] + [size], ); return ( @@ -67,30 +67,35 @@ const SortableGrid = ({ >
- {items.map(item => ( + {items.map((item) => ( {createElement(renderItem, { ...renderItemProps, item })} ))} - {locked.map(item => + {locked.map((item) => createElement(renderLocked, { ...renderLockedProps, locked: item, key: getLockedID(item), - }) + }), )} {draggingItem ? ( - {createElement(renderItem, { ...renderItemProps, item: draggingItem })} + {createElement(renderItem, { + ...renderItemProps, + item: draggingItem, + })} ) : null} diff --git a/src/components/sortable/SortableList/index.tsx b/src/components/sortable/SortableList/index.tsx index 73b6bf79..0f815719 100644 --- a/src/components/sortable/SortableList/index.tsx +++ b/src/components/sortable/SortableList/index.tsx @@ -1,12 +1,15 @@ import React, { createElement, FC } from 'react'; import { closestCenter, DndContext, DragOverlay } from '@dnd-kit/core'; -import { SortableContext, verticalListSortingStrategy } from '@dnd-kit/sortable'; +import { + SortableContext, + verticalListSortingStrategy, +} from '@dnd-kit/sortable'; import classNames from 'classnames'; import { DragOverlayItem } from '~/components/sortable/DragOverlayItem'; import { SortableItem } from '~/components/sortable/SortableItem'; -import { useSortableActions } from '~/hooks/sortable'; +import { useSortableActions } from '~/hooks/sortable/useSortableActions'; import styles from './styles.module.scss'; @@ -14,7 +17,7 @@ interface SortableListProps< RenderItemProps extends {}, RenderLockedProps extends {}, Item extends {}, - Locked extends {} + Locked extends {}, > { items: Item[]; locked: Locked[]; @@ -40,11 +43,8 @@ const SortableList = ({ renderLockedProps, onSortEnd, }: SortableListProps) => { - const { sensors, onDragEnd, onDragStart, draggingItem, ids } = useSortableActions( - items, - getID, - onSortEnd - ); + const { sensors, onDragEnd, onDragStart, draggingItem, ids } = + useSortableActions(items, getID, onSortEnd); return ( ({ >
- {items.map(item => ( + {items.map((item) => ( - {createElement(renderItem, { ...renderItemProps, item, key: getID(item) })} + {createElement(renderItem, { + ...renderItemProps, + item, + key: getID(item), + })} ))} - {locked.map(item => + {locked.map((item) => createElement(renderLocked, { ...renderLockedProps, locked: item, key: getLockedID(item), - }) + }), )} {draggingItem ? ( - {createElement(renderItem, { ...renderItemProps, item: draggingItem })} + {createElement(renderItem, { + ...renderItemProps, + item: draggingItem, + })} ) : null} diff --git a/src/components/sortable/index.ts b/src/components/sortable/index.ts deleted file mode 100644 index 0246de31..00000000 --- a/src/components/sortable/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './SortableImageGrid'; -export * from './SortableAudioGrid'; diff --git a/src/constants/api.ts b/src/constants/api.ts index a64dda1b..6cb36bf4 100644 --- a/src/constants/api.ts +++ b/src/constants/api.ts @@ -5,38 +5,43 @@ import { CONFIG } from '~/utils/config'; export const API = { BASE: CONFIG.apiHost, USER: { - LOGIN: '/user/login', - OAUTH_WINDOW: (provider: OAuthProvider) => `${CONFIG.apiHost}oauth/${provider}/redirect`, - ME: '/user/', - PROFILE: (username: string) => `/user/user/${username}/profile`, - MESSAGES: (username: string) => `/user/user/${username}/messages`, - MESSAGE_SEND: (username: string) => `/user/user/${username}/messages`, - MESSAGE_DELETE: (username: string, id: number) => `/user/user/${username}/messages/${id}`, - GET_UPDATES: '/user/updates', - REQUEST_CODE: (code?: string) => `/user/restore/${code || ''}`, + LOGIN: '/auth', + OAUTH_WINDOW: (provider: OAuthProvider) => + `${CONFIG.apiHost}oauth/${provider}/redirect`, + ME: '/auth', + UPDATE_PHOTO: '/auth/photo', + UPDATE_COVER: '/auth/photo', + PROFILE: (username: string) => `/users/${username}/profile`, + MESSAGES: (username: string) => `/users/${username}/messages`, + MESSAGE_SEND: (username: string) => `/users/${username}/messages`, + MESSAGE_DELETE: (username: string, id: number) => + `/users/${username}/messages/${id}`, + GET_UPDATES: '/auth/updates', + REQUEST_CODE: (code?: string) => `/auth/restore/${code || ''}`, UPLOAD: (target, type) => `/upload/${target}/${type}`, - GET_SOCIALS: '/oauth/', + GET_SOCIALS: '/oauth', DROP_SOCIAL: (provider, id) => `/oauth/${provider}/${id}`, - ATTACH_SOCIAL: `/oauth/attach`, - LOGIN_WITH_SOCIAL: `/oauth/login`, + ATTACH_SOCIAL: `/oauth`, + LOGIN_WITH_SOCIAL: `/oauth`, }, - NODE: { - SAVE: '/node/', - GET: '/node/', - GET_DIFF: '/flow/diff', - GET_NODE: (id: number | string) => `/node/${id}`, + NODES: { + SAVE: '/nodes/', + LIST: '/nodes/', + GET: (id: number | string) => `/nodes/${id}`, + DELETE: (id: INode['id']) => `/nodes/${id}`, + LIKE: (id: INode['id']) => `/nodes/${id}/like`, + HEROIC: (id: INode['id']) => `/nodes/${id}/heroic`, + SET_CELL_VIEW: (id: INode['id']) => `/nodes/${id}/cell-view`, + RELATED: (id: INode['id']) => `/nodes/${id}/related`, - COMMENT: (id: INode['id'] | string) => `/node/${id}/comment`, - RELATED: (id: INode['id']) => `/node/${id}/related`, - UPDATE_TAGS: (id: INode['id']) => `/node/${id}/tags`, - DELETE_TAG: (id: INode['id'], tagId: ITag['ID']) => `/node/${id}/tags/${tagId}`, - POST_LIKE: (id: INode['id']) => `/node/${id}/like`, - POST_HEROIC: (id: INode['id']) => `/node/${id}/heroic`, - POST_LOCK: (id: INode['id']) => `/node/${id}/lock`, + UPDATE_TAGS: (id: INode['id']) => `/nodes/${id}/tags`, + DELETE_TAG: (id: INode['id'], tagId: ITag['ID']) => + `/nodes/${id}/tags/${tagId}`, + + COMMENT: (id: INode['id'] | string) => `/nodes/${id}/comments`, LOCK_COMMENT: (id: INode['id'], comment_id: IComment['id']) => - `/node/${id}/comment/${comment_id}/lock`, - SET_CELL_VIEW: (id: INode['id']) => `/node/${id}/cell-view`, + `/nodes/${id}/comments/${comment_id}`, }, SEARCH: { NODES: '/search/nodes', @@ -49,12 +54,12 @@ export const API = { GITHUB_ISSUES: 'https://api.github.com/repos/muerwre/vault-frontend/issues', }, TAG: { - NODES: `/tag/nodes`, - AUTOCOMPLETE: `/tag/autocomplete`, + NODES: `/tags/nodes`, + AUTOCOMPLETE: `/tags/autocomplete`, }, LAB: { - NODES: `/lab/`, - STATS: '/lab/stats', - UPDATES: '/lab/updates', + NODES: `/nodes/lab`, + STATS: '/nodes/lab/stats', + UPDATES: '/nodes/lab/updates', }, }; diff --git a/src/containers/profile/ProfileSidebarLogoutButton/index.tsx b/src/containers/profile/ProfileSidebarLogoutButton/index.tsx index f2311214..c2726820 100644 --- a/src/containers/profile/ProfileSidebarLogoutButton/index.tsx +++ b/src/containers/profile/ProfileSidebarLogoutButton/index.tsx @@ -3,8 +3,7 @@ import React, { FC } from 'react'; import { Group } from '~/components/containers/Group'; import { Padder } from '~/components/containers/Padder'; import { Button } from '~/components/input/Button'; -import { Icon } from '~/components/input/Icon'; -import { MenuButton } from '~/components/menu'; +import { MenuButton } from '~/components/menu/MenuButton'; import styles from './styles.module.scss'; @@ -12,17 +11,30 @@ interface ProfileSidebarLogoutButtonProps { onLogout?: () => void; } -const ProfileSidebarLogoutButton: FC = ({ onLogout }) => ( - Выйти} position="top-end"> +const ProfileSidebarLogoutButton: FC = ({ + onLogout, +}) => ( + + Выйти + + } + position="top-end" + >
Захотелось наружу?
Там холодно, страшно и больше не раздают пончики!
-
+
+ +
); -export { ProfileSidebarLogoutButton } \ No newline at end of file +export { ProfileSidebarLogoutButton }; diff --git a/src/containers/settings/UserSettingsView/index.tsx b/src/containers/settings/UserSettingsView/index.tsx index f1cffc85..8b9bafee 100644 --- a/src/containers/settings/UserSettingsView/index.tsx +++ b/src/containers/settings/UserSettingsView/index.tsx @@ -16,9 +16,6 @@ import styles from './styles.module.scss'; interface UserSettingsViewProps {} -const getError = (error?: string) => - error && has(error, ERROR_LITERAL) ? error : undefined; - const UserSettingsView: FC = () => { const { values, handleChange, errors } = useSettings(); const { isPhone } = useWindowSize(); @@ -41,7 +38,7 @@ const UserSettingsView: FC = () => { value={values.fullname} handler={handleChange('fullname')} title="Полное имя" - error={getError(errors.fullname)} + error={errors.fullname} />