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;
setLink: (link: string) => void;
setUser: (user: string) => void;
customName?: string;
trueName?: string;
setRenaming: (val: boolean) => void;
};
function ChatUiMessage({
@ -37,6 +40,9 @@ function ChatUiMessage({
setImage,
setLink,
setUser,
customName,
trueName,
setRenaming,
}: ChatUiMessageProps) {
const [showMenu, setShowMenu] = useState(false);
const [isUntrustworthy, setIsUntrustworthy] = useState(false);
@ -63,6 +69,9 @@ function ChatUiMessage({
setShowMenu={setShowMenu}
isUntrustworthy={isUntrustworthy}
setIsUntrustworthy={setIsUntrustworthy}
customName={customName}
trueName={trueName}
setRenaming={setRenaming}
/>
)}
<UserIcon />
@ -71,7 +80,15 @@ function ChatUiMessage({
<ContentWrapper>
<MessageHeaderWrapper>
<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 />}
</UserNameWrapper>
<TimeWrapper>{message.date.toLocaleString()}</TimeWrapper>
@ -119,11 +136,23 @@ export function ChatMessages() {
);
useEffect(() => (!showLinkModal ? setLink("") : undefined), [showLinkModal]);
const [renaming, setRenaming] = useState(false);
const [customName, setCustomName] = useState("");
const [trueName, setTrueName] = useState("");
return (
<MessagesWrapper ref={ref}>
<PictureModal image={image} />
<LinkModal link={link} />
<ProfileModal user={user} />
<ProfileModal
user={user}
renaming={renaming}
setRenaming={setRenaming}
customName={customName}
setCustomName={setCustomName}
trueName={trueName}
setTrueName={setTrueName}
/>
<EmptyChannel channel={activeChannel} />
{loadingMessages && (
<LoadingWrapper>
@ -139,6 +168,9 @@ export function ChatMessages() {
setLink={setLink}
setImage={setImage}
setUser={setUser}
customName={customName}
trueName={trueName}
setRenaming={setRenaming}
/>
))}
</MessagesWrapper>
@ -226,6 +258,27 @@ const UserName = styled.p`
${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`
font-size: 10px;
line-height: 14px;

View File

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

View File

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

View File

@ -26,4 +26,6 @@ export const Text = styled.p`
export const ButtonSection = styled(Section)`
display: flex;
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 { copy } from "../../utils";
import { buttonStyles } from "../Buttons/buttonStyle";
import { ClearSvg } from "../Icons/ClearIcon";
import { CopySvg } from "../Icons/CopyIcon";
import { EditSvg } from "../Icons/EditIcon";
import { LeftIconSvg } from "../Icons/LeftIcon";
import { UntrustworthIcon } from "../Icons/UntrustworthIcon";
import { UserIcon } from "../Icons/UserIcon";
import { textMediumStyles } from "../Text";
@ -19,9 +21,24 @@ export const ProfileModalName = "profileModal";
interface ProfileModalProps {
user: 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 { blockedUsers, setBlockedUsers } = useBlockedUsers();
@ -41,7 +58,7 @@ export const ProfileModal = ({ user, image }: ProfileModalProps) => {
<Heading>{user.slice(0, 10)}s Profile</Heading>
</Section>
<Section>
<ProfileSection>
<NameSection>
{image ? (
<ProfileIcon
@ -53,64 +70,119 @@ export const ProfileModal = ({ user, image }: ProfileModalProps) => {
<UserIcon />
)}
<UserNameWrapper>
<UserName>{user.slice(0, 10)}</UserName>
<UserName>{customName ? customName : user.slice(0, 10)}</UserName>
{isUntrustworthy && <UntrustworthIcon />}
<EditSvg width={24} height={24} />
{!renaming && (
<button onClick={() => setRenaming(true)}>
{" "}
<EditSvg width={24} height={24} />
</button>
)}
</UserNameWrapper>
{trueName && <UserTrueName>{trueName}</UserTrueName>}
{trueName && <button onClick={() => setTrueName("")}></button>}
</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>
<UserAddress>Chatkey: {user.slice(0, 30)}</UserAddress>
<CopyButton onClick={() => copy(user)}>
<CopySvg width={24} height={24} />
</CopyButton>
</UserAddressWrapper>
<EmojiKey>🎩🍞🥑🦍🌈📡💅🏻🔔👵🅱</EmojiKey>
</Section>
<CopyButton onClick={() => copy(user)}>
<CopySvg width={24} height={24} />
</CopyButton>
</UserAddressWrapper>
<EmojiKey>🎩🍞🥑🦍🌈📡💅🏻🔔👵🅱</EmojiKey>{" "}
</>
)}
</ProfileSection>
<ButtonSection>
{!userIsFriend && (
<ProfileBtn
className={userInBlocked ? "" : "red"}
onClick={() => {
userInBlocked
? setBlockedUsers((prev) => prev.filter((e) => e != user))
: setBlockedUsers((prev) => [...prev, user]);
}}
>
{userInBlocked ? "Unblock" : "Block"}
</ProfileBtn>
)}
{userIsFriend && (
<ProfileBtn
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>
{renaming ? (
<>
<BackBtn onClick={() => setRenaming(false)}>
<LeftIconSvg width={28} height={28} />
</BackBtn>
<Btn
disabled={!customName}
onClick={() => {
setTrueName(user.slice(0, 10));
setRenaming(false);
}}
>
Apply nickname
</Btn>
</>
) : (
<>
{!userIsFriend && (
<ProfileBtn
className={userInBlocked ? "" : "red"}
onClick={() => {
userInBlocked
? setBlockedUsers((prev) => prev.filter((e) => e != user))
: setBlockedUsers((prev) => [...prev, user]);
}}
>
{userInBlocked ? "Unblock" : "Block"}
</ProfileBtn>
)}
{userIsFriend && (
<ProfileBtn
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>
</Modal>
);
};
const ProfileSection = styled(Section)`
display: flex;
flex-direction: column;
align-items: center;
`;
const NameSection = styled.div`
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
margin-bottom: 16px;
`;
@ -150,6 +222,14 @@ const UserName = styled.p`
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`
display: flex;
justify-content: center;
@ -211,4 +291,57 @@ const Btn = styled.button`
&:hover {
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 { FetchMetadataProvider } from "../contexts/fetchMetadataProvider";
import { FriendsProvider } from "../contexts/friendsProvider";
import { ModalProvider } from "../contexts/modalProvider";
import { NarrowProvider } from "../contexts/narrowProvider";
import { Metadata } from "../models/Metadata";
@ -29,13 +30,15 @@ export function ReactChat({
<NarrowProvider myRef={ref}>
<FetchMetadataProvider fetchMetadata={fetchMetadata}>
<BlockedUsersProvider>
<ModalProvider>
<Wrapper ref={ref}>
<GlobalStyle />
<ChatLoader communityKey={communityKey} />
<div id="modal-root" />
</Wrapper>
</ModalProvider>
<FriendsProvider>
<ModalProvider>
<Wrapper ref={ref}>
<GlobalStyle />
<ChatLoader communityKey={communityKey} />
<div id="modal-root" />
</Wrapper>
</ModalProvider>
</FriendsProvider>
</BlockedUsersProvider>
</FetchMetadataProvider>
</NarrowProvider>