Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Chat 240 display unread messages #116

Merged
merged 5 commits into from
Oct 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions src/common/Topics/ChatsBlock/ChatsBlock.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,20 @@ import Loader from '../../../components/Loader';
import { StyledNavLink } from './ChatsBlock.styled';

import {
clearSubscriptions,
selectAllTopicsNotifications,
selectSubscriptions,
selectUsersStatusOnlineTyping,
setAllTopicsNotifications,
} from '../../../redux/chatSlice';
import { useUser } from '../../../hooks/useUser';
// eslint-disable-next-line max-len
import { selectAccessToken } from '../../../redux/authOperatonsToolkit/authOperationsThunkSelectors';
import localLogOutUtil from '../../../utils/localLogOutUtil';
import {
subscribeOnlineOrTypingStatus,
unSubscribeOnlineOrTypingStatus,
} from '../../../redux/chat-operations';

const ChatsBlock = ({ filter, searchInputValue }) => {
const { isTopics, showTopics, setPrivateTopics } = useTopicsContext();
Expand All @@ -33,6 +40,7 @@ const ChatsBlock = ({ filter, searchInputValue }) => {
const navigate = useNavigate();
const dispatch = useDispatch();
const notificationsAllTopics = useSelector(selectAllTopicsNotifications);
const subscriptions = useSelector(selectSubscriptions);

const {
currentData: allTopicsData,
Expand Down Expand Up @@ -63,6 +71,16 @@ const ChatsBlock = ({ filter, searchInputValue }) => {
refetchOnReconnect: true,
});

// eslint-disable-next-line max-len
// Useeffect for subscribing to a userOnlineStatus endpoint, and get information about online users
useEffect(() => {
dispatch(subscribeOnlineOrTypingStatus());

return () => {
dispatch(unSubscribeOnlineOrTypingStatus());
};
}, [dispatch]);

useEffect(() => {
if (currentPrivateTopicsData) {
setPrivateTopics(currentPrivateTopicsData);
Expand Down
25 changes: 19 additions & 6 deletions src/components/Chat/Chat.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { memo, useEffect, useRef, useState } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { Link, useLocation, useNavigate, useParams } from 'react-router-dom';

import { getUserInfo } from '../../redux/userSlice';
import { selectUserInfo } from '../../redux/userSlice';
import {
useGetAllPrivateTopicsQuery,
useGetByIdQuery,
Expand Down Expand Up @@ -126,7 +126,7 @@ const Chat = ({ children }) => {
},
);

const { email } = useSelector(getUserInfo);
const { email } = useSelector(selectUserInfo);
const { isTopics, privateTopics, setPrivateTopics } = useTopicsContext();
const { contactsOpen, setContactsOpen } = useTopicsPageContext(); //?!
const { pathname } = useLocation();
Expand Down Expand Up @@ -352,6 +352,11 @@ const Chat = ({ children }) => {
);
}

// Try to scroll when isFetching is false (when new messages has arrived)
if (!isFetchingCurrentMessagesByTopic && currentPageRef.current === 1) {
chatWrapIdRef.current.scrollTo(0, chatWrapIdRef.current.scrollHeight);
}

// Automatically scroll down after sending a message and changing the message array
if (isSuccessSendMessage) {
chatWrapIdRef.current.scrollTo(0, chatWrapIdRef.current.scrollHeight);
Expand All @@ -362,7 +367,7 @@ const Chat = ({ children }) => {
chatWrapIdRef.current.scrollTo(0, chatWrapIdRef.current.scrollHeight);
}

// Here proccesing situation with message conatiner
// Here proccesing situation with message container
if (!isFirstUnreadMessageRef.current) {
return;
} else {
Expand All @@ -381,7 +386,7 @@ const Chat = ({ children }) => {
unreadMessageContainerRef.current = null;
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [topicId, messages]);
}, [topicId, messages, isFetchingCurrentMessagesByTopic]);

// Try to process the situation when user doesn't has a private dialog
useEffect(() => {
Expand Down Expand Up @@ -437,6 +442,7 @@ const Chat = ({ children }) => {

if (pathname.includes('topics') && connected) {
// dispatch(sendMessageByWs({ topicId, inputMessage }));
// sendMessageByWs({ topicId, inputMessage });
sendMessageToTopic({ topicId, inputMessage, accessTokenInStore });
inputRef.current.value = '';
setCurrentPage(1);
Expand Down Expand Up @@ -672,11 +678,18 @@ const Chat = ({ children }) => {
: null}
</ChatUserName>
<TypingIndicator variant={isMobile ? 'h6' : 'h5'}>
Ти/Пишеш...
{topicIdData.lastMessage
? topicIdData.lastMessage.sentFrom
: null}{' '}
/ Пишеш...
</TypingIndicator>
</InfoBox>
</UserBox>
<UsersAvatar topicId={topicId} />
{/* <UsersAvatar topicId={topicId} /> */}
<UsersAvatar
currentTopicSubscribers={topicIdData.topicSubscribers}
topicId={topicId}
/>
<InfoMoreBox>
{children}
<TopicSettingsMenu
Expand Down
14 changes: 6 additions & 8 deletions src/components/Chat/Chat.styled.js
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,10 @@ export const MessageContainer = styled.div`

padding: 5px;
background-color: ${(props) =>
props.messageStatus ? `${props.theme.palette.primary.light}` : 'inherit'};
props.messageStatus
? `${props.theme.palette.primary.light}`
: 'none'}; //light: '#ACADFF', light: '#6261AF',

border: ${(props) =>
props.messageStatus
? `${props.theme.palette.primary.main} 1px solid`
Expand All @@ -125,8 +128,7 @@ export const IndicatorBox = styled.div`
`;

export const TimeIndicator = styled(Typography)`
color: ${(props) =>
props.messageStatus ? props.theme.palette.primary.white : '#999'};
color: ${(p) => p.theme.palette.primary.dark};
font-size: 12px;
${({ isMyMessage }) =>
isMyMessage ? 'margin-right: 8px;' : 'margin-left: 8px;'}
Expand All @@ -139,11 +141,7 @@ export const TimeIndicator = styled(Typography)`

export const UserName = styled(Typography)`
${(p) => p.theme.typography.h6};
/* color: ${(p) => p.theme.palette.primary.dark}; */
color: ${(p) =>
p.messageStatus
? p.theme.palette.primary.white
: p.theme.palette.primary.dark};
color: ${(p) => p.theme.palette.primary.dark};

@media screen and (min-width: calc(845px - 0.02px)) {
${(p) => p.theme.typography.h5};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
import { useInView } from 'react-intersection-observer';
import { MessageContainer } from '../Chat.styled';
import { useSetMessageStatusMutation } from '../../../redux/messagesAPI/messagesAPI';
import { useSelector } from 'react-redux';
import { useDispatch, useSelector } from 'react-redux';
import { selectAccessToken } from '../../../redux/authOperatonsToolkit/authOperationsThunkSelectors';
import { useEffect, useState } from 'react';
import { deletReadedAllTopicsNotification } from '../../../redux/chatSlice';

const MessageContainerObserver = ({
chatWrapIdRef,
Expand All @@ -14,17 +16,30 @@ const MessageContainerObserver = ({
children,
isFirstUnreadMessage,
}) => {
const dispatch = useDispatch();
const accessTokenInStore = useSelector(selectAccessToken);
const [setMessageStatus, { isLoading: isLoadingMessageStatus }] =
useSetMessageStatusMutation();
const [
setMessageStatus,
{ isSuccess: isLoadingMessageStatus, data: setMessageStatusData },
] = useSetMessageStatusMutation();
const [changedMessageStatus, setChangedMessageStatus] =
useState(messageStatus);

// Useeffect for change background of not unread message
useEffect(() => {
if (isLoadingMessageStatus && changedMessageStatus) {
setChangedMessageStatus(false);
dispatch(deletReadedAllTopicsNotification(messageId));
}
}, [isLoadingMessageStatus, changedMessageStatus, dispatch, messageId]);

const {
ref: observerRef,
inView,
observerEntries,
} = useInView({
root: chatWrapIdRef.current,
threshold: 0.8,
threshold: 0.9,
onChange: (inView, entry) => {
if (inView) {
setMessageStatus({ messageId, accessTokenInStore });
Expand All @@ -38,7 +53,7 @@ const MessageContainerObserver = ({
ref={messageStatus ? observerRef : null}
data-messageId={messageId}
isMyMessage={isMyMessage}
messageStatus={messageStatus ? messageStatus : null}
messageStatus={messageStatus ? changedMessageStatus : null}
data-isFirstUnreadMessage={
isFirstUnreadMessage.messageStatus
? isFirstUnreadMessage.messageStatus
Expand Down
31 changes: 17 additions & 14 deletions src/components/Chat/UsersAvatar/UsersAvatar.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import { selectAccessToken } from '../../../redux/authOperatonsToolkit/authOpera
import { Avatars } from '../../../ui-kit/images/avatars';
import Avatar from '../../../ui-kit/components/Avatar';

import { getUserInfo } from '../../../redux/userSlice';
import { useMediaQuery } from 'react-responsive';
import {
UsersAvatarStyledList,
Expand All @@ -19,27 +18,31 @@ import { Link } from 'react-router-dom';
import { useTopicsContext } from '../../../common/Topics/TopicsContext';
import getPrivateTopicId from '../../../utils/getPrivateTopicId';

const UsersAvatar = ({ topicId }) => {
const UsersAvatar = ({ topicId, currentTopicSubscribers }) => {
const accessTokenInStore = useSelector(selectAccessToken);
const isTablet = useMediaQuery({ query: '(min-width: 768px' });
const isDesktop = useMediaQuery({ query: '(mint-width: 1200px)' });
const { privateTopics, setPrivateTopics } = useTopicsContext();

const {
isLoading,
isError,
error,
data: usersSubscribers,
} = useGetSubscribersQuery(
{ topicId, accessTokenInStore },
{ refetchOnFocus: true, refetchOnReconnect: true, refetchOnMountOrArgChange: 10 }
);
// It was additional request for the topic subscribers infromation, but this
// information already exist in topicIdData request.

// const {
// isLoading,
// isError,
// error,
// data: usersSubscribers,
// } = useGetSubscribersQuery(
// { topicId, accessTokenInStore },
// { refetchOnFocus: true, refetchOnReconnect: true, refetchOnMountOrArgChange: 10 }
// );

// console.log('privateTopics', privateTopics);
return (
<UsersAvatarStyledWrapper>
<UsersAvatarStyledList>
{usersSubscribers
{/* {usersSubscribers */}
{currentTopicSubscribers
? // ? usersSubscribers.map(user => (
// <UsersAvatarStyledLi key={user.id}>
// {Object.values(Avatars).map(
Expand All @@ -52,7 +55,7 @@ const UsersAvatar = ({ topicId }) => {
// )}
// </UsersAvatarStyledLi>
// ))
usersSubscribers.reduce((acuum, user, index) => {
currentTopicSubscribers.reduce((acuum, user, index) => {
if (index === 4) {
return [
...acuum,
Expand All @@ -75,7 +78,7 @@ const UsersAvatar = ({ topicId }) => {
// to={`/home/notification/chat/${topicId}`}
>
<Avatar size={isTablet ? 'md' : 'sm'} key={index} isCurrent={'true'}>
{usersSubscribers.length}
{currentTopicSubscribers.length}
</Avatar>
</Link>
</UsersAvatarStyledLi>,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useContext, useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { getUserInfo, setUserInfo } from '../../../../redux/userSlice';
import { selectUserInfo, setUserInfo } from '../../../../redux/userSlice';
// import { useContext } from 'react';
// import { useSelector } from 'react-redux';
// import { getUserInfo } from '../../../../redux/userSlice';
Expand Down Expand Up @@ -41,7 +41,7 @@ const HeaderUserInfo = () => {
// const { localLogOut } = useUser();
// const navigate = useNavigate();

const { avatarId } = useSelector(getUserInfo);
const { avatarId } = useSelector(selectUserInfo);
// const { nickname: userNickname, avatarId } = useSelector(selectUserThunk);

const notificationsAllTopics = useSelector(selectAllTopicsNotifications);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ export const calculateTotalUnreadMessages = (notifications) => {
let totalUnreadedMessages = 0;

notifications.map((notification) => {
totalUnreadedMessages += notification.unreadMessageCount;
if (notification.unreadMessageCount) {
totalUnreadedMessages += notification.unreadMessageCount;
}
});

return `${totalUnreadedMessages}`;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import {
import { useRegistrationMutation } from '../../redux/auth-operations';
import { PATH } from '../../constans/routes';
import { useNavigate } from 'react-router-dom';
import { setUserInfo } from '../../redux/userSlice';
import { useDispatch } from 'react-redux';

const defaultValues = {
nickname: '',
Expand All @@ -25,6 +27,7 @@ const defaultValues = {
function RegistrationPageComponent() {
const [registration] = useRegistrationMutation();
const navigate = useNavigate();
const dispatch = useDispatch();

const {
formState: { errors, isValid },
Expand Down Expand Up @@ -60,6 +63,7 @@ function RegistrationPageComponent() {
}
localStorage.setItem('accessToken', registrationData.accessToken);
localStorage.setItem('refreshToken', registrationData.refreshToken);
dispatch(setUserInfo(userData));
navigate(PATH.VERIFICATION_EMAIL);
} catch (error) {
console.error('Виникла помилка під час заповнення форми:', error);
Expand Down
4 changes: 2 additions & 2 deletions src/components/RegistrationPageComponent/validationRules.js
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,8 @@ export const validationRules = {
message: 'Мінімум - 4 символи',
},
maxLength: {
value: 12,
message: 'Максимум - 12 символів',
value: 20,
message: 'Максимум - 20 символів',
},
validate: { validatePassword },
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { useSelector } from 'react-redux';
import { getUserInfo } from '../../../redux/userSlice';
import { selectUserInfo } from '../../../redux/userSlice';
import { useEditUserInfoMutation } from '../../../redux/user-operations';
import { NewSettingsWrap, SaveChangeButton } from './ChangeNameInput.styled';
import { FieldText } from '../../RegistrationPageComponent/FieldText/FieldText';
import { useForm } from 'react-hook-form';
import { SettingsLabel } from '../SettingsPageComponent.styled';

const ChangeNameInput = () => {
const { nickname, avatarId } = useSelector(getUserInfo);
const { nickname, avatarId } = useSelector(selectUserInfo);

const [editUserInfo] = useEditUserInfoMutation();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ import {
UserAvatarForm,
} from './ChangeUserAvatar.styled';
import { useSelector } from 'react-redux';
import { getUserInfo } from '../../../redux/userSlice';
import { selectUserInfo } from '../../../redux/userSlice';
import { useEditUserInfoMutation } from '../../../redux/user-operations';

const ChangeUserAvatar = () => {
const { nickname, avatarId } = useSelector(getUserInfo);
const { nickname, avatarId } = useSelector(selectUserInfo);
const [editUserInfo] = useEditUserInfoMutation();

const defaultValues = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ import {
useProhibitPrivateMessageMutation,
} from '../../../redux/user-operations';
import { useSelector } from 'react-redux';
import { getUserInfo } from '../../../redux/userSlice';
import { selectUserInfo } from '../../../redux/userSlice';
// eslint-disable-next-line max-len
import { selectAccessToken } from '../../../redux/authOperatonsToolkit/authOperationsThunkSelectors';

export const PermissionPrivateMessage = () => {
const { hasPermissionSendingPrivateMessage } = useSelector(getUserInfo);
const { hasPermissionSendingPrivateMessage } = useSelector(selectUserInfo);
const [isPermission, setIsPermission] = useState(
hasPermissionSendingPrivateMessage || 'true',
);
Expand Down
Loading
Loading