This commit is contained in:
lx
2026-07-06 14:01:11 -04:00
commit c4f97d729d
16468 changed files with 935321 additions and 0 deletions
@@ -0,0 +1,14 @@
local CoreGui = game:GetService("CoreGui")
local Modules = CoreGui.RobloxGui.Modules
local SetActiveConversationId = require(Modules.LuaChat.Actions.SetActiveConversationId)
return function(state, action)
state = state or {}
if action.type == SetActiveConversationId.name then
return action.conversationId
end
return state
end
@@ -0,0 +1,14 @@
local CoreGui = game:GetService("CoreGui")
local Modules = CoreGui.RobloxGui.Modules
local SetAppLoaded = require(Modules.LuaChat.Actions.SetAppLoaded)
return function(state, action)
state = state or false
if action.type == SetAppLoaded.name then
return action.value
end
return state
end
@@ -0,0 +1,26 @@
return function()
local CoreGui = game:GetService("CoreGui")
local Modules = CoreGui.RobloxGui.Modules
local LuaChat = Modules.LuaChat
local SetAppLoaded = require(LuaChat.Actions.SetAppLoaded)
local AppLoaded = require(script.Parent.AppLoaded)
describe("Action AppLoaded", function()
it("should be unloaded by default", function()
local state = AppLoaded(nil, {})
expect(state).to.equal(false)
end)
it("should be changed using SetAppLoaded", function()
local state = AppLoaded(nil, {})
state = AppLoaded(state, SetAppLoaded(false))
expect(state).to.equal(false)
state = AppLoaded(state, SetAppLoaded(true))
expect(state).to.equal(true)
end)
end)
end
@@ -0,0 +1,38 @@
local CoreGui = game:GetService("CoreGui")
local Modules = CoreGui.RobloxGui.Modules
local Common = Modules.Common
local LuaChat = Modules.LuaChat
local DeleteAlert = require(LuaChat.Actions.DeleteAlert)
local ShowAlert = require(LuaChat.Actions.ShowAlert)
local Immutable = require(Common.Immutable)
local OrderedMap = require(LuaChat.OrderedMap)
local function getAlertId(alert)
return alert.id
end
local function alertSortPredicate(alert1, alert2)
return alert1.createdAt < alert2.createdAt
end
return function(state, action)
state = state or {}
if action.type == ShowAlert.name then
local alert = action.alert
local alerts = state["alerts"] or OrderedMap.new(getAlertId, alertSortPredicate)
alerts = OrderedMap.Insert(alerts, alert)
state = Immutable.Set(state, "alerts", alerts)
elseif action.type == DeleteAlert.name then
local alert = action.alert
local alerts = state["alerts"] or OrderedMap.new(getAlertId, alertSortPredicate)
alerts = OrderedMap.Delete(alerts, alert.id)
state = Immutable.Set(state, "alerts", alerts)
end
return state
end
@@ -0,0 +1,14 @@
local CoreGui = game:GetService("CoreGui")
local Modules = CoreGui.RobloxGui.Modules
local SetChatEnabled = require(Modules.LuaChat.Actions.SetChatEnabled)
return function(state, action)
state = (state == nil) and true or state
if action.type == SetChatEnabled.name then
return action.value
end
return state
end
@@ -0,0 +1,26 @@
return function()
local CoreGui = game:GetService("CoreGui")
local Modules = CoreGui.RobloxGui.Modules
local LuaChat = Modules.LuaChat
local SetChatEnabled = require(LuaChat.Actions.SetChatEnabled)
local ChatEnabled = require(script.Parent.ChatEnabled)
it("should be enabled by default", function()
local state = ChatEnabled(nil, {})
expect(state).to.equal(true)
end)
it("should be changed using SetChatEnabled", function()
local state = ChatEnabled(nil, {})
state = ChatEnabled(state, SetChatEnabled(false))
expect(state).to.equal(false)
state = ChatEnabled(state, SetChatEnabled(true))
expect(state).to.equal(true)
end)
end
@@ -0,0 +1,30 @@
local CoreGui = game:GetService("CoreGui")
local CorePackages = game:GetService("CorePackages")
local LuaChat = CoreGui.RobloxGui.Modules.LuaChat
local Immutable = require(CorePackages.AppTempCommon.Common.Immutable)
local RetrievalStatus = require(CorePackages.AppTempCommon.LuaApp.Enum.RetrievalStatus)
local FetchChatSettingsStarted = require(LuaChat.Actions.FetchChatSettingsStarted)
local FetchChatSettingsCompleted = require(LuaChat.Actions.FetchChatSettingsCompleted)
local FetchChatSettingsFailed = require(LuaChat.Actions.FetchChatSettingsFailed)
return function(state, action)
state = state or {
retrievalStatus = RetrievalStatus.NotStarted,
chatEnabled = true
}
if action.type == FetchChatSettingsStarted.name then
state = Immutable.Set(state, "retrievalStatus", RetrievalStatus.Fetching)
elseif action.type == FetchChatSettingsCompleted.name then
state = Immutable.Set(state, "retrievalStatus", RetrievalStatus.Done)
state = Immutable.JoinDictionaries(state, action.settings)
elseif action.type == FetchChatSettingsFailed.name then
state = Immutable.Set(state, "retrievalStatus", RetrievalStatus.Failed)
end
return state
end
@@ -0,0 +1,32 @@
return function()
local CoreGui = game:GetService("CoreGui")
local Modules = CoreGui.RobloxGui.Modules
local LuaChat = Modules.LuaChat
local FetchChatSettingsCompleted = require(LuaChat.Actions.FetchChatSettingsCompleted)
local ChatSettings = require(script.Parent.ChatSettings)
it("should be enabled by default", function()
local state = ChatSettings(nil, {})
expect(state.chatEnabled).to.equal(true)
expect(state.isActiveChatUser).to.equal(nil)
end)
it("should be changed using ChatSettings", function()
local state = ChatSettings(nil, {})
state = ChatSettings(state, FetchChatSettingsCompleted({}))
expect(state.chatEnabled).to.equal(true)
expect(state.isActiveChatUser).to.equal(nil)
state = ChatSettings(state, FetchChatSettingsCompleted({
chatEnabled = false,
isActiveChatUser = false
}))
expect(state.chatEnabled).to.equal(false)
expect(state.isActiveChatUser).to.equal(false)
end)
end
@@ -0,0 +1,14 @@
local CoreGui = game:GetService("CoreGui")
local Modules = CoreGui.RobloxGui.Modules
local SetConnectionState = require(Modules.LuaChat.Actions.SetConnectionState)
return function(state, action)
state = state or Enum.ConnectionState.Connected
if action.type == SetConnectionState.name then
state = action.connectionState
end
return state
end
@@ -0,0 +1,21 @@
return function()
local CoreGui = game:GetService("CoreGui")
local Modules = CoreGui.RobloxGui.Modules
local LuaChat = Modules.LuaChat
local SetConnectionState = require(LuaChat.Actions.SetConnectionState)
local ConnectionStateReducer = require(script.Parent.ConnectionState)
it("should default to Connected", function()
local state = ConnectionStateReducer(nil, {})
expect(state).to.equal(Enum.ConnectionState.Connected)
end)
it("should update the ConnectionState", function()
local state = ConnectionStateReducer(nil, {})
state = ConnectionStateReducer(state, SetConnectionState(Enum.ConnectionState.Disconnected))
expect(state).to.equal(Enum.ConnectionState.Disconnected)
end)
end
@@ -0,0 +1,248 @@
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
@@ -0,0 +1,455 @@
return function()
local CoreGui = game:GetService("CoreGui")
local Modules = CoreGui.RobloxGui.Modules
local LuaApp = Modules.LuaApp
local LuaChat = Modules.LuaChat
local ChangedParticipants = require(LuaChat.Actions.ChangedParticipants)
local Constants = require(LuaChat.Constants)
local Conversation = require(LuaChat.Models.Conversation)
local DateTime = require(LuaChat.DateTime)
local FetchedOldestMessage = require(LuaChat.Actions.FetchedOldestMessage)
local FetchingOlderMessages = require(LuaChat.Actions.FetchingOlderMessages)
local Message = require(LuaChat.Models.Message)
local MessageFailedToSend = require(LuaChat.Actions.MessageFailedToSend)
local MessageModerated = require(LuaChat.Actions.MessageModerated)
local MockId = require(LuaApp.MockId)
local ReadConversation = require(LuaChat.Actions.ReadConversation)
local ReceivedConversation = require(LuaChat.Actions.ReceivedConversation)
local ReceivedMessages = require(LuaChat.Actions.ReceivedMessages)
local RemovedConversation = require(LuaChat.Actions.RemovedConversation)
local RenamedGroupConversation = require(LuaChat.Actions.RenamedGroupConversation)
local SendingMessage = require(LuaChat.Actions.SendingMessage)
local SentMessage = require(LuaChat.Actions.SentMessage)
local SetConversationLoadingStatus = require(LuaChat.Actions.SetConversationLoadingStatus)
local SetPinnedGameForConversation = require(LuaChat.Actions.SetPinnedGameForConversation)
local SetUserTyping = require(LuaChat.Actions.SetUserTyping)
local User = require(LuaApp.Models.User)
local Conversations = require(script.Parent.Conversations)
describe("initial state", function()
it("should return an initial table when passed nil", function()
local state = Conversations(nil, {})
expect(state).to.be.a("table")
end)
end)
describe("Action ReceivedConversation", function()
it("should add a conversation to the store", function()
local conversation = Conversation.mock()
local state = nil
local action = ReceivedConversation(conversation)
state = Conversations(state, action)
expect(state).to.be.a("table")
expect(state[conversation.id]).to.be.a("table")
expect(state[conversation.id].id).to.equal(conversation.id)
end)
end)
describe("Action ReceivedMessages", function()
it("should add messages to an existing conversation", function()
local conversation = Conversation.mock()
local message = Message.mock()
local state = {
[conversation.id] = conversation
}
local action = ReceivedMessages(conversation.id, {message})
state = Conversations(state, action)
local messages = state[conversation.id].messages
expect(#messages.keys).to.equal(1)
expect(messages.values[messages.keys[1]].id).to.equal(message.id)
end)
it("should insert messages in-order", function()
local conversation = Conversation.mock()
local message1 = Message.mock({ sent = DateTime.new(1992) })
local message2 = Message.mock({ sent = DateTime.new(1990) })
local state = {
[conversation.id] = conversation
}
local action = ReceivedMessages(conversation.id, { message1, message2 })
state = Conversations(state, action)
do
local messages = state[conversation.id].messages
expect(#messages.keys).to.equal(2)
expect(messages.values[messages.keys[1]].id).to.equal(message2.id)
expect(messages.values[messages.keys[2]].id).to.equal(message1.id)
end
local message3 = Message.mock({ sent = DateTime.new(1991) })
action = ReceivedMessages(conversation.id, { message3 })
state = Conversations(state, action)
do
local messages = state[conversation.id].messages
expect(#messages.keys).to.equal(3)
expect(messages.values[messages.keys[1]].id).to.equal(message2.id)
expect(messages.values[messages.keys[2]].id).to.equal(message3.id)
expect(messages.values[messages.keys[3]].id).to.equal(message1.id)
end
end)
it("should set hasUnreadMessages if action.shouldMarkConversationUnread is true", function()
local conversation = Conversation.mock()
local message1 = Message.mock({ read = true })
local message2 = Message.mock({ read = false })
local state = {
[conversation.id] = conversation
}
expect(state[conversation.id].hasUnreadMessages).to.equal(false)
local action = ReceivedMessages(conversation.id, { message1, message2 }, true)
state = Conversations(state, action)
expect(state[conversation.id].hasUnreadMessages).to.equal(true)
end)
it("should not change hasUnreadMessages if action.shouldMarkConversationUnread is false", function()
local conversation = Conversation.mock()
local message1 = Message.mock({ read = false })
local message2 = Message.mock({ read = false })
local state = {
[conversation.id] = conversation
}
expect(state[conversation.id].hasUnreadMessages).to.equal(false)
local action = ReceivedMessages(conversation.id, { message1, message2 }, false)
state = Conversations(state, action)
expect(state[conversation.id].hasUnreadMessages).to.equal(false)
end)
end)
describe("Action SendingMessage", function()
it("should add to the list of sending messages", function()
local conversation = Conversation.mock()
local message = Message.mock()
local state = {
[conversation.id] = conversation
}
local action = SendingMessage(conversation.id, message)
state = Conversations(state, action)
expect(state[conversation.id].sendingMessages:Get(message.id)).to.be.ok()
end)
end)
describe("Action SentMessage", function()
it("should remove from the list of sending messages", function()
local conversation = Conversation.mock()
local message = Message.mock()
local state = {
[conversation.id] = conversation
}
local action1 = SendingMessage(conversation.id, message)
state = Conversations(state, action1)
expect(state[conversation.id].sendingMessages:Get(message.id)).to.be.ok()
local action2 = SentMessage(conversation.id, message.id)
state = Conversations(state, action2)
expect(state[conversation.id].sendingMessages:Get(message.id)).to.never.be.ok()
end)
end)
describe("Action RenamedGroupConversation", function()
it("should rename the conversation", function()
local conversation = Conversation.mock()
local state = {
[conversation.id] = conversation
}
local action = RenamedGroupConversation(conversation.id, "Fleebledegoop, Ham Sammich and Lemur Face")
state = Conversations(state, action)
expect(state[conversation.id].title).to.equal("Fleebledegoop, Ham Sammich and Lemur Face")
end)
it("should update isDefaultTitle value", function()
local conversation = Conversation.mock({
isDefaultTitle = true,
})
local state = {
[conversation.id] = conversation
}
state = Conversations(state, RenamedGroupConversation(conversation.id, "test", false))
expect(state[conversation.id].isDefaultTitle).to.equal(false)
end)
it("should update lastUpdated value", function()
local oldTick = 0
local newTick = 1
local conversation = Conversation.mock({
isDefaultTitle = true,
lastUpdated = oldTick,
})
local state = {
[conversation.id] = conversation
}
state = Conversations(state, RenamedGroupConversation(conversation.id, "test", nil, newTick))
expect(state[conversation.id].lastUpdated).to.equal(newTick)
end)
end)
describe("Action ChangedParticipants", function()
it("should update the participant list", function()
local conversation = Conversation.mock()
local user1 = User.mock()
local user2 = User.mock()
local state = {
[conversation.id] = conversation
}
local action = ChangedParticipants(conversation.id, { user1.id, user2.id })
state = Conversations(state, action)
expect(#state[conversation.id].participants).to.equal(2)
expect(state[conversation.id].participants[1]).to.equal(user1.id)
expect(state[conversation.id].participants[2]).to.equal(user2.id)
action = ChangedParticipants(conversation.id, { user2.id })
state = Conversations(state, action)
expect(#state[conversation.id].participants).to.equal(1)
expect(state[conversation.id].participants[1]).to.equal(user2.id)
end)
end)
describe("Action RemovedConversation", function()
it("should update the conversation list", function()
local conversation1 = Conversation.mock()
local conversation2 = Conversation.mock()
local state = {
[conversation1.id] = conversation1,
[conversation2.id] = conversation2
}
local action = RemovedConversation(conversation1.id)
state = Conversations(state, action)
expect(state[conversation1.id]).to.equal(nil)
expect(state[conversation2.id]).to.be.a("table")
expect(state[conversation2.id].id).to.equal(conversation2.id)
end)
end)
describe("Action SetUserTyping", function()
it("should set userTyping flag for user", function()
local user = User.mock()
local conversation = Conversation.mock({ participants = { user.id } })
local state = {
[conversation.id] = conversation
}
expect(state[conversation.id].usersTyping[user.id]).to.never.be.ok()
local action1 = SetUserTyping(conversation.id, user.id, true)
state = Conversations(state, action1)
expect(state[conversation.id].usersTyping[user.id]).to.equal(true)
local action2 = SetUserTyping(conversation.id, user.id, false)
state = Conversations(state, action2)
expect(state[conversation.id].usersTyping[user.id]).to.equal(false)
end)
end)
describe("Action FetchingOlderMessages", function()
it("sets the fetchingOlderMessages flag", function()
local conversation = Conversation.mock()
local state = {
[conversation.id] = conversation
}
expect(state[conversation.id].fetchingOlderMessages).to.equal(false)
local action1 = FetchingOlderMessages(conversation.id, true)
state = Conversations(state, action1)
expect(state[conversation.id].fetchingOlderMessages).to.equal(true)
local action2 = FetchingOlderMessages(conversation.id, false)
state = Conversations(state, action2)
expect(state[conversation.id].fetchingOlderMessages).to.equal(false)
end)
end)
describe("Action FetchedOldestMessage", function()
it("sets the fetchedOldestMessage flag", function()
local conversation = Conversation.mock()
local state = {
[conversation.id] = conversation
}
expect(state[conversation.id].fetchedOldestMessage).to.equal(false)
local action1 = FetchedOldestMessage(conversation.id, true)
state = Conversations(state, action1)
expect(state[conversation.id].fetchedOldestMessage).to.equal(true)
local action2 = FetchedOldestMessage(conversation.id, false)
state = Conversations(state, action2)
expect(state[conversation.id].fetchedOldestMessage).to.equal(false)
end)
end)
describe("Action ReadConversation", function()
it("should read messages and mark the conversation's unread state", function()
local message1 = Message.mock({ sent = DateTime.new(1992), read = true })
local message2 = Message.mock({ sent = DateTime.new(1993), read = false })
local message3 = Message.mock({ sent = DateTime.new(1994), read = false })
local message4 = Message.mock({ sent = DateTime.new(1995), read = false })
local message5 = Message.mock({ sent = DateTime.new(1996), read = false })
local conversation = Conversation.mock()
local state = {
[conversation.id] = conversation
}
local actionAddMessages = ReceivedMessages(conversation.id, { message1, message2, message3, message4 }, true)
state = Conversations(state, actionAddMessages)
expect(state[conversation.id].hasUnreadMessages).to.equal(true)
local actionReadAll = ReadConversation(conversation.id)
state = Conversations(state, actionReadAll)
do
expect(state[conversation.id].hasUnreadMessages).to.equal(false)
local messages = state[conversation.id].messages
expect(messages.values[message1.id].read).to.equal(true)
expect(messages.values[message2.id].read).to.equal(true)
expect(messages.values[message3.id].read).to.equal(true)
end
local action2 = ReceivedMessages(conversation.id, { message4, message5 }, true)
state = Conversations(state, action2)
do
expect(state[conversation.id].hasUnreadMessages).to.equal(true)
local messages = state[conversation.id].messages
expect(messages.values[message1.id].read).to.equal(true)
expect(messages.values[message2.id].read).to.equal(true)
expect(messages.values[message3.id].read).to.equal(true)
expect(messages.values[message4.id].read).to.equal(true)
expect(messages.values[message5.id].read).to.equal(false)
end
local actionReadAll2 = ReadConversation(conversation.id)
state = Conversations(state, actionReadAll2)
do
expect(state[conversation.id].hasUnreadMessages).to.equal(false)
local messages = state[conversation.id].messages
expect(messages.values[message1.id].read).to.equal(true)
expect(messages.values[message2.id].read).to.equal(true)
expect(messages.values[message3.id].read).to.equal(true)
expect(messages.values[message4.id].read).to.equal(true)
end
end)
end)
describe("Action MessageModerated", function()
it("should mark the sending message as moderated", function()
local conversation = Conversation.mock()
local message = Message.mock()
local state = {
[conversation.id] = conversation
}
local action = SendingMessage(conversation.id, message)
state = Conversations(state, action)
expect(state[conversation.id].sendingMessages:Get(message.id).moderated).to.never.be.ok()
action = MessageModerated(conversation.id, message.id)
state = Conversations(state, action)
expect(state[conversation.id].sendingMessages:Get(message.id).moderated).to.equal(true)
end)
end)
describe("Action MessageFailedToSend", function()
it("should mark the sending message as failed", function()
local conversation = Conversation.mock()
local message = Message.mock()
local state = {
[conversation.id] = conversation
}
local action = SendingMessage(conversation.id, message)
state = Conversations(state, action)
expect(state[conversation.id].sendingMessages:Get(message.id).failed).to.equal(nil)
action = MessageFailedToSend(conversation.id, message.id)
state = Conversations(state, action)
expect(state[conversation.id].sendingMessages:Get(message.id).failed).to.equal(true)
end)
end)
describe("Action SetConversationLoadingStatus", function()
it("should set the conversation loading status", function()
local conversation = Conversation.mock()
local state = {
[conversation.id] = conversation
}
expect(state[conversation.id].initialLoadingStatus).to.never.be.ok()
local action = SetConversationLoadingStatus(conversation.id, Constants.ConversationLoadingState.LOADING)
state = Conversations(state, action)
expect(state[conversation.id].initialLoadingStatus).to.equal(Constants.ConversationLoadingState.LOADING)
action = SetConversationLoadingStatus(conversation.id, Constants.ConversationLoadingState.DONE)
state = Conversations(state, action)
expect(state[conversation.id].initialLoadingStatus).to.equal(Constants.ConversationLoadingState.DONE)
end)
end)
describe("Action SetPinnedGameForConversation", function()
it("should set the pinned game for conversation", function()
local conversation = Conversation.mock()
local state = {
[conversation.id] = conversation
}
local mockRootPlaceId = MockId()
local mockUniverseId = MockId()
local action = SetPinnedGameForConversation(mockUniverseId, mockRootPlaceId, conversation.id)
state = Conversations(state, action)
expect(state[conversation.id].pinnedGame.rootPlaceId).to.equal(mockRootPlaceId)
expect(state[conversation.id].pinnedGame.universeId).to.equal(mockUniverseId)
end)
end)
end
@@ -0,0 +1,39 @@
local Modules = game:GetService("CoreGui").RobloxGui.Modules
local LuaChat = Modules.LuaChat
local ReceivedLatestMessages = require(LuaChat.Actions.ReceivedLatestMessages)
local ReceivedOldestConversation = require(LuaChat.Actions.ReceivedOldestConversation)
local ReceivedPageConversations = require(LuaChat.Actions.ReceivedPageConversations)
local RequestLatestMessages = require(LuaChat.Actions.RequestLatestMessages)
local RequestPageConversations = require(LuaChat.Actions.RequestPageConversations)
local Immutable = require(Modules.Common.Immutable)
return function(state, action)
state = state or {}
if action.type == RequestPageConversations.name then
return Immutable.JoinDictionaries(state, {
pageConversationsIsFetching = true,
})
elseif action.type == ReceivedPageConversations.name then
return Immutable.JoinDictionaries(state, {
pageConversationsIsFetching = false,
})
elseif action.type == RequestLatestMessages.name then
return Immutable.JoinDictionaries(state, {
latestMessagesIsFetching = true,
})
elseif action.type == ReceivedLatestMessages.name then
return Immutable.JoinDictionaries(state, {
latestMessagesIsFetching = false,
})
elseif action.type == ReceivedOldestConversation.name then
return Immutable.JoinDictionaries(state, {
oldestConversationIsFetched = true,
})
end
return state
end
@@ -0,0 +1,66 @@
return function()
local Modules = game:GetService("CoreGui").RobloxGui.Modules
local LuaChat = Modules.LuaChat
local ConversationsAsyncReducer = require(LuaChat.Reducers.ConversationsAsync)
local ReceivedLatestMessages = require(LuaChat.Actions.ReceivedLatestMessages)
local ReceivedOldestConversation = require(LuaChat.Actions.ReceivedOldestConversation)
local ReceivedPageConversations = require(LuaChat.Actions.ReceivedPageConversations)
local RequestLatestMessages = require(LuaChat.Actions.RequestLatestMessages)
local RequestPageConversations = require(LuaChat.Actions.RequestPageConversations)
describe("initial state", function()
it("should return an initial table when passed nil", function()
local state = ConversationsAsyncReducer(nil, {})
expect(state).to.be.a("table")
end)
end)
describe("RequestPageConversations", function()
it("should set the async state to true", function()
local state = ConversationsAsyncReducer(nil, {})
state = ConversationsAsyncReducer(state, RequestPageConversations())
expect(state.pageConversationsIsFetching).to.equal(true)
end)
end)
describe("ReceivedPageConversations", function()
it("should set the async state to false", function()
local state = ConversationsAsyncReducer(nil, {})
state = ConversationsAsyncReducer(state, ReceivedPageConversations())
expect(state.pageConversationsIsFetching).to.equal(false)
end)
end)
describe("RequestLatestMessages", function()
it("should set the async state to true", function()
local state = ConversationsAsyncReducer(nil, {})
state = ConversationsAsyncReducer(state, RequestLatestMessages())
expect(state.latestMessagesIsFetching).to.equal(true)
end)
end)
describe("ReceivedLatestMessages", function()
it("should set the async state to false", function()
local state = ConversationsAsyncReducer(nil, {})
state = ConversationsAsyncReducer(state, ReceivedLatestMessages())
expect(state.latestMessagesIsFetching).to.equal(false)
end)
end)
describe("ReceivedOldestConversation", function()
it("should set the oldestConversationIsFetched flag to true", function()
local state = ConversationsAsyncReducer(nil, {})
state = ConversationsAsyncReducer(state, ReceivedOldestConversation())
expect(state.oldestConversationIsFetched).to.equal(true)
end)
end)
end
@@ -0,0 +1,9 @@
-----------------------------------------------------------------------------
--- ---
--- Under Migration to CorePackages ---
--- ---
--- Please put your changes in AppTempCommon. ---
--- NOTE: You will have to rebuild for changes to kick in ---
-----------------------------------------------------------------------------
local CorePackages = game:GetService("CorePackages")
return require(CorePackages.AppTempCommon.LuaChat.Reducers.FriendCount)
@@ -0,0 +1,18 @@
return function()
local LuaChat = script.Parent.Parent
local FriendCount = require(script.Parent.FriendCount)
local SetFriendCount = require(LuaChat.Actions.SetFriendCount)
it("should be zero by default", function()
local state = FriendCount(nil, {})
expect(state).to.equal(0)
end)
it("should respond to SetFriendCount", function()
local state = FriendCount(nil, {})
state = FriendCount(state, SetFriendCount(520))
expect(state).to.equal(520)
end)
end
@@ -0,0 +1,97 @@
local CoreGui = game:GetService("CoreGui")
local Modules = CoreGui.RobloxGui.Modules
local Common = Modules.Common
local LuaChat = Modules.LuaChat
local PopRoute = require(LuaChat.Actions.PopRoute)
local RemoveRoute = require(LuaChat.Actions.RemoveRoute)
local SetRoute = require(LuaChat.Actions.SetRoute)
local Immutable = require(Common.Immutable)
return function(state, action)
state = state or {
current = {},
history = {}
}
if action.type == SetRoute.name then
local current = state.current
local history = state.history
local routeData = {
intent = action.intent,
popToIntent = action.popToIntent,
parameters = action.parameters
}
if action.popToIntent then
local found = false
for i = #history, 1, -1 do
local loc = history[i]
if loc.intent == action.popToIntent then
history = Immutable.RemoveRangeFromList(history, i + 1, #history - i)
current = history[#history]
found = true
break
end
end
if not found then
warn("Could not pop to unavailable intent: " .. action.popToIntent)
end
end
if routeData.intent ~= nil then
current = routeData
history = Immutable.Append(history, routeData)
end
return {
current = current,
history = history
}
elseif action.type == PopRoute.name then
local current
local history = state.history
if #history <= 1 then
return state
end
history = Immutable.RemoveFromList(history, #history)
current = history[#history]
if not current then
current = {}
end
return {
current = current,
history = history
}
elseif action.type == RemoveRoute.name then
local intent = action.intent
local history = state.history
for i = #history, 1, -1 do
local loc = history[i]
if loc.intent == intent then
history = Immutable.RemoveFromList(history, i)
break
end
end
local current = history[#history] or {}
return {
current = current,
history = history
}
end
return state
end
@@ -0,0 +1,236 @@
return function()
local LuaChat = script.Parent.Parent
local Location = require(script.Parent.Location)
local DialogInfo = require(LuaChat.DialogInfo)
local Intent = DialogInfo.Intent
local PopRoute = require(LuaChat.Actions.PopRoute)
local RemoveRoute = require(LuaChat.Actions.RemoveRoute)
local SetRoute = require(LuaChat.Actions.SetRoute)
describe("initial state", function()
it("should return an initial table when passed nil", function()
local state = Location(nil, {})
expect(state).to.be.a("table")
expect(state.current).to.be.a("table")
expect(state.history).to.be.a("table")
end)
end)
describe("SetRoute", function()
it("should set route to ConversationHub", function()
local intent = Intent.ConversationHub
local state = Location(nil, SetRoute(intent, {}))
expect(state.current.intent).to.equal(intent)
end)
it("should set route to Conversation with correct conversationId", function()
local intent = Intent.Conversation
local conversationId = "testConvoId"
local state = Location(nil, SetRoute(
intent,
{
conversationId = conversationId,
}
))
expect(state.current.intent).to.equal(intent)
expect(state.current.parameters.conversationId).to.equal(conversationId)
end)
end)
describe("SetRoute with popToIntent", function()
it("should pop to the right intent first and then add the new intent on top", function()
local state = Location(nil, SetRoute(Intent.ConversationHub, {}))
state = Location(state, SetRoute(
Intent.Conversation,
{
conversationId = "testConvoId1",
}
))
state = Location(state, SetRoute(Intent.NewChatGroup))
state = Location(state, SetRoute(
Intent.Conversation,
{
conversationId = "testConvoId2",
}
))
expect(#state.history).to.equal(4)
state = Location(state, SetRoute(
Intent.Conversation,
{
conversationId = "testConvoId3",
},
Intent.ConversationHub
))
expect(#state.history).to.equal(2)
expect(state.history[1].intent).to.equal(Intent.ConversationHub)
expect(state.current.parameters.conversationId).to.equal("testConvoId3")
expect(state.history[#state.history].parameters.conversationId).to.equal("testConvoId3")
end)
it("should pop to the right intent and stop if the new intent is nil", function()
local state = Location(nil, SetRoute(
Intent.ConversationHub,
{}
))
state = Location(state, SetRoute(
Intent.Conversation,
{
conversationId = "testConvoId1",
}
))
state = Location(state, SetRoute(Intent.NewChatGroup))
state = Location(state, SetRoute(
Intent.Conversation,
{
conversationId = "testConvoId2",
}
))
state = Location(state, SetRoute(
nil,
{
conversationId = "testConvoId3",
},
Intent.NewChatGroup
))
expect(#state.history).to.equal(3)
expect(state.current.intent).to.equal(Intent.NewChatGroup)
expect(state.history[#state.history].intent).to.equal(Intent.NewChatGroup)
end)
end)
describe("route history", function()
it("should push history", function()
local state = Location(nil, SetRoute(
Intent.ConversationHub,
{}
))
expect(#state.history).to.equal(1)
end)
it("should push history twice and have correct number of history entries", function()
local state = Location(nil, SetRoute(
Intent.ConversationHub,
{}
))
state = Location(state, SetRoute(
Intent.Conversation,
{
conversationId = "testConvoId",
}
))
expect(#state.history).to.equal(2)
end)
it("should have current be equal to top of history", function()
local state = Location(nil, SetRoute(
Intent.ConversationHub,
{}
))
expect(state.history[1].intent).to.equal(state.current.intent)
end)
it("should pop history", function()
local state = Location(nil, SetRoute(
Intent.ConversationHub,
{}
))
state = Location(state, SetRoute(Intent.Conversation,
{
conversationId = "testConvoId",
}
))
state = Location(state, PopRoute())
expect(state.current.intent).to.equal(Intent.ConversationHub)
expect(#state.history).to.equal(1)
expect(state.history[1].intent).to.equal(state.current.intent)
end)
it("should never pop routes where the history is empty", function()
local state = Location(nil, SetRoute(
Intent.ConversationHub,
{}
))
state = Location(state, SetRoute(Intent.Conversation,
{
conversationId = "testConvoId",
}
))
state = Location(state, PopRoute())
expect(state.current.intent).to.equal(Intent.ConversationHub)
expect(#state.history).to.equal(1)
expect(state.history[1].intent).to.equal(state.current.intent)
state = Location(state, PopRoute())
expect(state.current.intent).to.equal(Intent.ConversationHub)
expect(#state.history).to.equal(1)
expect(state.history[1].intent).to.equal(state.current.intent)
end)
it("should remove from history properly", function()
local state = Location(nil, SetRoute(
Intent.ConversationHub,
{}
))
state = Location(state, SetRoute(
Intent.Conversation,
{
conversationId = "testConvoId1"
}
))
state = Location(state, SetRoute(
Intent.NewChatGroup
))
state = Location(state, SetRoute(
Intent.Conversation,
{
conversationId = "testConvoId2"
}
))
expect(#state.history).to.equal(4)
state = Location(state, RemoveRoute(Intent.NewChatGroup))
expect(#state.history).to.equal(3)
state = Location(state, RemoveRoute(Intent.EditChatGroup))
expect(#state.history).to.equal(3)
state = Location(state, RemoveRoute(Intent.Conversation))
expect(state.current.intent).to.equal(Intent.Conversation)
expect(state.current.parameters.conversationId).to.equal("testConvoId1")
end)
end)
end
@@ -0,0 +1,28 @@
local CoreGui = game:GetService("CoreGui")
local Modules = CoreGui.RobloxGui.Modules
local Common = Modules.Common
local LuaChat = Modules.LuaChat
local Actions = LuaChat.Actions
local SetMostRecentlyPlayedGamesForUser = require(Actions.SetMostRecentlyPlayedGamesForUser)
local SetMostRecentlyPlayedPlayableGameForUser = require(Actions.SetMostRecentlyPlayedPlayableGameForUser)
local Immutable = require(Common.Immutable)
return function(state, action)
state = state or {}
if action.type == SetMostRecentlyPlayedGamesForUser.name then
return Immutable.JoinDictionaries(state, {
games = action.games
})
elseif action.type == SetMostRecentlyPlayedPlayableGameForUser.name then
return Immutable.JoinDictionaries(state, {
playableGamePlaceId = action.placeId,
setPlayableGame = true
})
end
return state
end
@@ -0,0 +1,9 @@
-----------------------------------------------------------------------------
--- ---
--- Under Migration to CorePackages ---
--- ---
--- Please put your changes in AppTempCommon. ---
--- NOTE: You will have to rebuild for changes to kick in ---
-----------------------------------------------------------------------------
local CorePackages = game:GetService("CorePackages")
return require(CorePackages.AppTempCommon.LuaChat.Reducers.PlaceInfos)
@@ -0,0 +1,33 @@
local Modules = game:GetService("CoreGui").RobloxGui.Modules
local LuaChat = Modules.LuaChat
local Actions = LuaChat.Actions
local Immutable = require(Modules.Common.Immutable)
local RequestMultiplePlaceInfos = require(Actions.RequestMultiplePlaceInfos)
local FailedToFetchMultiplePlaceInfos = require(Actions.FailedToFetchMultiplePlaceInfos)
local ReceivedMultiplePlaceInfos = require(Actions.ReceivedMultiplePlaceInfos)
return function(state, action)
state = state or {}
if action.type == RequestMultiplePlaceInfos.name then
local newFlags = {}
for _, placeId in ipairs(action.placeIds) do
newFlags[placeId] = true
end
return Immutable.JoinDictionaries(state, newFlags)
elseif action.type == ReceivedMultiplePlaceInfos.name then
local newFlags = {}
for _, placeInfo in ipairs(action.placeInfos) do
newFlags[placeInfo.placeId] = false
end
return Immutable.JoinDictionaries(state, newFlags)
elseif action.type == FailedToFetchMultiplePlaceInfos.name then
local newFlags = {}
for _, placeId in ipairs(action.placeIds) do
newFlags[placeId] = false
end
return Immutable.JoinDictionaries(state, newFlags)
end
return state
end
@@ -0,0 +1,16 @@
local CoreGui = game:GetService("CoreGui")
local Modules = CoreGui.RobloxGui.Modules
local Common = Modules.Common
local LuaChat = Modules.LuaChat
local Immutable = require(Common.Immutable)
local ReceivedPlaceThumbnail = require(LuaChat.Actions.ReceivedPlaceThumbnail)
return function(state, action)
state = state or {}
if action.type == ReceivedPlaceThumbnail.name then
state = Immutable.Set(state, action.imageToken, action.thumbnail)
end
return state
end
@@ -0,0 +1,25 @@
return function()
local CoreGui = game:GetService("CoreGui")
local Modules = CoreGui.RobloxGui.Modules
local LuaChat = Modules.LuaChat
local ReceivedPlaceThumbnail = require(LuaChat.Actions.ReceivedPlaceThumbnail)
local PlaceThumbnailsReducer = require(script.Parent.PlaceThumbnails)
describe("initial state", function()
it("should return an initial table when passed nil", function()
local state = PlaceThumbnailsReducer(nil, {})
expect(state).to.be.a("table")
end)
end)
describe("ReceivedPlaceThumbnail", function()
it("should add place thumbnail to the store", function()
local state = PlaceThumbnailsReducer(nil, {})
local returnedThumbnail = ReceivedPlaceThumbnail("imageToken", "thumbnail")
state = PlaceThumbnailsReducer(state, returnedThumbnail)
expect(state["imageToken"]).to.equal("thumbnail")
end)
end)
end
@@ -0,0 +1,25 @@
local Modules = game:GetService("CoreGui").RobloxGui.Modules
local Immutable = require(Modules.Common.Immutable)
local RequestPlaceThumbnail = require(Modules.LuaChat.Actions.RequestPlaceThumbnail)
local ReceivedPlaceThumbnail = require(Modules.LuaChat.Actions.ReceivedPlaceThumbnail)
local FailedToFetchPlaceThumbnail = require(Modules.LuaChat.Actions.FailedToFetchPlaceThumbnail)
return function(state, action)
state = state or {}
if action.type == RequestPlaceThumbnail.name then
return Immutable.JoinDictionaries(state, {
[action.imageToken] = true,
})
elseif action.type == ReceivedPlaceThumbnail.name then
return Immutable.JoinDictionaries(state, {
[action.imageToken] = false,
})
elseif action.type == FailedToFetchPlaceThumbnail.name then
return Immutable.JoinDictionaries(state, {
[action.imageToken] = false,
})
end
return state
end
@@ -0,0 +1,74 @@
local CoreGui = game:GetService("CoreGui")
local Modules = CoreGui.RobloxGui.Modules
local Common = Modules.Common
local LuaChat = Modules.LuaChat
local Actions = LuaChat.Actions
local FailedToFetchMostRecentlyPlayedGames = require(Actions.FailedToFetchMostRecentlyPlayedGames)
local FetchedMostRecentlyPlayedGames = require(Actions.FetchedMostRecentlyPlayedGames)
local FetchingMostRecentlyPlayedGames = require(Actions.FetchingMostRecentlyPlayedGames)
local GameFailedToPin = require(Actions.GameFailedToPin)
local GameFailedToUnpin = require(Actions.GameFailedToUnpin)
local PinnedGame = require(Actions.PinnedGame)
local PinningGame = require(Actions.PinningGame)
local UnpinnedGame = require(Actions.UnpinnedGame)
local UnpinningGame = require(Actions.UnpinningGame)
local Immutable = require(Common.Immutable)
return function(state, action)
state = state or {
pinningGames = {},
unPinningGames = {},
}
-- play together async
if action.type == PinningGame.name then
local newPinningGames = Immutable.Set(state.pinningGames, action.conversationId, true)
return Immutable.JoinDictionaries(state, {
pinningGames = newPinningGames;
})
elseif action.type == PinnedGame.name then
local newPinningGames = Immutable.Set(state.pinningGames, action.conversationId, false)
return Immutable.JoinDictionaries(state, {
pinningGames = newPinningGames;
})
elseif action.type == GameFailedToPin.name then
local newPinningGames = Immutable.Set(state.pinningGames, action.conversationId, false)
return Immutable.JoinDictionaries(state, {
pinningGames = newPinningGames;
})
elseif action.type == UnpinningGame.name then
local newUnpinningGames = Immutable.Set(state.unPinningGames, action.conversationId, true)
return Immutable.JoinDictionaries(state, {
unPinningGames = newUnpinningGames;
})
elseif action.type == UnpinnedGame.name then
local newUnpinningGames = Immutable.Set(state.unPinningGames, action.conversationId, false)
return Immutable.JoinDictionaries(state, {
unPinningGames = newUnpinningGames;
})
elseif action.type == GameFailedToUnpin.name then
local newUnpinningGames = Immutable.Set(state.unPinningGames, action.conversationId, false)
return Immutable.JoinDictionaries(state, {
unPinningGames = newUnpinningGames;
})
elseif action.type == FetchingMostRecentlyPlayedGames.name then
return Immutable.JoinDictionaries(state, {
fetchingMostRecentlyPlayedGames = true,
fetchedMostRecentlyPlayedGames = false
})
elseif action.type == FetchedMostRecentlyPlayedGames.name then
return Immutable.JoinDictionaries(state, {
fetchingMostRecentlyPlayedGames = false,
fetchedMostRecentlyPlayedGames = true,
})
elseif action.type == FailedToFetchMostRecentlyPlayedGames.name then
return Immutable.JoinDictionaries(state, {
fetchingMostRecentlyPlayedGames = false,
fetchedMostRecentlyPlayedGames = false
})
end
return state
end
@@ -0,0 +1,119 @@
local CoreGui = game:GetService("CoreGui")
local Modules = CoreGui.RobloxGui.Modules
local LuaApp = Modules.LuaApp
local LuaChat = Modules.LuaChat
local Actions = LuaChat.Actions
local MockId = require(LuaApp.MockId)
local PlayTogetherAsync = require(script.Parent.PlayTogetherAsync)
local FailedToFetchMostRecentlyPlayedGames = require(Actions.FailedToFetchMostRecentlyPlayedGames)
local FetchedMostRecentlyPlayedGames = require(Actions.FetchedMostRecentlyPlayedGames)
local FetchingMostRecentlyPlayedGames = require(Actions.FetchingMostRecentlyPlayedGames)
local GameFailedToPin = require(Actions.GameFailedToPin)
local GameFailedToUnpin = require(Actions.GameFailedToUnpin)
local PinnedGame = require(Actions.PinnedGame)
local PinningGame = require(Actions.PinningGame)
local UnpinnedGame = require(Actions.UnpinnedGame)
local UnpinningGame = require(Actions.UnpinningGame)
return function()
describe("initial state", function()
it("should return an initial table when passed nil", function()
local state = PlayTogetherAsync(nil, {})
expect(state).to.be.a("table")
expect(state.pinningGames).to.be.a("table")
expect(state.unPinningGames).to.be.a("table")
end)
end)
describe("PinningGame", function()
it("should set the pinning game async state to true", function()
local state = PlayTogetherAsync(nil, {})
local testConversationId = MockId()
state = PlayTogetherAsync(state, PinningGame(testConversationId))
expect(state.pinningGames[testConversationId]).to.equal(true)
end)
end)
describe("PinnedGame", function()
it("should set the pinning game async state to false", function()
local state = PlayTogetherAsync(nil, {})
local testConversationId = MockId()
state = PlayTogetherAsync(state, PinnedGame(testConversationId))
expect(state.pinningGames[testConversationId]).to.equal(false)
end)
end)
describe("GameFailedToPin", function()
it("should set the pinning game async state to false", function()
local state = PlayTogetherAsync(nil, {})
local testConversationId = MockId()
state = PlayTogetherAsync(state, GameFailedToPin(testConversationId))
expect(state.pinningGames[testConversationId]).to.equal(false)
end)
end)
describe("UnpinningGame", function()
it("should set the unpinning game async state to true", function()
local state = PlayTogetherAsync(nil, {})
local testConversationId = MockId()
state = PlayTogetherAsync(state, UnpinningGame(testConversationId))
expect(state.unPinningGames[testConversationId]).to.equal(true)
end)
end)
describe("UnpinnedGame", function()
it("should set the unpinning game async state to false", function()
local state = PlayTogetherAsync(nil, {})
local testConversationId = MockId()
state = PlayTogetherAsync(state, UnpinnedGame(testConversationId))
expect(state.unPinningGames[testConversationId]).to.equal(false)
end)
end)
describe("GameFailedToUnpin", function()
it("should set the unpinning game async state to false", function()
local state = PlayTogetherAsync(nil, {})
local testConversationId = MockId()
state = PlayTogetherAsync(state, GameFailedToUnpin(testConversationId))
expect(state.unPinningGames[testConversationId]).to.equal(false)
end)
end)
describe("FetchingMostRecentlyPlayedGames", function()
it("should update fecth state of most recently played games", function()
local state = PlayTogetherAsync(nil, {})
state = PlayTogetherAsync(state, FetchingMostRecentlyPlayedGames())
expect(state.fetchingMostRecentlyPlayedGames).to.equal(true)
expect(state.fetchedMostRecentlyPlayedGames).to.equal(false)
end)
end)
describe("FetchedMostRecentlyPlayedGames", function()
it("should update fecth state of most recently played games", function()
local state = PlayTogetherAsync(nil, {})
state = PlayTogetherAsync(state, FetchedMostRecentlyPlayedGames())
expect(state.fetchingMostRecentlyPlayedGames).to.equal(false)
expect(state.fetchedMostRecentlyPlayedGames).to.equal(true)
end)
end)
describe("FailedToFetchMostRecentlyPlayedGames", function()
it("should update fecth state of most recently played games", function()
local state = PlayTogetherAsync(nil, {})
state = PlayTogetherAsync(state, FailedToFetchMostRecentlyPlayedGames())
expect(state.fetchingMostRecentlyPlayedGames).to.equal(false)
expect(state.fetchedMostRecentlyPlayedGames).to.equal(false)
end)
end)
end
@@ -0,0 +1,84 @@
local CoreGui = game:GetService("CoreGui")
local Modules = CoreGui.RobloxGui.Modules
local Common = Modules.Common
local Immutable = require(Common.Immutable)
local LuaChat = Modules.LuaChat
local ShareGameToChatActions = LuaChat.Actions.ShareGameToChatFromChat
local FailedToFetchGamesBySort = require(ShareGameToChatActions.FailedToFetchGamesBySortShareGameToChatFromChat)
local FailedToShareGameToChat = require(ShareGameToChatActions.FailedToShareGameToChatFromChat)
local FetchedGamesBySort = require(ShareGameToChatActions.FetchedGamesBySortShareGameToChatFromChat)
local FetchingGamesBySort = require(ShareGameToChatActions.FetchingGamesBySortShareGameToChatFromChat)
local ResetShareGameToChatAsync = require(ShareGameToChatActions.ResetShareGameToChatFromChatAsync)
local ResetShareGame = require(ShareGameToChatActions.ResetShareGameToChatFromChat)
local SharedGameToChat = require(ShareGameToChatActions.SharedGameToChatFromChat)
local SharingGameToChat = require(ShareGameToChatActions.SharingGameToChatFromChat)
return function(state, action)
state = state or {
fetchingGamesBySort = {},
fetchedGamesBySort = {},
failedToFetchGamesBySort = {},
}
if action.type == FetchingGamesBySort.name then
local newFetchingGamesBySort = Immutable.Set(state.fetchingGamesBySort, action.gameSortName, true)
local newFetchedGamesBySort = Immutable.Set(state.fetchedGamesBySort, action.gameSortName, false)
local newFailedToFetchGamesBySort = Immutable.Set(state.failedToFetchGamesBySort, action.gameSortName, false)
return Immutable.JoinDictionaries(state, {
fetchingGamesBySort = newFetchingGamesBySort;
fetchedGamesBySort = newFetchedGamesBySort;
failedToFetchGamesBySort = newFailedToFetchGamesBySort;
})
elseif action.type == FetchedGamesBySort.name then
local newFetchingGamesBySort = Immutable.Set(state.fetchingGamesBySort, action.gameSortName, false)
local newFetchedGamesBySort = Immutable.Set(state.fetchedGamesBySort, action.gameSortName, true)
local newFailedToFetchGamesBySort = Immutable.Set(state.failedToFetchGamesBySort, action.gameSortName, false)
return Immutable.JoinDictionaries(state, {
fetchingGamesBySort = newFetchingGamesBySort;
fetchedGamesBySort = newFetchedGamesBySort;
failedToFetchGamesBySort = newFailedToFetchGamesBySort;
})
elseif action.type == FailedToFetchGamesBySort.name then
local newFetchingGamesBySort = Immutable.Set(state.fetchingGamesBySort, action.gameSortName, false)
local newFetchedGamesBySort = Immutable.Set(state.fetchedGamesBySort, action.gameSortName, false)
local newFailedToFetchGamesBySort = Immutable.Set(state.failedToFetchGamesBySort, action.gameSortName, true)
return Immutable.JoinDictionaries(state, {
fetchingGamesBySort = newFetchingGamesBySort;
fetchedGamesBySort = newFetchedGamesBySort;
failedToFetchGamesBySort = newFailedToFetchGamesBySort;
})
elseif action.type == ResetShareGameToChatAsync.name then
return {
fetchingGamesBySort = {},
fetchedGamesBySort = {},
failedToFetchGamesBySort = {},
}
elseif action.type == SharingGameToChat.name then
return Immutable.JoinDictionaries(state, {
sharingGame = true,
sharedGame = false,
})
elseif action.type == SharedGameToChat.name then
return Immutable.JoinDictionaries(state, {
sharingGame = false,
sharedGame = true,
})
elseif action.type == FailedToShareGameToChat.name then
return Immutable.JoinDictionaries(state, {
sharedGame = false,
sharingGame = false,
})
elseif action.type == ResetShareGame.name then
return Immutable.JoinDictionaries(state, {
sharedGame = false,
sharingGame = false,
})
end
return state
end
@@ -0,0 +1,40 @@
local CoreGui = game:GetService("CoreGui")
local Modules = CoreGui.RobloxGui.Modules
local Common = Modules.Common
local Immutable = require(Common.Immutable)
local LuaChat = Modules.LuaChat
local ShareGameToChatActions = LuaChat.Actions.ShareGameToChatFromChat
local AddGamesBySort = require(ShareGameToChatActions.AddGamesBySortShareGameToChatFromChat)
local UpdateGameSortsTokens = require(ShareGameToChatActions.UpdateGameSortsTokensShareGameToChatFromChat)
local ClearAllGamesInSorts = require(ShareGameToChatActions.ClearAllGamesInSortsShareGameToChatFromChat)
return function(state, action)
state = state or {}
if action.type == AddGamesBySort.name then
local sort = state[action.name] or {}
local newSort = Immutable.JoinDictionaries(sort, {
token = sort.token,
tokenExpiry = sort.tokenExpiry,
placeIds = action.placeIds
})
state = Immutable.Set(state, action.name, newSort)
elseif action.type == UpdateGameSortsTokens.name then
for _, gameSort in pairs(action.gameSorts) do
local sort = state[gameSort.name] or {}
local placeIds = state[gameSort.name] ~= nil and state[gameSort.name].placeIds or nil
local newSort = Immutable.JoinDictionaries(sort, {
token = gameSort.token,
tokenExpiry = gameSort.tokenExpiryInSeconds + tick(),
placeIds = placeIds
})
state = Immutable.Set(state, gameSort.name, newSort)
end
elseif action.type == ClearAllGamesInSorts.name then
state = {}
end
return state
end
@@ -0,0 +1,22 @@
local CoreGui = game:GetService("CoreGui")
local Modules = CoreGui.RobloxGui.Modules
local Common = Modules.Common
local Immutable = require(Common.Immutable)
local LuaChat = Modules.LuaChat
local ShareGameToChatActions = LuaChat.Actions.ShareGameToChatFromChat
local AddGamesInformation = require(ShareGameToChatActions.AddGamesInformationShareGameToChatFromChat)
return function(state, action)
state = state or {}
if action.type == AddGamesInformation.name then
local tmpTable = {}
for _, gameInfo in pairs(action.games) do
tmpTable[gameInfo.placeId] = gameInfo
end
state = Immutable.JoinDictionaries(state, tmpTable)
end
return state
end
@@ -0,0 +1,16 @@
local Modules = game:GetService("CoreGui").RobloxGui.Modules
local ShowToast = require(Modules.LuaChat.Actions.ShowToast)
local ToastComplete = require(Modules.LuaChat.Actions.ToastComplete)
return function(state, action)
state = state or nil
if action.type == ShowToast.name then
state = action.toast
elseif action.type == ToastComplete.name then
state = nil
end
return state
end
@@ -0,0 +1,42 @@
return function()
local CoreGui = game:GetService("CoreGui")
local Modules = CoreGui.RobloxGui.Modules
local LuaChat = Modules.LuaChat
local ShowToast = require(LuaChat.Actions.ShowToast)
local ToastComplete = require(LuaChat.Actions.ToastComplete)
local ToastReducer = require(script.Parent.Toast)
local ToastModel = require(LuaChat.Models.ToastModel)
describe("Action Toast", function()
it("should return nil when passed nil", function()
local state = ToastReducer(nil, {})
expect(state).to.equal(nil)
end)
it("Action ShowToast", function()
local state = ToastReducer(nil, {})
local myToast = ToastModel.new()
state = ToastReducer(state, ShowToast(myToast))
expect(state).to.equal(myToast)
end)
it("Action ToastComplete", function()
local state = ToastReducer(nil, {})
state = ToastReducer(state, ToastComplete())
expect(state).to.equal(nil)
end)
it("ToastComplete should clear current toast", function()
local state = ToastReducer(nil, {})
local myToast = ToastModel.new()
state = ToastReducer(state, ShowToast(myToast))
expect(state).to.equal(myToast)
state = ToastReducer(state, ToastComplete())
expect(state).to.equal(nil)
end)
end)
end
@@ -0,0 +1,13 @@
local Modules = game:GetService("CoreGui").RobloxGui.Modules
local ToggleChatPaused = require(Modules.LuaChat.Actions.ToggleChatPaused)
return function(state, action)
state = state or false
if action.type == ToggleChatPaused.name then
state = action.value
end
return state
end
@@ -0,0 +1,21 @@
return function()
local LuaChat = script.Parent.Parent
local ToggleChatPaused = require(script.Parent.ToggleChatPaused)
local ActionToggleChatPaused = require(LuaChat.Actions.ToggleChatPaused)
describe("Action ToggleChatPaused", function()
it("sets the ToggleChatPaused flag", function()
local state = ToggleChatPaused(nil, {})
expect(state).to.equal(false)
state = ToggleChatPaused(state, ActionToggleChatPaused(false))
expect(state).to.equal(false)
state = ToggleChatPaused(state, ActionToggleChatPaused(true))
expect(state).to.equal(true)
end)
end)
end
@@ -0,0 +1,18 @@
local Modules = game:GetService("CoreGui").RobloxGui.Modules
local SetUnreadConversationCount = require(Modules.LuaChat.Actions.SetUnreadConversationCount)
local IncrementUnreadConversationCount = require(Modules.LuaChat.Actions.IncrementUnreadConversationCount)
local DecrementUnreadConversationCount = require(Modules.LuaChat.Actions.DecrementUnreadConversationCount)
return function(state, action)
state = state or 0
if action.type == SetUnreadConversationCount.name then
state = action.count
elseif action.type == IncrementUnreadConversationCount.name then
state = state + 1
elseif action.type == DecrementUnreadConversationCount.name then
state = state - 1
end
return state
end
@@ -0,0 +1,48 @@
return function()
local LuaChat = script.Parent.Parent
local UnreadConversationCount = require(LuaChat.Reducers.UnreadConversationCount)
local SetUnreadConversationCount = require(LuaChat.Actions.SetUnreadConversationCount)
local IncrementUnreadConversationCount = require(LuaChat.Actions.IncrementUnreadConversationCount)
local DecrementUnreadConversationCount = require(LuaChat.Actions.DecrementUnreadConversationCount)
describe("Action SetUnreadConversationCount", function()
it("should set the value of UnreadConversationCount", function()
local state = nil
local action = SetUnreadConversationCount(5)
state = UnreadConversationCount(state, action)
expect(state).to.equal(5)
end)
end)
describe("Action IncrementUnreadConversationCount", function()
it("should increment the value of UnreadConversationCount", function()
local state = nil
local action = SetUnreadConversationCount(5)
state = UnreadConversationCount(state, action)
action = IncrementUnreadConversationCount()
state = UnreadConversationCount(state, action)
expect(state).to.equal(6)
end)
end)
describe("Action DecrementUnreadConversationCount", function()
it("should decrement the value of UnreadConversationCount", function()
local state = nil
local action = SetUnreadConversationCount(5)
state = UnreadConversationCount(state, action)
action = DecrementUnreadConversationCount()
state = UnreadConversationCount(state, action)
expect(state).to.equal(4)
end)
end)
end
@@ -0,0 +1,40 @@
local Modules = game:GetService("CoreGui").RobloxGui.Modules
local ReceivedAllFriends = require(Modules.LuaChat.Actions.ReceivedAllFriends)
local ReceivedUserPresence = require(Modules.LuaChat.Actions.ReceivedUserPresence)
local RequestAllFriends = require(Modules.LuaChat.Actions.RequestAllFriends)
local RequestUserPresence = require(Modules.LuaChat.Actions.RequestUserPresence)
local Immutable = require(Modules.Common.Immutable)
return function(state, action)
state = state or {}
if action.type == RequestAllFriends.name then
return Immutable.JoinDictionaries(state, {
allFriendsIsFetching = true,
})
elseif action.type == ReceivedAllFriends.name then
return Immutable.JoinDictionaries(state, {
allFriendsIsFetching = false,
})
elseif action.type == RequestUserPresence.name then
local userAsync = state[action.userId] or {}
return Immutable.JoinDictionaries(state, {
[action.userId] = Immutable.JoinDictionaries(userAsync, {
presenceIsFetching = true,
}),
})
elseif action.type == ReceivedUserPresence.name then
local userAsync = state[action.userId]
if userAsync then
return Immutable.JoinDictionaries(state, {
[action.userId] = Immutable.JoinDictionaries(userAsync, {
presenceIsFetching = false,
}),
})
end
end
return state
end
@@ -0,0 +1,59 @@
return function()
local Modules = game:GetService("CoreGui").RobloxGui.Modules
local LuaApp = Modules.LuaApp
local LuaChat = Modules.LuaChat
local UsersAsyncReducer = require(script.Parent.UsersAsync)
local User = require(LuaApp.Models.User)
local ReceivedAllFriends = require(LuaChat.Actions.ReceivedAllFriends)
local ReceivedUserPresence = require(LuaChat.Actions.ReceivedUserPresence)
local RequestAllFriends = require(LuaChat.Actions.RequestAllFriends)
local RequestUserPresence = require(LuaChat.Actions.RequestUserPresence)
describe("initial state", function()
it("should return an initial table when passed nil", function()
local state = UsersAsyncReducer(nil, {})
expect(state).to.be.a("table")
end)
end)
describe("RequestAllFriends", function()
it("should set the async state to true", function()
local state = UsersAsyncReducer(nil, {})
state = UsersAsyncReducer(state, RequestAllFriends())
expect(state.allFriendsIsFetching).to.equal(true)
end)
end)
describe("ReceivedAllFriends", function()
it("should set the async state to false", function()
local state = UsersAsyncReducer(nil, {})
state = UsersAsyncReducer(state, ReceivedAllFriends())
expect(state.allFriendsIsFetching).to.equal(false)
end)
end)
describe("RequestUserPresence", function()
it("should set the async state to true", function()
local user = User.mock()
local state = UsersAsyncReducer(nil, {})
state = UsersAsyncReducer(state, RequestUserPresence(user.id))
expect(state[user.id].presenceIsFetching).to.equal(true)
end)
end)
describe("ReceivedUserPresence", function()
it("should set the async state to false", function()
local user = User.mock()
local state = UsersAsyncReducer({[user.id] = {presenceIsFetching = true}}, {})
state = UsersAsyncReducer(state, ReceivedUserPresence(user.id))
expect(state[user.id].presenceIsFetching).to.equal(false)
end)
end)
end