SyntaxGameServer/RCCService2018/content/internal/Chat/Modules/LuaChat/Reducers/Conversations.lua

248 lines
9.5 KiB
Lua

local CoreGui = game:GetService("CoreGui")
local Modules = CoreGui.RobloxGui.Modules
local Common = Modules.Common
local LuaChat = Modules.LuaChat
local Actions = LuaChat.Actions
local ChangedParticipants = require(Actions.ChangedParticipants)
local FetchedOldestMessage = require(Actions.FetchedOldestMessage)
local FetchingOlderMessages = require(Actions.FetchingOlderMessages)
local MessageFailedToSend = require(Actions.MessageFailedToSend)
local MessageModerated = require(Actions.MessageModerated)
local ReadConversation = require(Actions.ReadConversation)
local ReceivedConversation = require(Actions.ReceivedConversation)
local ReceivedMessages = require(Actions.ReceivedMessages)
local RemovedConversation = require(Actions.RemovedConversation)
local RenamedGroupConversation = require(Actions.RenamedGroupConversation)
local SendingMessage = require(Actions.SendingMessage)
local SentMessage = require(Actions.SentMessage)
local SetConversationLoadingStatus = require(Actions.SetConversationLoadingStatus)
local SetPinnedGameForConversation = require(Actions.SetPinnedGameForConversation)
local SetUserLeavingConversation = require(Actions.SetUserLeavingConversation)
local SetUserTyping = require(Actions.SetUserTyping)
local ConversationModel = require(LuaChat.Models.Conversation)
local Immutable = require(Common.Immutable)
local OrderedMap = require(LuaChat.OrderedMap)
return function(state, action)
state = state or {}
if action.type == ReceivedConversation.name then
local conversation = action.conversation
if conversation.conversationType == ConversationModel.Type.ONE_TO_ONE_CONVERSATION then
local idForFake = ConversationModel.IdForFakeOneOnOne(conversation.participants)
if state[idForFake] ~= nil then
state = Immutable.Set(state, idForFake, nil)
end
end
if not state[conversation.id] then
state = Immutable.Set(state, conversation.id, conversation)
end
elseif action.type == ReceivedMessages.name then
local conversationId = action.conversationId
local conversation = state[conversationId]
if conversation then
local lastMessage = nil
for i = 1, #action.messages do
local message = action.messages[i]
local existing = conversation.messages:Get(message.id)
if existing then
if lastMessage then
lastMessage.previousMessageId = existing.id
end
if message.previousMessageId == nil and existing.previousMessageId ~= nil then
message.previousMessageId = existing.previousMessageId
end
message.read = message.read or existing.read
end
lastMessage = message
end
local messages = OrderedMap.Insert(conversation.messages, unpack(action.messages))
if action.exclusiveStartMessageId and #action.messages > 0 then
if messages:Get(action.exclusiveStartMessageId) then
local prevMessage = action.messages[1]
local nextMessage = messages:Get(action.exclusiveStartMessageId)
nextMessage = Immutable.Set(nextMessage, "previousMessageId", prevMessage.id)
messages = messages:Insert(nextMessage)
end
end
local lastConversationKey = messages.keys[#messages.keys]
lastMessage = messages.values[lastConversationKey]
if lastMessage ~= nil then
local lastUpdatedConvo = conversation.lastUpdated and conversation.lastUpdated:GetUnixTimestamp() or 0
local lastUpdated = (lastMessage.sent:GetUnixTimestamp() > lastUpdatedConvo) and
lastMessage.sent or conversation.lastUpdated
local hasUnreadMessages = action.shouldMarkConversationUnread or conversation.hasUnreadMessages
local newConversation = Immutable.JoinDictionaries(conversation, {
messages = messages;
lastUpdated = lastUpdated;
hasUnreadMessages = hasUnreadMessages;
})
-- Mark all users as no longer typing
-- We should only do this if a specific user sent a message and it's
-- the last message in the list, but that check would be expensive
-- to make every time we request more messages.
-- Notably, this will fail for group conversations.
newConversation = Immutable.Set(newConversation, "usersTyping", {})
state = Immutable.Set(state, newConversation.id, newConversation)
end
end
elseif action.type == SendingMessage.name then
local conversationId = action.conversationId
local conversation = state[conversationId]
if conversation then
local sendingMessages = OrderedMap.Insert(conversation.sendingMessages, action.message)
local newConversation = Immutable.Set(conversation, "sendingMessages", sendingMessages)
state = Immutable.Set(state, newConversation.id, newConversation)
end
elseif action.type == SentMessage.name then
local conversationId = action.conversationId
local conversation = state[conversationId]
if conversation then
local sendingMessages = OrderedMap.Delete(conversation.sendingMessages, action.messageId)
local newConversation = Immutable.Set(conversation, "sendingMessages", sendingMessages)
state = Immutable.Set(state, newConversation.id, newConversation)
end
elseif action.type == RenamedGroupConversation.name then
local conversationId = action.conversationId
local conversation = state[conversationId]
if conversation then
local newConversation = Immutable.JoinDictionaries(conversation, {
lastUpdated = action.lastUpdated,
title = action.title,
isDefaultTitle = action.isDefaultTitle,
})
state = Immutable.Set(state, conversationId, newConversation)
end
elseif action.type == ChangedParticipants.name then
local convoId = action.conversationId
local newParticipants = action.participants
local conversation = state[convoId]
if conversation then
local newConversation = Immutable.JoinDictionaries(conversation, {
participants = newParticipants,
lastUpdated = action.lastUpdated,
title = action.title,
})
state = Immutable.Set(state, convoId, newConversation)
end
elseif action.type == RemovedConversation.name then
local conversationId = action.conversationId
state = Immutable.Set(state, conversationId, nil)
elseif action.type == SetUserTyping.name then
local conversation = state[action.conversationId]
if conversation then
local usersTyping = conversation.usersTyping
local newUsersTyping = Immutable.Set(usersTyping, action.userId, action.value)
local newConversation = Immutable.Set(conversation, "usersTyping", newUsersTyping)
state = Immutable.Set(state, newConversation.id, newConversation)
end
elseif action.type == FetchingOlderMessages.name then
local conversation = state[action.conversationId]
if conversation then
local newConversation = Immutable.Set(conversation, "fetchingOlderMessages", action.fetchingOlderMessages)
state = Immutable.Set(state, newConversation.id, newConversation)
end
elseif action.type == FetchedOldestMessage.name then
local conversation = state[action.conversationId]
local newConversation = Immutable.Set(conversation, "fetchedOldestMessage", action.fetchedOldestMessage)
state = Immutable.Set(state, newConversation.id, newConversation)
elseif action.type == ReadConversation.name then
local conversation = state[action.conversationId]
if not conversation then
warn("Conversation " .. action.conversationId .. " not found in ReadConversation reducer")
return
end
local newMessages = conversation.messages:Map(function(message)
if message.read then
return message
else
return Immutable.Set(message, "read", true)
end
end)
local newConversation = Immutable.Set(conversation, "messages", newMessages)
newConversation = Immutable.Set(newConversation, "hasUnreadMessages", false)
state = Immutable.Set(state, newConversation.id, newConversation)
elseif action.type == MessageModerated.name then
local conversation = state[action.conversationId]
local message = conversation.sendingMessages:Get(action.messageId)
if message then
local newMessage = Immutable.Set(message, "moderated", true)
local newSendingMessages = conversation.sendingMessages:Insert(newMessage)
local newConversation = Immutable.Set(conversation, "sendingMessages", newSendingMessages)
state = Immutable.Set(state, newConversation.id, newConversation)
end
elseif action.type == MessageFailedToSend.name then
local conversation = state[action.conversationId]
local message = conversation.sendingMessages:Get(action.messageId)
if message then
local newMessage = Immutable.Set(message, "failed", true)
local newSendingMessages = conversation.sendingMessages:Insert(newMessage)
local newConversation = Immutable.Set(conversation, "sendingMessages", newSendingMessages)
state = Immutable.Set(state, newConversation.id, newConversation)
end
elseif action.type == SetConversationLoadingStatus.name then
local conversation = state[action.conversationId]
local newConversation = Immutable.Set(conversation, "initialLoadingStatus", action.value)
state = Immutable.Set(state, newConversation.id, newConversation)
elseif action.type == SetUserLeavingConversation.name then
local conversation = state[action.id]
if conversation then
local newConversation = Immutable.Set(conversation, "isUserLeaving", action.isLeaving)
state = Immutable.Set(state, newConversation.id, newConversation)
end
elseif action.type == SetPinnedGameForConversation.name then
local conversationId = action.conversationId
local conversation = state[conversationId]
if conversation then
local newPinnedGame = {
rootPlaceId = action.rootPlaceId;
universeId = action.universeId;
}
local newConversation = Immutable.JoinDictionaries(conversation, {
pinnedGame = newPinnedGame;
})
state = Immutable.Set(state, conversationId, newConversation)
end
end
return state
end