From 9233ccbadab1df70dc0686ad3860410264d9e9c9 Mon Sep 17 00:00:00 2001 From: Fedor Katurov Date: Wed, 13 Nov 2019 15:09:05 +0700 Subject: [PATCH] random titles --- .../notifications/NotificationBubble/index.tsx | 5 ++++- .../notifications/NotificationBubble/styles.scss | 4 ++++ .../profile/ProfileDescription/index.tsx | 3 ++- .../profile/ProfileDescription/styles.scss | 1 + src/constants/phrases.ts | 14 ++++++++++++++ src/containers/node/BorisLayout/index.tsx | 6 ++++-- src/containers/node/BorisLayout/styles.scss | 5 +++++ src/redux/auth/api.ts | 6 ++++++ src/redux/auth/sagas.ts | 14 +++++++++++++- src/utils/validators.ts | 16 ++++++++++------ 10 files changed, 63 insertions(+), 11 deletions(-) create mode 100644 src/constants/phrases.ts diff --git a/src/components/notifications/NotificationBubble/index.tsx b/src/components/notifications/NotificationBubble/index.tsx index 043ae34f..513a7013 100644 --- a/src/components/notifications/NotificationBubble/index.tsx +++ b/src/components/notifications/NotificationBubble/index.tsx @@ -3,6 +3,7 @@ import { INotification, NOTIFICATION_TYPES } from '~/redux/types'; import styles from './styles.scss'; import { NotificationMessage } from '../NotificationMessage'; import { Icon } from '~/components/input/Icon'; +import { getRandomPhrase } from '~/constants/phrases'; interface IProps { notifications: INotification[]; @@ -14,13 +15,15 @@ const NOTIFICATION_RENDERERS = { }; const NotificationBubble: FC = ({ notifications, onClick }) => { + const placeholder = getRandomPhrase('NOTHING_HERE'); + return (
{notifications.length === 0 && (
-
НЕТ УВЕДОМЛЕНИЙ
+
{placeholder}
)} {notifications.length > 0 && diff --git a/src/components/notifications/NotificationBubble/styles.scss b/src/components/notifications/NotificationBubble/styles.scss index 47154066..216113be 100644 --- a/src/components/notifications/NotificationBubble/styles.scss +++ b/src/components/notifications/NotificationBubble/styles.scss @@ -87,6 +87,10 @@ $notification_color: darken($content_bg, 2%); flex-direction: column; text-transform: uppercase; font: $font_16_semibold; + box-sizing: border-box; + padding: 80px; + text-align: center; + line-height: 1.6em; svg { width: 120px; diff --git a/src/components/profile/ProfileDescription/index.tsx b/src/components/profile/ProfileDescription/index.tsx index 0fd7a816..db41a68b 100644 --- a/src/components/profile/ProfileDescription/index.tsx +++ b/src/components/profile/ProfileDescription/index.tsx @@ -5,6 +5,7 @@ import styles from './styles.scss'; import { connect } from 'react-redux'; import { selectAuthProfile } from '~/redux/auth/selectors'; import { ProfileLoader } from '~/containers/profile/ProfileLoader'; +import { Group } from '~/components/containers/Group'; const mapStateToProps = state => ({ profile: selectAuthProfile(state), @@ -18,7 +19,7 @@ const ProfileDescriptionUnconnected: FC = ({ profile: { user, is_loading return (
{user.description && ( -
diff --git a/src/components/profile/ProfileDescription/styles.scss b/src/components/profile/ProfileDescription/styles.scss index 6da2db0d..ef27a6d1 100644 --- a/src/components/profile/ProfileDescription/styles.scss +++ b/src/components/profile/ProfileDescription/styles.scss @@ -3,6 +3,7 @@ min-height: 200px; display: flex; box-sizing: border-box; + flex-direction: column; } .placeholder { diff --git a/src/constants/phrases.ts b/src/constants/phrases.ts new file mode 100644 index 00000000..998b19eb --- /dev/null +++ b/src/constants/phrases.ts @@ -0,0 +1,14 @@ +import { useMemo } from 'react'; + +export const PHRASES = { + BORIS_TITLE: ['Снова вместе', 'Я видел это во сне', 'Что тут у нас?'], + NOTHING_HERE: [ + 'Тут пусто и одиноко', + 'Совсем ничего', + 'Хм... Где все?', + 'Тут будут наши с тобой сообщения', + ], +}; + +export const getRandomPhrase = (key: keyof typeof PHRASES) => + useMemo(() => PHRASES[key][Math.floor(Math.random() * PHRASES[key].length)], []); diff --git a/src/containers/node/BorisLayout/index.tsx b/src/containers/node/BorisLayout/index.tsx index 94f1e09b..33076dfc 100644 --- a/src/containers/node/BorisLayout/index.tsx +++ b/src/containers/node/BorisLayout/index.tsx @@ -10,6 +10,7 @@ import { CommentForm } from '~/components/node/CommentForm'; import { Group } from '~/components/containers/Group'; import boris from '~/sprites/boris_robot.svg'; import { NodeNoComments } from '~/components/node/NodeNoComments'; +import { getRandomPhrase } from '~/constants/phrases'; const mapStateToProps = state => ({ node: selectNode(state), @@ -36,6 +37,8 @@ const BorisLayoutUnconnected: FC = ({ user: { is_user }, nodeLoadNode, }) => { + const title = getRandomPhrase('BORIS_TITLE'); + useEffect(() => { if (is_loading) return; nodeLoadNode(id, 'DESC'); @@ -47,8 +50,7 @@ const BorisLayoutUnconnected: FC = ({
-
СНОВА
-
ВМЕСТЕ
+
{title}
diff --git a/src/containers/node/BorisLayout/styles.scss b/src/containers/node/BorisLayout/styles.scss index c25fd6d4..a6a7eb58 100644 --- a/src/containers/node/BorisLayout/styles.scss +++ b/src/containers/node/BorisLayout/styles.scss @@ -129,3 +129,8 @@ font-size: 48px; } } + +.caption_text { + max-width: 400px; + text-transform: uppercase; +} diff --git a/src/redux/auth/api.ts b/src/redux/auth/api.ts index a984909e..5dfa2f1b 100644 --- a/src/redux/auth/api.ts +++ b/src/redux/auth/api.ts @@ -60,3 +60,9 @@ export const apiAuthGetUpdates = ({ .get(API.USER.GET_UPDATES, configWithToken(access, { params: { exclude_dialogs, last } })) .then(resultMiddleware) .catch(errorMiddleware); + +export const apiUpdateUser = ({ access, user }): Promise> => + api + .patch(API.USER.ME, { user }, configWithToken(access)) + .then(resultMiddleware) + .catch(errorMiddleware); diff --git a/src/redux/auth/sagas.ts b/src/redux/auth/sagas.ts index 8d329ec3..11879a61 100644 --- a/src/redux/auth/sagas.ts +++ b/src/redux/auth/sagas.ts @@ -12,6 +12,7 @@ import { authSendMessage, authSetUpdates, authLoggedIn, + authSetLastSeenMessages, } from '~/redux/auth/actions'; import { apiUserLogin, @@ -20,6 +21,7 @@ import { apiAuthGetUserMessages, apiAuthSendMessage, apiAuthGetUpdates, + apiUpdateUser, } from '~/redux/auth/api'; import { modalSetShown, modalShowDialog } from '~/redux/modal/actions'; import { selectToken, selectAuthProfile, selectAuthUser, selectAuthUpdates } from './selectors'; @@ -248,15 +250,25 @@ function* startPollingSaga() { } } +function* setLastSeenMessages({ last_seen_messages }: ReturnType) { + if (!Date.parse(last_seen_messages)) return; + + const { data, error } = yield call(reqWrapper, apiUpdateUser, { user: { last_seen_messages } }); + + console.log({ data, error }); +} + function* authSaga() { yield takeLatest(REHYDRATE, checkUserSaga); + yield takeLatest([REHYDRATE, AUTH_USER_ACTIONS.LOGGED_IN], startPollingSaga); + yield takeLatest(AUTH_USER_ACTIONS.LOGOUT, logoutSaga); yield takeLatest(AUTH_USER_ACTIONS.SEND_LOGIN_REQUEST, sendLoginRequestSaga); yield takeLatest(AUTH_USER_ACTIONS.GOT_AUTH_POST_MESSAGE, gotPostMessageSaga); yield takeLatest(AUTH_USER_ACTIONS.OPEN_PROFILE, openProfile); yield takeLatest(AUTH_USER_ACTIONS.GET_MESSAGES, getMessages); yield takeLatest(AUTH_USER_ACTIONS.SEND_MESSAGE, sendMessage); - yield takeLatest([REHYDRATE, AUTH_USER_ACTIONS.LOGGED_IN], startPollingSaga); + yield takeLatest(AUTH_USER_ACTIONS.SET_LAST_SEEN_MESSAGES, setLastSeenMessages); } export default authSaga; diff --git a/src/utils/validators.ts b/src/utils/validators.ts index 58eda5c3..8c50b790 100644 --- a/src/utils/validators.ts +++ b/src/utils/validators.ts @@ -1,18 +1,21 @@ import isValid from 'date-fns/isValid'; import { IMAGE_MIME_TYPES } from '~/utils/uploader'; -const isValidEmail = (email: string): boolean => !!email - && String(email) - && !!String(email).match( +const isValidEmail = (email: string): boolean => + !!email && + String(email) && + !!String(email).match( /^[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/ ); -const isLikeEmail = (email: string): boolean => !!email && String(email) && !!String(email).match(/^([^\@]+)@([^\@]+)\.([^\@]+)$$/); +const isLikeEmail = (email: string): boolean => + !!email && String(email) && !!String(email).match(/^([^\@]+)@([^\@]+)\.([^\@]+)$$/); const isNonEmpty = (value: string): boolean => !!value && value.trim().length > 0; const isLikePhone = isNonEmpty; -const isAtLeast = (length: number, value: string): boolean => !!value && value.trim().length >= length; +const isAtLeast = (length: number, value: string): boolean => + !!value && value.trim().length >= length; const isMimeOfImage = (mime): boolean => !!mime && IMAGE_MIME_TYPES.indexOf(mime) >= 0; @@ -28,5 +31,6 @@ export const VALIDATORS = { IS_IMAGE_MIME: isMimeOfImage, IS_DATE: isDate, IS_STRINGY_DATE: isStringDate, - EVOLVE: (validator: (val: any) => boolean, error: string) => (val: any) => (!val || !validator(val) ? error : null) + EVOLVE: (validator: (val: any) => boolean, error: string) => (val: any) => + !val || !validator(val) ? error : null, };