Skip to content

Commit

Permalink
feat: Group chat (#196)
Browse files Browse the repository at this point in the history
Co-authored-by: jaswinder.khartri@fetch.ai <jaswinder.khartri@fetch.ai>
Co-authored-by: jas2212 <93518923+jas2212@users.noreply.github.com>
  • Loading branch information
3 people authored Feb 10, 2023
1 parent 2cafffe commit 9c78b41
Show file tree
Hide file tree
Showing 137 changed files with 7,399 additions and 944 deletions.
132 changes: 132 additions & 0 deletions packages/extension/src/@types/chat.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
// Params Type Definitions

export interface NewGroupDetails {
isEditGroup: boolean;
group: GroupDetails;
}
export interface GroupDetails {
contents: string;
description: string;
groupId: string;
members: GroupMembers[];
name: string;
onlyAdminMessages: boolean;
}

export interface GroupMembers {
address: string;
pubKey: string;
encryptedSymmetricKey: string;
isAdmin: boolean;
}

export interface GroupMessagePayload {
message: string;
type: string;
}

export interface PublicKeyDetails {
address: string;
channelId: string;
privacySetting: string;
publicKey: string;
}

export interface NewMessageUpdate {
type: string;
message: Message;
}

// Graphql Type Definitions
export interface Message {
id: string;
sender: string;
target: string;
contents: string;
groupId: string;
expiryTimestamp: string;
commitTimestamp: string;
}

export interface GroupAddress {
address: string;
pubKey: string;
lastSeenTimestamp: string;
groupLastSeenTimestamp: string;
encryptedSymmetricKey: string;
isAdmin: boolean;
removedAt: Date;
}

export interface Group {
id: string; // groupID
name: string; // contactAddress
isDm: boolean;
addresses: GroupAddress[];
lastMessageContents: string;
lastMessageSender: string;
lastMessageTimestamp: string;
lastSeenTimestamp: string;
description?: string;
createdAt: string;
removedAt: Date;
}

export interface Pagination {
page: number;
pageCount: number;
total: number;
lastPage: number;
}

//Redux Selectors Type Definitions
export interface Messages {
[key: string]: Message;
}

export interface Chat {
contactAddress: string;
messages: Messages;
pubKey?: string;
pagination: Pagination;
}

//key is group ID
export interface Chats {
[key: string]: Chat;
}

export interface BlockedAddressState {
[key: string]: boolean;
}

export interface Groups {
[contactAddress: string]: Group;
}

export interface NameAddress {
[key: string]: string;
}

export enum GroupChatOptions {
groupInfo,
muteGroup,
leaveGroup,
deleteGroup,
chatSettings,
}

export enum GroupChatMemberOptions {
addToAddressBook,
viewInAddressBook,
messageMember,
removeMember,
removeAdminStatus,
makeAdminStatus,
dissmisPopup,
}

export enum CommonPopupOptions {
cancel,
ok,
}
6 changes: 3 additions & 3 deletions packages/extension/src/bootstrap.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import React, { Suspense } from "react";
import ReactDOM from "react-dom";
import { Banner } from "./components/banner";
import { Banner } from "@components/banner";

const Application = React.lazy(() => import("./index"));

const LoadingScreen: React.FC = () => {
return (
<Banner
icon={require("./public/assets/temp-icon.svg")}
logo={require("./public/assets/logo-temp.png")}
icon={require("@assets/temp-icon.svg")}
logo={require("@assets/logo-temp.png")}
/>
);
};
Expand Down
101 changes: 101 additions & 0 deletions packages/extension/src/components/chat-actions-dropdown/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import amplitude from "amplitude-js";
import React from "react";
import { useHistory } from "react-router";
import style from "./style.module.scss";

export const ChatActionsDropdown = ({
added,
blocked,
showDropdown,
handleClick,
}: {
added: boolean;
blocked: boolean;
showDropdown: boolean;
handleClick: (data: string) => void;
}) => {
return (
<>
{showDropdown && (
<div className={style.dropdown}>
{added ? <ViewContactOption /> : <AddContactOption />}
{blocked ? (
<UnblockOption handleClick={handleClick} />
) : (
<BlockOption handleClick={handleClick} />
)}
{/* <div onClick={() => handleClick("delete")}>Delete chat</div> */}
</div>
)}
</>
);
};

const ViewContactOption = () => {
const history = useHistory();
return (
<div
onClick={() => {
amplitude.getInstance().logEvent("Address book viewed", {});
history.push("/setting/address-book");
}}
>
View in address book
</div>
);
};

const AddContactOption = () => {
const history = useHistory();
const userName = history.location.pathname.split("/")[2];
return (
<div
onClick={() => {
amplitude.getInstance().logEvent("Add to address click", {});
history.push({
pathname: "/setting/address-book",
state: {
openModal: true,
addressInputValue: userName,
},
});
}}
>
Add to address book
</div>
);
};

const BlockOption = ({
handleClick,
}: {
handleClick: (data: string) => void;
}) => {
return (
<div
onClick={() => {
amplitude.getInstance().logEvent("Block click", {});
handleClick("block");
}}
>
Block contact
</div>
);
};

const UnblockOption = ({
handleClick,
}: {
handleClick: (data: string) => void;
}) => {
return (
<div
onClick={() => {
amplitude.getInstance().logEvent("Unblock click", {});
handleClick("unblock");
}}
>
Unblock contact
</div>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import React from "react";
import style from "./style.module.scss";
import { CommonPopupOptions } from "@chatTypes";
export const AlertPopup = ({
heading,
description,
firstButtonTitle,
secondButtonTitle,
processing,
onClick,
}: {
setConfirmAction: React.Dispatch<React.SetStateAction<boolean>>;
heading: string;
description: string;
firstButtonTitle: string;
secondButtonTitle: string;
processing?: boolean;
onClick: (option: CommonPopupOptions) => void;
}) => {
return (
<>
<div className={style.overlay} />
<div className={style.popup}>
<h4>{heading}</h4>
<section>
<p style={{ whiteSpace: "pre-wrap" }} className={style.textContainer}>
{description}
</p>
</section>
<div className={style.buttonContainer}>
<button
type="button"
disabled={processing}
onClick={() => onClick(CommonPopupOptions.cancel)}
>
{firstButtonTitle}
</button>
<button
type="button"
className={style.btn}
disabled={processing}
onClick={() => onClick(CommonPopupOptions.ok)}
>
{secondButtonTitle}
</button>
</div>
</div>
</>
);
};
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { useState } from "react";
import { useHistory } from "react-router";
import { blockUser } from "../../graphQL/messages-api";
import { blockUser } from "@graphQL/messages-api";
import style from "./style.module.scss";

export const BlockUserPopup = ({
Expand Down
Original file line number Diff line number Diff line change
@@ -1,26 +1,23 @@
import { deleteGroup } from "@graphQL/groups-api";
import amplitude from "amplitude-js";
import React, { useState } from "react";
import { unblockUser } from "../../../../graphQL/messages-api";
import { useHistory } from "react-router";
import style from "./style.module.scss";

export const UnblockUserPopup = ({
userName,
export const DeleteGroupPopup = ({
setConfirmAction,
}: {
userName: string;
setConfirmAction: React.Dispatch<React.SetStateAction<boolean>>;
}) => {
const [processing, setProcessing] = useState(false);

const handleBlock = async () => {
const history = useHistory();
const handleDelete = async () => {
setProcessing(true);
try {
await unblockUser(userName);
} catch (e) {
console.log(e);
} finally {
setProcessing(false);
setConfirmAction(false);
}
const groupId = history.location.pathname.split("/")[3];
deleteGroup(groupId);
setConfirmAction(false);
amplitude.getInstance().logEvent("Delete group click", {});
history.push("/chat");
};

const handleCancel = () => {
Expand All @@ -31,11 +28,11 @@ export const UnblockUserPopup = ({
<>
<div className={style.overlay} />
<div className={style.popup}>
<h4>Unblock User</h4>
<h4>Delete Group</h4>
<section>
<p className={style.textContainer}>
This contact will not be able to send you messages. The contact will
not be notified.
You will lose all your messages in this group. This action cannot be
undone
</p>
</section>
<div className={style.buttonContainer}>
Expand All @@ -45,10 +42,10 @@ export const UnblockUserPopup = ({
<button
type="button"
className={style.btn}
onClick={handleBlock}
onClick={handleDelete}
disabled={processing}
>
Unblock
Delete
</button>
</div>
</div>
Expand Down
Loading

0 comments on commit 9c78b41

Please sign in to comment.