From c7065341b4d142b88ca61801192f958e104a41c2 Mon Sep 17 00:00:00 2001 From: Maria Rushkova <66270386+mrushkova@users.noreply.github.com> Date: Wed, 8 Dec 2021 10:08:24 +0100 Subject: [PATCH] Add activity center (#142) --- .../src/components/ActivityCenter.tsx | 427 ++++++++++++++++++ .../src/components/Buttons/buttonStyle.tsx | 1 + .../src/components/Channels/Channel.tsx | 1 + .../components/Chat/ChatMessageContent.tsx | 5 +- .../src/components/Chat/ChatMessages.tsx | 73 ++- .../src/components/Chat/ChatTopbar.tsx | 113 +++-- .../src/components/Icons/ActivityIcon.tsx | 25 + .../src/components/Icons/CheckIcon.tsx | 17 +- .../src/components/Icons/ClearIcon.tsx | 14 +- .../src/components/Icons/HideIcon.tsx | 24 + .../react-chat/src/components/Icons/Icon.ts | 16 + .../src/components/Icons/ReadIcon.tsx | 43 ++ .../components/Icons/ReplyActivityIcon.tsx | 19 + .../src/components/Icons/ShowIcon.tsx | 27 ++ .../src/components/Members/Member.tsx | 2 +- .../src/components/Modals/ProfileModal.tsx | 19 +- .../react-chat/src/components/ReactChat.tsx | 13 +- .../src/contexts/activityProvider.tsx | 29 ++ packages/react-chat/src/models/Activity.ts | 20 + packages/react-chat/src/styles/themes.ts | 3 + 20 files changed, 809 insertions(+), 82 deletions(-) create mode 100644 packages/react-chat/src/components/ActivityCenter.tsx create mode 100644 packages/react-chat/src/components/Icons/ActivityIcon.tsx create mode 100644 packages/react-chat/src/components/Icons/HideIcon.tsx create mode 100644 packages/react-chat/src/components/Icons/Icon.ts create mode 100644 packages/react-chat/src/components/Icons/ReadIcon.tsx create mode 100644 packages/react-chat/src/components/Icons/ReplyActivityIcon.tsx create mode 100644 packages/react-chat/src/components/Icons/ShowIcon.tsx create mode 100644 packages/react-chat/src/contexts/activityProvider.tsx create mode 100644 packages/react-chat/src/models/Activity.ts diff --git a/packages/react-chat/src/components/ActivityCenter.tsx b/packages/react-chat/src/components/ActivityCenter.tsx new file mode 100644 index 00000000..7d73d1ed --- /dev/null +++ b/packages/react-chat/src/components/ActivityCenter.tsx @@ -0,0 +1,427 @@ +import React, { useMemo, useRef, useState } from "react"; +import styled from "styled-components"; + +import { useActivities } from "../contexts/activityProvider"; +import { useMessengerContext } from "../contexts/messengerProvider"; +import { useClickOutside } from "../hooks/useClickOutside"; +import { Activity } from "../models/Activity"; +import { equalDate } from "../utils/equalDate"; + +import { buttonStyles } from "./Buttons/buttonStyle"; +import { + ContentWrapper, + DateSeparator, + MessageHeaderWrapper, + MessageOuterWrapper, + MessageText, + TimeWrapper, + UserAddress, + UserName, + UserNameWrapper, +} from "./Chat/ChatMessages"; +import { ContactMenu } from "./Form/ContactMenu"; +import { CheckSvg } from "./Icons/CheckIcon"; +import { ClearSvg } from "./Icons/ClearIcon"; +import { GroupIcon } from "./Icons/GroupIcon"; +import { HideIcon } from "./Icons/HideIcon"; +import { Icon } from "./Icons/Icon"; +import { MoreIcon } from "./Icons/MoreIcon"; +import { ReadIcon } from "./Icons/ReadIcon"; +import { ReplyIcon } from "./Icons/ReplyActivityIcon"; +import { ShowIcon } from "./Icons/ShowIcon"; +import { UntrustworthIcon } from "./Icons/UntrustworthIcon"; +import { UserIcon } from "./Icons/UserIcon"; +import { textMediumStyles, textSmallStyles } from "./Text"; + +const today = new Date(); + +type ActivityMessageProps = { + activity: Activity; +}; + +function ActivityMessage({ activity }: ActivityMessageProps) { + const { contacts } = useMessengerContext(); + + const [showMenu, setShowMenu] = useState(false); + + const type = activity.type; + + const contact = useMemo( + () => contacts[activity.user], + [activity.user, contacts] + ); + + return ( + + + {equalDate(activity.date, today) + ? "Today" + : activity.date.toLocaleDateString()} + + + + <> + + + + + + + + + {" "} + {contact.customName ?? activity.user.slice(0, 10)} + + {contact.customName && ( + + {activity.user.slice(0, 5)}...{activity.user.slice(-3)} + + )} + {contact.isUntrustworthy && } + + + {activity.date.toLocaleString("en-US", { + hour: "numeric", + minute: "numeric", + hour12: true, + })} + + + {type === "request" && ( + + Contact request + {activity.requestType === "outcome" + ? ` to ${activity.user.slice(0, 10)}` + : ": "} + + )} + + {activity.message?.content || + (activity.requestType === "income" && activity.request)} + + {type === "mention" && + activity.channel && + activity.channel.type !== "dm" && ( + + {activity.channel.type === "group" ? : "#"}{" "} + {` ${activity.channel.name.slice(0, 10)}`} + + )} + {type === "reply" && activity.quote && ( + + {activity.quote.image && ( + Posted an image in + )} + + {activity.quote.content} + + + )} + + + {type === "request" && + !activity.status && + activity.requestType === "income" && ( + <> + { + activity.isRead = true; + activity.status = "accepted"; + }} + className="accept" + > + + + { + activity.isRead = true; + activity.status = "declined"; + }} + className="decline" + > + + + { + setShowMenu((e) => !e); + }} + > + {showMenu && } + + + + )} + {type === "request" && activity.status === "accepted" && ( + Accepted + )} + {type === "request" && activity.status === "declined" && ( + Declined + )} + {type === "request" && activity.status === "sent" && ( + Sent + )} + {type !== "request" && ( + { + activity.isRead = true; + }} + className={`${activity.isRead && "read"}`} + > + + + )} + + + ); +} + +interface ActivityCenterProps { + setShowActivityCenter: (val: boolean) => void; +} + +export function ActivityCenter({ setShowActivityCenter }: ActivityCenterProps) { + const { activities } = useActivities(); + const { contacts } = useMessengerContext(); + + const ref = useRef(null); + useClickOutside(ref, () => setShowActivityCenter(false)); + + const shownActivities = useMemo( + () => + activities.filter( + (activity) => !contacts?.[activity.user]?.blocked ?? true + ), + [contacts, activities, activities.length] + ); + + const [hideRead, setHideRead] = useState(false); + + const [filter, setFilter] = useState(""); + + const filteredActivities = shownActivities.filter((activity) => + filter + ? activity.type === filter + : hideRead + ? activity.isRead !== true + : activity + ); + + return ( + + + + setFilter("")}>All + setFilter("mention")}>Mentions + setFilter("reply")}>Replies + setFilter("request")}> + Contact requests + + + + { + shownActivities.map((activity) => (activity.isRead = true)); + }} + > + + + setHideRead(!hideRead)}> + {hideRead ? : } + + + + {filteredActivities.length > 0 ? ( + + {filteredActivities.map((activity) => ( + + ))} + + ) : ( + Notifications will appear here + )} + + ); +} + +const ActivityBlock = styled.div` + width: 600px; + height: 770px; + display: flex; + flex-direction: column; + background: ${({ theme }) => theme.bodyBackgroundColor}; + box-shadow: 0px 12px 24px rgba(0, 34, 51, 0.1); + border-radius: 8px; + position: absolute; + top: 48px; + right: 8px; + z-index: 100; +`; + +const ActivityFilter = styled.div` + display: flex; + justify-content: space-between; + padding: 13px 16px; +`; + +const Filters = styled.div` + display: flex; +`; + +const FilterBtn = styled.button` + ${buttonStyles} + ${textSmallStyles} + + padding: 10px 12px; + background: ${({ theme }) => theme.bodyBackgroundColor}; + + & + & { + margin-left: 8px; + } + + &:hover { + background: ${({ theme }) => theme.buttonBgHover}; + } + + &:focus { + background: ${({ theme }) => theme.buttonBg}; + } +`; + +const ActivityBtn = styled.button` + width: 32px; + height: 32px; + display: flex; + justify-content: center; + align-items: center; + border-radius: 8px; + align-self: center; + + &:hover { + background: ${({ theme }) => theme.buttonBgHover}; + } + + &.read { + &:hover { + background: ${({ theme }) => theme.bodyBackgroundColor}; + } + } + + &.accept { + &:hover { + background: rgba(78, 188, 96, 0.1); + } + } + + &.decline { + &:hover { + background: rgba(255, 45, 85, 0.1); + } + } + + & + & { + margin-left: 8px; + } +`; + +const Activities = styled.div` + display: flex; + flex-direction: column; + width: 100%; + overflow: auto; +`; + +const EmptyActivities = styled.div` + display: flex; + justify-content: center; + align-items: center; + flex: 1; + width: 100%; + color: ${({ theme }) => theme.secondary}; +`; + +const ActivityDate = styled(DateSeparator)` + justify-content: flex-start; + padding: 8px 16px; + margin: 0; +`; + +const MessageWrapper = styled.div` + width: 100%; + display: flex; + align-items: flex-start; + padding: 8px 16px; + + &.unread { + background: ${({ theme }) => theme.buttonBgHover}; + } +`; + +const ActivityText = styled(MessageText)` + white-space: unset; + margin-bottom: 8px; +`; + +const Tag = styled.div` + width: fit-content; + max-width: 200px; + display: flex; + align-items: center; + + border: 1px solid ${({ theme }) => theme.secondary}; + border-radius: 11px; + padding: 0 6px; + cursor: pointer; + + font-weight: 500; + color: ${({ theme }) => theme.secondary}; + ${textSmallStyles} + + & > span { + text-overflow: ellipsis; + white-space: nowrap; + overflow: hidden; + } +`; + +const ContextHeading = styled.p` + font-style: italic; + color: ${({ theme }) => theme.secondary}; + flex-shrink: 0; + ${textMediumStyles} +`; + +const RequestStatus = styled.p` + font-weight: 500; + align-self: center; + text-align: end; + color: ${({ theme }) => theme.secondary}; + ${textSmallStyles} + + &.accepted { + color: ${({ theme }) => theme.greenColor}; + } + + &.declined { + color: ${({ theme }) => theme.redColor}; + } +`; + +const ActivityContent = styled(ContentWrapper)` + max-width: calc(100% - 80px); + flex: 1; +`; + +const Btns = styled.div` + display: flex; + align-items: center; +`; + +const ReplyWrapper = styled.div` + max-width: 100%; + display: flex; + align-items: center; + + & > p { + margin-right: 4px; + } +`; diff --git a/packages/react-chat/src/components/Buttons/buttonStyle.tsx b/packages/react-chat/src/components/Buttons/buttonStyle.tsx index cf461a4f..70a7157d 100644 --- a/packages/react-chat/src/components/Buttons/buttonStyle.tsx +++ b/packages/react-chat/src/components/Buttons/buttonStyle.tsx @@ -2,6 +2,7 @@ import { css } from "styled-components"; export const buttonStyles = css` border-radius: 8px; + font-family: "Inter"; font-weight: 500; font-size: 15px; line-height: 22px; diff --git a/packages/react-chat/src/components/Channels/Channel.tsx b/packages/react-chat/src/components/Channels/Channel.tsx index 09b6ae53..4193f180 100644 --- a/packages/react-chat/src/components/Channels/Channel.tsx +++ b/packages/react-chat/src/components/Channels/Channel.tsx @@ -188,6 +188,7 @@ const NotificationBagde = styled.div` border-radius: 50%; font-size: 12px; line-height: 16px; + font-weight: 500; background-color: ${({ theme }) => theme.notificationColor}; color: ${({ theme }) => theme.bodyBackgroundColor}; display: flex; diff --git a/packages/react-chat/src/components/Chat/ChatMessageContent.tsx b/packages/react-chat/src/components/Chat/ChatMessageContent.tsx index 2937002c..0dd8676d 100644 --- a/packages/react-chat/src/components/Chat/ChatMessageContent.tsx +++ b/packages/react-chat/src/components/Chat/ChatMessageContent.tsx @@ -24,7 +24,10 @@ function Mention({ id, setMentioned }: MentionProps) { const identity = useIdentity(); if (!contact) return <>{id}; - if (contact.id === utils.bufToHex(identity.publicKey)) setMentioned(true); + + useEffect(() => { + if (contact.id === utils.bufToHex(identity.publicKey)) setMentioned(true); + }, [contact.id]); return ( setShowMenu(!showMenu)}> diff --git a/packages/react-chat/src/components/Chat/ChatMessages.tsx b/packages/react-chat/src/components/Chat/ChatMessages.tsx index d3ce6b6c..3145300c 100644 --- a/packages/react-chat/src/components/Chat/ChatMessages.tsx +++ b/packages/react-chat/src/components/Chat/ChatMessages.tsx @@ -1,14 +1,19 @@ import React, { useEffect, useMemo, useRef, useState } from "react"; +import { utils } from "status-communities/dist/cjs"; import styled from "styled-components"; +import { useActivities } from "../../contexts/activityProvider"; +import { useIdentity } from "../../contexts/identityProvider"; import { useMessengerContext } from "../../contexts/messengerProvider"; import { useModal } from "../../contexts/modalProvider"; import { useChatScrollHandle } from "../../hooks/useChatScrollHandle"; import { Reply } from "../../hooks/useReply"; +import { ChannelData } from "../../models/ChannelData"; import { ChatMessage } from "../../models/ChatMessage"; import { equalDate } from "../../utils"; import { EmptyChannel } from "../Channels/EmptyChannel"; import { ContactMenu } from "../Form/ContactMenu"; +import { Icon } from "../Icons/Icon"; import { LoadingIcon } from "../Icons/LoadingIcon"; import { QuoteSvg } from "../Icons/QuoteIcon"; import { ReactionSvg } from "../Icons/ReactionIcon"; @@ -27,6 +32,7 @@ const today = new Date(); type ChatUiMessageProps = { idx: number; message: ChatMessage; + channel: ChannelData; prevMessage: ChatMessage; setImage: (img: string) => void; setLink: (link: string) => void; @@ -36,6 +42,7 @@ type ChatUiMessageProps = { function ChatUiMessage({ message, + channel, idx, prevMessage, setImage, @@ -44,6 +51,9 @@ function ChatUiMessage({ quote, }: ChatUiMessageProps) { const { contacts } = useMessengerContext(); + const { setActivities } = useActivities(); + const identity = useIdentity(); + const contact = useMemo( () => contacts[message.sender], [message.sender, contacts] @@ -51,6 +61,34 @@ function ChatUiMessage({ const [showMenu, setShowMenu] = useState(false); const [mentioned, setMentioned] = useState(false); + useEffect(() => { + if (mentioned) + setActivities((prev) => [ + ...prev, + { + id: message.date.getTime().toString() + message.content, + type: "mention", + date: message.date, + user: message.sender, + message: message, + channel: channel, + }, + ]); + if (quote && quote.sender === utils.bufToHex(identity.publicKey)) + setActivities((prev) => [ + ...prev, + { + id: message.date.getTime().toString() + message.content, + type: "reply", + date: message.date, + user: message.sender, + message: message, + channel: channel, + quote: quote, + }, + ]); + }, [mentioned, message, quote]); + return ( {(idx === 0 || !equalDate(prevMessage.date, message.date)) && ( @@ -190,6 +228,7 @@ export function ChatMessages({ setReply }: ChatMessagesProps) { theme.tertiary}; margin-right: 4px; @@ -331,7 +356,7 @@ export const UserAddress = styled.p` } `; -const TimeWrapper = styled.div` +export const TimeWrapper = styled.div` font-size: 10px; line-height: 14px; letter-spacing: 0.2px; @@ -340,7 +365,7 @@ const TimeWrapper = styled.div` margin-left: 4px; `; -const MessageText = styled.div` +export const MessageText = styled.div` overflow-wrap: anywhere; width: 100%; white-space: pre-wrap; diff --git a/packages/react-chat/src/components/Chat/ChatTopbar.tsx b/packages/react-chat/src/components/Chat/ChatTopbar.tsx index 910110f1..8f9b72be 100644 --- a/packages/react-chat/src/components/Chat/ChatTopbar.tsx +++ b/packages/react-chat/src/components/Chat/ChatTopbar.tsx @@ -1,11 +1,14 @@ import React, { useState } from "react"; import styled from "styled-components"; +import { useActivities } from "../../contexts/activityProvider"; import { useMessengerContext } from "../../contexts/messengerProvider"; import { useNarrow } from "../../contexts/narrowProvider"; +import { ActivityCenter } from "../ActivityCenter"; import { Channel } from "../Channels/Channel"; import { Community } from "../Community"; import { ChannelMenu } from "../Form/ChannelMenu"; +import { ActivityIcon } from "../Icons/ActivityIcon"; import { MembersIcon } from "../Icons/MembersIcon"; import { MoreIcon } from "../Icons/MoreIcon"; import { CommunitySkeleton } from "../Skeleton/CommunitySkeleton"; @@ -31,8 +34,10 @@ export function ChatTopbar({ setEditGroup, }: ChatTopbarProps) { const { messenger, activeChannel, communityData } = useMessengerContext(); + const { activities } = useActivities(); const narrow = useNarrow(); const [showChannelMenu, setShowChannelMenu] = useState(false); + const [showActivityCenter, setShowActivityCenter] = useState(false); return ( {!narrow && ( - + - + )} - setShowChannelMenu(!showChannelMenu)}> + setShowChannelMenu(!showChannelMenu)}> - + + + setShowActivityCenter(!showActivityCenter)} + className="activity" + > + + {activities.length > 0 && ( + {activities.length} + )} + + {!messenger && !communityData && } {showChannelMenu && ( @@ -80,10 +96,26 @@ export function ChatTopbar({ setEditGroup={setEditGroup} /> )} + {showActivityCenter && ( + + )} ); } +const Topbar = styled.div` + display: flex; + justify-content: space-between; + align-items: center; + padding: 5px 8px; + background: ${({ theme }) => theme.bodyBackgroundColor}; + position: relative; + + &.narrow { + width: 100%; + } +`; + const ChannelWrapper = styled.div` display: flex; align-items: center; @@ -98,19 +130,6 @@ const SkeletonWrapper = styled.div` padding: 8px; `; -const Topbar = styled.div` - display: flex; - justify-content: space-between; - align-items: center; - padding: 5px 8px; - background: ${({ theme }) => theme.bodyBackgroundColor}; - position: relative; - - &.narrow { - width: 100%; - } -`; - const CommunityWrap = styled.div` padding-right: 10px; margin-right: 16px; @@ -139,35 +158,61 @@ const MenuWrapper = styled.div` align-items: center; `; -const MemberBtn = styled.button` +const ActivityWrapper = styled.div` + padding-left: 10px; + margin-left: 10px; + position: relative; + + &:before { + content: ""; + position: absolute; + left: 0; + top: 50%; + width: 2px; + height: 24px; + transform: translateY(-50%); + border-radius: 1px; + background: ${({ theme }) => theme.primary}; + opacity: 0.1; + } +`; + +const TopBtn = styled.button` width: 32px; height: 32px; border-radius: 8px; padding: 0; &:hover { - background: ${({ theme }) => theme.border}; + background: ${({ theme }) => theme.sectionBackgroundColor}; } &:active, &.active { background: ${({ theme }) => theme.inputColor}; } -`; -const MoreBtn = styled.button` - width: 32px; - height: 32px; - border-radius: 8px; - padding: 0; - margin: 0 8px; - - &:hover { - background: ${({ theme }) => theme.border}; - } - - &:active, - &.active { - background: ${({ theme }) => theme.inputColor}; + &.activity { + &:hover { + background: ${({ theme }) => theme.bodyBackgroundColor}; + } } `; + +const NotificationBagde = styled.div` + width: 18px; + height: 18px; + position: absolute; + top: -2px; + right: -2px; + border-radius: 50%; + font-size: 12px; + line-height: 16px; + font-weight: 500; + background-color: ${({ theme }) => theme.notificationColor}; + color: ${({ theme }) => theme.bodyBackgroundColor}; + display: flex; + align-items: center; + justify-content: center; + flex-shrink: 0; +`; diff --git a/packages/react-chat/src/components/Icons/ActivityIcon.tsx b/packages/react-chat/src/components/Icons/ActivityIcon.tsx new file mode 100644 index 00000000..68ec4f32 --- /dev/null +++ b/packages/react-chat/src/components/Icons/ActivityIcon.tsx @@ -0,0 +1,25 @@ +import React from "react"; +import styled from "styled-components"; + +export const ActivityIcon = () => { + return ( + + + + ); +}; + +const Icon = styled.svg` + fill: ${({ theme }) => theme.primary}; +`; diff --git a/packages/react-chat/src/components/Icons/CheckIcon.tsx b/packages/react-chat/src/components/Icons/CheckIcon.tsx index 63670083..2a8fd0ea 100644 --- a/packages/react-chat/src/components/Icons/CheckIcon.tsx +++ b/packages/react-chat/src/components/Icons/CheckIcon.tsx @@ -9,11 +9,10 @@ type CheckSvgProps = { export function CheckSvg({ width, height, className }: CheckSvgProps) { return ( - @@ -23,7 +22,7 @@ export function CheckSvg({ width, height, className }: CheckSvgProps) { clipRule="evenodd" d="M7.99992 14.6668C4.31802 14.6668 1.33325 11.6821 1.33325 8.00016C1.33325 4.31826 4.31802 1.3335 7.99992 1.3335C11.6818 1.3335 14.6666 4.31826 14.6666 8.00016C14.6666 11.6821 11.6818 14.6668 7.99992 14.6668ZM7.99992 13.6668C4.8703 13.6668 2.33325 11.1298 2.33325 8.00016C2.33325 4.87055 4.8703 2.3335 7.99992 2.3335C11.1295 2.3335 13.6666 4.87055 13.6666 8.00016C13.6666 11.1298 11.1295 13.6668 7.99992 13.6668Z" /> - + ); } @@ -31,12 +30,14 @@ export const CheckIcon = () => { return ; }; -const Icon = styled(CheckSvg)` - & > path { - fill: ${({ theme }) => theme.tertiary}; - } +const Icon = styled.svg` + fill: ${({ theme }) => theme.tertiary}; - &:hover > path { + &:hover { fill: ${({ theme }) => theme.bodyBackgroundColor}; } + + &.accept { + fill: ${({ theme }) => theme.greenColor}; + } `; diff --git a/packages/react-chat/src/components/Icons/ClearIcon.tsx b/packages/react-chat/src/components/Icons/ClearIcon.tsx index e31f9407..c20abab7 100644 --- a/packages/react-chat/src/components/Icons/ClearIcon.tsx +++ b/packages/react-chat/src/components/Icons/ClearIcon.tsx @@ -9,7 +9,7 @@ type ClearSvgProps = { export function ClearSvg({ height, width, className }: ClearSvgProps) { return ( - - + ); } @@ -30,10 +30,8 @@ export const ClearIcon = () => { return ; }; -const Icon = styled(ClearSvg)` - & > path { - fill: ${({ theme }) => theme.tertiary}; - } +const Icon = styled.svg` + fill: ${({ theme }) => theme.tertiary}; &.profile { fill: ${({ theme }) => theme.secondary}; @@ -47,7 +45,7 @@ const Icon = styled(ClearSvg)` fill: ${({ theme }) => theme.bodyBackgroundColor}; } - &:hover > path { - fill: ${({ theme }) => theme.bodyBackgroundColor}; + &.decline { + fill: ${({ theme }) => theme.redColor}; } `; diff --git a/packages/react-chat/src/components/Icons/HideIcon.tsx b/packages/react-chat/src/components/Icons/HideIcon.tsx new file mode 100644 index 00000000..967e090e --- /dev/null +++ b/packages/react-chat/src/components/Icons/HideIcon.tsx @@ -0,0 +1,24 @@ +import React from "react"; +import styled from "styled-components"; + +export const HideIcon = () => ( + + + + + +); + +const Icon = styled.svg` + fill: ${({ theme }) => theme.tertiary}; +`; diff --git a/packages/react-chat/src/components/Icons/Icon.ts b/packages/react-chat/src/components/Icons/Icon.ts new file mode 100644 index 00000000..e9ff55d0 --- /dev/null +++ b/packages/react-chat/src/components/Icons/Icon.ts @@ -0,0 +1,16 @@ +import styled from "styled-components"; + +export const Icon = styled.div` + width: 40px; + height: 40px; + display: flex; + justify-content: center; + align-items: end; + border-radius: 50%; + background-color: #bcbdff; + background-size: contain; + background-position: center; + flex-shrink: 0; + position: relative; + cursor: pointer; +`; diff --git a/packages/react-chat/src/components/Icons/ReadIcon.tsx b/packages/react-chat/src/components/Icons/ReadIcon.tsx new file mode 100644 index 00000000..5c18d16c --- /dev/null +++ b/packages/react-chat/src/components/Icons/ReadIcon.tsx @@ -0,0 +1,43 @@ +import React from "react"; +import styled from "styled-components"; + +interface ReadIconProps { + isRead?: boolean; +} + +export const ReadIcon = ({ isRead }: ReadIconProps) => { + return ( + + + + + + ); +}; + +const Icon = styled.svg` + fill: ${({ theme }) => theme.tertiary}; + + &.read { + fill: ${({ theme }) => theme.secondary}; + } +`; diff --git a/packages/react-chat/src/components/Icons/ReplyActivityIcon.tsx b/packages/react-chat/src/components/Icons/ReplyActivityIcon.tsx new file mode 100644 index 00000000..815d582b --- /dev/null +++ b/packages/react-chat/src/components/Icons/ReplyActivityIcon.tsx @@ -0,0 +1,19 @@ +import React from "react"; +import styled from "styled-components"; + +export const ReplyIcon = () => ( + + + +); + +const Icon = styled.svg` + fill: ${({ theme }) => theme.secondary}; + flex-shrink: 0; +`; diff --git a/packages/react-chat/src/components/Icons/ShowIcon.tsx b/packages/react-chat/src/components/Icons/ShowIcon.tsx new file mode 100644 index 00000000..22eb5aef --- /dev/null +++ b/packages/react-chat/src/components/Icons/ShowIcon.tsx @@ -0,0 +1,27 @@ +import React from "react"; +import styled from "styled-components"; + +export const ShowIcon = () => ( + + + + +); + +const Icon = styled.svg` + fill: ${({ theme }) => theme.tertiary}; +`; diff --git a/packages/react-chat/src/components/Members/Member.tsx b/packages/react-chat/src/components/Members/Member.tsx index 222848ed..175e562e 100644 --- a/packages/react-chat/src/components/Members/Member.tsx +++ b/packages/react-chat/src/components/Members/Member.tsx @@ -3,8 +3,8 @@ import styled from "styled-components"; import { useMessengerContext } from "../../contexts/messengerProvider"; import { Contact } from "../../models/Contact"; -import { Icon } from "../Chat/ChatMessages"; import { ContactMenu } from "../Form/ContactMenu"; +import { Icon } from "../Icons/Icon"; import { UserIcon } from "../Icons/UserIcon"; interface MemberProps { diff --git a/packages/react-chat/src/components/Modals/ProfileModal.tsx b/packages/react-chat/src/components/Modals/ProfileModal.tsx index d68544d6..153c30f1 100644 --- a/packages/react-chat/src/components/Modals/ProfileModal.tsx +++ b/packages/react-chat/src/components/Modals/ProfileModal.tsx @@ -2,6 +2,7 @@ import React, { useEffect, useMemo, useState } from "react"; import { bufToHex } from "status-communities/dist/cjs/utils"; import styled from "styled-components"; +import { useActivities } from "../../contexts/activityProvider"; import { useIdentity } from "../../contexts/identityProvider"; import { useModal } from "../../contexts/modalProvider"; import { useManageContact } from "../../hooks/useManageContact"; @@ -40,6 +41,8 @@ export const ProfileModal = () => { [props] ); + const { setActivities } = useActivities(); + const identity = useIdentity(); const isUser = useMemo( () => id === bufToHex(identity.publicKey), @@ -47,12 +50,14 @@ export const ProfileModal = () => { ); const [renaming, setRenaming] = useState(renamingState ?? false); + useEffect(() => { setRenaming(renamingState ?? false); }, [renamingState]); const [request, setRequest] = useState(""); const [requestCreation, setRequestCreation] = useState(requestState ?? false); + useEffect(() => { setRequestCreation(requestState ?? false); }, [requestState]); @@ -183,7 +188,19 @@ export const ProfileModal = () => { { - setIsUserFriend(true), + setActivities((prev) => [ + ...prev, + { + id: id + request, + type: "request", + isRead: true, + date: new Date(), + user: id, + request: request, + requestType: "outcome", + status: "sent", + }, + ]), setRequestCreation(false), setRequest(""); }} diff --git a/packages/react-chat/src/components/ReactChat.tsx b/packages/react-chat/src/components/ReactChat.tsx index 94825983..c1bdaa96 100644 --- a/packages/react-chat/src/components/ReactChat.tsx +++ b/packages/react-chat/src/components/ReactChat.tsx @@ -2,6 +2,7 @@ import React, { useRef } from "react"; import { ThemeProvider } from "styled-components"; import styled from "styled-components"; +import { ActivityProvider } from "../contexts/activityProvider"; import { FetchMetadataProvider } from "../contexts/fetchMetadataProvider"; import { ModalProvider } from "../contexts/modalProvider"; import { NarrowProvider } from "../contexts/narrowProvider"; @@ -28,11 +29,13 @@ export function ReactChat({ - - - -