From 50193c5df648c219f4d8fec2c275cacde94b8fb7 Mon Sep 17 00:00:00 2001 From: talksik Date: Sat, 28 May 2022 15:30:11 -0500 Subject: [PATCH] adding more logic for creating a conversation --- .../core/src/models/conversation.model.ts | 25 ++++---- packages/core/src/models/user.model.ts | 1 + packages/desktop/package.json | 4 +- .../desktop/src/components/Conversations.tsx | 11 +++- packages/desktop/src/components/Terminal.tsx | 55 ++++++++++++++++- packages/desktop/src/firebase/firestore.ts | 59 +++++++++++++++++-- yarn.lock | 5 ++ 7 files changed, 137 insertions(+), 23 deletions(-) diff --git a/packages/core/src/models/conversation.model.ts b/packages/core/src/models/conversation.model.ts index 79bb314..3b2e505 100644 --- a/packages/core/src/models/conversation.model.ts +++ b/packages/core/src/models/conversation.model.ts @@ -1,11 +1,14 @@ import { FieldValue, serverTimestamp, Timestamp } from 'firebase/firestore'; export default class Conversation { - constructor( - public id: string, - public name: string, + id: string; + constructor( public createdByUserId: string, + public membersList: string[], + + public name?: string, + public lastUpdatedDate = Timestamp.now(), public createdDate = Timestamp.now(), @@ -14,11 +17,11 @@ export default class Conversation { ) {} } -export class Member { - constructor( - public id: string, - public userId: string, - public role: 'admin' | 'regular', - public joinedDate = Timestamp.now(), - ) {} -} +// export class Member { +// constructor( +// public id: string, +// public userId: string, +// public role: 'admin' | 'regular', +// public joinedDate = Timestamp.now(), +// ) {} +// } diff --git a/packages/core/src/models/user.model.ts b/packages/core/src/models/user.model.ts index da58c6b..a71b41a 100644 --- a/packages/core/src/models/user.model.ts +++ b/packages/core/src/models/user.model.ts @@ -1,6 +1,7 @@ import { Timestamp } from 'firebase/firestore'; export class User { + id: string; lastUpdatedDate?: Timestamp; constructor( diff --git a/packages/desktop/package.json b/packages/desktop/package.json index 0d94004..b221b17 100644 --- a/packages/desktop/package.json +++ b/packages/desktop/package.json @@ -73,6 +73,7 @@ "@electron-forge/maker-squirrel": "^6.0.0-beta.63", "@electron-forge/maker-zip": "^6.0.0-beta.63", "@electron-forge/plugin-webpack": "6.0.0-beta.63", + "@nirvana/core": "*", "@types/react": "^18.0.9", "@types/react-dom": "^18.0.5", "@typescript-eslint/eslint-plugin": "^5.0.0", @@ -89,8 +90,7 @@ "node-loader": "^2.0.0", "style-loader": "^3.0.0", "ts-loader": "^9.2.2", - "typescript": "~4.5.4", - "@nirvana/core": "*" + "typescript": "~4.5.4" }, "dependencies": { "@emotion/react": "^11.9.0", diff --git a/packages/desktop/src/components/Conversations.tsx b/packages/desktop/src/components/Conversations.tsx index 073cd3e..f557634 100644 --- a/packages/desktop/src/components/Conversations.tsx +++ b/packages/desktop/src/components/Conversations.tsx @@ -17,9 +17,10 @@ import { IconButton, Box, Tooltip, + ListItemSecondaryAction, } from '@mui/material'; import { blueGrey } from '@mui/material/colors'; -import { FiActivity, FiInbox, FiSearch, FiUsers } from 'react-icons/fi'; +import { FiActivity, FiInbox, FiSearch, FiUsers, FiCoffee } from 'react-icons/fi'; import NirvanaAvatar from './NirvanaAvatar'; import { useDebounce, useKey } from 'react-use'; import { useSnackbar } from 'notistack'; @@ -114,6 +115,8 @@ const Conversations = () => { }; function ListPeople({ people }: { people: User[] }) { + const { handleQuickDial } = useTerminal(); + return ( ( - + handleQuickDial(person.uid)}> - 20 sec + + + ))} diff --git a/packages/desktop/src/components/Terminal.tsx b/packages/desktop/src/components/Terminal.tsx index 11671a9..5bd9e43 100644 --- a/packages/desktop/src/components/Terminal.tsx +++ b/packages/desktop/src/components/Terminal.tsx @@ -1,4 +1,4 @@ -import React, { useContext, useState } from 'react'; +import React, { useContext, useState, useCallback, useMemo } from 'react'; import { Container } from '@mui/system'; import { Avatar, Box, Fab, Grid, IconButton, Paper, Stack, Typography } from '@mui/material'; @@ -9,10 +9,14 @@ import { useSnackbar } from 'notistack'; import Conversations from './Conversations'; import Navbar from './Navbar'; import Conversation from '@nirvana/core/src/models/conversation.model'; +import useAuth from '../providers/AuthProvider'; +import { createOneOnOneConversation } from '../firebase/firestore'; interface ITerminalContext { conversations: Conversation[]; - selectedConversation?: string; + selectedConversation?: Conversation; + + handleQuickDial?: (otherUserId: string) => void; } const TerminalContext = React.createContext({ @@ -37,11 +41,56 @@ const TerminalContext = React.createContext({ export function TerminalProvider({ children }: { children?: React.ReactNode }) { const { enqueueSnackbar } = useSnackbar(); + const { user } = useAuth(); + + const [selectedConversationId, setSelectedConversationId] = useState(undefined); const [conversations, setConversations] = useState([]); + // cache of selected conversation + + const selectedConversation: Conversation | undefined = useMemo(() => { + // get conversation if not here + // select if we do have it + + return undefined; + }, [selectedConversationId]); + + // handle create or open existing conversation + // not 100% consistent to the second, but still works...don't need atomicity + const handleQuickDial = useCallback( + async (otherUserId: string) => { + try { + // check all current conversations which should be live listened to + + // if there is already a convo with exactly me and him, then select it + const findExistingConversation = conversations.find((convo) => { + if ( + convo.membersInRoom?.length === 2 && + convo.membersInRoom.includes(user.uid) && + convo.membersInRoom.includes(otherUserId) + ) { + return true; + } + return false; + }); + + if (findExistingConversation) { + setSelectedConversationId(findExistingConversation.id); + return; + } + + // create conversation in this case + await createOneOnOneConversation(otherUserId, user.uid); + } catch (error) { + enqueueSnackbar('Something went wrong, please try again', { variant: 'error' }); + } + }, + [conversations, enqueueSnackbar, user], + ); + return ( - + () => ({ +const converter = () => ({ toFirestore: (data: T) => ({ ...data }), - fromFirestore: (snap: QueryDocumentSnapshot) => snap.data() as T, + fromFirestore: (snap: QueryDocumentSnapshot) => { + const data = snap.data() as T; + + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + data.id = snap.id; + + return data; + }, }); -const docPoint = (collectionPath: string) => +const docPoint = (collectionPath: string) => firestoreDb && doc(getFirestore(), collectionPath).withConverter(converter()); -const collectionPoint = (collectionPath: string) => +const collectionPoint = (collectionPath: string) => firestoreDb && collection(getFirestore(), collectionPath).withConverter(converter()); const db = { users: collectionPoint(`users`), user: (userId: string) => docPoint(`users/${userId}`), + conversations: collectionPoint(`conversations`), + conversation: (conversationId: string) => docPoint(`conversations/${conversationId}`), }; // enum COLLECTION { @@ -97,3 +111,40 @@ export const searchUsers = async (searchQuery: string): Promise => { + const conversation = new Conversation(myUserId, [myUserId, otherUserId]); + + try { + await setDoc( + db.conversations(user.uid), + new User( + user.uid, + user.providerId, + user.email, + user.displayName, + user.photoURL, + user.phoneNumber, + ), + { merge: true }, + ); + } catch (e) { + console.error('Error creating user: ', e); + + throw new Error('Error creating user'); + } + return ''; + + // const docRef = + // const docSnap = await getDoc(docRef); + + // if (docSnap.exists()) { + // console.log("Document data:", docSnap.data()); + // } else { + // // doc.data() will be undefined in this case + // console.log("No such document!"); + // } +}; diff --git a/yarn.lock b/yarn.lock index d4b9aa5..3b54266 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1389,6 +1389,11 @@ dependencies: "@types/node" "*" +"@types/uuid@^8.3.4": + version "8.3.4" + resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-8.3.4.tgz#bd86a43617df0594787d38b735f55c805becf1bc" + integrity sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw== + "@types/ws@^8.5.1": version "8.5.3" resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.5.3.tgz#7d25a1ffbecd3c4f2d35068d0b283c037003274d"