diff --git a/packages/common/models/conversation.ts b/packages/common/models/conversation.ts index 13c0135..9ca861f 100644 --- a/packages/common/models/conversation.ts +++ b/packages/common/models/conversation.ts @@ -43,6 +43,7 @@ export class ConversationMember { createdDate: Timestamp = Timestamp.now(); lastUpdatedDate?: Timestamp; + lastInteractionDate?: Timestamp; constructor( _userId: string, diff --git a/packages/common/services/collections.tsx b/packages/common/services/collections.ts similarity index 66% rename from packages/common/services/collections.tsx rename to packages/common/services/collections.ts index ff4015a..95b5915 100644 --- a/packages/common/services/collections.tsx +++ b/packages/common/services/collections.ts @@ -1,4 +1,4 @@ -export enum Collections { +enum Collections { users = "users", teams = "teams", teamMembers = "teamMembers", @@ -10,4 +10,10 @@ export enum Collections { links = "links", officeRooms = "officeRooms", + + // v2 + conversations = "conversations", + conversationMembers = "members", } + +export default Collections; diff --git a/packages/common/services/conversationService.ts b/packages/common/services/conversationService.ts new file mode 100644 index 0000000..d27c608 --- /dev/null +++ b/packages/common/services/conversationService.ts @@ -0,0 +1,74 @@ +import { + addDoc, + collection, + doc, + Firestore, + getFirestore, + serverTimestamp, + setDoc, + runTransaction, + writeBatch, +} from "firebase/firestore"; +import Conversation, { ConversationMember } from "../models/conversation"; +import Collections from "./collections"; + +export default class ConversationService { + private db: Firestore = getFirestore(); + + async test() { + const docRef = doc(this.db, "test", "test"); + await setDoc( + docRef, + { hi: " hiii", lastUpdatedDate: serverTimestamp() }, + { merge: true } + ); + } + + async createConversation( + conversation: Conversation, + members: ConversationMember[] + ) { + try { + const newConvoRef = doc( + this.db, + Collections.conversations, + conversation.id + ); + + const newConvo = await runTransaction(this.db, async (transaction) => { + transaction.set( + newConvoRef, + { + ...conversation, + createdDate: serverTimestamp(), + }, + { merge: true } + ); + + return newConvoRef; + }); + + const batch = writeBatch(this.db); + + members.forEach((mem) => { + const newMemberRef = doc( + this.db, + Collections.conversations, + newConvo.id, + Collections.conversationMembers, + mem.id + ); + batch.set(newMemberRef, { ...mem, createdDate: serverTimestamp() }); + }); + + await batch.commit(); + + console.log( + "submitted batch write for each new member of this conversation" + ); + } catch (e) { + console.error(e); + throw new Error("Problem in creating conversation"); + } + } +} diff --git a/packages/common/services/index.ts b/packages/common/services/index.ts new file mode 100644 index 0000000..ebc8496 --- /dev/null +++ b/packages/common/services/index.ts @@ -0,0 +1,3 @@ +import ConversationService from "./conversationService"; + +export const conversationService = new ConversationService(); diff --git a/packages/web/components/FullPageExperiences/CreateConversation.tsx.tsx b/packages/web/components/FullPageExperiences/CreateConversation.tsx.tsx index f57d2fa..bc54f04 100644 --- a/packages/web/components/FullPageExperiences/CreateConversation.tsx.tsx +++ b/packages/web/components/FullPageExperiences/CreateConversation.tsx.tsx @@ -1,18 +1,30 @@ -import { User, UserStatus } from "@nirvana/common/models/user"; -import { Divider, Select, Tag } from "antd"; -import { ChangeEvent, useEffect, useMemo, useRef, useState } from "react"; +import { User } from "@nirvana/common/models/user"; +import { useEffect, useMemo, useRef, useState } from "react"; import { FaPlus, FaRegTimesCircle, FaSearch } from "react-icons/fa"; -import searchClient, { usersIndex } from "../../services/algoliaSearchService"; +import { usersIndex } from "../../services/algoliaSearchService"; import SimpleLoadingDot from "../Loading/SimpleLoadingDot"; import SimpleUserDetailsRow from "../UserDetails/SimpleUserDetailsRow"; import { debounce } from "lodash"; import toast from "react-hot-toast"; import { SearchResponse } from "@algolia/client-search"; +import Conversation, { + ConversationMember, + ConversationMemberRole, + ConversationMemberState, +} from "@nirvana/common/models/conversation"; +import { useAuth } from "../../contexts/authContext"; +import { conversationService } from "@nirvana/common/services"; +import { QueryRoutes, Routes } from "@nirvana/common/helpers/routes"; +import { useRouter } from "next/router"; const searchDebounceMsTime = 3000; export default function CreateConversation() { + const { currUser } = useAuth(); + const router = useRouter(); + const input = useRef(); + const [selectedUsers, setSelectedUsers] = useState([] as User[]); const [isLoading, setIsLoading] = useState(false); const [userSearchInput, setUserSearchInput] = useState(""); @@ -79,6 +91,10 @@ export default function CreateConversation() { }, []); const selectUser = (addUser: User) => { + if (addUser.id == currUser.uid) { + toast.error("You cannot add yourself, silly!"); + return; + } if (selectedUsers.some((currUser) => currUser.id == addUser.id)) { toast("Already added member!"); return; @@ -104,27 +120,59 @@ export default function CreateConversation() { const [isSubmitting, setIsSubmitting] = useState(false); - const createConversation = (e) => { + const createConversation = async (e) => { e.preventDefault(); setIsSubmitting(true); if (!conversationName) { toast.error("Please put in a conversation name"); + setIsSubmitting(false); return; } if (!selectedUsers?.length) { toast.error("You must select members!"); + setIsSubmitting(false); return; } try { - console.log("created conversation in database"); + const newConversation = new Conversation(currUser.uid, conversationName); + + // create each conversation member based on the selected people + const members = selectedUsers.map((selUser) => { + return new ConversationMember( + selUser.id, + ConversationMemberState.default, + ConversationMemberRole.member + ); + }); + // add myself to this collection of members + members.push( + new ConversationMember( + currUser.uid, + ConversationMemberState.default, + ConversationMemberRole.admin + ) + ); + + console.log(members); + console.log(newConversation); + + // create main conversation object and all of the members associated + await conversationService.createConversation(newConversation, members); + + toast.success("Created Conversation"); + + // router.push({ + // pathname: Routes.home, + // query: { page: QueryRoutes.convos }, + // }); } catch (error) { - toast.error("Problem in creating issue"); + toast.error("Problem in creating conversation"); } - // setIsSubmitting(false); + setIsSubmitting(false); }; return (