Skip to content

Commit

Permalink
feat(messenger): redux and weshnet connection
Browse files Browse the repository at this point in the history
  • Loading branch information
sakul-budhathoki committed Nov 19, 2023
1 parent 3814aa7 commit 05248ec
Show file tree
Hide file tree
Showing 17 changed files with 1,434 additions and 11 deletions.
2 changes: 1 addition & 1 deletion packages/screens/Settings/SettingsScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ import { ScreenFC, useAppNavigation } from "../../utils/navigation";
import { neutralA3, primaryColor } from "../../utils/style/colors";
import { fontSemibold14 } from "../../utils/style/fonts";
import { modalMarginPadding } from "../../utils/style/modals";
import { createWeshClient } from "../../utils/weshnet";
import { createWeshClient } from "../../weshnet";

const NFTAPIKeyInput: React.FC = () => {
const userIPFSKey = useSelector(selectNFTStorageAPI);
Expand Down
214 changes: 214 additions & 0 deletions packages/store/slices/message.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,214 @@
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
import { uniqBy } from "lodash";
import moment from "moment";

import {
ContactRequest,
Conversation,
MessageList,
Message,
CONVERSATION_TYPES,
PeerItem,
} from "./../../utils/types/message";
import { weshConfig } from "../../weshnet/config";
import { stringFromBytes } from "../../weshnet/utils";
import { RootState } from "../store";

export interface MessageState {
isWeshConnected: boolean;
peerList: PeerItem[];
contactInfo: {
name: string;
avatar: string;
publicRendezvousSeed: string;
shareLink: string;
};
contactRequestList: ContactRequest[];
messageList: MessageList;
conversationList: {
[key: string]: Conversation;
};
lastIds: {
[key: string]: string;
};
}

const initialState: MessageState = {
isWeshConnected: false,
contactInfo: {
name: "Anon",
avatar: "",
publicRendezvousSeed: "",
shareLink: "",
},
messageList: {},
contactRequestList: [],
conversationList: {},
lastIds: {},
peerList: [],
};

export const selectIsWeshConnected = (state: RootState) =>
state.message.isWeshConnected;

export const selectContactInfo = (state: RootState) =>
state.message.contactInfo;

export const selectMessageList = (groupPk: string) => (state: RootState) =>
state.message.messageList[groupPk] || [];

export const selectPeerList = (state: RootState) => state.message.peerList;

export const selectPeerListById = (id: string) => (state: RootState) =>
state.message.peerList.find((item) => item.id === id);

export const selectLastIdByKey = (key: string) => (state: RootState) =>
state.message.lastIds[key];

export const selectMessageListByGroupPk =
(groupPk: string) =>
(state: RootState): Message[] =>
Object.values(state.message.messageList[groupPk] || {})
.filter((item) => item.id)
.sort(
(a: Message, b: Message) =>
moment(b.timestamp).valueOf() - moment(a.timestamp).valueOf(),
);

export const selectLastMessageByGroupPk =
(groupPk: string) => (state: RootState) =>
selectMessageListByGroupPk(groupPk)(state)[0];

export const selectLastContactMessageByGroupPk =
(groupPk: string) => (state: RootState) =>
selectMessageListByGroupPk(groupPk)(state).filter(
(item) =>
item.senderId !== stringFromBytes(weshConfig?.config?.accountPk),
)[0];

export const selectContactRequestList = (state: RootState) =>
state.message.contactRequestList;

export const selectConversationList =
(conversationType: CONVERSATION_TYPES = CONVERSATION_TYPES.ACTIVE) =>
(state: RootState): Conversation[] => {
switch (conversationType) {
case CONVERSATION_TYPES.ALL: {
return Object.values(state.message.conversationList);
}
case CONVERSATION_TYPES.ARCHIVED: {
return Object.values(state.message.conversationList).filter(
(conv) => conv.status === "archived",
);
}
case CONVERSATION_TYPES.ACTIVE:
default:
return Object.values(state.message.conversationList).filter(
(conv) => conv.status === "active",
);
}
};

export const selectConversationById =
(id: string) =>
(state: RootState): Conversation =>
state.message.conversationList[id];

const messageSlice = createSlice({
name: "message",
initialState,
reducers: {
setIsWeshConnected: (state, action: PayloadAction<boolean>) => {
state.isWeshConnected = action.payload;
},
setMessageList: (
state,
action: PayloadAction<{ groupPk: string; data: Message }>,
) => {
if (!state.messageList[action.payload.groupPk]) {
state.messageList[action.payload.groupPk] = {};
}
state.messageList[action.payload.groupPk][action.payload.data.id] =
action.payload.data;
},
setPeerList: (state, action: PayloadAction<PeerItem[]>) => {
state.peerList = action.payload;
},
updateMessageReaction: (
state,
action: PayloadAction<{ groupPk: string; data: Message }>,
) => {
if (action.payload.data.parentId) {
try {
state.messageList[action.payload.groupPk][
action.payload.data?.parentId
].reactions = uniqBy(
[
...(state.messageList[action.payload.groupPk][
action.payload.data.parentId
].reactions || []),
action.payload.data,
],
"id",
);
} catch (err) {
console.error("update reaction failed", err);
}
}
},
setContactRequestList: (
state,
action: PayloadAction<ContactRequest | ContactRequest[]>,
) => {
if (Array.isArray(action.payload)) {
state.contactRequestList = action.payload;
} else {
state.contactRequestList = [
action.payload,
...state.contactRequestList,
];
}
},
setConversationList: (state, action: PayloadAction<Conversation>) => {
state.conversationList[action.payload.id] = action.payload;
},
updateConversationById: (
state,
action: PayloadAction<Partial<Conversation>>,
) => {
if (action.payload.id) {
state.conversationList[action.payload.id] = {
...(state.conversationList[action.payload.id] || {}),
...action.payload,
};
}
},
setLastId: (
state,
action: PayloadAction<{ key: string; value: string }>,
) => {
state.lastIds[action.payload.key] = action.payload.value;
},

setContactInfo: (
state,
action: PayloadAction<Partial<MessageState["contactInfo"]>>,
) => {
state.contactInfo = { ...state.contactInfo, ...action.payload };
},
},
});

export const {
setMessageList,
setContactRequestList,
setConversationList,
updateMessageReaction,
setLastId,
setContactInfo,
updateConversationById,
setPeerList,
setIsWeshConnected,
} = messageSlice.actions;

export const messageReducer = messageSlice.reducer;
2 changes: 2 additions & 0 deletions packages/store/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
marketplaceFilters,
marketplaceFilterUI,
} from "./slices/marketplaceFilters";
import { messageReducer } from "./slices/message";
import { searchReducer } from "./slices/search";
import {
multisigTokensAdapter,
Expand Down Expand Up @@ -79,6 +80,7 @@ const rootReducer = combineReducers({
marketplaceFilters,
marketplaceFilterUI,
search: searchReducer,
message: messageReducer,
});

const persistedReducer = persistReducer(persistConfig, rootReducer);
Expand Down
11 changes: 11 additions & 0 deletions packages/utils/isElectron.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export const isElectron = () => {
try {
const userAgent = navigator.userAgent.toLowerCase();
if (userAgent.indexOf(" electron/") > -1) {
return true;
}
} catch (err) {
console.error("isElectron err", err);
}
return false;
};
98 changes: 98 additions & 0 deletions packages/utils/types/message.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import { RemoteFileData } from "./files";

export type MessageType =
| "message"
| "accept-contact"
| "reject-contact"
| "group-invite"
| "group-join"
| "group-leave"
| "group-create"
| "reaction"
| "contact-request"
| "read";

export type MessageFriendsTabItem = "friends" | "request" | "addFriend";

export type ConversationType = "contact" | "group";

export interface MessageFileData extends RemoteFileData {
type: string;
}

interface MessagePayload {
files: MessageFileData[];
message: string;
metadata?: {
groupName?: string;
group?: any;
contact?: Contact;
lastReadId?: string;
lastReadBy?: string;
};
}

export interface Message {
id: string;
senderId: string;
groupId: string;
type: MessageType;
payload?: MessagePayload;
timestamp: string;
parentId?: string;
reactions?: any[];
isRead?: boolean;
}

export interface Contact {
id: string;
tokenId?: string;
name: string;
avatar: string;
rdvSeed: string;
peerId?: string;
hasLeft?: boolean;
}

export interface Conversation {
id: string;
type: ConversationType;
members: Contact[];
name: string;
status: "active" | "archived" | "deleted" | "blocked";
lastReadIdByMe?: string;
lastReadIdByContact?: string;
}

export interface MessageList {
[key: string]: { [key: string]: Message };
}

export interface ConversationList {
[key: string]: Conversation[];
}

export interface ContactRequest {
id: string;
contactId: string;
rdvSeed: string;
avatar: string;
name: string;
peerId?: string;
}

export interface ReplyTo {
id: string;
message: string;
}

export enum CONVERSATION_TYPES {
ACTIVE = "Active Conversations",
ALL = "All Conversations",
ARCHIVED = "Archived Conversations",
}

export interface PeerItem {
id: string;
isActive: boolean;
}
10 changes: 0 additions & 10 deletions packages/utils/weshnet.ts

This file was deleted.

Loading

0 comments on commit 05248ec

Please sign in to comment.