From 9a82b249ac96558342043dfe39ffdba8ec0e369a Mon Sep 17 00:00:00 2001 From: Arjun Patel Date: Sat, 5 Feb 2022 20:04:13 -0800 Subject: [PATCH] sending message nicely --- packages/common/models/conversation.ts | 8 +-- ...rageService.tsx => cloudStorageService.ts} | 0 packages/common/services/collections.ts | 1 + .../common/services/conversationService.ts | 51 ++++++++++++++++++- packages/common/services/index.ts | 3 ++ .../components/MainTabsOrPages/Priority.tsx | 28 +++++++++- 6 files changed, 83 insertions(+), 8 deletions(-) rename packages/common/services/{cloudStorageService.tsx => cloudStorageService.ts} (100%) diff --git a/packages/common/models/conversation.ts b/packages/common/models/conversation.ts index 7002c31..a7c79b3 100644 --- a/packages/common/models/conversation.ts +++ b/packages/common/models/conversation.ts @@ -11,9 +11,9 @@ export default class Conversation { activeMembers: string[]; // userIds membersInLiveRoom: string[] = [] as string[]; // all members in a live call right now for this convo - cachedAudioClips: AudioClip[] = [] as AudioClip[]; - cachedDrawerItems: Link[] = [] as Link[]; - tldrClips: AudioClip[] = [] as AudioClip[]; + cachedAudioClip?: AudioClip; // last message pretty much + cachedDrawerItem?: Link; // last link pretty much + cachedTldrClip?: string; createdDate: Timestamp = Timestamp.now(); createdByUserId: string; @@ -68,7 +68,7 @@ export enum ConversationMemberState { export class AudioClip { id: string = uuid(); - audioDataUrl: string; + audioDataUrl?: string; senderUserId: string; createdDate: Timestamp = Timestamp.now(); diff --git a/packages/common/services/cloudStorageService.tsx b/packages/common/services/cloudStorageService.ts similarity index 100% rename from packages/common/services/cloudStorageService.tsx rename to packages/common/services/cloudStorageService.ts diff --git a/packages/common/services/collections.ts b/packages/common/services/collections.ts index 95b5915..46c4329 100644 --- a/packages/common/services/collections.ts +++ b/packages/common/services/collections.ts @@ -14,6 +14,7 @@ enum Collections { // v2 conversations = "conversations", conversationMembers = "members", + conversationAudioClips = "audioClips", } export default Collections; diff --git a/packages/common/services/conversationService.ts b/packages/common/services/conversationService.ts index fd35732..e05859c 100644 --- a/packages/common/services/conversationService.ts +++ b/packages/common/services/conversationService.ts @@ -9,9 +9,13 @@ import { runTransaction, writeBatch, } from "firebase/firestore"; -import Conversation, { ConversationMember } from "../models/conversation"; +import Conversation, { + AudioClip, + ConversationMember, + ConversationMemberState, +} from "../models/conversation"; import Collections from "./collections"; -import { ConversationMemberState } from "../models/conversation"; +import { cloudStorageService } from "./index"; export default class ConversationService { private db: Firestore = getFirestore(); @@ -103,4 +107,47 @@ export default class ConversationService { await setDoc(docRef, newUpdates, { merge: true }); } + + async sendAudioClip( + createdByUserId: string, + audioMp3File: File, + convoId: string + ) { + // upload to cloud storage + const downloadUrl = await cloudStorageService.uploadMessageAudioFile( + audioMp3File + ); + const newAudioClip = new AudioClip(downloadUrl, createdByUserId); + newAudioClip.audioDataUrl = downloadUrl; + + const audioClipRef = doc( + this.db, + Collections.conversations, + convoId, + Collections.conversationAudioClips, + newAudioClip.id + ); + + const conversationDoc = doc(this.db, Collections.conversations, convoId); + + await runTransaction(this.db, async (transaction) => { + // want to add to the long term collection of all audio clips for a conversation + transaction.set( + audioClipRef, + { ...newAudioClip, createdDate: serverTimestamp() }, + { merge: true } + ); + + // want to make updates to the conversation document itself: set the last item for just the basic information to be + // published to users + transaction.set( + conversationDoc, + { + lastActivityDate: serverTimestamp(), + cachedAudioClip: { ...newAudioClip, createdDate: serverTimestamp() }, + }, + { merge: true } + ); + }); + } } diff --git a/packages/common/services/index.ts b/packages/common/services/index.ts index 2903234..9f0bcf8 100644 --- a/packages/common/services/index.ts +++ b/packages/common/services/index.ts @@ -1,6 +1,9 @@ +import CloudStorageService from "./cloudStorageService"; import ConversationService from "./conversationService"; import UserService from "./userService"; export const conversationService = new ConversationService(); export const userService = new UserService(); + +export const cloudStorageService = new CloudStorageService(); diff --git a/packages/web/components/MainTabsOrPages/Priority.tsx b/packages/web/components/MainTabsOrPages/Priority.tsx index 65b1469..2cc698d 100644 --- a/packages/web/components/MainTabsOrPages/Priority.tsx +++ b/packages/web/components/MainTabsOrPages/Priority.tsx @@ -20,6 +20,9 @@ import { useEffect, useState } from "react"; import toast from "react-hot-toast"; import MicRecorder from "mic-recorder-to-mp3"; import { v4 as uuidv4 } from "uuid"; +import { conversationService } from "../../../common/services/index"; +import { AudioClip } from "@nirvana/common/models/conversation"; +import { useAuth } from "../../contexts/authContext"; // New instance const recorder = new MicRecorder({ @@ -29,12 +32,14 @@ const recorder = new MicRecorder({ const MAX_SHORTCUT_MAPPINGS_PRIORITY = 8; export default function Priority() { + const { currUser } = useAuth(); + const priorityConvos = useRecoilValue(priorityConvosSelector); const [mapShortcutsToConvoId, setmapShortcutsToConvoId] = useState< Map >(new Map()); - const setSelectedConversationId = useSetRecoilState( + const [selectedConvoId, setSelectedConversationId] = useRecoilState( selectedPriorityConvoAtom ); @@ -110,6 +115,10 @@ export default function Priority() { const startRecording = () => { // check if there is a person selected + if (!selectedConvoId) { + toast.error("You must select a person first!"); + return; + } // check that we have mic permissions if (!hasMicPermissions) { @@ -149,10 +158,15 @@ export default function Priority() { setIsRecording(false); + if (!selectedConvoId) { + toast.error("problem in sending clip"); + return; + } + recorder .stop() .getMp3() - .then(([buffer, blob]) => { + .then(async ([buffer, blob]) => { const blobURL = URL.createObjectURL(blob); const file = new File(buffer, uuidv4() + ".mp3", { @@ -163,6 +177,16 @@ export default function Priority() { const player = new Audio(URL.createObjectURL(file)); // player.onended = onEndedPlaying; player.play(); + + // send to service which handles the upload to blob and also the conversation database + await conversationService.sendAudioClip( + currUser!.uid, + file, + selectedConvoId + ); + + console.log("successfully sent audio clip"); + toast.success("successfully sent audio clip"); }) .catch((error) => { console.log(error);