Contact renaming (#131)

This commit is contained in:
Maria Rushkova 2021-11-16 20:18:58 +01:00 committed by GitHub
parent 3079487c02
commit 7fb0bfbdc7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 277 additions and 65 deletions

View File

@ -28,6 +28,9 @@ type ChatUiMessageProps = {
setImage: (img: string) => void; setImage: (img: string) => void;
setLink: (link: string) => void; setLink: (link: string) => void;
setUser: (user: string) => void; setUser: (user: string) => void;
customName?: string;
trueName?: string;
setRenaming: (val: boolean) => void;
}; };
function ChatUiMessage({ function ChatUiMessage({
@ -37,6 +40,9 @@ function ChatUiMessage({
setImage, setImage,
setLink, setLink,
setUser, setUser,
customName,
trueName,
setRenaming,
}: ChatUiMessageProps) { }: ChatUiMessageProps) {
const [showMenu, setShowMenu] = useState(false); const [showMenu, setShowMenu] = useState(false);
const [isUntrustworthy, setIsUntrustworthy] = useState(false); const [isUntrustworthy, setIsUntrustworthy] = useState(false);
@ -63,6 +69,9 @@ function ChatUiMessage({
setShowMenu={setShowMenu} setShowMenu={setShowMenu}
isUntrustworthy={isUntrustworthy} isUntrustworthy={isUntrustworthy}
setIsUntrustworthy={setIsUntrustworthy} setIsUntrustworthy={setIsUntrustworthy}
customName={customName}
trueName={trueName}
setRenaming={setRenaming}
/> />
)} )}
<UserIcon /> <UserIcon />
@ -71,7 +80,15 @@ function ChatUiMessage({
<ContentWrapper> <ContentWrapper>
<MessageHeaderWrapper> <MessageHeaderWrapper>
<UserNameWrapper> <UserNameWrapper>
<UserName>{message.sender.slice(0, 10)}</UserName> <UserName>
{" "}
{customName ? customName : message.sender.slice(0, 10)}
</UserName>
{customName && (
<UserAddress>
{message.sender.slice(0, 5)}...{message.sender.slice(-3)}
</UserAddress>
)}
{isUntrustworthy && <UntrustworthIcon />} {isUntrustworthy && <UntrustworthIcon />}
</UserNameWrapper> </UserNameWrapper>
<TimeWrapper>{message.date.toLocaleString()}</TimeWrapper> <TimeWrapper>{message.date.toLocaleString()}</TimeWrapper>
@ -119,11 +136,23 @@ export function ChatMessages() {
); );
useEffect(() => (!showLinkModal ? setLink("") : undefined), [showLinkModal]); useEffect(() => (!showLinkModal ? setLink("") : undefined), [showLinkModal]);
const [renaming, setRenaming] = useState(false);
const [customName, setCustomName] = useState("");
const [trueName, setTrueName] = useState("");
return ( return (
<MessagesWrapper ref={ref}> <MessagesWrapper ref={ref}>
<PictureModal image={image} /> <PictureModal image={image} />
<LinkModal link={link} /> <LinkModal link={link} />
<ProfileModal user={user} /> <ProfileModal
user={user}
renaming={renaming}
setRenaming={setRenaming}
customName={customName}
setCustomName={setCustomName}
trueName={trueName}
setTrueName={setTrueName}
/>
<EmptyChannel channel={activeChannel} /> <EmptyChannel channel={activeChannel} />
{loadingMessages && ( {loadingMessages && (
<LoadingWrapper> <LoadingWrapper>
@ -139,6 +168,9 @@ export function ChatMessages() {
setLink={setLink} setLink={setLink}
setImage={setImage} setImage={setImage}
setUser={setUser} setUser={setUser}
customName={customName}
trueName={trueName}
setRenaming={setRenaming}
/> />
))} ))}
</MessagesWrapper> </MessagesWrapper>
@ -226,6 +258,27 @@ const UserName = styled.p`
${textMediumStyles} ${textMediumStyles}
`; `;
export const UserAddress = styled.p`
font-size: 10px;
line-height: 14px;
letter-spacing: 0.2px;
color: ${({ theme }) => theme.secondary};
position: relative;
padding-right: 8px;
&:after {
content: "";
position: absolute;
right: 0;
top: 50%;
transform: translateY(-50%);
width: 4px;
height: 4px;
border-radius: 50%;
background: ${({ theme }) => theme.secondary};
}
`;
const TimeWrapper = styled.div` const TimeWrapper = styled.div`
font-size: 10px; font-size: 10px;
line-height: 14px; line-height: 14px;

View File

@ -5,7 +5,7 @@ import { useBlockedUsers } from "../../contexts/blockedUsersProvider";
import { useFriends } from "../../contexts/friendsProvider"; import { useFriends } from "../../contexts/friendsProvider";
import { useModal } from "../../contexts/modalProvider"; import { useModal } from "../../contexts/modalProvider";
import { ChatMessage } from "../../models/ChatMessage"; import { ChatMessage } from "../../models/ChatMessage";
import { Icon } from "../Chat/ChatMessages"; import { Icon, UserAddress } from "../Chat/ChatMessages";
import { AddContactSvg } from "../Icons/AddContactIcon"; import { AddContactSvg } from "../Icons/AddContactIcon";
import { BlockSvg } from "../Icons/BlockIcon"; import { BlockSvg } from "../Icons/BlockIcon";
import { ChatSvg } from "../Icons/ChatIcon"; import { ChatSvg } from "../Icons/ChatIcon";
@ -24,6 +24,9 @@ type ContactMenuProps = {
setShowMenu: (val: boolean) => void; setShowMenu: (val: boolean) => void;
isUntrustworthy: boolean; isUntrustworthy: boolean;
setIsUntrustworthy: (val: boolean) => void; setIsUntrustworthy: (val: boolean) => void;
customName?: string;
trueName?: string;
setRenaming: (val: boolean) => void;
}; };
export function ContactMenu({ export function ContactMenu({
@ -31,6 +34,9 @@ export function ContactMenu({
setShowMenu, setShowMenu,
isUntrustworthy, isUntrustworthy,
setIsUntrustworthy, setIsUntrustworthy,
customName,
trueName,
setRenaming,
}: ContactMenuProps) { }: ContactMenuProps) {
const id = message.sender; const id = message.sender;
const { blockedUsers, setBlockedUsers } = useBlockedUsers(); const { blockedUsers, setBlockedUsers } = useBlockedUsers();
@ -59,9 +65,12 @@ export function ContactMenu({
<UserIcon /> <UserIcon />
)} )}
<UserNameWrapper> <UserNameWrapper>
<UserName>{message.sender.slice(0, 10)}</UserName> <UserName>
{customName ? customName : message.sender.slice(0, 10)}
</UserName>
{isUntrustworthy && <UntrustworthIcon />} {isUntrustworthy && <UntrustworthIcon />}
</UserNameWrapper> </UserNameWrapper>
{trueName && <UserTrueName>({trueName})</UserTrueName>}
<UserAddress> <UserAddress>
{message.sender.slice(0, 10)}...{message.sender.slice(-3)} {message.sender.slice(0, 10)}...{message.sender.slice(-3)}
</UserAddress> </UserAddress>
@ -83,7 +92,12 @@ export function ContactMenu({
<MenuText>Send Message</MenuText> <MenuText>Send Message</MenuText>
</MenuItem> </MenuItem>
)} )}
<MenuItem> <MenuItem
onClick={() => {
setModal(true);
setRenaming(true);
}}
>
<EditSvg width={16} height={16} /> <EditSvg width={16} height={16} />
<MenuText>Rename</MenuText> <MenuText>Rename</MenuText>
</MenuItem> </MenuItem>
@ -151,10 +165,10 @@ const UserName = styled.p`
${textMediumStyles} ${textMediumStyles}
`; `;
const UserAddress = styled.p` const UserTrueName = styled.p`
font-size: 10px; color: ${({ theme }) => theme.primary};
line-height: 14px; font-size: 12px;
letter-spacing: 0.2px; line-height: 16px;
margin-bottom: 8px; letter-spacing: 0.1px;
color: ${({ theme }) => theme.secondary}; margin-top: 4px;
`; `;

View File

@ -13,7 +13,6 @@ export function ClearSvg({ height, width, className }: ClearSvgProps) {
width={width} width={width}
height={height} height={height}
viewBox="0 0 16 16" viewBox="0 0 16 16"
fill="none"
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
className={className} className={className}
> >
@ -36,6 +35,14 @@ const Icon = styled(ClearSvg)`
fill: ${({ theme }) => theme.tertiary}; fill: ${({ theme }) => theme.tertiary};
} }
&.profile {
fill: ${({ theme }) => theme.secondary};
}
&.profile > path {
fill: ${({ theme }) => theme.bodyBackgroundColor};
}
&:hover > path { &:hover > path {
fill: ${({ theme }) => theme.bodyBackgroundColor}; fill: ${({ theme }) => theme.bodyBackgroundColor};
} }

View File

@ -26,4 +26,6 @@ export const Text = styled.p`
export const ButtonSection = styled(Section)` export const ButtonSection = styled(Section)`
display: flex; display: flex;
justify-content: flex-end; justify-content: flex-end;
align-items: center;
position: relative;
`; `;

View File

@ -5,8 +5,10 @@ import { useBlockedUsers } from "../../contexts/blockedUsersProvider";
import { useFriends } from "../../contexts/friendsProvider"; import { useFriends } from "../../contexts/friendsProvider";
import { copy } from "../../utils"; import { copy } from "../../utils";
import { buttonStyles } from "../Buttons/buttonStyle"; import { buttonStyles } from "../Buttons/buttonStyle";
import { ClearSvg } from "../Icons/ClearIcon";
import { CopySvg } from "../Icons/CopyIcon"; import { CopySvg } from "../Icons/CopyIcon";
import { EditSvg } from "../Icons/EditIcon"; import { EditSvg } from "../Icons/EditIcon";
import { LeftIconSvg } from "../Icons/LeftIcon";
import { UntrustworthIcon } from "../Icons/UntrustworthIcon"; import { UntrustworthIcon } from "../Icons/UntrustworthIcon";
import { UserIcon } from "../Icons/UserIcon"; import { UserIcon } from "../Icons/UserIcon";
import { textMediumStyles } from "../Text"; import { textMediumStyles } from "../Text";
@ -19,9 +21,24 @@ export const ProfileModalName = "profileModal";
interface ProfileModalProps { interface ProfileModalProps {
user: string; user: string;
image?: string; image?: string;
renaming: boolean;
customName?: string;
trueName?: string;
setRenaming: (val: boolean) => void;
setTrueName: (val: string) => void;
setCustomName: (val: string) => void;
} }
export const ProfileModal = ({ user, image }: ProfileModalProps) => { export const ProfileModal = ({
user,
image,
renaming,
customName,
trueName,
setRenaming,
setTrueName,
setCustomName,
}: ProfileModalProps) => {
const [isUntrustworthy, setIsUntrustworthy] = useState(false); const [isUntrustworthy, setIsUntrustworthy] = useState(false);
const { blockedUsers, setBlockedUsers } = useBlockedUsers(); const { blockedUsers, setBlockedUsers } = useBlockedUsers();
@ -41,7 +58,7 @@ export const ProfileModal = ({ user, image }: ProfileModalProps) => {
<Heading>{user.slice(0, 10)}s Profile</Heading> <Heading>{user.slice(0, 10)}s Profile</Heading>
</Section> </Section>
<Section> <ProfileSection>
<NameSection> <NameSection>
{image ? ( {image ? (
<ProfileIcon <ProfileIcon
@ -53,64 +70,119 @@ export const ProfileModal = ({ user, image }: ProfileModalProps) => {
<UserIcon /> <UserIcon />
)} )}
<UserNameWrapper> <UserNameWrapper>
<UserName>{user.slice(0, 10)}</UserName> <UserName>{customName ? customName : user.slice(0, 10)}</UserName>
{isUntrustworthy && <UntrustworthIcon />} {isUntrustworthy && <UntrustworthIcon />}
<EditSvg width={24} height={24} /> {!renaming && (
<button onClick={() => setRenaming(true)}>
{" "}
<EditSvg width={24} height={24} />
</button>
)}
</UserNameWrapper> </UserNameWrapper>
{trueName && <UserTrueName>{trueName}</UserTrueName>}
{trueName && <button onClick={() => setTrueName("")}></button>}
</NameSection> </NameSection>
{renaming ? (
<NameInputWrapper>
<NameInput
placeholder="Only you will see this nickname"
value={customName}
onChange={(e) => setCustomName(e.currentTarget.value)}
/>
{customName && (
<ClearBtn
onClick={() => {
setCustomName("");
setTrueName("");
}}
>
<ClearSvg width={16} height={16} className="profile" />
</ClearBtn>
)}
</NameInputWrapper>
) : (
<>
<UserAddressWrapper>
<UserAddress>Chatkey: {user.slice(0, 30)}</UserAddress>
<UserAddressWrapper> <CopyButton onClick={() => copy(user)}>
<UserAddress>Chatkey: {user.slice(0, 30)}</UserAddress> <CopySvg width={24} height={24} />
</CopyButton>
<CopyButton onClick={() => copy(user)}> </UserAddressWrapper>
<CopySvg width={24} height={24} /> <EmojiKey>🎩🍞🥑🦍🌈📡💅🏻🔔👵🅱</EmojiKey>{" "}
</CopyButton> </>
</UserAddressWrapper> )}
</ProfileSection>
<EmojiKey>🎩🍞🥑🦍🌈📡💅🏻🔔👵🅱</EmojiKey>
</Section>
<ButtonSection> <ButtonSection>
{!userIsFriend && ( {renaming ? (
<ProfileBtn <>
className={userInBlocked ? "" : "red"} <BackBtn onClick={() => setRenaming(false)}>
onClick={() => { <LeftIconSvg width={28} height={28} />
userInBlocked </BackBtn>
? setBlockedUsers((prev) => prev.filter((e) => e != user)) <Btn
: setBlockedUsers((prev) => [...prev, user]); disabled={!customName}
}} onClick={() => {
> setTrueName(user.slice(0, 10));
{userInBlocked ? "Unblock" : "Block"} setRenaming(false);
</ProfileBtn> }}
)} >
{userIsFriend && ( Apply nickname
<ProfileBtn </Btn>
className="red" </>
onClick={() => setFriends((prev) => prev.filter((e) => e != user))} ) : (
> <>
Remove Contact {!userIsFriend && (
</ProfileBtn> <ProfileBtn
)} className={userInBlocked ? "" : "red"}
<ProfileBtn onClick={() => {
className={isUntrustworthy ? "" : "red"} userInBlocked
onClick={() => setIsUntrustworthy(!isUntrustworthy)} ? setBlockedUsers((prev) => prev.filter((e) => e != user))
> : setBlockedUsers((prev) => [...prev, user]);
{isUntrustworthy }}
? "Remove Untrustworthy Mark" >
: "Mark as Untrustworthy"} {userInBlocked ? "Unblock" : "Block"}
</ProfileBtn> </ProfileBtn>
{!userIsFriend && ( )}
<Btn onClick={() => setFriends((prev) => [...prev, user])}> {userIsFriend && (
Send Contact Request <ProfileBtn
</Btn> className="red"
onClick={() =>
setFriends((prev) => prev.filter((e) => e != user))
}
>
Remove Contact
</ProfileBtn>
)}
<ProfileBtn
className={isUntrustworthy ? "" : "red"}
onClick={() => setIsUntrustworthy(!isUntrustworthy)}
>
{isUntrustworthy
? "Remove Untrustworthy Mark"
: "Mark as Untrustworthy"}
</ProfileBtn>
{!userIsFriend && (
<Btn onClick={() => setFriends((prev) => [...prev, user])}>
Send Contact Request
</Btn>
)}
</>
)} )}
</ButtonSection> </ButtonSection>
</Modal> </Modal>
); );
}; };
const ProfileSection = styled(Section)`
display: flex;
flex-direction: column;
align-items: center;
`;
const NameSection = styled.div` const NameSection = styled.div`
display: flex; display: flex;
flex-direction: column; flex-direction: column;
justify-content: center;
align-items: center; align-items: center;
margin-bottom: 16px; margin-bottom: 16px;
`; `;
@ -150,6 +222,14 @@ const UserName = styled.p`
margin-right: 8px; margin-right: 8px;
`; `;
const UserTrueName = styled.p`
color: ${({ theme }) => theme.primary};
font-size: 12px;
line-height: 16px;
letter-spacing: 0.1px;
margin-top: 8px;
`;
const UserAddressWrapper = styled.div` const UserAddressWrapper = styled.div`
display: flex; display: flex;
justify-content: center; justify-content: center;
@ -211,4 +291,57 @@ const Btn = styled.button`
&:hover { &:hover {
background: ${({ theme }) => theme.buttonBgHover}; background: ${({ theme }) => theme.buttonBgHover};
} }
&:disabled {
background: ${({ theme }) => theme.border};
color: ${({ theme }) => theme.secondary};
}
`;
const BackBtn = styled(Btn)`
position: absolute;
left: 16px;
top: 16px;
width: 44px;
height: 44px;
border-radius: 50%;
padding: 8px;
margin-left: 0;
& > svg {
fill: ${({ theme }) => theme.tertiary};
}
`;
const ClearBtn = styled.button`
position: absolute;
right: 16px;
top: 50%;
transform: translateY(-50%);
border-radius: 50%;
& > svg {
fill: ${({ theme }) => theme.secondary};
}
`;
const NameInputWrapper = styled.div`
position: relative;
`;
const NameInput = styled.input`
width: 328px;
padding: 11px 16px;
background: ${({ theme }) => theme.inputColor};
border-radius: 8px;
border: 1px solid ${({ theme }) => theme.border};
color: ${({ theme }) => theme.primary};
outline: none;
${textMediumStyles}
&:focus {
outline: 1px solid ${({ theme }) => theme.tertiary};
caret-color: ${({ theme }) => theme.notificationColor};
}
`; `;

View File

@ -4,6 +4,7 @@ import styled from "styled-components";
import { BlockedUsersProvider } from "../contexts/blockedUsersProvider"; import { BlockedUsersProvider } from "../contexts/blockedUsersProvider";
import { FetchMetadataProvider } from "../contexts/fetchMetadataProvider"; import { FetchMetadataProvider } from "../contexts/fetchMetadataProvider";
import { FriendsProvider } from "../contexts/friendsProvider";
import { ModalProvider } from "../contexts/modalProvider"; import { ModalProvider } from "../contexts/modalProvider";
import { NarrowProvider } from "../contexts/narrowProvider"; import { NarrowProvider } from "../contexts/narrowProvider";
import { Metadata } from "../models/Metadata"; import { Metadata } from "../models/Metadata";
@ -29,13 +30,15 @@ export function ReactChat({
<NarrowProvider myRef={ref}> <NarrowProvider myRef={ref}>
<FetchMetadataProvider fetchMetadata={fetchMetadata}> <FetchMetadataProvider fetchMetadata={fetchMetadata}>
<BlockedUsersProvider> <BlockedUsersProvider>
<ModalProvider> <FriendsProvider>
<Wrapper ref={ref}> <ModalProvider>
<GlobalStyle /> <Wrapper ref={ref}>
<ChatLoader communityKey={communityKey} /> <GlobalStyle />
<div id="modal-root" /> <ChatLoader communityKey={communityKey} />
</Wrapper> <div id="modal-root" />
</ModalProvider> </Wrapper>
</ModalProvider>
</FriendsProvider>
</BlockedUsersProvider> </BlockedUsersProvider>
</FetchMetadataProvider> </FetchMetadataProvider>
</NarrowProvider> </NarrowProvider>