diff --git a/constants.ts b/constants.ts index a6d4512..f43abc1 100644 --- a/constants.ts +++ b/constants.ts @@ -1 +1,2 @@ export const BACKEND_URL = 'http://localhost:3333'; +export const WS_URL = 'ws://localhost:3333'; diff --git a/src/api.config.ts b/src/api.config.ts index 6a20d45..aa818a4 100644 --- a/src/api.config.ts +++ b/src/api.config.ts @@ -1,7 +1,8 @@ import { AxiosRequestConfig } from 'axios'; +import * as constants from '../constants'; const apiConfig: AxiosRequestConfig = { - baseURL: '/api/', + baseURL: `${constants.BACKEND_URL}/api/`, responseType: 'json', withCredentials: true, }; diff --git a/src/components/Chat/Sidebar/Users/User/Avatar.tsx b/src/components/Chat/Sidebar/Users/User/Avatar.tsx index 3e7ceac..d5caa58 100644 --- a/src/components/Chat/Sidebar/Users/User/Avatar.tsx +++ b/src/components/Chat/Sidebar/Users/User/Avatar.tsx @@ -1,5 +1,7 @@ import React from 'react'; import { Avatar as ChakraAvatar, AvatarBadge, WrapItem } from '@chakra-ui/react'; +import { useRootStore } from '@educt/hooks/useRootStore'; +import { MdOutlineBookmark } from 'react-icons/md'; export interface IAvatarProps { fullname: string; @@ -7,12 +9,21 @@ export interface IAvatarProps { } const Avatar: React.FC = ({ fullname: name, isOnline }) => { + const { + userStore: { me }, + } = useRootStore(); + const isMe = me?.fullname === name; const onlineBg = isOnline ? 'green.500' : 'red.500'; return ( - - + } + size='md' + > + {!isMe && } ); diff --git a/src/components/Chat/Sidebar/Users/User/Info.tsx b/src/components/Chat/Sidebar/Users/User/Info.tsx index 9b74a71..90dc789 100644 --- a/src/components/Chat/Sidebar/Users/User/Info.tsx +++ b/src/components/Chat/Sidebar/Users/User/Info.tsx @@ -1,5 +1,6 @@ import React from 'react'; import { Box, Text } from '@chakra-ui/react'; +import { useRootStore } from '@educt/hooks/useRootStore'; export interface IInfoProps { fullname: string; @@ -7,10 +8,15 @@ export interface IInfoProps { } const Info: React.FC = ({ fullname, lastMessage }) => { + const { + userStore: { me }, + } = useRootStore(); + const isMe = me?.fullname === fullname; + return ( - {fullname}
+ {isMe ? 'Favorites' : fullname}
{lastMessage} diff --git a/src/components/Chat/Window/Window.tsx b/src/components/Chat/Window/Window.tsx index 26ffb6d..219f70c 100644 --- a/src/components/Chat/Window/Window.tsx +++ b/src/components/Chat/Window/Window.tsx @@ -38,6 +38,8 @@ const Window: React.FC = props => { const history = useHistory(); const toast = useToast(); + const isMe = me?.id === selectedUser?.id; + const onSubmit = (e: React.FormEvent) => { e.preventDefault(); @@ -54,7 +56,7 @@ const Window: React.FC = props => { * Emit event to server and update messages state */ if (chatId) { - socket?.emit('message:private', { + socket?.emit('chat:message', { content: message.content, to: chatId, }); @@ -74,7 +76,22 @@ const Window: React.FC = props => { try { setIsLoading(true); const { data: user } = await UserServiceInstance.fetchUserById(chatId); + const { + data: { history }, + } = await UserServiceInstance.fetchChatHistory(chatId); + + // TODO add type for message + const messages = history.map(message => { + return { + isMyMessage: message.from === me.id, + content: message.content, + time: new Date(message.time).toLocaleTimeString(), + userName: message.from === me.id ? me.fullname : user.fullname, + }; + }); + setSelectedUser(user); + setMessages(messages); } catch (error) { if (axios.isAxiosError(error)) { if (error.response?.status === 404) { @@ -91,20 +108,11 @@ const Window: React.FC = props => { } }, [chatId]); - // TODO load message history - /** - * Loading messages history - */ - useEffect(() => { - console.log('chat id changed!'); - setMessages([]); - }, [chatId]); - // TODO add types for this event /** * Event on accept new messages */ - useSocketEvent('message:private', data => { + useSocketEvent('chat:message', data => { const user = onlineStore.getUser(data.from); if (user) { @@ -118,7 +126,7 @@ const Window: React.FC = props => { content: data.content, userName: user.userName, isMyMessage: false, - time: new Date().toLocaleTimeString(), + time: new Date(data.time).toLocaleTimeString(), }; setMessages(prev => [...prev, message]); @@ -155,7 +163,7 @@ const Window: React.FC = props => { - {selectedUser.fullname} + {isMe && me ? 'Favorites' : selectedUser.fullname} diff --git a/src/components/UserProfile/Settings/SettingsContextProvider.tsx b/src/components/UserProfile/Settings/SettingsContextProvider.tsx index 9fdceb7..6e23b71 100644 --- a/src/components/UserProfile/Settings/SettingsContextProvider.tsx +++ b/src/components/UserProfile/Settings/SettingsContextProvider.tsx @@ -47,11 +47,12 @@ const SettingsContextProvider: React.FC = ({ children }) => { runInAction(() => { if (me !== null) { me.about = about === undefined ? me.about : about; - if (me.contacts) { - me.contacts.phone_number = phone_number === undefined ? me.contacts.phone_number : phone_number; - me.contacts.twitter_id = twitter_id === undefined ? me.contacts.twitter_id : twitter_id; - me.contacts.telegram_id = telegram_id === undefined ? me.contacts.telegram_id : telegram_id; - } + me.contacts = { + phone_number: phone_number === undefined ? me.contacts?.phone_number || null : phone_number, + twitter_id: twitter_id === undefined ? me.contacts?.twitter_id || null : twitter_id, + telegram_id: telegram_id === undefined ? me.contacts?.telegram_id || null : telegram_id, + vk_id: null, + }; } }); diff --git a/src/pages/main/main.tsx b/src/pages/main/main.tsx index 4bce30c..ee6be1c 100644 --- a/src/pages/main/main.tsx +++ b/src/pages/main/main.tsx @@ -48,7 +48,7 @@ const MainPage: React.FC = () => { Online - {onlineStore.count} + {onlineStore.count || 0} diff --git a/src/pages/profile/change-email/change-email.tsx b/src/pages/profile/change-email/change-email.tsx index a28e321..508d48c 100644 --- a/src/pages/profile/change-email/change-email.tsx +++ b/src/pages/profile/change-email/change-email.tsx @@ -1,6 +1,5 @@ import React from 'react'; import { observer } from 'mobx-react'; -import { Box, Flex, Heading, Text } from '@chakra-ui/layout'; /** * Types @@ -10,6 +9,7 @@ import { IPageProps } from '@educt/interfaces'; /** * Components */ +import { Page } from '@educt/components/PageElements'; import LoadingPage from '@educt/components/LoadingPage'; import UpdateEmailForm from './components/UpdateEmailForm'; @@ -32,7 +32,6 @@ import { ChangeEmailPageContext } from '@educt/contexts'; * Providers */ import { ChangeEmailPageContextProvider } from '@educt/providers'; -import PrevPageButton from '@educt/components/PrevPageButton'; /** * Change email page @@ -48,22 +47,18 @@ const ChangeEmailPage: React.FC = () => { {({ isCodeSent, confirmEmailData }) => ( - <> + {!isCodeSent ? ( - - - - Edit email address - - - Type your new email address. - - - + <> + + + + + ) : ( confirmEmailData && )} - + )} diff --git a/src/pages/profile/change-email/components/UpdateEmailForm/UpdateEmailForm.tsx b/src/pages/profile/change-email/components/UpdateEmailForm/UpdateEmailForm.tsx index 4f8134c..275ae2f 100644 --- a/src/pages/profile/change-email/components/UpdateEmailForm/UpdateEmailForm.tsx +++ b/src/pages/profile/change-email/components/UpdateEmailForm/UpdateEmailForm.tsx @@ -1,5 +1,4 @@ import React from 'react'; -import { Button } from '@chakra-ui/button'; import { FormControl, FormHelperText, FormLabel } from '@chakra-ui/form-control'; import { Input } from '@chakra-ui/input'; import { Box, Stack } from '@chakra-ui/layout'; @@ -26,6 +25,7 @@ import { ChangeEmailPageContext } from '@educt/contexts'; * Schema */ import UpdateEmailSchema from './UpdateEmailForm.validator'; +import { SaveButton } from '@educt/components/Buttons'; type UpdateEmailInputType = { email: string; @@ -87,17 +87,7 @@ const UpdateEmailForm: React.FC = ({ currentEmail }) = - +
); diff --git a/src/pages/profile/change-password/change-password.tsx b/src/pages/profile/change-password/change-password.tsx index d8a66ba..2a564ab 100644 --- a/src/pages/profile/change-password/change-password.tsx +++ b/src/pages/profile/change-password/change-password.tsx @@ -1,6 +1,5 @@ import React from 'react'; import { observer } from 'mobx-react'; -import { Box, Heading, Flex, Text } from '@chakra-ui/react'; /** * Types @@ -11,13 +10,13 @@ import { IPageProps } from '@educt/interfaces'; * Components */ import UpdatePasswordForm from './components/UpdatePasswordForm'; -import PrevPageButton from '@educt/components/PrevPageButton'; import LoadingPage from '@educt/components/LoadingPage'; /** * Hooks */ import { useRootStore } from '@educt/hooks/useRootStore'; +import { Page } from '@educt/components/PageElements'; /** * Change password page @@ -30,16 +29,12 @@ const ChangePasswordPage: React.FC = () => { if (me === null) return ; return ( - - - - Update password - - - Your new password must be different from the current one. - - - + + + + + + ); }; diff --git a/src/pages/profile/change-password/components/UpdatePasswordForm/UpdatePasswordForm.tsx b/src/pages/profile/change-password/components/UpdatePasswordForm/UpdatePasswordForm.tsx index 4acb56b..d6b07fd 100644 --- a/src/pages/profile/change-password/components/UpdatePasswordForm/UpdatePasswordForm.tsx +++ b/src/pages/profile/change-password/components/UpdatePasswordForm/UpdatePasswordForm.tsx @@ -1,8 +1,8 @@ import React from 'react'; import { Box, Stack } from '@chakra-ui/layout'; import { FormControl, FormLabel, FormHelperText } from '@chakra-ui/form-control'; -import { Button } from '@chakra-ui/button'; import { Input } from '@chakra-ui/input'; +import { SaveButton } from '@educt/components/Buttons'; import { yupResolver } from '@hookform/resolvers/yup'; /** @@ -129,17 +129,7 @@ const UpdatePasswordForm: React.FC = () => { - + ); diff --git a/src/providers/index.tsx b/src/providers/index.tsx index 1e9c225..d9994d2 100644 --- a/src/providers/index.tsx +++ b/src/providers/index.tsx @@ -1,4 +1,5 @@ import React, { useState, ReactNode } from 'react'; +import * as constants from '../../constants'; import { ChangeEmailPageContext, CoursesPageContext, @@ -25,7 +26,7 @@ export const RootStoreProvider = ({ children }: { children: ReactNode }) => { * Socket context provider */ export const SocketContextProvider: React.FC = ({ children }) => { - const socket = useSocket('ws://localhost:3333'); + const socket = useSocket(constants.WS_URL); return {children}; }; diff --git a/src/services/UserService.ts b/src/services/UserService.ts index a6571f2..74bbc57 100644 --- a/src/services/UserService.ts +++ b/src/services/UserService.ts @@ -163,6 +163,17 @@ class UserService { }); return result.data; } + + /** + * Get history of chat + * + * @param chatId Chat id + * @returns Array of messages + */ + public async fetchChatHistory(chatId: string): Promise> { + const result = await this.api.get(`v1/me/messages/${chatId}`); + return result.data; + } } export const UserServiceInstance = new UserService(ApiServiceInstance.api);