From 298a989cd96220bd8b7423d835c4f4bae4141919 Mon Sep 17 00:00:00 2001 From: talksik Date: Sat, 11 Jun 2022 12:25:41 -0500 Subject: [PATCH] quick dial and creating conversations --- packages/api/routes/conversations.ts | 4 +- packages/desktop/src/api/NirvanaApi.tsx | 4 + .../src/providers/ConversationProvider.tsx | 88 ++++++++++++++++++- .../desktop/src/providers/RouterProvider.tsx | 14 ++- .../src/tree/NewConversationDialog.tsx | 24 ++--- packages/desktop/src/util/types.ts | 2 +- 6 files changed, 111 insertions(+), 25 deletions(-) diff --git a/packages/api/routes/conversations.ts b/packages/api/routes/conversations.ts index fe2723f..f6f7081 100644 --- a/packages/api/routes/conversations.ts +++ b/packages/api/routes/conversations.ts @@ -75,8 +75,8 @@ const getOneOnOneConversationIfExists = async (req: Request, res: Response, next resultConversation?._id ?? undefined, undefined, resultConversation - ? 'no such conversation exists!' - : 'there is a conversation...quick dial them now!', + ? 'there is a conversation...quick dial them now!' + : 'no such conversation exists!', ), ); } catch (error) { diff --git a/packages/desktop/src/api/NirvanaApi.tsx b/packages/desktop/src/api/NirvanaApi.tsx index b8aa4eb..b41626a 100644 --- a/packages/desktop/src/api/NirvanaApi.tsx +++ b/packages/desktop/src/api/NirvanaApi.tsx @@ -85,3 +85,7 @@ export async function createConversation( export async function getConversations(): Promise> { return await NirvanaApi.fetch(`/conversations`, 'GET', true); } + +export async function checkIfOnOnOneExists(otherUserId: string): Promise> { + return await NirvanaApi.fetch(`/conversations/check/${otherUserId}`, 'GET', true); +} diff --git a/packages/desktop/src/providers/ConversationProvider.tsx b/packages/desktop/src/providers/ConversationProvider.tsx index 59e3eba..ed82eec 100644 --- a/packages/desktop/src/providers/ConversationProvider.tsx +++ b/packages/desktop/src/providers/ConversationProvider.tsx @@ -1,14 +1,22 @@ -import React, { useEffect } from 'react'; +import React, { useCallback, useEffect, useState } from 'react'; +import { checkIfOnOnOneExists, createConversation, getConversations } from '../api/NirvanaApi'; import Conversation from '@nirvana/core/models/conversation.model'; import { ConversationMap } from '../util/types'; +import CreateConversationRequest from '@nirvana/core/requests/CreateConversationRequest.request'; import { Typography } from '@mui/material'; -import { getConversations } from '../api/NirvanaApi'; +import User from '@nirvana/core/models/user.model'; +import { toast } from 'react-toastify'; import { useAsyncFn } from 'react-use'; import { useImmer } from 'use-immer'; interface IConversationContext { conversations: ConversationMap; + + selectedConversation?: Conversation; + // handleSetConversation?: (conversationId: string) => void; + + handleStartConversation?: (otherUsers: User[]) => void; } const ConversationContext = React.createContext({ @@ -22,6 +30,8 @@ export function ConversationProvider({ children }: { children: React.ReactNode } // the map that we manage throughout the app const [conversationMap, setConversationMap] = useImmer({}); + const [selectedConversation, setSelectedConversation] = useState(undefined); + useEffect(() => { doFetch(); }, [doFetch]); @@ -42,6 +52,76 @@ export function ConversationProvider({ children }: { children: React.ReactNode } } }, [fetchState.value, setConversationMap]); + /** + * temporaryOverrideSort: tell me if you want to temporarily prioritize this conversation above all others + */ + const selectConversation = useCallback( + (conversationId: string, temporaryOverrideSort = false) => { + /** + * see if there is such a conversation in our map + * if not, then go and fetch it from backend + * set the temporary sort accordingly + */ + + const allConversationIds = Object.keys(conversationMap); + + if (allConversationIds.includes(conversationId)) { + toast.success('we have that conversation!!!'); + + setSelectedConversation(conversationMap[conversationId]); + } + }, + [conversationMap, setSelectedConversation], + ); + + const handleStartConversation = useCallback( + async (otherUsers: User[]) => { + try { + /** group conversation + * 1. create it + * 2. select the conversation based on the id + * + * one on one: + * 1. hit backend to see if we already have a conversation with them + * 2. if so, then go and select it with priority sort flag + * 3. if not, then go ahead and create + * 4. use the conversation id to select it + */ + + if (!otherUsers || otherUsers.length === 0) { + toast.error('Must provider users'); + return; + } + + // todo: check to make sure that the other user is not the user himself, although backend should error out + + if (otherUsers.length === 1) { + const conversationDmCheck = await checkIfOnOnOneExists(otherUsers[0]._id.toString()); + + // if we found a conversation + if (conversationDmCheck.data) { + toast.success('already have this user...quick dialing'); + + selectConversation(conversationDmCheck.data, true); + return; + } + } + + const createdConversationResult = await createConversation( + new CreateConversationRequest(otherUsers), + ); + + selectConversation(createdConversationResult.data.conversationId.toString()); + + toast.success('started conversation'); + } catch (error) { + console.error(error); + toast.error(error.message); + } + }, + [conversationMap, selectConversation], + ); + // todo: open up a handler for children // to refetch or search for a particular conversation and add it to the list of conversations @@ -56,7 +136,9 @@ export function ConversationProvider({ children }: { children: React.ReactNode } } return ( - + {children} ); diff --git a/packages/desktop/src/providers/RouterProvider.tsx b/packages/desktop/src/providers/RouterProvider.tsx index 7243287..b203925 100644 --- a/packages/desktop/src/providers/RouterProvider.tsx +++ b/packages/desktop/src/providers/RouterProvider.tsx @@ -1,11 +1,13 @@ // make do router given absense of react router in desktop apps -import React, { useCallback, useState } from 'react'; +import React, { useCallback, useEffect, useState } from 'react'; + +import useConversations from './ConversationProvider'; type TPage = | 'START_NEW_CONVERSATION' | 'FULL_PAGE_OMNI_SEARCH' - | 'CONVERSATION_DETAILS' + | 'SELECTED_CONVERSATION' | 'PROFILE' | 'WELCOME'; @@ -21,6 +23,14 @@ const RouterContext = React.createContext({ export function RouterProvider({ children }: { children: React.ReactNode }) { const [page, setPage] = useState('WELCOME'); + const { selectedConversation } = useConversations(); + + useEffect(() => { + if (selectedConversation) { + setPage('SELECTED_CONVERSATION'); + } + }, [setPage, selectedConversation]); + const handleSetPage = useCallback((newPage: TPage) => () => setPage(newPage), [setPage]); return ( diff --git a/packages/desktop/src/tree/NewConversationDialog.tsx b/packages/desktop/src/tree/NewConversationDialog.tsx index 566696d..736433e 100644 --- a/packages/desktop/src/tree/NewConversationDialog.tsx +++ b/packages/desktop/src/tree/NewConversationDialog.tsx @@ -29,6 +29,7 @@ import { blueGrey } from '@mui/material/colors'; import { createConversation } from '../api/NirvanaApi'; import toast from 'react-hot-toast'; import useAuth from '../providers/AuthProvider'; +import useConversations from '../providers/ConversationProvider'; import useRouter from '../providers/RouterProvider'; import useSearch from '../providers/SearchProvider'; @@ -81,6 +82,8 @@ export default function NewConversationDialog() { const [isSubmitting, setIsSubmitting] = useState(false); + const { handleStartConversation } = useConversations(); + const handleSubmit = useCallback(async () => { if (selectedUsers.length === 0) { toast.error('Must select a person!'); @@ -94,24 +97,11 @@ export default function NewConversationDialog() { setIsSubmitting(true); - try { - // if it's just one other person, then call quick dial master function which would do all of the checking + handleStartConversation(selectedUsers); - // if more than one person, then just create conversation - - const createResult = await createConversation( - new CreateConversationRequest(selectedUsers, conversationName), - ); - - // clear form for next time - setSelectedUsers([]); - setConversationName(''); - - // todo: select conversation Id that was created - } catch (error) { - console.error(error); - toast.error(error.message); - } + // clear form for next time + setSelectedUsers([]); + setConversationName(''); setIsSubmitting(false); }, [selectedUsers, setConversationName, conversationName, setSelectedUsers, setIsSubmitting]); diff --git a/packages/desktop/src/util/types.ts b/packages/desktop/src/util/types.ts index c816425..f87d772 100644 --- a/packages/desktop/src/util/types.ts +++ b/packages/desktop/src/util/types.ts @@ -9,7 +9,7 @@ export type ConversationMap = { // allows client side to have this pushed up in the list and can uncheck it once user is done with this // if action is take, normal ordering should take place with database upserts - temporaryInboxTop?: boolean; + temporaryOverrideSort?: boolean; }; };