Add user creation modal (#159)
This commit is contained in:
parent
35cc40329e
commit
51802fa03d
|
@ -13,6 +13,7 @@ import { Members } from "./Members/Members";
|
|||
import { CommunityModal } from "./Modals/CommunityModal";
|
||||
import { EditModal } from "./Modals/EditModal";
|
||||
import { ProfileModal } from "./Modals/ProfileModal";
|
||||
import { UserCreationModal } from "./Modals/UserCreationModal";
|
||||
import { ToastMessageList } from "./ToastMessages/ToastMessageList";
|
||||
import { UserCreation } from "./UserCreation/UserCreation";
|
||||
|
||||
|
@ -20,6 +21,7 @@ function Modals() {
|
|||
return (
|
||||
<>
|
||||
<CommunityModal subtitle="Public Community" />
|
||||
<UserCreationModal />
|
||||
<EditModal />
|
||||
<ProfileModal />
|
||||
</>
|
||||
|
|
|
@ -23,8 +23,9 @@ export function ChatCreation({
|
|||
const identity = useIdentity();
|
||||
const [query, setQuery] = useState("");
|
||||
const [styledGroup, setStyledGroup] = useState<string[]>(
|
||||
activeChannel?.members?.map((member) => member?.customName ?? member.id) ??
|
||||
[]
|
||||
activeChannel?.members?.map(
|
||||
(member) => member?.customName ?? member.trueName
|
||||
) ?? []
|
||||
);
|
||||
const { contacts, createGroupChat, addMembers } = useMessengerContext();
|
||||
const setChatState = useChatState()[1];
|
||||
|
|
|
@ -34,7 +34,7 @@ export function Mention({ id, setMentioned, className }: MentionProps) {
|
|||
|
||||
return (
|
||||
<MentionBLock onClick={() => setShowMenu(!showMenu)} className={className}>
|
||||
{`@${contact?.customName ?? contact.id}`}
|
||||
{`@${contact?.customName ?? contact.trueName}`}
|
||||
{showMenu && <ContactMenu id={id.slice(1)} setShowMenu={setShowMenu} />}
|
||||
</MentionBLock>
|
||||
);
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import React, { useState } from "react";
|
||||
import { Identity } from "status-communities/dist/cjs";
|
||||
import React from "react";
|
||||
|
||||
import { ChatStateProvider } from "../contexts/chatStateProvider";
|
||||
import { IdentityProvider } from "../contexts/identityProvider";
|
||||
|
@ -17,13 +16,12 @@ interface ChatLoaderProps {
|
|||
}
|
||||
|
||||
export function ChatLoader({ communityKey }: ChatLoaderProps) {
|
||||
const [identity, setIdentity] = useState<Identity | undefined>(undefined);
|
||||
const [userCreationState] = useUserCreationState();
|
||||
|
||||
if (userCreationState === UserCreationState.NotCreating)
|
||||
return (
|
||||
<IdentityProvider identity={identity}>
|
||||
<MessengerProvider identity={identity} communityKey={communityKey}>
|
||||
<IdentityProvider>
|
||||
<MessengerProvider communityKey={communityKey}>
|
||||
<ChatStateProvider>
|
||||
<Chat />
|
||||
</ChatStateProvider>
|
||||
|
@ -31,7 +29,7 @@ export function ChatLoader({ communityKey }: ChatLoaderProps) {
|
|||
</IdentityProvider>
|
||||
);
|
||||
if (userCreationState === UserCreationState.Creating) {
|
||||
return <IdentityLoader setIdentity={setIdentity} />;
|
||||
return <IdentityLoader />;
|
||||
}
|
||||
|
||||
return null;
|
||||
|
|
|
@ -43,7 +43,7 @@ export function ContactMenu({ id, setShowMenu }: ContactMenuProps) {
|
|||
<ContactInfo>
|
||||
<UserIcon />
|
||||
<UserNameWrapper>
|
||||
<UserName>{contact?.customName ?? id.slice(0, 10)}</UserName>
|
||||
<UserName>{contact?.customName ?? contact.trueName}</UserName>
|
||||
{contact.isUntrustworthy && <UntrustworthIcon />}
|
||||
</UserNameWrapper>
|
||||
{contact?.customName && (
|
||||
|
|
|
@ -2,6 +2,7 @@ import React, { useCallback, useEffect, useState } from "react";
|
|||
import { Identity } from "status-communities/dist/cjs";
|
||||
import styled from "styled-components";
|
||||
|
||||
import { useSetIdentity } from "../../contexts/identityProvider";
|
||||
import {
|
||||
UserCreationState,
|
||||
useUserCreationState,
|
||||
|
@ -12,11 +13,8 @@ import {
|
|||
saveIdentity,
|
||||
} from "../../utils";
|
||||
|
||||
interface IdentityLoaderProps {
|
||||
setIdentity: (e: Identity) => void;
|
||||
}
|
||||
|
||||
export function IdentityLoader({ setIdentity }: IdentityLoaderProps) {
|
||||
export function IdentityLoader() {
|
||||
const setIdentity = useSetIdentity();
|
||||
const [password, setPassword] = useState("");
|
||||
const state = useUserCreationState();
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ export function ColorChatSvg({ width, height }: ColorChatSvgProps) {
|
|||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<g clip-path="url(#clip0_1307_429352)">
|
||||
<g clipPath="url(#clip0_1307_429352)">
|
||||
<path
|
||||
d="M43.0453 20.5165C54.7313 20.338 64.2693 29.5356 64.4955 41.2207C64.5288 42.9363 64.3573 44.6062 64.004 46.2079C63.4058 48.92 63.0501 51.6799 63.0501 54.4573V59.8258C63.0501 60.6483 62.3834 61.315 61.5609 61.315H56.1924C53.415 61.315 50.6552 61.6707 47.943 62.2689C46.3414 62.6222 44.6715 62.7936 42.9559 62.7604C31.2709 62.5343 22.0733 52.9965 22.2516 41.3108C22.4254 29.9046 31.6392 20.6907 43.0453 20.5165Z"
|
||||
fill="url(#paint0_linear_1307_429352)"
|
||||
|
@ -62,8 +62,8 @@ export function ColorChatSvg({ width, height }: ColorChatSvgProps) {
|
|||
y2="68.3915"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop stop-color="#A7F3CE" />
|
||||
<stop offset="1" stop-color="#61DB99" />
|
||||
<stop stopColor="#A7F3CE" />
|
||||
<stop offset="1" stopColor="#61DB99" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="paint1_linear_1307_429352"
|
||||
|
@ -73,8 +73,8 @@ export function ColorChatSvg({ width, height }: ColorChatSvgProps) {
|
|||
y2="34.356"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop stop-color="#61DB99" stop-opacity="0" />
|
||||
<stop offset="1" stop-color="#009E74" />
|
||||
<stop stopColor="#61DB99" stopOpacity="0" />
|
||||
<stop offset="1" stopColor="#009E74" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="paint2_linear_1307_429352"
|
||||
|
@ -84,8 +84,8 @@ export function ColorChatSvg({ width, height }: ColorChatSvgProps) {
|
|||
y2="55.5561"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop stop-color="#62E1FB" />
|
||||
<stop offset="1" stop-color="#00A2F3" />
|
||||
<stop stopColor="#62E1FB" />
|
||||
<stop offset="1" stopColor="#00A2F3" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="paint3_linear_1307_429352"
|
||||
|
@ -95,8 +95,8 @@ export function ColorChatSvg({ width, height }: ColorChatSvgProps) {
|
|||
y2="19.9482"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop stop-color="#00A2F3" stop-opacity="0" />
|
||||
<stop offset="1" stop-color="#0075CD" />
|
||||
<stop stopColor="#00A2F3" stopOpacity="0" />
|
||||
<stop offset="1" stopColor="#0075CD" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="paint4_linear_1307_429352"
|
||||
|
@ -106,8 +106,8 @@ export function ColorChatSvg({ width, height }: ColorChatSvgProps) {
|
|||
y2="19.9478"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop stop-color="#00A2F3" stop-opacity="0" />
|
||||
<stop offset="1" stop-color="#2A353D" />
|
||||
<stop stopColor="#00A2F3" stopOpacity="0" />
|
||||
<stop offset="1" stopColor="#2A353D" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="paint5_linear_1307_429352"
|
||||
|
@ -117,8 +117,8 @@ export function ColorChatSvg({ width, height }: ColorChatSvgProps) {
|
|||
y2="19.9479"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop stop-color="#00A2F3" stop-opacity="0" />
|
||||
<stop offset="1" stop-color="#0075CD" />
|
||||
<stop stopColor="#00A2F3" stopOpacity="0" />
|
||||
<stop offset="1" stopColor="#0075CD" />
|
||||
</linearGradient>
|
||||
<clipPath id="clip0_1307_429352">
|
||||
<rect
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
import React, { useMemo } from "react";
|
||||
import { utils } from "status-communities/dist/cjs";
|
||||
import { bufToHex } from "status-communities/dist/cjs/utils";
|
||||
import styled from "styled-components";
|
||||
|
||||
import { useIdentity } from "../../contexts/identityProvider";
|
||||
import { useIdentity, useNickname } from "../../contexts/identityProvider";
|
||||
import { useMessengerContext } from "../../contexts/messengerProvider";
|
||||
import { UserIcon } from "../Icons/UserIcon";
|
||||
|
||||
|
@ -16,6 +15,7 @@ interface MembersListProps {
|
|||
export function MembersList({ switchShowMembers }: MembersListProps) {
|
||||
const { contacts } = useMessengerContext();
|
||||
const identity = useIdentity();
|
||||
const nickname = useNickname();
|
||||
const userContacts = useMemo(() => {
|
||||
if (identity) {
|
||||
return Object.values(contacts).filter(
|
||||
|
@ -42,9 +42,7 @@ export function MembersList({ switchShowMembers }: MembersListProps) {
|
|||
<MemberIcon>
|
||||
<UserIcon memberView={true} />
|
||||
</MemberIcon>
|
||||
{identity && (
|
||||
<MemberName>{utils.bufToHex(identity.publicKey)}</MemberName>
|
||||
)}
|
||||
{identity && <MemberName>{nickname}</MemberName>}
|
||||
</MemberData>
|
||||
</MemberCategory>
|
||||
{onlineContacts.length > 0 && (
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
import React, { useMemo } from "react";
|
||||
import styled from "styled-components";
|
||||
|
||||
type UserLogoProps = {
|
||||
radius: number;
|
||||
colorWheel: [string, number][];
|
||||
icon?: string;
|
||||
text?: string;
|
||||
};
|
||||
|
||||
export function UserLogo({ icon, text, radius, colorWheel }: UserLogoProps) {
|
||||
const conicGradient = useMemo(() => {
|
||||
const colors = colorWheel
|
||||
.map((color, idx) => {
|
||||
const prevDeg = idx === 0 ? "0deg" : `${colorWheel[idx - 1][1]}deg`;
|
||||
return `${color[0]} ${prevDeg} ${color[1]}deg`;
|
||||
})
|
||||
.join(",");
|
||||
return `conic-gradient(${colors})`;
|
||||
}, [colorWheel]);
|
||||
return (
|
||||
<Wrapper radius={radius} conicGradient={conicGradient}>
|
||||
<Logo icon={icon} radius={radius}>
|
||||
{!icon && text && <TextWrapper>{text}</TextWrapper>}
|
||||
</Logo>
|
||||
</Wrapper>
|
||||
);
|
||||
}
|
||||
|
||||
const TextWrapper = styled.div`
|
||||
font-family: Inter;
|
||||
font-style: normal;
|
||||
font-weight: bold;
|
||||
font-size: 32px;
|
||||
line-height: 38px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
letter-spacing: -0.4px;
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
`;
|
||||
|
||||
const Logo = styled.div<{ radius: number; icon?: string }>`
|
||||
width: calc(${({ radius }) => radius}px - 6px);
|
||||
height: calc(${({ radius }) => radius}px - 6px);
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
border-radius: 50%;
|
||||
font-weight: bold;
|
||||
font-size: 15px;
|
||||
line-height: 20px;
|
||||
background-color: ${({ theme }) => theme.logoColor};
|
||||
background-size: cover;
|
||||
background-repeat: no-repeat;
|
||||
background-image: ${({ icon }) => icon && `url(${icon}`};
|
||||
color: ${({ theme }) => theme.iconTextColor};
|
||||
margin: auto;
|
||||
display: flex;
|
||||
`;
|
||||
|
||||
const Wrapper = styled.div<{ radius: number; conicGradient: string }>`
|
||||
width: ${({ radius }) => radius}px;
|
||||
height: ${({ radius }) => radius}px;
|
||||
display: flex;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
border-radius: 50%;
|
||||
background: ${({ conicGradient }) => conicGradient};
|
||||
`;
|
|
@ -121,15 +121,10 @@ export function UiMessage({
|
|||
<ContentWrapper>
|
||||
<MessageHeaderWrapper>
|
||||
<UserNameWrapper>
|
||||
<UserName>
|
||||
{" "}
|
||||
{contact?.customName ?? message.sender.slice(0, 10)}
|
||||
</UserName>
|
||||
{contact?.customName && (
|
||||
<UserName> {contact?.customName ?? contact.trueName}</UserName>
|
||||
<UserAddress>
|
||||
{message.sender.slice(0, 5)}...{message.sender.slice(-3)}
|
||||
</UserAddress>
|
||||
)}
|
||||
{contact.isUntrustworthy && <UntrustworthIcon />}
|
||||
</UserNameWrapper>
|
||||
<TimeWrapper>{message.date.toLocaleString()}</TimeWrapper>
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import styled, { css } from "styled-components";
|
||||
|
||||
import { buttonStyles } from "../Buttons/buttonStyle";
|
||||
import { textMediumStyles } from "../Text";
|
||||
|
||||
export const Section = styled.div`
|
||||
|
@ -23,6 +24,36 @@ export const Text = styled.p`
|
|||
${textMediumStyles}
|
||||
`;
|
||||
|
||||
export const Btn = styled.button`
|
||||
padding: 11px 24px;
|
||||
margin-left: 8px;
|
||||
${buttonStyles}
|
||||
|
||||
&:hover {
|
||||
background: ${({ theme }) => theme.buttonBgHover};
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
background: ${({ theme }) => theme.border};
|
||||
color: ${({ theme }) => theme.secondary};
|
||||
}
|
||||
`;
|
||||
|
||||
export 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};
|
||||
}
|
||||
`;
|
||||
|
||||
export const ButtonSection = styled(Section)`
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
|
@ -7,6 +7,7 @@ import { useIdentity } from "../../contexts/identityProvider";
|
|||
import { useModal } from "../../contexts/modalProvider";
|
||||
import { useToasts } from "../../contexts/toastProvider";
|
||||
import { useManageContact } from "../../hooks/useManageContact";
|
||||
import { NameInput } from "../../styles/Inputs";
|
||||
import { copy } from "../../utils";
|
||||
import { buttonStyles } from "../Buttons/buttonStyle";
|
||||
import { ClearSvg } from "../Icons/ClearIcon";
|
||||
|
@ -19,6 +20,8 @@ import { textMediumStyles, textSmallStyles } from "../Text";
|
|||
|
||||
import { Modal } from "./Modal";
|
||||
import {
|
||||
BackBtn,
|
||||
Btn,
|
||||
ButtonSection,
|
||||
Heading,
|
||||
Hint,
|
||||
|
@ -84,7 +87,7 @@ export const ProfileModal = () => {
|
|||
className={`${!requestCreation && "profile"}`}
|
||||
>
|
||||
<Section>
|
||||
<Heading>{id.slice(0, 10)}’s Profile</Heading>
|
||||
<Heading>{contact.trueName}’s Profile</Heading>
|
||||
</Section>
|
||||
|
||||
<ProfileSection>
|
||||
|
@ -101,7 +104,7 @@ export const ProfileModal = () => {
|
|||
)}
|
||||
<UserNameWrapper>
|
||||
<UserName className={`${requestCreation && "small"}`}>
|
||||
{contact?.customName ?? id.slice(0, 10)}
|
||||
{contact?.customName ?? contact.trueName}
|
||||
</UserName>
|
||||
{contact.isUntrustworthy && <UntrustworthIcon />}
|
||||
{!renaming && (
|
||||
|
@ -402,36 +405,6 @@ const CopyButton = styled.button`
|
|||
}
|
||||
`;
|
||||
|
||||
const Btn = styled.button`
|
||||
padding: 11px 24px;
|
||||
margin-left: 8px;
|
||||
${buttonStyles}
|
||||
|
||||
&: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;
|
||||
|
@ -448,13 +421,6 @@ const NameInputWrapper = styled.div`
|
|||
position: relative;
|
||||
`;
|
||||
|
||||
const NameInput = styled.input`
|
||||
width: 328px;
|
||||
padding: 11px 16px;
|
||||
|
||||
${inputStyles}
|
||||
`;
|
||||
|
||||
const RequestSection = styled.div`
|
||||
width: 100%;
|
||||
display: flex;
|
||||
|
|
|
@ -0,0 +1,117 @@
|
|||
import React, { useState } from "react";
|
||||
import { Identity } from "status-communities/dist/cjs";
|
||||
import styled from "styled-components";
|
||||
|
||||
import {
|
||||
useSetIdentity,
|
||||
useSetNikcname,
|
||||
} from "../../contexts/identityProvider";
|
||||
import { useModal } from "../../contexts/modalProvider";
|
||||
import { NameInput } from "../../styles/Inputs";
|
||||
import { LeftIconSvg } from "../Icons/LeftIcon";
|
||||
import { UserLogo } from "../Members/UserLogo";
|
||||
|
||||
import { Modal } from "./Modal";
|
||||
import {
|
||||
BackBtn,
|
||||
Btn,
|
||||
ButtonSection,
|
||||
Heading,
|
||||
Hint,
|
||||
Section,
|
||||
Text,
|
||||
} from "./ModalStyle";
|
||||
|
||||
export const UserCreationModalName = "UserCreationModal";
|
||||
|
||||
export function UserCreationModal() {
|
||||
const setIdentity = useSetIdentity();
|
||||
const setNickname = useSetNikcname();
|
||||
|
||||
const [customNameInput, setCustomNameInput] = useState("");
|
||||
const { setModal } = useModal(UserCreationModalName);
|
||||
return (
|
||||
<Modal name={UserCreationModalName}>
|
||||
<Section>
|
||||
<Heading>Create a Status Profile</Heading>
|
||||
</Section>
|
||||
<MiddleSection>
|
||||
<Content>
|
||||
<Title>Your profile</Title>
|
||||
<StyledHint>
|
||||
Longer and unusual names are better as they are less likely to be
|
||||
used by someone else.
|
||||
</StyledHint>
|
||||
<LogoWrapper>
|
||||
<UserLogo
|
||||
text={customNameInput.slice(0, 2)}
|
||||
radius={80}
|
||||
colorWheel={[
|
||||
["red", 150],
|
||||
["blue", 250],
|
||||
["green", 360],
|
||||
]}
|
||||
/>
|
||||
</LogoWrapper>
|
||||
<NameInput
|
||||
placeholder="Display name"
|
||||
value={customNameInput}
|
||||
onChange={(e) => setCustomNameInput(e.currentTarget.value)}
|
||||
/>
|
||||
</Content>
|
||||
</MiddleSection>
|
||||
<ButtonSection style={{ marginBottom: "40px" }}>
|
||||
<BackBtn onClick={() => setModal(false)}>
|
||||
<LeftIconSvg width={28} height={28} />
|
||||
</BackBtn>
|
||||
<Btn
|
||||
onClick={() => {
|
||||
setIdentity(Identity.generate());
|
||||
setNickname(customNameInput);
|
||||
setModal(false);
|
||||
}}
|
||||
>
|
||||
Next
|
||||
</Btn>
|
||||
</ButtonSection>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
const MiddleSection = styled(Section)`
|
||||
margin-bottom: 102px;
|
||||
`;
|
||||
|
||||
const LogoWrapper = styled.div`
|
||||
position: relative;
|
||||
display: flex;
|
||||
margin-top: 32px;
|
||||
margin-bottom: 38px;
|
||||
`;
|
||||
|
||||
const StyledHint = styled(Hint)`
|
||||
font-family: Inter;
|
||||
font-style: normal;
|
||||
font-weight: normal;
|
||||
font-size: 15px;
|
||||
line-height: 22px;
|
||||
text-align: center;
|
||||
`;
|
||||
|
||||
const Title = styled(Text)`
|
||||
font-family: Inter;
|
||||
font-style: normal;
|
||||
font-weight: bold;
|
||||
font-size: 22px;
|
||||
line-height: 30px;
|
||||
|
||||
text-align: center;
|
||||
letter-spacing: -0.2px;
|
||||
margin-bottom: 16px;
|
||||
`;
|
||||
|
||||
const Content = styled.div`
|
||||
margin-top: 16px;
|
||||
margin-left: 65px;
|
||||
margin-right: 65px;
|
||||
`;
|
|
@ -1,14 +1,12 @@
|
|||
import React from "react";
|
||||
import styled from "styled-components";
|
||||
|
||||
import {
|
||||
UserCreationState,
|
||||
useUserCreationState,
|
||||
} from "../../contexts/userCreationStateProvider";
|
||||
import { useModal } from "../../contexts/modalProvider";
|
||||
import { ColorChatIcon } from "../Icons/ColorChatIcon";
|
||||
import { UserCreationModalName } from "../Modals/UserCreationModal";
|
||||
|
||||
export function UserCreation() {
|
||||
const state = useUserCreationState();
|
||||
const { setModal } = useModal(UserCreationModalName);
|
||||
return (
|
||||
<Background>
|
||||
<Wrapper>
|
||||
|
@ -16,7 +14,7 @@ export function UserCreation() {
|
|||
<ColorChatIcon />
|
||||
</IconWrapper>
|
||||
<TitleWrapper>Want in on the discussion ?</TitleWrapper>
|
||||
<ThrowAwayButton onClick={() => state[1](UserCreationState.Creating)}>
|
||||
<ThrowAwayButton onClick={() => setModal(true)}>
|
||||
Use a throwaway account
|
||||
</ThrowAwayButton>
|
||||
</Wrapper>
|
||||
|
|
|
@ -1,20 +1,46 @@
|
|||
import React, { createContext, useContext } from "react";
|
||||
import React, { createContext, useContext, useState } from "react";
|
||||
import { Identity } from "status-communities/dist/cjs";
|
||||
|
||||
const IdentityContext = createContext<Identity | undefined>(undefined);
|
||||
const IdentityContext = createContext<{
|
||||
identity: Identity | undefined;
|
||||
setIdentity: React.Dispatch<React.SetStateAction<Identity | undefined>>;
|
||||
nickname: string | undefined;
|
||||
setNickname: React.Dispatch<React.SetStateAction<string | undefined>>;
|
||||
}>({
|
||||
identity: undefined,
|
||||
setIdentity: () => undefined,
|
||||
nickname: undefined,
|
||||
setNickname: () => undefined,
|
||||
});
|
||||
|
||||
export function useIdentity() {
|
||||
return useContext(IdentityContext);
|
||||
return useContext(IdentityContext).identity;
|
||||
}
|
||||
|
||||
export function useSetIdentity() {
|
||||
return useContext(IdentityContext).setIdentity;
|
||||
}
|
||||
|
||||
export function useNickname() {
|
||||
return useContext(IdentityContext).nickname;
|
||||
}
|
||||
|
||||
export function useSetNikcname() {
|
||||
return useContext(IdentityContext).setNickname;
|
||||
}
|
||||
|
||||
interface IdentityProviderProps {
|
||||
children: React.ReactNode;
|
||||
identity: Identity | undefined;
|
||||
}
|
||||
|
||||
export function IdentityProvider({
|
||||
children,
|
||||
identity,
|
||||
}: IdentityProviderProps) {
|
||||
return <IdentityContext.Provider value={identity} children={children} />;
|
||||
export function IdentityProvider({ children }: IdentityProviderProps) {
|
||||
const [identity, setIdentity] = useState<Identity | undefined>(undefined);
|
||||
const [nickname, setNickname] = useState<string | undefined>(undefined);
|
||||
|
||||
return (
|
||||
<IdentityContext.Provider
|
||||
value={{ identity, setIdentity, nickname, setNickname }}
|
||||
children={children}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
import React, { createContext, useContext } from "react";
|
||||
import { Identity } from "status-communities/dist/cjs";
|
||||
|
||||
import { MessengerType, useMessenger } from "../hooks/messenger/useMessenger";
|
||||
|
||||
import { useIdentity, useNickname } from "./identityProvider";
|
||||
|
||||
const MessengerContext = createContext<MessengerType>({
|
||||
messenger: undefined,
|
||||
messages: [],
|
||||
|
@ -37,14 +38,14 @@ export function useMessengerContext() {
|
|||
interface MessengerProviderProps {
|
||||
children: React.ReactNode;
|
||||
communityKey?: string;
|
||||
identity?: Identity;
|
||||
}
|
||||
|
||||
export function MessengerProvider({
|
||||
children,
|
||||
communityKey,
|
||||
identity,
|
||||
}: MessengerProviderProps) {
|
||||
const messenger = useMessenger(communityKey, identity);
|
||||
const identity = useIdentity();
|
||||
const nickname = useNickname();
|
||||
const messenger = useMessenger(communityKey, identity, nickname);
|
||||
return <MessengerContext.Provider value={messenger} children={children} />;
|
||||
}
|
||||
|
|
|
@ -9,10 +9,11 @@ import { Contacts } from "../../models/Contact";
|
|||
|
||||
export function useContacts(
|
||||
messenger: Messenger | undefined,
|
||||
identity: Identity | undefined
|
||||
identity: Identity | undefined,
|
||||
nickname: string | undefined
|
||||
) {
|
||||
const [internalContacts, setInternalContacts] = useState<{
|
||||
[id: string]: number;
|
||||
[id: string]: { clock: number; nickname?: string };
|
||||
}>({});
|
||||
|
||||
const contactsClass = useMemo(() => {
|
||||
|
@ -22,9 +23,15 @@ export function useContacts(
|
|||
messenger.waku,
|
||||
(id, clock) => {
|
||||
setInternalContacts((prev) => {
|
||||
return { ...prev, [id]: clock };
|
||||
return { ...prev, [id]: { ...prev[id], clock } };
|
||||
});
|
||||
}
|
||||
},
|
||||
(id, nickname) => {
|
||||
setInternalContacts((prev) => {
|
||||
return { ...prev, [id]: { ...prev[id], nickname } };
|
||||
});
|
||||
},
|
||||
nickname
|
||||
);
|
||||
return newContacts;
|
||||
}
|
||||
|
@ -36,11 +43,11 @@ export function useContacts(
|
|||
const now = Date.now();
|
||||
setContacts((prev) => {
|
||||
const newContacts: Contacts = {};
|
||||
Object.entries(internalContacts).forEach(([id, clock]) => {
|
||||
Object.entries(internalContacts).forEach(([id, { clock, nickname }]) => {
|
||||
newContacts[id] = {
|
||||
id,
|
||||
online: clock > now - 301000,
|
||||
trueName: id.slice(0, 10),
|
||||
trueName: nickname ?? id.slice(0, 10),
|
||||
isUntrustworthy: false,
|
||||
blocked: false,
|
||||
};
|
||||
|
|
|
@ -24,7 +24,7 @@ export function useLoadPrevDay(
|
|||
async (id: string, groupChat?: boolean) => {
|
||||
if (messenger) {
|
||||
const endTime = lastLoadTime.current[id] ?? new Date();
|
||||
const startTime = new Date(endTime.getTime() - _MS_PER_DAY);
|
||||
const startTime = new Date(endTime.getTime() - _MS_PER_DAY * 5);
|
||||
const timeDiff = Math.floor(
|
||||
(new Date().getTime() - endTime.getTime()) / _MS_PER_DAY
|
||||
);
|
||||
|
|
|
@ -99,7 +99,8 @@ function useCreateCommunity(
|
|||
|
||||
export function useMessenger(
|
||||
communityKey: string | undefined,
|
||||
identity: Identity | undefined
|
||||
identity: Identity | undefined,
|
||||
nickname: string | undefined
|
||||
) {
|
||||
const [activeChannel, setActiveChannel] = useState<ChannelData>({
|
||||
id: "",
|
||||
|
@ -112,7 +113,8 @@ export function useMessenger(
|
|||
|
||||
const { contacts, setContacts, contactsClass } = useContacts(
|
||||
messenger,
|
||||
identity
|
||||
identity,
|
||||
nickname
|
||||
);
|
||||
|
||||
const {
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
import styled from "styled-components";
|
||||
|
||||
import { inputStyles } from "../components/Modals/ModalStyle";
|
||||
|
||||
export const NameInput = styled.input`
|
||||
width: 328px;
|
||||
padding: 11px 16px;
|
||||
|
||||
${inputStyles}
|
||||
`;
|
|
@ -8,6 +8,7 @@ export type Theme = {
|
|||
iconColor: string;
|
||||
iconUserColor: string;
|
||||
iconTextColor: string;
|
||||
logoColor: string;
|
||||
activeChannelBackground: string;
|
||||
notificationColor: string;
|
||||
inputColor: string;
|
||||
|
@ -37,6 +38,7 @@ export const lightTheme: Theme = {
|
|||
iconColor: "#D37EF4",
|
||||
iconUserColor: "#717199",
|
||||
iconTextColor: "rgba(255, 255, 255, 0.7)",
|
||||
logoColor: "#51D0F0",
|
||||
activeChannelBackground: "#E9EDF1",
|
||||
notificationColor: "#4360DF",
|
||||
inputColor: "#EEF2F5",
|
||||
|
@ -66,6 +68,7 @@ export const darkTheme: Theme = {
|
|||
guestNameColor: "#887AF9",
|
||||
iconColor: "#D37EF4",
|
||||
iconUserColor: "#717199",
|
||||
logoColor: "#51D0F0",
|
||||
iconTextColor: "rgba(0, 0, 0, 0.7)",
|
||||
activeChannelBackground: "#2C2C2C",
|
||||
notificationColor: "#887AF9",
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
import { Waku, WakuMessage } from "js-waku";
|
||||
import { PageDirection, Waku, WakuMessage } from "js-waku";
|
||||
|
||||
import { idToContactCodeTopic } from "./contentTopic";
|
||||
import { Identity } from "./identity";
|
||||
import { StatusUpdate_StatusType } from "./proto/communities/v1/status_update";
|
||||
import { bufToHex } from "./utils";
|
||||
import { ChatIdentity } from "./wire/chat_identity";
|
||||
import { StatusUpdate } from "./wire/status_update";
|
||||
|
||||
const STATUS_BROADCAST_INTERVAL = 30000;
|
||||
|
@ -11,7 +12,9 @@ const STATUS_BROADCAST_INTERVAL = 30000;
|
|||
export class Contacts {
|
||||
waku: Waku;
|
||||
identity: Identity | undefined;
|
||||
nickname?: string;
|
||||
private callback: (publicKey: string, clock: number) => void;
|
||||
private callbackNickname: (publicKey: string, nickname: string) => void;
|
||||
private contacts: string[] = [];
|
||||
|
||||
/**
|
||||
|
@ -30,11 +33,15 @@ export class Contacts {
|
|||
public constructor(
|
||||
identity: Identity | undefined,
|
||||
waku: Waku,
|
||||
callback: (publicKey: string, clock: number) => void
|
||||
callback: (publicKey: string, clock: number) => void,
|
||||
callbackNickname: (publicKey: string, nickname: string) => void,
|
||||
nickname?: string
|
||||
) {
|
||||
this.waku = waku;
|
||||
this.identity = identity;
|
||||
this.nickname = nickname;
|
||||
this.callback = callback;
|
||||
this.callbackNickname = callbackNickname;
|
||||
this.startBroadcast();
|
||||
if (identity) {
|
||||
this.addContact(bufToHex(identity.publicKey));
|
||||
|
@ -66,6 +73,26 @@ export class Contacts {
|
|||
endTime: now,
|
||||
},
|
||||
});
|
||||
this.waku.store.queryHistory([idToContactCodeTopic(publicKey)], {
|
||||
callback: (msgs) =>
|
||||
msgs.some((e) => {
|
||||
try {
|
||||
if (e.payload) {
|
||||
const chatIdentity = ChatIdentity.decode(e?.payload);
|
||||
if (chatIdentity) {
|
||||
this.callbackNickname(
|
||||
publicKey,
|
||||
chatIdentity?.displayName ?? ""
|
||||
);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}),
|
||||
pageDirection: PageDirection.BACKWARD,
|
||||
});
|
||||
this.waku.relay.addObserver(callback, [idToContactCodeTopic(publicKey)]);
|
||||
}
|
||||
}
|
||||
|
@ -84,6 +111,27 @@ export class Contacts {
|
|||
this.waku.relay.send(msg);
|
||||
}
|
||||
};
|
||||
|
||||
const sendNickname = async (): Promise<void> => {
|
||||
if (this.identity && this.nickname) {
|
||||
const chatIdentity = new ChatIdentity({
|
||||
clock: new Date().getTime(),
|
||||
color: "",
|
||||
description: "",
|
||||
emoji: "",
|
||||
images: {},
|
||||
ensName: "",
|
||||
displayName: this?.nickname ?? "",
|
||||
});
|
||||
const msg = await WakuMessage.fromBytes(
|
||||
chatIdentity.encode(),
|
||||
idToContactCodeTopic(bufToHex(this.identity.publicKey)),
|
||||
{ sigPrivKey: this.identity.privateKey }
|
||||
);
|
||||
await this.waku.relay.send(msg);
|
||||
}
|
||||
};
|
||||
sendNickname();
|
||||
send();
|
||||
setInterval(send, STATUS_BROADCAST_INTERVAL);
|
||||
}
|
||||
|
|
|
@ -223,7 +223,7 @@ export class Messenger {
|
|||
callback(messages.filter(isDefined));
|
||||
}
|
||||
};
|
||||
|
||||
console.log(`querying ${chat.contentTopic} for ${startTime} to ${endTime}`);
|
||||
const allMessages = await this.waku.store.queryHistory(
|
||||
[chat.contentTopic],
|
||||
{
|
||||
|
@ -231,6 +231,10 @@ export class Messenger {
|
|||
callback: _callback,
|
||||
}
|
||||
);
|
||||
console.log(
|
||||
`ended querying ${chat.contentTopic} for ${startTime} to ${endTime}`
|
||||
);
|
||||
|
||||
return allMessages.length;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue