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

refactored component errors

This commit is contained in:
Fedor Katurov 2021-03-03 17:54:58 +07:00
parent 7031084b09
commit d4c2e7ee09
79 changed files with 573 additions and 462 deletions

View file

@ -1,43 +1,42 @@
import React, { FC, useCallback, useEffect, useState } from "react";
import styles from "./styles.module.scss";
import { connect } from "react-redux";
import { getURL } from "~/utils/dom";
import { pick } from "ramda";
import { selectAuthProfile, selectAuthUser } from "~/redux/auth/selectors";
import { PRESETS } from "~/constants/urls";
import { selectUploads } from "~/redux/uploads/selectors";
import { IFileWithUUID } from "~/redux/types";
import uuid from "uuid4";
import { UPLOAD_SUBJECTS, UPLOAD_TARGETS, UPLOAD_TYPES } from "~/redux/uploads/constants";
import React, { FC, useCallback, useEffect, useState } from 'react';
import styles from './styles.module.scss';
import { connect } from 'react-redux';
import { getURL } from '~/utils/dom';
import { pick } from 'ramda';
import { selectAuthProfile, selectAuthUser } from '~/redux/auth/selectors';
import { PRESETS } from '~/constants/urls';
import { selectUploads } from '~/redux/uploads/selectors';
import { IFileWithUUID } from '~/redux/types';
import uuid from 'uuid4';
import { UPLOAD_SUBJECTS, UPLOAD_TARGETS, UPLOAD_TYPES } from '~/redux/uploads/constants';
import { path } from 'ramda';
import * as UPLOAD_ACTIONS from "~/redux/uploads/actions";
import * as AUTH_ACTIONS from "~/redux/auth/actions";
import { Icon } from "~/components/input/Icon";
import * as UPLOAD_ACTIONS from '~/redux/uploads/actions';
import * as AUTH_ACTIONS from '~/redux/auth/actions';
import { Icon } from '~/components/input/Icon';
const mapStateToProps = state => ({
user: pick(["id"], selectAuthUser(state)),
profile: pick(["is_loading", "user"], selectAuthProfile(state)),
uploads: pick(["statuses", "files"], selectUploads(state))
user: pick(['id'], selectAuthUser(state)),
profile: pick(['is_loading', 'user'], selectAuthProfile(state)),
uploads: pick(['statuses', 'files'], selectUploads(state)),
});
const mapDispatchToProps = {
uploadUploadFiles: UPLOAD_ACTIONS.uploadUploadFiles,
authPatchUser: AUTH_ACTIONS.authPatchUser
authPatchUser: AUTH_ACTIONS.authPatchUser,
};
type IProps = ReturnType<typeof mapStateToProps> &
typeof mapDispatchToProps & {};
type IProps = ReturnType<typeof mapStateToProps> & typeof mapDispatchToProps & {};
const ProfileAvatarUnconnected: FC<IProps> = ({
user: { id },
profile: { is_loading, user },
uploads: { statuses, files },
uploadUploadFiles,
authPatchUser
authPatchUser,
}) => {
const can_edit = !is_loading && id && id === user.id;
const can_edit = !is_loading && id && id === user?.id;
const [temp, setTemp] = useState<string>(null);
const [temp, setTemp] = useState<string>('');
useEffect(() => {
if (!can_edit) return;
@ -45,7 +44,7 @@ const ProfileAvatarUnconnected: FC<IProps> = ({
Object.entries(statuses).forEach(([id, status]) => {
if (temp === id && !!status.uuid && files[status.uuid]) {
authPatchUser({ photo: files[status.uuid] });
setTemp(null);
setTemp('');
}
});
}, [statuses, files, temp, can_edit, authPatchUser]);
@ -58,11 +57,11 @@ const ProfileAvatarUnconnected: FC<IProps> = ({
temp_id: uuid(),
subject: UPLOAD_SUBJECTS.AVATAR,
target: UPLOAD_TARGETS.PROFILES,
type: UPLOAD_TYPES.IMAGE
type: UPLOAD_TYPES.IMAGE,
})
);
setTemp(path([0, "temp_id"], items));
setTemp(path([0, 'temp_id'], items) || '');
uploadUploadFiles(items.slice(0, 1));
},
[uploadUploadFiles, setTemp]
@ -81,13 +80,15 @@ const ProfileAvatarUnconnected: FC<IProps> = ({
[onUpload, can_edit]
);
const backgroundImage = is_loading
? undefined
: `url("${user && getURL(user.photo, PRESETS.avatar)}")`;
return (
<div
className={styles.avatar}
style={{
backgroundImage: is_loading
? null
: `url("${user && getURL(user.photo, PRESETS.avatar)}")`
backgroundImage,
}}
>
{can_edit && <input type="file" onInput={onInputChange} />}
@ -100,9 +101,6 @@ const ProfileAvatarUnconnected: FC<IProps> = ({
);
};
const ProfileAvatar = connect(
mapStateToProps,
mapDispatchToProps
)(ProfileAvatarUnconnected);
const ProfileAvatar = connect(mapStateToProps, mapDispatchToProps)(ProfileAvatarUnconnected);
export { ProfileAvatar };

View file

@ -1,5 +1,5 @@
import React, { FC, ReactNode } from 'react';
import { IUser } from '~/redux/auth/types';
import { IAuthState, IUser } from '~/redux/auth/types';
import styles from './styles.module.scss';
import { Group } from '~/components/containers/Group';
import { Placeholder } from '~/components/placeholders/Placeholder';
@ -14,7 +14,7 @@ interface IProps {
is_loading?: boolean;
is_own?: boolean;
setTab?: (tab: string) => void;
setTab?: (tab: IAuthState['profile']['tab']) => void;
content?: ReactNode;
}
@ -26,16 +26,16 @@ const ProfileInfo: FC<IProps> = ({ user, tab, is_loading, is_own, setTab, conten
<div className={styles.field}>
<div className={styles.name}>
{is_loading ? <Placeholder width="80%" /> : user.fullname || user.username}
{is_loading ? <Placeholder width="80%" /> : user?.fullname || user?.username}
</div>
<div className={styles.description}>
{is_loading ? <Placeholder /> : getPrettyDate(user.last_seen)}
{is_loading ? <Placeholder /> : getPrettyDate(user?.last_seen)}
</div>
</div>
</Group>
<ProfileTabs tab={tab} is_own={is_own} setTab={setTab} />
<ProfileTabs tab={tab} is_own={!!is_own} setTab={setTab} />
{content}
</div>

View file

@ -20,10 +20,10 @@ const ProfileLayoutUnconnected: FC<IProps> = ({ history, nodeSetCoverImage }) =>
const {
params: { username },
} = useRouteMatch<{ username: string }>();
const [user, setUser] = useState<IUser>(null);
const [user, setUser] = useState<IUser | undefined>(undefined);
useEffect(() => {
if (user) setUser(null);
if (user) setUser(undefined);
}, [username]);
useEffect(() => {

View file

@ -31,7 +31,7 @@ const ProfileMessagesUnconnected: FC<IProps> = ({
messagesRefreshMessages,
}) => {
const wasAtBottom = useRef(true);
const [wrap, setWrap] = useState<HTMLDivElement>(null);
const [wrap, setWrap] = useState<HTMLDivElement | undefined>(undefined);
const [editingMessageId, setEditingMessageId] = useState(0);
const onEditMessage = useCallback((id: number) => setEditingMessageId(id), [setEditingMessageId]);
@ -95,31 +95,33 @@ const ProfileMessagesUnconnected: FC<IProps> = ({
if (!messages.messages.length || profile.is_loading)
return <NodeNoComments is_loading={messages.is_loading_messages || profile.is_loading} />;
return (
messages.messages.length > 0 && (
<div className={styles.messages} ref={storeRef}>
{messages.messages
.filter(message => !!message.text)
.map((
message // TODO: show files / memo
) => (
<Message
message={message}
incoming={id !== message.from.id}
key={message.id}
onEdit={onEditMessage}
onDelete={onDeleteMessage}
isEditing={editingMessageId === message.id}
onCancelEdit={onCancelEdit}
onRestore={onRestoreMessage}
/>
))}
if (messages.messages.length <= 0) {
return null;
}
{!messages.is_loading_messages && messages.messages.length > 0 && (
<div className={styles.placeholder}>Когда-нибудь здесь будут еще сообщения</div>
)}
</div>
)
return (
<div className={styles.messages} ref={storeRef}>
{messages.messages
.filter(message => !!message.text)
.map((
message // TODO: show files / memo
) => (
<Message
message={message}
incoming={id !== message.from.id}
key={message.id}
onEdit={onEditMessage}
onDelete={onDeleteMessage}
isEditing={editingMessageId === message.id}
onCancelEdit={onCancelEdit}
onRestore={onRestoreMessage}
/>
))}
{!messages.is_loading_messages && messages.messages.length > 0 && (
<div className={styles.placeholder}>Когда-нибудь здесь будут еще сообщения</div>
)}
</div>
);
};

View file

@ -1,11 +1,14 @@
import React, { FC, useMemo } from 'react';
import styles from './styles.module.scss';
import { IAuthState } from '~/redux/auth/types';
import { getURL } from '~/utils/dom';
import { formatText, getURL } from '~/utils/dom';
import { PRESETS, URLS } from '~/constants/urls';
import { Placeholder } from '~/components/placeholders/Placeholder';
import { Link } from 'react-router-dom';
import { Icon } from '~/components/input/Icon';
import classNames from 'classnames';
import styles from './styles.module.scss';
import markdown from '~/styles/common/markdown.module.scss';
interface IProps {
profile: IAuthState['profile'];
@ -26,11 +29,11 @@ const ProfilePageLeft: FC<IProps> = ({ username, profile }) => {
<div className={styles.region_wrap}>
<div className={styles.region}>
<div className={styles.name}>
{profile.is_loading ? <Placeholder /> : profile.user.fullname}
{profile.is_loading ? <Placeholder /> : profile?.user?.fullname}
</div>
<div className={styles.username}>
{profile.is_loading ? <Placeholder /> : `~${profile.user.username}`}
{profile.is_loading ? <Placeholder /> : `~${profile?.user?.username}`}
</div>
<div className={styles.menu}>
@ -53,7 +56,9 @@ const ProfilePageLeft: FC<IProps> = ({ username, profile }) => {
</div>
{profile && profile.user && profile.user.description && false && (
<div className={styles.description}>{profile.user.description}</div>
<div className={classNames(styles.description, markdown.wrapper)}>
{formatText(profile?.user?.description || '')}
</div>
)}
</div>
);

View file

@ -1,38 +1,49 @@
import React, { FC } from 'react';
import React, { FC, useCallback } from 'react';
import styles from './styles.module.scss';
import classNames from 'classnames';
import { IAuthState } from '~/redux/auth/types';
interface IProps {
tab: string;
is_own: boolean;
setTab: (tab: string) => void;
setTab?: (tab: IAuthState['profile']['tab']) => void;
}
const ProfileTabs: FC<IProps> = ({ tab, is_own, setTab }) => (
<div className={styles.wrap}>
<div
className={classNames(styles.tab, { [styles.active]: tab === 'profile' })}
onClick={() => setTab('profile')}
>
Профиль
const ProfileTabs: FC<IProps> = ({ tab, is_own, setTab }) => {
const changeTab = useCallback(
(tab: IAuthState['profile']['tab']) => () => {
if (!setTab) return;
setTab(tab);
},
[setTab]
);
return (
<div className={styles.wrap}>
<div
className={classNames(styles.tab, { [styles.active]: tab === 'profile' })}
onClick={changeTab('profile')}
>
Профиль
</div>
<div
className={classNames(styles.tab, { [styles.active]: tab === 'messages' })}
onClick={changeTab('messages')}
>
Сообщения
</div>
{is_own && (
<>
<div
className={classNames(styles.tab, { [styles.active]: tab === 'settings' })}
onClick={changeTab('settings')}
>
Настройки
</div>
</>
)}
</div>
<div
className={classNames(styles.tab, { [styles.active]: tab === 'messages' })}
onClick={() => setTab('messages')}
>
Сообщения
</div>
{is_own && (
<>
<div
className={classNames(styles.tab, { [styles.active]: tab === 'settings' })}
onClick={() => setTab('settings')}
>
Настройки
</div>
</>
)}
</div>
);
);
};
export { ProfileTabs };