Show chat without identity (#157)
This commit is contained in:
parent
15e5731167
commit
2323fc273f
|
@ -120,9 +120,9 @@ function ActivityMessage({
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{" "}
|
{" "}
|
||||||
{contact.customName ?? activity.user.slice(0, 10)}
|
{contact?.customName ?? activity.user.slice(0, 10)}
|
||||||
</ActivityUserName>
|
</ActivityUserName>
|
||||||
{contact.customName && (
|
{contact?.customName && (
|
||||||
<UserAddress>
|
<UserAddress>
|
||||||
{activity.user.slice(0, 5)}...{activity.user.slice(-3)}
|
{activity.user.slice(0, 5)}...{activity.user.slice(-3)}
|
||||||
</UserAddress>
|
</UserAddress>
|
||||||
|
|
|
@ -34,7 +34,8 @@ export function EmptyChannel({ channel }: EmptyChannelProps) {
|
||||||
</EmptyText>
|
</EmptyText>
|
||||||
) : channel.type === "group" ? (
|
) : channel.type === "group" ? (
|
||||||
<EmptyTextGroup>
|
<EmptyTextGroup>
|
||||||
<span>{utils.bufToHex(identity.publicKey)}</span> created a group with{" "}
|
{identity && <span>{utils.bufToHex(identity.publicKey)}</span>}{" "}
|
||||||
|
created a group with{" "}
|
||||||
<span>{groupName.slice(groupName.length - 1)}</span> and{" "}
|
<span>{groupName.slice(groupName.length - 1)}</span> and{" "}
|
||||||
<span>{groupName.at(-1)}</span>
|
<span>{groupName.at(-1)}</span>
|
||||||
</EmptyTextGroup>
|
</EmptyTextGroup>
|
||||||
|
|
|
@ -2,6 +2,7 @@ import React, { useState } from "react";
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
|
|
||||||
import { ChatState, useChatState } from "../contexts/chatStateProvider";
|
import { ChatState, useChatState } from "../contexts/chatStateProvider";
|
||||||
|
import { useIdentity } from "../contexts/identityProvider";
|
||||||
import { useNarrow } from "../contexts/narrowProvider";
|
import { useNarrow } from "../contexts/narrowProvider";
|
||||||
|
|
||||||
import { Channels } from "./Channels/Channels";
|
import { Channels } from "./Channels/Channels";
|
||||||
|
@ -13,6 +14,7 @@ import { CommunityModal } from "./Modals/CommunityModal";
|
||||||
import { EditModal } from "./Modals/EditModal";
|
import { EditModal } from "./Modals/EditModal";
|
||||||
import { ProfileModal } from "./Modals/ProfileModal";
|
import { ProfileModal } from "./Modals/ProfileModal";
|
||||||
import { ToastMessageList } from "./ToastMessages/ToastMessageList";
|
import { ToastMessageList } from "./ToastMessages/ToastMessageList";
|
||||||
|
import { UserCreation } from "./UserCreation/UserCreation";
|
||||||
|
|
||||||
function Modals() {
|
function Modals() {
|
||||||
return (
|
return (
|
||||||
|
@ -28,13 +30,13 @@ export function Chat() {
|
||||||
const [state] = useChatState();
|
const [state] = useChatState();
|
||||||
const [showMembers, setShowMembers] = useState(false);
|
const [showMembers, setShowMembers] = useState(false);
|
||||||
const narrow = useNarrow();
|
const narrow = useNarrow();
|
||||||
|
const identity = useIdentity();
|
||||||
return (
|
return (
|
||||||
<ChatWrapper>
|
<ChatWrapper>
|
||||||
{!narrow && (
|
{!narrow && (
|
||||||
<ChannelsWrapper>
|
<ChannelsWrapper>
|
||||||
<StyledCommunity />
|
<StyledCommunity />
|
||||||
<Channels />
|
{identity ? <Channels /> : <UserCreation />}
|
||||||
</ChannelsWrapper>
|
</ChannelsWrapper>
|
||||||
)}
|
)}
|
||||||
{state === ChatState.ChatBody && (
|
{state === ChatState.ChatBody && (
|
||||||
|
|
|
@ -46,10 +46,12 @@ export function ChatCreation({
|
||||||
};
|
};
|
||||||
|
|
||||||
const createChat = (group: string[]) => {
|
const createChat = (group: string[]) => {
|
||||||
const newGroup = group.slice();
|
if (identity) {
|
||||||
newGroup.push(bufToHex(identity.publicKey));
|
const newGroup = group.slice();
|
||||||
group.length > 1 ? createGroupChat(newGroup) : createGroupChat(newGroup);
|
newGroup.push(bufToHex(identity.publicKey));
|
||||||
setChatState(ChatState.ChatBody);
|
group.length > 1 ? createGroupChat(newGroup) : createGroupChat(newGroup);
|
||||||
|
setChatState(ChatState.ChatBody);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -108,20 +110,21 @@ export function ChatCreation({
|
||||||
<Contacts>
|
<Contacts>
|
||||||
<ContactsHeading>Contacts</ContactsHeading>
|
<ContactsHeading>Contacts</ContactsHeading>
|
||||||
<ContactsList>
|
<ContactsList>
|
||||||
{Object.values(contacts)
|
{identity &&
|
||||||
.filter(
|
Object.values(contacts)
|
||||||
(e) =>
|
.filter(
|
||||||
e.id != bufToHex(identity.publicKey) &&
|
(e) =>
|
||||||
!styledGroup.includes(e.id)
|
e.id != bufToHex(identity.publicKey) &&
|
||||||
)
|
!styledGroup.includes(e.id)
|
||||||
.map((contact) => (
|
)
|
||||||
<Member
|
.map((contact) => (
|
||||||
key={contact.id}
|
<Member
|
||||||
contact={contact}
|
key={contact.id}
|
||||||
isOnline={contact.online}
|
contact={contact}
|
||||||
onClick={() => addMember(contact.id)}
|
isOnline={contact.online}
|
||||||
/>
|
onClick={() => addMember(contact.id)}
|
||||||
))}
|
/>
|
||||||
|
))}
|
||||||
</ContactsList>
|
</ContactsList>
|
||||||
</Contacts>
|
</Contacts>
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -27,12 +27,14 @@ export function Mention({ id, setMentioned, className }: MentionProps) {
|
||||||
if (!contact) return <>{id}</>;
|
if (!contact) return <>{id}</>;
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (contact.id === utils.bufToHex(identity.publicKey)) setMentioned(true);
|
if (identity) {
|
||||||
}, [contact.id]);
|
if (contact.id === utils.bufToHex(identity.publicKey)) setMentioned(true);
|
||||||
|
}
|
||||||
|
}, [contact.id, identity]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MentionBLock onClick={() => setShowMenu(!showMenu)} className={className}>
|
<MentionBLock onClick={() => setShowMenu(!showMenu)} className={className}>
|
||||||
{`@${contact.customName ?? contact.id}`}
|
{`@${contact?.customName ?? contact.id}`}
|
||||||
{showMenu && <ContactMenu id={id.slice(1)} setShowMenu={setShowMenu} />}
|
{showMenu && <ContactMenu id={id.slice(1)} setShowMenu={setShowMenu} />}
|
||||||
</MentionBLock>
|
</MentionBLock>
|
||||||
);
|
);
|
||||||
|
|
|
@ -4,6 +4,10 @@ import { Identity } from "status-communities/dist/cjs";
|
||||||
import { ChatStateProvider } from "../contexts/chatStateProvider";
|
import { ChatStateProvider } from "../contexts/chatStateProvider";
|
||||||
import { IdentityProvider } from "../contexts/identityProvider";
|
import { IdentityProvider } from "../contexts/identityProvider";
|
||||||
import { MessengerProvider } from "../contexts/messengerProvider";
|
import { MessengerProvider } from "../contexts/messengerProvider";
|
||||||
|
import {
|
||||||
|
UserCreationState,
|
||||||
|
useUserCreationState,
|
||||||
|
} from "../contexts/userCreationStateProvider";
|
||||||
|
|
||||||
import { Chat } from "./Chat";
|
import { Chat } from "./Chat";
|
||||||
import { IdentityLoader } from "./Form/IdentityLoader";
|
import { IdentityLoader } from "./Form/IdentityLoader";
|
||||||
|
@ -14,8 +18,9 @@ interface ChatLoaderProps {
|
||||||
|
|
||||||
export function ChatLoader({ communityKey }: ChatLoaderProps) {
|
export function ChatLoader({ communityKey }: ChatLoaderProps) {
|
||||||
const [identity, setIdentity] = useState<Identity | undefined>(undefined);
|
const [identity, setIdentity] = useState<Identity | undefined>(undefined);
|
||||||
|
const [userCreationState] = useUserCreationState();
|
||||||
|
|
||||||
if (identity) {
|
if (userCreationState === UserCreationState.NotCreating)
|
||||||
return (
|
return (
|
||||||
<IdentityProvider identity={identity}>
|
<IdentityProvider identity={identity}>
|
||||||
<MessengerProvider identity={identity} communityKey={communityKey}>
|
<MessengerProvider identity={identity} communityKey={communityKey}>
|
||||||
|
@ -25,7 +30,9 @@ export function ChatLoader({ communityKey }: ChatLoaderProps) {
|
||||||
</MessengerProvider>
|
</MessengerProvider>
|
||||||
</IdentityProvider>
|
</IdentityProvider>
|
||||||
);
|
);
|
||||||
} else {
|
if (userCreationState === UserCreationState.Creating) {
|
||||||
return <IdentityLoader setIdentity={setIdentity} />;
|
return <IdentityLoader setIdentity={setIdentity} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,10 +26,13 @@ type ContactMenuProps = {
|
||||||
|
|
||||||
export function ContactMenu({ id, setShowMenu }: ContactMenuProps) {
|
export function ContactMenu({ id, setShowMenu }: ContactMenuProps) {
|
||||||
const identity = useIdentity();
|
const identity = useIdentity();
|
||||||
const isUser = useMemo(
|
const isUser = useMemo(() => {
|
||||||
() => id === bufToHex(identity.publicKey),
|
if (identity) {
|
||||||
[id, identity]
|
return id === bufToHex(identity.publicKey);
|
||||||
);
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}, [id, identity]);
|
||||||
|
|
||||||
const { setModal } = useModal(ProfileModalName);
|
const { setModal } = useModal(ProfileModalName);
|
||||||
const { contact, setBlocked, setIsUntrustworthy } = useManageContact(id);
|
const { contact, setBlocked, setIsUntrustworthy } = useManageContact(id);
|
||||||
|
@ -40,10 +43,10 @@ export function ContactMenu({ id, setShowMenu }: ContactMenuProps) {
|
||||||
<ContactInfo>
|
<ContactInfo>
|
||||||
<UserIcon />
|
<UserIcon />
|
||||||
<UserNameWrapper>
|
<UserNameWrapper>
|
||||||
<UserName>{contact.customName ?? id.slice(0, 10)}</UserName>
|
<UserName>{contact?.customName ?? id.slice(0, 10)}</UserName>
|
||||||
{contact.isUntrustworthy && <UntrustworthIcon />}
|
{contact.isUntrustworthy && <UntrustworthIcon />}
|
||||||
</UserNameWrapper>
|
</UserNameWrapper>
|
||||||
{contact.customName && (
|
{contact?.customName && (
|
||||||
<UserTrueName>({contact.trueName})</UserTrueName>
|
<UserTrueName>({contact.trueName})</UserTrueName>
|
||||||
)}
|
)}
|
||||||
<UserAddress>
|
<UserAddress>
|
||||||
|
|
|
@ -2,6 +2,10 @@ import React, { useCallback, useEffect, useState } from "react";
|
||||||
import { Identity } from "status-communities/dist/cjs";
|
import { Identity } from "status-communities/dist/cjs";
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
|
|
||||||
|
import {
|
||||||
|
UserCreationState,
|
||||||
|
useUserCreationState,
|
||||||
|
} from "../../contexts/userCreationStateProvider";
|
||||||
import {
|
import {
|
||||||
decryptIdentity,
|
decryptIdentity,
|
||||||
loadEncryptedIdentity,
|
loadEncryptedIdentity,
|
||||||
|
@ -14,8 +18,8 @@ interface IdentityLoaderProps {
|
||||||
|
|
||||||
export function IdentityLoader({ setIdentity }: IdentityLoaderProps) {
|
export function IdentityLoader({ setIdentity }: IdentityLoaderProps) {
|
||||||
const [password, setPassword] = useState("");
|
const [password, setPassword] = useState("");
|
||||||
// Test password for now
|
const state = useUserCreationState();
|
||||||
// Need design for password input
|
|
||||||
const [encryptedIdentity, setEncryptedIdentity] = useState(
|
const [encryptedIdentity, setEncryptedIdentity] = useState(
|
||||||
loadEncryptedIdentity() ?? ""
|
loadEncryptedIdentity() ?? ""
|
||||||
);
|
);
|
||||||
|
@ -35,6 +39,7 @@ export function IdentityLoader({ setIdentity }: IdentityLoaderProps) {
|
||||||
setWrongPassword(true);
|
setWrongPassword(true);
|
||||||
} else {
|
} else {
|
||||||
setIdentity(identity);
|
setIdentity(identity);
|
||||||
|
state[1](UserCreationState.NotCreating);
|
||||||
}
|
}
|
||||||
}, [encryptedIdentity, password]);
|
}, [encryptedIdentity, password]);
|
||||||
|
|
||||||
|
@ -42,6 +47,7 @@ export function IdentityLoader({ setIdentity }: IdentityLoaderProps) {
|
||||||
const identity = Identity.generate();
|
const identity = Identity.generate();
|
||||||
await saveIdentity(identity, password);
|
await saveIdentity(identity, password);
|
||||||
setIdentity(identity);
|
setIdentity(identity);
|
||||||
|
state[1](UserCreationState.NotCreating);
|
||||||
}, [encryptedIdentity, password]);
|
}, [encryptedIdentity, password]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -0,0 +1,148 @@
|
||||||
|
import React from "react";
|
||||||
|
import styled from "styled-components";
|
||||||
|
|
||||||
|
type ColorChatSvgProps = {
|
||||||
|
width: number;
|
||||||
|
height: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function ColorChatSvg({ width, height }: ColorChatSvgProps) {
|
||||||
|
return (
|
||||||
|
<svg
|
||||||
|
width={width}
|
||||||
|
height={height}
|
||||||
|
viewBox="0 0 64 64"
|
||||||
|
fill="none"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<g clip-path="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)"
|
||||||
|
/>
|
||||||
|
<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(#paint1_linear_1307_429352)"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M26.6372 1.23773C12.4005 1.02023 0.780669 12.2253 0.50492 26.4611C0.464545 28.5509 0.67342 30.5856 1.10392 32.5368C1.83267 35.8408 2.26592 39.2032 2.26592 42.5868V49.127C2.26592 50.129 3.07816 50.9414 4.08029 50.9414H10.6205C14.004 50.9414 17.3664 51.3746 20.6705 52.1034C22.6218 52.5338 24.6562 52.7428 26.7461 52.7023C40.9816 52.4266 52.1867 40.8072 51.9697 26.5707C51.7577 12.6748 40.533 1.44986 26.6372 1.23773Z"
|
||||||
|
fill="url(#paint2_linear_1307_429352)"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M17.0238 25.5916C16.2968 24.8191 15.2678 24.334 14.1231 24.334C11.9215 24.334 10.1367 26.1187 10.1367 28.3204C10.1367 29.465 10.6217 30.494 11.3943 31.2211L19.9936 39.8203C20.7207 40.5928 21.7497 41.0779 22.8943 41.0779C25.0959 41.0779 26.8807 39.2932 26.8807 37.0916C26.8807 35.947 26.3956 34.918 25.6231 34.1908L17.0238 25.5916Z"
|
||||||
|
fill="url(#paint3_linear_1307_429352)"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M14.1231 32.3075C16.3247 32.3075 18.1095 30.5227 18.1095 28.3211C18.1095 26.1195 16.3247 24.3347 14.1231 24.3347C11.9215 24.3347 10.1367 26.1195 10.1367 28.3211C10.1367 30.5227 11.9215 32.3075 14.1231 32.3075Z"
|
||||||
|
fill="white"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M28.2973 25.5916C27.5703 24.8191 26.5413 24.334 25.3965 24.334C23.1949 24.334 21.4102 26.1187 21.4102 28.3204C21.4102 29.465 21.8952 30.494 22.6678 31.2211L31.267 39.8203C31.9941 40.5928 33.0231 41.0779 34.1678 41.0779C36.3694 41.0779 38.1541 39.2932 38.1541 37.0916C38.1541 35.947 37.669 34.918 36.8965 34.1908L28.2973 25.5916Z"
|
||||||
|
fill="url(#paint4_linear_1307_429352)"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M25.3975 32.3075C27.5991 32.3075 29.3839 30.5227 29.3839 28.3211C29.3839 26.1195 27.5991 24.3347 25.3975 24.3347C23.1959 24.3347 21.4111 26.1195 21.4111 28.3211C21.4111 30.5227 23.1959 32.3075 25.3975 32.3075Z"
|
||||||
|
fill="white"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M39.5717 25.5916C38.8447 24.8191 37.8157 24.334 36.6709 24.334C34.4693 24.334 32.6846 26.1187 32.6846 28.3204C32.6846 29.465 33.1697 30.494 33.9422 31.2211L42.5414 39.8203C43.2686 40.5928 44.2976 41.0779 45.4422 41.0779C47.6438 41.0779 49.4285 39.2932 49.4285 37.0916C49.4285 35.947 48.9434 34.918 48.1709 34.1908L39.5717 25.5916Z"
|
||||||
|
fill="url(#paint5_linear_1307_429352)"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M36.6719 32.3075C38.8735 32.3075 40.6583 30.5227 40.6583 28.3211C40.6583 26.1195 38.8735 24.3347 36.6719 24.3347C34.4703 24.3347 32.6855 26.1195 32.6855 28.3211C32.6855 30.5227 34.4703 32.3075 36.6719 32.3075Z"
|
||||||
|
fill="white"
|
||||||
|
/>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<linearGradient
|
||||||
|
id="paint0_linear_1307_429352"
|
||||||
|
x1="39.1099"
|
||||||
|
y1="37.3761"
|
||||||
|
x2="70.1253"
|
||||||
|
y2="68.3915"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
>
|
||||||
|
<stop stop-color="#A7F3CE" />
|
||||||
|
<stop offset="1" stop-color="#61DB99" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
id="paint1_linear_1307_429352"
|
||||||
|
x1="49.2627"
|
||||||
|
y1="47.5284"
|
||||||
|
x2="36.0891"
|
||||||
|
y2="34.356"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
>
|
||||||
|
<stop stop-color="#61DB99" stop-opacity="0" />
|
||||||
|
<stop offset="1" stop-color="#009E74" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
id="paint2_linear_1307_429352"
|
||||||
|
x1="16.8336"
|
||||||
|
y1="22.8102"
|
||||||
|
x2="49.5796"
|
||||||
|
y2="55.5561"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
>
|
||||||
|
<stop stop-color="#62E1FB" />
|
||||||
|
<stop offset="1" stop-color="#00A2F3" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
id="paint3_linear_1307_429352"
|
||||||
|
x1="22.9908"
|
||||||
|
y1="37.1889"
|
||||||
|
x2="5.74961"
|
||||||
|
y2="19.9482"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
>
|
||||||
|
<stop stop-color="#00A2F3" stop-opacity="0" />
|
||||||
|
<stop offset="1" stop-color="#0075CD" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
id="paint4_linear_1307_429352"
|
||||||
|
x1="34.2635"
|
||||||
|
y1="37.1884"
|
||||||
|
x2="17.0228"
|
||||||
|
y2="19.9478"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
>
|
||||||
|
<stop stop-color="#00A2F3" stop-opacity="0" />
|
||||||
|
<stop offset="1" stop-color="#2A353D" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
id="paint5_linear_1307_429352"
|
||||||
|
x1="45.5379"
|
||||||
|
y1="37.1886"
|
||||||
|
x2="28.2972"
|
||||||
|
y2="19.9479"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
>
|
||||||
|
<stop stop-color="#00A2F3" stop-opacity="0" />
|
||||||
|
<stop offset="1" stop-color="#0075CD" />
|
||||||
|
</linearGradient>
|
||||||
|
<clipPath id="clip0_1307_429352">
|
||||||
|
<rect
|
||||||
|
width="64"
|
||||||
|
height="64"
|
||||||
|
fill="white"
|
||||||
|
transform="translate(0.5)"
|
||||||
|
/>
|
||||||
|
</clipPath>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ColorChatIcon = () => {
|
||||||
|
return <Icon width={64} height={64} />;
|
||||||
|
};
|
||||||
|
|
||||||
|
const Icon = styled(ColorChatSvg)`
|
||||||
|
& > path {
|
||||||
|
fill: ${({ theme }) => theme.tertiary};
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover > path {
|
||||||
|
fill: ${({ theme }) => theme.bodyBackgroundColor};
|
||||||
|
}
|
||||||
|
`;
|
|
@ -28,7 +28,7 @@ export function Member({
|
||||||
switchShowMembers?.();
|
switchShowMembers?.();
|
||||||
setChannel({
|
setChannel({
|
||||||
id: contact.id,
|
id: contact.id,
|
||||||
name: contact.customName ?? contact.trueName,
|
name: contact?.customName ?? contact.trueName,
|
||||||
type: "dm",
|
type: "dm",
|
||||||
description: "Contact",
|
description: "Contact",
|
||||||
members: [contact],
|
members: [contact],
|
||||||
|
@ -47,7 +47,7 @@ export function Member({
|
||||||
{showMenu && <ContactMenu id={contact.id} setShowMenu={setShowMenu} />}
|
{showMenu && <ContactMenu id={contact.id} setShowMenu={setShowMenu} />}
|
||||||
<UserIcon memberView={true} />
|
<UserIcon memberView={true} />
|
||||||
</MemberIcon>
|
</MemberIcon>
|
||||||
<MemberName>{contact.customName ?? contact.id}</MemberName>
|
<MemberName>{contact?.customName ?? contact.id}</MemberName>
|
||||||
</MemberData>
|
</MemberData>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,13 +16,15 @@ interface MembersListProps {
|
||||||
export function MembersList({ switchShowMembers }: MembersListProps) {
|
export function MembersList({ switchShowMembers }: MembersListProps) {
|
||||||
const { contacts } = useMessengerContext();
|
const { contacts } = useMessengerContext();
|
||||||
const identity = useIdentity();
|
const identity = useIdentity();
|
||||||
const userContacts = useMemo(
|
const userContacts = useMemo(() => {
|
||||||
() =>
|
if (identity) {
|
||||||
Object.values(contacts).filter(
|
return Object.values(contacts).filter(
|
||||||
(e) => e.id != bufToHex(identity.publicKey)
|
(e) => e.id != bufToHex(identity.publicKey)
|
||||||
),
|
);
|
||||||
[contacts, identity]
|
} else {
|
||||||
);
|
return Object.values(contacts);
|
||||||
|
}
|
||||||
|
}, [contacts, identity]);
|
||||||
const onlineContacts = useMemo(
|
const onlineContacts = useMemo(
|
||||||
() => userContacts.filter((e) => e.online),
|
() => userContacts.filter((e) => e.online),
|
||||||
[userContacts]
|
[userContacts]
|
||||||
|
@ -40,7 +42,9 @@ export function MembersList({ switchShowMembers }: MembersListProps) {
|
||||||
<MemberIcon>
|
<MemberIcon>
|
||||||
<UserIcon memberView={true} />
|
<UserIcon memberView={true} />
|
||||||
</MemberIcon>
|
</MemberIcon>
|
||||||
<MemberName>{utils.bufToHex(identity.publicKey)}</MemberName>
|
{identity && (
|
||||||
|
<MemberName>{utils.bufToHex(identity.publicKey)}</MemberName>
|
||||||
|
)}
|
||||||
</MemberData>
|
</MemberData>
|
||||||
</MemberCategory>
|
</MemberCategory>
|
||||||
{onlineContacts.length > 0 && (
|
{onlineContacts.length > 0 && (
|
||||||
|
|
|
@ -77,7 +77,11 @@ export function UiMessage({
|
||||||
channel: channel,
|
channel: channel,
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
if (quote && quote.sender === utils.bufToHex(identity.publicKey))
|
if (
|
||||||
|
quote &&
|
||||||
|
identity &&
|
||||||
|
quote.sender === utils.bufToHex(identity.publicKey)
|
||||||
|
)
|
||||||
setActivities((prev) => [
|
setActivities((prev) => [
|
||||||
...prev,
|
...prev,
|
||||||
{
|
{
|
||||||
|
@ -119,9 +123,9 @@ export function UiMessage({
|
||||||
<UserNameWrapper>
|
<UserNameWrapper>
|
||||||
<UserName>
|
<UserName>
|
||||||
{" "}
|
{" "}
|
||||||
{contact.customName ?? message.sender.slice(0, 10)}
|
{contact?.customName ?? message.sender.slice(0, 10)}
|
||||||
</UserName>
|
</UserName>
|
||||||
{contact.customName && (
|
{contact?.customName && (
|
||||||
<UserAddress>
|
<UserAddress>
|
||||||
{message.sender.slice(0, 5)}...{message.sender.slice(-3)}
|
{message.sender.slice(0, 5)}...{message.sender.slice(-3)}
|
||||||
</UserAddress>
|
</UserAddress>
|
||||||
|
|
|
@ -47,10 +47,13 @@ export const ProfileModal = () => {
|
||||||
const { setModal } = useModal(ProfileModalName);
|
const { setModal } = useModal(ProfileModalName);
|
||||||
|
|
||||||
const identity = useIdentity();
|
const identity = useIdentity();
|
||||||
const isUser = useMemo(
|
const isUser = useMemo(() => {
|
||||||
() => id === bufToHex(identity.publicKey),
|
if (identity) {
|
||||||
[id, identity]
|
return id === bufToHex(identity.publicKey);
|
||||||
);
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}, [id, identity]);
|
||||||
|
|
||||||
const [renaming, setRenaming] = useState(renamingState ?? false);
|
const [renaming, setRenaming] = useState(renamingState ?? false);
|
||||||
|
|
||||||
|
@ -98,7 +101,7 @@ export const ProfileModal = () => {
|
||||||
)}
|
)}
|
||||||
<UserNameWrapper>
|
<UserNameWrapper>
|
||||||
<UserName className={`${requestCreation && "small"}`}>
|
<UserName className={`${requestCreation && "small"}`}>
|
||||||
{contact.customName ?? id.slice(0, 10)}
|
{contact?.customName ?? id.slice(0, 10)}
|
||||||
</UserName>
|
</UserName>
|
||||||
{contact.isUntrustworthy && <UntrustworthIcon />}
|
{contact.isUntrustworthy && <UntrustworthIcon />}
|
||||||
{!renaming && (
|
{!renaming && (
|
||||||
|
@ -108,7 +111,7 @@ export const ProfileModal = () => {
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
</UserNameWrapper>
|
</UserNameWrapper>
|
||||||
{contact.customName && (
|
{contact?.customName && (
|
||||||
<UserTrueName>{contact.trueName}</UserTrueName>
|
<UserTrueName>{contact.trueName}</UserTrueName>
|
||||||
)}
|
)}
|
||||||
</NameSection>
|
</NameSection>
|
||||||
|
|
|
@ -7,6 +7,7 @@ import { FetchMetadataProvider } from "../contexts/fetchMetadataProvider";
|
||||||
import { ModalProvider } from "../contexts/modalProvider";
|
import { ModalProvider } from "../contexts/modalProvider";
|
||||||
import { NarrowProvider } from "../contexts/narrowProvider";
|
import { NarrowProvider } from "../contexts/narrowProvider";
|
||||||
import { ToastProvider } from "../contexts/toastProvider";
|
import { ToastProvider } from "../contexts/toastProvider";
|
||||||
|
import { UserCreationStateProvider } from "../contexts/userCreationStateProvider";
|
||||||
import { Metadata } from "../models/Metadata";
|
import { Metadata } from "../models/Metadata";
|
||||||
import { GlobalStyle } from "../styles/GlobalStyle";
|
import { GlobalStyle } from "../styles/GlobalStyle";
|
||||||
import { Theme } from "../styles/themes";
|
import { Theme } from "../styles/themes";
|
||||||
|
@ -31,13 +32,15 @@ export function ReactChat({
|
||||||
<FetchMetadataProvider fetchMetadata={fetchMetadata}>
|
<FetchMetadataProvider fetchMetadata={fetchMetadata}>
|
||||||
<ModalProvider>
|
<ModalProvider>
|
||||||
<ActivityProvider>
|
<ActivityProvider>
|
||||||
<ToastProvider>
|
<UserCreationStateProvider>
|
||||||
<Wrapper ref={ref}>
|
<ToastProvider>
|
||||||
<GlobalStyle />
|
<Wrapper ref={ref}>
|
||||||
<ChatLoader communityKey={communityKey} />
|
<GlobalStyle />
|
||||||
<div id="modal-root" />
|
<ChatLoader communityKey={communityKey} />
|
||||||
</Wrapper>
|
<div id="modal-root" />
|
||||||
</ToastProvider>
|
</Wrapper>
|
||||||
|
</ToastProvider>
|
||||||
|
</UserCreationStateProvider>
|
||||||
</ActivityProvider>
|
</ActivityProvider>
|
||||||
</ModalProvider>
|
</ModalProvider>
|
||||||
</FetchMetadataProvider>
|
</FetchMetadataProvider>
|
||||||
|
|
|
@ -0,0 +1,68 @@
|
||||||
|
import React from "react";
|
||||||
|
import styled from "styled-components";
|
||||||
|
|
||||||
|
import {
|
||||||
|
UserCreationState,
|
||||||
|
useUserCreationState,
|
||||||
|
} from "../../contexts/userCreationStateProvider";
|
||||||
|
import { ColorChatIcon } from "../Icons/ColorChatIcon";
|
||||||
|
|
||||||
|
export function UserCreation() {
|
||||||
|
const state = useUserCreationState();
|
||||||
|
return (
|
||||||
|
<Background>
|
||||||
|
<Wrapper>
|
||||||
|
<IconWrapper>
|
||||||
|
<ColorChatIcon />
|
||||||
|
</IconWrapper>
|
||||||
|
<TitleWrapper>Want in on the discussion ?</TitleWrapper>
|
||||||
|
<ThrowAwayButton onClick={() => state[1](UserCreationState.Creating)}>
|
||||||
|
Use a throwaway account
|
||||||
|
</ThrowAwayButton>
|
||||||
|
</Wrapper>
|
||||||
|
</Background>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const ThrowAwayButton = styled.button`
|
||||||
|
font-family: Inter;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 13px;
|
||||||
|
line-height: 18px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
text-align: center;
|
||||||
|
color: #4360df;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const IconWrapper = styled.div`
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const TitleWrapper = styled.div`
|
||||||
|
font-family: Inter;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 17px;
|
||||||
|
line-height: 24px;
|
||||||
|
text-align: center;
|
||||||
|
margin-top: 25px;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const Wrapper = styled.div`
|
||||||
|
margin: auto;
|
||||||
|
align-items: center;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const Background = styled.div`
|
||||||
|
background: #f6f8fa;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
height: 100%;
|
||||||
|
`;
|
|
@ -1,7 +1,7 @@
|
||||||
import React, { createContext, useContext } from "react";
|
import React, { createContext, useContext } from "react";
|
||||||
import { Identity } from "status-communities/dist/cjs";
|
import { Identity } from "status-communities/dist/cjs";
|
||||||
|
|
||||||
const IdentityContext = createContext(new Identity(new Uint8Array()));
|
const IdentityContext = createContext<Identity | undefined>(undefined);
|
||||||
|
|
||||||
export function useIdentity() {
|
export function useIdentity() {
|
||||||
return useContext(IdentityContext);
|
return useContext(IdentityContext);
|
||||||
|
@ -9,7 +9,7 @@ export function useIdentity() {
|
||||||
|
|
||||||
interface IdentityProviderProps {
|
interface IdentityProviderProps {
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
identity: Identity;
|
identity: Identity | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function IdentityProvider({
|
export function IdentityProvider({
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
import React, { createContext, useContext, useState } from "react";
|
||||||
|
|
||||||
|
export enum UserCreationState {
|
||||||
|
Creating,
|
||||||
|
NotCreating,
|
||||||
|
}
|
||||||
|
|
||||||
|
type UserCreationContextType = [
|
||||||
|
UserCreationState,
|
||||||
|
React.Dispatch<React.SetStateAction<UserCreationState>>
|
||||||
|
];
|
||||||
|
|
||||||
|
const ChatStateContext = createContext<UserCreationContextType>([
|
||||||
|
UserCreationState.NotCreating,
|
||||||
|
() => undefined,
|
||||||
|
]);
|
||||||
|
|
||||||
|
export function useUserCreationState() {
|
||||||
|
return useContext(ChatStateContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function UserCreationStateProvider({
|
||||||
|
children,
|
||||||
|
}: {
|
||||||
|
children: React.ReactNode;
|
||||||
|
}) {
|
||||||
|
const state = useState(UserCreationState.NotCreating);
|
||||||
|
return <ChatStateContext.Provider value={state} children={children} />;
|
||||||
|
}
|
|
@ -16,7 +16,7 @@ export function useContacts(
|
||||||
}>({});
|
}>({});
|
||||||
|
|
||||||
const contactsClass = useMemo(() => {
|
const contactsClass = useMemo(() => {
|
||||||
if (messenger && identity) {
|
if (messenger) {
|
||||||
const newContacts = new ContactsClass(
|
const newContacts = new ContactsClass(
|
||||||
identity,
|
identity,
|
||||||
messenger.waku,
|
messenger.waku,
|
||||||
|
|
|
@ -12,6 +12,16 @@ import { ChatMessage } from "../../models/ChatMessage";
|
||||||
import { Contact } from "../../models/Contact";
|
import { Contact } from "../../models/Contact";
|
||||||
import { uintToImgUrl } from "../../utils";
|
import { uintToImgUrl } from "../../utils";
|
||||||
|
|
||||||
|
const contactFromId = (member: string): Contact => {
|
||||||
|
return {
|
||||||
|
blocked: false,
|
||||||
|
id: member,
|
||||||
|
isUntrustworthy: false,
|
||||||
|
online: false,
|
||||||
|
trueName: member,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
export function useGroupChats(
|
export function useGroupChats(
|
||||||
messenger: Messenger | undefined,
|
messenger: Messenger | undefined,
|
||||||
identity: Identity | undefined,
|
identity: Identity | undefined,
|
||||||
|
@ -23,15 +33,6 @@ export function useGroupChats(
|
||||||
const groupChat = useMemo(() => {
|
const groupChat = useMemo(() => {
|
||||||
if (messenger && identity) {
|
if (messenger && identity) {
|
||||||
const addChat = (chat: GroupChat) => {
|
const addChat = (chat: GroupChat) => {
|
||||||
const contactFromId = (member: string): Contact => {
|
|
||||||
return {
|
|
||||||
blocked: false,
|
|
||||||
id: member,
|
|
||||||
isUntrustworthy: false,
|
|
||||||
online: false,
|
|
||||||
trueName: member,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
const members = chat.members.map(contactFromId);
|
const members = chat.members.map(contactFromId);
|
||||||
const channel: ChannelData = {
|
const channel: ChannelData = {
|
||||||
id: chat.chatId,
|
id: chat.chatId,
|
||||||
|
|
|
@ -51,11 +51,9 @@ export type MessengerType = {
|
||||||
function useCreateMessenger(identity: Identity | undefined) {
|
function useCreateMessenger(identity: Identity | undefined) {
|
||||||
const [messenger, setMessenger] = useState<Messenger | undefined>(undefined);
|
const [messenger, setMessenger] = useState<Messenger | undefined>(undefined);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (identity) {
|
createMessenger(identity).then((e) => {
|
||||||
createMessenger(identity).then((e) => {
|
setMessenger(e);
|
||||||
setMessenger(e);
|
});
|
||||||
});
|
|
||||||
}
|
|
||||||
}, [identity]);
|
}, [identity]);
|
||||||
return messenger;
|
return messenger;
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@ const WAKU_OPTIONS = {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export async function createMessenger(identity: Identity) {
|
export async function createMessenger(identity: Identity | undefined) {
|
||||||
const messenger = await Messenger.create(identity, WAKU_OPTIONS);
|
const messenger = await Messenger.create(identity, WAKU_OPTIONS);
|
||||||
await new Promise((resolve) => {
|
await new Promise((resolve) => {
|
||||||
messenger.waku.libp2p.peerStore.on("change:protocols", ({ protocols }) => {
|
messenger.waku.libp2p.peerStore.on("change:protocols", ({ protocols }) => {
|
||||||
|
|
|
@ -10,7 +10,7 @@ const STATUS_BROADCAST_INTERVAL = 30000;
|
||||||
|
|
||||||
export class Contacts {
|
export class Contacts {
|
||||||
waku: Waku;
|
waku: Waku;
|
||||||
identity: Identity;
|
identity: Identity | undefined;
|
||||||
private callback: (publicKey: string, clock: number) => void;
|
private callback: (publicKey: string, clock: number) => void;
|
||||||
private contacts: string[] = [];
|
private contacts: string[] = [];
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ export class Contacts {
|
||||||
* @param callback callback function called when user status broadcast is received
|
* @param callback callback function called when user status broadcast is received
|
||||||
*/
|
*/
|
||||||
public constructor(
|
public constructor(
|
||||||
identity: Identity,
|
identity: Identity | undefined,
|
||||||
waku: Waku,
|
waku: Waku,
|
||||||
callback: (publicKey: string, clock: number) => void
|
callback: (publicKey: string, clock: number) => void
|
||||||
) {
|
) {
|
||||||
|
@ -36,7 +36,9 @@ export class Contacts {
|
||||||
this.identity = identity;
|
this.identity = identity;
|
||||||
this.callback = callback;
|
this.callback = callback;
|
||||||
this.startBroadcast();
|
this.startBroadcast();
|
||||||
this.addContact(bufToHex(identity.publicKey));
|
if (identity) {
|
||||||
|
this.addContact(bufToHex(identity.publicKey));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -70,15 +72,17 @@ export class Contacts {
|
||||||
|
|
||||||
private startBroadcast(): void {
|
private startBroadcast(): void {
|
||||||
const send = async (): Promise<void> => {
|
const send = async (): Promise<void> => {
|
||||||
const statusUpdate = StatusUpdate.create(
|
if (this.identity) {
|
||||||
StatusUpdate_StatusType.AUTOMATIC,
|
const statusUpdate = StatusUpdate.create(
|
||||||
""
|
StatusUpdate_StatusType.AUTOMATIC,
|
||||||
);
|
""
|
||||||
const msg = await WakuMessage.fromBytes(
|
);
|
||||||
statusUpdate.encode(),
|
const msg = await WakuMessage.fromBytes(
|
||||||
idToContactCodeTopic(bufToHex(this.identity.publicKey))
|
statusUpdate.encode(),
|
||||||
);
|
idToContactCodeTopic(bufToHex(this.identity.publicKey))
|
||||||
this.waku.relay.send(msg);
|
);
|
||||||
|
this.waku.relay.send(msg);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
send();
|
send();
|
||||||
setInterval(send, STATUS_BROADCAST_INTERVAL);
|
setInterval(send, STATUS_BROADCAST_INTERVAL);
|
||||||
|
|
|
@ -22,9 +22,9 @@ export class Messenger {
|
||||||
) => void
|
) => void
|
||||||
>;
|
>;
|
||||||
};
|
};
|
||||||
identity: Identity;
|
identity: Identity | undefined;
|
||||||
|
|
||||||
private constructor(identity: Identity, waku: Waku) {
|
private constructor(identity: Identity | undefined, waku: Waku) {
|
||||||
this.identity = identity;
|
this.identity = identity;
|
||||||
this.waku = waku;
|
this.waku = waku;
|
||||||
this.chatsById = new Map();
|
this.chatsById = new Map();
|
||||||
|
@ -32,7 +32,7 @@ export class Messenger {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async create(
|
public static async create(
|
||||||
identity: Identity,
|
identity: Identity | undefined,
|
||||||
wakuOptions?: WakuCreateOptions
|
wakuOptions?: WakuCreateOptions
|
||||||
): Promise<Messenger> {
|
): Promise<Messenger> {
|
||||||
const _wakuOptions = Object.assign({ bootstrap: true }, wakuOptions);
|
const _wakuOptions = Object.assign({ bootstrap: true }, wakuOptions);
|
||||||
|
@ -105,24 +105,26 @@ export class Messenger {
|
||||||
content: Content,
|
content: Content,
|
||||||
responseTo?: string
|
responseTo?: string
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const chat = this.chatsById.get(chatId);
|
if (this.identity) {
|
||||||
if (!chat) throw `Failed to send message, chat not joined: ${chatId}`;
|
const chat = this.chatsById.get(chatId);
|
||||||
|
if (!chat) throw `Failed to send message, chat not joined: ${chatId}`;
|
||||||
|
|
||||||
const chatMessage = chat.createMessage(content, responseTo);
|
const chatMessage = chat.createMessage(content, responseTo);
|
||||||
|
|
||||||
const appMetadataMessage = ApplicationMetadataMessage.create(
|
const appMetadataMessage = ApplicationMetadataMessage.create(
|
||||||
chatMessage.encode(),
|
chatMessage.encode(),
|
||||||
ApplicationMetadataMessage_Type.TYPE_CHAT_MESSAGE,
|
ApplicationMetadataMessage_Type.TYPE_CHAT_MESSAGE,
|
||||||
this.identity
|
this.identity
|
||||||
);
|
);
|
||||||
|
|
||||||
const wakuMessage = await WakuMessage.fromBytes(
|
const wakuMessage = await WakuMessage.fromBytes(
|
||||||
appMetadataMessage.encode(),
|
appMetadataMessage.encode(),
|
||||||
chat.contentTopic,
|
chat.contentTopic,
|
||||||
{ symKey: chat.symKey, sigPrivKey: this.identity.privateKey }
|
{ symKey: chat.symKey, sigPrivKey: this.identity.privateKey }
|
||||||
);
|
);
|
||||||
|
|
||||||
await this.waku.relay.send(wakuMessage);
|
await this.waku.relay.send(wakuMessage);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in New Issue