add gs
This commit is contained in:
@@ -0,0 +1,31 @@
|
||||
local Workspace = game:GetService("Workspace")
|
||||
|
||||
local Thunk = require(script.Parent.Parent.Thunk)
|
||||
|
||||
local SetPromptState = require(script.Parent.Parent.Actions.SetPromptState)
|
||||
|
||||
local PromptState = require(script.Parent.Parent.PromptState)
|
||||
|
||||
--[[
|
||||
This delay is used to make sure the animation plays long enough
|
||||
for the player to see that the purchase is happening; it's only
|
||||
for visual effect
|
||||
]]
|
||||
local DELAY = 1
|
||||
|
||||
local function completePurchase()
|
||||
return Thunk.new(script.Name, {}, function(store, services)
|
||||
local startTime = store:getState().purchasingStartTime
|
||||
|
||||
local timeElapsed = startTime - Workspace.DistributedGameTime
|
||||
if timeElapsed >= DELAY then
|
||||
return store:dispatch(SetPromptState(PromptState.PurchaseComplete))
|
||||
else
|
||||
delay(DELAY - timeElapsed, function()
|
||||
return store:dispatch(SetPromptState(PromptState.PurchaseComplete))
|
||||
end)
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
return completePurchase
|
||||
@@ -0,0 +1,71 @@
|
||||
local Players = game:GetService("Players")
|
||||
|
||||
local Promise = require(script.Parent.Parent.Promise)
|
||||
local Thunk = require(script.Parent.Parent.Thunk)
|
||||
|
||||
local Network = require(script.Parent.Parent.Services.Network)
|
||||
local ExternalSettings = require(script.Parent.Parent.Services.ExternalSettings)
|
||||
|
||||
local PurchaseError = require(script.Parent.Parent.PurchaseError)
|
||||
|
||||
local ErrorOccurred = require(script.Parent.Parent.Actions.ErrorOccurred)
|
||||
local SetProduct = require(script.Parent.Parent.Actions.SetProduct)
|
||||
|
||||
local getProductInfo = require(script.Parent.Parent.Network.getProductInfo)
|
||||
local getIsAlreadyOwned = require(script.Parent.Parent.Network.getIsAlreadyOwned)
|
||||
local getAccountInfo = require(script.Parent.Parent.Network.getAccountInfo)
|
||||
|
||||
local resolvePromptState = require(script.Parent.resolvePromptState)
|
||||
|
||||
local requiredServices = {
|
||||
Network,
|
||||
ExternalSettings,
|
||||
}
|
||||
|
||||
local function initiatePurchase(id, infoType, equipIfPurchased)
|
||||
return Thunk.new(script.Name, requiredServices, function(store, services)
|
||||
local network = services[Network]
|
||||
local externalSettings = services[ExternalSettings]
|
||||
|
||||
--[[
|
||||
If a purchase is already in progress, we abort the new one
|
||||
]]
|
||||
if store:getState().product.id ~= nil then
|
||||
return nil
|
||||
end
|
||||
|
||||
store:dispatch(SetProduct(id, infoType, equipIfPurchased))
|
||||
|
||||
local isStudio = externalSettings.isStudio()
|
||||
|
||||
if not isStudio and Players.LocalPlayer.UserId <= 0 then
|
||||
store:dispatch(ErrorOccurred(PurchaseError.Guest))
|
||||
return nil
|
||||
end
|
||||
|
||||
if externalSettings.getFlagOrder66() then
|
||||
store:dispatch(ErrorOccurred(PurchaseError.PurchaseDisabled))
|
||||
return nil
|
||||
end
|
||||
|
||||
return Promise.all({
|
||||
productInfo = getProductInfo(network, id, infoType),
|
||||
accountInfo = getAccountInfo(network, externalSettings),
|
||||
alreadyOwned = getIsAlreadyOwned(network, id, infoType),
|
||||
})
|
||||
:andThen(function(results)
|
||||
-- Once we've finished all of our async data fetching, we'll
|
||||
-- resolve the state of the prompt
|
||||
store:dispatch(resolvePromptState(
|
||||
results.productInfo,
|
||||
results.accountInfo,
|
||||
results.alreadyOwned
|
||||
))
|
||||
end)
|
||||
:catch(function(errorReason)
|
||||
store:dispatch(ErrorOccurred(errorReason))
|
||||
end)
|
||||
end)
|
||||
end
|
||||
|
||||
return initiatePurchase
|
||||
@@ -0,0 +1,68 @@
|
||||
return function()
|
||||
local CorePackages = game:GetService("CorePackages")
|
||||
local Rodux = require(CorePackages.Rodux)
|
||||
|
||||
local Reducer = require(script.Parent.Parent.Reducers.Reducer)
|
||||
|
||||
local MockNetwork = require(script.Parent.Parent.Test.MockNetwork)
|
||||
local MockExternalSettings = require(script.Parent.Parent.Test.MockExternalSettings)
|
||||
|
||||
local Network = require(script.Parent.Parent.Services.Network)
|
||||
local ExternalSettings = require(script.Parent.Parent.Services.ExternalSettings)
|
||||
|
||||
local PromptState = require(script.Parent.Parent.PromptState)
|
||||
local Thunk = require(script.Parent.Parent.Thunk)
|
||||
|
||||
local initiatePurchase = require(script.Parent.initiatePurchase)
|
||||
|
||||
it("should run without errors", function()
|
||||
local store = Rodux.Store.new(Reducer)
|
||||
|
||||
local thunk = initiatePurchase(15, Enum.InfoType.Product, false)
|
||||
|
||||
Thunk.test(thunk, store, {
|
||||
[Network] = MockNetwork.new(),
|
||||
[ExternalSettings] = MockExternalSettings.new(false, false, false, false),
|
||||
})
|
||||
|
||||
local state = store:getState()
|
||||
|
||||
expect(state.product.id).to.equal(15)
|
||||
end)
|
||||
|
||||
it("should abort when a purchase is already in progress", function()
|
||||
local store = Rodux.Store.new(Reducer, {
|
||||
promptState = PromptState.PromptPurchase,
|
||||
product = {
|
||||
id = 12,
|
||||
infoType = Enum.InfoType.Product,
|
||||
}
|
||||
})
|
||||
|
||||
-- Initiate a purchase for a different product id
|
||||
local thunk = initiatePurchase(999, Enum.InfoType.Product, false)
|
||||
|
||||
Thunk.test(thunk, store, {
|
||||
[Network] = MockNetwork.new(),
|
||||
[ExternalSettings] = MockExternalSettings.new(false, false, false, false),
|
||||
})
|
||||
|
||||
local state = store:getState()
|
||||
expect(state.product.id).to.equal(12)
|
||||
expect(state.promptState).to.equal(PromptState.PromptPurchase)
|
||||
end)
|
||||
|
||||
it("should resolve to an error state if a network failure occurs", function()
|
||||
local store = Rodux.Store.new(Reducer)
|
||||
|
||||
local thunk = initiatePurchase(15, Enum.InfoType.Product, false)
|
||||
|
||||
Thunk.test(thunk, store, {
|
||||
[Network] = MockNetwork.new(true),
|
||||
[ExternalSettings] = MockExternalSettings.new(false, false, false, false),
|
||||
})
|
||||
|
||||
local state = store:getState()
|
||||
expect(state.promptState).to.equal(PromptState.Error)
|
||||
end)
|
||||
end
|
||||
@@ -0,0 +1,28 @@
|
||||
local Thunk = require(script.Parent.Parent.Thunk)
|
||||
local PlatformInterface = require(script.Parent.Parent.Services.PlatformInterface)
|
||||
local ExternalSettings = require(script.Parent.Parent.Services.ExternalSettings)
|
||||
|
||||
local PromptState = require(script.Parent.Parent.PromptState)
|
||||
|
||||
local SetPromptState = require(script.Parent.Parent.Actions.SetPromptState)
|
||||
|
||||
local requiredServices = {
|
||||
ExternalSettings,
|
||||
PlatformInterface,
|
||||
}
|
||||
|
||||
local function launchBuildersClubUpsell()
|
||||
return Thunk.new(script.Name, requiredServices, function(store, services)
|
||||
local externalSettings = services[ExternalSettings]
|
||||
local platformInterface = services[PlatformInterface]
|
||||
|
||||
if externalSettings.isStudio() then
|
||||
return
|
||||
end
|
||||
|
||||
platformInterface.startBuildersClubUpsellWeb()
|
||||
store:dispatch(SetPromptState(PromptState.UpsellInProgress))
|
||||
end)
|
||||
end
|
||||
|
||||
return launchBuildersClubUpsell
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
return function()
|
||||
local CorePackages = game:GetService("CorePackages")
|
||||
local Rodux = require(CorePackages.Rodux)
|
||||
|
||||
local Reducer = require(script.Parent.Parent.Reducers.Reducer)
|
||||
|
||||
local MockPlatformInterface = require(script.Parent.Parent.Test.MockPlatformInterface)
|
||||
local MockExternalSettings = require(script.Parent.Parent.Test.MockExternalSettings)
|
||||
|
||||
local PlatformInterface = require(script.Parent.Parent.Services.PlatformInterface)
|
||||
local ExternalSettings = require(script.Parent.Parent.Services.ExternalSettings)
|
||||
|
||||
local PromptState = require(script.Parent.Parent.PromptState)
|
||||
local Thunk = require(script.Parent.Parent.Thunk)
|
||||
|
||||
local launchBuildersClubUpsell = require(script.Parent.launchBuildersClubUpsell)
|
||||
|
||||
it("should run without errors", function()
|
||||
local store = Rodux.Store.new(Reducer)
|
||||
|
||||
local thunk = launchBuildersClubUpsell()
|
||||
local externalSettings = MockExternalSettings.new(false, false, false, false)
|
||||
local platformInterface = MockPlatformInterface.new()
|
||||
|
||||
Thunk.test(thunk, store, {
|
||||
[ExternalSettings] = externalSettings,
|
||||
[PlatformInterface] = platformInterface,
|
||||
})
|
||||
|
||||
local state = store:getState()
|
||||
|
||||
expect(platformInterface.startBuildersClubUpsellWeb_callCount).to.equal(1)
|
||||
expect(state.promptState).to.equal(PromptState.UpsellInProgress)
|
||||
end)
|
||||
end
|
||||
@@ -0,0 +1,60 @@
|
||||
local Players = game:GetService("Players")
|
||||
local UserInputService = game:GetService("UserInputService")
|
||||
|
||||
local Thunk = require(script.Parent.Parent.Thunk)
|
||||
local Promise = require(script.Parent.Parent.Promise)
|
||||
|
||||
local UpsellFlow = require(script.Parent.Parent.UpsellFlow)
|
||||
local PromptState = require(script.Parent.Parent.PromptState)
|
||||
|
||||
local SetPromptState = require(script.Parent.Parent.Actions.SetPromptState)
|
||||
|
||||
local Analytics = require(script.Parent.Parent.Services.Analytics)
|
||||
local PlatformInterface = require(script.Parent.Parent.Services.PlatformInterface)
|
||||
|
||||
local getUpsellFlow = require(script.Parent.Parent.NativeUpsell.getUpsellFlow)
|
||||
local retryAfterUpsell = require(script.Parent.retryAfterUpsell)
|
||||
|
||||
local requiredServices = {
|
||||
Analytics,
|
||||
PlatformInterface,
|
||||
}
|
||||
|
||||
local function launchRobuxUpsell()
|
||||
return Thunk.new(script.Name, requiredServices, function(store, services)
|
||||
local analytics = services[Analytics]
|
||||
local platformInterface = services[PlatformInterface]
|
||||
|
||||
local upsellFlow = getUpsellFlow(UserInputService:GetPlatform())
|
||||
|
||||
if upsellFlow == UpsellFlow.Web then
|
||||
platformInterface.startRobuxUpsellWeb()
|
||||
analytics.reportRobuxUpsellStarted()
|
||||
store:dispatch(SetPromptState(PromptState.UpsellInProgress))
|
||||
|
||||
elseif upsellFlow == UpsellFlow.Mobile then
|
||||
local nativeProductId = store:getState().nativeUpsell.robuxProductId
|
||||
|
||||
platformInterface.promptNativePurchase(Players.LocalPlayer, nativeProductId)
|
||||
store:dispatch(SetPromptState(PromptState.UpsellInProgress))
|
||||
|
||||
elseif upsellFlow == UpsellFlow.Xbox then
|
||||
local nativeProductId = store:getState().nativeUpsell.robuxProductId
|
||||
store:dispatch(SetPromptState(PromptState.UpsellInProgress))
|
||||
return Promise.new(function(resolve, reject)
|
||||
local platformPurchaseResult = platformInterface.beginPlatformStorePurchase(nativeProductId)
|
||||
|
||||
Promise.resolve(platformPurchaseResult)
|
||||
end)
|
||||
:andThen(function(result)
|
||||
if result ~= 0 then
|
||||
store:dispatch(retryAfterUpsell)
|
||||
end
|
||||
end)
|
||||
else
|
||||
warn("Need more Robux: platform not supported for Robux purchase")
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
return launchRobuxUpsell
|
||||
@@ -0,0 +1,36 @@
|
||||
return function()
|
||||
local CorePackages = game:GetService("CorePackages")
|
||||
local Rodux = require(CorePackages.Rodux)
|
||||
|
||||
local Reducer = require(script.Parent.Parent.Reducers.Reducer)
|
||||
|
||||
local MockAnalytics = require(script.Parent.Parent.Test.MockAnalytics)
|
||||
local MockPlatformInterface = require(script.Parent.Parent.Test.MockPlatformInterface)
|
||||
|
||||
local Analytics = require(script.Parent.Parent.Services.Analytics)
|
||||
local PlatformInterface = require(script.Parent.Parent.Services.PlatformInterface)
|
||||
|
||||
local PromptState = require(script.Parent.Parent.PromptState)
|
||||
local Thunk = require(script.Parent.Parent.Thunk)
|
||||
|
||||
local launchRobuxUpsell = require(script.Parent.launchRobuxUpsell)
|
||||
|
||||
it("should run without errors", function()
|
||||
local store = Rodux.Store.new(Reducer)
|
||||
|
||||
local thunk = launchRobuxUpsell()
|
||||
local analytics = MockAnalytics.new()
|
||||
local platformInterface = MockPlatformInterface.new()
|
||||
|
||||
Thunk.test(thunk, store, {
|
||||
[Analytics] = analytics,
|
||||
[PlatformInterface] = platformInterface,
|
||||
})
|
||||
|
||||
local state = store:getState()
|
||||
|
||||
expect(analytics.reportRobuxUpsellStarted_callCount).to.equal(1)
|
||||
expect(platformInterface.startRobuxUpsellWeb_callCount).to.equal(1)
|
||||
expect(state.promptState).to.equal(PromptState.UpsellInProgress)
|
||||
end)
|
||||
end
|
||||
@@ -0,0 +1,74 @@
|
||||
local HttpService = game:GetService("HttpService")
|
||||
local Workspace = game:GetService("Workspace")
|
||||
local Players = game:GetService("Players")
|
||||
|
||||
local Thunk = require(script.Parent.Parent.Thunk)
|
||||
local Promise = require(script.Parent.Parent.Promise)
|
||||
|
||||
local Network = require(script.Parent.Parent.Services.Network)
|
||||
local Analytics = require(script.Parent.Parent.Services.Analytics)
|
||||
|
||||
local StartPurchase = require(script.Parent.Parent.Actions.StartPurchase)
|
||||
local ErrorOccurred = require(script.Parent.Parent.Actions.ErrorOccurred)
|
||||
|
||||
local getToolAsset = require(script.Parent.Parent.Network.getToolAsset)
|
||||
|
||||
local completePurchase = require(script.Parent.completePurchase)
|
||||
|
||||
local performPurchase = require(script.Parent.Parent.Network.performPurchase)
|
||||
|
||||
-- Only tools can be equipped on purchase
|
||||
local ASSET_TYPE_TOOL = 19
|
||||
|
||||
local requiredServices = {
|
||||
Network,
|
||||
Analytics,
|
||||
}
|
||||
|
||||
local function purchaseItem()
|
||||
return Thunk.new(script.Name, requiredServices, function(store, services)
|
||||
local network = services[Network]
|
||||
local analytics = services[Analytics]
|
||||
|
||||
store:dispatch(StartPurchase(Workspace.DistributedGameTime))
|
||||
|
||||
local state = store:getState()
|
||||
|
||||
local requestId = HttpService:GenerateGUID(false)
|
||||
|
||||
local id = state.product.id
|
||||
local infoType = state.product.infoType
|
||||
local equipIfPurchased = state.product.equipIfPurchased
|
||||
|
||||
local salePrice = state.productInfo.price
|
||||
local assetTypeId = state.productInfo.assetTypeId
|
||||
local productId = state.productInfo.productId
|
||||
|
||||
return performPurchase(network, infoType, productId, salePrice, requestId)
|
||||
:andThen(function(result)
|
||||
--[[
|
||||
If the purchase was successful, we signal success,
|
||||
record analytics, and equip the item if needed
|
||||
]]
|
||||
store:dispatch(completePurchase())
|
||||
|
||||
analytics.signalPurchaseSuccess(id, infoType, salePrice, result)
|
||||
|
||||
if equipIfPurchased and assetTypeId == ASSET_TYPE_TOOL then
|
||||
return getToolAsset(network, id)
|
||||
:andThen(function(tool)
|
||||
if tool then
|
||||
tool.Parent = Players.LocalPlayer.Backpack
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
return Promise.resolve()
|
||||
end)
|
||||
:catch(function(errorReason)
|
||||
store:dispatch(ErrorOccurred(errorReason))
|
||||
end)
|
||||
end)
|
||||
end
|
||||
|
||||
return purchaseItem
|
||||
@@ -0,0 +1,53 @@
|
||||
return function()
|
||||
local CorePackages = game:GetService("CorePackages")
|
||||
local Rodux = require(CorePackages.Rodux)
|
||||
|
||||
local Reducer = require(script.Parent.Parent.Reducers.Reducer)
|
||||
|
||||
local MockNetwork = require(script.Parent.Parent.Test.MockNetwork)
|
||||
local MockAnalytics = require(script.Parent.Parent.Test.MockAnalytics)
|
||||
|
||||
local Network = require(script.Parent.Parent.Services.Network)
|
||||
local Analytics = require(script.Parent.Parent.Services.Analytics)
|
||||
|
||||
local PromptState = require(script.Parent.Parent.PromptState)
|
||||
local Thunk = require(script.Parent.Parent.Thunk)
|
||||
|
||||
local purchaseItem = require(script.Parent.purchaseItem)
|
||||
|
||||
it("should run without errors", function()
|
||||
local store = Rodux.Store.new(Reducer)
|
||||
|
||||
local thunk = purchaseItem()
|
||||
local network = MockNetwork.new()
|
||||
local analytics = MockAnalytics.new()
|
||||
|
||||
Thunk.test(thunk, store, {
|
||||
[Network] = network,
|
||||
[Analytics] = analytics,
|
||||
})
|
||||
|
||||
local state = store:getState()
|
||||
|
||||
expect(analytics.signalPurchaseSuccess_callCount).to.equal(1)
|
||||
expect(state.promptState).to.equal(PromptState.PurchaseInProgress)
|
||||
end)
|
||||
|
||||
it("should resolve to an error state if a network error occurs", function()
|
||||
local store = Rodux.Store.new(Reducer)
|
||||
|
||||
local thunk = purchaseItem()
|
||||
local network = MockNetwork.new(true)
|
||||
local analytics = MockAnalytics.new()
|
||||
|
||||
Thunk.test(thunk, store, {
|
||||
[Network] = network,
|
||||
[Analytics] = analytics,
|
||||
})
|
||||
|
||||
local state = store:getState()
|
||||
|
||||
expect(analytics.signalPurchaseSuccess_callCount).to.equal(0)
|
||||
expect(state.promptState).to.equal(PromptState.Error)
|
||||
end)
|
||||
end
|
||||
@@ -0,0 +1,78 @@
|
||||
local UserInputService = game:GetService("UserInputService")
|
||||
|
||||
local Thunk = require(script.Parent.Parent.Thunk)
|
||||
|
||||
local ExternalSettings = require(script.Parent.Parent.Services.ExternalSettings)
|
||||
|
||||
local PromptState = require(script.Parent.Parent.PromptState)
|
||||
local PurchaseError = require(script.Parent.Parent.PurchaseError)
|
||||
local UpsellFlow = require(script.Parent.Parent.UpsellFlow)
|
||||
|
||||
local SetPromptState = require(script.Parent.Parent.Actions.SetPromptState)
|
||||
local ProductInfoReceived = require(script.Parent.Parent.Actions.ProductInfoReceived)
|
||||
local AccountInfoReceived = require(script.Parent.Parent.Actions.AccountInfoReceived)
|
||||
local ItemCannotBePurchased = require(script.Parent.Parent.Actions.ItemCannotBePurchased)
|
||||
local PromptNativeUpsell = require(script.Parent.Parent.Actions.PromptNativeUpsell)
|
||||
|
||||
local selectRobuxProduct = require(script.Parent.Parent.NativeUpsell.selectRobuxProduct)
|
||||
local getUpsellFlow = require(script.Parent.Parent.NativeUpsell.getUpsellFlow)
|
||||
|
||||
local meetsPrerequisites = require(script.Parent.Parent.meetsPrerequisites)
|
||||
|
||||
local requiredServices = {
|
||||
ExternalSettings,
|
||||
}
|
||||
|
||||
local function resolvePromptState(productInfo, accountInfo, alreadyOwned)
|
||||
return Thunk.new(script.Name, requiredServices, function(store, services)
|
||||
local externalSettings = services[ExternalSettings]
|
||||
|
||||
store:dispatch(ProductInfoReceived(productInfo))
|
||||
store:dispatch(AccountInfoReceived(accountInfo))
|
||||
|
||||
local restrictThirdParty = externalSettings.getFlagRestrictSales2()
|
||||
|
||||
local canPurchase, failureReason = meetsPrerequisites(productInfo, alreadyOwned, restrictThirdParty)
|
||||
if not canPurchase then
|
||||
return store:dispatch(ItemCannotBePurchased(failureReason))
|
||||
end
|
||||
|
||||
-- Price may be nil if the item is free
|
||||
local price = productInfo.PriceInRobux or 0
|
||||
local platform = UserInputService:GetPlatform()
|
||||
local upsellFlow = getUpsellFlow(platform)
|
||||
|
||||
if productInfo.MinimumMembershipLevel > accountInfo.MembershipType then
|
||||
|
||||
if upsellFlow == UpsellFlow.Web then
|
||||
return store:dispatch(SetPromptState(PromptState.BuildersClubUpsell))
|
||||
else
|
||||
return store:dispatch(SetPromptState(PurchaseError.BuildersClubLevelTooLow))
|
||||
end
|
||||
|
||||
elseif price > accountInfo.RobuxBalance then
|
||||
|
||||
if upsellFlow == UpsellFlow.Web then
|
||||
return store:dispatch(SetPromptState(PromptState.RobuxUpsell))
|
||||
else
|
||||
local hasBuildersClub = accountInfo.MembershipType > 0
|
||||
return selectRobuxProduct(platform, price, hasBuildersClub)
|
||||
:andThen(function(product)
|
||||
-- We found a valid upsell product for the current platform
|
||||
store:dispatch(PromptNativeUpsell(product.productId, product.robuxValue))
|
||||
end, function()
|
||||
-- No upsell item will provide sufficient funds to make this purchase
|
||||
if platform == Enum.Platform.XBoxOne then
|
||||
store:dispatch(ItemCannotBePurchased(PurchaseError.NotEnoughRobuxXbox))
|
||||
else
|
||||
store:dispatch(ItemCannotBePurchased(PurchaseError.NotEnoughRobux))
|
||||
end
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
return store:dispatch(SetPromptState(PromptState.PromptPurchase))
|
||||
end)
|
||||
end
|
||||
|
||||
return resolvePromptState
|
||||
@@ -0,0 +1,125 @@
|
||||
return function()
|
||||
local CorePackages = game:GetService("CorePackages")
|
||||
local Rodux = require(CorePackages.Rodux)
|
||||
|
||||
local Reducer = require(script.Parent.Parent.Reducers.Reducer)
|
||||
|
||||
local ExternalSettings = require(script.Parent.Parent.Services.ExternalSettings)
|
||||
|
||||
local MockExternalSettings = require(script.Parent.Parent.Test.MockExternalSettings)
|
||||
|
||||
local PromptState = require(script.Parent.Parent.PromptState)
|
||||
local Thunk = require(script.Parent.Parent.Thunk)
|
||||
|
||||
local resolvePromptState = require(script.Parent.resolvePromptState)
|
||||
|
||||
local function getTestProductInfo()
|
||||
return {
|
||||
IsForSale = true,
|
||||
Name = "Test Product",
|
||||
PriceInRobux = 10,
|
||||
MinimumMembershipLevel = 0,
|
||||
}
|
||||
end
|
||||
|
||||
it("should populate store with provided info", function()
|
||||
local store = Rodux.Store.new(Reducer, {})
|
||||
|
||||
local productInfo = getTestProductInfo()
|
||||
local accountInfo = {
|
||||
RobuxBalance = 10,
|
||||
MembershipType = 0,
|
||||
}
|
||||
local thunk = resolvePromptState(productInfo, accountInfo, false)
|
||||
|
||||
Thunk.test(thunk, store, {
|
||||
[ExternalSettings] = MockExternalSettings.new(false, false, false, false)
|
||||
})
|
||||
|
||||
local state = store:getState()
|
||||
|
||||
expect(state.productInfo.name).to.be.ok()
|
||||
expect(state.accountInfo.balance).to.be.ok()
|
||||
end)
|
||||
|
||||
it("should resolve state to CannotPurchase if prerequisites are failed", function()
|
||||
local store = Rodux.Store.new(Reducer, {})
|
||||
|
||||
local productInfo = getTestProductInfo()
|
||||
-- Set product to not for sale
|
||||
productInfo.IsForSale = false
|
||||
local accountInfo = {
|
||||
RobuxBalance = 10,
|
||||
MembershipType = 0,
|
||||
}
|
||||
local thunk = resolvePromptState(productInfo, accountInfo, false)
|
||||
|
||||
Thunk.test(thunk, store, {
|
||||
[ExternalSettings] = MockExternalSettings.new(false, false, false, false)
|
||||
})
|
||||
|
||||
local state = store:getState()
|
||||
|
||||
expect(state.promptState).to.equal(PromptState.CannotPurchase)
|
||||
end)
|
||||
|
||||
it("should resolve state to PromptPurchase if account meets requirements", function()
|
||||
local store = Rodux.Store.new(Reducer, {})
|
||||
|
||||
local productInfo = getTestProductInfo()
|
||||
local accountInfo = {
|
||||
RobuxBalance = 10,
|
||||
MembershipType = 0,
|
||||
}
|
||||
local thunk = resolvePromptState(productInfo, accountInfo, false)
|
||||
|
||||
Thunk.test(thunk, store, {
|
||||
[ExternalSettings] = MockExternalSettings.new(false, false, false, false)
|
||||
})
|
||||
|
||||
local state = store:getState()
|
||||
|
||||
expect(state.promptState).to.equal(PromptState.PromptPurchase)
|
||||
end)
|
||||
|
||||
it("should resolve state to RobuxUpsell if account is short on Robux", function()
|
||||
local store = Rodux.Store.new(Reducer, {})
|
||||
|
||||
local productInfo = getTestProductInfo()
|
||||
-- Player will not have enough robux
|
||||
local accountInfo = {
|
||||
RobuxBalance = 0,
|
||||
MembershipType = 0,
|
||||
}
|
||||
local thunk = resolvePromptState(productInfo, accountInfo, false)
|
||||
|
||||
Thunk.test(thunk, store, {
|
||||
[ExternalSettings] = MockExternalSettings.new(false, false, false, false)
|
||||
})
|
||||
|
||||
local state = store:getState()
|
||||
|
||||
expect(state.promptState).to.equal(PromptState.RobuxUpsell)
|
||||
end)
|
||||
|
||||
it("should resolve state to BuildersClubUpsell if account has insufficient bc level", function()
|
||||
local store = Rodux.Store.new(Reducer, {})
|
||||
|
||||
local productInfo = getTestProductInfo()
|
||||
-- Player does not have the sufficient BC level
|
||||
productInfo.MinimumMembershipLevel = 3
|
||||
local accountInfo = {
|
||||
RobuxBalance = 0,
|
||||
MembershipType = 0,
|
||||
}
|
||||
local thunk = resolvePromptState(productInfo, accountInfo, false)
|
||||
|
||||
Thunk.test(thunk, store, {
|
||||
[ExternalSettings] = MockExternalSettings.new(false, false, false, false)
|
||||
})
|
||||
|
||||
local state = store:getState()
|
||||
|
||||
expect(state.promptState).to.equal(PromptState.BuildersClubUpsell)
|
||||
end)
|
||||
end
|
||||
@@ -0,0 +1,75 @@
|
||||
local Thunk = require(script.Parent.Parent.Thunk)
|
||||
|
||||
local PurchaseError = require(script.Parent.Parent.PurchaseError)
|
||||
|
||||
local Network = require(script.Parent.Parent.Services.Network)
|
||||
local ExternalSettings = require(script.Parent.Parent.Services.ExternalSettings)
|
||||
|
||||
local AccountInfoReceived = require(script.Parent.Parent.Actions.AccountInfoReceived)
|
||||
local ErrorOccurred = require(script.Parent.Parent.Actions.ErrorOccurred)
|
||||
|
||||
local getAccountInfo = require(script.Parent.Parent.Network.getAccountInfo)
|
||||
|
||||
local purchaseItem = require(script.Parent.purchaseItem)
|
||||
|
||||
local MAX_RETRIES = 3
|
||||
local RETRY_RATE = 1
|
||||
|
||||
local requiredServices = {
|
||||
Network,
|
||||
ExternalSettings,
|
||||
}
|
||||
|
||||
local function retryAfterUpsell(retriesRemaining)
|
||||
retriesRemaining = retriesRemaining or MAX_RETRIES
|
||||
|
||||
return Thunk.new(script.Name, requiredServices, function(store, services)
|
||||
local network = services[Network]
|
||||
local externalSettings = services[ExternalSettings]
|
||||
|
||||
return getAccountInfo(network, externalSettings)
|
||||
:andThen(function(accountInfo)
|
||||
local state = store:getState()
|
||||
|
||||
local price = state.productInfo.price
|
||||
local minimumBCLevel = state.productInfo.bcLevelRequired
|
||||
|
||||
local balance = accountInfo.RobuxBalance
|
||||
local membershipLevel = accountInfo.MembershipType
|
||||
|
||||
store:dispatch(AccountInfoReceived(accountInfo))
|
||||
|
||||
if price ~= nil and price > balance then
|
||||
if retriesRemaining > 0 then
|
||||
-- Upsell result may not yet have propagated, so we need to
|
||||
-- wait a while and try again
|
||||
delay(RETRY_RATE, function()
|
||||
store:dispatch(retryAfterUpsell(retriesRemaining - 1))
|
||||
end)
|
||||
else
|
||||
store:dispatch(ErrorOccurred(PurchaseError.InvalidFunds))
|
||||
end
|
||||
|
||||
elseif minimumBCLevel > membershipLevel then
|
||||
if retriesRemaining > 0 then
|
||||
-- Upsell result may not yet have propagated, so we need to
|
||||
-- wait a while and try again
|
||||
delay(RETRY_RATE, function()
|
||||
store:dispatch(retryAfterUpsell(retriesRemaining - 1))
|
||||
end)
|
||||
else
|
||||
store:dispatch(ErrorOccurred(PurchaseError.BuildersClubUpsellFailure))
|
||||
end
|
||||
|
||||
else
|
||||
-- Upsell was successful and purchase can now be completed
|
||||
store:dispatch(purchaseItem())
|
||||
end
|
||||
end)
|
||||
:catch(function(error)
|
||||
store:dispatch(ErrorOccurred(error))
|
||||
end)
|
||||
end)
|
||||
end
|
||||
|
||||
return retryAfterUpsell
|
||||
@@ -0,0 +1,44 @@
|
||||
return function()
|
||||
local CorePackages = game:GetService("CorePackages")
|
||||
local Rodux = require(CorePackages.Rodux)
|
||||
|
||||
local Reducer = require(script.Parent.Parent.Reducers.Reducer)
|
||||
|
||||
local MockNetwork = require(script.Parent.Parent.Test.MockNetwork)
|
||||
local MockExternalSettings = require(script.Parent.Parent.Test.MockExternalSettings)
|
||||
|
||||
local Network = require(script.Parent.Parent.Services.Network)
|
||||
local ExternalSettings = require(script.Parent.Parent.Services.ExternalSettings)
|
||||
|
||||
local Thunk = require(script.Parent.Parent.Thunk)
|
||||
|
||||
local retryAfterUpsell = require(script.Parent.retryAfterUpsell)
|
||||
|
||||
it("should run without errors", function()
|
||||
local store = Rodux.Store.new(Reducer, {
|
||||
productInfo = {
|
||||
price = 0,
|
||||
bcLevelRequired = 0,
|
||||
}
|
||||
})
|
||||
|
||||
local thunk = retryAfterUpsell()
|
||||
local network = MockNetwork.new()
|
||||
local externalSettings = MockExternalSettings.new(true, false, false, false)
|
||||
|
||||
Thunk.test(thunk, store, {
|
||||
[Network] = network,
|
||||
[ExternalSettings] = externalSettings,
|
||||
})
|
||||
|
||||
local state = store:getState()
|
||||
local accountInfo
|
||||
network.getAccountInfo():andThen(function(result)
|
||||
accountInfo = result
|
||||
end)
|
||||
|
||||
-- Account info should be re-populated
|
||||
expect(state.accountInfo.balance).to.be.equal(accountInfo.RobuxBalance)
|
||||
expect(state.accountInfo.bcLevel).to.be.equal(accountInfo.MembershipType)
|
||||
end)
|
||||
end
|
||||
Reference in New Issue
Block a user