Improve Prettier monorepo configuration (#225)

* Add prettier configuration files

* Move prettier command to monorepo root

* Format all files
This commit is contained in:
Pavel 2022-02-23 15:49:00 +01:00 committed by GitHub
parent 5ed925c02d
commit 2a2c356807
No known key found for this signature in database
GPG Key ID: 0EB8D75C775AB6F1
222 changed files with 6443 additions and 9709 deletions

5
.prettierignore Normal file
View File

@ -0,0 +1,5 @@
**/dist
**/node_modules
.parcel-cache
.github
.vscode

5
.prettierrc Normal file
View File

@ -0,0 +1,5 @@
{
"semi": false,
"singleQuote": true,
"arrowParens": "avoid"
}

View File

@ -1 +1 @@
# Status Communities for the Web
# Status Communities for the Web

View File

@ -1,6 +1,6 @@
import React, { render } from 'react-dom';
import { GroupChat, lightTheme } from '@status-im/react';
import { StrictMode } from 'react';
import React, { render } from 'react-dom'
import { GroupChat, lightTheme } from '@status-im/react'
import { StrictMode } from 'react'
const App = () => {
return (
@ -14,12 +14,12 @@ const App = () => {
}}
/>
</div>
);
};
)
}
render(
<StrictMode>
<App />
</StrictMode>,
document.getElementById('root')
);
)

View File

@ -1,6 +1,6 @@
import React, { render } from 'react-dom';
import { CommunityChat, lightTheme } from '@status-im/react';
import { StrictMode } from 'react';
import React, { render } from 'react-dom'
import { CommunityChat, lightTheme } from '@status-im/react'
import { StrictMode } from 'react'
const App = () => {
return (
@ -14,12 +14,12 @@ const App = () => {
}}
/>
</div>
);
};
)
}
render(
<StrictMode>
<App />
</StrictMode>,
document.getElementById('root')
);
)

View File

@ -7,13 +7,13 @@
"keywords": [],
"scripts": {
"fix": "run-s 'fix:*' && wsrun -e -c -s fix",
"fix:prettier": "prettier \"./*.json\" --write",
"build": "wsrun -e -c -s build",
"format": "prettier --write .",
"test": "wsrun -e -c -s test"
},
"devDependencies": {
"npm-run-all": "^4.1.5",
"prettier": "^2.3.2",
"prettier": "^2.5.1",
"wsrun": "^5.2.4"
},
"packageManager": "yarn@1.22.17"

View File

@ -18,11 +18,9 @@
"build:esm": "tsc --module es2020 --target es2017 --outDir dist/esm",
"build:cjs": "tsc --outDir dist/cjs",
"fix": "run-s 'fix:*'",
"fix:prettier": "prettier \"src/**/*.ts\" \"./*.json\" --write",
"fix:lint": "eslint src --ext .ts --fix",
"test": "run-s 'test:*'",
"test:lint": "eslint src --ext .ts",
"test:prettier": "prettier \"src/**/*.ts\" \"./*.json\" --list-different",
"test:unit": "mocha",
"proto": "run-s 'proto:*'",
"proto:lint": "buf lint",
@ -47,7 +45,6 @@
"eslint-plugin-import": "^2.24.2",
"mocha": "^9.1.1",
"npm-run-all": "^4.1.5",
"prettier": "^2.4.0",
"ts-node": "^10.2.1",
"ts-proto": "^1.83.0",
"typescript": "^4.4.3"

View File

@ -1,14 +1,14 @@
import { idToContentTopic } from "./contentTopic";
import { createSymKeyFromPassword } from "./encryption";
import { ChatMessage, Content } from "./wire/chat_message";
import { CommunityChat } from "./wire/community_chat";
import { idToContentTopic } from './contentTopic'
import { createSymKeyFromPassword } from './encryption'
import { ChatMessage, Content } from './wire/chat_message'
import { CommunityChat } from './wire/community_chat'
/**
* Represent a chat room. Only public chats are currently supported.
*/
export class Chat {
private lastClockValue?: number;
private lastMessage?: ChatMessage;
private lastClockValue?: number
private lastMessage?: ChatMessage
private constructor(
public id: string,
@ -24,17 +24,17 @@ export class Chat {
id: string,
communityChat?: CommunityChat
): Promise<Chat> {
const symKey = await createSymKeyFromPassword(id);
const symKey = await createSymKeyFromPassword(id)
return new Chat(id, symKey, communityChat);
return new Chat(id, symKey, communityChat)
}
public get contentTopic(): string {
return idToContentTopic(this.id);
return idToContentTopic(this.id)
}
public createMessage(content: Content, responseTo?: string): ChatMessage {
const { timestamp, clock } = this._nextClockAndTimestamp();
const { timestamp, clock } = this._nextClockAndTimestamp()
const message = ChatMessage.createMessage(
clock,
@ -42,28 +42,28 @@ export class Chat {
this.id,
content,
responseTo
);
)
this._updateClockFromMessage(message);
this._updateClockFromMessage(message)
return message;
return message
}
public handleNewMessage(message: ChatMessage): void {
this._updateClockFromMessage(message);
this._updateClockFromMessage(message)
}
private _nextClockAndTimestamp(): { clock: number; timestamp: number } {
let clock = this.lastClockValue;
const timestamp = Date.now();
let clock = this.lastClockValue
const timestamp = Date.now()
if (!clock || clock < timestamp) {
clock = timestamp;
clock = timestamp
} else {
clock += 1;
clock += 1
}
return { clock, timestamp };
return { clock, timestamp }
}
private _updateClockFromMessage(message: ChatMessage): void {
@ -72,14 +72,14 @@ export class Chat {
!this.lastMessage.clock ||
(message.clock && this.lastMessage.clock <= message.clock)
) {
this.lastMessage = message;
this.lastMessage = message
}
if (
!this.lastClockValue ||
(message.clock && this.lastClockValue < message.clock)
) {
this.lastClockValue = message.clock;
this.lastClockValue = message.clock
}
}
}

View File

@ -1,42 +1,42 @@
import { expect } from "chai";
import { Waku } from "js-waku";
import { expect } from 'chai'
import { Waku } from 'js-waku'
import { Community } from "./community";
import { CommunityDescription } from "./wire/community_description";
import { Community } from './community'
import { CommunityDescription } from './wire/community_description'
describe("Community [live data]", () => {
describe('Community [live data]', () => {
before(function () {
if (process.env.CI) {
// Skip live data test in CI
this.skip();
this.skip()
}
});
})
it("Retrieves community description For DappConnect Test from Waku prod fleet", async function () {
this.timeout(20000);
const waku = await Waku.create({ bootstrap: { default: true } });
it('Retrieves community description For DappConnect Test from Waku prod fleet', async function () {
this.timeout(20000)
const waku = await Waku.create({ bootstrap: { default: true } })
await waku.waitForRemotePeer();
await waku.waitForRemotePeer()
const community = await Community.instantiateCommunity(
"0x02cf13719c8b836bebd4e430c497ee38e798a43e4d8c4760c34bbd9bf4f2434d26",
'0x02cf13719c8b836bebd4e430c497ee38e798a43e4d8c4760c34bbd9bf4f2434d26',
waku
);
const desc = community.description as CommunityDescription;
expect(desc).to.not.be.undefined;
)
const desc = community.description as CommunityDescription
expect(desc).to.not.be.undefined
expect(desc.identity?.displayName).to.eq("Test Community");
expect(desc.identity?.displayName).to.eq('Test Community')
const descChats = Array.from(desc.chats.values()).map(
(chat) => chat?.identity?.displayName
);
expect(descChats).to.include("Test Chat");
expect(descChats).to.include("Additional Chat");
chat => chat?.identity?.displayName
)
expect(descChats).to.include('Test Chat')
expect(descChats).to.include('Additional Chat')
const chats = Array.from(community.chats.values()).map(
(chat) => chat?.communityChat?.identity?.displayName
);
expect(chats).to.include("Test Chat");
expect(chats).to.include("Additional Chat");
});
});
chat => chat?.communityChat?.identity?.displayName
)
expect(chats).to.include('Test Chat')
expect(chats).to.include('Additional Chat')
})
})

View File

@ -1,23 +1,23 @@
import debug from "debug";
import { Waku } from "js-waku";
import debug from 'debug'
import { Waku } from 'js-waku'
import { Chat } from "./chat";
import { bufToHex, hexToBuf } from "./utils";
import { CommunityChat } from "./wire/community_chat";
import { CommunityDescription } from "./wire/community_description";
import { Chat } from './chat'
import { bufToHex, hexToBuf } from './utils'
import { CommunityChat } from './wire/community_chat'
import { CommunityDescription } from './wire/community_description'
const dbg = debug("communities:community");
const dbg = debug('communities:community')
export class Community {
public publicKey: Uint8Array;
private waku: Waku;
public chats: Map<string, Chat>; // Chat id, Chat
public description?: CommunityDescription;
public publicKey: Uint8Array
private waku: Waku
public chats: Map<string, Chat> // Chat id, Chat
public description?: CommunityDescription
constructor(publicKey: Uint8Array, waku: Waku) {
this.publicKey = publicKey;
this.waku = waku;
this.chats = new Map();
this.publicKey = publicKey
this.waku = waku
this.chats = new Map()
}
/**
@ -34,15 +34,15 @@ export class Community {
publicKey: string,
waku: Waku
): Promise<Community> {
const community = new Community(hexToBuf(publicKey), waku);
const community = new Community(hexToBuf(publicKey), waku)
await community.refreshCommunityDescription();
await community.refreshCommunityDescription()
return community;
return community
}
public get publicKeyStr(): string {
return bufToHex(this.publicKey);
return bufToHex(this.publicKey)
}
/**
@ -53,20 +53,20 @@ export class Community {
const desc = await CommunityDescription.retrieve(
this.publicKey,
this.waku.store
);
)
if (!desc) {
dbg(`Failed to retrieve Community Description for ${this.publicKeyStr}`);
return;
dbg(`Failed to retrieve Community Description for ${this.publicKeyStr}`)
return
}
this.description = desc;
this.description = desc
await Promise.all(
Array.from(this.description.chats).map(([chatUuid, communityChat]) => {
return this.instantiateChat(chatUuid, communityChat);
return this.instantiateChat(chatUuid, communityChat)
})
);
)
}
/**
@ -80,13 +80,13 @@ export class Community {
communityChat: CommunityChat
): Promise<void> {
if (!this.description)
throw "Failed to retrieve community description, cannot instantiate chat";
throw 'Failed to retrieve community description, cannot instantiate chat'
const chatId = this.publicKeyStr + chatUuid;
if (this.chats.get(chatId)) return;
const chatId = this.publicKeyStr + chatUuid
if (this.chats.get(chatId)) return
const chat = await Chat.create(chatId, communityChat);
const chat = await Chat.create(chatId, communityChat)
this.chats.set(chatId, chat);
this.chats.set(chatId, chat)
}
}

View File

@ -1,22 +1,22 @@
import { PageDirection, 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, getLatestUserNickname } from "./utils";
import { ChatIdentity } from "./wire/chat_identity";
import { StatusUpdate } from "./wire/status_update";
import { idToContactCodeTopic } from './contentTopic'
import { Identity } from './identity'
import { StatusUpdate_StatusType } from './proto/communities/v1/status_update'
import { bufToHex, getLatestUserNickname } from './utils'
import { ChatIdentity } from './wire/chat_identity'
import { StatusUpdate } from './wire/status_update'
const STATUS_BROADCAST_INTERVAL = 30000;
const NICKNAME_BROADCAST_INTERVAL = 300000;
const STATUS_BROADCAST_INTERVAL = 30000
const NICKNAME_BROADCAST_INTERVAL = 300000
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[] = [];
waku: Waku
identity: Identity | undefined
nickname?: string
private callback: (publicKey: string, clock: number) => void
private callbackNickname: (publicKey: string, nickname: string) => void
private contacts: string[] = []
/**
* Contacts holds a list of user contacts and listens to their status broadcast
@ -38,14 +38,14 @@ export class Contacts {
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();
this.waku = waku
this.identity = identity
this.nickname = nickname
this.callback = callback
this.callbackNickname = callbackNickname
this.startBroadcast()
if (identity) {
this.addContact(bufToHex(identity.publicKey));
this.addContact(bufToHex(identity.publicKey))
}
}
@ -57,44 +57,44 @@ export class Contacts {
* @param publicKey public key of user
*/
public addContact(publicKey: string): void {
if (!this.contacts.find((e) => publicKey === e)) {
const now = new Date();
if (!this.contacts.find(e => publicKey === e)) {
const now = new Date()
const callback = (wakuMessage: WakuMessage): void => {
if (wakuMessage.payload) {
const msg = StatusUpdate.decode(wakuMessage.payload);
this.callback(publicKey, msg.clock ?? 0);
const msg = StatusUpdate.decode(wakuMessage.payload)
this.callback(publicKey, msg.clock ?? 0)
}
};
this.contacts.push(publicKey);
this.callback(publicKey, 0);
}
this.contacts.push(publicKey)
this.callback(publicKey, 0)
this.waku.store.queryHistory([idToContactCodeTopic(publicKey)], {
callback: (msgs) => msgs.forEach((e) => callback(e)),
callback: msgs => msgs.forEach(e => callback(e)),
timeFilter: {
startTime: new Date(now.getTime() - STATUS_BROADCAST_INTERVAL * 2),
endTime: now,
},
});
})
this.waku.store.queryHistory([idToContactCodeTopic(publicKey)], {
callback: (msgs) =>
msgs.some((e) => {
callback: msgs =>
msgs.some(e => {
try {
if (e.payload) {
const chatIdentity = ChatIdentity.decode(e?.payload);
const chatIdentity = ChatIdentity.decode(e?.payload)
if (chatIdentity) {
this.callbackNickname(
publicKey,
chatIdentity?.displayName ?? ""
);
chatIdentity?.displayName ?? ''
)
}
return true;
return true
}
} catch {
return false;
return false
}
}),
pageDirection: PageDirection.BACKWARD,
});
this.waku.relay.addObserver(callback, [idToContactCodeTopic(publicKey)]);
})
this.waku.relay.addObserver(callback, [idToContactCodeTopic(publicKey)])
}
}
@ -103,67 +103,67 @@ export class Contacts {
if (this.identity) {
const statusUpdate = StatusUpdate.create(
StatusUpdate_StatusType.AUTOMATIC,
""
);
''
)
const msg = await WakuMessage.fromBytes(
statusUpdate.encode(),
idToContactCodeTopic(bufToHex(this.identity.publicKey))
);
this.waku.relay.send(msg);
)
this.waku.relay.send(msg)
}
};
}
const handleNickname = async (): Promise<void> => {
if (this.identity) {
const now = new Date().getTime();
const now = new Date().getTime()
const { clock, nickname: newNickname } = await getLatestUserNickname(
this.identity.publicKey,
this.waku
);
)
if (this.nickname) {
if (this.nickname !== newNickname) {
await sendNickname();
await sendNickname()
} else {
if (clock < now - NICKNAME_BROADCAST_INTERVAL) {
await sendNickname();
await sendNickname()
}
}
} else {
this.nickname = newNickname;
this.callbackNickname(bufToHex(this.identity.publicKey), newNickname);
this.nickname = newNickname
this.callbackNickname(bufToHex(this.identity.publicKey), newNickname)
if (clock < now - NICKNAME_BROADCAST_INTERVAL) {
await sendNickname();
await sendNickname()
}
}
}
setInterval(send, NICKNAME_BROADCAST_INTERVAL);
};
setInterval(send, NICKNAME_BROADCAST_INTERVAL)
}
const sendNickname = async (): Promise<void> => {
if (this.identity) {
const publicKey = bufToHex(this.identity.publicKey);
const publicKey = bufToHex(this.identity.publicKey)
if (this.nickname) {
const chatIdentity = new ChatIdentity({
clock: new Date().getTime(),
color: "",
description: "",
emoji: "",
color: '',
description: '',
emoji: '',
images: {},
ensName: "",
displayName: this?.nickname ?? "",
});
ensName: '',
displayName: this?.nickname ?? '',
})
const msg = await WakuMessage.fromBytes(
chatIdentity.encode(),
idToContactCodeTopic(publicKey),
{ sigPrivKey: this.identity.privateKey }
);
await this.waku.relay.send(msg);
)
await this.waku.relay.send(msg)
}
}
};
handleNickname();
send();
setInterval(send, STATUS_BROADCAST_INTERVAL);
}
handleNickname()
send()
setInterval(send, STATUS_BROADCAST_INTERVAL)
}
}

View File

@ -1,8 +1,8 @@
import { Buffer } from "buffer";
import { Buffer } from 'buffer'
import { keccak256 } from "js-sha3";
import { keccak256 } from 'js-sha3'
const TopicLength = 4;
const TopicLength = 4
/**
* Get the content topic of for a given Chat or Community
@ -10,13 +10,13 @@ const TopicLength = 4;
* @returns string The Waku v2 Content Topic.
*/
export function idToContentTopic(id: string): string {
const hash = keccak256.arrayBuffer(id);
const hash = keccak256.arrayBuffer(id)
const topic = Buffer.from(hash).slice(0, TopicLength);
const topic = Buffer.from(hash).slice(0, TopicLength)
return "/waku/1/" + "0x" + topic.toString("hex") + "/rfc26";
return '/waku/1/' + '0x' + topic.toString('hex') + '/rfc26'
}
export function idToContactCodeTopic(id: string): string {
return idToContentTopic(id + "-contact-code");
return idToContentTopic(id + '-contact-code')
}

View File

@ -1,24 +1,24 @@
import { expect } from "chai";
import { expect } from 'chai'
import { createSymKeyFromPassword } from "./encryption";
import { createSymKeyFromPassword } from './encryption'
describe("Encryption", () => {
it("Generate symmetric key from password", async function () {
const str = "arbitrary data here";
const symKey = await createSymKeyFromPassword(str);
describe('Encryption', () => {
it('Generate symmetric key from password', async function () {
const str = 'arbitrary data here'
const symKey = await createSymKeyFromPassword(str)
expect(Buffer.from(symKey).toString("hex")).to.eq(
"c49ad65ebf2a7b7253bf400e3d27719362a91b2c9b9f54d50a69117021666c33"
);
});
expect(Buffer.from(symKey).toString('hex')).to.eq(
'c49ad65ebf2a7b7253bf400e3d27719362a91b2c9b9f54d50a69117021666c33'
)
})
it("Generate symmetric key from password for chat", async function () {
it('Generate symmetric key from password for chat', async function () {
const str =
"0x02dcec6041fb999d65f1d33363e08c93d3c1f6f0fbbb26add383e2cf46c2b921f41dc14fd8-9a8b-4df5-a358-2c3067be5439";
const symKey = await createSymKeyFromPassword(str);
'0x02dcec6041fb999d65f1d33363e08c93d3c1f6f0fbbb26add383e2cf46c2b921f41dc14fd8-9a8b-4df5-a358-2c3067be5439'
const symKey = await createSymKeyFromPassword(str)
expect(Buffer.from(symKey).toString("hex")).to.eq(
"76ff5bf0a74a8e724367c7fc003f066d477641f468768a8da2817addf5c2ce76"
);
});
});
expect(Buffer.from(symKey).toString('hex')).to.eq(
'76ff5bf0a74a8e724367c7fc003f066d477641f468768a8da2817addf5c2ce76'
)
})
})

View File

@ -1,15 +1,15 @@
import pbkdf2 from "pbkdf2";
import pbkdf2 from 'pbkdf2'
const AESKeyLength = 32; // bytes
const AESKeyLength = 32 // bytes
export async function createSymKeyFromPassword(
password: string
): Promise<Uint8Array> {
return pbkdf2.pbkdf2Sync(
Buffer.from(password, "utf-8"),
"",
Buffer.from(password, 'utf-8'),
'',
65356,
AESKeyLength,
"sha256"
);
'sha256'
)
}

View File

@ -1,68 +1,68 @@
import { Waku, WakuMessage } from "js-waku";
import { DecryptionMethod } from "js-waku/build/main/lib/waku_message";
import { Waku, WakuMessage } from 'js-waku'
import { DecryptionMethod } from 'js-waku/build/main/lib/waku_message'
import { createSymKeyFromPassword } from "./encryption";
import { Identity } from "./identity";
import { MembershipUpdateEvent_EventType } from "./proto/communities/v1/membership_update_message";
import { getNegotiatedTopic, getPartitionedTopic } from "./topics";
import { bufToHex, compressPublicKey } from "./utils";
import { createSymKeyFromPassword } from './encryption'
import { Identity } from './identity'
import { MembershipUpdateEvent_EventType } from './proto/communities/v1/membership_update_message'
import { getNegotiatedTopic, getPartitionedTopic } from './topics'
import { bufToHex, compressPublicKey } from './utils'
import {
MembershipSignedEvent,
MembershipUpdateMessage,
} from "./wire/membership_update_message";
} from './wire/membership_update_message'
import { ChatMessage, Content } from ".";
import { ChatMessage, Content } from '.'
type GroupMember = {
id: string;
topic: string;
symKey: Uint8Array;
partitionedTopic: string;
};
id: string
topic: string
symKey: Uint8Array
partitionedTopic: string
}
export type GroupChat = {
chatId: string;
members: GroupMember[];
admins?: string[];
name?: string;
removed: boolean;
};
chatId: string
members: GroupMember[]
admins?: string[]
name?: string
removed: boolean
}
export type GroupChatsType = {
[id: string]: GroupChat;
};
[id: string]: GroupChat
}
/* TODO: add chat messages encryption */
class GroupChatUsers {
private users: { [id: string]: GroupMember } = {};
private identity: Identity;
private users: { [id: string]: GroupMember } = {}
private identity: Identity
public constructor(_identity: Identity) {
this.identity = _identity;
this.identity = _identity
}
public async getUser(id: string): Promise<GroupMember> {
if (this.users[id]) {
return this.users[id];
return this.users[id]
}
const topic = await getNegotiatedTopic(this.identity, id);
const symKey = await createSymKeyFromPassword(topic);
const partitionedTopic = getPartitionedTopic(id);
const groupUser: GroupMember = { topic, symKey, id, partitionedTopic };
this.users[id] = groupUser;
return groupUser;
const topic = await getNegotiatedTopic(this.identity, id)
const symKey = await createSymKeyFromPassword(topic)
const partitionedTopic = getPartitionedTopic(id)
const groupUser: GroupMember = { topic, symKey, id, partitionedTopic }
this.users[id] = groupUser
return groupUser
}
}
export class GroupChats {
waku: Waku;
identity: Identity;
private callback: (chats: GroupChat) => void;
private removeCallback: (chats: GroupChat) => void;
private addMessage: (message: ChatMessage, sender: string) => void;
private groupChatUsers;
waku: Waku
identity: Identity
private callback: (chats: GroupChat) => void
private removeCallback: (chats: GroupChat) => void
private addMessage: (message: ChatMessage, sender: string) => void
private groupChatUsers
public chats: GroupChatsType = {};
public chats: GroupChatsType = {}
/**
* GroupChats holds a list of private chats and listens to their status broadcast
*
@ -83,13 +83,13 @@ export class GroupChats {
removeCallback: (chat: GroupChat) => void,
addMessage: (message: ChatMessage, sender: string) => void
) {
this.waku = waku;
this.identity = identity;
this.groupChatUsers = new GroupChatUsers(identity);
this.callback = callback;
this.removeCallback = removeCallback;
this.addMessage = addMessage;
this.listen();
this.waku = waku
this.identity = identity
this.groupChatUsers = new GroupChatUsers(identity)
this.callback = callback
this.removeCallback = removeCallback
this.addMessage = addMessage
this.listen()
}
/**
@ -104,26 +104,26 @@ export class GroupChats {
content: Content,
responseTo?: string
): Promise<void> {
const now = Date.now();
const chat = this.chats[chatId];
const now = Date.now()
const chat = this.chats[chatId]
if (chat) {
await Promise.all(
chat.members.map(async (member) => {
chat.members.map(async member => {
const chatMessage = ChatMessage.createMessage(
now,
now,
chatId,
content,
responseTo
);
)
const wakuMessage = await WakuMessage.fromBytes(
chatMessage.encode(),
member.topic,
{ sigPrivKey: this.identity.privateKey, symKey: member.symKey }
);
this.waku.relay.send(wakuMessage);
)
this.waku.relay.send(wakuMessage)
})
);
)
}
}
@ -132,18 +132,18 @@ export class GroupChats {
event: MembershipSignedEvent,
useCallback: boolean
): Promise<void> {
const signer = event.signer ? bufToHex(event.signer) : "";
const thisUser = bufToHex(this.identity.publicKey);
const chat: GroupChat | undefined = this.chats[chatId];
const signer = event.signer ? bufToHex(event.signer) : ''
const thisUser = bufToHex(this.identity.publicKey)
const chat: GroupChat | undefined = this.chats[chatId]
if (signer) {
switch (event.event.type) {
case MembershipUpdateEvent_EventType.CHAT_CREATED: {
const members: GroupMember[] = [];
const members: GroupMember[] = []
await Promise.all(
event.event.members.map(async (member) => {
members.push(await this.groupChatUsers.getUser(member));
event.event.members.map(async member => {
members.push(await this.groupChatUsers.getUser(member))
})
);
)
await this.addChat(
{
chatId: chatId,
@ -152,14 +152,14 @@ export class GroupChats {
removed: false,
},
useCallback
);
break;
)
break
}
case MembershipUpdateEvent_EventType.MEMBER_REMOVED: {
if (chat) {
chat.members = chat.members.filter(
(member) => !event.event.members.includes(member.id)
);
member => !event.event.members.includes(member.id)
)
if (event.event.members.includes(thisUser)) {
await this.removeChat(
{
@ -167,41 +167,39 @@ export class GroupChats {
removed: true,
},
useCallback
);
)
} else {
if (!chat.removed && useCallback) {
this.callback(this.chats[chatId]);
this.callback(this.chats[chatId])
}
}
}
break;
break
}
case MembershipUpdateEvent_EventType.MEMBERS_ADDED: {
if (chat && chat.admins?.includes(signer)) {
const members: GroupMember[] = [];
const members: GroupMember[] = []
await Promise.all(
event.event.members.map(async (member) => {
members.push(await this.groupChatUsers.getUser(member));
event.event.members.map(async member => {
members.push(await this.groupChatUsers.getUser(member))
})
);
chat.members.push(...members);
if (
chat.members.findIndex((member) => member.id === thisUser) > -1
) {
chat.removed = false;
await this.addChat(chat, useCallback);
)
chat.members.push(...members)
if (chat.members.findIndex(member => member.id === thisUser) > -1) {
chat.removed = false
await this.addChat(chat, useCallback)
}
}
break;
break
}
case MembershipUpdateEvent_EventType.NAME_CHANGED: {
if (chat) {
if (chat.admins?.includes(signer)) {
chat.name = event.event.name;
this.callback(chat);
chat.name = event.event.name
this.callback(chat)
}
}
break;
break
}
}
}
@ -213,22 +211,20 @@ export class GroupChats {
): Promise<void> {
try {
if (message?.payload) {
const membershipUpdate = MembershipUpdateMessage.decode(
message.payload
);
const membershipUpdate = MembershipUpdateMessage.decode(message.payload)
await Promise.all(
membershipUpdate.events.map(
async (event) =>
async event =>
await this.handleUpdateEvent(
membershipUpdate.chatId,
event,
useCallback
)
)
);
)
}
} catch {
return;
return
}
}
@ -239,19 +235,19 @@ export class GroupChats {
): void {
try {
if (message.payload) {
const chatMessage = ChatMessage.decode(message.payload);
const chatMessage = ChatMessage.decode(message.payload)
if (chatMessage) {
if (chatMessage.chatId === chat.chatId) {
let sender = member;
let sender = member
if (message.signaturePublicKey) {
sender = compressPublicKey(message.signaturePublicKey);
sender = compressPublicKey(message.signaturePublicKey)
}
this.addMessage(chatMessage, sender);
this.addMessage(chatMessage, sender)
}
}
}
} catch {
return;
return
}
}
@ -259,34 +255,34 @@ export class GroupChats {
chat: GroupChat,
removeObserver?: boolean
): Promise<void> {
const observerFunction = removeObserver ? "deleteObserver" : "addObserver";
const observerFunction = removeObserver ? 'deleteObserver' : 'addObserver'
await Promise.all(
chat.members.map(async (member) => {
chat.members.map(async member => {
if (!removeObserver) {
this.waku.relay.addDecryptionKey(member.symKey, {
method: DecryptionMethod.Symmetric,
contentTopics: [member.topic],
});
})
}
this.waku.relay[observerFunction](
(message) => this.handleWakuChatMessage(message, chat, member.id),
message => this.handleWakuChatMessage(message, chat, member.id),
[member.topic]
);
)
})
);
)
}
private async addChat(chat: GroupChat, useCallback: boolean): Promise<void> {
if (this.chats[chat.chatId]) {
this.chats[chat.chatId] = chat;
this.chats[chat.chatId] = chat
if (useCallback) {
this.callback(chat);
this.callback(chat)
}
} else {
this.chats[chat.chatId] = chat;
this.chats[chat.chatId] = chat
if (useCallback) {
await this.handleChatObserver(chat);
this.callback(chat);
await this.handleChatObserver(chat)
this.callback(chat)
}
}
}
@ -295,34 +291,34 @@ export class GroupChats {
chat: GroupChat,
useCallback: boolean
): Promise<void> {
this.chats[chat.chatId] = chat;
this.chats[chat.chatId] = chat
if (useCallback) {
await this.handleChatObserver(chat, true);
this.removeCallback(chat);
await this.handleChatObserver(chat, true)
this.removeCallback(chat)
}
}
private async listen(): Promise<void> {
const topic = getPartitionedTopic(bufToHex(this.identity.publicKey));
const messages = await this.waku.store.queryHistory([topic]);
const topic = getPartitionedTopic(bufToHex(this.identity.publicKey))
const messages = await this.waku.store.queryHistory([topic])
messages.sort((a, b) =>
(a?.timestamp?.getTime() ?? 0) < (b?.timestamp?.getTime() ?? 0) ? -1 : 1
);
)
for (let i = 0; i < messages.length; i++) {
await this.decodeUpdateMessage(messages[i], false);
await this.decodeUpdateMessage(messages[i], false)
}
this.waku.relay.addObserver(
(message) => this.decodeUpdateMessage(message, true),
message => this.decodeUpdateMessage(message, true),
[topic]
);
)
await Promise.all(
Object.values(this.chats).map(async (chat) => {
Object.values(this.chats).map(async chat => {
if (!chat?.removed) {
await this.handleChatObserver(chat);
this.callback(chat);
await this.handleChatObserver(chat)
this.callback(chat)
}
})
);
)
}
private async sendUpdateMessage(
@ -331,11 +327,11 @@ export class GroupChats {
): Promise<void> {
const wakuMessages = await Promise.all(
members.map(
async (member) =>
async member =>
await WakuMessage.fromBytes(payload, member.partitionedTopic)
)
);
wakuMessages.forEach((msg) => this.waku.relay.send(msg));
)
wakuMessages.forEach(msg => this.waku.relay.send(msg))
}
/**
@ -346,11 +342,11 @@ export class GroupChats {
* @param name a name which chat should be changed to
*/
public async changeChatName(chatId: string, name: string): Promise<void> {
const payload = MembershipUpdateMessage.create(chatId, this.identity);
const chat = this.chats[chatId];
const payload = MembershipUpdateMessage.create(chatId, this.identity)
const chat = this.chats[chatId]
if (chat && payload) {
payload.addNameChangeEvent(name);
await this.sendUpdateMessage(payload.encode(), chat.members);
payload.addNameChangeEvent(name)
await this.sendUpdateMessage(payload.encode(), chat.members)
}
}
@ -362,27 +358,27 @@ export class GroupChats {
* @param members a list of members to be added
*/
public async addMembers(chatId: string, members: string[]): Promise<void> {
const payload = MembershipUpdateMessage.create(chatId, this.identity);
const chat = this.chats[chatId];
const payload = MembershipUpdateMessage.create(chatId, this.identity)
const chat = this.chats[chatId]
if (chat && payload) {
const newMembers: GroupMember[] = [];
const newMembers: GroupMember[] = []
await Promise.all(
members
.filter(
(member) =>
!chat.members.map((chatMember) => chatMember.id).includes(member)
member =>
!chat.members.map(chatMember => chatMember.id).includes(member)
)
.map(async (member) => {
newMembers.push(await this.groupChatUsers.getUser(member));
.map(async member => {
newMembers.push(await this.groupChatUsers.getUser(member))
})
);
)
payload.addMembersAddedEvent(newMembers.map((member) => member.id));
payload.addMembersAddedEvent(newMembers.map(member => member.id))
await this.sendUpdateMessage(payload.encode(), [
...chat.members,
...newMembers,
]);
])
}
}
@ -395,17 +391,17 @@ export class GroupChats {
const payload = MembershipUpdateMessage.createChat(
this.identity,
members
).encode();
).encode()
const newMembers: GroupMember[] = [];
const newMembers: GroupMember[] = []
await Promise.all(
members.map(async (member) => {
newMembers.push(await this.groupChatUsers.getUser(member));
members.map(async member => {
newMembers.push(await this.groupChatUsers.getUser(member))
})
);
)
await this.sendUpdateMessage(payload, newMembers);
await this.sendUpdateMessage(payload, newMembers)
}
/**
@ -414,10 +410,10 @@ export class GroupChats {
* @param chatId id of private group chat
*/
public async quitChat(chatId: string): Promise<void> {
const payload = MembershipUpdateMessage.create(chatId, this.identity);
const chat = this.chats[chatId];
payload.addMemberRemovedEvent(bufToHex(this.identity.publicKey));
await this.sendUpdateMessage(payload.encode(), chat.members);
const payload = MembershipUpdateMessage.create(chatId, this.identity)
const chat = this.chats[chatId]
payload.addMemberRemovedEvent(bufToHex(this.identity.publicKey))
await this.sendUpdateMessage(payload.encode(), chat.members)
}
/**
@ -429,31 +425,31 @@ export class GroupChats {
startTime: Date,
endTime: Date
): Promise<number> {
const chat = this.chats[chatId];
const chat = this.chats[chatId]
if (!chat)
throw `Failed to retrieve messages, chat is not joined: ${chatId}`;
throw `Failed to retrieve messages, chat is not joined: ${chatId}`
const _callback = (wakuMessages: WakuMessage[], member: string): void => {
wakuMessages.forEach((wakuMessage: WakuMessage) =>
this.handleWakuChatMessage(wakuMessage, chat, member)
);
};
)
}
const amountOfMessages: number[] = [];
const amountOfMessages: number[] = []
await Promise.all(
chat.members.map(async (member) => {
chat.members.map(async member => {
const msgLength = (
await this.waku.store.queryHistory([member.topic], {
timeFilter: { startTime, endTime },
callback: (msg) => _callback(msg, member.id),
callback: msg => _callback(msg, member.id),
decryptionKeys: [member.symKey],
})
).length;
amountOfMessages.push(msgLength);
).length
amountOfMessages.push(msgLength)
})
);
return amountOfMessages.reduce((a, b) => a + b);
)
return amountOfMessages.reduce((a, b) => a + b)
}
}

View File

@ -1,39 +1,39 @@
import { Buffer } from "buffer";
import { Buffer } from 'buffer'
import { keccak256 } from "js-sha3";
import { generatePrivateKey } from "js-waku";
import * as secp256k1 from "secp256k1";
import { keccak256 } from 'js-sha3'
import { generatePrivateKey } from 'js-waku'
import * as secp256k1 from 'secp256k1'
import { hexToBuf } from "./utils";
import { hexToBuf } from './utils'
export class Identity {
private pubKey: Uint8Array;
private pubKey: Uint8Array
public constructor(public privateKey: Uint8Array) {
this.pubKey = secp256k1.publicKeyCreate(this.privateKey, true);
this.pubKey = secp256k1.publicKeyCreate(this.privateKey, true)
}
public static generate(): Identity {
const privateKey = generatePrivateKey();
return new Identity(privateKey);
const privateKey = generatePrivateKey()
return new Identity(privateKey)
}
/**
* Hashes the payload with SHA3-256 and signs the result using the internal private key.
*/
public sign(payload: Uint8Array): Uint8Array {
const hash = keccak256(payload);
const hash = keccak256(payload)
const { signature, recid } = secp256k1.ecdsaSign(
hexToBuf(hash),
this.privateKey
);
)
return Buffer.concat([signature, Buffer.from([recid])]);
return Buffer.concat([signature, Buffer.from([recid])])
}
/**
* Returns the compressed public key.
*/
public get publicKey(): Uint8Array {
return this.pubKey;
return this.pubKey
}
}

View File

@ -1,11 +1,11 @@
export { Identity } from "./identity";
export { Messenger } from "./messenger";
export { Community } from "./community";
export { Contacts } from "./contacts";
export { Chat } from "./chat";
export * from "./groupChats";
export * as utils from "./utils";
export { ApplicationMetadataMessage } from "./wire/application_metadata_message";
export { Identity } from './identity'
export { Messenger } from './messenger'
export { Community } from './community'
export { Contacts } from './contacts'
export { Chat } from './chat'
export * from './groupChats'
export * as utils from './utils'
export { ApplicationMetadataMessage } from './wire/application_metadata_message'
export {
ChatMessage,
ContentType,
@ -14,5 +14,5 @@ export {
ImageContent,
AudioContent,
TextContent,
} from "./wire/chat_message";
export { getNodesFromHostedJson } from "js-waku";
} from './wire/chat_message'
export { getNodesFromHostedJson } from 'js-waku'

View File

@ -1,178 +1,177 @@
import { expect } from "chai";
import debug from "debug";
import { Protocols } from "js-waku/build/main/lib/waku";
import { expect } from 'chai'
import debug from 'debug'
import { Protocols } from 'js-waku/build/main/lib/waku'
import { Community } from "./community";
import { Identity } from "./identity";
import { Messenger } from "./messenger";
import { bufToHex } from "./utils";
import { ApplicationMetadataMessage } from "./wire/application_metadata_message";
import { ContentType } from "./wire/chat_message";
import { Community } from './community'
import { Identity } from './identity'
import { Messenger } from './messenger'
import { bufToHex } from './utils'
import { ApplicationMetadataMessage } from './wire/application_metadata_message'
import { ContentType } from './wire/chat_message'
const testChatId = "test-chat-id";
const testChatId = 'test-chat-id'
const dbg = debug("communities:test:messenger");
const dbg = debug('communities:test:messenger')
describe("Messenger", () => {
let messengerAlice: Messenger;
let messengerBob: Messenger;
let identityAlice: Identity;
let identityBob: Identity;
describe('Messenger', () => {
let messengerAlice: Messenger
let messengerBob: Messenger
let identityAlice: Identity
let identityBob: Identity
beforeEach(async function () {
this.timeout(20_000);
this.timeout(20_000)
dbg("Generate keys");
identityAlice = Identity.generate();
identityBob = Identity.generate();
dbg('Generate keys')
identityAlice = Identity.generate()
identityBob = Identity.generate()
dbg("Create messengers");
[messengerAlice, messengerBob] = await Promise.all([
dbg('Create messengers')
;[messengerAlice, messengerBob] = await Promise.all([
Messenger.create(identityAlice, { bootstrap: {} }),
Messenger.create(identityBob, {
bootstrap: {},
libp2p: { addresses: { listen: ["/ip4/0.0.0.0/tcp/0/ws"] } },
libp2p: { addresses: { listen: ['/ip4/0.0.0.0/tcp/0/ws'] } },
}),
]);
])
dbg("Connect messengers");
dbg('Connect messengers')
// Connect both messengers together for test purposes
messengerAlice.waku.addPeerToAddressBook(
messengerBob.waku.libp2p.peerId,
messengerBob.waku.libp2p.multiaddrs
);
)
dbg("Wait for remote peer");
dbg('Wait for remote peer')
await Promise.all([
messengerAlice.waku.waitForRemotePeer([Protocols.Relay]),
messengerBob.waku.waitForRemotePeer([Protocols.Relay]),
]);
dbg("Messengers ready");
});
])
dbg('Messengers ready')
})
it("Sends & Receive public chat messages", async function () {
this.timeout(10_000);
it('Sends & Receive public chat messages', async function () {
this.timeout(10_000)
await messengerAlice.joinChatById(testChatId);
await messengerBob.joinChatById(testChatId);
await messengerAlice.joinChatById(testChatId)
await messengerBob.joinChatById(testChatId)
const text = "This is a message.";
const text = 'This is a message.'
const receivedMessagePromise: Promise<ApplicationMetadataMessage> =
new Promise((resolve) => {
messengerBob.addObserver((message) => {
resolve(message);
}, testChatId);
});
new Promise(resolve => {
messengerBob.addObserver(message => {
resolve(message)
}, testChatId)
})
await messengerAlice.sendMessage(testChatId, {
text,
contentType: ContentType.Text,
});
})
const receivedMessage = await receivedMessagePromise;
const receivedMessage = await receivedMessagePromise
expect(receivedMessage.chatMessage?.text).to.eq(text);
});
expect(receivedMessage.chatMessage?.text).to.eq(text)
})
it("public chat messages have signers", async function () {
this.timeout(10_000);
it('public chat messages have signers', async function () {
this.timeout(10_000)
await messengerAlice.joinChatById(testChatId);
await messengerBob.joinChatById(testChatId);
await messengerAlice.joinChatById(testChatId)
await messengerBob.joinChatById(testChatId)
const text = "This is a message.";
const text = 'This is a message.'
const receivedMessagePromise: Promise<ApplicationMetadataMessage> =
new Promise((resolve) => {
messengerBob.addObserver((message) => {
resolve(message);
}, testChatId);
});
new Promise(resolve => {
messengerBob.addObserver(message => {
resolve(message)
}, testChatId)
})
await messengerAlice.sendMessage(testChatId, {
text,
contentType: ContentType.Text,
});
})
const receivedMessage = await receivedMessagePromise;
const receivedMessage = await receivedMessagePromise
expect(bufToHex(receivedMessage.signer!)).to.eq(
bufToHex(identityAlice.publicKey)
);
});
)
})
afterEach(async function () {
this.timeout(5000);
await messengerAlice.stop();
await messengerBob.stop();
});
});
this.timeout(5000)
await messengerAlice.stop()
await messengerBob.stop()
})
})
describe("Messenger [live data]", () => {
describe('Messenger [live data]', () => {
before(function () {
if (process.env.CI) {
// Skip live data test in CI
this.skip();
this.skip()
}
});
})
let messenger: Messenger;
let identity: Identity;
let messenger: Messenger
let identity: Identity
beforeEach(async function () {
this.timeout(20_000);
this.timeout(20_000)
dbg("Generate keys");
identity = Identity.generate();
dbg('Generate keys')
identity = Identity.generate()
dbg("Create messengers");
dbg('Create messengers')
messenger = await Messenger.create(identity, {
bootstrap: { default: true },
});
})
dbg("Wait to be connected to a peer");
await messenger.waku.waitForRemotePeer();
dbg("Messengers ready");
});
dbg('Wait to be connected to a peer')
await messenger.waku.waitForRemotePeer()
dbg('Messengers ready')
})
it("Receive public chat messages", async function () {
this.timeout(20_000);
it('Receive public chat messages', async function () {
this.timeout(20_000)
const community = await Community.instantiateCommunity(
"0x02cf13719c8b836bebd4e430c497ee38e798a43e4d8c4760c34bbd9bf4f2434d26",
'0x02cf13719c8b836bebd4e430c497ee38e798a43e4d8c4760c34bbd9bf4f2434d26',
messenger.waku
);
)
await messenger.joinChats(community.chats.values());
await messenger.joinChats(community.chats.values())
const startTime = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000);
const endTime = new Date();
const startTime = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000)
const endTime = new Date()
const chat = Array.from(community.chats.values()).find(
(chat) => chat.communityChat?.identity?.displayName === "Test Chat"
);
chat => chat.communityChat?.identity?.displayName === 'Test Chat'
)
if (!chat) throw "Could not find foobar chat";
if (!chat) throw 'Could not find foobar chat'
console.log(chat);
console.log(chat)
await messenger.retrievePreviousMessages(
chat.id,
startTime,
endTime,
(metadata) => {
metadata.forEach((m) => {
console.log("Message", m.chatMessage?.text);
});
metadata => {
metadata.forEach(m => {
console.log('Message', m.chatMessage?.text)
})
}
);
});
)
})
afterEach(async function () {
this.timeout(5000);
await messenger.stop();
});
});
this.timeout(5000)
await messenger.stop()
})
})

View File

@ -1,20 +1,20 @@
import debug from "debug";
import { Waku, WakuMessage } from "js-waku";
import { CreateOptions as WakuCreateOptions } from "js-waku/build/main/lib/waku";
import { DecryptionMethod } from "js-waku/build/main/lib/waku_message";
import debug from 'debug'
import { Waku, WakuMessage } from 'js-waku'
import { CreateOptions as WakuCreateOptions } from 'js-waku/build/main/lib/waku'
import { DecryptionMethod } from 'js-waku/build/main/lib/waku_message'
import { Chat } from "./chat";
import { Identity } from "./identity";
import { ApplicationMetadataMessage_Type } from "./proto/status/v1/application_metadata_message";
import { getLatestUserNickname } from "./utils";
import { ApplicationMetadataMessage } from "./wire/application_metadata_message";
import { ChatMessage, Content } from "./wire/chat_message";
import { Chat } from './chat'
import { Identity } from './identity'
import { ApplicationMetadataMessage_Type } from './proto/status/v1/application_metadata_message'
import { getLatestUserNickname } from './utils'
import { ApplicationMetadataMessage } from './wire/application_metadata_message'
import { ChatMessage, Content } from './wire/chat_message'
const dbg = debug("communities:messenger");
const dbg = debug('communities:messenger')
export class Messenger {
waku: Waku;
chatsById: Map<string, Chat>;
waku: Waku
chatsById: Map<string, Chat>
observers: {
[chatId: string]: Set<
(
@ -22,15 +22,15 @@ export class Messenger {
timestamp: Date,
chatId: string
) => void
>;
};
identity: Identity | undefined;
>
}
identity: Identity | undefined
private constructor(identity: Identity | undefined, waku: Waku) {
this.identity = identity;
this.waku = waku;
this.chatsById = new Map();
this.observers = {};
this.identity = identity
this.waku = waku
this.chatsById = new Map()
this.observers = {}
}
public static async create(
@ -40,9 +40,9 @@ export class Messenger {
const _wakuOptions = Object.assign(
{ bootstrap: { default: true } },
wakuOptions
);
const waku = await Waku.create(_wakuOptions);
return new Messenger(identity, waku);
)
const waku = await Waku.create(_wakuOptions)
return new Messenger(identity, waku)
}
/**
@ -53,9 +53,9 @@ export class Messenger {
* Use `addListener` to get messages received on this chat.
*/
public async joinChatById(chatId: string): Promise<void> {
const chat = await Chat.create(chatId);
const chat = await Chat.create(chatId)
await this.joinChat(chat);
await this.joinChat(chat)
}
/**
@ -65,10 +65,10 @@ export class Messenger {
*/
public async joinChats(chats: Iterable<Chat>): Promise<void> {
await Promise.all(
Array.from(chats).map((chat) => {
return this.joinChat(chat);
Array.from(chats).map(chat => {
return this.joinChat(chat)
})
);
)
}
/**
@ -78,31 +78,31 @@ export class Messenger {
*/
public async joinChat(chat: Chat): Promise<void> {
if (this.chatsById.has(chat.id))
throw `Failed to join chat, it is already joined: ${chat.id}`;
throw `Failed to join chat, it is already joined: ${chat.id}`
this.waku.addDecryptionKey(chat.symKey, {
method: DecryptionMethod.Symmetric,
contentTopics: [chat.contentTopic],
});
})
this.waku.relay.addObserver(
(wakuMessage: WakuMessage) => {
if (!wakuMessage.payload || !wakuMessage.timestamp) return;
if (!wakuMessage.payload || !wakuMessage.timestamp) return
const message = ApplicationMetadataMessage.decode(wakuMessage.payload);
const message = ApplicationMetadataMessage.decode(wakuMessage.payload)
switch (message.type) {
case ApplicationMetadataMessage_Type.TYPE_CHAT_MESSAGE:
this._handleNewChatMessage(chat, message, wakuMessage.timestamp);
break;
this._handleNewChatMessage(chat, message, wakuMessage.timestamp)
break
default:
dbg("Received unsupported message type", message.type);
dbg('Received unsupported message type', message.type)
}
},
[chat.contentTopic]
);
)
this.chatsById.set(chat.id, chat);
this.chatsById.set(chat.id, chat)
}
/**
@ -114,24 +114,24 @@ export class Messenger {
responseTo?: string
): Promise<void> {
if (this.identity) {
const chat = this.chatsById.get(chatId);
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(
chatMessage.encode(),
ApplicationMetadataMessage_Type.TYPE_CHAT_MESSAGE,
this.identity
);
)
const wakuMessage = await WakuMessage.fromBytes(
appMetadataMessage.encode(),
chat.contentTopic,
{ symKey: chat.symKey, sigPrivKey: this.identity.privateKey }
);
)
await this.waku.relay.send(wakuMessage);
await this.waku.relay.send(wakuMessage)
}
}
@ -148,23 +148,23 @@ export class Messenger {
) => void,
chatId: string | string[]
): void {
let chats = [];
let chats = []
if (typeof chatId === "string") {
chats.push(chatId);
if (typeof chatId === 'string') {
chats.push(chatId)
} else {
chats = [...chatId];
chats = [...chatId]
}
chats.forEach((id) => {
chats.forEach(id => {
if (!this.chatsById.has(id))
throw "Cannot add observer on a chat that is not joined.";
throw 'Cannot add observer on a chat that is not joined.'
if (!this.observers[id]) {
this.observers[id] = new Set();
this.observers[id] = new Set()
}
this.observers[id].add(observer);
});
this.observers[id].add(observer)
})
}
/**
@ -178,7 +178,7 @@ export class Messenger {
chatId: string
): void {
if (this.observers[chatId]) {
this.observers[chatId].delete(observer);
this.observers[chatId].delete(observer)
}
}
@ -186,7 +186,7 @@ export class Messenger {
* Stops the messenger.
*/
public async stop(): Promise<void> {
await this.waku.stop();
await this.waku.stop()
}
/**
@ -202,43 +202,43 @@ export class Messenger {
endTime: Date,
callback?: (messages: ApplicationMetadataMessage[]) => void
): Promise<number> {
const chat = this.chatsById.get(chatId);
const chat = this.chatsById.get(chatId)
if (!chat)
throw `Failed to retrieve messages, chat is not joined: ${chatId}`;
throw `Failed to retrieve messages, chat is not joined: ${chatId}`
const _callback = (wakuMessages: WakuMessage[]): void => {
const isDefined = (
msg: ApplicationMetadataMessage | undefined
): msg is ApplicationMetadataMessage => {
return !!msg;
};
return !!msg
}
const messages = wakuMessages.map((wakuMessage: WakuMessage) => {
if (!wakuMessage.payload || !wakuMessage.timestamp) return;
if (!wakuMessage.payload || !wakuMessage.timestamp) return
const message = ApplicationMetadataMessage.decode(wakuMessage.payload);
const message = ApplicationMetadataMessage.decode(wakuMessage.payload)
switch (message.type) {
case ApplicationMetadataMessage_Type.TYPE_CHAT_MESSAGE:
this._handleNewChatMessage(chat, message, wakuMessage.timestamp);
return message;
this._handleNewChatMessage(chat, message, wakuMessage.timestamp)
return message
default:
dbg("Retrieved unsupported message type", message.type);
return;
dbg('Retrieved unsupported message type', message.type)
return
}
});
})
if (callback) {
callback(messages.filter(isDefined));
callback(messages.filter(isDefined))
}
};
}
const allMessages = await this.waku.store.queryHistory(
[chat.contentTopic],
{
timeFilter: { startTime, endTime },
callback: _callback,
}
);
return allMessages.length;
)
return allMessages.length
}
private _handleNewChatMessage(
@ -246,15 +246,15 @@ export class Messenger {
message: ApplicationMetadataMessage,
timestamp: Date
): void {
if (!message.payload || !message.type || !message.signature) return;
if (!message.payload || !message.type || !message.signature) return
const chatMessage = ChatMessage.decode(message.payload);
chat.handleNewMessage(chatMessage);
const chatMessage = ChatMessage.decode(message.payload)
chat.handleNewMessage(chatMessage)
if (this.observers[chat.id]) {
this.observers[chat.id].forEach((observer) => {
observer(message, timestamp, chat.id);
});
this.observers[chat.id].forEach(observer => {
observer(message, timestamp, chat.id)
})
}
}
@ -262,7 +262,7 @@ export class Messenger {
const { clock, nickname } = await getLatestUserNickname(
publicKey,
this.waku
);
return clock > 0 && nickname !== "";
)
return clock > 0 && nickname !== ''
}
}

View File

@ -1,33 +1,33 @@
/* eslint-disable */
import Long from "long";
import _m0 from "protobufjs/minimal";
import Long from 'long'
import _m0 from 'protobufjs/minimal'
import {
ImageType,
imageTypeFromJSON,
imageTypeToJSON,
} from "../../communities/v1/enums";
} from '../../communities/v1/enums'
export const protobufPackage = "communities.v1";
export const protobufPackage = 'communities.v1'
/** ChatIdentity represents the user defined identity associated with their public chat key */
export interface ChatIdentity {
/** Lamport timestamp of the message */
clock: number;
clock: number
/** ens_name is the valid ENS name associated with the chat key */
ensName: string;
ensName: string
/** images is a string indexed mapping of images associated with an identity */
images: { [key: string]: IdentityImage };
images: { [key: string]: IdentityImage }
/** display name is the user set identity, valid only for organisations */
displayName: string;
displayName: string
/** description is the user set description, valid only for organisations */
description: string;
color: string;
emoji: string;
description: string
color: string
emoji: string
}
export interface ChatIdentity_ImagesEntry {
key: string;
value: IdentityImage | undefined;
key: string
value: IdentityImage | undefined
}
/** ProfileImage represents data associated with a user's profile image */
@ -36,11 +36,11 @@ export interface IdentityImage {
* payload is a context based payload for the profile image data,
* context is determined by the `source_type`
*/
payload: Uint8Array;
payload: Uint8Array
/** source_type signals the image payload source */
sourceType: IdentityImage_SourceType;
sourceType: IdentityImage_SourceType
/** image_type signals the image type and method of parsing the payload */
imageType: ImageType;
imageType: ImageType
}
/** SourceType are the predefined types of image source allowed */
@ -63,18 +63,18 @@ export function identityImage_SourceTypeFromJSON(
): IdentityImage_SourceType {
switch (object) {
case 0:
case "UNKNOWN_SOURCE_TYPE":
return IdentityImage_SourceType.UNKNOWN_SOURCE_TYPE;
case 'UNKNOWN_SOURCE_TYPE':
return IdentityImage_SourceType.UNKNOWN_SOURCE_TYPE
case 1:
case "RAW_PAYLOAD":
return IdentityImage_SourceType.RAW_PAYLOAD;
case 'RAW_PAYLOAD':
return IdentityImage_SourceType.RAW_PAYLOAD
case 2:
case "ENS_AVATAR":
return IdentityImage_SourceType.ENS_AVATAR;
case 'ENS_AVATAR':
return IdentityImage_SourceType.ENS_AVATAR
case -1:
case "UNRECOGNIZED":
case 'UNRECOGNIZED':
default:
return IdentityImage_SourceType.UNRECOGNIZED;
return IdentityImage_SourceType.UNRECOGNIZED
}
}
@ -83,24 +83,24 @@ export function identityImage_SourceTypeToJSON(
): string {
switch (object) {
case IdentityImage_SourceType.UNKNOWN_SOURCE_TYPE:
return "UNKNOWN_SOURCE_TYPE";
return 'UNKNOWN_SOURCE_TYPE'
case IdentityImage_SourceType.RAW_PAYLOAD:
return "RAW_PAYLOAD";
return 'RAW_PAYLOAD'
case IdentityImage_SourceType.ENS_AVATAR:
return "ENS_AVATAR";
return 'ENS_AVATAR'
default:
return "UNKNOWN";
return 'UNKNOWN'
}
}
const baseChatIdentity: object = {
clock: 0,
ensName: "",
displayName: "",
description: "",
color: "",
emoji: "",
};
ensName: '',
displayName: '',
description: '',
color: '',
emoji: '',
}
export const ChatIdentity = {
encode(
@ -108,246 +108,244 @@ export const ChatIdentity = {
writer: _m0.Writer = _m0.Writer.create()
): _m0.Writer {
if (message.clock !== 0) {
writer.uint32(8).uint64(message.clock);
writer.uint32(8).uint64(message.clock)
}
if (message.ensName !== "") {
writer.uint32(18).string(message.ensName);
if (message.ensName !== '') {
writer.uint32(18).string(message.ensName)
}
Object.entries(message.images).forEach(([key, value]) => {
ChatIdentity_ImagesEntry.encode(
{ key: key as any, value },
writer.uint32(26).fork()
).ldelim();
});
if (message.displayName !== "") {
writer.uint32(34).string(message.displayName);
).ldelim()
})
if (message.displayName !== '') {
writer.uint32(34).string(message.displayName)
}
if (message.description !== "") {
writer.uint32(42).string(message.description);
if (message.description !== '') {
writer.uint32(42).string(message.description)
}
if (message.color !== "") {
writer.uint32(50).string(message.color);
if (message.color !== '') {
writer.uint32(50).string(message.color)
}
if (message.emoji !== "") {
writer.uint32(58).string(message.emoji);
if (message.emoji !== '') {
writer.uint32(58).string(message.emoji)
}
return writer;
return writer
},
decode(input: _m0.Reader | Uint8Array, length?: number): ChatIdentity {
const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input);
let end = length === undefined ? reader.len : reader.pos + length;
const message = { ...baseChatIdentity } as ChatIdentity;
message.images = {};
const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input)
let end = length === undefined ? reader.len : reader.pos + length
const message = { ...baseChatIdentity } as ChatIdentity
message.images = {}
while (reader.pos < end) {
const tag = reader.uint32();
const tag = reader.uint32()
switch (tag >>> 3) {
case 1:
message.clock = longToNumber(reader.uint64() as Long);
break;
message.clock = longToNumber(reader.uint64() as Long)
break
case 2:
message.ensName = reader.string();
break;
message.ensName = reader.string()
break
case 3:
const entry3 = ChatIdentity_ImagesEntry.decode(
reader,
reader.uint32()
);
)
if (entry3.value !== undefined) {
message.images[entry3.key] = entry3.value;
message.images[entry3.key] = entry3.value
}
break;
break
case 4:
message.displayName = reader.string();
break;
message.displayName = reader.string()
break
case 5:
message.description = reader.string();
break;
message.description = reader.string()
break
case 6:
message.color = reader.string();
break;
message.color = reader.string()
break
case 7:
message.emoji = reader.string();
break;
message.emoji = reader.string()
break
default:
reader.skipType(tag & 7);
break;
reader.skipType(tag & 7)
break
}
}
return message;
return message
},
fromJSON(object: any): ChatIdentity {
const message = { ...baseChatIdentity } as ChatIdentity;
message.images = {};
const message = { ...baseChatIdentity } as ChatIdentity
message.images = {}
if (object.clock !== undefined && object.clock !== null) {
message.clock = Number(object.clock);
message.clock = Number(object.clock)
} else {
message.clock = 0;
message.clock = 0
}
if (object.ensName !== undefined && object.ensName !== null) {
message.ensName = String(object.ensName);
message.ensName = String(object.ensName)
} else {
message.ensName = "";
message.ensName = ''
}
if (object.images !== undefined && object.images !== null) {
Object.entries(object.images).forEach(([key, value]) => {
message.images[key] = IdentityImage.fromJSON(value);
});
message.images[key] = IdentityImage.fromJSON(value)
})
}
if (object.displayName !== undefined && object.displayName !== null) {
message.displayName = String(object.displayName);
message.displayName = String(object.displayName)
} else {
message.displayName = "";
message.displayName = ''
}
if (object.description !== undefined && object.description !== null) {
message.description = String(object.description);
message.description = String(object.description)
} else {
message.description = "";
message.description = ''
}
if (object.color !== undefined && object.color !== null) {
message.color = String(object.color);
message.color = String(object.color)
} else {
message.color = "";
message.color = ''
}
if (object.emoji !== undefined && object.emoji !== null) {
message.emoji = String(object.emoji);
message.emoji = String(object.emoji)
} else {
message.emoji = "";
message.emoji = ''
}
return message;
return message
},
toJSON(message: ChatIdentity): unknown {
const obj: any = {};
message.clock !== undefined && (obj.clock = message.clock);
message.ensName !== undefined && (obj.ensName = message.ensName);
obj.images = {};
const obj: any = {}
message.clock !== undefined && (obj.clock = message.clock)
message.ensName !== undefined && (obj.ensName = message.ensName)
obj.images = {}
if (message.images) {
Object.entries(message.images).forEach(([k, v]) => {
obj.images[k] = IdentityImage.toJSON(v);
});
obj.images[k] = IdentityImage.toJSON(v)
})
}
message.displayName !== undefined &&
(obj.displayName = message.displayName);
message.description !== undefined &&
(obj.description = message.description);
message.color !== undefined && (obj.color = message.color);
message.emoji !== undefined && (obj.emoji = message.emoji);
return obj;
message.displayName !== undefined && (obj.displayName = message.displayName)
message.description !== undefined && (obj.description = message.description)
message.color !== undefined && (obj.color = message.color)
message.emoji !== undefined && (obj.emoji = message.emoji)
return obj
},
fromPartial(object: DeepPartial<ChatIdentity>): ChatIdentity {
const message = { ...baseChatIdentity } as ChatIdentity;
message.images = {};
const message = { ...baseChatIdentity } as ChatIdentity
message.images = {}
if (object.clock !== undefined && object.clock !== null) {
message.clock = object.clock;
message.clock = object.clock
} else {
message.clock = 0;
message.clock = 0
}
if (object.ensName !== undefined && object.ensName !== null) {
message.ensName = object.ensName;
message.ensName = object.ensName
} else {
message.ensName = "";
message.ensName = ''
}
if (object.images !== undefined && object.images !== null) {
Object.entries(object.images).forEach(([key, value]) => {
if (value !== undefined) {
message.images[key] = IdentityImage.fromPartial(value);
message.images[key] = IdentityImage.fromPartial(value)
}
});
})
}
if (object.displayName !== undefined && object.displayName !== null) {
message.displayName = object.displayName;
message.displayName = object.displayName
} else {
message.displayName = "";
message.displayName = ''
}
if (object.description !== undefined && object.description !== null) {
message.description = object.description;
message.description = object.description
} else {
message.description = "";
message.description = ''
}
if (object.color !== undefined && object.color !== null) {
message.color = object.color;
message.color = object.color
} else {
message.color = "";
message.color = ''
}
if (object.emoji !== undefined && object.emoji !== null) {
message.emoji = object.emoji;
message.emoji = object.emoji
} else {
message.emoji = "";
message.emoji = ''
}
return message;
return message
},
};
}
const baseChatIdentity_ImagesEntry: object = { key: "" };
const baseChatIdentity_ImagesEntry: object = { key: '' }
export const ChatIdentity_ImagesEntry = {
encode(
message: ChatIdentity_ImagesEntry,
writer: _m0.Writer = _m0.Writer.create()
): _m0.Writer {
if (message.key !== "") {
writer.uint32(10).string(message.key);
if (message.key !== '') {
writer.uint32(10).string(message.key)
}
if (message.value !== undefined) {
IdentityImage.encode(message.value, writer.uint32(18).fork()).ldelim();
IdentityImage.encode(message.value, writer.uint32(18).fork()).ldelim()
}
return writer;
return writer
},
decode(
input: _m0.Reader | Uint8Array,
length?: number
): ChatIdentity_ImagesEntry {
const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input);
let end = length === undefined ? reader.len : reader.pos + length;
const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input)
let end = length === undefined ? reader.len : reader.pos + length
const message = {
...baseChatIdentity_ImagesEntry,
} as ChatIdentity_ImagesEntry;
} as ChatIdentity_ImagesEntry
while (reader.pos < end) {
const tag = reader.uint32();
const tag = reader.uint32()
switch (tag >>> 3) {
case 1:
message.key = reader.string();
break;
message.key = reader.string()
break
case 2:
message.value = IdentityImage.decode(reader, reader.uint32());
break;
message.value = IdentityImage.decode(reader, reader.uint32())
break
default:
reader.skipType(tag & 7);
break;
reader.skipType(tag & 7)
break
}
}
return message;
return message
},
fromJSON(object: any): ChatIdentity_ImagesEntry {
const message = {
...baseChatIdentity_ImagesEntry,
} as ChatIdentity_ImagesEntry;
} as ChatIdentity_ImagesEntry
if (object.key !== undefined && object.key !== null) {
message.key = String(object.key);
message.key = String(object.key)
} else {
message.key = "";
message.key = ''
}
if (object.value !== undefined && object.value !== null) {
message.value = IdentityImage.fromJSON(object.value);
message.value = IdentityImage.fromJSON(object.value)
} else {
message.value = undefined;
message.value = undefined
}
return message;
return message
},
toJSON(message: ChatIdentity_ImagesEntry): unknown {
const obj: any = {};
message.key !== undefined && (obj.key = message.key);
const obj: any = {}
message.key !== undefined && (obj.key = message.key)
message.value !== undefined &&
(obj.value = message.value
? IdentityImage.toJSON(message.value)
: undefined);
return obj;
: undefined)
return obj
},
fromPartial(
@ -355,22 +353,22 @@ export const ChatIdentity_ImagesEntry = {
): ChatIdentity_ImagesEntry {
const message = {
...baseChatIdentity_ImagesEntry,
} as ChatIdentity_ImagesEntry;
} as ChatIdentity_ImagesEntry
if (object.key !== undefined && object.key !== null) {
message.key = object.key;
message.key = object.key
} else {
message.key = "";
message.key = ''
}
if (object.value !== undefined && object.value !== null) {
message.value = IdentityImage.fromPartial(object.value);
message.value = IdentityImage.fromPartial(object.value)
} else {
message.value = undefined;
message.value = undefined
}
return message;
return message
},
};
}
const baseIdentityImage: object = { sourceType: 0, imageType: 0 };
const baseIdentityImage: object = { sourceType: 0, imageType: 0 }
export const IdentityImage = {
encode(
@ -378,127 +376,127 @@ export const IdentityImage = {
writer: _m0.Writer = _m0.Writer.create()
): _m0.Writer {
if (message.payload.length !== 0) {
writer.uint32(10).bytes(message.payload);
writer.uint32(10).bytes(message.payload)
}
if (message.sourceType !== 0) {
writer.uint32(16).int32(message.sourceType);
writer.uint32(16).int32(message.sourceType)
}
if (message.imageType !== 0) {
writer.uint32(24).int32(message.imageType);
writer.uint32(24).int32(message.imageType)
}
return writer;
return writer
},
decode(input: _m0.Reader | Uint8Array, length?: number): IdentityImage {
const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input);
let end = length === undefined ? reader.len : reader.pos + length;
const message = { ...baseIdentityImage } as IdentityImage;
message.payload = new Uint8Array();
const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input)
let end = length === undefined ? reader.len : reader.pos + length
const message = { ...baseIdentityImage } as IdentityImage
message.payload = new Uint8Array()
while (reader.pos < end) {
const tag = reader.uint32();
const tag = reader.uint32()
switch (tag >>> 3) {
case 1:
message.payload = reader.bytes();
break;
message.payload = reader.bytes()
break
case 2:
message.sourceType = reader.int32() as any;
break;
message.sourceType = reader.int32() as any
break
case 3:
message.imageType = reader.int32() as any;
break;
message.imageType = reader.int32() as any
break
default:
reader.skipType(tag & 7);
break;
reader.skipType(tag & 7)
break
}
}
return message;
return message
},
fromJSON(object: any): IdentityImage {
const message = { ...baseIdentityImage } as IdentityImage;
message.payload = new Uint8Array();
const message = { ...baseIdentityImage } as IdentityImage
message.payload = new Uint8Array()
if (object.payload !== undefined && object.payload !== null) {
message.payload = bytesFromBase64(object.payload);
message.payload = bytesFromBase64(object.payload)
}
if (object.sourceType !== undefined && object.sourceType !== null) {
message.sourceType = identityImage_SourceTypeFromJSON(object.sourceType);
message.sourceType = identityImage_SourceTypeFromJSON(object.sourceType)
} else {
message.sourceType = 0;
message.sourceType = 0
}
if (object.imageType !== undefined && object.imageType !== null) {
message.imageType = imageTypeFromJSON(object.imageType);
message.imageType = imageTypeFromJSON(object.imageType)
} else {
message.imageType = 0;
message.imageType = 0
}
return message;
return message
},
toJSON(message: IdentityImage): unknown {
const obj: any = {};
const obj: any = {}
message.payload !== undefined &&
(obj.payload = base64FromBytes(
message.payload !== undefined ? message.payload : new Uint8Array()
));
))
message.sourceType !== undefined &&
(obj.sourceType = identityImage_SourceTypeToJSON(message.sourceType));
(obj.sourceType = identityImage_SourceTypeToJSON(message.sourceType))
message.imageType !== undefined &&
(obj.imageType = imageTypeToJSON(message.imageType));
return obj;
(obj.imageType = imageTypeToJSON(message.imageType))
return obj
},
fromPartial(object: DeepPartial<IdentityImage>): IdentityImage {
const message = { ...baseIdentityImage } as IdentityImage;
const message = { ...baseIdentityImage } as IdentityImage
if (object.payload !== undefined && object.payload !== null) {
message.payload = object.payload;
message.payload = object.payload
} else {
message.payload = new Uint8Array();
message.payload = new Uint8Array()
}
if (object.sourceType !== undefined && object.sourceType !== null) {
message.sourceType = object.sourceType;
message.sourceType = object.sourceType
} else {
message.sourceType = 0;
message.sourceType = 0
}
if (object.imageType !== undefined && object.imageType !== null) {
message.imageType = object.imageType;
message.imageType = object.imageType
} else {
message.imageType = 0;
message.imageType = 0
}
return message;
return message
},
};
}
declare var self: any | undefined;
declare var window: any | undefined;
declare var global: any | undefined;
declare var self: any | undefined
declare var window: any | undefined
declare var global: any | undefined
var globalThis: any = (() => {
if (typeof globalThis !== "undefined") return globalThis;
if (typeof self !== "undefined") return self;
if (typeof window !== "undefined") return window;
if (typeof global !== "undefined") return global;
throw "Unable to locate global object";
})();
if (typeof globalThis !== 'undefined') return globalThis
if (typeof self !== 'undefined') return self
if (typeof window !== 'undefined') return window
if (typeof global !== 'undefined') return global
throw 'Unable to locate global object'
})()
const atob: (b64: string) => string =
globalThis.atob ||
((b64) => globalThis.Buffer.from(b64, "base64").toString("binary"));
(b64 => globalThis.Buffer.from(b64, 'base64').toString('binary'))
function bytesFromBase64(b64: string): Uint8Array {
const bin = atob(b64);
const arr = new Uint8Array(bin.length);
const bin = atob(b64)
const arr = new Uint8Array(bin.length)
for (let i = 0; i < bin.length; ++i) {
arr[i] = bin.charCodeAt(i);
arr[i] = bin.charCodeAt(i)
}
return arr;
return arr
}
const btoa: (bin: string) => string =
globalThis.btoa ||
((bin) => globalThis.Buffer.from(bin, "binary").toString("base64"));
(bin => globalThis.Buffer.from(bin, 'binary').toString('base64'))
function base64FromBytes(arr: Uint8Array): string {
const bin: string[] = [];
const bin: string[] = []
for (const byte of arr) {
bin.push(String.fromCharCode(byte));
bin.push(String.fromCharCode(byte))
}
return btoa(bin.join(""));
return btoa(bin.join(''))
}
type Builtin =
@ -508,7 +506,7 @@ type Builtin =
| string
| number
| boolean
| undefined;
| undefined
export type DeepPartial<T> = T extends Builtin
? T
: T extends Array<infer U>
@ -517,16 +515,16 @@ export type DeepPartial<T> = T extends Builtin
? ReadonlyArray<DeepPartial<U>>
: T extends {}
? { [K in keyof T]?: DeepPartial<T[K]> }
: Partial<T>;
: Partial<T>
function longToNumber(long: Long): number {
if (long.gt(Number.MAX_SAFE_INTEGER)) {
throw new globalThis.Error("Value is larger than Number.MAX_SAFE_INTEGER");
throw new globalThis.Error('Value is larger than Number.MAX_SAFE_INTEGER')
}
return long.toNumber();
return long.toNumber()
}
if (_m0.util.Long !== Long) {
_m0.util.Long = Long as any;
_m0.configure();
_m0.util.Long = Long as any
_m0.configure()
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,32 +1,32 @@
/* eslint-disable */
import Long from "long";
import _m0 from "protobufjs/minimal";
import Long from 'long'
import _m0 from 'protobufjs/minimal'
import {
MessageType,
messageTypeFromJSON,
messageTypeToJSON,
} from "../../communities/v1/enums";
} from '../../communities/v1/enums'
export const protobufPackage = "communities.v1";
export const protobufPackage = 'communities.v1'
export interface EmojiReaction {
/** clock Lamport timestamp of the chat message */
clock: number;
clock: number
/**
* chat_id the ID of the chat the message belongs to, for query efficiency the chat_id is stored in the db even though the
* target message also stores the chat_id
*/
chatId: string;
chatId: string
/** message_id the ID of the target message that the user wishes to react to */
messageId: string;
messageId: string
/** message_type is (somewhat confusingly) the ID of the type of chat the message belongs to */
messageType: MessageType;
messageType: MessageType
/** type the ID of the emoji the user wishes to react with */
type: EmojiReaction_Type;
type: EmojiReaction_Type
/** whether this is a rectraction of a previously sent emoji */
retracted: boolean;
retracted: boolean
/** Grant for organisation chat messages */
grant: Uint8Array;
grant: Uint8Array
}
export enum EmojiReaction_Type {
@ -43,62 +43,62 @@ export enum EmojiReaction_Type {
export function emojiReaction_TypeFromJSON(object: any): EmojiReaction_Type {
switch (object) {
case 0:
case "UNKNOWN_EMOJI_REACTION_TYPE":
return EmojiReaction_Type.UNKNOWN_EMOJI_REACTION_TYPE;
case 'UNKNOWN_EMOJI_REACTION_TYPE':
return EmojiReaction_Type.UNKNOWN_EMOJI_REACTION_TYPE
case 1:
case "LOVE":
return EmojiReaction_Type.LOVE;
case 'LOVE':
return EmojiReaction_Type.LOVE
case 2:
case "THUMBS_UP":
return EmojiReaction_Type.THUMBS_UP;
case 'THUMBS_UP':
return EmojiReaction_Type.THUMBS_UP
case 3:
case "THUMBS_DOWN":
return EmojiReaction_Type.THUMBS_DOWN;
case 'THUMBS_DOWN':
return EmojiReaction_Type.THUMBS_DOWN
case 4:
case "LAUGH":
return EmojiReaction_Type.LAUGH;
case 'LAUGH':
return EmojiReaction_Type.LAUGH
case 5:
case "SAD":
return EmojiReaction_Type.SAD;
case 'SAD':
return EmojiReaction_Type.SAD
case 6:
case "ANGRY":
return EmojiReaction_Type.ANGRY;
case 'ANGRY':
return EmojiReaction_Type.ANGRY
case -1:
case "UNRECOGNIZED":
case 'UNRECOGNIZED':
default:
return EmojiReaction_Type.UNRECOGNIZED;
return EmojiReaction_Type.UNRECOGNIZED
}
}
export function emojiReaction_TypeToJSON(object: EmojiReaction_Type): string {
switch (object) {
case EmojiReaction_Type.UNKNOWN_EMOJI_REACTION_TYPE:
return "UNKNOWN_EMOJI_REACTION_TYPE";
return 'UNKNOWN_EMOJI_REACTION_TYPE'
case EmojiReaction_Type.LOVE:
return "LOVE";
return 'LOVE'
case EmojiReaction_Type.THUMBS_UP:
return "THUMBS_UP";
return 'THUMBS_UP'
case EmojiReaction_Type.THUMBS_DOWN:
return "THUMBS_DOWN";
return 'THUMBS_DOWN'
case EmojiReaction_Type.LAUGH:
return "LAUGH";
return 'LAUGH'
case EmojiReaction_Type.SAD:
return "SAD";
return 'SAD'
case EmojiReaction_Type.ANGRY:
return "ANGRY";
return 'ANGRY'
default:
return "UNKNOWN";
return 'UNKNOWN'
}
}
const baseEmojiReaction: object = {
clock: 0,
chatId: "",
messageId: "",
chatId: '',
messageId: '',
messageType: 0,
type: 0,
retracted: false,
};
}
export const EmojiReaction = {
encode(
@ -106,195 +106,195 @@ export const EmojiReaction = {
writer: _m0.Writer = _m0.Writer.create()
): _m0.Writer {
if (message.clock !== 0) {
writer.uint32(8).uint64(message.clock);
writer.uint32(8).uint64(message.clock)
}
if (message.chatId !== "") {
writer.uint32(18).string(message.chatId);
if (message.chatId !== '') {
writer.uint32(18).string(message.chatId)
}
if (message.messageId !== "") {
writer.uint32(26).string(message.messageId);
if (message.messageId !== '') {
writer.uint32(26).string(message.messageId)
}
if (message.messageType !== 0) {
writer.uint32(32).int32(message.messageType);
writer.uint32(32).int32(message.messageType)
}
if (message.type !== 0) {
writer.uint32(40).int32(message.type);
writer.uint32(40).int32(message.type)
}
if (message.retracted === true) {
writer.uint32(48).bool(message.retracted);
writer.uint32(48).bool(message.retracted)
}
if (message.grant.length !== 0) {
writer.uint32(58).bytes(message.grant);
writer.uint32(58).bytes(message.grant)
}
return writer;
return writer
},
decode(input: _m0.Reader | Uint8Array, length?: number): EmojiReaction {
const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input);
let end = length === undefined ? reader.len : reader.pos + length;
const message = { ...baseEmojiReaction } as EmojiReaction;
message.grant = new Uint8Array();
const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input)
let end = length === undefined ? reader.len : reader.pos + length
const message = { ...baseEmojiReaction } as EmojiReaction
message.grant = new Uint8Array()
while (reader.pos < end) {
const tag = reader.uint32();
const tag = reader.uint32()
switch (tag >>> 3) {
case 1:
message.clock = longToNumber(reader.uint64() as Long);
break;
message.clock = longToNumber(reader.uint64() as Long)
break
case 2:
message.chatId = reader.string();
break;
message.chatId = reader.string()
break
case 3:
message.messageId = reader.string();
break;
message.messageId = reader.string()
break
case 4:
message.messageType = reader.int32() as any;
break;
message.messageType = reader.int32() as any
break
case 5:
message.type = reader.int32() as any;
break;
message.type = reader.int32() as any
break
case 6:
message.retracted = reader.bool();
break;
message.retracted = reader.bool()
break
case 7:
message.grant = reader.bytes();
break;
message.grant = reader.bytes()
break
default:
reader.skipType(tag & 7);
break;
reader.skipType(tag & 7)
break
}
}
return message;
return message
},
fromJSON(object: any): EmojiReaction {
const message = { ...baseEmojiReaction } as EmojiReaction;
message.grant = new Uint8Array();
const message = { ...baseEmojiReaction } as EmojiReaction
message.grant = new Uint8Array()
if (object.clock !== undefined && object.clock !== null) {
message.clock = Number(object.clock);
message.clock = Number(object.clock)
} else {
message.clock = 0;
message.clock = 0
}
if (object.chatId !== undefined && object.chatId !== null) {
message.chatId = String(object.chatId);
message.chatId = String(object.chatId)
} else {
message.chatId = "";
message.chatId = ''
}
if (object.messageId !== undefined && object.messageId !== null) {
message.messageId = String(object.messageId);
message.messageId = String(object.messageId)
} else {
message.messageId = "";
message.messageId = ''
}
if (object.messageType !== undefined && object.messageType !== null) {
message.messageType = messageTypeFromJSON(object.messageType);
message.messageType = messageTypeFromJSON(object.messageType)
} else {
message.messageType = 0;
message.messageType = 0
}
if (object.type !== undefined && object.type !== null) {
message.type = emojiReaction_TypeFromJSON(object.type);
message.type = emojiReaction_TypeFromJSON(object.type)
} else {
message.type = 0;
message.type = 0
}
if (object.retracted !== undefined && object.retracted !== null) {
message.retracted = Boolean(object.retracted);
message.retracted = Boolean(object.retracted)
} else {
message.retracted = false;
message.retracted = false
}
if (object.grant !== undefined && object.grant !== null) {
message.grant = bytesFromBase64(object.grant);
message.grant = bytesFromBase64(object.grant)
}
return message;
return message
},
toJSON(message: EmojiReaction): unknown {
const obj: any = {};
message.clock !== undefined && (obj.clock = message.clock);
message.chatId !== undefined && (obj.chatId = message.chatId);
message.messageId !== undefined && (obj.messageId = message.messageId);
const obj: any = {}
message.clock !== undefined && (obj.clock = message.clock)
message.chatId !== undefined && (obj.chatId = message.chatId)
message.messageId !== undefined && (obj.messageId = message.messageId)
message.messageType !== undefined &&
(obj.messageType = messageTypeToJSON(message.messageType));
(obj.messageType = messageTypeToJSON(message.messageType))
message.type !== undefined &&
(obj.type = emojiReaction_TypeToJSON(message.type));
message.retracted !== undefined && (obj.retracted = message.retracted);
(obj.type = emojiReaction_TypeToJSON(message.type))
message.retracted !== undefined && (obj.retracted = message.retracted)
message.grant !== undefined &&
(obj.grant = base64FromBytes(
message.grant !== undefined ? message.grant : new Uint8Array()
));
return obj;
))
return obj
},
fromPartial(object: DeepPartial<EmojiReaction>): EmojiReaction {
const message = { ...baseEmojiReaction } as EmojiReaction;
const message = { ...baseEmojiReaction } as EmojiReaction
if (object.clock !== undefined && object.clock !== null) {
message.clock = object.clock;
message.clock = object.clock
} else {
message.clock = 0;
message.clock = 0
}
if (object.chatId !== undefined && object.chatId !== null) {
message.chatId = object.chatId;
message.chatId = object.chatId
} else {
message.chatId = "";
message.chatId = ''
}
if (object.messageId !== undefined && object.messageId !== null) {
message.messageId = object.messageId;
message.messageId = object.messageId
} else {
message.messageId = "";
message.messageId = ''
}
if (object.messageType !== undefined && object.messageType !== null) {
message.messageType = object.messageType;
message.messageType = object.messageType
} else {
message.messageType = 0;
message.messageType = 0
}
if (object.type !== undefined && object.type !== null) {
message.type = object.type;
message.type = object.type
} else {
message.type = 0;
message.type = 0
}
if (object.retracted !== undefined && object.retracted !== null) {
message.retracted = object.retracted;
message.retracted = object.retracted
} else {
message.retracted = false;
message.retracted = false
}
if (object.grant !== undefined && object.grant !== null) {
message.grant = object.grant;
message.grant = object.grant
} else {
message.grant = new Uint8Array();
message.grant = new Uint8Array()
}
return message;
return message
},
};
}
declare var self: any | undefined;
declare var window: any | undefined;
declare var global: any | undefined;
declare var self: any | undefined
declare var window: any | undefined
declare var global: any | undefined
var globalThis: any = (() => {
if (typeof globalThis !== "undefined") return globalThis;
if (typeof self !== "undefined") return self;
if (typeof window !== "undefined") return window;
if (typeof global !== "undefined") return global;
throw "Unable to locate global object";
})();
if (typeof globalThis !== 'undefined') return globalThis
if (typeof self !== 'undefined') return self
if (typeof window !== 'undefined') return window
if (typeof global !== 'undefined') return global
throw 'Unable to locate global object'
})()
const atob: (b64: string) => string =
globalThis.atob ||
((b64) => globalThis.Buffer.from(b64, "base64").toString("binary"));
(b64 => globalThis.Buffer.from(b64, 'base64').toString('binary'))
function bytesFromBase64(b64: string): Uint8Array {
const bin = atob(b64);
const arr = new Uint8Array(bin.length);
const bin = atob(b64)
const arr = new Uint8Array(bin.length)
for (let i = 0; i < bin.length; ++i) {
arr[i] = bin.charCodeAt(i);
arr[i] = bin.charCodeAt(i)
}
return arr;
return arr
}
const btoa: (bin: string) => string =
globalThis.btoa ||
((bin) => globalThis.Buffer.from(bin, "binary").toString("base64"));
(bin => globalThis.Buffer.from(bin, 'binary').toString('base64'))
function base64FromBytes(arr: Uint8Array): string {
const bin: string[] = [];
const bin: string[] = []
for (const byte of arr) {
bin.push(String.fromCharCode(byte));
bin.push(String.fromCharCode(byte))
}
return btoa(bin.join(""));
return btoa(bin.join(''))
}
type Builtin =
@ -304,7 +304,7 @@ type Builtin =
| string
| number
| boolean
| undefined;
| undefined
export type DeepPartial<T> = T extends Builtin
? T
: T extends Array<infer U>
@ -313,16 +313,16 @@ export type DeepPartial<T> = T extends Builtin
? ReadonlyArray<DeepPartial<U>>
: T extends {}
? { [K in keyof T]?: DeepPartial<T[K]> }
: Partial<T>;
: Partial<T>
function longToNumber(long: Long): number {
if (long.gt(Number.MAX_SAFE_INTEGER)) {
throw new globalThis.Error("Value is larger than Number.MAX_SAFE_INTEGER");
throw new globalThis.Error('Value is larger than Number.MAX_SAFE_INTEGER')
}
return long.toNumber();
return long.toNumber()
}
if (_m0.util.Long !== Long) {
_m0.util.Long = Long as any;
_m0.configure();
_m0.util.Long = Long as any
_m0.configure()
}

View File

@ -1,8 +1,8 @@
/* eslint-disable */
import Long from "long";
import _m0 from "protobufjs/minimal";
import Long from 'long'
import _m0 from 'protobufjs/minimal'
export const protobufPackage = "communities.v1";
export const protobufPackage = 'communities.v1'
export enum MessageType {
MESSAGE_TYPE_UNKNOWN_UNSPECIFIED = 0,
@ -20,51 +20,51 @@ export enum MessageType {
export function messageTypeFromJSON(object: any): MessageType {
switch (object) {
case 0:
case "MESSAGE_TYPE_UNKNOWN_UNSPECIFIED":
return MessageType.MESSAGE_TYPE_UNKNOWN_UNSPECIFIED;
case 'MESSAGE_TYPE_UNKNOWN_UNSPECIFIED':
return MessageType.MESSAGE_TYPE_UNKNOWN_UNSPECIFIED
case 1:
case "MESSAGE_TYPE_ONE_TO_ONE":
return MessageType.MESSAGE_TYPE_ONE_TO_ONE;
case 'MESSAGE_TYPE_ONE_TO_ONE':
return MessageType.MESSAGE_TYPE_ONE_TO_ONE
case 2:
case "MESSAGE_TYPE_MESSAGE_TYPE_PUBLIC_GROUP":
return MessageType.MESSAGE_TYPE_MESSAGE_TYPE_PUBLIC_GROUP;
case 'MESSAGE_TYPE_MESSAGE_TYPE_PUBLIC_GROUP':
return MessageType.MESSAGE_TYPE_MESSAGE_TYPE_PUBLIC_GROUP
case 3:
case "MESSAGE_TYPE_PRIVATE_GROUP":
return MessageType.MESSAGE_TYPE_PRIVATE_GROUP;
case 'MESSAGE_TYPE_PRIVATE_GROUP':
return MessageType.MESSAGE_TYPE_PRIVATE_GROUP
case 4:
case "MESSAGE_TYPE_SYSTEM_MESSAGE_PRIVATE_GROUP":
return MessageType.MESSAGE_TYPE_SYSTEM_MESSAGE_PRIVATE_GROUP;
case 'MESSAGE_TYPE_SYSTEM_MESSAGE_PRIVATE_GROUP':
return MessageType.MESSAGE_TYPE_SYSTEM_MESSAGE_PRIVATE_GROUP
case 5:
case "MESSAGE_TYPE_COMMUNITY_CHAT":
return MessageType.MESSAGE_TYPE_COMMUNITY_CHAT;
case 'MESSAGE_TYPE_COMMUNITY_CHAT':
return MessageType.MESSAGE_TYPE_COMMUNITY_CHAT
case 6:
case "MESSAGE_TYPE_SYSTEM_MESSAGE_GAP":
return MessageType.MESSAGE_TYPE_SYSTEM_MESSAGE_GAP;
case 'MESSAGE_TYPE_SYSTEM_MESSAGE_GAP':
return MessageType.MESSAGE_TYPE_SYSTEM_MESSAGE_GAP
case -1:
case "UNRECOGNIZED":
case 'UNRECOGNIZED':
default:
return MessageType.UNRECOGNIZED;
return MessageType.UNRECOGNIZED
}
}
export function messageTypeToJSON(object: MessageType): string {
switch (object) {
case MessageType.MESSAGE_TYPE_UNKNOWN_UNSPECIFIED:
return "MESSAGE_TYPE_UNKNOWN_UNSPECIFIED";
return 'MESSAGE_TYPE_UNKNOWN_UNSPECIFIED'
case MessageType.MESSAGE_TYPE_ONE_TO_ONE:
return "MESSAGE_TYPE_ONE_TO_ONE";
return 'MESSAGE_TYPE_ONE_TO_ONE'
case MessageType.MESSAGE_TYPE_MESSAGE_TYPE_PUBLIC_GROUP:
return "MESSAGE_TYPE_MESSAGE_TYPE_PUBLIC_GROUP";
return 'MESSAGE_TYPE_MESSAGE_TYPE_PUBLIC_GROUP'
case MessageType.MESSAGE_TYPE_PRIVATE_GROUP:
return "MESSAGE_TYPE_PRIVATE_GROUP";
return 'MESSAGE_TYPE_PRIVATE_GROUP'
case MessageType.MESSAGE_TYPE_SYSTEM_MESSAGE_PRIVATE_GROUP:
return "MESSAGE_TYPE_SYSTEM_MESSAGE_PRIVATE_GROUP";
return 'MESSAGE_TYPE_SYSTEM_MESSAGE_PRIVATE_GROUP'
case MessageType.MESSAGE_TYPE_COMMUNITY_CHAT:
return "MESSAGE_TYPE_COMMUNITY_CHAT";
return 'MESSAGE_TYPE_COMMUNITY_CHAT'
case MessageType.MESSAGE_TYPE_SYSTEM_MESSAGE_GAP:
return "MESSAGE_TYPE_SYSTEM_MESSAGE_GAP";
return 'MESSAGE_TYPE_SYSTEM_MESSAGE_GAP'
default:
return "UNKNOWN";
return 'UNKNOWN'
}
}
@ -81,45 +81,45 @@ export enum ImageType {
export function imageTypeFromJSON(object: any): ImageType {
switch (object) {
case 0:
case "IMAGE_TYPE_UNKNOWN_UNSPECIFIED":
return ImageType.IMAGE_TYPE_UNKNOWN_UNSPECIFIED;
case 'IMAGE_TYPE_UNKNOWN_UNSPECIFIED':
return ImageType.IMAGE_TYPE_UNKNOWN_UNSPECIFIED
case 1:
case "IMAGE_TYPE_PNG":
return ImageType.IMAGE_TYPE_PNG;
case 'IMAGE_TYPE_PNG':
return ImageType.IMAGE_TYPE_PNG
case 2:
case "IMAGE_TYPE_JPEG":
return ImageType.IMAGE_TYPE_JPEG;
case 'IMAGE_TYPE_JPEG':
return ImageType.IMAGE_TYPE_JPEG
case 3:
case "IMAGE_TYPE_WEBP":
return ImageType.IMAGE_TYPE_WEBP;
case 'IMAGE_TYPE_WEBP':
return ImageType.IMAGE_TYPE_WEBP
case 4:
case "IMAGE_TYPE_GIF":
return ImageType.IMAGE_TYPE_GIF;
case 'IMAGE_TYPE_GIF':
return ImageType.IMAGE_TYPE_GIF
case -1:
case "UNRECOGNIZED":
case 'UNRECOGNIZED':
default:
return ImageType.UNRECOGNIZED;
return ImageType.UNRECOGNIZED
}
}
export function imageTypeToJSON(object: ImageType): string {
switch (object) {
case ImageType.IMAGE_TYPE_UNKNOWN_UNSPECIFIED:
return "IMAGE_TYPE_UNKNOWN_UNSPECIFIED";
return 'IMAGE_TYPE_UNKNOWN_UNSPECIFIED'
case ImageType.IMAGE_TYPE_PNG:
return "IMAGE_TYPE_PNG";
return 'IMAGE_TYPE_PNG'
case ImageType.IMAGE_TYPE_JPEG:
return "IMAGE_TYPE_JPEG";
return 'IMAGE_TYPE_JPEG'
case ImageType.IMAGE_TYPE_WEBP:
return "IMAGE_TYPE_WEBP";
return 'IMAGE_TYPE_WEBP'
case ImageType.IMAGE_TYPE_GIF:
return "IMAGE_TYPE_GIF";
return 'IMAGE_TYPE_GIF'
default:
return "UNKNOWN";
return 'UNKNOWN'
}
}
if (_m0.util.Long !== Long) {
_m0.util.Long = Long as any;
_m0.configure();
_m0.util.Long = Long as any
_m0.configure()
}

View File

@ -1,20 +1,20 @@
/* eslint-disable */
import Long from "long";
import _m0 from "protobufjs/minimal";
import { ChatMessage } from "../../communities/v1/chat_message";
import { EmojiReaction } from "../../communities/v1/emoji_reaction";
import Long from 'long'
import _m0 from 'protobufjs/minimal'
import { ChatMessage } from '../../communities/v1/chat_message'
import { EmojiReaction } from '../../communities/v1/emoji_reaction'
export const protobufPackage = "communities.v1";
export const protobufPackage = 'communities.v1'
export interface MembershipUpdateEvent {
/** Lamport timestamp of the event */
clock: number;
clock: number
/** List of public keys of objects of the action */
members: string[];
members: string[]
/** Name of the chat for the CHAT_CREATED/NAME_CHANGED event types */
name: string;
name: string
/** The type of the event */
type: MembershipUpdateEvent_EventType;
type: MembershipUpdateEvent_EventType
}
export enum MembershipUpdateEvent_EventType {
@ -34,33 +34,33 @@ export function membershipUpdateEvent_EventTypeFromJSON(
): MembershipUpdateEvent_EventType {
switch (object) {
case 0:
case "UNKNOWN":
return MembershipUpdateEvent_EventType.UNKNOWN;
case 'UNKNOWN':
return MembershipUpdateEvent_EventType.UNKNOWN
case 1:
case "CHAT_CREATED":
return MembershipUpdateEvent_EventType.CHAT_CREATED;
case 'CHAT_CREATED':
return MembershipUpdateEvent_EventType.CHAT_CREATED
case 2:
case "NAME_CHANGED":
return MembershipUpdateEvent_EventType.NAME_CHANGED;
case 'NAME_CHANGED':
return MembershipUpdateEvent_EventType.NAME_CHANGED
case 3:
case "MEMBERS_ADDED":
return MembershipUpdateEvent_EventType.MEMBERS_ADDED;
case 'MEMBERS_ADDED':
return MembershipUpdateEvent_EventType.MEMBERS_ADDED
case 4:
case "MEMBER_JOINED":
return MembershipUpdateEvent_EventType.MEMBER_JOINED;
case 'MEMBER_JOINED':
return MembershipUpdateEvent_EventType.MEMBER_JOINED
case 5:
case "MEMBER_REMOVED":
return MembershipUpdateEvent_EventType.MEMBER_REMOVED;
case 'MEMBER_REMOVED':
return MembershipUpdateEvent_EventType.MEMBER_REMOVED
case 6:
case "ADMINS_ADDED":
return MembershipUpdateEvent_EventType.ADMINS_ADDED;
case 'ADMINS_ADDED':
return MembershipUpdateEvent_EventType.ADMINS_ADDED
case 7:
case "ADMIN_REMOVED":
return MembershipUpdateEvent_EventType.ADMIN_REMOVED;
case 'ADMIN_REMOVED':
return MembershipUpdateEvent_EventType.ADMIN_REMOVED
case -1:
case "UNRECOGNIZED":
case 'UNRECOGNIZED':
default:
return MembershipUpdateEvent_EventType.UNRECOGNIZED;
return MembershipUpdateEvent_EventType.UNRECOGNIZED
}
}
@ -69,23 +69,23 @@ export function membershipUpdateEvent_EventTypeToJSON(
): string {
switch (object) {
case MembershipUpdateEvent_EventType.UNKNOWN:
return "UNKNOWN";
return 'UNKNOWN'
case MembershipUpdateEvent_EventType.CHAT_CREATED:
return "CHAT_CREATED";
return 'CHAT_CREATED'
case MembershipUpdateEvent_EventType.NAME_CHANGED:
return "NAME_CHANGED";
return 'NAME_CHANGED'
case MembershipUpdateEvent_EventType.MEMBERS_ADDED:
return "MEMBERS_ADDED";
return 'MEMBERS_ADDED'
case MembershipUpdateEvent_EventType.MEMBER_JOINED:
return "MEMBER_JOINED";
return 'MEMBER_JOINED'
case MembershipUpdateEvent_EventType.MEMBER_REMOVED:
return "MEMBER_REMOVED";
return 'MEMBER_REMOVED'
case MembershipUpdateEvent_EventType.ADMINS_ADDED:
return "ADMINS_ADDED";
return 'ADMINS_ADDED'
case MembershipUpdateEvent_EventType.ADMIN_REMOVED:
return "ADMIN_REMOVED";
return 'ADMIN_REMOVED'
default:
return "UNKNOWN";
return 'UNKNOWN'
}
}
@ -96,22 +96,22 @@ export function membershipUpdateEvent_EventTypeToJSON(
*/
export interface MembershipUpdateMessage {
/** The chat id of the private group chat */
chatId: string;
chatId: string
/**
* A list of events for this group chat, first x bytes are the signature, then is a
* protobuf encoded MembershipUpdateEvent
*/
events: Uint8Array[];
message: ChatMessage | undefined;
emojiReaction: EmojiReaction | undefined;
events: Uint8Array[]
message: ChatMessage | undefined
emojiReaction: EmojiReaction | undefined
}
const baseMembershipUpdateEvent: object = {
clock: 0,
members: "",
name: "",
members: '',
name: '',
type: 0,
};
}
export const MembershipUpdateEvent = {
encode(
@ -119,225 +119,225 @@ export const MembershipUpdateEvent = {
writer: _m0.Writer = _m0.Writer.create()
): _m0.Writer {
if (message.clock !== 0) {
writer.uint32(8).uint64(message.clock);
writer.uint32(8).uint64(message.clock)
}
for (const v of message.members) {
writer.uint32(18).string(v!);
writer.uint32(18).string(v!)
}
if (message.name !== "") {
writer.uint32(26).string(message.name);
if (message.name !== '') {
writer.uint32(26).string(message.name)
}
if (message.type !== 0) {
writer.uint32(32).int32(message.type);
writer.uint32(32).int32(message.type)
}
return writer;
return writer
},
decode(
input: _m0.Reader | Uint8Array,
length?: number
): MembershipUpdateEvent {
const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input);
let end = length === undefined ? reader.len : reader.pos + length;
const message = { ...baseMembershipUpdateEvent } as MembershipUpdateEvent;
message.members = [];
const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input)
let end = length === undefined ? reader.len : reader.pos + length
const message = { ...baseMembershipUpdateEvent } as MembershipUpdateEvent
message.members = []
while (reader.pos < end) {
const tag = reader.uint32();
const tag = reader.uint32()
switch (tag >>> 3) {
case 1:
message.clock = longToNumber(reader.uint64() as Long);
break;
message.clock = longToNumber(reader.uint64() as Long)
break
case 2:
message.members.push(reader.string());
break;
message.members.push(reader.string())
break
case 3:
message.name = reader.string();
break;
message.name = reader.string()
break
case 4:
message.type = reader.int32() as any;
break;
message.type = reader.int32() as any
break
default:
reader.skipType(tag & 7);
break;
reader.skipType(tag & 7)
break
}
}
return message;
return message
},
fromJSON(object: any): MembershipUpdateEvent {
const message = { ...baseMembershipUpdateEvent } as MembershipUpdateEvent;
message.members = [];
const message = { ...baseMembershipUpdateEvent } as MembershipUpdateEvent
message.members = []
if (object.clock !== undefined && object.clock !== null) {
message.clock = Number(object.clock);
message.clock = Number(object.clock)
} else {
message.clock = 0;
message.clock = 0
}
if (object.members !== undefined && object.members !== null) {
for (const e of object.members) {
message.members.push(String(e));
message.members.push(String(e))
}
}
if (object.name !== undefined && object.name !== null) {
message.name = String(object.name);
message.name = String(object.name)
} else {
message.name = "";
message.name = ''
}
if (object.type !== undefined && object.type !== null) {
message.type = membershipUpdateEvent_EventTypeFromJSON(object.type);
message.type = membershipUpdateEvent_EventTypeFromJSON(object.type)
} else {
message.type = 0;
message.type = 0
}
return message;
return message
},
toJSON(message: MembershipUpdateEvent): unknown {
const obj: any = {};
message.clock !== undefined && (obj.clock = message.clock);
const obj: any = {}
message.clock !== undefined && (obj.clock = message.clock)
if (message.members) {
obj.members = message.members.map((e) => e);
obj.members = message.members.map(e => e)
} else {
obj.members = [];
obj.members = []
}
message.name !== undefined && (obj.name = message.name);
message.name !== undefined && (obj.name = message.name)
message.type !== undefined &&
(obj.type = membershipUpdateEvent_EventTypeToJSON(message.type));
return obj;
(obj.type = membershipUpdateEvent_EventTypeToJSON(message.type))
return obj
},
fromPartial(
object: DeepPartial<MembershipUpdateEvent>
): MembershipUpdateEvent {
const message = { ...baseMembershipUpdateEvent } as MembershipUpdateEvent;
message.members = [];
const message = { ...baseMembershipUpdateEvent } as MembershipUpdateEvent
message.members = []
if (object.clock !== undefined && object.clock !== null) {
message.clock = object.clock;
message.clock = object.clock
} else {
message.clock = 0;
message.clock = 0
}
if (object.members !== undefined && object.members !== null) {
for (const e of object.members) {
message.members.push(e);
message.members.push(e)
}
}
if (object.name !== undefined && object.name !== null) {
message.name = object.name;
message.name = object.name
} else {
message.name = "";
message.name = ''
}
if (object.type !== undefined && object.type !== null) {
message.type = object.type;
message.type = object.type
} else {
message.type = 0;
message.type = 0
}
return message;
return message
},
};
}
const baseMembershipUpdateMessage: object = { chatId: "" };
const baseMembershipUpdateMessage: object = { chatId: '' }
export const MembershipUpdateMessage = {
encode(
message: MembershipUpdateMessage,
writer: _m0.Writer = _m0.Writer.create()
): _m0.Writer {
if (message.chatId !== "") {
writer.uint32(10).string(message.chatId);
if (message.chatId !== '') {
writer.uint32(10).string(message.chatId)
}
for (const v of message.events) {
writer.uint32(18).bytes(v!);
writer.uint32(18).bytes(v!)
}
if (message.message !== undefined) {
ChatMessage.encode(message.message, writer.uint32(26).fork()).ldelim();
ChatMessage.encode(message.message, writer.uint32(26).fork()).ldelim()
}
if (message.emojiReaction !== undefined) {
EmojiReaction.encode(
message.emojiReaction,
writer.uint32(34).fork()
).ldelim();
).ldelim()
}
return writer;
return writer
},
decode(
input: _m0.Reader | Uint8Array,
length?: number
): MembershipUpdateMessage {
const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input);
let end = length === undefined ? reader.len : reader.pos + length;
const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input)
let end = length === undefined ? reader.len : reader.pos + length
const message = {
...baseMembershipUpdateMessage,
} as MembershipUpdateMessage;
message.events = [];
} as MembershipUpdateMessage
message.events = []
while (reader.pos < end) {
const tag = reader.uint32();
const tag = reader.uint32()
switch (tag >>> 3) {
case 1:
message.chatId = reader.string();
break;
message.chatId = reader.string()
break
case 2:
message.events.push(reader.bytes());
break;
message.events.push(reader.bytes())
break
case 3:
message.message = ChatMessage.decode(reader, reader.uint32());
break;
message.message = ChatMessage.decode(reader, reader.uint32())
break
case 4:
message.emojiReaction = EmojiReaction.decode(reader, reader.uint32());
break;
message.emojiReaction = EmojiReaction.decode(reader, reader.uint32())
break
default:
reader.skipType(tag & 7);
break;
reader.skipType(tag & 7)
break
}
}
return message;
return message
},
fromJSON(object: any): MembershipUpdateMessage {
const message = {
...baseMembershipUpdateMessage,
} as MembershipUpdateMessage;
message.events = [];
} as MembershipUpdateMessage
message.events = []
if (object.chatId !== undefined && object.chatId !== null) {
message.chatId = String(object.chatId);
message.chatId = String(object.chatId)
} else {
message.chatId = "";
message.chatId = ''
}
if (object.events !== undefined && object.events !== null) {
for (const e of object.events) {
message.events.push(bytesFromBase64(e));
message.events.push(bytesFromBase64(e))
}
}
if (object.message !== undefined && object.message !== null) {
message.message = ChatMessage.fromJSON(object.message);
message.message = ChatMessage.fromJSON(object.message)
} else {
message.message = undefined;
message.message = undefined
}
if (object.emojiReaction !== undefined && object.emojiReaction !== null) {
message.emojiReaction = EmojiReaction.fromJSON(object.emojiReaction);
message.emojiReaction = EmojiReaction.fromJSON(object.emojiReaction)
} else {
message.emojiReaction = undefined;
message.emojiReaction = undefined
}
return message;
return message
},
toJSON(message: MembershipUpdateMessage): unknown {
const obj: any = {};
message.chatId !== undefined && (obj.chatId = message.chatId);
const obj: any = {}
message.chatId !== undefined && (obj.chatId = message.chatId)
if (message.events) {
obj.events = message.events.map((e) =>
obj.events = message.events.map(e =>
base64FromBytes(e !== undefined ? e : new Uint8Array())
);
)
} else {
obj.events = [];
obj.events = []
}
message.message !== undefined &&
(obj.message = message.message
? ChatMessage.toJSON(message.message)
: undefined);
: undefined)
message.emojiReaction !== undefined &&
(obj.emojiReaction = message.emojiReaction
? EmojiReaction.toJSON(message.emojiReaction)
: undefined);
return obj;
: undefined)
return obj
},
fromPartial(
@ -345,64 +345,64 @@ export const MembershipUpdateMessage = {
): MembershipUpdateMessage {
const message = {
...baseMembershipUpdateMessage,
} as MembershipUpdateMessage;
message.events = [];
} as MembershipUpdateMessage
message.events = []
if (object.chatId !== undefined && object.chatId !== null) {
message.chatId = object.chatId;
message.chatId = object.chatId
} else {
message.chatId = "";
message.chatId = ''
}
if (object.events !== undefined && object.events !== null) {
for (const e of object.events) {
message.events.push(e);
message.events.push(e)
}
}
if (object.message !== undefined && object.message !== null) {
message.message = ChatMessage.fromPartial(object.message);
message.message = ChatMessage.fromPartial(object.message)
} else {
message.message = undefined;
message.message = undefined
}
if (object.emojiReaction !== undefined && object.emojiReaction !== null) {
message.emojiReaction = EmojiReaction.fromPartial(object.emojiReaction);
message.emojiReaction = EmojiReaction.fromPartial(object.emojiReaction)
} else {
message.emojiReaction = undefined;
message.emojiReaction = undefined
}
return message;
return message
},
};
}
declare var self: any | undefined;
declare var window: any | undefined;
declare var global: any | undefined;
declare var self: any | undefined
declare var window: any | undefined
declare var global: any | undefined
var globalThis: any = (() => {
if (typeof globalThis !== "undefined") return globalThis;
if (typeof self !== "undefined") return self;
if (typeof window !== "undefined") return window;
if (typeof global !== "undefined") return global;
throw "Unable to locate global object";
})();
if (typeof globalThis !== 'undefined') return globalThis
if (typeof self !== 'undefined') return self
if (typeof window !== 'undefined') return window
if (typeof global !== 'undefined') return global
throw 'Unable to locate global object'
})()
const atob: (b64: string) => string =
globalThis.atob ||
((b64) => globalThis.Buffer.from(b64, "base64").toString("binary"));
(b64 => globalThis.Buffer.from(b64, 'base64').toString('binary'))
function bytesFromBase64(b64: string): Uint8Array {
const bin = atob(b64);
const arr = new Uint8Array(bin.length);
const bin = atob(b64)
const arr = new Uint8Array(bin.length)
for (let i = 0; i < bin.length; ++i) {
arr[i] = bin.charCodeAt(i);
arr[i] = bin.charCodeAt(i)
}
return arr;
return arr
}
const btoa: (bin: string) => string =
globalThis.btoa ||
((bin) => globalThis.Buffer.from(bin, "binary").toString("base64"));
(bin => globalThis.Buffer.from(bin, 'binary').toString('base64'))
function base64FromBytes(arr: Uint8Array): string {
const bin: string[] = [];
const bin: string[] = []
for (const byte of arr) {
bin.push(String.fromCharCode(byte));
bin.push(String.fromCharCode(byte))
}
return btoa(bin.join(""));
return btoa(bin.join(''))
}
type Builtin =
@ -412,7 +412,7 @@ type Builtin =
| string
| number
| boolean
| undefined;
| undefined
export type DeepPartial<T> = T extends Builtin
? T
: T extends Array<infer U>
@ -421,16 +421,16 @@ export type DeepPartial<T> = T extends Builtin
? ReadonlyArray<DeepPartial<U>>
: T extends {}
? { [K in keyof T]?: DeepPartial<T[K]> }
: Partial<T>;
: Partial<T>
function longToNumber(long: Long): number {
if (long.gt(Number.MAX_SAFE_INTEGER)) {
throw new globalThis.Error("Value is larger than Number.MAX_SAFE_INTEGER");
throw new globalThis.Error('Value is larger than Number.MAX_SAFE_INTEGER')
}
return long.toNumber();
return long.toNumber()
}
if (_m0.util.Long !== Long) {
_m0.util.Long = Long as any;
_m0.configure();
_m0.util.Long = Long as any
_m0.configure()
}

View File

@ -1,8 +1,8 @@
/* eslint-disable */
import Long from "long";
import _m0 from "protobufjs/minimal";
import Long from 'long'
import _m0 from 'protobufjs/minimal'
export const protobufPackage = "communities.v1";
export const protobufPackage = 'communities.v1'
/**
* Specs:
@ -18,9 +18,9 @@ export const protobufPackage = "communities.v1";
* Note: Only send pings if the user interacted with the app in the last x minutes.
*/
export interface StatusUpdate {
clock: number;
statusType: StatusUpdate_StatusType;
customText: string;
clock: number
statusType: StatusUpdate_StatusType
customText: string
}
export enum StatusUpdate_StatusType {
@ -37,24 +37,24 @@ export function statusUpdate_StatusTypeFromJSON(
): StatusUpdate_StatusType {
switch (object) {
case 0:
case "UNKNOWN_STATUS_TYPE":
return StatusUpdate_StatusType.UNKNOWN_STATUS_TYPE;
case 'UNKNOWN_STATUS_TYPE':
return StatusUpdate_StatusType.UNKNOWN_STATUS_TYPE
case 1:
case "AUTOMATIC":
return StatusUpdate_StatusType.AUTOMATIC;
case 'AUTOMATIC':
return StatusUpdate_StatusType.AUTOMATIC
case 2:
case "DO_NOT_DISTURB":
return StatusUpdate_StatusType.DO_NOT_DISTURB;
case 'DO_NOT_DISTURB':
return StatusUpdate_StatusType.DO_NOT_DISTURB
case 3:
case "ALWAYS_ONLINE":
return StatusUpdate_StatusType.ALWAYS_ONLINE;
case 'ALWAYS_ONLINE':
return StatusUpdate_StatusType.ALWAYS_ONLINE
case 4:
case "INACTIVE":
return StatusUpdate_StatusType.INACTIVE;
case 'INACTIVE':
return StatusUpdate_StatusType.INACTIVE
case -1:
case "UNRECOGNIZED":
case 'UNRECOGNIZED':
default:
return StatusUpdate_StatusType.UNRECOGNIZED;
return StatusUpdate_StatusType.UNRECOGNIZED
}
}
@ -63,21 +63,21 @@ export function statusUpdate_StatusTypeToJSON(
): string {
switch (object) {
case StatusUpdate_StatusType.UNKNOWN_STATUS_TYPE:
return "UNKNOWN_STATUS_TYPE";
return 'UNKNOWN_STATUS_TYPE'
case StatusUpdate_StatusType.AUTOMATIC:
return "AUTOMATIC";
return 'AUTOMATIC'
case StatusUpdate_StatusType.DO_NOT_DISTURB:
return "DO_NOT_DISTURB";
return 'DO_NOT_DISTURB'
case StatusUpdate_StatusType.ALWAYS_ONLINE:
return "ALWAYS_ONLINE";
return 'ALWAYS_ONLINE'
case StatusUpdate_StatusType.INACTIVE:
return "INACTIVE";
return 'INACTIVE'
default:
return "UNKNOWN";
return 'UNKNOWN'
}
}
const baseStatusUpdate: object = { clock: 0, statusType: 0, customText: "" };
const baseStatusUpdate: object = { clock: 0, statusType: 0, customText: '' }
export const StatusUpdate = {
encode(
@ -85,101 +85,101 @@ export const StatusUpdate = {
writer: _m0.Writer = _m0.Writer.create()
): _m0.Writer {
if (message.clock !== 0) {
writer.uint32(8).uint64(message.clock);
writer.uint32(8).uint64(message.clock)
}
if (message.statusType !== 0) {
writer.uint32(16).int32(message.statusType);
writer.uint32(16).int32(message.statusType)
}
if (message.customText !== "") {
writer.uint32(26).string(message.customText);
if (message.customText !== '') {
writer.uint32(26).string(message.customText)
}
return writer;
return writer
},
decode(input: _m0.Reader | Uint8Array, length?: number): StatusUpdate {
const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input);
let end = length === undefined ? reader.len : reader.pos + length;
const message = { ...baseStatusUpdate } as StatusUpdate;
const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input)
let end = length === undefined ? reader.len : reader.pos + length
const message = { ...baseStatusUpdate } as StatusUpdate
while (reader.pos < end) {
const tag = reader.uint32();
const tag = reader.uint32()
switch (tag >>> 3) {
case 1:
message.clock = longToNumber(reader.uint64() as Long);
break;
message.clock = longToNumber(reader.uint64() as Long)
break
case 2:
message.statusType = reader.int32() as any;
break;
message.statusType = reader.int32() as any
break
case 3:
message.customText = reader.string();
break;
message.customText = reader.string()
break
default:
reader.skipType(tag & 7);
break;
reader.skipType(tag & 7)
break
}
}
return message;
return message
},
fromJSON(object: any): StatusUpdate {
const message = { ...baseStatusUpdate } as StatusUpdate;
const message = { ...baseStatusUpdate } as StatusUpdate
if (object.clock !== undefined && object.clock !== null) {
message.clock = Number(object.clock);
message.clock = Number(object.clock)
} else {
message.clock = 0;
message.clock = 0
}
if (object.statusType !== undefined && object.statusType !== null) {
message.statusType = statusUpdate_StatusTypeFromJSON(object.statusType);
message.statusType = statusUpdate_StatusTypeFromJSON(object.statusType)
} else {
message.statusType = 0;
message.statusType = 0
}
if (object.customText !== undefined && object.customText !== null) {
message.customText = String(object.customText);
message.customText = String(object.customText)
} else {
message.customText = "";
message.customText = ''
}
return message;
return message
},
toJSON(message: StatusUpdate): unknown {
const obj: any = {};
message.clock !== undefined && (obj.clock = message.clock);
const obj: any = {}
message.clock !== undefined && (obj.clock = message.clock)
message.statusType !== undefined &&
(obj.statusType = statusUpdate_StatusTypeToJSON(message.statusType));
message.customText !== undefined && (obj.customText = message.customText);
return obj;
(obj.statusType = statusUpdate_StatusTypeToJSON(message.statusType))
message.customText !== undefined && (obj.customText = message.customText)
return obj
},
fromPartial(object: DeepPartial<StatusUpdate>): StatusUpdate {
const message = { ...baseStatusUpdate } as StatusUpdate;
const message = { ...baseStatusUpdate } as StatusUpdate
if (object.clock !== undefined && object.clock !== null) {
message.clock = object.clock;
message.clock = object.clock
} else {
message.clock = 0;
message.clock = 0
}
if (object.statusType !== undefined && object.statusType !== null) {
message.statusType = object.statusType;
message.statusType = object.statusType
} else {
message.statusType = 0;
message.statusType = 0
}
if (object.customText !== undefined && object.customText !== null) {
message.customText = object.customText;
message.customText = object.customText
} else {
message.customText = "";
message.customText = ''
}
return message;
return message
},
};
}
declare var self: any | undefined;
declare var window: any | undefined;
declare var global: any | undefined;
declare var self: any | undefined
declare var window: any | undefined
declare var global: any | undefined
var globalThis: any = (() => {
if (typeof globalThis !== "undefined") return globalThis;
if (typeof self !== "undefined") return self;
if (typeof window !== "undefined") return window;
if (typeof global !== "undefined") return global;
throw "Unable to locate global object";
})();
if (typeof globalThis !== 'undefined') return globalThis
if (typeof self !== 'undefined') return self
if (typeof window !== 'undefined') return window
if (typeof global !== 'undefined') return global
throw 'Unable to locate global object'
})()
type Builtin =
| Date
@ -188,7 +188,7 @@ type Builtin =
| string
| number
| boolean
| undefined;
| undefined
export type DeepPartial<T> = T extends Builtin
? T
: T extends Array<infer U>
@ -197,16 +197,16 @@ export type DeepPartial<T> = T extends Builtin
? ReadonlyArray<DeepPartial<U>>
: T extends {}
? { [K in keyof T]?: DeepPartial<T[K]> }
: Partial<T>;
: Partial<T>
function longToNumber(long: Long): number {
if (long.gt(Number.MAX_SAFE_INTEGER)) {
throw new globalThis.Error("Value is larger than Number.MAX_SAFE_INTEGER");
throw new globalThis.Error('Value is larger than Number.MAX_SAFE_INTEGER')
}
return long.toNumber();
return long.toNumber()
}
if (_m0.util.Long !== Long) {
_m0.util.Long = Long as any;
_m0.configure();
_m0.util.Long = Long as any
_m0.configure()
}

View File

@ -1,16 +1,16 @@
/* eslint-disable */
import Long from "long";
import _m0 from "protobufjs/minimal";
import Long from 'long'
import _m0 from 'protobufjs/minimal'
export const protobufPackage = "status.v1";
export const protobufPackage = 'status.v1'
export interface ApplicationMetadataMessage {
/** Signature of the payload field */
signature: Uint8Array;
signature: Uint8Array
/** This is the encoded protobuf of the application level message, i.e ChatMessage */
payload: Uint8Array;
payload: Uint8Array
/** The type of protobuf message sent */
type: ApplicationMetadataMessage_Type;
type: ApplicationMetadataMessage_Type
}
export enum ApplicationMetadataMessage_Type {
@ -56,111 +56,111 @@ export function applicationMetadataMessage_TypeFromJSON(
): ApplicationMetadataMessage_Type {
switch (object) {
case 0:
case "TYPE_UNKNOWN_UNSPECIFIED":
return ApplicationMetadataMessage_Type.TYPE_UNKNOWN_UNSPECIFIED;
case 'TYPE_UNKNOWN_UNSPECIFIED':
return ApplicationMetadataMessage_Type.TYPE_UNKNOWN_UNSPECIFIED
case 1:
case "TYPE_CHAT_MESSAGE":
return ApplicationMetadataMessage_Type.TYPE_CHAT_MESSAGE;
case 'TYPE_CHAT_MESSAGE':
return ApplicationMetadataMessage_Type.TYPE_CHAT_MESSAGE
case 2:
case "TYPE_CONTACT_UPDATE":
return ApplicationMetadataMessage_Type.TYPE_CONTACT_UPDATE;
case 'TYPE_CONTACT_UPDATE':
return ApplicationMetadataMessage_Type.TYPE_CONTACT_UPDATE
case 3:
case "TYPE_MEMBERSHIP_UPDATE_MESSAGE":
return ApplicationMetadataMessage_Type.TYPE_MEMBERSHIP_UPDATE_MESSAGE;
case 'TYPE_MEMBERSHIP_UPDATE_MESSAGE':
return ApplicationMetadataMessage_Type.TYPE_MEMBERSHIP_UPDATE_MESSAGE
case 4:
case "TYPE_PAIR_INSTALLATION":
return ApplicationMetadataMessage_Type.TYPE_PAIR_INSTALLATION;
case 'TYPE_PAIR_INSTALLATION':
return ApplicationMetadataMessage_Type.TYPE_PAIR_INSTALLATION
case 5:
case "TYPE_SYNC_INSTALLATION":
return ApplicationMetadataMessage_Type.TYPE_SYNC_INSTALLATION;
case 'TYPE_SYNC_INSTALLATION':
return ApplicationMetadataMessage_Type.TYPE_SYNC_INSTALLATION
case 6:
case "TYPE_REQUEST_ADDRESS_FOR_TRANSACTION":
return ApplicationMetadataMessage_Type.TYPE_REQUEST_ADDRESS_FOR_TRANSACTION;
case 'TYPE_REQUEST_ADDRESS_FOR_TRANSACTION':
return ApplicationMetadataMessage_Type.TYPE_REQUEST_ADDRESS_FOR_TRANSACTION
case 7:
case "TYPE_ACCEPT_REQUEST_ADDRESS_FOR_TRANSACTION":
return ApplicationMetadataMessage_Type.TYPE_ACCEPT_REQUEST_ADDRESS_FOR_TRANSACTION;
case 'TYPE_ACCEPT_REQUEST_ADDRESS_FOR_TRANSACTION':
return ApplicationMetadataMessage_Type.TYPE_ACCEPT_REQUEST_ADDRESS_FOR_TRANSACTION
case 8:
case "TYPE_DECLINE_REQUEST_ADDRESS_FOR_TRANSACTION":
return ApplicationMetadataMessage_Type.TYPE_DECLINE_REQUEST_ADDRESS_FOR_TRANSACTION;
case 'TYPE_DECLINE_REQUEST_ADDRESS_FOR_TRANSACTION':
return ApplicationMetadataMessage_Type.TYPE_DECLINE_REQUEST_ADDRESS_FOR_TRANSACTION
case 9:
case "TYPE_REQUEST_TRANSACTION":
return ApplicationMetadataMessage_Type.TYPE_REQUEST_TRANSACTION;
case 'TYPE_REQUEST_TRANSACTION':
return ApplicationMetadataMessage_Type.TYPE_REQUEST_TRANSACTION
case 10:
case "TYPE_SEND_TRANSACTION":
return ApplicationMetadataMessage_Type.TYPE_SEND_TRANSACTION;
case 'TYPE_SEND_TRANSACTION':
return ApplicationMetadataMessage_Type.TYPE_SEND_TRANSACTION
case 11:
case "TYPE_DECLINE_REQUEST_TRANSACTION":
return ApplicationMetadataMessage_Type.TYPE_DECLINE_REQUEST_TRANSACTION;
case 'TYPE_DECLINE_REQUEST_TRANSACTION':
return ApplicationMetadataMessage_Type.TYPE_DECLINE_REQUEST_TRANSACTION
case 12:
case "TYPE_SYNC_INSTALLATION_CONTACT":
return ApplicationMetadataMessage_Type.TYPE_SYNC_INSTALLATION_CONTACT;
case 'TYPE_SYNC_INSTALLATION_CONTACT':
return ApplicationMetadataMessage_Type.TYPE_SYNC_INSTALLATION_CONTACT
case 13:
case "TYPE_SYNC_INSTALLATION_ACCOUNT":
return ApplicationMetadataMessage_Type.TYPE_SYNC_INSTALLATION_ACCOUNT;
case 'TYPE_SYNC_INSTALLATION_ACCOUNT':
return ApplicationMetadataMessage_Type.TYPE_SYNC_INSTALLATION_ACCOUNT
case 14:
case "TYPE_SYNC_INSTALLATION_PUBLIC_CHAT":
return ApplicationMetadataMessage_Type.TYPE_SYNC_INSTALLATION_PUBLIC_CHAT;
case 'TYPE_SYNC_INSTALLATION_PUBLIC_CHAT':
return ApplicationMetadataMessage_Type.TYPE_SYNC_INSTALLATION_PUBLIC_CHAT
case 15:
case "TYPE_CONTACT_CODE_ADVERTISEMENT":
return ApplicationMetadataMessage_Type.TYPE_CONTACT_CODE_ADVERTISEMENT;
case 'TYPE_CONTACT_CODE_ADVERTISEMENT':
return ApplicationMetadataMessage_Type.TYPE_CONTACT_CODE_ADVERTISEMENT
case 16:
case "TYPE_PUSH_NOTIFICATION_REGISTRATION":
return ApplicationMetadataMessage_Type.TYPE_PUSH_NOTIFICATION_REGISTRATION;
case 'TYPE_PUSH_NOTIFICATION_REGISTRATION':
return ApplicationMetadataMessage_Type.TYPE_PUSH_NOTIFICATION_REGISTRATION
case 17:
case "TYPE_PUSH_NOTIFICATION_REGISTRATION_RESPONSE":
return ApplicationMetadataMessage_Type.TYPE_PUSH_NOTIFICATION_REGISTRATION_RESPONSE;
case 'TYPE_PUSH_NOTIFICATION_REGISTRATION_RESPONSE':
return ApplicationMetadataMessage_Type.TYPE_PUSH_NOTIFICATION_REGISTRATION_RESPONSE
case 18:
case "TYPE_PUSH_NOTIFICATION_QUERY":
return ApplicationMetadataMessage_Type.TYPE_PUSH_NOTIFICATION_QUERY;
case 'TYPE_PUSH_NOTIFICATION_QUERY':
return ApplicationMetadataMessage_Type.TYPE_PUSH_NOTIFICATION_QUERY
case 19:
case "TYPE_PUSH_NOTIFICATION_QUERY_RESPONSE":
return ApplicationMetadataMessage_Type.TYPE_PUSH_NOTIFICATION_QUERY_RESPONSE;
case 'TYPE_PUSH_NOTIFICATION_QUERY_RESPONSE':
return ApplicationMetadataMessage_Type.TYPE_PUSH_NOTIFICATION_QUERY_RESPONSE
case 20:
case "TYPE_PUSH_NOTIFICATION_REQUEST":
return ApplicationMetadataMessage_Type.TYPE_PUSH_NOTIFICATION_REQUEST;
case 'TYPE_PUSH_NOTIFICATION_REQUEST':
return ApplicationMetadataMessage_Type.TYPE_PUSH_NOTIFICATION_REQUEST
case 21:
case "TYPE_PUSH_NOTIFICATION_RESPONSE":
return ApplicationMetadataMessage_Type.TYPE_PUSH_NOTIFICATION_RESPONSE;
case 'TYPE_PUSH_NOTIFICATION_RESPONSE':
return ApplicationMetadataMessage_Type.TYPE_PUSH_NOTIFICATION_RESPONSE
case 22:
case "TYPE_EMOJI_REACTION":
return ApplicationMetadataMessage_Type.TYPE_EMOJI_REACTION;
case 'TYPE_EMOJI_REACTION':
return ApplicationMetadataMessage_Type.TYPE_EMOJI_REACTION
case 23:
case "TYPE_GROUP_CHAT_INVITATION":
return ApplicationMetadataMessage_Type.TYPE_GROUP_CHAT_INVITATION;
case 'TYPE_GROUP_CHAT_INVITATION':
return ApplicationMetadataMessage_Type.TYPE_GROUP_CHAT_INVITATION
case 24:
case "TYPE_CHAT_IDENTITY":
return ApplicationMetadataMessage_Type.TYPE_CHAT_IDENTITY;
case 'TYPE_CHAT_IDENTITY':
return ApplicationMetadataMessage_Type.TYPE_CHAT_IDENTITY
case 25:
case "TYPE_COMMUNITY_DESCRIPTION":
return ApplicationMetadataMessage_Type.TYPE_COMMUNITY_DESCRIPTION;
case 'TYPE_COMMUNITY_DESCRIPTION':
return ApplicationMetadataMessage_Type.TYPE_COMMUNITY_DESCRIPTION
case 26:
case "TYPE_COMMUNITY_INVITATION":
return ApplicationMetadataMessage_Type.TYPE_COMMUNITY_INVITATION;
case 'TYPE_COMMUNITY_INVITATION':
return ApplicationMetadataMessage_Type.TYPE_COMMUNITY_INVITATION
case 27:
case "TYPE_COMMUNITY_REQUEST_TO_JOIN":
return ApplicationMetadataMessage_Type.TYPE_COMMUNITY_REQUEST_TO_JOIN;
case 'TYPE_COMMUNITY_REQUEST_TO_JOIN':
return ApplicationMetadataMessage_Type.TYPE_COMMUNITY_REQUEST_TO_JOIN
case 28:
case "TYPE_PIN_MESSAGE":
return ApplicationMetadataMessage_Type.TYPE_PIN_MESSAGE;
case 'TYPE_PIN_MESSAGE':
return ApplicationMetadataMessage_Type.TYPE_PIN_MESSAGE
case 29:
case "TYPE_EDIT_MESSAGE":
return ApplicationMetadataMessage_Type.TYPE_EDIT_MESSAGE;
case 'TYPE_EDIT_MESSAGE':
return ApplicationMetadataMessage_Type.TYPE_EDIT_MESSAGE
case 30:
case "TYPE_STATUS_UPDATE":
return ApplicationMetadataMessage_Type.TYPE_STATUS_UPDATE;
case 'TYPE_STATUS_UPDATE':
return ApplicationMetadataMessage_Type.TYPE_STATUS_UPDATE
case 31:
case "TYPE_DELETE_MESSAGE":
return ApplicationMetadataMessage_Type.TYPE_DELETE_MESSAGE;
case 'TYPE_DELETE_MESSAGE':
return ApplicationMetadataMessage_Type.TYPE_DELETE_MESSAGE
case 32:
case "TYPE_SYNC_INSTALLATION_COMMUNITY":
return ApplicationMetadataMessage_Type.TYPE_SYNC_INSTALLATION_COMMUNITY;
case 'TYPE_SYNC_INSTALLATION_COMMUNITY':
return ApplicationMetadataMessage_Type.TYPE_SYNC_INSTALLATION_COMMUNITY
case 33:
case "TYPE_ANONYMOUS_METRIC_BATCH":
return ApplicationMetadataMessage_Type.TYPE_ANONYMOUS_METRIC_BATCH;
case 'TYPE_ANONYMOUS_METRIC_BATCH':
return ApplicationMetadataMessage_Type.TYPE_ANONYMOUS_METRIC_BATCH
case -1:
case "UNRECOGNIZED":
case 'UNRECOGNIZED':
default:
return ApplicationMetadataMessage_Type.UNRECOGNIZED;
return ApplicationMetadataMessage_Type.UNRECOGNIZED
}
}
@ -169,79 +169,79 @@ export function applicationMetadataMessage_TypeToJSON(
): string {
switch (object) {
case ApplicationMetadataMessage_Type.TYPE_UNKNOWN_UNSPECIFIED:
return "TYPE_UNKNOWN_UNSPECIFIED";
return 'TYPE_UNKNOWN_UNSPECIFIED'
case ApplicationMetadataMessage_Type.TYPE_CHAT_MESSAGE:
return "TYPE_CHAT_MESSAGE";
return 'TYPE_CHAT_MESSAGE'
case ApplicationMetadataMessage_Type.TYPE_CONTACT_UPDATE:
return "TYPE_CONTACT_UPDATE";
return 'TYPE_CONTACT_UPDATE'
case ApplicationMetadataMessage_Type.TYPE_MEMBERSHIP_UPDATE_MESSAGE:
return "TYPE_MEMBERSHIP_UPDATE_MESSAGE";
return 'TYPE_MEMBERSHIP_UPDATE_MESSAGE'
case ApplicationMetadataMessage_Type.TYPE_PAIR_INSTALLATION:
return "TYPE_PAIR_INSTALLATION";
return 'TYPE_PAIR_INSTALLATION'
case ApplicationMetadataMessage_Type.TYPE_SYNC_INSTALLATION:
return "TYPE_SYNC_INSTALLATION";
return 'TYPE_SYNC_INSTALLATION'
case ApplicationMetadataMessage_Type.TYPE_REQUEST_ADDRESS_FOR_TRANSACTION:
return "TYPE_REQUEST_ADDRESS_FOR_TRANSACTION";
return 'TYPE_REQUEST_ADDRESS_FOR_TRANSACTION'
case ApplicationMetadataMessage_Type.TYPE_ACCEPT_REQUEST_ADDRESS_FOR_TRANSACTION:
return "TYPE_ACCEPT_REQUEST_ADDRESS_FOR_TRANSACTION";
return 'TYPE_ACCEPT_REQUEST_ADDRESS_FOR_TRANSACTION'
case ApplicationMetadataMessage_Type.TYPE_DECLINE_REQUEST_ADDRESS_FOR_TRANSACTION:
return "TYPE_DECLINE_REQUEST_ADDRESS_FOR_TRANSACTION";
return 'TYPE_DECLINE_REQUEST_ADDRESS_FOR_TRANSACTION'
case ApplicationMetadataMessage_Type.TYPE_REQUEST_TRANSACTION:
return "TYPE_REQUEST_TRANSACTION";
return 'TYPE_REQUEST_TRANSACTION'
case ApplicationMetadataMessage_Type.TYPE_SEND_TRANSACTION:
return "TYPE_SEND_TRANSACTION";
return 'TYPE_SEND_TRANSACTION'
case ApplicationMetadataMessage_Type.TYPE_DECLINE_REQUEST_TRANSACTION:
return "TYPE_DECLINE_REQUEST_TRANSACTION";
return 'TYPE_DECLINE_REQUEST_TRANSACTION'
case ApplicationMetadataMessage_Type.TYPE_SYNC_INSTALLATION_CONTACT:
return "TYPE_SYNC_INSTALLATION_CONTACT";
return 'TYPE_SYNC_INSTALLATION_CONTACT'
case ApplicationMetadataMessage_Type.TYPE_SYNC_INSTALLATION_ACCOUNT:
return "TYPE_SYNC_INSTALLATION_ACCOUNT";
return 'TYPE_SYNC_INSTALLATION_ACCOUNT'
case ApplicationMetadataMessage_Type.TYPE_SYNC_INSTALLATION_PUBLIC_CHAT:
return "TYPE_SYNC_INSTALLATION_PUBLIC_CHAT";
return 'TYPE_SYNC_INSTALLATION_PUBLIC_CHAT'
case ApplicationMetadataMessage_Type.TYPE_CONTACT_CODE_ADVERTISEMENT:
return "TYPE_CONTACT_CODE_ADVERTISEMENT";
return 'TYPE_CONTACT_CODE_ADVERTISEMENT'
case ApplicationMetadataMessage_Type.TYPE_PUSH_NOTIFICATION_REGISTRATION:
return "TYPE_PUSH_NOTIFICATION_REGISTRATION";
return 'TYPE_PUSH_NOTIFICATION_REGISTRATION'
case ApplicationMetadataMessage_Type.TYPE_PUSH_NOTIFICATION_REGISTRATION_RESPONSE:
return "TYPE_PUSH_NOTIFICATION_REGISTRATION_RESPONSE";
return 'TYPE_PUSH_NOTIFICATION_REGISTRATION_RESPONSE'
case ApplicationMetadataMessage_Type.TYPE_PUSH_NOTIFICATION_QUERY:
return "TYPE_PUSH_NOTIFICATION_QUERY";
return 'TYPE_PUSH_NOTIFICATION_QUERY'
case ApplicationMetadataMessage_Type.TYPE_PUSH_NOTIFICATION_QUERY_RESPONSE:
return "TYPE_PUSH_NOTIFICATION_QUERY_RESPONSE";
return 'TYPE_PUSH_NOTIFICATION_QUERY_RESPONSE'
case ApplicationMetadataMessage_Type.TYPE_PUSH_NOTIFICATION_REQUEST:
return "TYPE_PUSH_NOTIFICATION_REQUEST";
return 'TYPE_PUSH_NOTIFICATION_REQUEST'
case ApplicationMetadataMessage_Type.TYPE_PUSH_NOTIFICATION_RESPONSE:
return "TYPE_PUSH_NOTIFICATION_RESPONSE";
return 'TYPE_PUSH_NOTIFICATION_RESPONSE'
case ApplicationMetadataMessage_Type.TYPE_EMOJI_REACTION:
return "TYPE_EMOJI_REACTION";
return 'TYPE_EMOJI_REACTION'
case ApplicationMetadataMessage_Type.TYPE_GROUP_CHAT_INVITATION:
return "TYPE_GROUP_CHAT_INVITATION";
return 'TYPE_GROUP_CHAT_INVITATION'
case ApplicationMetadataMessage_Type.TYPE_CHAT_IDENTITY:
return "TYPE_CHAT_IDENTITY";
return 'TYPE_CHAT_IDENTITY'
case ApplicationMetadataMessage_Type.TYPE_COMMUNITY_DESCRIPTION:
return "TYPE_COMMUNITY_DESCRIPTION";
return 'TYPE_COMMUNITY_DESCRIPTION'
case ApplicationMetadataMessage_Type.TYPE_COMMUNITY_INVITATION:
return "TYPE_COMMUNITY_INVITATION";
return 'TYPE_COMMUNITY_INVITATION'
case ApplicationMetadataMessage_Type.TYPE_COMMUNITY_REQUEST_TO_JOIN:
return "TYPE_COMMUNITY_REQUEST_TO_JOIN";
return 'TYPE_COMMUNITY_REQUEST_TO_JOIN'
case ApplicationMetadataMessage_Type.TYPE_PIN_MESSAGE:
return "TYPE_PIN_MESSAGE";
return 'TYPE_PIN_MESSAGE'
case ApplicationMetadataMessage_Type.TYPE_EDIT_MESSAGE:
return "TYPE_EDIT_MESSAGE";
return 'TYPE_EDIT_MESSAGE'
case ApplicationMetadataMessage_Type.TYPE_STATUS_UPDATE:
return "TYPE_STATUS_UPDATE";
return 'TYPE_STATUS_UPDATE'
case ApplicationMetadataMessage_Type.TYPE_DELETE_MESSAGE:
return "TYPE_DELETE_MESSAGE";
return 'TYPE_DELETE_MESSAGE'
case ApplicationMetadataMessage_Type.TYPE_SYNC_INSTALLATION_COMMUNITY:
return "TYPE_SYNC_INSTALLATION_COMMUNITY";
return 'TYPE_SYNC_INSTALLATION_COMMUNITY'
case ApplicationMetadataMessage_Type.TYPE_ANONYMOUS_METRIC_BATCH:
return "TYPE_ANONYMOUS_METRIC_BATCH";
return 'TYPE_ANONYMOUS_METRIC_BATCH'
default:
return "UNKNOWN";
return 'UNKNOWN'
}
}
const baseApplicationMetadataMessage: object = { type: 0 };
const baseApplicationMetadataMessage: object = { type: 0 }
export const ApplicationMetadataMessage = {
encode(
@ -249,81 +249,81 @@ export const ApplicationMetadataMessage = {
writer: _m0.Writer = _m0.Writer.create()
): _m0.Writer {
if (message.signature.length !== 0) {
writer.uint32(10).bytes(message.signature);
writer.uint32(10).bytes(message.signature)
}
if (message.payload.length !== 0) {
writer.uint32(18).bytes(message.payload);
writer.uint32(18).bytes(message.payload)
}
if (message.type !== 0) {
writer.uint32(24).int32(message.type);
writer.uint32(24).int32(message.type)
}
return writer;
return writer
},
decode(
input: _m0.Reader | Uint8Array,
length?: number
): ApplicationMetadataMessage {
const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input);
let end = length === undefined ? reader.len : reader.pos + length;
const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input)
let end = length === undefined ? reader.len : reader.pos + length
const message = {
...baseApplicationMetadataMessage,
} as ApplicationMetadataMessage;
message.signature = new Uint8Array();
message.payload = new Uint8Array();
} as ApplicationMetadataMessage
message.signature = new Uint8Array()
message.payload = new Uint8Array()
while (reader.pos < end) {
const tag = reader.uint32();
const tag = reader.uint32()
switch (tag >>> 3) {
case 1:
message.signature = reader.bytes();
break;
message.signature = reader.bytes()
break
case 2:
message.payload = reader.bytes();
break;
message.payload = reader.bytes()
break
case 3:
message.type = reader.int32() as any;
break;
message.type = reader.int32() as any
break
default:
reader.skipType(tag & 7);
break;
reader.skipType(tag & 7)
break
}
}
return message;
return message
},
fromJSON(object: any): ApplicationMetadataMessage {
const message = {
...baseApplicationMetadataMessage,
} as ApplicationMetadataMessage;
message.signature = new Uint8Array();
message.payload = new Uint8Array();
} as ApplicationMetadataMessage
message.signature = new Uint8Array()
message.payload = new Uint8Array()
if (object.signature !== undefined && object.signature !== null) {
message.signature = bytesFromBase64(object.signature);
message.signature = bytesFromBase64(object.signature)
}
if (object.payload !== undefined && object.payload !== null) {
message.payload = bytesFromBase64(object.payload);
message.payload = bytesFromBase64(object.payload)
}
if (object.type !== undefined && object.type !== null) {
message.type = applicationMetadataMessage_TypeFromJSON(object.type);
message.type = applicationMetadataMessage_TypeFromJSON(object.type)
} else {
message.type = 0;
message.type = 0
}
return message;
return message
},
toJSON(message: ApplicationMetadataMessage): unknown {
const obj: any = {};
const obj: any = {}
message.signature !== undefined &&
(obj.signature = base64FromBytes(
message.signature !== undefined ? message.signature : new Uint8Array()
));
))
message.payload !== undefined &&
(obj.payload = base64FromBytes(
message.payload !== undefined ? message.payload : new Uint8Array()
));
))
message.type !== undefined &&
(obj.type = applicationMetadataMessage_TypeToJSON(message.type));
return obj;
(obj.type = applicationMetadataMessage_TypeToJSON(message.type))
return obj
},
fromPartial(
@ -331,58 +331,58 @@ export const ApplicationMetadataMessage = {
): ApplicationMetadataMessage {
const message = {
...baseApplicationMetadataMessage,
} as ApplicationMetadataMessage;
} as ApplicationMetadataMessage
if (object.signature !== undefined && object.signature !== null) {
message.signature = object.signature;
message.signature = object.signature
} else {
message.signature = new Uint8Array();
message.signature = new Uint8Array()
}
if (object.payload !== undefined && object.payload !== null) {
message.payload = object.payload;
message.payload = object.payload
} else {
message.payload = new Uint8Array();
message.payload = new Uint8Array()
}
if (object.type !== undefined && object.type !== null) {
message.type = object.type;
message.type = object.type
} else {
message.type = 0;
message.type = 0
}
return message;
return message
},
};
}
declare var self: any | undefined;
declare var window: any | undefined;
declare var global: any | undefined;
declare var self: any | undefined
declare var window: any | undefined
declare var global: any | undefined
var globalThis: any = (() => {
if (typeof globalThis !== "undefined") return globalThis;
if (typeof self !== "undefined") return self;
if (typeof window !== "undefined") return window;
if (typeof global !== "undefined") return global;
throw "Unable to locate global object";
})();
if (typeof globalThis !== 'undefined') return globalThis
if (typeof self !== 'undefined') return self
if (typeof window !== 'undefined') return window
if (typeof global !== 'undefined') return global
throw 'Unable to locate global object'
})()
const atob: (b64: string) => string =
globalThis.atob ||
((b64) => globalThis.Buffer.from(b64, "base64").toString("binary"));
(b64 => globalThis.Buffer.from(b64, 'base64').toString('binary'))
function bytesFromBase64(b64: string): Uint8Array {
const bin = atob(b64);
const arr = new Uint8Array(bin.length);
const bin = atob(b64)
const arr = new Uint8Array(bin.length)
for (let i = 0; i < bin.length; ++i) {
arr[i] = bin.charCodeAt(i);
arr[i] = bin.charCodeAt(i)
}
return arr;
return arr
}
const btoa: (bin: string) => string =
globalThis.btoa ||
((bin) => globalThis.Buffer.from(bin, "binary").toString("base64"));
(bin => globalThis.Buffer.from(bin, 'binary').toString('base64'))
function base64FromBytes(arr: Uint8Array): string {
const bin: string[] = [];
const bin: string[] = []
for (const byte of arr) {
bin.push(String.fromCharCode(byte));
bin.push(String.fromCharCode(byte))
}
return btoa(bin.join(""));
return btoa(bin.join(''))
}
type Builtin =
@ -392,7 +392,7 @@ type Builtin =
| string
| number
| boolean
| undefined;
| undefined
export type DeepPartial<T> = T extends Builtin
? T
: T extends Array<infer U>
@ -401,9 +401,9 @@ export type DeepPartial<T> = T extends Builtin
? ReadonlyArray<DeepPartial<U>>
: T extends {}
? { [K in keyof T]?: DeepPartial<T[K]> }
: Partial<T>;
: Partial<T>
if (_m0.util.Long !== Long) {
_m0.util.Long = Long as any;
_m0.configure();
_m0.util.Long = Long as any
_m0.configure()
}

View File

@ -1,15 +1,15 @@
import { BN } from "bn.js";
import { derive } from "ecies-geth";
import { ec } from "elliptic";
import { bufToHex } from "js-waku/build/main/lib/utils";
import { BN } from 'bn.js'
import { derive } from 'ecies-geth'
import { ec } from 'elliptic'
import { bufToHex } from 'js-waku/build/main/lib/utils'
import { idToContentTopic } from "./contentTopic";
import { hexToBuf } from "./utils";
import { idToContentTopic } from './contentTopic'
import { hexToBuf } from './utils'
import { Identity } from ".";
import { Identity } from '.'
const EC = new ec("secp256k1");
const partitionsNum = new BN(5000);
const EC = new ec('secp256k1')
const partitionsNum = new BN(5000)
/**
* Get the partitioned topic https://specs.status.im/spec/3#partitioned-topic
@ -17,14 +17,14 @@ const partitionsNum = new BN(5000);
* @returns string The Waku v2 Content Topic.
*/
export function getPartitionedTopic(publicKey: string): string {
const key = EC.keyFromPublic(publicKey.slice(2), "hex");
const X = key.getPublic().getX();
const key = EC.keyFromPublic(publicKey.slice(2), 'hex')
const X = key.getPublic().getX()
const partition = X.mod(partitionsNum);
const partition = X.mod(partitionsNum)
const partitionTopic = `contact-discovery-${partition.toString()}`;
const partitionTopic = `contact-discovery-${partition.toString()}`
return idToContentTopic(partitionTopic);
return idToContentTopic(partitionTopic)
}
/**
@ -37,10 +37,10 @@ export async function getNegotiatedTopic(
identity: Identity,
publicKey: string
): Promise<string> {
const key = EC.keyFromPublic(publicKey.slice(2), "hex");
const key = EC.keyFromPublic(publicKey.slice(2), 'hex')
const sharedSecret = await derive(
Buffer.from(identity.privateKey),
hexToBuf(key.getPublic("hex"))
);
return idToContentTopic(bufToHex(sharedSecret));
hexToBuf(key.getPublic('hex'))
)
return idToContentTopic(bufToHex(sharedSecret))
}

View File

@ -1,57 +1,57 @@
import { ec } from "elliptic";
import { PageDirection, utils, Waku } from "js-waku";
import { ec } from 'elliptic'
import { PageDirection, utils, Waku } from 'js-waku'
import { idToContactCodeTopic } from "./contentTopic";
import { ChatIdentity } from "./proto/communities/v1/chat_identity";
import { idToContactCodeTopic } from './contentTopic'
import { ChatIdentity } from './proto/communities/v1/chat_identity'
const EC = new ec("secp256k1");
const EC = new ec('secp256k1')
const hexToBuf = utils.hexToBuf;
export { hexToBuf };
const hexToBuf = utils.hexToBuf
export { hexToBuf }
/**
* Return hex string with 0x prefix (commonly used for string format of a community id/public key.
*/
export function bufToHex(buf: Uint8Array): string {
return "0x" + utils.bufToHex(buf);
return '0x' + utils.bufToHex(buf)
}
export function compressPublicKey(key: Uint8Array): string {
const PubKey = EC.keyFromPublic(key);
return "0x" + PubKey.getPublic(true, "hex");
const PubKey = EC.keyFromPublic(key)
return '0x' + PubKey.getPublic(true, 'hex')
}
export function genPrivateKeyWithEntropy(key: string): Uint8Array {
const pair = EC.genKeyPair({ entropy: key });
return hexToBuf("0x" + pair.getPrivate("hex"));
const pair = EC.genKeyPair({ entropy: key })
return hexToBuf('0x' + pair.getPrivate('hex'))
}
export async function getLatestUserNickname(
key: Uint8Array,
waku: Waku
): Promise<{ clock: number; nickname: string }> {
const publicKey = bufToHex(key);
let nickname = "";
let clock = 0;
const publicKey = bufToHex(key)
let nickname = ''
let clock = 0
await waku.store.queryHistory([idToContactCodeTopic(publicKey)], {
callback: (msgs) =>
msgs.some((e) => {
callback: msgs =>
msgs.some(e => {
try {
if (e.payload) {
const chatIdentity = ChatIdentity.decode(e?.payload);
const chatIdentity = ChatIdentity.decode(e?.payload)
if (chatIdentity) {
if (chatIdentity?.displayName) {
clock = chatIdentity?.clock ?? 0;
nickname = chatIdentity?.displayName;
clock = chatIdentity?.clock ?? 0
nickname = chatIdentity?.displayName
}
}
return true;
return true
}
} catch {
return false;
return false
}
}),
pageDirection: PageDirection.BACKWARD,
});
return { clock, nickname };
})
return { clock, nickname }
}

View File

@ -1,13 +1,13 @@
import { keccak256 } from "js-sha3";
import { Reader } from "protobufjs";
import secp256k1 from "secp256k1";
import { keccak256 } from 'js-sha3'
import { Reader } from 'protobufjs'
import secp256k1 from 'secp256k1'
import { Identity } from "../identity";
import * as proto from "../proto/status/v1/application_metadata_message";
import { ApplicationMetadataMessage_Type } from "../proto/status/v1/application_metadata_message";
import { hexToBuf } from "../utils";
import { Identity } from '../identity'
import * as proto from '../proto/status/v1/application_metadata_message'
import { ApplicationMetadataMessage_Type } from '../proto/status/v1/application_metadata_message'
import { hexToBuf } from '../utils'
import { ChatMessage } from "./chat_message";
import { ChatMessage } from './chat_message'
export class ApplicationMetadataMessage {
private constructor(public proto: proto.ApplicationMetadataMessage) {}
@ -20,56 +20,56 @@ export class ApplicationMetadataMessage {
type: ApplicationMetadataMessage_Type,
identity: Identity
): ApplicationMetadataMessage {
const signature = identity.sign(payload);
const signature = identity.sign(payload)
const proto = {
signature,
payload,
type,
};
}
return new ApplicationMetadataMessage(proto);
return new ApplicationMetadataMessage(proto)
}
static decode(bytes: Uint8Array): ApplicationMetadataMessage {
const protoBuf = proto.ApplicationMetadataMessage.decode(
Reader.create(bytes)
);
)
return new ApplicationMetadataMessage(protoBuf);
return new ApplicationMetadataMessage(protoBuf)
}
encode(): Uint8Array {
return proto.ApplicationMetadataMessage.encode(this.proto).finish();
return proto.ApplicationMetadataMessage.encode(this.proto).finish()
}
public get signature(): Uint8Array | undefined {
return this.proto.signature;
return this.proto.signature
}
public get payload(): Uint8Array | undefined {
return this.proto.payload;
return this.proto.payload
}
public get type(): ApplicationMetadataMessage_Type | undefined {
return this.proto.type;
return this.proto.type
}
/**
* Returns a chat message if the type is [TYPE_CHAT_MESSAGE], undefined otherwise.
*/
public get chatMessage(): ChatMessage | undefined {
if (!this.payload) return;
if (!this.payload) return
return ChatMessage.decode(this.payload);
return ChatMessage.decode(this.payload)
}
public get signer(): Uint8Array | undefined {
if (!this.signature || !this.payload) return;
if (!this.signature || !this.payload) return
const signature = this.signature.slice(0, 64);
const recid = this.signature.slice(64)[0];
const hash = keccak256(this.payload);
const signature = this.signature.slice(0, 64)
const recid = this.signature.slice(64)[0]
const hash = keccak256(this.payload)
return secp256k1.ecdsaRecover(signature, recid, hexToBuf(hash));
return secp256k1.ecdsaRecover(signature, recid, hexToBuf(hash))
}
}

View File

@ -1,51 +1,51 @@
import { Reader } from "protobufjs";
import { Reader } from 'protobufjs'
import * as proto from "../proto/communities/v1/chat_identity";
import { IdentityImage } from "../proto/communities/v1/chat_identity";
import * as proto from '../proto/communities/v1/chat_identity'
import { IdentityImage } from '../proto/communities/v1/chat_identity'
export class ChatIdentity {
public constructor(public proto: proto.ChatIdentity) {}
static decode(bytes: Uint8Array): ChatIdentity {
const protoBuf = proto.ChatIdentity.decode(Reader.create(bytes));
const protoBuf = proto.ChatIdentity.decode(Reader.create(bytes))
return new ChatIdentity(protoBuf);
return new ChatIdentity(protoBuf)
}
encode(): Uint8Array {
return proto.ChatIdentity.encode(this.proto).finish();
return proto.ChatIdentity.encode(this.proto).finish()
}
/** Lamport timestamp of the message */
get clock(): number | undefined {
return this.proto.clock;
return this.proto.clock
}
/** ens_name is the valid ENS name associated with the chat key */
get ensName(): string | undefined {
return this.proto.ensName;
return this.proto.ensName
}
/** images is a string indexed mapping of images associated with an identity */
get images(): { [key: string]: IdentityImage } | undefined {
return this.proto.images;
return this.proto.images
}
/** display name is the user set identity, valid only for organisations */
get displayName(): string | undefined {
return this.proto.displayName;
return this.proto.displayName
}
/** description is the user set description, valid only for organisations */
get description(): string | undefined {
return this.proto.description;
return this.proto.description
}
get color(): string | undefined {
return this.proto.color;
return this.proto.color
}
get emoji(): string | undefined {
return this.proto.emoji;
return this.proto.emoji
}
}

View File

@ -1,10 +1,10 @@
import { expect } from "chai";
import { expect } from 'chai'
import {
AudioMessage_AudioType,
ChatMessage_ContentType,
} from "../proto/communities/v1/chat_message";
import { ImageType } from "../proto/communities/v1/enums";
} from '../proto/communities/v1/chat_message'
import { ImageType } from '../proto/communities/v1/enums'
import {
AudioContent,
@ -12,67 +12,67 @@ import {
ContentType,
ImageContent,
StickerContent,
} from "./chat_message";
} from './chat_message'
describe("Chat Message", () => {
it("Encode & decode Image message", () => {
const payload = Buffer.from([1, 1]);
describe('Chat Message', () => {
it('Encode & decode Image message', () => {
const payload = Buffer.from([1, 1])
const imageContent: ImageContent = {
image: payload,
imageType: ImageType.IMAGE_TYPE_PNG,
contentType: ContentType.Image,
};
}
const message = ChatMessage.createMessage(1, 1, "chat-id", imageContent);
const message = ChatMessage.createMessage(1, 1, 'chat-id', imageContent)
const buf = message.encode();
const dec = ChatMessage.decode(buf);
const buf = message.encode()
const dec = ChatMessage.decode(buf)
expect(dec.contentType).eq(ChatMessage_ContentType.CONTENT_TYPE_IMAGE);
expect(dec.image?.payload?.toString()).eq(payload.toString());
expect(dec.image?.type).eq(ImageType.IMAGE_TYPE_PNG);
});
expect(dec.contentType).eq(ChatMessage_ContentType.CONTENT_TYPE_IMAGE)
expect(dec.image?.payload?.toString()).eq(payload.toString())
expect(dec.image?.type).eq(ImageType.IMAGE_TYPE_PNG)
})
it("Encode & decode Audio message", () => {
const payload = Buffer.from([1, 1]);
const durationMs = 12345;
it('Encode & decode Audio message', () => {
const payload = Buffer.from([1, 1])
const durationMs = 12345
const audioContent: AudioContent = {
audio: payload,
audioType: AudioMessage_AudioType.AUDIO_TYPE_AAC,
durationMs,
contentType: ContentType.Audio,
};
}
const message = ChatMessage.createMessage(1, 1, "chat-id", audioContent);
const message = ChatMessage.createMessage(1, 1, 'chat-id', audioContent)
const buf = message.encode();
const dec = ChatMessage.decode(buf);
const buf = message.encode()
const dec = ChatMessage.decode(buf)
expect(dec.contentType).eq(ChatMessage_ContentType.CONTENT_TYPE_AUDIO);
expect(dec.audio?.payload?.toString()).eq(payload.toString());
expect(dec.audio?.type).eq(ImageType.IMAGE_TYPE_PNG);
expect(dec.audio?.durationMs).eq(durationMs);
});
expect(dec.contentType).eq(ChatMessage_ContentType.CONTENT_TYPE_AUDIO)
expect(dec.audio?.payload?.toString()).eq(payload.toString())
expect(dec.audio?.type).eq(ImageType.IMAGE_TYPE_PNG)
expect(dec.audio?.durationMs).eq(durationMs)
})
it("Encode & decode Sticker message", () => {
const hash = "deadbeef";
const pack = 12345;
it('Encode & decode Sticker message', () => {
const hash = 'deadbeef'
const pack = 12345
const stickerContent: StickerContent = {
hash,
pack,
contentType: ContentType.Sticker,
};
}
const message = ChatMessage.createMessage(1, 1, "chat-id", stickerContent);
const message = ChatMessage.createMessage(1, 1, 'chat-id', stickerContent)
const buf = message.encode();
const dec = ChatMessage.decode(buf);
const buf = message.encode()
const dec = ChatMessage.decode(buf)
expect(dec.contentType).eq(ChatMessage_ContentType.CONTENT_TYPE_STICKER);
expect(dec.sticker?.hash).eq(hash);
expect(dec.sticker?.pack).eq(pack);
});
});
expect(dec.contentType).eq(ChatMessage_ContentType.CONTENT_TYPE_STICKER)
expect(dec.sticker?.hash).eq(hash)
expect(dec.sticker?.pack).eq(pack)
})
})

View File

@ -1,20 +1,16 @@
import { Reader } from "protobufjs";
import { Reader } from 'protobufjs'
import * as proto from "../proto/communities/v1/chat_message";
import * as proto from '../proto/communities/v1/chat_message'
import {
AudioMessage,
AudioMessage_AudioType,
ChatMessage_ContentType,
ImageMessage,
StickerMessage,
} from "../proto/communities/v1/chat_message";
import { ImageType, MessageType } from "../proto/communities/v1/enums";
} from '../proto/communities/v1/chat_message'
import { ImageType, MessageType } from '../proto/communities/v1/enums'
export type Content =
| TextContent
| StickerContent
| ImageContent
| AudioContent;
export type Content = TextContent | StickerContent | ImageContent | AudioContent
export enum ContentType {
Text,
@ -24,43 +20,43 @@ export enum ContentType {
}
export interface TextContent {
text: string;
contentType: ContentType.Text;
text: string
contentType: ContentType.Text
}
export interface StickerContent {
hash: string;
pack: number;
contentType: ContentType.Sticker;
hash: string
pack: number
contentType: ContentType.Sticker
}
export interface ImageContent {
image: Uint8Array;
imageType: ImageType;
contentType: ContentType.Image;
image: Uint8Array
imageType: ImageType
contentType: ContentType.Image
}
export interface AudioContent {
audio: Uint8Array;
audioType: AudioMessage_AudioType;
durationMs: number;
contentType: ContentType.Audio;
audio: Uint8Array
audioType: AudioMessage_AudioType
durationMs: number
contentType: ContentType.Audio
}
function isText(content: Content): content is TextContent {
return content.contentType === ContentType.Text;
return content.contentType === ContentType.Text
}
function isSticker(content: Content): content is StickerContent {
return content.contentType === ContentType.Sticker;
return content.contentType === ContentType.Sticker
}
function isImage(content: Content): content is ImageContent {
return content.contentType === ContentType.Image;
return content.contentType === ContentType.Image
}
function isAudio(content: Content): content is AudioContent {
return content.contentType === ContentType.Audio;
return content.contentType === ContentType.Audio
}
export class ChatMessage {
@ -81,36 +77,36 @@ export class ChatMessage {
let sticker,
image,
audio,
text = "Upgrade to the latest version to see this media content.";
let contentType = ChatMessage_ContentType.CONTENT_TYPE_TEXT_PLAIN;
text = 'Upgrade to the latest version to see this media content.'
let contentType = ChatMessage_ContentType.CONTENT_TYPE_TEXT_PLAIN
if (isText(content)) {
if (!content.text) throw "Malformed Text Content";
text = content.text;
contentType = ChatMessage_ContentType.CONTENT_TYPE_TEXT_PLAIN;
if (!content.text) throw 'Malformed Text Content'
text = content.text
contentType = ChatMessage_ContentType.CONTENT_TYPE_TEXT_PLAIN
} else if (isSticker(content)) {
if (!content.hash || !content.pack) throw "Malformed Sticker Content";
if (!content.hash || !content.pack) throw 'Malformed Sticker Content'
sticker = {
hash: content.hash,
pack: content.pack,
};
contentType = ChatMessage_ContentType.CONTENT_TYPE_STICKER;
}
contentType = ChatMessage_ContentType.CONTENT_TYPE_STICKER
} else if (isImage(content)) {
if (!content.image || !content.imageType) throw "Malformed Image Content";
if (!content.image || !content.imageType) throw 'Malformed Image Content'
image = {
payload: content.image,
type: content.imageType,
};
contentType = ChatMessage_ContentType.CONTENT_TYPE_IMAGE;
}
contentType = ChatMessage_ContentType.CONTENT_TYPE_IMAGE
} else if (isAudio(content)) {
if (!content.audio || !content.audioType || !content.durationMs)
throw "Malformed Audio Content";
throw 'Malformed Audio Content'
audio = {
payload: content.audio,
type: content.audioType,
durationMs: content.durationMs,
};
contentType = ChatMessage_ContentType.CONTENT_TYPE_AUDIO;
}
contentType = ChatMessage_ContentType.CONTENT_TYPE_AUDIO
}
const proto = {
@ -118,9 +114,9 @@ export class ChatMessage {
timestamp, //ms?
text,
/** Id of the message that we are replying to */
responseTo: responseTo ?? "",
responseTo: responseTo ?? '',
/** Ens name of the sender */
ensName: "",
ensName: '',
/** Public Key of the community (TBC) **/
chatId,
/** The type of message (public/one-to-one/private-group-chat) */
@ -132,24 +128,24 @@ export class ChatMessage {
audio,
community: undefined, // Used to share a community
grant: undefined,
};
}
return new ChatMessage(proto);
return new ChatMessage(proto)
}
static decode(bytes: Uint8Array): ChatMessage {
const protoBuf = proto.ChatMessage.decode(Reader.create(bytes));
const protoBuf = proto.ChatMessage.decode(Reader.create(bytes))
return new ChatMessage(protoBuf);
return new ChatMessage(protoBuf)
}
encode(): Uint8Array {
return proto.ChatMessage.encode(this.proto).finish();
return proto.ChatMessage.encode(this.proto).finish()
}
/** Lamport timestamp of the chat message */
public get clock(): number | undefined {
return this.proto.clock;
return this.proto.clock
}
/**
@ -157,28 +153,28 @@ export class ChatMessage {
* so that we don't rely on it
*/
public get timestamp(): number | undefined {
return this.proto.timestamp;
return this.proto.timestamp
}
/**
* Text of the message
*/
public get text(): string | undefined {
return this.proto.text;
return this.proto.text
}
/**
* Id of the message that we are replying to
*/
public get responseTo(): string | undefined {
return this.proto.responseTo;
return this.proto.responseTo
}
/**
* Ens name of the sender
*/
public get ensName(): string | undefined {
return this.proto.ensName;
return this.proto.ensName
}
/**
@ -188,39 +184,39 @@ export class ChatMessage {
* Probably should be the concatenation of sender-pk & receiver-pk in alphabetical order
*/
public get chatId(): string {
return this.proto.chatId;
return this.proto.chatId
}
/**
* The type of message (public/one-to-one/private-group-chat)
*/
public get messageType(): MessageType | undefined {
return this.proto.messageType;
return this.proto.messageType
}
/**
* The type of the content of the message
*/
public get contentType(): ChatMessage_ContentType | undefined {
return this.proto.contentType;
return this.proto.contentType
}
public get sticker(): StickerMessage | undefined {
return this.proto.sticker;
return this.proto.sticker
}
public get image(): ImageMessage | undefined {
return this.proto.image;
return this.proto.image
}
public get audio(): AudioMessage | undefined {
return this.proto.audio;
return this.proto.audio
}
/**
* Used when sharing a community via a chat message.
*/
public get community(): Uint8Array | undefined {
return this.proto.community;
return this.proto.community
}
}

View File

@ -1,12 +1,12 @@
import { Reader } from "protobufjs";
import { Reader } from 'protobufjs'
import * as proto from "../proto/communities/v1/communities";
import * as proto from '../proto/communities/v1/communities'
import {
CommunityMember,
CommunityPermissions,
} from "../proto/communities/v1/communities";
} from '../proto/communities/v1/communities'
import { ChatIdentity } from "./chat_identity";
import { ChatIdentity } from './chat_identity'
export class CommunityChat {
public constructor(public proto: proto.CommunityChat) {}
@ -17,43 +17,43 @@ export class CommunityChat {
* @throws
*/
static decode(bytes: Uint8Array): CommunityChat {
const protoBuf = proto.CommunityChat.decode(Reader.create(bytes));
const protoBuf = proto.CommunityChat.decode(Reader.create(bytes))
return new CommunityChat(protoBuf);
return new CommunityChat(protoBuf)
}
encode(): Uint8Array {
return proto.CommunityChat.encode(this.proto).finish();
return proto.CommunityChat.encode(this.proto).finish()
}
// TODO: check and document what is the key of the returned Map;
public get members(): Map<string, CommunityMember> {
const map = new Map();
const map = new Map()
for (const key of Object.keys(this.proto.members)) {
map.set(key, this.proto.members[key]);
map.set(key, this.proto.members[key])
}
return map;
return map
}
public get permissions(): CommunityPermissions | undefined {
return this.proto.permissions;
return this.proto.permissions
}
public get identity(): ChatIdentity | undefined {
if (!this.proto.identity) return;
if (!this.proto.identity) return
return new ChatIdentity(this.proto.identity);
return new ChatIdentity(this.proto.identity)
}
// TODO: Document this
public get categoryId(): string | undefined {
return this.proto.categoryId;
return this.proto.categoryId
}
// TODO: Document this
public get position(): number | undefined {
return this.proto.position;
return this.proto.position
}
}

View File

@ -1,29 +1,29 @@
import debug from "debug";
import { WakuMessage, WakuStore } from "js-waku";
import { Reader } from "protobufjs";
import debug from 'debug'
import { WakuMessage, WakuStore } from 'js-waku'
import { Reader } from 'protobufjs'
import { idToContentTopic } from "../contentTopic";
import { createSymKeyFromPassword } from "../encryption";
import * as proto from "../proto/communities/v1/communities";
import { bufToHex } from "../utils";
import { idToContentTopic } from '../contentTopic'
import { createSymKeyFromPassword } from '../encryption'
import * as proto from '../proto/communities/v1/communities'
import { bufToHex } from '../utils'
import { ApplicationMetadataMessage } from "./application_metadata_message";
import { ChatIdentity } from "./chat_identity";
import { CommunityChat } from "./community_chat";
import { ApplicationMetadataMessage } from './application_metadata_message'
import { ChatIdentity } from './chat_identity'
import { CommunityChat } from './community_chat'
const dbg = debug("communities:wire:community_description");
const dbg = debug('communities:wire:community_description')
export class CommunityDescription {
private constructor(public proto: proto.CommunityDescription) {}
static decode(bytes: Uint8Array): CommunityDescription {
const protoBuf = proto.CommunityDescription.decode(Reader.create(bytes));
const protoBuf = proto.CommunityDescription.decode(Reader.create(bytes))
return new CommunityDescription(protoBuf);
return new CommunityDescription(protoBuf)
}
encode(): Uint8Array {
return proto.CommunityDescription.encode(this.proto).finish();
return proto.CommunityDescription.encode(this.proto).finish()
}
/**
@ -33,69 +33,69 @@ export class CommunityDescription {
communityPublicKey: Uint8Array,
wakuStore: WakuStore
): Promise<CommunityDescription | undefined> {
const hexCommunityPublicKey = bufToHex(communityPublicKey);
const contentTopic = idToContentTopic(hexCommunityPublicKey);
const hexCommunityPublicKey = bufToHex(communityPublicKey)
const contentTopic = idToContentTopic(hexCommunityPublicKey)
let communityDescription: CommunityDescription | undefined;
let communityDescription: CommunityDescription | undefined
const callback = (messages: WakuMessage[]): void => {
// Value found, stop processing
if (communityDescription) return;
if (communityDescription) return
// Process most recent message first
const orderedMessages = messages.reverse();
const orderedMessages = messages.reverse()
orderedMessages.forEach((message: WakuMessage) => {
if (!message.payload) return;
if (!message.payload) return
try {
const metadata = ApplicationMetadataMessage.decode(message.payload);
if (!metadata.payload) return;
const metadata = ApplicationMetadataMessage.decode(message.payload)
if (!metadata.payload) return
const _communityDescription = CommunityDescription.decode(
metadata.payload
);
)
if (!_communityDescription.identity) return;
if (!_communityDescription.identity) return
communityDescription = _communityDescription;
communityDescription = _communityDescription
} catch (e) {
dbg(
`Failed to decode message as CommunityDescription found on content topic ${contentTopic}`,
e
);
)
}
});
};
})
}
const symKey = await createSymKeyFromPassword(hexCommunityPublicKey);
const symKey = await createSymKeyFromPassword(hexCommunityPublicKey)
await wakuStore
.queryHistory([contentTopic], {
callback,
decryptionKeys: [symKey],
})
.catch((e) => {
.catch(e => {
dbg(
`Failed to retrieve community description for ${hexCommunityPublicKey}`,
e
);
});
)
})
return communityDescription;
return communityDescription
}
get identity(): ChatIdentity | undefined {
if (!this.proto.identity) return;
if (!this.proto.identity) return
return new ChatIdentity(this.proto.identity);
return new ChatIdentity(this.proto.identity)
}
get chats(): Map<string, CommunityChat> {
const map = new Map();
const map = new Map()
for (const key of Object.keys(this.proto.chats)) {
map.set(key, this.proto.chats[key]);
map.set(key, this.proto.chats[key])
}
return map;
return map
}
}

View File

@ -1,73 +1,73 @@
import { keccak256 } from "js-sha3";
import { Reader } from "protobufjs";
import * as secp256k1 from "secp256k1";
import { v4 as uuidV4 } from "uuid";
import { keccak256 } from 'js-sha3'
import { Reader } from 'protobufjs'
import * as secp256k1 from 'secp256k1'
import { v4 as uuidV4 } from 'uuid'
import { Identity } from "..";
import * as proto from "../proto/communities/v1/membership_update_message";
import { bufToHex, hexToBuf } from "../utils";
import { Identity } from '..'
import * as proto from '../proto/communities/v1/membership_update_message'
import { bufToHex, hexToBuf } from '../utils'
export class MembershipUpdateEvent {
public constructor(public proto: proto.MembershipUpdateEvent) {}
static decode(bytes: Uint8Array): MembershipUpdateEvent {
const protoBuf = proto.MembershipUpdateEvent.decode(Reader.create(bytes));
return new MembershipUpdateEvent(protoBuf);
const protoBuf = proto.MembershipUpdateEvent.decode(Reader.create(bytes))
return new MembershipUpdateEvent(protoBuf)
}
encode(): Uint8Array {
return proto.MembershipUpdateEvent.encode(this.proto).finish();
return proto.MembershipUpdateEvent.encode(this.proto).finish()
}
public get members(): string[] {
return this.proto.members;
return this.proto.members
}
public get name(): string {
return this.proto.name;
return this.proto.name
}
public get clock(): number {
return this.proto.clock;
return this.proto.clock
}
public get type(): proto.MembershipUpdateEvent_EventType {
return this.proto.type;
return this.proto.type
}
}
export class MembershipSignedEvent {
public sig: Uint8Array;
public event: MembershipUpdateEvent;
private chatId: string;
public sig: Uint8Array
public event: MembershipUpdateEvent
private chatId: string
public constructor(
sig: Uint8Array,
event: MembershipUpdateEvent,
chatId: string
) {
this.sig = sig;
this.event = event;
this.chatId = chatId;
this.sig = sig
this.event = event
this.chatId = chatId
}
public get signer(): Uint8Array | undefined {
const encEvent = this.event.encode();
const eventToSign = Buffer.concat([hexToBuf(this.chatId), encEvent]);
const encEvent = this.event.encode()
const eventToSign = Buffer.concat([hexToBuf(this.chatId), encEvent])
if (!this.sig || !eventToSign) return;
if (!this.sig || !eventToSign) return
const signature = this.sig.slice(0, 64);
const recid = this.sig.slice(64)[0];
const hash = keccak256(eventToSign);
const signature = this.sig.slice(0, 64)
const recid = this.sig.slice(64)[0]
const hash = keccak256(eventToSign)
return secp256k1.ecdsaRecover(signature, recid, hexToBuf(hash));
return secp256k1.ecdsaRecover(signature, recid, hexToBuf(hash))
}
}
export class MembershipUpdateMessage {
private clock: number = Date.now();
private identity: Identity = Identity.generate();
private clock: number = Date.now()
private identity: Identity = Identity.generate()
public constructor(public proto: proto.MembershipUpdateMessage) {}
public static create(
@ -77,18 +77,18 @@ export class MembershipUpdateMessage {
const partial = proto.MembershipUpdateMessage.fromPartial({
chatId,
events: [],
});
const newMessage = new MembershipUpdateMessage(partial);
newMessage.clock = Date.now();
newMessage.identity = identity;
return newMessage;
})
const newMessage = new MembershipUpdateMessage(partial)
newMessage.clock = Date.now()
newMessage.identity = identity
return newMessage
}
private addEvent(event: MembershipUpdateEvent): void {
const encEvent = event.encode();
const eventToSign = Buffer.concat([hexToBuf(this.proto.chatId), encEvent]);
const signature = this.identity.sign(eventToSign);
this.proto.events.push(Buffer.concat([signature, encEvent]));
const encEvent = event.encode()
const eventToSign = Buffer.concat([hexToBuf(this.proto.chatId), encEvent])
const signature = this.identity.sign(eventToSign)
this.proto.events.push(Buffer.concat([signature, encEvent]))
}
public static createChat(
@ -96,106 +96,106 @@ export class MembershipUpdateMessage {
members: string[],
name?: string
): MembershipUpdateMessage {
const chatId = `${uuidV4()}-${bufToHex(identity.publicKey)}`;
const chatId = `${uuidV4()}-${bufToHex(identity.publicKey)}`
const message = this.create(chatId, identity);
const type = proto.MembershipUpdateEvent_EventType.CHAT_CREATED;
const message = this.create(chatId, identity)
const type = proto.MembershipUpdateEvent_EventType.CHAT_CREATED
const event = new MembershipUpdateEvent({
clock: message.clock,
members,
name: name ?? "",
name: name ?? '',
type,
});
message.addEvent(event);
return message;
})
message.addEvent(event)
return message
}
public addNameChangeEvent(name: string): void {
const type = proto.MembershipUpdateEvent_EventType.NAME_CHANGED;
const type = proto.MembershipUpdateEvent_EventType.NAME_CHANGED
const event = new MembershipUpdateEvent({
clock: this.clock,
members: [],
name: name,
type,
});
this.addEvent(event);
})
this.addEvent(event)
}
public addMembersAddedEvent(members: string[]): void {
const type = proto.MembershipUpdateEvent_EventType.MEMBERS_ADDED;
const type = proto.MembershipUpdateEvent_EventType.MEMBERS_ADDED
const event = new MembershipUpdateEvent({
clock: this.clock,
members,
name: "",
name: '',
type,
});
this.addEvent(event);
})
this.addEvent(event)
}
public addMemberJoinedEvent(member: string): void {
const type = proto.MembershipUpdateEvent_EventType.MEMBER_JOINED;
const type = proto.MembershipUpdateEvent_EventType.MEMBER_JOINED
const event = new MembershipUpdateEvent({
clock: this.clock,
members: [member],
name: "",
name: '',
type,
});
this.addEvent(event);
})
this.addEvent(event)
}
public addMemberRemovedEvent(member: string): void {
const type = proto.MembershipUpdateEvent_EventType.MEMBER_REMOVED;
const type = proto.MembershipUpdateEvent_EventType.MEMBER_REMOVED
const event = new MembershipUpdateEvent({
clock: this.clock,
members: [member],
name: "",
name: '',
type,
});
this.addEvent(event);
})
this.addEvent(event)
}
public addAdminsAddedEvent(members: string[]): void {
const type = proto.MembershipUpdateEvent_EventType.ADMINS_ADDED;
const type = proto.MembershipUpdateEvent_EventType.ADMINS_ADDED
const event = new MembershipUpdateEvent({
clock: this.clock,
members,
name: "",
name: '',
type,
});
this.addEvent(event);
})
this.addEvent(event)
}
public addAdminRemovedEvent(member: string): void {
const type = proto.MembershipUpdateEvent_EventType.ADMINS_ADDED;
const type = proto.MembershipUpdateEvent_EventType.ADMINS_ADDED
const event = new MembershipUpdateEvent({
clock: this.clock,
members: [member],
name: "",
name: '',
type,
});
this.addEvent(event);
})
this.addEvent(event)
}
static decode(bytes: Uint8Array): MembershipUpdateMessage {
const protoBuf = proto.MembershipUpdateMessage.decode(Reader.create(bytes));
return new MembershipUpdateMessage(protoBuf);
const protoBuf = proto.MembershipUpdateMessage.decode(Reader.create(bytes))
return new MembershipUpdateMessage(protoBuf)
}
public get events(): MembershipSignedEvent[] {
return this.proto.events.map((bufArray) => {
return this.proto.events.map(bufArray => {
return new MembershipSignedEvent(
bufArray.slice(0, 65),
MembershipUpdateEvent.decode(bufArray.slice(65)),
this.chatId
);
});
)
})
}
public get chatId(): string {
return this.proto.chatId;
return this.proto.chatId
}
encode(): Uint8Array {
return proto.MembershipUpdateMessage.encode(this.proto).finish();
return proto.MembershipUpdateMessage.encode(this.proto).finish()
}
}

View File

@ -1,6 +1,6 @@
import { Reader } from "protobufjs";
import { Reader } from 'protobufjs'
import * as proto from "../proto/communities/v1/status_update";
import * as proto from '../proto/communities/v1/status_update'
export class StatusUpdate {
public constructor(public proto: proto.StatusUpdate) {}
@ -9,15 +9,15 @@ export class StatusUpdate {
statusType: proto.StatusUpdate_StatusType,
customText: string
): StatusUpdate {
const clock = Date.now();
const clock = Date.now()
const proto = {
clock,
statusType,
customText,
};
}
return new StatusUpdate(proto);
return new StatusUpdate(proto)
}
/**
@ -26,24 +26,24 @@ export class StatusUpdate {
* @throws
*/
static decode(bytes: Uint8Array): StatusUpdate {
const protoBuf = proto.StatusUpdate.decode(Reader.create(bytes));
const protoBuf = proto.StatusUpdate.decode(Reader.create(bytes))
return new StatusUpdate(protoBuf);
return new StatusUpdate(protoBuf)
}
encode(): Uint8Array {
return proto.StatusUpdate.encode(this.proto).finish();
return proto.StatusUpdate.encode(this.proto).finish()
}
public get clock(): number | undefined {
return this.proto.clock;
return this.proto.clock
}
public get statusType(): proto.StatusUpdate_StatusType | undefined {
return this.proto.statusType;
return this.proto.statusType
}
public get customText(): string | undefined {
return this.proto.customText;
return this.proto.customText
}
}

View File

@ -19,11 +19,9 @@
"build:esm": "tsc --module es2020 --target es2017 --outDir dist/esm",
"build:cjs": "tsc --outDir dist/cjs",
"fix": "run-s 'fix:*'",
"fix:prettier": "prettier './{src,test}/**/*.{ts,tsx}' \"./*.json\" --write",
"fix:lint": "eslint './{src,test}/**/*.{ts,tsx}' --fix",
"test": "run-s 'test:*'",
"test:lint": "eslint './{src,test}/**/*.{ts,tsx}'",
"test:prettier": "prettier './{src,test}/**/*.{ts,tsx}' \"./*.json\" --list-different",
"proto": "run-s 'proto:*'",
"proto:lint": "buf lint",
"proto:build": "buf generate"
@ -49,7 +47,6 @@
"mocha": "^9.0.3",
"npm-run-all": "^4.1.5",
"npm-watch": "^0.11.0",
"prettier": "^2.3.2",
"qrcode.react": "^1.0.1",
"rimraf": "^3.0.2",
"ts-node": "^10.1.0",

View File

@ -1,30 +1,30 @@
import React, { useMemo, useRef, useState } from "react";
import styled from "styled-components";
import React, { useMemo, useRef, useState } from 'react'
import styled from 'styled-components'
import { useIdentity } from "../../contexts/identityProvider";
import { useActivities } from "../../hooks/useActivities";
import { useClickOutside } from "../../hooks/useClickOutside";
import { TopBtn } from "../Chat/ChatTopbar";
import { ActivityIcon } from "../Icons/ActivityIcon";
import { useIdentity } from '../../contexts/identityProvider'
import { useActivities } from '../../hooks/useActivities'
import { useClickOutside } from '../../hooks/useClickOutside'
import { TopBtn } from '../Chat/ChatTopbar'
import { ActivityIcon } from '../Icons/ActivityIcon'
import { ActivityCenter } from "./ActivityCenter";
import { ActivityCenter } from './ActivityCenter'
interface ActivityButtonProps {
className?: string;
className?: string
}
export function ActivityButton({ className }: ActivityButtonProps) {
const { activities, activityDispatch } = useActivities();
const identity = useIdentity();
const disabled = useMemo(() => !identity, [identity]);
const ref = useRef(null);
useClickOutside(ref, () => setShowActivityCenter(false));
const { activities, activityDispatch } = useActivities()
const identity = useIdentity()
const disabled = useMemo(() => !identity, [identity])
const ref = useRef(null)
useClickOutside(ref, () => setShowActivityCenter(false))
const [showActivityCenter, setShowActivityCenter] = useState(false);
const [showActivityCenter, setShowActivityCenter] = useState(false)
const badgeAmount = useMemo(
() => activities.filter((activity) => !activity.isRead).length,
() => activities.filter(activity => !activity.isRead).length,
[activities]
);
)
return (
<ActivityWrapper ref={ref} className={className}>
@ -37,13 +37,13 @@ export function ActivityButton({ className }: ActivityButtonProps) {
<NotificationBagde
className={
badgeAmount > 99
? "countless"
? 'countless'
: badgeAmount > 9
? "wide"
? 'wide'
: undefined
}
>
{badgeAmount < 100 ? badgeAmount : "∞"}
{badgeAmount < 100 ? badgeAmount : '∞'}
</NotificationBagde>
)}
</TopBtn>
@ -55,7 +55,7 @@ export function ActivityButton({ className }: ActivityButtonProps) {
/>
)}
</ActivityWrapper>
);
)
}
export const ActivityWrapper = styled.div`
@ -64,7 +64,7 @@ export const ActivityWrapper = styled.div`
position: relative;
&:before {
content: "";
content: '';
position: absolute;
left: 0;
top: 50%;
@ -85,7 +85,7 @@ export const ActivityWrapper = styled.div`
height: 0px;
}
}
`;
`
const NotificationBagde = styled.div`
width: 18px;
@ -113,4 +113,4 @@ const NotificationBagde = styled.div`
&.countless {
width: 22px;
}
`;
`

View File

@ -1,21 +1,21 @@
import React, { useMemo, useState } from "react";
import styled from "styled-components";
import React, { useMemo, useState } from 'react'
import styled from 'styled-components'
import { useMessengerContext } from "../../contexts/messengerProvider";
import { ActivityAction } from "../../hooks/useActivities";
import { Activity } from "../../models/Activity";
import { buttonTransparentStyles } from "../Buttons/buttonStyle";
import { Tooltip } from "../Form/Tooltip";
import { HideIcon } from "../Icons/HideIcon";
import { ReadIcon } from "../Icons/ReadIcon";
import { ShowIcon } from "../Icons/ShowIcon";
import { useMessengerContext } from '../../contexts/messengerProvider'
import { ActivityAction } from '../../hooks/useActivities'
import { Activity } from '../../models/Activity'
import { buttonTransparentStyles } from '../Buttons/buttonStyle'
import { Tooltip } from '../Form/Tooltip'
import { HideIcon } from '../Icons/HideIcon'
import { ReadIcon } from '../Icons/ReadIcon'
import { ShowIcon } from '../Icons/ShowIcon'
import { ActivityMessage } from "./ActivityMessage";
import { ActivityMessage } from './ActivityMessage'
interface ActivityCenterProps {
activities: Activity[];
setShowActivityCenter: (val: boolean) => void;
activityDispatch: React.Dispatch<ActivityAction>;
activities: Activity[]
setShowActivityCenter: (val: boolean) => void
activityDispatch: React.Dispatch<ActivityAction>
}
export function ActivityCenter({
@ -23,43 +23,43 @@ export function ActivityCenter({
setShowActivityCenter,
activityDispatch,
}: ActivityCenterProps) {
const { contacts } = useMessengerContext();
const { contacts } = useMessengerContext()
const shownActivities = useMemo(
() =>
activities.filter(
(activity) => !contacts?.[activity.user]?.blocked ?? true
activity => !contacts?.[activity.user]?.blocked ?? true
),
[contacts, activities]
);
)
const [hideRead, setHideRead] = useState(false);
const [hideRead, setHideRead] = useState(false)
const [filter, setFilter] = useState("");
const [filter, setFilter] = useState('')
const filteredActivities = shownActivities.filter((activity) =>
const filteredActivities = shownActivities.filter(activity =>
filter
? activity.type === filter
: hideRead
? activity.isRead !== true
: activity
);
)
return (
<ActivityBlock>
<ActivityFilter>
<FlexDiv>
<FilterBtn onClick={() => setFilter("")}>All</FilterBtn>
<FilterBtn onClick={() => setFilter("mention")}>Mentions</FilterBtn>
<FilterBtn onClick={() => setFilter("reply")}>Replies</FilterBtn>
<FilterBtn onClick={() => setFilter("request")}>
<FilterBtn onClick={() => setFilter('')}>All</FilterBtn>
<FilterBtn onClick={() => setFilter('mention')}>Mentions</FilterBtn>
<FilterBtn onClick={() => setFilter('reply')}>Replies</FilterBtn>
<FilterBtn onClick={() => setFilter('request')}>
Contact requests
</FilterBtn>
</FlexDiv>
<Btns>
<BtnWrapper>
<ActivityBtn
onClick={() => activityDispatch({ type: "setAllAsRead" })}
onClick={() => activityDispatch({ type: 'setAllAsRead' })}
>
<ReadIcon />
</ActivityBtn>
@ -69,13 +69,13 @@ export function ActivityCenter({
<ActivityBtn onClick={() => setHideRead(!hideRead)}>
{hideRead ? <ShowIcon /> : <HideIcon />}
</ActivityBtn>
<Tooltip tip={hideRead ? "Show read" : "Hide read"} />
<Tooltip tip={hideRead ? 'Show read' : 'Hide read'} />
</BtnWrapper>
</Btns>
</ActivityFilter>
{filteredActivities.length > 0 ? (
<Activities>
{filteredActivities.map((activity) => (
{filteredActivities.map(activity => (
<ActivityMessage
key={activity.id}
activity={activity}
@ -88,7 +88,7 @@ export function ActivityCenter({
<EmptyActivities>Notifications will appear here</EmptyActivities>
)}
</ActivityBlock>
);
)
}
const ActivityBlock = styled.div`
@ -103,17 +103,17 @@ const ActivityBlock = styled.div`
top: calc(100% + 4px);
right: 0;
z-index: 100;
`;
`
const ActivityFilter = styled.div`
display: flex;
justify-content: space-between;
padding: 13px 16px;
`;
`
export const FlexDiv = styled.div`
display: flex;
`;
`
const FilterBtn = styled.button`
${buttonTransparentStyles}
@ -121,7 +121,7 @@ const FilterBtn = styled.button`
& + & {
margin-left: 8px;
}
`;
`
const BtnWrapper = styled.div`
position: relative;
@ -129,7 +129,7 @@ const BtnWrapper = styled.div`
&:hover > div {
visibility: visible;
}
`;
`
export const ActivityBtn = styled.button`
width: 32px;
@ -165,14 +165,14 @@ export const ActivityBtn = styled.button`
& + & {
margin-left: 8px;
}
`;
`
const Activities = styled.div`
display: flex;
flex-direction: column;
width: 100%;
overflow: auto;
`;
`
const EmptyActivities = styled.div`
display: flex;
@ -181,9 +181,9 @@ const EmptyActivities = styled.div`
flex: 1;
width: 100%;
color: ${({ theme }) => theme.secondary};
`;
`
const Btns = styled.div`
display: flex;
align-items: center;
`;
`

View File

@ -1,27 +1,27 @@
import React, { useEffect, useMemo, useRef, useState } from "react";
import styled from "styled-components";
import React, { useEffect, useMemo, useRef, useState } from 'react'
import styled from 'styled-components'
import { useMessengerContext } from "../../contexts/messengerProvider";
import { useModal } from "../../contexts/modalProvider";
import { useScrollToMessage } from "../../contexts/scrollProvider";
import { ActivityAction } from "../../hooks/useActivities";
import { useClickOutside } from "../../hooks/useClickOutside";
import { Activity } from "../../models/Activity";
import { equalDate } from "../../utils/equalDate";
import { DownloadButton } from "../Buttons/DownloadButton";
import { Mention } from "../Chat/ChatMessageContent";
import { Logo } from "../CommunityIdentity";
import { ContactMenu } from "../Form/ContactMenu";
import { Tooltip } from "../Form/Tooltip";
import { CheckIcon } from "../Icons/CheckIcon";
import { ClearSvg } from "../Icons/ClearIcon";
import { CommunityIcon } from "../Icons/CommunityIcon";
import { GroupIcon } from "../Icons/GroupIcon";
import { MoreIcon } from "../Icons/MoreIcon";
import { ReadMessageIcon } from "../Icons/ReadMessageIcon";
import { ReplyIcon } from "../Icons/ReplyActivityIcon";
import { UntrustworthIcon } from "../Icons/UntrustworthIcon";
import { UserIcon } from "../Icons/UserIcon";
import { useMessengerContext } from '../../contexts/messengerProvider'
import { useModal } from '../../contexts/modalProvider'
import { useScrollToMessage } from '../../contexts/scrollProvider'
import { ActivityAction } from '../../hooks/useActivities'
import { useClickOutside } from '../../hooks/useClickOutside'
import { Activity } from '../../models/Activity'
import { equalDate } from '../../utils/equalDate'
import { DownloadButton } from '../Buttons/DownloadButton'
import { Mention } from '../Chat/ChatMessageContent'
import { Logo } from '../CommunityIdentity'
import { ContactMenu } from '../Form/ContactMenu'
import { Tooltip } from '../Form/Tooltip'
import { CheckIcon } from '../Icons/CheckIcon'
import { ClearSvg } from '../Icons/ClearIcon'
import { CommunityIcon } from '../Icons/CommunityIcon'
import { GroupIcon } from '../Icons/GroupIcon'
import { MoreIcon } from '../Icons/MoreIcon'
import { ReadMessageIcon } from '../Icons/ReadMessageIcon'
import { ReplyIcon } from '../Icons/ReplyActivityIcon'
import { UntrustworthIcon } from '../Icons/UntrustworthIcon'
import { UserIcon } from '../Icons/UserIcon'
import {
ContentWrapper,
DateSeparator,
@ -32,52 +32,52 @@ import {
UserAddress,
UserName,
UserNameWrapper,
} from "../Messages/Styles";
import { ProfileModalName } from "../Modals/ProfileModal";
import { textMediumStyles, textSmallStyles } from "../Text";
} from '../Messages/Styles'
import { ProfileModalName } from '../Modals/ProfileModal'
import { textMediumStyles, textSmallStyles } from '../Text'
import { ActivityBtn, FlexDiv } from "./ActivityCenter";
import { ActivityBtn, FlexDiv } from './ActivityCenter'
const today = new Date();
const today = new Date()
type ActivityMessageProps = {
activity: Activity;
setShowActivityCenter: (val: boolean) => void;
activityDispatch: React.Dispatch<ActivityAction>;
};
activity: Activity
setShowActivityCenter: (val: boolean) => void
activityDispatch: React.Dispatch<ActivityAction>
}
export function ActivityMessage({
activity,
setShowActivityCenter,
activityDispatch,
}: ActivityMessageProps) {
const { contacts, channelsDispatch } = useMessengerContext();
const scroll = useScrollToMessage();
const { setModal } = useModal(ProfileModalName);
const { contacts, channelsDispatch } = useMessengerContext()
const scroll = useScrollToMessage()
const { setModal } = useModal(ProfileModalName)
const showChannel = () => {
"channel" in activity &&
channelsDispatch({ type: "ChangeActive", payload: activity.channel.id }),
setShowActivityCenter(false);
};
'channel' in activity &&
channelsDispatch({ type: 'ChangeActive', payload: activity.channel.id }),
setShowActivityCenter(false)
}
const [showMenu, setShowMenu] = useState(false);
const [showMenu, setShowMenu] = useState(false)
const type = activity.type;
const type = activity.type
const contact = useMemo(
() => contacts[activity.user],
[activity.user, contacts]
);
)
const [elements, setElements] = useState<
(string | React.ReactElement | undefined)[]
>(["message" in activity ? activity.message?.content : undefined]);
>(['message' in activity ? activity.message?.content : undefined])
useEffect(() => {
if ("message" in activity) {
const split = activity.message?.content.split(" ");
if ('message' in activity) {
const split = activity.message?.content.split(' ')
const newSplit = split.flatMap((element, idx) => {
if (element.startsWith("@")) {
if (element.startsWith('@')) {
return [
<Mention
key={idx}
@ -85,28 +85,28 @@ export function ActivityMessage({
setMentioned={() => true}
className="activity"
/>,
" ",
];
' ',
]
}
return [element, " "];
});
newSplit.pop();
setElements(newSplit);
return [element, ' ']
})
newSplit.pop()
setElements(newSplit)
}
}, [activity]);
}, [activity])
const ref = useRef(null);
useClickOutside(ref, () => setShowMenu(false));
const ref = useRef(null)
useClickOutside(ref, () => setShowMenu(false))
return (
<MessageOuterWrapper>
<ActivityDate>
{equalDate(activity.date, today)
? "Today"
? 'Today'
: activity.date.toLocaleDateString()}
</ActivityDate>
<MessageWrapper className={`${!activity.isRead && "unread"}`}>
<MessageWrapper className={`${!activity.isRead && 'unread'}`}>
<>
<UserIcon />
<ActivityContent>
@ -118,10 +118,10 @@ export function ActivityMessage({
id: activity.user,
renamingState: false,
requestState: false,
});
})
}}
>
{" "}
{' '}
{contact?.customName ?? activity.user.slice(0, 10)}
</ActivityUserName>
{contact?.customName && (
@ -132,22 +132,22 @@ export function ActivityMessage({
{contact.isUntrustworthy && <UntrustworthIcon />}
</UserNameWrapper>
<TimeWrapper>
{activity.date.toLocaleString("en-US", {
hour: "numeric",
minute: "numeric",
{activity.date.toLocaleString('en-US', {
hour: 'numeric',
minute: 'numeric',
hour12: true,
})}
</TimeWrapper>
</MessageHeaderWrapper>
{type === "request" && (
{type === 'request' && (
<ContextHeading>
Contact request
{activity.requestType === "outcome"
{activity.requestType === 'outcome'
? ` to ${activity.user.slice(0, 10)}`
: ": "}
: ': '}
</ContextHeading>
)}
{type === "invitation" && (
{type === 'invitation' && (
<FlexDiv>
<ContextHeading>{`Invited you to join a community `}</ContextHeading>
<Tag>
@ -156,7 +156,7 @@ export function ActivityMessage({
style={{
backgroundImage: activity.invitation?.icon
? `url(${activity.invitation?.icon}`
: "",
: '',
}}
>
{activity.invitation?.icon === undefined &&
@ -167,29 +167,29 @@ export function ActivityMessage({
</FlexDiv>
)}
<ActivityText>
{"message" in activity && activity.message?.content && (
{'message' in activity && activity.message?.content && (
<div
onClick={() => {
scroll(activity.message, activity.channel.id);
setShowActivityCenter(false);
scroll(activity.message, activity.channel.id)
setShowActivityCenter(false)
}}
>
{elements.map((el) => el)}
{elements.map(el => el)}
</div>
)}
{activity.type === "request" &&
activity.requestType === "income" &&
{activity.type === 'request' &&
activity.requestType === 'income' &&
activity.request}
</ActivityText>
{type === "mention" &&
{type === 'mention' &&
activity.channel &&
activity.channel.type !== "dm" && (
activity.channel.type !== 'dm' && (
<Tag onClick={showChannel}>
{activity.channel.type === "group" ? <GroupIcon /> : "#"}{" "}
{activity.channel.type === 'group' ? <GroupIcon /> : '#'}{' '}
<span>{` ${activity.channel.name.slice(0, 10)}`}</span>
</Tag>
)}
{type === "reply" && activity.quote && (
{type === 'reply' && activity.quote && (
<ReplyWrapper>
{activity.quote.image && (
<ContextHeading>Posted an image in</ContextHeading>
@ -199,7 +199,7 @@ export function ActivityMessage({
</Tag>
</ReplyWrapper>
)}
{type === "invitation" && (
{type === 'invitation' && (
<InviteDiv>
<ContextHeading>{`To access other communities, `}</ContextHeading>
<DownloadButton className="activity" />
@ -207,16 +207,16 @@ export function ActivityMessage({
)}
</ActivityContent>
</>
{type === "request" &&
{type === 'request' &&
!activity.status &&
activity.requestType === "income" && (
activity.requestType === 'income' && (
<>
<ActivityBtn
onClick={() => {
activityDispatch({
type: "setStatus",
payload: { id: activity.id, status: "accepted" },
});
type: 'setStatus',
payload: { id: activity.id, status: 'accepted' },
})
}}
className="accept"
>
@ -225,9 +225,9 @@ export function ActivityMessage({
<ActivityBtn
onClick={() => {
activityDispatch({
type: "setStatus",
payload: { id: activity.id, status: "declined" },
});
type: 'setStatus',
payload: { id: activity.id, status: 'declined' },
})
}}
className="decline"
>
@ -235,7 +235,7 @@ export function ActivityMessage({
</ActivityBtn>
<ActivityBtn
onClick={() => {
setShowMenu((e) => !e);
setShowMenu(e => !e)
}}
ref={ref}
>
@ -246,22 +246,22 @@ export function ActivityMessage({
</ActivityBtn>
</>
)}
{type === "request" && activity.status === "accepted" && (
{type === 'request' && activity.status === 'accepted' && (
<RequestStatus className="accepted">Accepted</RequestStatus>
)}
{type === "request" && activity.status === "declined" && (
{type === 'request' && activity.status === 'declined' && (
<RequestStatus className="declined">Declined</RequestStatus>
)}
{type === "request" && activity.status === "sent" && (
{type === 'request' && activity.status === 'sent' && (
<RequestStatus>Sent</RequestStatus>
)}
{(type === "mention" || type === "reply") && (
{(type === 'mention' || type === 'reply') && (
<BtnWrapper>
<ActivityBtn
onClick={() =>
activityDispatch({ type: "setAsRead", payload: activity.id })
activityDispatch({ type: 'setAsRead', payload: activity.id })
}
className={`${activity.isRead && "read"}`}
className={`${activity.isRead && 'read'}`}
>
<ReadMessageIcon isRead={activity.isRead} />
</ActivityBtn>
@ -270,13 +270,13 @@ export function ActivityMessage({
)}
</MessageWrapper>
</MessageOuterWrapper>
);
)
}
const InviteDiv = styled.div`
display: flex;
margin-top: -4px;
`;
`
const BtnWrapper = styled.div`
position: relative;
@ -284,13 +284,13 @@ const BtnWrapper = styled.div`
&:hover > div {
visibility: visible;
}
`;
`
const ActivityDate = styled(DateSeparator)`
justify-content: flex-start;
padding: 8px 16px;
margin: 0;
`;
`
const MessageWrapper = styled.div`
width: 100%;
@ -301,12 +301,12 @@ const MessageWrapper = styled.div`
&.unread {
background: ${({ theme }) => theme.buttonBgHover};
}
`;
`
const ActivityText = styled(MessageText)`
white-space: unset;
margin-bottom: 8px;
`;
`
const Tag = styled.div`
width: fit-content;
@ -328,7 +328,7 @@ const Tag = styled.div`
white-space: nowrap;
overflow: hidden;
}
`;
`
const ContextHeading = styled.p`
font-style: italic;
@ -336,7 +336,7 @@ const ContextHeading = styled.p`
flex-shrink: 0;
white-space: pre-wrap;
${textMediumStyles}
`;
`
const RequestStatus = styled.p`
font-weight: 500;
@ -352,12 +352,12 @@ const RequestStatus = styled.p`
&.declined {
color: ${({ theme }) => theme.redColor};
}
`;
`
const ActivityContent = styled(ContentWrapper)`
max-width: calc(100% - 80px);
flex: 1;
`;
`
const ActivityUserName = styled(UserName)`
cursor: pointer;
@ -365,7 +365,7 @@ const ActivityUserName = styled(UserName)`
&:hover {
text-decoration: underline;
}
`;
`
const ReplyWrapper = styled.div`
max-width: 100%;
@ -375,7 +375,7 @@ const ReplyWrapper = styled.div`
& > p {
margin-right: 4px;
}
`;
`
const CommunityLogo = styled(Logo)`
width: 16px;
@ -383,4 +383,4 @@ const CommunityLogo = styled(Logo)`
margin: 0 2px 0 4px;
${textSmallStyles}
`;
`

View File

@ -1,11 +1,11 @@
import React from "react";
import styled from "styled-components";
import React from 'react'
import styled from 'styled-components'
import { LeftIcon } from "../Icons/LeftIcon";
import { LeftIcon } from '../Icons/LeftIcon'
interface BackButtonProps {
onBtnClick: () => void;
className?: string;
onBtnClick: () => void
className?: string
}
export function BackButton({ onBtnClick, className }: BackButtonProps) {
@ -13,7 +13,7 @@ export function BackButton({ onBtnClick, className }: BackButtonProps) {
<BackBtn onClick={onBtnClick} className={className}>
<LeftIcon width={24} height={24} className="black" />
</BackBtn>
);
)
}
const BackBtn = styled.button`
@ -28,4 +28,4 @@ const BackBtn = styled.button`
position: static;
margin-right: 13px;
}
`;
`

View File

@ -1,50 +1,50 @@
import React, { useEffect, useState } from "react";
import styled from "styled-components";
import React, { useEffect, useState } from 'react'
import styled from 'styled-components'
import { buttonStyles } from "./buttonStyle";
import { buttonStyles } from './buttonStyle'
const userAgent = window.navigator.userAgent;
const platform = window.navigator.platform;
const macosPlatforms = ["Macintosh", "MacIntel", "MacPPC", "Mac68K"];
const windowsPlatforms = ["Win32", "Win64", "Windows", "WinCE"];
const iosPlatforms = ["iPhone", "iPad", "iPod"];
const userAgent = window.navigator.userAgent
const platform = window.navigator.platform
const macosPlatforms = ['Macintosh', 'MacIntel', 'MacPPC', 'Mac68K']
const windowsPlatforms = ['Win32', 'Win64', 'Windows', 'WinCE']
const iosPlatforms = ['iPhone', 'iPad', 'iPod']
interface DownloadButtonProps {
className?: string;
className?: string
}
export const DownloadButton = ({ className }: DownloadButtonProps) => {
const [link, setlink] = useState("https://status.im/get/");
const [os, setOs] = useState<string | null>(null);
const [link, setlink] = useState('https://status.im/get/')
const [os, setOs] = useState<string | null>(null)
useEffect(() => {
if (macosPlatforms.includes(platform)) {
setlink(
"https://status-im-files.ams3.cdn.digitaloceanspaces.com/StatusIm-Desktop-v0.3.0-beta-a8c37d.dmg"
);
setOs("Mac");
'https://status-im-files.ams3.cdn.digitaloceanspaces.com/StatusIm-Desktop-v0.3.0-beta-a8c37d.dmg'
)
setOs('Mac')
} else if (iosPlatforms.includes(platform)) {
setlink(
"https://apps.apple.com/us/app/status-private-communication/id1178893006"
);
setOs("iOS");
'https://apps.apple.com/us/app/status-private-communication/id1178893006'
)
setOs('iOS')
} else if (windowsPlatforms.includes(platform)) {
setlink(
"https://status-im-files.ams3.cdn.digitaloceanspaces.com/StatusIm-Desktop-v0.3.0-beta-a8c37d.exe"
);
setOs("Windows");
'https://status-im-files.ams3.cdn.digitaloceanspaces.com/StatusIm-Desktop-v0.3.0-beta-a8c37d.exe'
)
setOs('Windows')
} else if (/Android/.test(userAgent)) {
setlink(
"https://play.google.com/store/apps/details?id=im.status.ethereum"
);
setOs("Android");
'https://play.google.com/store/apps/details?id=im.status.ethereum'
)
setOs('Android')
} else if (/Linux/.test(platform)) {
setlink(
"https://status-im-files.ams3.cdn.digitaloceanspaces.com/StatusIm-Desktop-v0.3.0-beta-a8c37d.tar.gz"
);
setOs("Linux");
'https://status-im-files.ams3.cdn.digitaloceanspaces.com/StatusIm-Desktop-v0.3.0-beta-a8c37d.tar.gz'
)
setOs('Linux')
}
}, []);
}, [])
return (
<Link
@ -54,11 +54,11 @@ export const DownloadButton = ({ className }: DownloadButtonProps) => {
rel="noopener noreferrer"
>
{os
? `${className === "activity" ? "d" : "D"}ownload Status for ${os}`
: `${className === "activity" ? "d" : "D"}ownload Status`}
? `${className === 'activity' ? 'd' : 'D'}ownload Status for ${os}`
: `${className === 'activity' ? 'd' : 'D'}ownload Status`}
</Link>
);
};
)
}
const Link = styled.a`
margin-top: 24px;
@ -81,4 +81,4 @@ const Link = styled.a`
color: ${({ theme }) => theme.tertiary};
}
}
`;
`

View File

@ -1,7 +1,7 @@
import styled, { css } from "styled-components";
import styled, { css } from 'styled-components'
export const buttonStyles = css`
font-family: "Inter";
font-family: 'Inter';
font-weight: 500;
font-size: 15px;
line-height: 22px;
@ -17,10 +17,10 @@ export const buttonStyles = css`
&:focus {
background: ${({ theme }) => theme.buttonBg};
}
`;
`
export const buttonTransparentStyles = css`
font-family: "Inter";
font-family: 'Inter';
font-weight: 500;
font-size: 13px;
line-height: 18px;
@ -37,7 +37,7 @@ export const buttonTransparentStyles = css`
&:focus {
background: ${({ theme }) => theme.buttonBg};
}
`;
`
export const ButtonNo = styled.button`
padding: 11px 24px;
@ -50,10 +50,10 @@ export const ButtonNo = styled.button`
&:hover {
background: ${({ theme }) => theme.buttonNoBgHover};
}
`;
`
export const ButtonYes = styled.button`
padding: 11px 24px;
${buttonStyles}
`;
`

View File

@ -1,29 +1,29 @@
import React from "react";
import styled from "styled-components";
import React from 'react'
import styled from 'styled-components'
import { useMessengerContext } from "../../contexts/messengerProvider";
import { useNarrow } from "../../contexts/narrowProvider";
import { ChannelData } from "../../models/ChannelData";
import { ChannelMenu } from "../Form/ChannelMenu";
import { Tooltip } from "../Form/Tooltip";
import { GroupIcon } from "../Icons/GroupIcon";
import { MutedIcon } from "../Icons/MutedIcon";
import { textMediumStyles } from "../Text";
import { useMessengerContext } from '../../contexts/messengerProvider'
import { useNarrow } from '../../contexts/narrowProvider'
import { ChannelData } from '../../models/ChannelData'
import { ChannelMenu } from '../Form/ChannelMenu'
import { Tooltip } from '../Form/Tooltip'
import { GroupIcon } from '../Icons/GroupIcon'
import { MutedIcon } from '../Icons/MutedIcon'
import { textMediumStyles } from '../Text'
import { ChannelIcon } from "./ChannelIcon";
import { ChannelIcon } from './ChannelIcon'
function RenderChannelName({
channel,
activeView,
className,
}: {
channel: ChannelData;
activeView?: boolean;
className?: string;
channel: ChannelData
activeView?: boolean
className?: string
}) {
const { activeChannel } = useMessengerContext();
const { activeChannel } = useMessengerContext()
switch (channel.type) {
case "group":
case 'group':
return (
<div className={className}>
{!activeView && (
@ -31,22 +31,22 @@ function RenderChannelName({
)}
{` ${channel.name}`}
</div>
);
case "channel":
return <div className={className}>{`# ${channel.name}`}</div>;
case "dm":
return <div className={className}>{channel.name.slice(0, 20)}</div>;
)
case 'channel':
return <div className={className}>{`# ${channel.name}`}</div>
case 'dm':
return <div className={className}>{channel.name.slice(0, 20)}</div>
}
}
interface ChannelProps {
channel: ChannelData;
notified?: boolean;
mention?: number;
isActive: boolean;
activeView?: boolean;
onClick?: () => void;
setEditGroup?: React.Dispatch<React.SetStateAction<boolean>>;
channel: ChannelData
notified?: boolean
mention?: number
isActive: boolean
activeView?: boolean
onClick?: () => void
setEditGroup?: React.Dispatch<React.SetStateAction<boolean>>
}
export function Channel({
@ -58,15 +58,15 @@ export function Channel({
mention,
setEditGroup,
}: ChannelProps) {
const narrow = useNarrow();
const { channelsDispatch } = useMessengerContext();
const narrow = useNarrow()
const { channelsDispatch } = useMessengerContext()
return (
<ChannelWrapper
className={`${isActive && "active"}`}
className={`${isActive && 'active'}`}
isNarrow={narrow && activeView}
onClick={onClick}
id={!activeView ? `${channel.id + "contextMenu"}` : ""}
id={!activeView ? `${channel.id + 'contextMenu'}` : ''}
>
<ChannelInfo activeView={activeView}>
<ChannelIcon channel={channel} activeView={activeView} />
@ -82,7 +82,7 @@ export function Channel({
{channel?.isMuted && activeView && !narrow && (
<MutedBtn
onClick={() =>
channelsDispatch({ type: "ToggleMuted", payload: channel.id })
channelsDispatch({ type: 'ToggleMuted', payload: channel.id })
}
>
<MutedIcon />
@ -103,15 +103,15 @@ export function Channel({
<ChannelMenu
channel={channel}
setEditGroup={setEditGroup}
className={narrow ? "sideNarrow" : "side"}
className={narrow ? 'sideNarrow' : 'side'}
/>
)}
</ChannelWrapper>
);
)
}
const ChannelWrapper = styled.div<{ isNarrow?: boolean }>`
width: ${({ isNarrow }) => (isNarrow ? "calc(100% - 162px)" : "100%")};
width: ${({ isNarrow }) => (isNarrow ? 'calc(100% - 162px)' : '100%')};
display: flex;
justify-content: space-between;
align-items: center;
@ -128,13 +128,13 @@ const ChannelWrapper = styled.div<{ isNarrow?: boolean }>`
&:hover {
background-color: ${({ theme, isNarrow }) => isNarrow && theme.border};
}
`;
`
export const ChannelInfo = styled.div<{ activeView?: boolean }>`
display: flex;
align-items: ${({ activeView }) => (activeView ? "flex-start" : "center")};
align-items: ${({ activeView }) => (activeView ? 'flex-start' : 'center')};
overflow-x: hidden;
`;
`
const ChannelTextInfo = styled.div<{ activeView?: boolean }>`
display: flex;
@ -142,33 +142,33 @@ const ChannelTextInfo = styled.div<{ activeView?: boolean }>`
text-overflow: ellipsis;
overflow-x: hidden;
white-space: nowrap;
padding: ${({ activeView }) => activeView && "0 24px 24px 0"};
`;
padding: ${({ activeView }) => activeView && '0 24px 24px 0'};
`
const ChannelNameWrapper = styled.div`
display: flex;
align-items: center;
`;
`
export const ChannelName = styled(RenderChannelName)<{
muted?: boolean;
notified?: boolean;
active?: boolean;
activeView?: boolean;
muted?: boolean
notified?: boolean
active?: boolean
activeView?: boolean
}>`
font-weight: ${({ notified, muted, active }) =>
notified && !muted && !active ? "600" : "500"};
notified && !muted && !active ? '600' : '500'};
opacity: ${({ notified, muted, active }) =>
muted ? "0.4" : notified || active ? "1.0" : "0.7"};
muted ? '0.4' : notified || active ? '1.0' : '0.7'};
color: ${({ theme }) => theme.primary};
margin-right: ${({ muted, activeView }) =>
muted && activeView ? "8px" : ""};
muted && activeView ? '8px' : ''};
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
${textMediumStyles}
`;
`
const ChannelDescription = styled.p`
font-size: 12px;
@ -178,7 +178,7 @@ const ChannelDescription = styled.p`
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
`;
`
const NotificationBagde = styled.div`
width: 24px;
@ -193,7 +193,7 @@ const NotificationBagde = styled.div`
align-items: center;
justify-content: center;
flex-shrink: 0;
`;
`
const MutedBtn = styled.button`
padding: 0;
@ -208,4 +208,4 @@ const MutedBtn = styled.button`
&:hover > div {
visibility: visible;
}
`;
`

View File

@ -1,25 +1,25 @@
import React from "react";
import styled from "styled-components";
import React from 'react'
import styled from 'styled-components'
import { useNarrow } from "../../contexts/narrowProvider";
import { ChannelData } from "../../models/ChannelData";
import { useNarrow } from '../../contexts/narrowProvider'
import { ChannelData } from '../../models/ChannelData'
interface ChannelIconProps {
channel: ChannelData;
activeView?: boolean;
channel: ChannelData
activeView?: boolean
}
export function ChannelIcon({ channel, activeView }: ChannelIconProps) {
const narrow = useNarrow();
const narrow = useNarrow()
return (
<ChannelLogo
icon={channel.icon}
className={activeView ? "active" : narrow ? "narrow" : ""}
className={activeView ? 'active' : narrow ? 'narrow' : ''}
>
{!channel.icon && channel.name.slice(0, 1).toUpperCase()}
</ChannelLogo>
);
)
}
export const ChannelLogo = styled.div<{ icon?: string }>`
@ -51,4 +51,4 @@ export const ChannelLogo = styled.div<{ icon?: string }>`
height: 40px;
font-size: 20px;
}
`;
`

View File

@ -1,22 +1,22 @@
import React, { useMemo } from "react";
import styled from "styled-components";
import React, { useMemo } from 'react'
import styled from 'styled-components'
import { ChatState, useChatState } from "../../contexts/chatStateProvider";
import { useIdentity } from "../../contexts/identityProvider";
import { useMessengerContext } from "../../contexts/messengerProvider";
import { CreateIcon } from "../Icons/CreateIcon";
import { UserCreation } from "../UserCreation/UserCreation";
import { ChatState, useChatState } from '../../contexts/chatStateProvider'
import { useIdentity } from '../../contexts/identityProvider'
import { useMessengerContext } from '../../contexts/messengerProvider'
import { CreateIcon } from '../Icons/CreateIcon'
import { UserCreation } from '../UserCreation/UserCreation'
import { Channel } from "./Channel";
import { Channel } from './Channel'
interface ChannelsProps {
onCommunityClick?: () => void;
setEditGroup?: React.Dispatch<React.SetStateAction<boolean>>;
onCommunityClick?: () => void
setEditGroup?: React.Dispatch<React.SetStateAction<boolean>>
}
type GenerateChannelsProps = ChannelsProps & {
type: string;
};
type: string
}
function GenerateChannels({
type,
@ -24,16 +24,16 @@ function GenerateChannels({
setEditGroup,
}: GenerateChannelsProps) {
const { mentions, notifications, activeChannel, channelsDispatch, channels } =
useMessengerContext();
useMessengerContext()
const channelList = useMemo(() => Object.values(channels), [channels]);
const channelList = useMemo(() => Object.values(channels), [channels])
const setChatState = useChatState()[1];
const setChatState = useChatState()[1]
return (
<>
{channelList
.filter((channel) => channel.type === type)
.map((channel) => (
.filter(channel => channel.type === type)
.map(channel => (
<Channel
key={channel.id}
channel={channel}
@ -41,26 +41,26 @@ function GenerateChannels({
notified={notifications?.[channel.id] > 0}
mention={mentions?.[channel.id]}
onClick={() => {
channelsDispatch({ type: "ChangeActive", payload: channel.id });
channelsDispatch({ type: 'ChangeActive', payload: channel.id })
if (onCommunityClick) {
onCommunityClick();
onCommunityClick()
}
setChatState(ChatState.ChatBody);
setChatState(ChatState.ChatBody)
}}
setEditGroup={setEditGroup}
/>
))}
</>
);
)
}
type ChatsListProps = {
onCommunityClick?: () => void;
setEditGroup?: React.Dispatch<React.SetStateAction<boolean>>;
};
onCommunityClick?: () => void
setEditGroup?: React.Dispatch<React.SetStateAction<boolean>>
}
function ChatsSideBar({ onCommunityClick, setEditGroup }: ChatsListProps) {
const setChatState = useChatState()[1];
const setChatState = useChatState()[1]
return (
<>
<ChatsBar>
@ -71,21 +71,21 @@ function ChatsSideBar({ onCommunityClick, setEditGroup }: ChatsListProps) {
</ChatsBar>
<ChatsList>
<GenerateChannels
type={"group"}
type={'group'}
onCommunityClick={onCommunityClick}
setEditGroup={setEditGroup}
/>
<GenerateChannels type={"dm"} onCommunityClick={onCommunityClick} />
<GenerateChannels type={'dm'} onCommunityClick={onCommunityClick} />
</ChatsList>
</>
);
)
}
export function Channels({ onCommunityClick, setEditGroup }: ChannelsProps) {
const identity = useIdentity();
const identity = useIdentity()
return (
<ChannelList>
<GenerateChannels type={"channel"} onCommunityClick={onCommunityClick} />
<GenerateChannels type={'channel'} onCommunityClick={onCommunityClick} />
<Chats>
{identity ? (
<ChatsSideBar
@ -97,7 +97,7 @@ export function Channels({ onCommunityClick, setEditGroup }: ChannelsProps) {
)}
</Chats>
</ChannelList>
);
)
}
export const ChannelList = styled.div`
@ -107,7 +107,7 @@ export const ChannelList = styled.div`
&::-webkit-scrollbar {
width: 0;
}
`;
`
const Chats = styled.div`
display: flex;
@ -117,7 +117,7 @@ const Chats = styled.div`
position: relative;
&::before {
content: "";
content: '';
position: absolute;
top: 0;
left: 50%;
@ -127,26 +127,26 @@ const Chats = styled.div`
background-color: ${({ theme }) => theme.primary};
opacity: 0.1;
}
`;
`
const ChatsBar = styled.div`
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 8px;
`;
`
const ChatsList = styled.div`
display: flex;
flex-direction: column;
`;
`
const Heading = styled.p`
font-weight: bold;
font-size: 17px;
line-height: 24px;
color: ${({ theme }) => theme.primary};
`;
`
const EditBtn = styled.button`
width: 32px;
@ -161,4 +161,4 @@ const EditBtn = styled.button`
&:active {
background: ${({ theme }) => theme.sectionBackgroundColor};
}
`;
`

View File

@ -1,44 +1,44 @@
import React, { useMemo } from "react";
import styled from "styled-components";
import React, { useMemo } from 'react'
import styled from 'styled-components'
import { useUserPublicKey } from "../../contexts/identityProvider";
import { useMessengerContext } from "../../contexts/messengerProvider";
import { useNarrow } from "../../contexts/narrowProvider";
import { ChannelData } from "../../models/ChannelData";
import { textMediumStyles } from "../Text";
import { useUserPublicKey } from '../../contexts/identityProvider'
import { useMessengerContext } from '../../contexts/messengerProvider'
import { useNarrow } from '../../contexts/narrowProvider'
import { ChannelData } from '../../models/ChannelData'
import { textMediumStyles } from '../Text'
import { ChannelInfo, ChannelName } from "./Channel";
import { ChannelLogo } from "./ChannelIcon";
import { ChannelInfo, ChannelName } from './Channel'
import { ChannelLogo } from './ChannelIcon'
type ChannelBeggingTextProps = {
channel: ChannelData;
};
channel: ChannelData
}
function ChannelBeggingText({ channel }: ChannelBeggingTextProps) {
const userPK = useUserPublicKey();
const { contacts } = useMessengerContext();
const userPK = useUserPublicKey()
const { contacts } = useMessengerContext()
const members = useMemo(() => {
if (channel?.members && userPK) {
return channel.members
.filter((contact) => contact.id !== userPK)
.map((member) => contacts?.[member.id] ?? member);
.filter(contact => contact.id !== userPK)
.map(member => contacts?.[member.id] ?? member)
}
return [];
}, [channel, contacts, userPK]);
return []
}, [channel, contacts, userPK])
switch (channel.type) {
case "dm":
case 'dm':
return (
<EmptyText>
Any messages you send here are encrypted and can only be read by you
and <br />
<span>{channel.name.slice(0, 10)}</span>.
</EmptyText>
);
case "group":
)
case 'group':
return (
<EmptyTextGroup>
{userPK && <span>{userPK}</span>} created a group with{" "}
{userPK && <span>{userPK}</span>} created a group with{' '}
{members.map((contact, idx) => (
<span key={contact.id}>
{contact?.customName ?? contact.trueName.slice(0, 10)}
@ -46,36 +46,36 @@ function ChannelBeggingText({ channel }: ChannelBeggingTextProps) {
</span>
))}
</EmptyTextGroup>
);
case "channel":
)
case 'channel':
return (
<EmptyText>
Welcome to the beginning of the <span>#{channel.name}</span> channel!
</EmptyText>
);
)
}
return null;
return null
}
type EmptyChannelProps = {
channel: ChannelData;
};
channel: ChannelData
}
export function EmptyChannel({ channel }: EmptyChannelProps) {
const narrow = useNarrow();
const narrow = useNarrow()
return (
<Wrapper className={`${!narrow && "wide"}`}>
<Wrapper className={`${!narrow && 'wide'}`}>
<ChannelInfoEmpty>
<ChannelLogoEmpty icon={channel.icon}>
{" "}
{' '}
{!channel.icon && channel.name.slice(0, 1).toUpperCase()}
</ChannelLogoEmpty>
<ChannelNameEmpty active={true} channel={channel} />
</ChannelInfoEmpty>
<ChannelBeggingText channel={channel} />
</Wrapper>
);
)
}
const Wrapper = styled.div`
@ -87,11 +87,11 @@ const Wrapper = styled.div`
&.wide {
margin-top: 24px;
}
`;
`
const ChannelInfoEmpty = styled(ChannelInfo)`
flex-direction: column;
`;
`
const ChannelLogoEmpty = styled(ChannelLogo)`
width: 120px;
@ -100,14 +100,14 @@ const ChannelLogoEmpty = styled(ChannelLogo)`
font-size: 51px;
line-height: 62px;
margin-bottom: 16px;
`;
`
const ChannelNameEmpty = styled(ChannelName)`
font-weight: bold;
font-size: 22px;
line-height: 30px;
margin-bottom: 16px;
`;
`
const EmptyText = styled.p`
display: inline-block;
@ -120,10 +120,10 @@ const EmptyText = styled.p`
}
${textMediumStyles}
`;
`
const EmptyTextGroup = styled(EmptyText)`
& > span {
word-break: break-all;
}
`;
`

View File

@ -1,19 +1,19 @@
import React, { useCallback, useEffect, useMemo, useState } from "react";
import styled from "styled-components";
import React, { useCallback, useEffect, useMemo, useState } from 'react'
import styled from 'styled-components'
import { useMessengerContext } from "../../contexts/messengerProvider";
import { useNarrow } from "../../contexts/narrowProvider";
import { Reply } from "../../hooks/useReply";
import { ChannelData } from "../../models/ChannelData";
import { TokenRequirement } from "../Form/TokenRequirement";
import { MessagesList } from "../Messages/MessagesList";
import { NarrowChannels } from "../NarrowMode/NarrowChannels";
import { NarrowMembers } from "../NarrowMode/NarrowMembers";
import { LoadingSkeleton } from "../Skeleton/LoadingSkeleton";
import { useMessengerContext } from '../../contexts/messengerProvider'
import { useNarrow } from '../../contexts/narrowProvider'
import { Reply } from '../../hooks/useReply'
import { ChannelData } from '../../models/ChannelData'
import { TokenRequirement } from '../Form/TokenRequirement'
import { MessagesList } from '../Messages/MessagesList'
import { NarrowChannels } from '../NarrowMode/NarrowChannels'
import { NarrowMembers } from '../NarrowMode/NarrowMembers'
import { LoadingSkeleton } from '../Skeleton/LoadingSkeleton'
import { ChatCreation } from "./ChatCreation";
import { ChatInput } from "./ChatInput";
import { ChatTopbar, ChatTopbarLoading } from "./ChatTopbar";
import { ChatCreation } from './ChatCreation'
import { ChatInput } from './ChatInput'
import { ChatTopbar, ChatTopbarLoading } from './ChatTopbar'
export enum ChatBodyState {
Chat,
@ -22,30 +22,30 @@ export enum ChatBodyState {
}
function ChatBodyLoading() {
const narrow = useNarrow();
const narrow = useNarrow()
return (
<Wrapper>
<ChatBodyWrapper className={narrow ? "narrow" : ""}>
<ChatBodyWrapper className={narrow ? 'narrow' : ''}>
<ChatTopbarLoading />
<LoadingSkeleton />
<ChatInput reply={undefined} setReply={() => undefined} />
</ChatBodyWrapper>
</Wrapper>
);
)
}
type ChatBodyContentProps = {
showState: ChatBodyState;
switchShowState: (state: ChatBodyState) => void;
channel: ChannelData;
};
showState: ChatBodyState
switchShowState: (state: ChatBodyState) => void
channel: ChannelData
}
function ChatBodyContent({
showState,
switchShowState,
channel,
}: ChatBodyContentProps) {
const [reply, setReply] = useState<Reply | undefined>(undefined);
const [reply, setReply] = useState<Reply | undefined>(undefined)
switch (showState) {
case ChatBodyState.Chat:
@ -54,28 +54,28 @@ function ChatBodyContent({
<MessagesList setReply={setReply} channel={channel} />
<ChatInput reply={reply} setReply={setReply} />
</>
);
)
case ChatBodyState.Channels:
return (
<NarrowChannels
setShowChannels={() => switchShowState(ChatBodyState.Channels)}
/>
);
)
case ChatBodyState.Members:
return (
<NarrowMembers
switchShowMembersList={() => switchShowState(ChatBodyState.Members)}
/>
);
)
}
}
interface ChatBodyProps {
onClick: () => void;
showMembers: boolean;
permission: boolean;
editGroup: boolean;
setEditGroup: React.Dispatch<React.SetStateAction<boolean>>;
onClick: () => void
showMembers: boolean
permission: boolean
editGroup: boolean
setEditGroup: React.Dispatch<React.SetStateAction<boolean>>
}
export function ChatBody({
@ -85,26 +85,26 @@ export function ChatBody({
editGroup,
setEditGroup,
}: ChatBodyProps) {
const { activeChannel, loadingMessenger } = useMessengerContext();
const { activeChannel, loadingMessenger } = useMessengerContext()
const narrow = useNarrow();
const className = useMemo(() => (narrow ? "narrow" : ""), [narrow]);
const narrow = useNarrow()
const className = useMemo(() => (narrow ? 'narrow' : ''), [narrow])
const [showState, setShowState] = useState<ChatBodyState>(ChatBodyState.Chat);
const [showState, setShowState] = useState<ChatBodyState>(ChatBodyState.Chat)
const switchShowState = useCallback(
(state: ChatBodyState) => {
if (narrow) {
setShowState((prev) => (prev === state ? ChatBodyState.Chat : state));
setShowState(prev => (prev === state ? ChatBodyState.Chat : state))
}
},
[narrow]
);
)
useEffect(() => {
if (!narrow) {
setShowState(ChatBodyState.Chat);
setShowState(ChatBodyState.Chat)
}
}, [narrow]);
}, [narrow])
if (!loadingMessenger && activeChannel) {
return (
@ -138,10 +138,10 @@ export function ChatBody({
</BluredWrapper>
)}
</Wrapper>
);
)
}
return <ChatBodyLoading />;
return <ChatBodyLoading />
}
export const Wrapper = styled.div`
@ -156,7 +156,7 @@ export const Wrapper = styled.div`
&.narrow {
width: 100%;
}
`;
`
const ChatBodyWrapper = styled.div`
width: 100%;
@ -165,7 +165,7 @@ const ChatBodyWrapper = styled.div`
flex-direction: column;
flex: 1;
background: ${({ theme }) => theme.bodyBackgroundColor};
`;
`
const BluredWrapper = styled.div`
width: 100%;
@ -179,4 +179,4 @@ const BluredWrapper = styled.div`
background: ${({ theme }) => theme.bodyBackgroundGradient};
backdrop-filter: blur(4px);
z-index: 2;
`;
`

View File

@ -1,107 +1,107 @@
import React, { useCallback, useMemo, useState } from "react";
import styled from "styled-components";
import React, { useCallback, useMemo, useState } from 'react'
import styled from 'styled-components'
import { ChatState, useChatState } from "../../contexts/chatStateProvider";
import { useUserPublicKey } from "../../contexts/identityProvider";
import { useMessengerContext } from "../../contexts/messengerProvider";
import { useNarrow } from "../../contexts/narrowProvider";
import { ChannelData } from "../../models/ChannelData";
import { ActivityButton } from "../ActivityCenter/ActivityButton";
import { BackButton } from "../Buttons/BackButton";
import { buttonStyles } from "../Buttons/buttonStyle";
import { CrossIcon } from "../Icons/CrossIcon";
import { Member } from "../Members/Member";
import { SearchBlock } from "../SearchBlock";
import { textMediumStyles } from "../Text";
import { ChatState, useChatState } from '../../contexts/chatStateProvider'
import { useUserPublicKey } from '../../contexts/identityProvider'
import { useMessengerContext } from '../../contexts/messengerProvider'
import { useNarrow } from '../../contexts/narrowProvider'
import { ChannelData } from '../../models/ChannelData'
import { ActivityButton } from '../ActivityCenter/ActivityButton'
import { BackButton } from '../Buttons/BackButton'
import { buttonStyles } from '../Buttons/buttonStyle'
import { CrossIcon } from '../Icons/CrossIcon'
import { Member } from '../Members/Member'
import { SearchBlock } from '../SearchBlock'
import { textMediumStyles } from '../Text'
import { ChatInput } from "./ChatInput";
import { ChatInput } from './ChatInput'
interface ChatCreationProps {
setEditGroup?: (val: boolean) => void;
activeChannel?: ChannelData;
setEditGroup?: (val: boolean) => void
activeChannel?: ChannelData
}
export function ChatCreation({
setEditGroup,
activeChannel,
}: ChatCreationProps) {
const narrow = useNarrow();
const userPK = useUserPublicKey();
const [query, setQuery] = useState("");
const narrow = useNarrow()
const userPK = useUserPublicKey()
const [query, setQuery] = useState('')
const [groupChatMembersIds, setGroupChatMembersIds] = useState<string[]>(
activeChannel?.members?.map((member) => member.id) ?? []
);
const { contacts, createGroupChat, addMembers } = useMessengerContext();
activeChannel?.members?.map(member => member.id) ?? []
)
const { contacts, createGroupChat, addMembers } = useMessengerContext()
const groupChatMembers = useMemo(
() => groupChatMembersIds.map((id) => contacts[id]).filter((e) => !!e),
() => groupChatMembersIds.map(id => contacts[id]).filter(e => !!e),
[groupChatMembersIds, contacts]
);
)
const contactsList = useMemo(() => {
return Object.values(contacts)
.filter(
(member) =>
member =>
member.id.includes(query) ||
member?.customName?.includes(query) ||
member.trueName.includes(query)
)
.filter((member) => !groupChatMembersIds.includes(member.id));
}, [query, groupChatMembersIds, contacts]);
.filter(member => !groupChatMembersIds.includes(member.id))
}, [query, groupChatMembersIds, contacts])
const setChatState = useChatState()[1];
const setChatState = useChatState()[1]
const addMember = useCallback(
(member: string) => {
setGroupChatMembersIds((prevMembers: string[]) => {
if (
prevMembers.find((mem) => mem === member) ||
prevMembers.find(mem => mem === member) ||
prevMembers.length >= 5
) {
return prevMembers;
return prevMembers
} else {
return [...prevMembers, member];
return [...prevMembers, member]
}
});
setQuery("");
})
setQuery('')
},
[setGroupChatMembersIds]
);
)
const removeMember = useCallback(
(member: string) => {
setGroupChatMembersIds((prev) => prev.filter((e) => e != member));
setGroupChatMembersIds(prev => prev.filter(e => e != member))
},
[setGroupChatMembersIds]
);
)
const createChat = useCallback(
(group: string[]) => {
if (userPK) {
const newGroup = group.slice();
newGroup.push(userPK);
createGroupChat(newGroup);
setChatState(ChatState.ChatBody);
const newGroup = group.slice()
newGroup.push(userPK)
createGroupChat(newGroup)
setChatState(ChatState.ChatBody)
}
},
[userPK, createGroupChat, setChatState]
);
)
const handleCreationClick = useCallback(() => {
if (!activeChannel) {
createChat(groupChatMembers.map((member) => member.id));
createChat(groupChatMembers.map(member => member.id))
} else {
addMembers(
groupChatMembers.map((member) => member.id),
groupChatMembers.map(member => member.id),
activeChannel.id
);
)
}
setEditGroup?.(false);
}, [activeChannel, groupChatMembers, createChat, addMembers, setEditGroup]);
setEditGroup?.(false)
}, [activeChannel, groupChatMembers, createChat, addMembers, setEditGroup])
return (
<CreationWrapper className={`${narrow && "narrow"}`}>
<CreationWrapper className={`${narrow && 'narrow'}`}>
<CreationBar
className={`${groupChatMembers.length === 5 && narrow && "limit"}`}
className={`${groupChatMembers.length === 5 && narrow && 'limit'}`}
>
{narrow && (
<BackButton
@ -117,7 +117,7 @@ export function ChatCreation({
<InputBar>
<InputText>To:</InputText>
<StyledList>
{groupChatMembers.map((member) => (
{groupChatMembers.map(member => (
<StyledMember key={member.id}>
<StyledName>
{member?.customName?.slice(0, 10) ??
@ -133,7 +133,7 @@ export function ChatCreation({
<SearchMembers>
<Input
value={query}
onInput={(e) => setQuery(e.currentTarget.value)}
onInput={e => setQuery(e.currentTarget.value)}
/>
</SearchMembers>
)}
@ -166,7 +166,7 @@ export function ChatCreation({
<ContactsHeading>Contacts</ContactsHeading>
<ContactsList>
{userPK && narrow
? contactsList.map((contact) => (
? contactsList.map(contact => (
<Contact key={contact.id}>
<Member
contact={contact}
@ -177,10 +177,9 @@ export function ChatCreation({
))
: Object.values(contacts)
.filter(
(e) =>
e.id != userPK && !groupChatMembersIds.includes(e.id)
e => e.id != userPK && !groupChatMembersIds.includes(e.id)
)
.map((contact) => (
.map(contact => (
<Contact key={contact.id}>
<Member
contact={contact}
@ -195,10 +194,10 @@ export function ChatCreation({
{!setEditGroup && Object.keys(contacts).length === 0 && (
<EmptyContacts>
<EmptyContactsHeading>
You only can send direct messages to your Contacts.{" "}
You only can send direct messages to your Contacts.{' '}
</EmptyContactsHeading>
<EmptyContactsHeading>
{" "}
{' '}
Send a contact request to the person you would like to chat with,
you will be able to chat with them once they have accepted your
contact request.
@ -209,11 +208,11 @@ export function ChatCreation({
{!activeChannel && (
<ChatInput
createChat={createChat}
group={groupChatMembers.map((member) => member.id)}
group={groupChatMembers.map(member => member.id)}
/>
)}
</CreationWrapper>
);
)
}
const CreationWrapper = styled.div`
@ -229,7 +228,7 @@ const CreationWrapper = styled.div`
width: 100%;
max-width: 100%;
}
`;
`
const CreationBar = styled.div`
display: flex;
@ -240,7 +239,7 @@ const CreationBar = styled.div`
&.limit {
align-items: flex-start;
}
`;
`
const Column = styled.div`
display: flex;
@ -249,7 +248,7 @@ const Column = styled.div`
flex: 1;
margin-right: 16px;
overflow-x: hidden;
`;
`
const InputBar = styled.div`
display: flex;
@ -262,7 +261,7 @@ const InputBar = styled.div`
padding: 6px 16px;
${textMediumStyles}
`;
`
const Input = styled.input`
width: 100%;
@ -278,12 +277,12 @@ const Input = styled.input`
outline: none;
caret-color: ${({ theme }) => theme.notificationColor};
}
`;
`
const InputText = styled.div`
color: ${({ theme }) => theme.secondary};
margin-right: 8px;
`;
`
const CreationBtn = styled.button`
padding: 11px 24px;
@ -293,7 +292,7 @@ const CreationBtn = styled.button`
background: ${({ theme }) => theme.inputColor};
color: ${({ theme }) => theme.secondary};
}
`;
`
const StyledList = styled.div`
display: flex;
@ -303,7 +302,7 @@ const StyledList = styled.div`
&::-webkit-scrollbar {
display: none;
}
`;
`
const StyledMember = styled.div`
display: flex;
@ -316,18 +315,18 @@ const StyledMember = styled.div`
& + & {
margin-left: 8px;
}
`;
`
const StyledName = styled.p`
color: ${({ theme }) => theme.bodyBackgroundColor};
${textMediumStyles}
`;
`
const CloseButton = styled.button`
width: 20px;
height: 20px;
`;
`
const Contacts = styled.div`
height: calc(100% - 44px);
@ -335,7 +334,7 @@ const Contacts = styled.div`
flex-direction: column;
flex: 1;
overflow: auto;
`;
`
const Contact = styled.div`
display: flex;
@ -346,34 +345,34 @@ const Contact = styled.div`
&:hover {
background: ${({ theme }) => theme.inputColor};
}
`;
`
const ContactsHeading = styled.p`
color: ${({ theme }) => theme.secondary};
${textMediumStyles}
`;
`
export const ContactsList = styled.div`
display: flex;
flex-direction: column;
`;
`
const EmptyContacts = styled(Contacts)`
justify-content: center;
align-items: center;
`;
`
const EmptyContactsHeading = styled(ContactsHeading)`
max-width: 550px;
margin-bottom: 24px;
text-align: center;
`;
`
const SearchMembers = styled.div`
position: relative;
flex: 1;
`;
`
const LimitAlert = styled.p`
text-transform: uppercase;
@ -384,4 +383,4 @@ const LimitAlert = styled.p`
&.narrow {
margin: 8px 0 0;
}
`;
`

View File

@ -1,42 +1,36 @@
import { EmojiData } from "emoji-mart";
import React, {
useCallback,
useEffect,
useMemo,
useRef,
useState,
} from "react";
import styled from "styled-components";
import { EmojiData } from 'emoji-mart'
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
import styled from 'styled-components'
import { ChatState, useChatState } from "../../contexts/chatStateProvider";
import { useIdentity } from "../../contexts/identityProvider";
import { useMessengerContext } from "../../contexts/messengerProvider";
import { useModal } from "../../contexts/modalProvider";
import { useNarrow } from "../../contexts/narrowProvider";
import { useClickOutside } from "../../hooks/useClickOutside";
import { Reply } from "../../hooks/useReply";
import { uintToImgUrl } from "../../utils/uintToImgUrl";
import { ClearBtn } from "../Form/inputStyles";
import { ClearSvg } from "../Icons/ClearIcon";
import { ClearSvgFull } from "../Icons/ClearIconFull";
import { EmojiIcon } from "../Icons/EmojiIcon";
import { GifIcon } from "../Icons/GifIcon";
import { PictureIcon } from "../Icons/PictureIcon";
import { ReplySvg } from "../Icons/ReplyIcon";
import { StickerIcon } from "../Icons/StickerIcon";
import "emoji-mart/css/emoji-mart.css";
import { SizeLimitModal, SizeLimitModalName } from "../Modals/SizeLimitModal";
import { UserCreationStartModalName } from "../Modals/UserCreationStartModal";
import { SearchBlock } from "../SearchBlock";
import { textMediumStyles, textSmallStyles } from "../Text";
import { ChatState, useChatState } from '../../contexts/chatStateProvider'
import { useIdentity } from '../../contexts/identityProvider'
import { useMessengerContext } from '../../contexts/messengerProvider'
import { useModal } from '../../contexts/modalProvider'
import { useNarrow } from '../../contexts/narrowProvider'
import { useClickOutside } from '../../hooks/useClickOutside'
import { Reply } from '../../hooks/useReply'
import { uintToImgUrl } from '../../utils/uintToImgUrl'
import { ClearBtn } from '../Form/inputStyles'
import { ClearSvg } from '../Icons/ClearIcon'
import { ClearSvgFull } from '../Icons/ClearIconFull'
import { EmojiIcon } from '../Icons/EmojiIcon'
import { GifIcon } from '../Icons/GifIcon'
import { PictureIcon } from '../Icons/PictureIcon'
import { ReplySvg } from '../Icons/ReplyIcon'
import { StickerIcon } from '../Icons/StickerIcon'
import 'emoji-mart/css/emoji-mart.css'
import { SizeLimitModal, SizeLimitModalName } from '../Modals/SizeLimitModal'
import { UserCreationStartModalName } from '../Modals/UserCreationStartModal'
import { SearchBlock } from '../SearchBlock'
import { textMediumStyles, textSmallStyles } from '../Text'
import { EmojiPicker } from "./EmojiPicker";
import { EmojiPicker } from './EmojiPicker'
interface ChatInputProps {
reply?: Reply | undefined;
setReply?: (val: Reply | undefined) => void;
createChat?: (group: string[]) => void;
group?: string[];
reply?: Reply | undefined
setReply?: (val: Reply | undefined) => void
createChat?: (group: string[]) => void
group?: string[]
}
export function ChatInput({
@ -45,109 +39,109 @@ export function ChatInput({
createChat,
group,
}: ChatInputProps) {
const narrow = useNarrow();
const identity = useIdentity();
const setChatState = useChatState()[1];
const disabled = useMemo(() => !identity, [identity]);
const { sendMessage, contacts } = useMessengerContext();
const [content, setContent] = useState("");
const [clearComponent, setClearComponent] = useState("");
const [showEmoji, setShowEmoji] = useState(false);
const [inputHeight, setInputHeight] = useState(40);
const [imageUint, setImageUint] = useState<undefined | Uint8Array>(undefined);
const narrow = useNarrow()
const identity = useIdentity()
const setChatState = useChatState()[1]
const disabled = useMemo(() => !identity, [identity])
const { sendMessage, contacts } = useMessengerContext()
const [content, setContent] = useState('')
const [clearComponent, setClearComponent] = useState('')
const [showEmoji, setShowEmoji] = useState(false)
const [inputHeight, setInputHeight] = useState(40)
const [imageUint, setImageUint] = useState<undefined | Uint8Array>(undefined)
const { setModal } = useModal(SizeLimitModalName);
const { setModal } = useModal(SizeLimitModalName)
const { setModal: setCreationStartModal } = useModal(
UserCreationStartModalName
);
)
const [query, setQuery] = useState("");
const [query, setQuery] = useState('')
const inputRef = useRef<HTMLDivElement>(null);
const inputRef = useRef<HTMLDivElement>(null)
const ref = useRef(null);
useClickOutside(ref, () => setShowEmoji(false));
const ref = useRef(null)
useClickOutside(ref, () => setShowEmoji(false))
const image = useMemo(
() => (imageUint ? uintToImgUrl(imageUint) : ""),
() => (imageUint ? uintToImgUrl(imageUint) : ''),
[imageUint]
);
)
const addEmoji = useCallback(
(e: EmojiData) => {
if ("unified" in e) {
const sym = e.unified.split("-");
const codesArray: string[] = [];
sym.forEach((el: string) => codesArray.push("0x" + el));
if ('unified' in e) {
const sym = e.unified.split('-')
const codesArray: string[] = []
sym.forEach((el: string) => codesArray.push('0x' + el))
const emoji = String.fromCodePoint(
...(codesArray as unknown as number[])
);
)
if (inputRef.current) {
inputRef.current.appendChild(document.createTextNode(emoji));
inputRef.current.appendChild(document.createTextNode(emoji))
}
setContent((p) => p + emoji);
setContent(p => p + emoji)
}
},
[setContent]
);
)
const resizeTextArea = useCallback((target: HTMLDivElement) => {
target.style.height = "40px";
target.style.height = `${Math.min(target.scrollHeight, 438)}px`;
setInputHeight(target.scrollHeight);
}, []);
target.style.height = '40px'
target.style.height = `${Math.min(target.scrollHeight, 438)}px`
setInputHeight(target.scrollHeight)
}, [])
const rowHeight = inputHeight + (image ? 73 : 0);
const rowHeight = inputHeight + (image ? 73 : 0)
const onInputChange = useCallback(
(e: React.ChangeEvent<HTMLDivElement>) => {
const element = document.getSelection();
const inputElement = inputRef.current;
const element = document.getSelection()
const inputElement = inputRef.current
if (inputElement && element && element.rangeCount > 0) {
const selection = element?.getRangeAt(0)?.startOffset;
const parentElement = element.anchorNode?.parentElement;
if (parentElement && parentElement.tagName === "B") {
parentElement.outerHTML = parentElement.innerText;
const range = document.createRange();
const sel = window.getSelection();
const selection = element?.getRangeAt(0)?.startOffset
const parentElement = element.anchorNode?.parentElement
if (parentElement && parentElement.tagName === 'B') {
parentElement.outerHTML = parentElement.innerText
const range = document.createRange()
const sel = window.getSelection()
if (element.anchorNode.firstChild) {
const childNumber =
element.focusOffset === 0 ? 0 : element.focusOffset - 1;
element.focusOffset === 0 ? 0 : element.focusOffset - 1
range.setStart(
element.anchorNode.childNodes[childNumber],
selection
);
)
}
range.collapse(true);
range.collapse(true)
sel?.removeAllRanges();
sel?.addRange(range);
sel?.removeAllRanges()
sel?.addRange(range)
}
}
const target = e.target;
resizeTextArea(target);
setContent(target.textContent ?? "");
const target = e.target
resizeTextArea(target)
setContent(target.textContent ?? '')
},
[resizeTextArea]
);
)
const onInputKeyPress = useCallback(
(e: React.KeyboardEvent<HTMLDivElement>) => {
if (e.key == "Enter" && !e.getModifierState("Shift")) {
e.preventDefault();
(e.target as HTMLDivElement).style.height = "40px";
setInputHeight(40);
sendMessage(content, imageUint, reply?.id);
setImageUint(undefined);
setClearComponent("");
if (e.key == 'Enter' && !e.getModifierState('Shift')) {
e.preventDefault()
;(e.target as HTMLDivElement).style.height = '40px'
setInputHeight(40)
sendMessage(content, imageUint, reply?.id)
setImageUint(undefined)
setClearComponent('')
if (inputRef.current) {
inputRef.current.innerHTML = "";
inputRef.current.innerHTML = ''
}
setContent("");
if (setReply) setReply(undefined);
setContent('')
if (setReply) setReply(undefined)
if (createChat && group) {
createChat(group);
setChatState(ChatState.ChatBody);
createChat(group)
setChatState(ChatState.ChatBody)
}
}
},
@ -161,88 +155,88 @@ export function ChatInput({
setChatState,
setReply,
]
);
)
const [selectedElement, setSelectedElement] = useState<{
element: Selection | null;
start: number;
end: number;
text: string;
node: Node | null;
}>({ element: null, start: 0, end: 0, text: "", node: null });
element: Selection | null
start: number
end: number
text: string
node: Node | null
}>({ element: null, start: 0, end: 0, text: '', node: null })
const handleCursorChange = useCallback(() => {
const element = document.getSelection();
const element = document.getSelection()
if (element && element.rangeCount > 0) {
const selection = element?.getRangeAt(0)?.startOffset;
const text = element?.anchorNode?.textContent;
const selection = element?.getRangeAt(0)?.startOffset
const text = element?.anchorNode?.textContent
if (selection && text) {
const end = text.indexOf(" ", selection);
const start = text.lastIndexOf(" ", selection - 1);
const end = text.indexOf(' ', selection)
const start = text.lastIndexOf(' ', selection - 1)
setSelectedElement({
element,
start,
end,
text,
node: element.anchorNode,
});
})
const substring = text.substring(
start > -1 ? start + 1 : 0,
end > -1 ? end : undefined
);
if (substring.startsWith("@")) {
setQuery(substring.slice(1));
)
if (substring.startsWith('@')) {
setQuery(substring.slice(1))
} else {
setQuery("");
setQuery('')
}
}
}
}, []);
}, [])
useEffect(handleCursorChange, [content, handleCursorChange]);
useEffect(handleCursorChange, [content, handleCursorChange])
const addMention = useCallback(
(contact: string) => {
if (inputRef?.current) {
const { element, start, end, text, node } = selectedElement;
const { element, start, end, text, node } = selectedElement
if (element && text && node) {
const firstSlice = text.slice(0, start > -1 ? start : 0);
const secondSlice = text.slice(end > -1 ? end : content.length);
const replaceContent = `${firstSlice} @${contact}${secondSlice}`;
const spaceElement = document.createTextNode(" ");
const contactElement = document.createElement("span");
contactElement.innerText = `@${contact}`;
const firstSlice = text.slice(0, start > -1 ? start : 0)
const secondSlice = text.slice(end > -1 ? end : content.length)
const replaceContent = `${firstSlice} @${contact}${secondSlice}`
const spaceElement = document.createTextNode(' ')
const contactElement = document.createElement('span')
contactElement.innerText = `@${contact}`
if (contactElement && element.rangeCount > 0) {
const range = element.getRangeAt(0);
range.setStart(node, start > -1 ? start : 0);
const range = element.getRangeAt(0)
range.setStart(node, start > -1 ? start : 0)
if (end === -1 || end > text.length) {
range.setEnd(node, text.length);
range.setEnd(node, text.length)
} else {
range.setEnd(node, end);
range.setEnd(node, end)
}
range.deleteContents();
range.deleteContents()
if (end === -1) {
range.insertNode(spaceElement.cloneNode());
range.insertNode(spaceElement.cloneNode())
}
range.insertNode(contactElement);
range.insertNode(contactElement)
if (start > -1) {
range.insertNode(spaceElement.cloneNode());
range.insertNode(spaceElement.cloneNode())
}
range.collapse();
range.collapse()
}
inputRef.current.focus();
setQuery("");
setContent(replaceContent);
resizeTextArea(inputRef.current);
inputRef.current.focus()
setQuery('')
setContent(replaceContent)
resizeTextArea(inputRef.current)
}
}
},
[inputRef, content, selectedElement, resizeTextArea]
);
)
return (
<View className={`${createChat && "creation"}`}>
<View className={`${createChat && 'creation'}`}>
<SizeLimitModal />
<AddPictureInputWrapper>
<PictureIcon />
@ -251,18 +245,18 @@ export function ChatInput({
type="file"
multiple={true}
accept="image/png, image/jpeg"
onChange={(e) => {
const fileReader = new FileReader();
fileReader.onloadend = (s) => {
const arr = new Uint8Array(s.target?.result as ArrayBuffer);
setImageUint(arr);
};
onChange={e => {
const fileReader = new FileReader()
fileReader.onloadend = s => {
const arr = new Uint8Array(s.target?.result as ArrayBuffer)
setImageUint(arr)
}
if (e?.target?.files?.[0]) {
if (e.target.files[0].size < 1024 * 1024) {
fileReader.readAsArrayBuffer(e.target.files[0]);
fileReader.readAsArrayBuffer(e.target.files[0])
} else {
setModal(true);
setModal(true)
}
}
}}
@ -272,8 +266,8 @@ export function ChatInput({
{reply && (
<ReplyWrapper>
<ReplyTo>
{" "}
<ReplySvg width={18} height={18} className="input" />{" "}
{' '}
<ReplySvg width={18} height={18} className="input" />{' '}
{contacts[reply.sender]?.customName ??
contacts[reply.sender].trueName}
</ReplyTo>
@ -281,10 +275,10 @@ export function ChatInput({
{reply.image && <ImagePreview src={reply.image} />}
<CloseButton
onClick={() => {
if (setReply) setReply(undefined);
if (setReply) setReply(undefined)
}}
>
{" "}
{' '}
<ClearSvg width={20} height={20} className="input" />
</CloseButton>
</ReplyWrapper>
@ -314,10 +308,10 @@ export function ChatInput({
onClick={handleCursorChange}
dangerouslySetInnerHTML={{
__html: disabled
? "You need to join this community to send messages"
? 'You need to join this community to send messages'
: clearComponent,
}}
className={`${disabled && "disabled"} `}
className={`${disabled && 'disabled'} `}
/>
)}
{query && (
@ -333,7 +327,7 @@ export function ChatInput({
<EmojiWrapper ref={ref}>
<ChatButton
onClick={() => {
if (!disabled) setShowEmoji(!showEmoji);
if (!disabled) setShowEmoji(!showEmoji)
}}
disabled={disabled}
>
@ -355,7 +349,7 @@ export function ChatInput({
</Row>
</InputArea>
</View>
);
)
}
const InputWrapper = styled.div`
@ -363,11 +357,11 @@ const InputWrapper = styled.div`
flex-direction: column;
width: 100%;
position: relative;
`;
`
const EmojiWrapper = styled.div`
position: relative;
`;
`
const View = styled.div`
display: flex;
@ -378,7 +372,7 @@ const View = styled.div`
&.creation {
padding: 0;
}
`;
`
const InputArea = styled.div`
position: relative;
@ -389,7 +383,7 @@ const InputArea = styled.div`
padding: 2px;
background: ${({ theme }) => theme.inputColor};
border-radius: 16px 16px 4px 16px;
`;
`
const Row = styled.div`
position: relative;
@ -400,7 +394,7 @@ const Row = styled.div`
padding-right: 6px;
background: ${({ theme }) => theme.inputColor};
border-radius: 16px 16px 4px 16px;
`;
`
const InputButtons = styled.div`
display: flex;
@ -409,19 +403,19 @@ const InputButtons = styled.div`
button + button {
margin-left: 4px;
}
`;
`
const ImageWrapper = styled.div`
width: 64px;
position: relative;
`;
`
const ImagePreview = styled.img`
width: 64px;
height: 64px;
border-radius: 16px 16px 4px 16px;
margin-left: 8px;
margin-top: 9px;
`;
`
const ClearImgBtn = styled(ClearBtn)`
width: 24px;
@ -432,7 +426,7 @@ const ClearImgBtn = styled(ClearBtn)`
padding: 0;
border: 2px solid ${({ theme }) => theme.inputColor};
background-color: ${({ theme }) => theme.inputColor};
`;
`
const Input = styled.div`
display: block;
@ -480,7 +474,7 @@ const Input = styled.div`
cursor: default;
}
}
`;
`
const AddPictureInputWrapper = styled.div`
position: relative;
@ -491,14 +485,14 @@ const AddPictureInputWrapper = styled.div`
height: 32px;
margin-right: 4px;
& > input[type="file"]::-webkit-file-upload-button {
& > input[type='file']::-webkit-file-upload-button {
cursor: pointer;
}
& > input:disabled::-webkit-file-upload-button {
cursor: default;
}
`;
`
const AddPictureInput = styled.input`
position: absolute;
@ -507,7 +501,7 @@ const AddPictureInput = styled.input`
width: 100%;
height: 100%;
opacity: 0;
`;
`
const ChatButton = styled.button`
width: 32px;
@ -516,13 +510,13 @@ const ChatButton = styled.button`
&:disabled {
cursor: default;
}
`;
`
const CloseButton = styled(ChatButton)`
position: absolute;
top: 0;
right: 0;
`;
`
const ReplyWrapper = styled.div`
display: flex;
@ -533,14 +527,14 @@ const ReplyWrapper = styled.div`
color: ${({ theme }) => theme.primary};
border-radius: 14px 14px 4px 14px;
position: relative;
`;
`
export const ReplyTo = styled.div`
display: flex;
align-items: center;
font-weight: 500;
${textSmallStyles};
`;
`
export const ReplyOn = styled.div`
width: 100%;
@ -548,7 +542,7 @@ export const ReplyOn = styled.div`
white-space: nowrap;
text-overflow: ellipsis;
${textSmallStyles};
`;
`
const JoinBtn = styled.button`
color: ${({ theme }) => theme.secondary};
@ -559,4 +553,4 @@ const JoinBtn = styled.button`
text-align: start;
${textMediumStyles};
`;
`

View File

@ -1,39 +1,39 @@
import { decode } from "html-entities";
import React, { useEffect, useMemo, useRef, useState } from "react";
import styled from "styled-components";
import { decode } from 'html-entities'
import React, { useEffect, useMemo, useRef, useState } from 'react'
import styled from 'styled-components'
import { useFetchMetadata } from "../../contexts/fetchMetadataProvider";
import { useUserPublicKey } from "../../contexts/identityProvider";
import { useMessengerContext } from "../../contexts/messengerProvider";
import { useClickOutside } from "../../hooks/useClickOutside";
import { ChatMessage } from "../../models/ChatMessage";
import { Metadata } from "../../models/Metadata";
import { ContactMenu } from "../Form/ContactMenu";
import { ImageMenu } from "../Form/ImageMenu";
import { textMediumStyles, textSmallStyles } from "../Text";
import { useFetchMetadata } from '../../contexts/fetchMetadataProvider'
import { useUserPublicKey } from '../../contexts/identityProvider'
import { useMessengerContext } from '../../contexts/messengerProvider'
import { useClickOutside } from '../../hooks/useClickOutside'
import { ChatMessage } from '../../models/ChatMessage'
import { Metadata } from '../../models/Metadata'
import { ContactMenu } from '../Form/ContactMenu'
import { ImageMenu } from '../Form/ImageMenu'
import { textMediumStyles, textSmallStyles } from '../Text'
interface MentionProps {
id: string;
setMentioned: (val: boolean) => void;
className?: string;
id: string
setMentioned: (val: boolean) => void
className?: string
}
export function Mention({ id, setMentioned, className }: MentionProps) {
const { contacts } = useMessengerContext();
const contact = useMemo(() => contacts[id.slice(1)], [id, contacts]);
const [showMenu, setShowMenu] = useState(false);
const userPK = useUserPublicKey();
const { contacts } = useMessengerContext()
const contact = useMemo(() => contacts[id.slice(1)], [id, contacts])
const [showMenu, setShowMenu] = useState(false)
const userPK = useUserPublicKey()
useEffect(() => {
if (userPK && contact) {
if (contact.id === userPK) setMentioned(true);
if (contact.id === userPK) setMentioned(true)
}
}, [contact, userPK, setMentioned]);
}, [contact, userPK, setMentioned])
const ref = useRef(null);
useClickOutside(ref, () => setShowMenu(false));
const ref = useRef(null)
useClickOutside(ref, () => setShowMenu(false))
if (!contact) return <>{id}</>;
if (!contact) return <>{id}</>
return (
<MentionBLock
onClick={() => setShowMenu(!showMenu)}
@ -43,15 +43,15 @@ export function Mention({ id, setMentioned, className }: MentionProps) {
{`@${contact?.customName ?? contact.trueName}`}
{showMenu && <ContactMenu id={id.slice(1)} setShowMenu={setShowMenu} />}
</MentionBLock>
);
)
}
type ChatMessageContentProps = {
message: ChatMessage;
setImage: (image: string) => void;
setLinkOpen: (link: string) => void;
setMentioned: (val: boolean) => void;
};
message: ChatMessage
setImage: (image: string) => void
setLinkOpen: (link: string) => void
setMentioned: (val: boolean) => void
}
export function ChatMessageContent({
message,
@ -59,82 +59,82 @@ export function ChatMessageContent({
setLinkOpen,
setMentioned,
}: ChatMessageContentProps) {
const fetchMetadata = useFetchMetadata();
const { content, image } = useMemo(() => message, [message]);
const fetchMetadata = useFetchMetadata()
const { content, image } = useMemo(() => message, [message])
const [elements, setElements] = useState<(string | React.ReactElement)[]>([
content,
]);
const [link, setLink] = useState<string | undefined>(undefined);
const [openGraph, setOpenGraph] = useState<Metadata | undefined>(undefined);
])
const [link, setLink] = useState<string | undefined>(undefined)
const [openGraph, setOpenGraph] = useState<Metadata | undefined>(undefined)
useEffect(() => {
let link;
const split = content.split(" ");
let link
const split = content.split(' ')
const newSplit = split.flatMap((element, idx) => {
if (element.startsWith("http://") || element.startsWith("https://")) {
link = element;
if (element.startsWith('http://') || element.startsWith('https://')) {
link = element
return [
<Link key={idx} onClick={() => setLinkOpen(element)}>
{element}
</Link>,
" ",
];
' ',
]
}
if (element.startsWith("@")) {
if (element.startsWith('@')) {
return [
<Mention key={idx} id={element} setMentioned={setMentioned} />,
" ",
];
' ',
]
}
return [element, " "];
});
newSplit.pop();
setLink(link);
setElements(newSplit);
}, [content, setLink, setMentioned, setElements, setLinkOpen]);
return [element, ' ']
})
newSplit.pop()
setLink(link)
setElements(newSplit)
}, [content, setLink, setMentioned, setElements, setLinkOpen])
useEffect(() => {
const updatePreview = async () => {
if (link && fetchMetadata) {
try {
const metadata = await fetchMetadata(link);
const metadata = await fetchMetadata(link)
if (metadata) {
setOpenGraph(metadata);
setOpenGraph(metadata)
}
} catch {
return;
return
}
}
};
updatePreview();
}, [link, fetchMetadata]);
}
updatePreview()
}, [link, fetchMetadata])
return (
<ContentWrapper>
<div>{elements.map((el) => el)}</div>
<div>{elements.map(el => el)}</div>
{image && (
<MessageImageWrapper>
<MessageImage
src={image}
id={image}
onClick={() => {
setImage(image);
setImage(image)
}}
/>
<ImageMenu imageId={image} />
</MessageImageWrapper>
)}
{openGraph && (
<PreviewWrapper onClick={() => setLinkOpen(link ?? "")}>
<PreviewImage src={decodeURI(decode(openGraph["og:image"]))} />
<PreviewTitleWrapper>{openGraph["og:title"]}</PreviewTitleWrapper>
<PreviewWrapper onClick={() => setLinkOpen(link ?? '')}>
<PreviewImage src={decodeURI(decode(openGraph['og:image']))} />
<PreviewTitleWrapper>{openGraph['og:title']}</PreviewTitleWrapper>
<PreviewSiteNameWrapper>
{openGraph["og:site_name"]}
{openGraph['og:site_name']}
</PreviewSiteNameWrapper>
</PreviewWrapper>
)}
</ContentWrapper>
);
)
}
const MessageImageWrapper = styled.div`
@ -142,7 +142,7 @@ const MessageImageWrapper = styled.div`
height: 196px;
margin-top: 8px;
position: relative;
`;
`
const MessageImage = styled.img`
width: 100%;
@ -150,10 +150,10 @@ const MessageImage = styled.img`
object-fit: cover;
border-radius: 16px;
cursor: pointer;
`;
`
const PreviewSiteNameWrapper = styled.div`
font-family: "Inter";
font-family: 'Inter';
font-style: normal;
font-weight: normal;
font-size: 12px;
@ -162,7 +162,7 @@ const PreviewSiteNameWrapper = styled.div`
margin-top: 2px;
color: #939ba1;
margin-left: 12px;
`;
`
const PreviewTitleWrapper = styled.div`
margin-top: 7px;
@ -176,13 +176,13 @@ const PreviewTitleWrapper = styled.div`
margin-left: 12px;
${textSmallStyles}
`;
`
const PreviewImage = styled.img`
border-radius: 15px 15px 15px 4px;
width: 305px;
height: 170px;
`;
`
const PreviewWrapper = styled.div`
margin-top: 9px;
@ -195,12 +195,12 @@ const PreviewWrapper = styled.div`
display: flex;
flex-direction: column;
padding: 0px;
`;
`
const ContentWrapper = styled.div`
display: flex;
flex-direction: column;
`;
`
const MentionBLock = styled.div`
display: inline-flex;
@ -224,10 +224,10 @@ const MentionBLock = styled.div`
}
${textMediumStyles}
`;
`
const Link = styled.a`
text-decoration: underline;
cursor: pointer;
color: ${({ theme }) => theme.memberNameColor};
`;
`

View File

@ -1,30 +1,30 @@
import React, { useRef, useState } from "react";
import styled from "styled-components";
import React, { useRef, useState } from 'react'
import styled from 'styled-components'
import { useMessengerContext } from "../../contexts/messengerProvider";
import { useNarrow } from "../../contexts/narrowProvider";
import { useClickOutside } from "../../hooks/useClickOutside";
import { useMessengerContext } from '../../contexts/messengerProvider'
import { useNarrow } from '../../contexts/narrowProvider'
import { useClickOutside } from '../../hooks/useClickOutside'
import {
ActivityButton,
ActivityWrapper,
} from "../ActivityCenter/ActivityButton";
import { Channel } from "../Channels/Channel";
import { Community } from "../Community";
import { ChannelMenu } from "../Form/ChannelMenu";
import { ActivityIcon } from "../Icons/ActivityIcon";
import { MembersIcon } from "../Icons/MembersIcon";
import { MoreIcon } from "../Icons/MoreIcon";
import { CommunitySkeleton } from "../Skeleton/CommunitySkeleton";
import { Loading } from "../Skeleton/Loading";
} from '../ActivityCenter/ActivityButton'
import { Channel } from '../Channels/Channel'
import { Community } from '../Community'
import { ChannelMenu } from '../Form/ChannelMenu'
import { ActivityIcon } from '../Icons/ActivityIcon'
import { MembersIcon } from '../Icons/MembersIcon'
import { MoreIcon } from '../Icons/MoreIcon'
import { CommunitySkeleton } from '../Skeleton/CommunitySkeleton'
import { Loading } from '../Skeleton/Loading'
import { ChatBodyState } from "./ChatBody";
import { ChatBodyState } from './ChatBody'
export function ChatTopbarLoading() {
const narrow = useNarrow();
const narrow = useNarrow()
return (
<Topbar className={narrow ? "narrow" : ""}>
<ChannelWrapper className={narrow ? "narrow" : ""}>
<Topbar className={narrow ? 'narrow' : ''}>
<ChannelWrapper className={narrow ? 'narrow' : ''}>
<SkeletonWrapper>
<CommunitySkeleton />
</SkeletonWrapper>
@ -46,16 +46,16 @@ export function ChatTopbarLoading() {
</MenuWrapper>
<Loading />
</Topbar>
);
)
}
type ChatTopbarProps = {
showState: ChatBodyState;
onClick: () => void;
switchShowState: (state: ChatBodyState) => void;
showMembers: boolean;
setEditGroup: React.Dispatch<React.SetStateAction<boolean>>;
};
showState: ChatBodyState
onClick: () => void
switchShowState: (state: ChatBodyState) => void
showMembers: boolean
setEditGroup: React.Dispatch<React.SetStateAction<boolean>>
}
export function ChatTopbar({
showState,
@ -64,27 +64,27 @@ export function ChatTopbar({
showMembers,
setEditGroup,
}: ChatTopbarProps) {
const { activeChannel, loadingMessenger } = useMessengerContext();
const { activeChannel, loadingMessenger } = useMessengerContext()
const narrow = useNarrow();
const [showChannelMenu, setShowChannelMenu] = useState(false);
const narrow = useNarrow()
const [showChannelMenu, setShowChannelMenu] = useState(false)
const ref = useRef(null);
useClickOutside(ref, () => setShowChannelMenu(false));
const ref = useRef(null)
useClickOutside(ref, () => setShowChannelMenu(false))
if (!activeChannel) {
return <ChatTopbarLoading />;
return <ChatTopbarLoading />
}
return (
<Topbar
className={narrow && showState !== ChatBodyState.Chat ? "narrow" : ""}
className={narrow && showState !== ChatBodyState.Chat ? 'narrow' : ''}
>
<ChannelWrapper className={narrow ? "narrow" : ""}>
<ChannelWrapper className={narrow ? 'narrow' : ''}>
{!loadingMessenger ? (
<>
{narrow && (
<CommunityWrap className={narrow ? "narrow" : ""}>
<CommunityWrap className={narrow ? 'narrow' : ''}>
<Community />
</CommunityWrap>
)}
@ -104,8 +104,8 @@ export function ChatTopbar({
</ChannelWrapper>
<MenuWrapper>
{!narrow && activeChannel.type !== "dm" && (
<TopBtn onClick={onClick} className={showMembers ? "active" : ""}>
{!narrow && activeChannel.type !== 'dm' && (
<TopBtn onClick={onClick} className={showMembers ? 'active' : ''}>
<MembersIcon />
</TopBtn>
)}
@ -119,7 +119,7 @@ export function ChatTopbar({
switchMemberList={() => switchShowState(ChatBodyState.Members)}
setShowChannelMenu={setShowChannelMenu}
setEditGroup={setEditGroup}
className={`${narrow && "narrow"}`}
className={`${narrow && 'narrow'}`}
/>
)}
</TopBtn>
@ -128,7 +128,7 @@ export function ChatTopbar({
</MenuWrapper>
{loadingMessenger && <Loading />}
</Topbar>
);
)
}
const Topbar = styled.div`
@ -142,7 +142,7 @@ const Topbar = styled.div`
&.narrow {
width: 100%;
}
`;
`
const ChannelWrapper = styled.div`
display: flex;
@ -152,11 +152,11 @@ const ChannelWrapper = styled.div`
&.narrow {
width: calc(100% - 46px);
}
`;
`
const SkeletonWrapper = styled.div`
padding: 8px;
`;
`
const CommunityWrap = styled.div`
padding-right: 10px;
@ -168,7 +168,7 @@ const CommunityWrap = styled.div`
}
&:after {
content: "";
content: '';
position: absolute;
right: 0;
top: 50%;
@ -179,13 +179,13 @@ const CommunityWrap = styled.div`
background: ${({ theme }) => theme.primary};
opacity: 0.1;
}
`;
`
const MenuWrapper = styled.div`
display: flex;
align-items: center;
padding: 8px 0;
`;
`
export const TopBtn = styled.button`
width: 32px;
@ -206,4 +206,4 @@ export const TopBtn = styled.button`
&:disabled {
cursor: default;
}
`;
`

View File

@ -1,41 +1,41 @@
import { EmojiData, Picker } from "emoji-mart";
import React from "react";
import { useTheme } from "styled-components";
import { EmojiData, Picker } from 'emoji-mart'
import React from 'react'
import { useTheme } from 'styled-components'
import { useLow } from "../../contexts/narrowProvider";
import { lightTheme, Theme } from "../../styles/themes";
import { useLow } from '../../contexts/narrowProvider'
import { lightTheme, Theme } from '../../styles/themes'
type EmojiPickerProps = {
showEmoji: boolean;
addEmoji: (e: EmojiData) => void;
bottom: number;
};
showEmoji: boolean
addEmoji: (e: EmojiData) => void
bottom: number
}
export function EmojiPicker({ showEmoji, addEmoji, bottom }: EmojiPickerProps) {
const theme = useTheme() as Theme;
const low = useLow();
const theme = useTheme() as Theme
const low = useLow()
if (showEmoji) {
return (
<Picker
onSelect={addEmoji}
theme={theme === lightTheme ? "light" : "dark"}
theme={theme === lightTheme ? 'light' : 'dark'}
set="twitter"
color={theme.tertiary}
emojiSize={26}
style={{
position: "absolute",
position: 'absolute',
bottom: `calc(100% + ${bottom}px)`,
right: "-76px",
right: '-76px',
color: theme.secondary,
height: low ? "200px" : "355px",
overflow: "auto",
height: low ? '200px' : '355px',
overflow: 'auto',
}}
showPreview={false}
showSkinTones={false}
title={""}
title={''}
/>
);
)
}
return null;
return null
}

View File

@ -1,27 +1,27 @@
import React from "react";
import styled from "styled-components";
import React from 'react'
import styled from 'styled-components'
import { useMessengerContext } from "../contexts/messengerProvider";
import { useModal } from "../contexts/modalProvider";
import { useMessengerContext } from '../contexts/messengerProvider'
import { useModal } from '../contexts/modalProvider'
import { CommunityIdentity } from "./CommunityIdentity";
import { CommunityModalName } from "./Modals/CommunityModal";
import { CommunitySkeleton } from "./Skeleton/CommunitySkeleton";
import { CommunityIdentity } from './CommunityIdentity'
import { CommunityModalName } from './Modals/CommunityModal'
import { CommunitySkeleton } from './Skeleton/CommunitySkeleton'
interface CommunityProps {
className?: string;
className?: string
}
export function Community({ className }: CommunityProps) {
const { communityData } = useMessengerContext();
const { setModal } = useModal(CommunityModalName);
const { communityData } = useMessengerContext()
const { setModal } = useModal(CommunityModalName)
if (!communityData) {
return (
<SkeletonWrapper>
<CommunitySkeleton />
</SkeletonWrapper>
);
)
}
return (
@ -30,9 +30,9 @@ export function Community({ className }: CommunityProps) {
<CommunityIdentity subtitle={`${communityData.members} members`} />
</button>
</>
);
)
}
const SkeletonWrapper = styled.div`
margin-bottom: 16px;
`;
`

View File

@ -1,28 +1,28 @@
import React, { useRef } from "react";
import { ThemeProvider } from "styled-components";
import styled from "styled-components";
import React, { useRef } from 'react'
import { ThemeProvider } from 'styled-components'
import styled from 'styled-components'
import { ConfigType } from "..";
import { ChatStateProvider } from "../contexts/chatStateProvider";
import { ConfigProvider } from "../contexts/configProvider";
import { FetchMetadataProvider } from "../contexts/fetchMetadataProvider";
import { IdentityProvider } from "../contexts/identityProvider";
import { MessengerProvider } from "../contexts/messengerProvider";
import { ModalProvider } from "../contexts/modalProvider";
import { NarrowProvider } from "../contexts/narrowProvider";
import { ScrollProvider } from "../contexts/scrollProvider";
import { ToastProvider } from "../contexts/toastProvider";
import { Metadata } from "../models/Metadata";
import { GlobalStyle } from "../styles/GlobalStyle";
import { Theme } from "../styles/themes";
import { ConfigType } from '..'
import { ChatStateProvider } from '../contexts/chatStateProvider'
import { ConfigProvider } from '../contexts/configProvider'
import { FetchMetadataProvider } from '../contexts/fetchMetadataProvider'
import { IdentityProvider } from '../contexts/identityProvider'
import { MessengerProvider } from '../contexts/messengerProvider'
import { ModalProvider } from '../contexts/modalProvider'
import { NarrowProvider } from '../contexts/narrowProvider'
import { ScrollProvider } from '../contexts/scrollProvider'
import { ToastProvider } from '../contexts/toastProvider'
import { Metadata } from '../models/Metadata'
import { GlobalStyle } from '../styles/GlobalStyle'
import { Theme } from '../styles/themes'
import { CommunityChatRoom } from "./CommunityChatRoom";
import { CommunityChatRoom } from './CommunityChatRoom'
interface CommunityChatProps {
theme: Theme;
communityKey: string;
config: ConfigType;
fetchMetadata?: (url: string) => Promise<Metadata | undefined>;
theme: Theme
communityKey: string
config: ConfigType
fetchMetadata?: (url: string) => Promise<Metadata | undefined>
}
export function CommunityChat({
@ -31,7 +31,7 @@ export function CommunityChat({
fetchMetadata,
communityKey,
}: CommunityChatProps) {
const ref = useRef<HTMLHeadingElement>(null);
const ref = useRef<HTMLHeadingElement>(null)
return (
<ConfigProvider config={config}>
<ThemeProvider theme={theme}>
@ -58,10 +58,10 @@ export function CommunityChat({
</NarrowProvider>
</ThemeProvider>
</ConfigProvider>
);
)
}
const Wrapper = styled.div`
height: 100%;
overflow: hidden;
`;
`

View File

@ -1,29 +1,29 @@
import React, { useState } from "react";
import styled from "styled-components";
import React, { useState } from 'react'
import styled from 'styled-components'
import { ChatState, useChatState } from "../contexts/chatStateProvider";
import { useMessengerContext } from "../contexts/messengerProvider";
import { useNarrow } from "../contexts/narrowProvider";
import { ChatState, useChatState } from '../contexts/chatStateProvider'
import { useMessengerContext } from '../contexts/messengerProvider'
import { useNarrow } from '../contexts/narrowProvider'
import { Channels } from "./Channels/Channels";
import { ChatBody } from "./Chat/ChatBody";
import { ChatCreation } from "./Chat/ChatCreation";
import { Community } from "./Community";
import { Members } from "./Members/Members";
import { AgreementModal } from "./Modals/AgreementModal";
import { CoinbaseModal } from "./Modals/CoinbaseModal";
import { CommunityModal } from "./Modals/CommunityModal";
import { EditModal } from "./Modals/EditModal";
import { LeavingModal } from "./Modals/LeavingModal";
import { LogoutModal } from "./Modals/LogoutModal";
import { ProfileFoundModal } from "./Modals/ProfileFoundModal";
import { ProfileModal } from "./Modals/ProfileModal";
import { StatusModal } from "./Modals/StatusModal";
import { UserCreationModal } from "./Modals/UserCreationModal";
import { UserCreationStartModal } from "./Modals/UserCreationStartModal";
import { WalletConnectModal } from "./Modals/WalletConnectModal";
import { WalletModal } from "./Modals/WalletModal";
import { ToastMessageList } from "./ToastMessages/ToastMessageList";
import { Channels } from './Channels/Channels'
import { ChatBody } from './Chat/ChatBody'
import { ChatCreation } from './Chat/ChatCreation'
import { Community } from './Community'
import { Members } from './Members/Members'
import { AgreementModal } from './Modals/AgreementModal'
import { CoinbaseModal } from './Modals/CoinbaseModal'
import { CommunityModal } from './Modals/CommunityModal'
import { EditModal } from './Modals/EditModal'
import { LeavingModal } from './Modals/LeavingModal'
import { LogoutModal } from './Modals/LogoutModal'
import { ProfileFoundModal } from './Modals/ProfileFoundModal'
import { ProfileModal } from './Modals/ProfileModal'
import { StatusModal } from './Modals/StatusModal'
import { UserCreationModal } from './Modals/UserCreationModal'
import { UserCreationStartModal } from './Modals/UserCreationStartModal'
import { WalletConnectModal } from './Modals/WalletConnectModal'
import { WalletModal } from './Modals/WalletModal'
import { ToastMessageList } from './ToastMessages/ToastMessageList'
function Modals() {
return (
@ -42,15 +42,15 @@ function Modals() {
<UserCreationStartModal />
<LeavingModal />
</>
);
)
}
export function CommunityChatRoom() {
const [state] = useChatState();
const [showMembers, setShowMembers] = useState(false);
const [editGroup, setEditGroup] = useState(false);
const narrow = useNarrow();
const { activeChannel } = useMessengerContext();
const [state] = useChatState()
const [showMembers, setShowMembers] = useState(false)
const [editGroup, setEditGroup] = useState(false)
const narrow = useNarrow()
const { activeChannel } = useMessengerContext()
return (
<ChatWrapper>
@ -73,12 +73,12 @@ export function CommunityChatRoom() {
!narrow &&
state === ChatState.ChatBody &&
activeChannel &&
activeChannel.type !== "dm" && <Members />}
activeChannel.type !== 'dm' && <Members />}
{state === ChatState.ChatCreation && <ChatCreation />}
<Modals />
<ToastMessageList />
</ChatWrapper>
);
)
}
const ChatWrapper = styled.div`
@ -86,7 +86,7 @@ const ChatWrapper = styled.div`
height: 100%;
display: flex;
position: relative;
`;
`
const ChannelsWrapper = styled.div`
width: 21%;
@ -96,9 +96,9 @@ const ChannelsWrapper = styled.div`
padding: 10px 16px;
display: flex;
flex-direction: column;
`;
`
const StyledCommunity = styled(Community)`
padding: 0 0 0 8px;
margin: 0 0 16px;
`;
`

View File

@ -1,20 +1,20 @@
import React from "react";
import styled from "styled-components";
import React from 'react'
import styled from 'styled-components'
import { useMessengerContext } from "../contexts/messengerProvider";
import { useMessengerContext } from '../contexts/messengerProvider'
import { textMediumStyles } from "./Text";
import { textMediumStyles } from './Text'
export interface CommunityIdentityProps {
subtitle: string;
className?: string;
subtitle: string
className?: string
}
export const CommunityIdentity = ({
subtitle,
className,
}: CommunityIdentityProps) => {
const { communityData } = useMessengerContext();
const { communityData } = useMessengerContext()
return (
<Row className={className}>
@ -22,10 +22,10 @@ export const CommunityIdentity = ({
style={{
backgroundImage: communityData?.icon
? `url(${communityData?.icon}`
: "",
: '',
}}
>
{" "}
{' '}
{communityData?.icon === undefined &&
communityData?.name.slice(0, 1).toUpperCase()}
</Logo>
@ -34,18 +34,18 @@ export const CommunityIdentity = ({
<Subtitle>{subtitle}</Subtitle>
</Column>
</Row>
);
};
)
}
const Row = styled.div`
display: flex;
`;
`
export const Column = styled.div`
display: flex;
flex-direction: column;
align-items: flex-start;
`;
`
export const Logo = styled.div`
width: 36px;
@ -63,22 +63,22 @@ export const Logo = styled.div`
font-weight: bold;
font-size: 15px;
line-height: 20px;
`;
`
const Name = styled.p`
font-family: "Inter", sans-serif;
font-family: 'Inter', sans-serif;
font-weight: 500;
text-align: left;
color: ${({ theme }) => theme.primary};
white-space: nowrap;
${textMediumStyles}
`;
`
const Subtitle = styled.p`
font-family: "Inter", sans-serif;
font-family: 'Inter', sans-serif;
font-size: 12px;
line-height: 16px;
letter-spacing: 0.1px;
color: ${({ theme }) => theme.secondary};
`;
`

View File

@ -1,36 +1,36 @@
import React, { useMemo, useRef, useState } from "react";
import styled from "styled-components";
import React, { useMemo, useRef, useState } from 'react'
import styled from 'styled-components'
import { useMessengerContext } from "../../contexts/messengerProvider";
import { useModal } from "../../contexts/modalProvider";
import { useNarrow } from "../../contexts/narrowProvider";
import { useClickOutside } from "../../hooks/useClickOutside";
import { useContextMenu } from "../../hooks/useContextMenu";
import { ChannelData } from "../../models/ChannelData";
import { AddMemberIcon } from "../Icons/AddMemberIcon";
import { CheckIcon } from "../Icons/CheckIcon";
import { DeleteIcon } from "../Icons/DeleteIcon";
import { DownloadIcon } from "../Icons/DownloadIcon";
import { EditIcon } from "../Icons/EditIcon";
import { LeftIcon } from "../Icons/LeftIcon";
import { MembersSmallIcon } from "../Icons/MembersSmallIcon";
import { MuteIcon } from "../Icons/MuteIcon";
import { NextIcon } from "../Icons/NextIcon";
import { ProfileIcon } from "../Icons/ProfileIcon";
import { EditModalName } from "../Modals/EditModal";
import { LeavingModalName } from "../Modals/LeavingModal";
import { ProfileModalName } from "../Modals/ProfileModal";
import { useMessengerContext } from '../../contexts/messengerProvider'
import { useModal } from '../../contexts/modalProvider'
import { useNarrow } from '../../contexts/narrowProvider'
import { useClickOutside } from '../../hooks/useClickOutside'
import { useContextMenu } from '../../hooks/useContextMenu'
import { ChannelData } from '../../models/ChannelData'
import { AddMemberIcon } from '../Icons/AddMemberIcon'
import { CheckIcon } from '../Icons/CheckIcon'
import { DeleteIcon } from '../Icons/DeleteIcon'
import { DownloadIcon } from '../Icons/DownloadIcon'
import { EditIcon } from '../Icons/EditIcon'
import { LeftIcon } from '../Icons/LeftIcon'
import { MembersSmallIcon } from '../Icons/MembersSmallIcon'
import { MuteIcon } from '../Icons/MuteIcon'
import { NextIcon } from '../Icons/NextIcon'
import { ProfileIcon } from '../Icons/ProfileIcon'
import { EditModalName } from '../Modals/EditModal'
import { LeavingModalName } from '../Modals/LeavingModal'
import { ProfileModalName } from '../Modals/ProfileModal'
import { DropdownMenu, MenuItem, MenuSection, MenuText } from "./DropdownMenu";
import { MuteMenu } from "./MuteMenu";
import { DropdownMenu, MenuItem, MenuSection, MenuText } from './DropdownMenu'
import { MuteMenu } from './MuteMenu'
interface ChannelMenuProps {
channel: ChannelData;
setShowChannelMenu?: (val: boolean) => void;
showNarrowMembers?: boolean;
switchMemberList?: () => void;
setEditGroup?: (val: boolean) => void;
className?: string;
channel: ChannelData
setShowChannelMenu?: (val: boolean) => void
showNarrowMembers?: boolean
switchMemberList?: () => void
setEditGroup?: (val: boolean) => void
className?: string
}
export const ChannelMenu = ({
@ -41,45 +41,45 @@ export const ChannelMenu = ({
setEditGroup,
className,
}: ChannelMenuProps) => {
const narrow = useNarrow();
const { clearNotifications, channelsDispatch } = useMessengerContext();
const { setModal } = useModal(EditModalName);
const { setModal: setLeavingModal } = useModal(LeavingModalName);
const { setModal: setProfileModal } = useModal(ProfileModalName);
const [showSubmenu, setShowSubmenu] = useState(false);
const narrow = useNarrow()
const { clearNotifications, channelsDispatch } = useMessengerContext()
const { setModal } = useModal(EditModalName)
const { setModal: setLeavingModal } = useModal(LeavingModalName)
const { setModal: setProfileModal } = useModal(ProfileModalName)
const [showSubmenu, setShowSubmenu] = useState(false)
const { showMenu, setShowMenu: setShowSideMenu } = useContextMenu(
channel.id + "contextMenu"
);
channel.id + 'contextMenu'
)
const setShowMenu = useMemo(
() => (setShowChannelMenu ? setShowChannelMenu : setShowSideMenu),
[setShowChannelMenu, setShowSideMenu]
);
)
const ref = useRef(null);
useClickOutside(ref, () => setShowMenu(false));
const ref = useRef(null)
useClickOutside(ref, () => setShowMenu(false))
if (showMenu || setShowChannelMenu) {
return (
<ChannelDropdown className={className} menuRef={ref}>
{narrow && channel.type !== "dm" && (
{narrow && channel.type !== 'dm' && (
<MenuItem
onClick={() => {
if (switchMemberList) switchMemberList();
setShowMenu(false);
if (switchMemberList) switchMemberList()
setShowMenu(false)
}}
>
<MembersSmallIcon width={16} height={16} />
<MenuText>{showNarrowMembers ? "Hide" : "View"} Members</MenuText>
<MenuText>{showNarrowMembers ? 'Hide' : 'View'} Members</MenuText>
</MenuItem>
)}
{channel.type === "group" && (
{channel.type === 'group' && (
<>
<MenuItem
onClick={() => {
if (setEditGroup) setEditGroup(true);
setShowMenu(false);
if (setEditGroup) setEditGroup(true)
setShowMenu(false)
}}
>
<AddMemberIcon width={16} height={16} />
@ -91,50 +91,50 @@ export const ChannelMenu = ({
</MenuItem>
</>
)}
{channel.type === "dm" && (
{channel.type === 'dm' && (
<MenuItem
onClick={() => {
setProfileModal({
id: channel.name,
renamingState: false,
requestState: false,
});
setShowMenu(false);
})
setShowMenu(false)
}}
>
<ProfileIcon width={16} height={16} />
<MenuText>View Profile</MenuText>
</MenuItem>
)}
<MenuSection className={`${channel.type === "channel" && "channel"}`}>
<MenuSection className={`${channel.type === 'channel' && 'channel'}`}>
<MenuItem
onClick={() => {
if (channel.isMuted) {
channelsDispatch({
type: "ToggleMuted",
type: 'ToggleMuted',
payload: channel.id,
});
setShowMenu(false);
})
setShowMenu(false)
}
}}
onMouseEnter={() => {
if (!channel.isMuted) setShowSubmenu(true);
if (!channel.isMuted) setShowSubmenu(true)
}}
onMouseLeave={() => {
if (!channel.isMuted) setShowSubmenu(false);
if (!channel.isMuted) setShowSubmenu(false)
}}
>
<MuteIcon width={16} height={16} />
{!channel.isMuted && <NextIcon />}
<MenuText>
{(channel.isMuted ? "Unmute" : "Mute") +
(channel.type === "group" ? " Group" : "Chat")}
{(channel.isMuted ? 'Unmute' : 'Mute') +
(channel.type === 'group' ? ' Group' : 'Chat')}
</MenuText>
{!channel.isMuted && showSubmenu && (
<MuteMenu
setIsMuted={() =>
channelsDispatch({
type: "ToggleMuted",
type: 'ToggleMuted',
payload: channel.id,
})
}
@ -151,30 +151,30 @@ export const ChannelMenu = ({
<MenuText>Fetch Messages</MenuText>
</MenuItem>
</MenuSection>
{(channel.type === "group" || channel.type === "dm") && (
{(channel.type === 'group' || channel.type === 'dm') && (
<MenuItem
onClick={() => {
setLeavingModal(true);
setShowMenu(false);
setLeavingModal(true)
setShowMenu(false)
}}
>
{channel.type === "group" && (
{channel.type === 'group' && (
<LeftIcon width={16} height={16} className="red" />
)}
{channel.type === "dm" && (
{channel.type === 'dm' && (
<DeleteIcon width={16} height={16} className="red" />
)}
<MenuText className="red">
{channel.type === "group" ? "Leave Group" : "Delete Chat"}
{channel.type === 'group' ? 'Leave Group' : 'Delete Chat'}
</MenuText>
</MenuItem>
)}
</ChannelDropdown>
);
)
} else {
return null;
return null
}
};
}
const ChannelDropdown = styled(DropdownMenu)`
top: calc(100% + 4px);
@ -190,4 +190,4 @@ const ChannelDropdown = styled(DropdownMenu)`
top: 20px;
right: 8px;
}
`;
`

View File

@ -1,43 +1,43 @@
import React, { useMemo } from "react";
import styled from "styled-components";
import React, { useMemo } from 'react'
import styled from 'styled-components'
import { useUserPublicKey } from "../../contexts/identityProvider";
import { useMessengerContext } from "../../contexts/messengerProvider";
import { useModal } from "../../contexts/modalProvider";
import { AddContactIcon } from "../Icons/AddContactIcon";
import { BlockSvg } from "../Icons/BlockIcon";
import { ChatSvg } from "../Icons/ChatIcon";
import { EditIcon } from "../Icons/EditIcon";
import { ProfileIcon } from "../Icons/ProfileIcon";
import { UntrustworthIcon } from "../Icons/UntrustworthIcon";
import { UserIcon } from "../Icons/UserIcon";
import { WarningSvg } from "../Icons/WarningIcon";
import { UserAddress } from "../Messages/Styles";
import { ProfileModalName } from "../Modals/ProfileModal";
import { textMediumStyles } from "../Text";
import { useUserPublicKey } from '../../contexts/identityProvider'
import { useMessengerContext } from '../../contexts/messengerProvider'
import { useModal } from '../../contexts/modalProvider'
import { AddContactIcon } from '../Icons/AddContactIcon'
import { BlockSvg } from '../Icons/BlockIcon'
import { ChatSvg } from '../Icons/ChatIcon'
import { EditIcon } from '../Icons/EditIcon'
import { ProfileIcon } from '../Icons/ProfileIcon'
import { UntrustworthIcon } from '../Icons/UntrustworthIcon'
import { UserIcon } from '../Icons/UserIcon'
import { WarningSvg } from '../Icons/WarningIcon'
import { UserAddress } from '../Messages/Styles'
import { ProfileModalName } from '../Modals/ProfileModal'
import { textMediumStyles } from '../Text'
import { DropdownMenu, MenuItem, MenuText } from "./DropdownMenu";
import { DropdownMenu, MenuItem, MenuText } from './DropdownMenu'
type ContactMenuProps = {
id: string;
setShowMenu: (val: boolean) => void;
};
id: string
setShowMenu: (val: boolean) => void
}
export function ContactMenu({ id, setShowMenu }: ContactMenuProps) {
const userPK = useUserPublicKey();
const { contacts, contactsDispatch } = useMessengerContext();
const contact = useMemo(() => contacts[id], [id, contacts]);
const userPK = useUserPublicKey()
const { contacts, contactsDispatch } = useMessengerContext()
const contact = useMemo(() => contacts[id], [id, contacts])
const isUser = useMemo(() => {
if (userPK) {
return id === userPK;
return id === userPK
} else {
return false;
return false
}
}, [id, userPK]);
}, [id, userPK])
const { setModal } = useModal(ProfileModalName);
const { setModal } = useModal(ProfileModalName)
if (!contact) return null;
if (!contact) return null
return (
<ContactDropdown>
<ContactInfo>
@ -56,7 +56,7 @@ export function ContactMenu({ id, setShowMenu }: ContactMenuProps) {
<MenuSection>
<MenuItem
onClick={() => {
setModal({ id, renamingState: false, requestState: false });
setModal({ id, renamingState: false, requestState: false })
}}
>
<ProfileIcon width={16} height={16} />
@ -65,7 +65,7 @@ export function ContactMenu({ id, setShowMenu }: ContactMenuProps) {
{!contact.isFriend && (
<MenuItem
onClick={() => {
setModal({ id, requestState: true });
setModal({ id, requestState: true })
}}
>
<AddContactIcon width={16} height={16} />
@ -80,7 +80,7 @@ export function ContactMenu({ id, setShowMenu }: ContactMenuProps) {
)}
<MenuItem
onClick={() => {
setModal({ id, renamingState: true });
setModal({ id, renamingState: true })
}}
>
<EditIcon width={16} height={16} />
@ -90,69 +90,69 @@ export function ContactMenu({ id, setShowMenu }: ContactMenuProps) {
<MenuSection>
<MenuItem
onClick={() =>
contactsDispatch({ type: "toggleTrustworthy", payload: { id } })
contactsDispatch({ type: 'toggleTrustworthy', payload: { id } })
}
>
<WarningSvg
width={16}
height={16}
className={contact.isUntrustworthy ? "" : "red"}
className={contact.isUntrustworthy ? '' : 'red'}
/>
<MenuText className={contact.isUntrustworthy ? "" : "red"}>
<MenuText className={contact.isUntrustworthy ? '' : 'red'}>
{contact.isUntrustworthy
? "Remove Untrustworthy Mark"
: "Mark as Untrustworthy"}
? 'Remove Untrustworthy Mark'
: 'Mark as Untrustworthy'}
</MenuText>
</MenuItem>
{!contact.isFriend && !isUser && (
<MenuItem
onClick={() => {
contactsDispatch({ type: "toggleBlocked", payload: { id } });
setShowMenu(false);
contactsDispatch({ type: 'toggleBlocked', payload: { id } })
setShowMenu(false)
}}
>
<BlockSvg width={16} height={16} className="red" />
<MenuText className="red">
{contact.blocked ? "Unblock User" : "Block User"}
{contact.blocked ? 'Unblock User' : 'Block User'}
</MenuText>
</MenuItem>
)}
</MenuSection>
</ContactDropdown>
);
)
}
const ContactDropdown = styled(DropdownMenu)`
top: 20px;
left: 0px;
width: 222px;
`;
`
const ContactInfo = styled.div`
display: flex;
flex-direction: column;
align-items: center;
`;
`
const MenuSection = styled.div`
margin-top: 5px;
padding-top: 5px;
border-top: 1px solid ${({ theme }) => theme.inputColor};
`;
`
const UserNameWrapper = styled.div`
display: flex;
align-items: center;
margin-bottom: 4px;
`;
`
const UserName = styled.p`
color: ${({ theme }) => theme.primary};
margin-right: 4px;
${textMediumStyles}
`;
`
const UserTrueName = styled.p`
color: ${({ theme }) => theme.primary};
@ -160,4 +160,4 @@ const UserTrueName = styled.p`
line-height: 16px;
letter-spacing: 0.1px;
margin-top: 4px;
`;
`

View File

@ -1,7 +1,7 @@
import React from "react";
import React from 'react'
import { copy } from "../../utils/copy";
import { reduceString } from "../../utils/reduceString";
import { copy } from '../../utils/copy'
import { reduceString } from '../../utils/reduceString'
import {
ButtonWrapper,
@ -10,11 +10,11 @@ import {
Label,
Text,
Wrapper,
} from "./inputStyles";
} from './inputStyles'
interface CopyInputProps {
label?: string;
value: string;
label?: string
value: string
}
export const CopyInput = ({ label, value }: CopyInputProps) => (
@ -27,4 +27,4 @@ export const CopyInput = ({ label, value }: CopyInputProps) => (
</ButtonWrapper>
</Wrapper>
</InputWrapper>
);
)

View File

@ -1,15 +1,15 @@
import React, { ReactNode } from "react";
import styled from "styled-components";
import React, { ReactNode } from 'react'
import styled from 'styled-components'
import { textSmallStyles } from "../Text";
import { textSmallStyles } from '../Text'
type DropdownMenuProps = {
children: ReactNode;
className?: string;
style?: { top: number; left: number };
menuRef?: React.MutableRefObject<null>;
id?: string;
};
children: ReactNode
className?: string
style?: { top: number; left: number }
menuRef?: React.MutableRefObject<null>
id?: string
}
export function DropdownMenu({
children,
@ -22,7 +22,7 @@ export function DropdownMenu({
<MenuBlock className={className} style={style} ref={menuRef} id={id}>
<MenuList>{children}</MenuList>
</MenuBlock>
);
)
}
const MenuBlock = styled.div`
@ -34,11 +34,11 @@ const MenuBlock = styled.div`
padding: 8px 0;
position: absolute;
z-index: 2;
`;
`
const MenuList = styled.ul`
list-style: none;
`;
`
export const MenuItem = styled.li`
width: 100%;
@ -61,7 +61,7 @@ export const MenuItem = styled.li`
& > svg.red {
fill: ${({ theme }) => theme.redColor};
}
`;
`
export const MenuText = styled.span`
margin-left: 6px;
@ -72,7 +72,7 @@ export const MenuText = styled.span`
}
${textSmallStyles}
`;
`
export const MenuSection = styled.div`
padding: 4px 0;
@ -91,4 +91,4 @@ export const MenuSection = styled.div`
margin: 4px 0 0;
border-bottom: none;
}
`;
`

View File

@ -1,24 +1,24 @@
import React, { useRef } from "react";
import styled from "styled-components";
import React, { useRef } from 'react'
import styled from 'styled-components'
import { useClickOutside } from "../../hooks/useClickOutside";
import { useContextMenu } from "../../hooks/useContextMenu";
import { copyImg } from "../../utils/copyImg";
import { downloadImg } from "../../utils/downloadImg";
import { CopyIcon } from "../Icons/CopyIcon";
import { DownloadIcon } from "../Icons/DownloadIcon";
import { useClickOutside } from '../../hooks/useClickOutside'
import { useContextMenu } from '../../hooks/useContextMenu'
import { copyImg } from '../../utils/copyImg'
import { downloadImg } from '../../utils/downloadImg'
import { CopyIcon } from '../Icons/CopyIcon'
import { DownloadIcon } from '../Icons/DownloadIcon'
import { DropdownMenu, MenuItem, MenuText } from "./DropdownMenu";
import { DropdownMenu, MenuItem, MenuText } from './DropdownMenu'
interface ImageMenuProps {
imageId: string;
imageId: string
}
export const ImageMenu = ({ imageId }: ImageMenuProps) => {
const { showMenu, setShowMenu } = useContextMenu(imageId);
const { showMenu, setShowMenu } = useContextMenu(imageId)
const ref = useRef(null);
useClickOutside(ref, () => setShowMenu(false));
const ref = useRef(null)
useClickOutside(ref, () => setShowMenu(false))
return showMenu ? (
<ImageDropdown menuRef={ref}>
@ -32,11 +32,11 @@ export const ImageMenu = ({ imageId }: ImageMenuProps) => {
</ImageDropdown>
) : (
<></>
);
};
)
}
const ImageDropdown = styled(DropdownMenu)`
width: 176px;
left: 120px;
top: 46px;
`;
`

View File

@ -1,52 +1,52 @@
import React from "react";
import styled from "styled-components";
import React from 'react'
import styled from 'styled-components'
import { MobileIcon } from "../Icons/MobileIcon";
import { ProfileIcon } from "../Icons/ProfileIcon";
import { ScanIcon } from "../Icons/ScanIcon";
import { textMediumStyles } from "../Text";
import { MobileIcon } from '../Icons/MobileIcon'
import { ProfileIcon } from '../Icons/ProfileIcon'
import { ScanIcon } from '../Icons/ScanIcon'
import { textMediumStyles } from '../Text'
interface LoginInstructionsProps {
mobileFlow: boolean;
mobileFlow: boolean
}
export function LoginInstructions({ mobileFlow }: LoginInstructionsProps) {
return (
<Instructions>
<InstructionStep>
Open Status App on your {mobileFlow ? "mobile" : "desktop"}
Open Status App on your {mobileFlow ? 'mobile' : 'desktop'}
</InstructionStep>
<InstructionStep>
Navigate yourself to{" "}
Navigate yourself to{' '}
<InstructionIcon>
{" "}
{' '}
<ProfileIcon width={13} height={13} /> <span>Profile</span>
</InstructionIcon>{" "}
</InstructionIcon>{' '}
tab
</InstructionStep>
<InstructionStep>
Select{" "}
Select{' '}
<InstructionIcon>
<MobileIcon />
</InstructionIcon>{" "}
</InstructionIcon>{' '}
<span>Sync Settings</span>
</InstructionStep>
<InstructionStep>
Tap{" "}
Tap{' '}
<InstructionIcon>
{" "}
<ScanIcon />{" "}
</InstructionIcon>{" "}
<span>{mobileFlow ? "Scan" : "Display"} sync code</span>
{' '}
<ScanIcon />{' '}
</InstructionIcon>{' '}
<span>{mobileFlow ? 'Scan' : 'Display'} sync code</span>
</InstructionStep>
<InstructionStep>
{mobileFlow
? "Scan the sync code from this screen"
: "Paste the sync code above"}{" "}
? 'Scan the sync code from this screen'
: 'Paste the sync code above'}{' '}
</InstructionStep>
</Instructions>
);
)
}
const Instructions = styled.ol`
@ -56,7 +56,7 @@ const Instructions = styled.ol`
counter-reset: ollist;
${textMediumStyles}
`;
`
const InstructionStep = styled.li`
display: flex;
@ -72,10 +72,10 @@ const InstructionStep = styled.li`
&::before {
counter-increment: ollist;
content: counter(ollist) ".";
content: counter(ollist) '.';
margin-right: 4px;
}
`;
`
const InstructionIcon = styled.div`
width: 40px;
@ -90,4 +90,4 @@ const InstructionIcon = styled.div`
font-size: 8px;
line-height: 10px;
margin: 0 6px;
`;
`

View File

@ -1,28 +1,28 @@
import { BaseEmoji } from "emoji-mart";
import React, { useMemo, useRef } from "react";
import styled from "styled-components";
import { BaseEmoji } from 'emoji-mart'
import React, { useMemo, useRef } from 'react'
import styled from 'styled-components'
import { useUserPublicKey } from "../../contexts/identityProvider";
import { useMessengerContext } from "../../contexts/messengerProvider";
import { useClickOutside } from "../../hooks/useClickOutside";
import { useClickPosition } from "../../hooks/useClickPosition";
import { useContextMenu } from "../../hooks/useContextMenu";
import { Reply } from "../../hooks/useReply";
import { ChatMessage } from "../../models/ChatMessage";
import { DeleteIcon } from "../Icons/DeleteIcon";
import { EditIcon } from "../Icons/EditIcon";
import { PinIcon } from "../Icons/PinIcon";
import { ReplySvg } from "../Icons/ReplyIcon";
import { ReactionPicker } from "../Reactions/ReactionPicker";
import { useUserPublicKey } from '../../contexts/identityProvider'
import { useMessengerContext } from '../../contexts/messengerProvider'
import { useClickOutside } from '../../hooks/useClickOutside'
import { useClickPosition } from '../../hooks/useClickPosition'
import { useContextMenu } from '../../hooks/useContextMenu'
import { Reply } from '../../hooks/useReply'
import { ChatMessage } from '../../models/ChatMessage'
import { DeleteIcon } from '../Icons/DeleteIcon'
import { EditIcon } from '../Icons/EditIcon'
import { PinIcon } from '../Icons/PinIcon'
import { ReplySvg } from '../Icons/ReplyIcon'
import { ReactionPicker } from '../Reactions/ReactionPicker'
import { DropdownMenu, MenuItem, MenuSection, MenuText } from "./DropdownMenu";
import { DropdownMenu, MenuItem, MenuSection, MenuText } from './DropdownMenu'
interface MessageMenuProps {
message: ChatMessage;
messageReactions: BaseEmoji[];
setMessageReactions: React.Dispatch<React.SetStateAction<BaseEmoji[]>>;
setReply: (val: Reply | undefined) => void;
messageRef: React.MutableRefObject<null>;
message: ChatMessage
messageReactions: BaseEmoji[]
setMessageReactions: React.Dispatch<React.SetStateAction<BaseEmoji[]>>
setReply: (val: Reply | undefined) => void
messageRef: React.MutableRefObject<null>
}
export const MessageMenu = ({
@ -32,25 +32,25 @@ export const MessageMenu = ({
setReply,
messageRef,
}: MessageMenuProps) => {
const userPK = useUserPublicKey();
const { activeChannel } = useMessengerContext();
const { showMenu, setShowMenu } = useContextMenu(message.id);
const { topPosition, leftPosition } = useClickPosition(messageRef);
const userPK = useUserPublicKey()
const { activeChannel } = useMessengerContext()
const { showMenu, setShowMenu } = useContextMenu(message.id)
const { topPosition, leftPosition } = useClickPosition(messageRef)
const menuStyle = useMemo(() => {
return {
top: topPosition,
left: leftPosition,
};
}, [topPosition, leftPosition]);
}
}, [topPosition, leftPosition])
const ref = useRef(null);
useClickOutside(ref, () => setShowMenu(false));
const ref = useRef(null)
useClickOutside(ref, () => setShowMenu(false))
const userMessage = useMemo(
() => !!userPK && message.sender === userPK,
[userPK, message]
);
)
return userPK && showMenu ? (
<MessageDropdown style={menuStyle} menuRef={ref} id="messageDropdown">
@ -61,7 +61,7 @@ export const MessageMenu = ({
className="menu"
/>
</MenuItem>
<MenuSection className={`${!userMessage && "message"}`}>
<MenuSection className={`${!userMessage && 'message'}`}>
<MenuItem
onClick={() => {
setReply({
@ -69,8 +69,8 @@ export const MessageMenu = ({
content: message.content,
image: message.image,
id: message.id,
});
setShowMenu(false);
})
setShowMenu(false)
}}
>
<ReplySvg width={16} height={16} className="menu" />
@ -80,17 +80,17 @@ export const MessageMenu = ({
{userMessage && (
<MenuItem
onClick={() => {
setShowMenu(false);
setShowMenu(false)
}}
>
<EditIcon width={16} height={16} />
<MenuText>Edit</MenuText>
</MenuItem>
)}
{activeChannel?.type !== "channel" && (
{activeChannel?.type !== 'channel' && (
<MenuItem
onClick={() => {
setShowMenu(false);
setShowMenu(false)
}}
>
<PinIcon width={16} height={16} className="menu" />
@ -101,7 +101,7 @@ export const MessageMenu = ({
{userMessage && (
<MenuItem
onClick={() => {
setShowMenu(false);
setShowMenu(false)
}}
>
<DeleteIcon width={16} height={16} className="red" />
@ -111,9 +111,9 @@ export const MessageMenu = ({
</MessageDropdown>
) : (
<></>
);
};
)
}
const MessageDropdown = styled(DropdownMenu)`
width: 176px;
`;
`

View File

@ -1,24 +1,24 @@
import React, { useCallback } from "react";
import styled from "styled-components";
import React, { useCallback } from 'react'
import styled from 'styled-components'
import { DropdownMenu, MenuItem, MenuText } from "./DropdownMenu";
import { DropdownMenu, MenuItem, MenuText } from './DropdownMenu'
interface SubMenuProps {
setIsMuted: (val: boolean) => void;
className?: string;
setIsMuted: (val: boolean) => void
className?: string
}
export const MuteMenu = ({ setIsMuted, className }: SubMenuProps) => {
const muteChannel = useCallback(
(timeout: number) => {
setIsMuted(true);
const timer = setTimeout(() => setIsMuted(false), timeout * 6000000);
setIsMuted(true)
const timer = setTimeout(() => setIsMuted(false), timeout * 6000000)
return () => {
clearTimeout(timer);
};
clearTimeout(timer)
}
},
[setIsMuted]
);
)
return (
<MuteDropdown className={className}>
@ -38,8 +38,8 @@ export const MuteMenu = ({ setIsMuted, className }: SubMenuProps) => {
<MenuText>Until I turn it back on</MenuText>
</MenuItem>
</MuteDropdown>
);
};
)
}
const MuteDropdown = styled(DropdownMenu)`
width: 176px;
@ -61,4 +61,4 @@ const MuteDropdown = styled(DropdownMenu)`
right: -16px;
z-index: 3;
}
`;
`

View File

@ -1,38 +1,38 @@
import React from "react";
import styled from "styled-components";
import React from 'react'
import styled from 'styled-components'
import { NameErrors } from "../../hooks/useNameError";
import { Hint } from "../Modals/ModalStyle";
import { NameErrors } from '../../hooks/useNameError'
import { Hint } from '../Modals/ModalStyle'
type NameErrorProps = {
error: NameErrors;
};
error: NameErrors
}
export function NameError({ error }: NameErrorProps) {
switch (error) {
case NameErrors.NoError:
return null;
return null
case NameErrors.NameExists:
return (
<ErrorText>
Sorry, the name you have chosen is not allowed, try picking another
username
</ErrorText>
);
)
case NameErrors.BadCharacters:
return (
<ErrorText>
Only letters, numbers, underscores and hypens allowed
</ErrorText>
);
)
case NameErrors.EndingWithEth:
return (
<ErrorText>
Usernames ending with _eth or "-eth" are not allowed
</ErrorText>
);
)
case NameErrors.TooLong:
return <ErrorText>24 character username limit</ErrorText>;
return <ErrorText>24 character username limit</ErrorText>
}
}
@ -41,4 +41,4 @@ const ErrorText = styled(Hint)`
text-align: center;
width: 328px;
margin: 8px 0;
`;
`

View File

@ -1,7 +1,7 @@
import React from "react";
import styled from "styled-components";
import React from 'react'
import styled from 'styled-components'
import { paste } from "../../utils/paste";
import { paste } from '../../utils/paste'
import {
ButtonWrapper,
@ -10,10 +10,10 @@ import {
InputWrapper,
Label,
Wrapper,
} from "./inputStyles";
} from './inputStyles'
interface PasteInputProps {
label: string;
label: string
}
export const PasteInput = ({ label }: PasteInputProps) => (
@ -22,11 +22,11 @@ export const PasteInput = ({ label }: PasteInputProps) => (
<Wrapper>
<Input id="pasteInput" type="text" placeholder="eg. 0x2Ef19" />
<ButtonWrapper>
<InputBtn onClick={() => paste("pasteInput")}>Paste</InputBtn>
<InputBtn onClick={() => paste('pasteInput')}>Paste</InputBtn>
</ButtonWrapper>
</Wrapper>
</InputWrapper>
);
)
const Input = styled.input`
${inputStyles}
@ -37,4 +37,4 @@ const Input = styled.input`
}
border: none;
`;
`

View File

@ -1,33 +1,33 @@
import React from "react";
import styled from "styled-components";
import React from 'react'
import styled from 'styled-components'
import { useMessengerContext } from "../../contexts/messengerProvider";
import { textMediumStyles } from "../Text";
import { useMessengerContext } from '../../contexts/messengerProvider'
import { textMediumStyles } from '../Text'
const communityRequirements = {
requirements: [
{
name: "STN",
name: 'STN',
amount: 10,
logo: "https://status.im/img/logo.svg",
logo: 'https://status.im/img/logo.svg',
},
],
alternativeRequirements: [
{
name: "ETH",
name: 'ETH',
amount: 1,
logo: "https://ethereum.org/static/a110735dade3f354a46fc2446cd52476/db4de/eth-home-icon.webp",
logo: 'https://ethereum.org/static/a110735dade3f354a46fc2446cd52476/db4de/eth-home-icon.webp',
},
{
name: "MKR",
name: 'MKR',
amount: 10,
logo: "https://cryptologos.cc/logos/maker-mkr-logo.svg?v=017",
logo: 'https://cryptologos.cc/logos/maker-mkr-logo.svg?v=017',
},
],
};
}
export function TokenRequirement() {
const { communityData } = useMessengerContext();
const { communityData } = useMessengerContext()
return (
<Wrapper>
<Text>
@ -35,7 +35,7 @@ export function TokenRequirement() {
hold:
</Text>
<Row>
{communityRequirements.requirements.map((req) => (
{communityRequirements.requirements.map(req => (
<Requirement key={req.name + req.amount}>
<Logo
style={{
@ -43,14 +43,14 @@ export function TokenRequirement() {
}}
/>
<Amount>
{req.amount} {req.name}{" "}
{req.amount} {req.name}{' '}
</Amount>
</Requirement>
))}
</Row>
{communityRequirements.alternativeRequirements && <Text>or</Text>}
<Row>
{communityRequirements.alternativeRequirements.map((req) => (
{communityRequirements.alternativeRequirements.map(req => (
<Requirement key={req.name + req.amount}>
<Logo
style={{
@ -58,13 +58,13 @@ export function TokenRequirement() {
}}
/>
<Amount>
{req.amount} {req.name}{" "}
{req.amount} {req.name}{' '}
</Amount>
</Requirement>
))}
</Row>
</Wrapper>
);
)
}
const Wrapper = styled.div`
@ -72,7 +72,7 @@ const Wrapper = styled.div`
flex-direction: column;
align-items: center;
height: 50%;
`;
`
const Text = styled.p`
color: ${({ theme }) => theme.primary};
@ -84,7 +84,7 @@ const Text = styled.p`
}
${textMediumStyles}
`;
`
const Requirement = styled.div`
display: flex;
@ -102,7 +102,7 @@ const Requirement = styled.div`
& + & {
margin-left: 18px;
}
`;
`
const Amount = styled.p`
font-weight: 500;
@ -110,13 +110,13 @@ const Amount = styled.p`
margin-left: 6px;
${textMediumStyles}
`;
`
const Row = styled.div`
display: flex;
align-items: center;
margin-bottom: 16px;
`;
`
const Logo = styled.div`
width: 28px;
@ -128,4 +128,4 @@ const Logo = styled.div`
border-radius: 50%;
background-size: cover;
background-repeat: no-repeat;
`;
`

View File

@ -1,13 +1,13 @@
import React from "react";
import styled from "styled-components";
import React from 'react'
import styled from 'styled-components'
import { TipIcon } from "../Icons/TipIcon";
import { textSmallStyles } from "../Text";
import { TipIcon } from '../Icons/TipIcon'
import { textSmallStyles } from '../Text'
type TooltipProps = {
tip: string;
className?: string;
};
tip: string
className?: string
}
export function Tooltip({ tip, className }: TooltipProps) {
return (
@ -17,7 +17,7 @@ export function Tooltip({ tip, className }: TooltipProps) {
<TipIcon className={className} />
</TooltipBlock>
</TooltipWrapper>
);
)
}
const TooltipWrapper = styled.div`
@ -36,16 +36,16 @@ const TooltipWrapper = styled.div`
top: calc(100% + 8px);
z-index: 10;
}
`;
`
const TooltipBlock = styled.div`
background: ${({ theme }) => theme.primary};
border-radius: 8px;
position: relative;
padding: 8px;
`;
`
const TooltipText = styled.p`
font-weight: 500;
color: ${({ theme }) => theme.bodyBackgroundColor};
${textSmallStyles};
`;
`

View File

@ -1,6 +1,6 @@
import styled, { css } from "styled-components";
import styled, { css } from 'styled-components'
import { textMediumStyles, textSmallStyles } from "../Text";
import { textMediumStyles, textSmallStyles } from '../Text'
export const inputStyles = css`
background: ${({ theme }) => theme.inputColor};
@ -15,7 +15,7 @@ export const inputStyles = css`
outline: 1px solid ${({ theme }) => theme.tertiary};
caret-color: ${({ theme }) => theme.notificationColor};
}
`;
`
export const Label = styled.p`
margin-bottom: 7px;
@ -25,24 +25,24 @@ export const Label = styled.p`
color: ${({ theme }) => theme.primary};
${textSmallStyles}
`;
`
export const InputWrapper = styled.div`
width: 100%;
`;
`
export const Wrapper = styled.div`
position: relative;
padding: 14px 70px 14px 8px;
background: ${({ theme }) => theme.inputColor};
border-radius: 8px;
`;
`
export const Text = styled.p`
color: ${({ theme }) => theme.primary};
${textMediumStyles}
`;
`
export const ButtonWrapper = styled.div`
position: absolute;
@ -56,7 +56,7 @@ export const ButtonWrapper = styled.div`
transform: translateY(-50%);
background: ${({ theme }) => theme.inputColor};
border-radius: 8px;
`;
`
export const InputBtn = styled.button`
padding: 6px 12px;
@ -67,18 +67,18 @@ export const InputBtn = styled.button`
background: ${({ theme }) => theme.buttonBg};
border: 1px solid ${({ theme }) => theme.tertiary};
border-radius: 6px;
`;
`
export const NameInputWrapper = styled.div`
position: relative;
`;
`
export const NameInput = styled.input`
width: 328px;
padding: 11px 16px;
${inputStyles}
`;
`
export const ClearBtn = styled.button`
position: absolute;
@ -90,4 +90,4 @@ export const ClearBtn = styled.button`
& > svg {
fill: ${({ theme }) => theme.secondary};
}
`;
`

View File

@ -1,5 +1,5 @@
import React from "react";
import styled from "styled-components";
import React from 'react'
import styled from 'styled-components'
export const ActivityIcon = () => {
return (
@ -16,9 +16,9 @@ export const ActivityIcon = () => {
d="M15.2815 19C14.9452 19 14.7036 19.3279 14.7349 19.6628C14.7449 19.7703 14.7504 19.8827 14.7504 20C14.7504 21.3889 13.5441 22.75 12.0004 22.75C10.4568 22.75 9.25041 21.3889 9.25041 20C9.25041 19.8827 9.25591 19.7703 9.26596 19.6628C9.29725 19.3279 9.05564 19 8.71934 19H5.52151C3.78523 19 2.87368 16.9394 4.04163 15.6547L5.21849 14.3601C5.72921 13.7983 6.06949 13.1028 6.19958 12.3548L7.31505 5.94085C7.71121 3.66293 9.6883 2 12.0004 2C14.3125 2 16.2896 3.66293 16.6858 5.94085L17.8012 12.3548C17.9313 13.1028 18.2716 13.7983 18.7823 14.3601L19.9592 15.6547C21.1271 16.9394 20.2156 19 18.4793 19H15.2815ZM11.0327 19.0283L11.0318 19.0293L11.0395 19.0214L11.0419 19.0188C11.0432 19.0175 11.0438 19.0168 11.0439 19.0167C11.0443 19.0163 11.0439 19.0167 11.0439 19.0167L11.0419 19.0188C11.0529 19.0073 11.0685 19 11.0845 19H12.9164C12.9323 19 12.9474 19.0068 12.9584 19.0183C12.9612 19.0217 12.9684 19.0302 12.9785 19.0438C13.0015 19.0744 13.0394 19.13 13.0796 19.2104C13.1587 19.3687 13.2504 19.6296 13.2504 20C13.2504 20.6111 12.6659 21.25 12.0004 21.25C11.3349 21.25 10.7504 20.6111 10.7504 20C10.7504 19.6296 10.8421 19.3687 10.9212 19.2104C10.9614 19.13 10.9993 19.0744 11.0223 19.0438C11.0325 19.0302 11.0391 19.0222 11.0419 19.0188L11.0395 19.0214L11.0377 19.0233L11.0345 19.0265L11.0327 19.0283ZM5.15154 16.6637L6.3284 15.3691C7.03064 14.5967 7.49853 13.6403 7.6774 12.6118L8.79286 6.19786C9.06407 4.63842 10.4176 3.5 12.0004 3.5C13.5833 3.5 14.9368 4.63842 15.208 6.19786L16.3234 12.6118C16.5023 13.6403 16.9702 14.5967 17.6724 15.3691L18.8493 16.6637C19.1413 16.9849 18.9134 17.5 18.4793 17.5H5.52151C5.08744 17.5 4.85956 16.9849 5.15154 16.6637Z"
/>
</Icon>
);
};
)
}
const Icon = styled.svg`
fill: ${({ theme }) => theme.primary};
`;
`

View File

@ -1,11 +1,11 @@
import React from "react";
import styled from "styled-components";
import React from 'react'
import styled from 'styled-components'
type AddContactIconProps = {
width: number;
height: number;
className?: string;
};
width: number
height: number
className?: string
}
export function AddContactIcon({
width,
@ -29,9 +29,9 @@ export function AddContactIcon({
<path d="M8.07357 11.6671C8.35289 11.6707 8.60016 11.4677 8.62336 11.1893C8.64601 10.9175 8.44624 10.6758 8.17357 10.6689C8.11597 10.6674 8.05818 10.6667 8.00022 10.6667C5.97321 10.6667 4.15749 11.5713 2.93477 12.9989C2.77487 13.1856 2.79579 13.4622 2.96961 13.636C3.18548 13.8519 3.54282 13.8208 3.74449 13.5916C4.78296 12.4114 6.30462 11.6667 8.00022 11.6667C8.02471 11.6667 8.04916 11.6668 8.07357 11.6671Z" />
<path d="M10.167 11.1667C10.167 10.8905 10.3908 10.6667 10.667 10.6667H11.5003C11.6844 10.6667 11.8337 10.5174 11.8337 10.3333V9.5C11.8337 9.22386 12.0575 9 12.3337 9C12.6098 9 12.8337 9.22386 12.8337 9.5V10.3333C12.8337 10.5174 12.9829 10.6667 13.167 10.6667H14.0003C14.2765 10.6667 14.5003 10.8905 14.5003 11.1667C14.5003 11.4428 14.2765 11.6667 14.0003 11.6667H13.167C12.9829 11.6667 12.8337 11.8159 12.8337 12V12.8333C12.8337 13.1095 12.6098 13.3333 12.3337 13.3333C12.0575 13.3333 11.8337 13.1095 11.8337 12.8333V12C11.8337 11.8159 11.6844 11.6667 11.5003 11.6667H10.667C10.3908 11.6667 10.167 11.4428 10.167 11.1667Z" />
</Icon>
);
)
}
const Icon = styled.svg`
fill: ${({ theme }) => theme.tertiary};
`;
`

View File

@ -1,5 +1,5 @@
import React from "react";
import styled from "styled-components";
import React from 'react'
import styled from 'styled-components'
export const AddIcon = () => {
return (
@ -12,11 +12,11 @@ export const AddIcon = () => {
>
<path d="M12 5.25C12.4142 5.25 12.75 5.58579 12.75 6V10.75C12.75 11.0261 12.9739 11.25 13.25 11.25H18C18.4142 11.25 18.75 11.5858 18.75 12C18.75 12.4142 18.4142 12.75 18 12.75H13.25C12.9739 12.75 12.75 12.9739 12.75 13.25V18C12.75 18.4142 12.4142 18.75 12 18.75C11.5858 18.75 11.25 18.4142 11.25 18V13.25C11.25 12.9739 11.0261 12.75 10.75 12.75H6C5.58579 12.75 5.25 12.4142 5.25 12C5.25 11.5858 5.58579 11.25 6 11.25H10.75C11.0261 11.25 11.25 11.0261 11.25 10.75V6C11.25 5.58579 11.5858 5.25 12 5.25Z" />
</Icon>
);
};
)
}
const Icon = styled.svg`
& > path {
fill: ${({ theme }) => theme.bodyBackgroundColor};
}
`;
`

View File

@ -1,11 +1,11 @@
import React from "react";
import styled from "styled-components";
import React from 'react'
import styled from 'styled-components'
type AddMemberIconProps = {
width: number;
height: number;
className?: string;
};
width: number
height: number
className?: string
}
export function AddMemberIcon({
width,
@ -31,9 +31,9 @@ export function AddMemberIcon({
<path d="M8.07357 11.6671C8.35289 11.6707 8.60016 11.4677 8.62336 11.1893C8.64601 10.9175 8.44624 10.6758 8.17357 10.6689C8.11597 10.6674 8.05818 10.6667 8.00022 10.6667C5.97321 10.6667 4.15749 11.5713 2.93477 12.9989C2.77487 13.1856 2.79579 13.4622 2.96961 13.636C3.18548 13.8519 3.54282 13.8208 3.74449 13.5916C4.78296 12.4114 6.30462 11.6667 8.00022 11.6667C8.02471 11.6667 8.04916 11.6668 8.07357 11.6671Z" />
<path d="M10.167 11.1667C10.167 10.8905 10.3908 10.6667 10.667 10.6667H11.5003C11.6844 10.6667 11.8337 10.5174 11.8337 10.3333V9.5C11.8337 9.22386 12.0575 9 12.3337 9C12.6098 9 12.8337 9.22386 12.8337 9.5V10.3333C12.8337 10.5174 12.9829 10.6667 13.167 10.6667H14.0003C14.2765 10.6667 14.5003 10.8905 14.5003 11.1667C14.5003 11.4428 14.2765 11.6667 14.0003 11.6667H13.167C12.9829 11.6667 12.8337 11.8159 12.8337 12V12.8333C12.8337 13.1095 12.6098 13.3333 12.3337 13.3333C12.0575 13.3333 11.8337 13.1095 11.8337 12.8333V12C11.8337 11.8159 11.6844 11.6667 11.5003 11.6667H10.667C10.3908 11.6667 10.167 11.4428 10.167 11.1667Z" />
</Icon>
);
)
}
const Icon = styled.svg`
fill: ${({ theme }) => theme.tertiary};
`;
`

View File

@ -1,11 +1,11 @@
import React from "react";
import styled from "styled-components";
import React from 'react'
import styled from 'styled-components'
type BlockSvgProps = {
width: number;
height: number;
className?: string;
};
width: number
height: number
className?: string
}
export function BlockSvg({ width, height, className }: BlockSvgProps) {
return (
@ -23,12 +23,12 @@ export function BlockSvg({ width, height, className }: BlockSvgProps) {
d="M8.00065 14.6673C4.31875 14.6673 1.33398 11.6825 1.33398 8.00065C1.33398 4.31875 4.31875 1.33398 8.00065 1.33398C11.6826 1.33398 14.6673 4.31875 14.6673 8.00065C14.6673 11.6826 11.6825 14.6673 8.00065 14.6673ZM3.91306 11.3811C3.77473 11.5195 3.54679 11.5099 3.43096 11.3523C2.74134 10.4136 2.33398 9.2547 2.33398 8.00065C2.33398 4.87104 4.87104 2.33398 8.00065 2.33398C9.2547 2.33398 10.4136 2.74135 11.3523 3.43096C11.5099 3.54679 11.5195 3.77473 11.3811 3.91306L3.91306 11.3811ZM4.62017 12.0882C4.48183 12.2266 4.49138 12.4545 4.64904 12.5703C5.58769 13.26 6.7466 13.6673 8.00065 13.6673C11.1303 13.6673 13.6673 11.1303 13.6673 8.00065C13.6673 6.7466 13.26 5.58769 12.5703 4.64904C12.4545 4.49138 12.2266 4.48183 12.0882 4.62017L4.62017 12.0882Z"
/>
</svg>
);
)
}
export const BlockIcon = () => {
return <Icon width={16} height={16} />;
};
return <Icon width={16} height={16} />
}
const Icon = styled(BlockSvg)`
& > path {
@ -38,4 +38,4 @@ const Icon = styled(BlockSvg)`
&:hover > path {
fill: ${({ theme }) => theme.bodyBackgroundColor};
}
`;
`

View File

@ -1,8 +1,8 @@
import React from "react";
import styled from "styled-components";
import React from 'react'
import styled from 'styled-components'
interface ChainIconProps {
className?: string;
className?: string
}
export const ChainIcon = ({ className }: ChainIconProps) => {
@ -17,8 +17,8 @@ export const ChainIcon = ({ className }: ChainIconProps) => {
>
<path d="M20.4919 24.7159C20.8389 24.3784 21.0941 23.9583 21.2306 23.4878C21.4369 22.7771 21.3498 22.0383 20.9854 21.4075L19.409 18.6769C19.0542 18.0624 18.4794 17.6245 17.7859 17.4387C17.7672 17.4337 17.7484 17.4289 17.7296 17.4242C17.2537 17.3072 16.7622 17.318 16.2963 17.4498L16.0648 17.0489C16.4119 16.7113 16.6672 16.2913 16.8038 15.8207C17.01 15.11 16.9229 14.371 16.5583 13.7399L14.9818 11.0093C14.6175 10.3783 14.0207 9.93364 13.3026 9.75668C12.8268 9.63968 12.3354 9.6507 11.8696 9.78247L11.6383 9.38174C11.9854 9.04419 12.2406 8.62397 12.3771 8.15336C12.5833 7.44267 12.4961 6.70371 12.1317 6.07268L10.5555 3.34242C9.92796 2.25533 8.63218 1.78173 7.44346 2.11579L6.77962 0.966562L5.55141 1.67598L6.21505 2.82497C5.33134 3.6873 5.09343 5.04607 5.72069 6.13334L7.29678 8.86349C7.65152 9.47804 8.22631 9.91611 8.91998 10.1019C8.93866 10.1069 8.95759 10.1118 8.97645 10.1164C9.4525 10.2334 9.94405 10.2225 10.41 10.0907L10.6413 10.4915C10.2942 10.829 10.0389 11.2492 9.90228 11.7198C9.69599 12.4305 9.78306 13.1695 10.1474 13.8005L11.7239 16.5311C12.0787 17.1456 12.6535 17.5836 13.3469 17.7693C13.3656 17.7743 13.3844 17.7792 13.4032 17.7838C13.8793 17.9009 14.3708 17.8899 14.8366 17.7581L15.068 18.1587C14.7209 18.4963 14.4657 18.9166 14.3292 19.3873C14.1231 20.0981 14.2102 20.837 14.5746 21.4677L16.1507 24.1983C16.5166 24.8315 17.1093 25.2567 17.7754 25.4351C18.2525 25.5629 18.7673 25.5642 19.2634 25.4247L19.9272 26.5746L21.1557 25.8658L20.4919 24.7159ZM10.881 8.06957L10.283 7.03348L9.05454 7.74257L9.65273 8.77879C9.53961 8.77949 9.42646 8.76647 9.31528 8.73914C8.97586 8.6576 8.69461 8.44787 8.52523 8.15445L6.94922 5.42435C6.71569 5.01958 6.74147 4.53136 6.97287 4.1369L7.17981 4.49521L8.40806 3.7858L8.20171 3.42851C8.32536 3.42779 8.44744 3.44307 8.56435 3.4744C8.87937 3.5588 9.15698 3.75669 9.32721 4.05159L10.9034 6.782C11.0729 7.07532 11.1125 7.422 11.015 7.75814C10.9831 7.86787 10.938 7.97221 10.881 8.06957ZM15.3074 15.7371L14.709 14.7008L13.4807 15.4101L14.079 16.4463C13.9662 16.447 13.8531 16.4339 13.7421 16.4066C13.4017 16.3224 13.1216 16.1153 12.9523 15.8221L11.3758 13.0914C11.2065 12.7982 11.1669 12.4515 11.2645 12.1153C11.2964 12.0055 11.3416 11.901 11.3987 11.8036L11.9967 12.8396L13.2252 12.1305L12.627 11.0943C12.7398 11.0936 12.8529 11.1067 12.9638 11.134C12.9729 11.1362 12.982 11.1385 12.991 11.1409C13.3186 11.2287 13.5886 11.4329 13.7534 11.7184L15.3299 14.449L15.33 14.4491C15.4995 14.7425 15.5391 15.0891 15.4415 15.4253C15.4098 15.5352 15.3645 15.6396 15.3074 15.7371ZM19.7344 23.4038L19.5279 23.0461L18.2996 23.7553L18.5057 24.1125C18.0485 24.1155 17.6129 23.8936 17.3791 23.4891L15.8029 20.7587C15.6336 20.4655 15.594 20.1188 15.6915 19.7825C15.7234 19.6727 15.7685 19.5682 15.8256 19.4708L16.424 20.5071L17.6523 19.7978L17.054 18.7618C17.1668 18.7611 17.2796 18.7742 17.3907 18.8015C17.3997 18.8037 17.4087 18.806 17.4177 18.8084C17.7455 18.8963 18.0157 19.1006 18.1805 19.3861L19.757 22.1167L19.7571 22.1169C19.9264 22.4099 19.966 22.7564 19.8684 23.0924C19.8366 23.2021 19.7914 23.3064 19.7344 23.4038Z" />
</Icon>
);
};
)
}
const Icon = styled.svg`
fill: ${({ theme }) => theme.secondary};
@ -27,4 +27,4 @@ const Icon = styled.svg`
&.transformed {
transform: matrix(-0.97, 0.26, 0.26, 0.97, 0, 0);
}
`;
`

View File

@ -1,10 +1,10 @@
import React from "react";
import styled from "styled-components";
import React from 'react'
import styled from 'styled-components'
type ChatSvgProps = {
width: number;
height: number;
};
width: number
height: number
}
export function ChatSvg({ width, height }: ChatSvgProps) {
return (
@ -20,12 +20,12 @@ export function ChatSvg({ width, height }: ChatSvgProps) {
d="M1.69922 7.99922C1.69922 4.51983 4.51983 1.69922 7.99922 1.69922C11.4786 1.69922 14.2992 4.51983 14.2992 7.99922V11.9992C14.2992 13.2695 13.2695 14.2992 11.9992 14.2992H7.99922C4.51983 14.2992 1.69922 11.4786 1.69922 7.99922ZM7.99922 3.19922C5.34825 3.19922 3.19922 5.34825 3.19922 7.99922C3.19922 10.6502 5.34825 12.7992 7.99922 12.7992H11.9992C12.441 12.7992 12.7992 12.441 12.7992 11.9992V7.99922C12.7992 5.34825 10.6502 3.19922 7.99922 3.19922Z"
/>
</svg>
);
)
}
export const ChatIcon = () => {
return <Icon width={16} height={16} />;
};
return <Icon width={16} height={16} />
}
const Icon = styled(ChatSvg)`
& > path {
@ -35,4 +35,4 @@ const Icon = styled(ChatSvg)`
&:hover > path {
fill: ${({ theme }) => theme.bodyBackgroundColor};
}
`;
`

View File

@ -1,11 +1,11 @@
import React from "react";
import styled from "styled-components";
import React from 'react'
import styled from 'styled-components'
type CheckIconProps = {
width: number;
height: number;
className?: string;
};
width: number
height: number
className?: string
}
export function CheckIcon({ width, height, className }: CheckIconProps) {
return (
@ -23,7 +23,7 @@ export function CheckIcon({ width, height, className }: CheckIconProps) {
d="M7.99992 14.6668C4.31802 14.6668 1.33325 11.6821 1.33325 8.00016C1.33325 4.31826 4.31802 1.3335 7.99992 1.3335C11.6818 1.3335 14.6666 4.31826 14.6666 8.00016C14.6666 11.6821 11.6818 14.6668 7.99992 14.6668ZM7.99992 13.6668C4.8703 13.6668 2.33325 11.1298 2.33325 8.00016C2.33325 4.87055 4.8703 2.3335 7.99992 2.3335C11.1295 2.3335 13.6666 4.87055 13.6666 8.00016C13.6666 11.1298 11.1295 13.6668 7.99992 13.6668Z"
/>
</Icon>
);
)
}
const Icon = styled.svg`
@ -32,4 +32,4 @@ const Icon = styled.svg`
&.green {
fill: ${({ theme }) => theme.greenColor};
}
`;
`

View File

@ -1,11 +1,11 @@
import React from "react";
import styled from "styled-components";
import React from 'react'
import styled from 'styled-components'
type ClearSvgProps = {
width: number;
height: number;
className?: string;
};
width: number
height: number
className?: string
}
export function ClearSvg({ height, width, className }: ClearSvgProps) {
return (
@ -23,10 +23,10 @@ export function ClearSvg({ height, width, className }: ClearSvgProps) {
d="M7.99992 14.6668C11.6818 14.6668 14.6666 11.6821 14.6666 8.00016C14.6666 4.31826 11.6818 1.3335 7.99992 1.3335C4.31802 1.3335 1.33325 4.31826 1.33325 8.00016C1.33325 11.6821 4.31802 14.6668 7.99992 14.6668ZM7.99992 13.6668C11.1295 13.6668 13.6666 11.1298 13.6666 8.00016C13.6666 4.87055 11.1295 2.3335 7.99992 2.3335C4.87031 2.3335 2.33325 4.87055 2.33325 8.00016C2.33325 11.1298 4.87031 13.6668 7.99992 13.6668Z"
/>
</Icon>
);
)
}
<svg
;<svg
width="16"
height="16"
viewBox="0 0 16 16"
@ -39,11 +39,11 @@ export function ClearSvg({ height, width, className }: ClearSvgProps) {
d="M8 15C11.866 15 15 11.866 15 8C15 4.13401 11.866 1 8 1C4.13401 1 1 4.13401 1 8C1 11.866 4.13401 15 8 15ZM11 5C11.2441 5.24408 11.2441 5.63981 11 5.88388L8.88393 8L11 10.1161C11.2441 10.3602 11.2441 10.7559 11 11C10.756 11.2441 10.3602 11.2441 10.1162 11L8.00005 8.88389L5.88393 11C5.63985 11.2441 5.24412 11.2441 5.00005 11C4.75597 10.7559 4.75597 10.3602 5.00005 10.1161L7.11616 8L5.00005 5.88389C4.75597 5.63981 4.75597 5.24408 5.00005 5C5.24412 4.75593 5.63985 4.75593 5.88393 5L8.00005 7.11612L10.1162 5C10.3602 4.75592 10.756 4.75592 11 5Z"
fill="#939BA1"
/>
</svg>;
</svg>
export const ClearIcon = () => {
return <Icon width={16} height={16} />;
};
return <Icon width={16} height={16} />
}
const Icon = styled.svg`
fill: ${({ theme }) => theme.tertiary};
@ -63,4 +63,4 @@ const Icon = styled.svg`
&.decline {
fill: ${({ theme }) => theme.redColor};
}
`;
`

View File

@ -1,11 +1,11 @@
import React from "react";
import styled from "styled-components";
import React from 'react'
import styled from 'styled-components'
type ClearSvgFullProps = {
width: number;
height: number;
className?: string;
};
width: number
height: number
className?: string
}
export function ClearSvgFull({ height, width, className }: ClearSvgFullProps) {
return (
@ -23,7 +23,7 @@ export function ClearSvgFull({ height, width, className }: ClearSvgFullProps) {
d="M8 15C11.866 15 15 11.866 15 8C15 4.13401 11.866 1 8 1C4.13401 1 1 4.13401 1 8C1 11.866 4.13401 15 8 15ZM11 5C11.2441 5.24408 11.2441 5.63981 11 5.88388L8.88393 8L11 10.1161C11.2441 10.3602 11.2441 10.7559 11 11C10.756 11.2441 10.3602 11.2441 10.1162 11L8.00005 8.88389L5.88393 11C5.63985 11.2441 5.24412 11.2441 5.00005 11C4.75597 10.7559 4.75597 10.3602 5.00005 10.1161L7.11616 8L5.00005 5.88389C4.75597 5.63981 4.75597 5.24408 5.00005 5C5.24412 4.75593 5.63985 4.75593 5.88393 5L8.00005 7.11612L10.1162 5C10.3602 4.75592 10.756 4.75592 11 5Z"
/>
</Icon>
);
)
}
const Icon = styled.svg`
@ -32,4 +32,4 @@ const Icon = styled.svg`
&:hover {
fill: ${({ theme }) => theme.primary};
}
`;
`

View File

@ -1,4 +1,4 @@
import React from "react";
import React from 'react'
export const CoinbaseLogo = () => {
return (
@ -46,5 +46,5 @@ export const CoinbaseLogo = () => {
</linearGradient>
</defs>
</svg>
);
};
)
}

View File

@ -1,10 +1,10 @@
import React from "react";
import styled from "styled-components";
import React from 'react'
import styled from 'styled-components'
type ColorChatSvgProps = {
width: number;
height: number;
};
width: number
height: number
}
export function ColorChatSvg({ width, height }: ColorChatSvgProps) {
return (
@ -130,12 +130,12 @@ export function ColorChatSvg({ width, height }: ColorChatSvgProps) {
</clipPath>
</defs>
</svg>
);
)
}
export const ColorChatIcon = () => {
return <Icon width={64} height={64} />;
};
return <Icon width={64} height={64} />
}
const Icon = styled(ColorChatSvg)`
& > path {
@ -145,4 +145,4 @@ const Icon = styled(ColorChatSvg)`
&:hover > path {
fill: ${({ theme }) => theme.bodyBackgroundColor};
}
`;
`

View File

@ -1,11 +1,11 @@
import React from "react";
import styled from "styled-components";
import React from 'react'
import styled from 'styled-components'
type CommunityIconProps = {
width: number;
height: number;
className?: string;
};
width: number
height: number
className?: string
}
export const CommunityIcon = ({
width,
@ -27,8 +27,8 @@ export const CommunityIcon = ({
d="M10.6641 14C11.7686 14 12.6641 13.1046 12.6641 12C13.7686 12 14.6641 11.1046 14.6641 10V4C14.6641 2.89543 13.7686 2 12.6641 2C7.14121 2 2.66406 6.47715 2.66406 12C2.66406 13.1046 3.55949 14 4.66406 14H10.6641ZM5.16406 12C4.88792 12 4.66244 11.7755 4.67944 11.4999C4.92738 7.47997 8.14404 4.26332 12.164 4.01538C12.4396 3.99838 12.6641 4.22386 12.6641 4.5V5.5C12.6641 5.77614 12.4394 5.99783 12.1642 6.02052C9.24919 6.26094 6.925 8.58513 6.68459 11.5002C6.66189 11.7754 6.4402 12 6.16406 12H5.16406ZM12.6641 8.5C12.6641 8.22386 12.4391 7.99672 12.1651 8.03082C10.3549 8.25609 8.92015 9.69083 8.69489 11.501C8.66078 11.775 8.88792 12 9.16406 12H10.1641C10.4402 12 10.6576 11.7727 10.7258 11.5051C10.9057 10.7982 11.4622 10.2417 12.1691 10.0617C12.4367 9.99359 12.6641 9.77614 12.6641 9.5V8.5Z"
/>
</Icon>
);
};
)
}
const Icon = styled.svg`
fill: ${({ theme }) => theme.secondary};
@ -40,4 +40,4 @@ const Icon = styled.svg`
&.red {
fill: ${({ theme }) => theme.redColor};
}
`;
`

View File

@ -1,11 +1,11 @@
import React from "react";
import styled from "styled-components";
import React from 'react'
import styled from 'styled-components'
type CopyIconProps = {
width: number;
height: number;
className?: string;
};
width: number
height: number
className?: string
}
export function CopyIcon({ width, height, className }: CopyIconProps) {
return (
@ -23,9 +23,9 @@ export function CopyIcon({ width, height, className }: CopyIconProps) {
d="M6.00016 4.00065C6.00016 2.52789 7.19407 1.33398 8.66683 1.33398H12.0002C13.4729 1.33398 14.6668 2.52789 14.6668 4.00065V7.33398C14.6668 8.80674 13.4729 10.0007 12.0002 10.0007H8.66683C7.19407 10.0007 6.00016 8.80674 6.00016 7.33398V4.00065ZM8.66683 2.33398H12.0002C12.9206 2.33398 13.6668 3.08018 13.6668 4.00065V7.33398C13.6668 8.25446 12.9206 9.00065 12.0002 9.00065H8.66683C7.74636 9.00065 7.00016 8.25446 7.00016 7.33398V4.00065C7.00016 3.08018 7.74636 2.33398 8.66683 2.33398Z"
/>
</Icon>
);
)
}
const Icon = styled.svg`
fill: ${({ theme }) => theme.tertiary};
`;
`

View File

@ -1,5 +1,5 @@
import React from "react";
import styled from "styled-components";
import React from 'react'
import styled from 'styled-components'
export const CreateIcon = () => {
return (
@ -17,11 +17,11 @@ export const CreateIcon = () => {
d="M21.2803 2.71986C20.2971 1.73661 18.7029 1.73661 17.7197 2.71986L9.33613 11.1034C9.00567 11.4339 8.76487 11.8431 8.63648 12.2925L7.77886 15.2941C7.70403 15.556 7.77707 15.8379 7.96967 16.0305C8.16227 16.2231 8.44415 16.2962 8.70604 16.2213L11.7077 15.3637C12.1571 15.2353 12.5663 14.9945 12.8968 14.6641L21.2803 6.28052C22.2636 5.29727 22.2636 3.70311 21.2803 2.71986ZM18.7803 3.78052C19.1778 3.38306 19.8222 3.38306 20.2197 3.78052C20.6171 4.17798 20.6171 4.8224 20.2197 5.21986L11.8361 13.6034C11.6859 13.7536 11.4999 13.8631 11.2956 13.9214C10.5531 14.1336 9.86662 13.4471 10.0788 12.7045C10.1371 12.5003 10.2466 12.3143 10.3968 12.1641L18.7803 3.78052Z"
/>
</Icon>
);
};
)
}
const Icon = styled.svg`
& > path {
fill: ${({ theme }) => theme.primary};
}
`;
`

View File

@ -1,8 +1,8 @@
import React from "react";
import styled from "styled-components";
import React from 'react'
import styled from 'styled-components'
interface CrossIconProps {
memberView?: boolean;
memberView?: boolean
}
export const CrossIcon = ({ memberView }: CrossIconProps) => (
@ -12,7 +12,7 @@ export const CrossIcon = ({ memberView }: CrossIconProps) => (
viewBox="0 0 12 12"
fill="none"
xmlns="http://www.w3.org/2000/svg"
className={memberView ? "white" : ""}
className={memberView ? 'white' : ''}
>
<path
fillRule="evenodd"
@ -20,7 +20,7 @@ export const CrossIcon = ({ memberView }: CrossIconProps) => (
d="M6 4.57404L1.72275 0.296796C1.32616 -0.0997918 0.689941 -0.0975927 0.296174 0.296174C-0.100338 0.692686 -0.0973145 1.32864 0.296796 1.72275L4.57404 6L0.296796 10.2772C-0.0997918 10.6738 -0.0975927 11.3101 0.296174 11.7038C0.692686 12.1003 1.32864 12.0973 1.72275 11.7032L6 7.42596L10.2772 11.7032C10.6738 12.0998 11.3101 12.0976 11.7038 11.7038C12.1003 11.3073 12.0973 10.6714 11.7032 10.2772L7.42596 6L11.7032 1.72275C12.0998 1.32616 12.0976 0.689941 11.7038 0.296174C11.3073 -0.100338 10.6714 -0.0973145 10.2772 0.296796L6 4.57404Z"
/>
</Icon>
);
)
const Icon = styled.svg`
& > path {
@ -32,4 +32,4 @@ const Icon = styled.svg`
fill: ${({ theme }) => theme.bodyBackgroundColor};
}
}
`;
`

View File

@ -1,11 +1,11 @@
import React from "react";
import styled from "styled-components";
import React from 'react'
import styled from 'styled-components'
type DeleteIconProps = {
width: number;
height: number;
className?: string;
};
width: number
height: number
className?: string
}
export const DeleteIcon = ({ width, height, className }: DeleteIconProps) => {
return (
@ -22,8 +22,8 @@ export const DeleteIcon = ({ width, height, className }: DeleteIconProps) => {
d="M6.26191 1.5C5.47293 1.5 4.83333 2.13959 4.83333 2.92857C4.83333 3.33621 4.50288 3.66667 4.09524 3.66667H2C1.72386 3.66667 1.5 3.89052 1.5 4.16667C1.5 4.44281 1.72386 4.66667 2 4.66667H2.49251C2.66109 4.66667 2.80314 4.79253 2.82342 4.95989L3.71566 12.3209C3.87795 13.6597 5.0143 14.6667 6.36295 14.6667H9.63705C10.9857 14.6667 12.1221 13.6597 12.2843 12.3209L13.1766 4.95989C13.1969 4.79253 13.3389 4.66667 13.5075 4.66667H14C14.2761 4.66667 14.5 4.44281 14.5 4.16667C14.5 3.89052 14.2761 3.66667 14 3.66667H11.9048C11.4971 3.66667 11.1667 3.33621 11.1667 2.92857C11.1667 2.13959 10.5271 1.5 9.7381 1.5L6.26191 1.5ZM9.80586 3.66667C10.0501 3.66667 10.2156 3.40724 10.1826 3.16524C10.1721 3.08786 10.1667 3.00885 10.1667 2.92857C10.1667 2.69188 9.97479 2.5 9.7381 2.5L6.2619 2.5C6.02521 2.5 5.83333 2.69188 5.83333 2.92857C5.83333 3.00885 5.82789 3.08786 5.81736 3.16524C5.78441 3.40725 5.9499 3.66667 6.19414 3.66667L9.80586 3.66667ZM11.9048 4.66667C12.0643 4.66667 12.1879 4.80617 12.1687 4.96453L11.2916 12.2006C11.1902 13.0373 10.48 13.6667 9.63705 13.6667H6.36295C5.52004 13.6667 4.80983 13.0373 4.7084 12.2006L3.8313 4.96453C3.81211 4.80616 3.93572 4.66667 4.09524 4.66667L11.9048 4.66667Z"
/>
</Icon>
);
};
)
}
const Icon = styled.svg`
fill: ${({ theme }) => theme.tertiary};
@ -35,4 +35,4 @@ const Icon = styled.svg`
&.grey {
fill: ${({ theme }) => theme.secondary};
}
`;
`

View File

@ -1,11 +1,11 @@
import React from "react";
import styled from "styled-components";
import React from 'react'
import styled from 'styled-components'
type DownloadIconProps = {
width: number;
height: number;
className?: string;
};
width: number
height: number
className?: string
}
export function DownloadIcon({ width, height, className }: DownloadIconProps) {
return (
@ -19,9 +19,9 @@ export function DownloadIcon({ width, height, className }: DownloadIconProps) {
<path d="M10.6668 8.83399C10.6668 8.55784 10.8924 8.33835 11.1647 8.29286C12.5846 8.05568 13.6668 6.82121 13.6668 5.33399C13.6668 3.67713 12.3237 2.33399 10.6668 2.33399L5.3335 2.33399C3.67664 2.33399 2.3335 3.67713 2.3335 5.33399C2.3335 6.82121 3.4157 8.05568 4.83559 8.29286C5.10796 8.33835 5.3335 8.55784 5.3335 8.83399C5.3335 9.11013 5.10852 9.33726 4.83449 9.30316C2.86085 9.05755 1.3335 7.37414 1.3335 5.33399C1.3335 3.12485 3.12436 1.33398 5.3335 1.33398L10.6668 1.33399C12.876 1.33399 14.6668 3.12485 14.6668 5.33399C14.6668 7.37414 13.1395 9.05755 11.1658 9.30316C10.8918 9.33726 10.6668 9.11013 10.6668 8.83399Z" />
<path d="M8.00016 4.83399C8.27631 4.83399 8.50016 5.05784 8.50016 5.33399V11.9888C8.50016 12.2858 8.85921 12.4345 9.0692 12.2245L10.3133 10.9804C10.5085 10.7852 10.8251 10.7852 11.0204 10.9804C11.2156 11.1757 11.2156 11.4923 11.0204 11.6875L8.35372 14.3542C8.15845 14.5495 7.84187 14.5495 7.64661 14.3542L4.97994 11.6875C4.78468 11.4923 4.78468 11.1757 4.97994 10.9804C5.1752 10.7852 5.49179 10.7852 5.68705 10.9804L6.93113 12.2245C7.14112 12.4345 7.50016 12.2858 7.50016 11.9888V5.33399C7.50016 5.05784 7.72402 4.83399 8.00016 4.83399Z" />
</Icon>
);
)
}
const Icon = styled.svg`
fill: ${({ theme }) => theme.tertiary};
`;
`

View File

@ -1,11 +1,11 @@
import React from "react";
import styled from "styled-components";
import React from 'react'
import styled from 'styled-components'
type EditIconProps = {
width: number;
height: number;
className?: string;
};
width: number
height: number
className?: string
}
export function EditIcon({ width, height, className }: EditIconProps) {
return (
@ -22,7 +22,7 @@ export function EditIcon({ width, height, className }: EditIconProps) {
d="M10.7914 2.16376C11.6321 1.32302 12.9952 1.32302 13.836 2.16376C14.6767 3.00451 14.6767 4.36763 13.836 5.20838L6.0015 13.0429C5.71671 13.3276 5.36405 13.5352 4.97679 13.6458L2.1717 14.4472C1.99679 14.4972 1.80854 14.4484 1.67992 14.3198C1.55129 14.1912 1.50251 14.0029 1.55249 13.828L2.35394 11.0229C2.46459 10.6357 2.6721 10.283 2.95688 9.99823L10.7914 2.16376ZM13.1276 2.87212C12.6781 2.42258 11.9492 2.42258 11.4997 2.87212L3.66524 10.7066C3.50083 10.871 3.38103 11.0746 3.31716 11.2981C3.07579 12.1429 3.85682 12.9239 4.70159 12.6826C4.92515 12.6187 5.12874 12.4989 5.29315 12.3345L13.1276 4.50003C13.5772 4.05049 13.5772 3.32165 13.1276 2.87212Z"
/>
</Icon>
);
)
}
const Icon = styled.svg`
@ -31,4 +31,4 @@ const Icon = styled.svg`
&.grey {
fill: ${({ theme }) => theme.secondary};
}
`;
`

View File

@ -1,8 +1,8 @@
import React from "react";
import styled from "styled-components";
import React from 'react'
import styled from 'styled-components'
interface ThemeProps {
isActive?: boolean;
isActive?: boolean
}
export const EmojiIcon = ({ isActive }: ThemeProps) => {
@ -14,26 +14,26 @@ export const EmojiIcon = ({ isActive }: ThemeProps) => {
xmlns="http://www.w3.org/2000/svg"
>
<path
className={isActive ? "active" : ""}
className={isActive ? 'active' : ''}
fillRule="evenodd"
clipRule="evenodd"
d="M10 18.5C14.6944 18.5 18.5 14.6944 18.5 10C18.5 5.30558 14.6944 1.5 10 1.5C5.30558 1.5 1.5 5.30558 1.5 10C1.5 14.6944 5.30558 18.5 10 18.5ZM10 20C15.5228 20 20 15.5228 20 10C20 4.47715 15.5228 0 10 0C4.47715 0 0 4.47715 0 10C0 15.5228 4.47715 20 10 20Z"
/>
<path
className={isActive ? "active" : ""}
className={isActive ? 'active' : ''}
d="M7.56858 13.1746C7.22903 12.9373 6.75712 12.9308 6.46422 13.2237C6.17133 13.5166 6.16876 13.996 6.49708 14.2485C7.46695 14.9946 8.68155 15.4381 9.99976 15.4381C11.318 15.4381 12.5326 14.9946 13.5024 14.2485C13.8308 13.996 13.8282 13.5166 13.5353 13.2237C13.2424 12.9308 12.7705 12.9373 12.4309 13.1746C11.742 13.6558 10.9039 13.9381 9.99976 13.9381C9.09565 13.9381 8.25747 13.6558 7.56858 13.1746Z"
/>
<path
className={isActive ? "active" : ""}
className={isActive ? 'active' : ''}
d="M15 8.5C15 9.32843 14.3284 10 13.5 10C12.6716 10 12 9.32843 12 8.5C12 7.67157 12.6716 7 13.5 7C14.3284 7 15 7.67157 15 8.5Z"
/>
<path
className={isActive ? "active" : ""}
className={isActive ? 'active' : ''}
d="M8 8.5C8 9.32843 7.32843 10 6.5 10C5.67157 10 5 9.32843 5 8.5C5 7.67157 5.67157 7 6.5 7C7.32843 7 8 7.67157 8 8.5Z"
/>
</Icon>
);
};
)
}
const Icon = styled.svg`
& > path {
@ -43,4 +43,4 @@ const Icon = styled.svg`
& > path.active {
fill: ${({ theme }) => theme.tertiary};
}
`;
`

View File

@ -1,4 +1,4 @@
import React from "react";
import React from 'react'
export const EthereumLogo = () => (
<svg
@ -35,4 +35,4 @@ export const EthereumLogo = () => (
fillOpacity="0.602"
/>
</svg>
);
)

View File

@ -1,8 +1,8 @@
import React from "react";
import styled from "styled-components";
import React from 'react'
import styled from 'styled-components'
interface ThemeProps {
isActive?: boolean;
isActive?: boolean
}
export const GifIcon = ({ isActive }: ThemeProps) => {
@ -14,26 +14,26 @@ export const GifIcon = ({ isActive }: ThemeProps) => {
xmlns="http://www.w3.org/2000/svg"
>
<path
className={isActive ? "active" : ""}
className={isActive ? 'active' : ''}
fillRule="evenodd"
clipRule="evenodd"
d="M16 1.5H4C2.61929 1.5 1.5 2.61929 1.5 4V16C1.5 17.3807 2.61929 18.5 4 18.5H16C17.3807 18.5 18.5 17.3807 18.5 16V4C18.5 2.61929 17.3807 1.5 16 1.5ZM4 0C1.79086 0 0 1.79086 0 4V16C0 18.2091 1.79086 20 4 20H16C18.2091 20 20 18.2091 20 16V4C20 1.79086 18.2091 0 16 0H4Z"
/>
<path
className={isActive ? "active" : ""}
className={isActive ? 'active' : ''}
d="M8.72261 11.4868V10.4133C8.72261 9.99528 8.38061 9.65328 7.96261 9.65328H6.22411C5.90111 9.65328 5.64461 9.90978 5.64461 10.2328C5.64461 10.5748 5.90111 10.8313 6.22411 10.8313H7.37361V11.5913C7.11711 11.8288 6.58511 12.0758 6.02461 12.0758C4.87511 12.0758 4.03911 11.1923 4.03911 9.99528C4.03911 8.79828 4.87511 7.91478 6.02461 7.91478C6.50911 7.91478 6.98411 8.12378 7.34511 8.47528C7.46861 8.59878 7.63961 8.66528 7.80111 8.66528C8.13361 8.66528 8.43761 8.38978 8.43761 8.05728C8.43761 7.91478 8.38061 7.76278 8.27611 7.64878C7.78211 7.11678 7.05061 6.71778 6.02461 6.71778C4.17211 6.71778 2.65211 7.99078 2.65211 9.99528C2.65211 11.9903 4.17211 13.2823 6.02461 13.2823C7.30711 13.2823 8.72261 12.6363 8.72261 11.4868Z"
/>
<path
className={isActive ? "active" : ""}
className={isActive ? 'active' : ''}
d="M11.4392 12.5603V7.43978C11.4392 7.07878 11.1352 6.77478 10.7742 6.77478C10.3942 6.77478 10.0902 7.07878 10.0902 7.43978V12.5603C10.0902 12.9213 10.3942 13.2253 10.7552 13.2253C11.1352 13.2253 11.4392 12.9213 11.4392 12.5603Z"
/>
<path
className={isActive ? "active" : ""}
className={isActive ? 'active' : ''}
d="M17.3479 7.43029C17.3479 7.09778 17.0819 6.83179 16.7684 6.83179H13.5669C13.1489 6.83179 12.8069 7.17379 12.8069 7.59179V12.5603C12.8069 12.9213 13.1109 13.2253 13.4719 13.2253C13.8519 13.2253 14.1559 12.9213 14.1559 12.5603V11.0463C14.1559 10.7701 14.3797 10.5463 14.6559 10.5463H16.2425C16.556 10.5463 16.822 10.2803 16.822 9.95728C16.822 9.62478 16.556 9.35879 16.2425 9.35879H14.6559C14.3797 9.35879 14.1559 9.13493 14.1559 8.85879V8.51929C14.1559 8.24314 14.3797 8.01929 14.6559 8.01929H16.7684C17.0819 8.01929 17.3479 7.75329 17.3479 7.43029Z"
/>
</Icon>
);
};
)
}
const Icon = styled.svg`
& > path {
@ -43,4 +43,4 @@ const Icon = styled.svg`
& > path.active {
fill: ${({ theme }) => theme.tertiary};
}
`;
`

View File

@ -1,8 +1,8 @@
import React from "react";
import styled from "styled-components";
import React from 'react'
import styled from 'styled-components'
interface GroupIconProps {
active?: boolean;
active?: boolean
}
export const GroupIcon = ({ active }: GroupIconProps) => {
@ -13,15 +13,15 @@ export const GroupIcon = ({ active }: GroupIconProps) => {
viewBox="0 0 14 10"
fill="none"
xmlns="http://www.w3.org/2000/svg"
className={`${active && "active"}`}
className={`${active && 'active'}`}
>
<path d="M7 4.5C8.24265 4.5 9.25 3.49264 9.25 2.25C9.25 1.00736 8.24265 0 7 0C5.75736 0 4.75 1.00736 4.75 2.25C4.75 3.49264 5.75736 4.5 7 4.5Z" />
<path d="M3.12343 9.01012C3.56395 7.27976 5.13252 6 7 6C8.86749 6 10.4361 7.27976 10.8766 9.01012C11.0128 9.54533 10.5523 10 10 10H4C3.44772 10 2.98718 9.54533 3.12343 9.01012Z" />
<path d="M3.5 4.25C3.5 5.2165 2.7165 6 1.75 6C0.783502 6 0 5.2165 0 4.25C0 3.2835 0.783502 2.5 1.75 2.5C2.7165 2.5 3.5 3.2835 3.5 4.25Z" />
<path d="M12.25 6C13.2165 6 14 5.2165 14 4.25C14 3.2835 13.2165 2.5 12.25 2.5C11.2835 2.5 10.5 3.2835 10.5 4.25C10.5 5.2165 11.2835 6 12.25 6Z" />
</Icon>
);
};
)
}
const Icon = styled.svg`
fill: ${({ theme }) => theme.secondary};
@ -29,4 +29,4 @@ const Icon = styled.svg`
&.active {
fill: ${({ theme }) => theme.primary};
}
`;
`

View File

@ -1,5 +1,5 @@
import React from "react";
import styled from "styled-components";
import React from 'react'
import styled from 'styled-components'
export const HideIcon = () => (
<Icon
@ -17,8 +17,8 @@ export const HideIcon = () => (
<path d="M8.85753 6.41675C8.56645 6.19035 8.61339 5.73908 8.95606 5.60284C9.89767 5.22846 10.9163 5 12.0003 5C17.0371 5 20.6645 9.93293 21.6993 11.5167C21.893 11.8132 21.893 12.1868 21.6993 12.4833C21.3897 12.9571 20.8481 13.7307 20.1061 14.5822C19.9349 14.7787 19.6402 14.8032 19.4344 14.6432L19.0412 14.3374C18.8097 14.1573 18.7827 13.8179 18.9753 13.5967C19.1214 13.429 19.2592 13.2645 19.3883 13.1052C19.9119 12.459 19.9119 11.541 19.3883 10.8948C18.8556 10.2375 18.1761 9.49212 17.373 8.80219C15.8471 7.49116 14.0175 6.5 12.0003 6.5C11.2517 6.5 10.529 6.63648 9.83805 6.87515C9.672 6.93251 9.48731 6.90658 9.34863 6.79872L8.85753 6.41675Z" />
<path d="M15.8618 10.9529C15.9709 11.3561 15.5158 11.5954 15.1862 11.339L13.7844 10.2487C13.6279 10.0894 13.4503 9.95089 13.2561 9.83783L11.8057 8.70975C11.4964 8.46923 11.6085 8 12.0002 8C13.8471 8 15.4016 9.25163 15.8618 10.9529Z" />
</Icon>
);
)
const Icon = styled.svg`
fill: ${({ theme }) => theme.tertiary};
`;
`

View File

@ -1,11 +1,11 @@
import React from "react";
import styled from "styled-components";
import React from 'react'
import styled from 'styled-components'
type LeftIconProps = {
width: number;
height: number;
className?: string;
};
width: number
height: number
className?: string
}
export function LeftIcon({ width, height, className }: LeftIconProps) {
return (
@ -18,7 +18,7 @@ export function LeftIcon({ width, height, className }: LeftIconProps) {
>
<path d="M7.01957 4.35355C7.21483 4.15829 7.21483 3.84171 7.01957 3.64645C6.82431 3.45118 6.50772 3.45118 6.31246 3.64645L2.31246 7.64645C2.1172 7.84171 2.1172 8.15829 2.31246 8.35355L6.31246 12.3536C6.50772 12.5488 6.82431 12.5488 7.01957 12.3536C7.21483 12.1583 7.21483 11.8417 7.01957 11.6464L4.44216 9.06904C4.23217 8.85905 4.38089 8.5 4.67786 8.5H13.3327C13.6088 8.5 13.8327 8.27614 13.8327 8C13.8327 7.72386 13.6088 7.5 13.3327 7.5H4.67786C4.38089 7.5 4.23217 7.14095 4.44216 6.93096L7.01957 4.35355Z" />
</Icon>
);
)
}
const Icon = styled.svg`
@ -31,4 +31,4 @@ const Icon = styled.svg`
&.red {
fill: ${({ theme }) => theme.redColor};
}
`;
`

View File

@ -1,5 +1,5 @@
import React from "react";
import styled, { keyframes } from "styled-components";
import React from 'react'
import styled, { keyframes } from 'styled-components'
const rotation = keyframes`
from {
@ -8,10 +8,10 @@ const rotation = keyframes`
to {
transform: rotate(360deg);
}
`;
`
interface LoadingIconProps {
className?: string;
className?: string
}
export const LoadingIcon = ({ className }: LoadingIconProps) => (
@ -28,7 +28,7 @@ export const LoadingIcon = ({ className }: LoadingIconProps) => (
d="M10.7682 5.07742C10.5667 4.18403 10.0777 3.37742 9.37244 2.77889C8.66702 2.18025 7.78327 1.8222 6.85295 1.7598C5.9226 1.69741 4.99749 1.93417 4.21597 2.43357C3.4346 2.93289 2.83935 3.66744 2.51731 4.52621C2.19533 5.38485 2.16318 6.32294 2.4255 7.20091C2.68785 8.07899 3.23118 8.85135 3.9762 9.40157C4.72137 9.95188 5.62791 10.25 6.56041 10.25L6.56041 11.75C5.30863 11.75 4.08949 11.3499 3.0851 10.6082C2.08057 9.86633 1.34435 8.82207 0.988276 7.63032C0.632173 6.43846 0.675924 5.16459 1.11282 3.99953C1.54966 2.8346 2.35554 1.84232 3.40827 1.16961C4.46086 0.496978 5.7044 0.179402 6.95332 0.263164C8.20227 0.346928 9.39145 0.827686 10.343 1.63521C11.2947 2.44286 11.9578 3.53431 12.2314 4.74738L10.7682 5.07742Z"
/>
</Icon>
);
)
const Icon = styled.svg`
& > path {
@ -41,4 +41,4 @@ const Icon = styled.svg`
fill: ${({ theme }) => theme.secondary};
}
}
`;
`

View File

@ -1,5 +1,5 @@
import React from "react";
import styled from "styled-components";
import React from 'react'
import styled from 'styled-components'
export const LogoutIcon = () => {
return (
@ -13,9 +13,9 @@ export const LogoutIcon = () => {
<path d="M13.5371 6C16.1605 6 18.2871 8.12665 18.2871 10.75V12.75C18.2871 13.1642 17.9513 13.5 17.5371 13.5C17.1229 13.5 16.7871 13.1642 16.7871 12.75V10.75C16.7871 8.95507 15.332 7.5 13.5371 7.5L12.5372 7.5H11.7499L10.75 7.5C8.95507 7.5 7.5 8.95507 7.5 10.75V11.4999V12.75V18.75V19.4999V20.75C7.5 22.5449 8.95507 24 10.75 24H11.7499H12.5372H13.5371C15.332 24 16.7871 22.5449 16.7871 20.75V18.75C16.7871 18.3358 17.1229 18 17.5371 18C17.9513 18 18.2871 18.3358 18.2871 18.75V20.75C18.2871 23.3734 16.1605 25.5 13.5371 25.5H12.5372H11.7499H10.75C8.12665 25.5 6 23.3734 6 20.75V19.4999V18.75V12.75V11.4999V10.75C6 8.12665 8.12665 6 10.75 6H11.7499H12.5372H13.5371Z" />
<path d="M21.9822 16.75C22.4277 16.75 22.6508 17.2886 22.3358 17.6036L20.4697 19.4697C20.1768 19.7626 20.1768 20.2374 20.4697 20.5303C20.7626 20.8232 21.2374 20.8232 21.5303 20.5303L25.5303 16.5303C25.8232 16.2374 25.8232 15.7626 25.5303 15.4697L21.5303 11.4697C21.2374 11.1768 20.7626 11.1768 20.4697 11.4697C20.1768 11.7626 20.1768 12.2374 20.4697 12.5303L22.3358 14.3964C22.6508 14.7114 22.4277 15.25 21.9822 15.25L12 15.25C11.5858 15.25 11.25 15.5858 11.25 16C11.25 16.4142 11.5858 16.75 12 16.75L21.9822 16.75Z" />
</Icon>
);
};
)
}
const Icon = styled.svg`
fill: ${({ theme }) => theme.tertiary};
`;
`

View File

@ -1,4 +1,4 @@
import React from "react";
import React from 'react'
export const MarkerdaoLogo = () => (
<svg
@ -30,4 +30,4 @@ export const MarkerdaoLogo = () => (
</linearGradient>
</defs>
</svg>
);
)

View File

@ -1,5 +1,5 @@
import React from "react";
import styled from "styled-components";
import React from 'react'
import styled from 'styled-components'
export const MembersIcon = () => {
return (
@ -16,11 +16,11 @@ export const MembersIcon = () => {
/>
<path d="M9.14735 25.0368C9.53098 25.1327 9.91944 24.9141 10.0836 24.5543C11.1079 22.3099 13.3718 20.75 16 20.75C18.6684 20.75 20.9613 22.3579 21.9625 24.6577C22.1289 25.0398 22.5478 25.2663 22.9456 25.142C23.3386 25.0192 23.5622 24.6006 23.4061 24.2196C22.2119 21.3039 19.3458 19.25 16 19.25C12.704 19.25 9.8736 21.2432 8.64834 24.0901C8.47629 24.4898 8.72515 24.9313 9.14735 25.0368Z" />
</Icon>
);
};
)
}
const Icon = styled.svg`
& > path {
fill: ${({ theme }) => theme.primary};
}
`;
`

Some files were not shown because too many files have changed in this diff Show More