add gs
This commit is contained in:
+126
@@ -0,0 +1,126 @@
|
||||
local CorePackages = game:GetService("CorePackages")
|
||||
local UserInputService = game:GetService("UserInputService")
|
||||
|
||||
local Roact = require(CorePackages.Roact)
|
||||
|
||||
local connectToStore = require(script.Parent.Parent.Parent.connectToStore)
|
||||
|
||||
local LocalizationService = require(script.Parent.Parent.Parent.Localization.LocalizationService)
|
||||
|
||||
local PromptState = require(script.Parent.Parent.Parent.PromptState)
|
||||
local UpsellFlow = require(script.Parent.Parent.Parent.UpsellFlow)
|
||||
|
||||
local TextLocalizer = require(script.Parent.Parent.Connection.TextLocalizer)
|
||||
|
||||
local withLayoutValues = require(script.Parent.Parent.Connection.withLayoutValues)
|
||||
|
||||
local getUpsellFlow = require(script.Parent.Parent.Parent.NativeUpsell.getUpsellFlow)
|
||||
local isMockingPurchases = require(script.Parent.Parent.Parent.isMockingPurchases)
|
||||
|
||||
local PURCHASE_DETAILS_KEY = "CoreScripts.PurchasePrompt.PurchaseDetails.%s"
|
||||
|
||||
local function AdditionalDetailLabel(props)
|
||||
return withLayoutValues(function(values)
|
||||
local layoutOrder = props.layoutOrder
|
||||
local messageKey = props.messageKey
|
||||
local messageParams = props.messageParams
|
||||
|
||||
if messageKey == nil then
|
||||
-- We return an empty frame to preserve UIListLayout spacing
|
||||
return Roact.createElement("Frame", {
|
||||
LayoutOrder = layoutOrder,
|
||||
Size = values.Size.AdditonalDetailsLabel,
|
||||
BackgroundTransparency = 1,
|
||||
BorderSizePixel = 0,
|
||||
})
|
||||
end
|
||||
|
||||
return Roact.createElement(TextLocalizer, {
|
||||
key = messageKey,
|
||||
params = messageParams,
|
||||
render = function(localizedText)
|
||||
return Roact.createElement("TextLabel", {
|
||||
Text = localizedText,
|
||||
LayoutOrder = layoutOrder,
|
||||
Size = values.Size.AdditonalDetailsLabel,
|
||||
BackgroundTransparency = 1,
|
||||
BorderSizePixel = 0,
|
||||
TextColor3 = Color3.new(1, 1, 1),
|
||||
Font = Enum.Font.SourceSans,
|
||||
TextSize = values.TextSize.AdditonalDetails,
|
||||
TextYAlignment = Enum.TextYAlignment.Top,
|
||||
TextScaled = true,
|
||||
TextWrapped = true,
|
||||
}, {
|
||||
TextSizeConstraint = Roact.createElement("UITextSizeConstraint", {
|
||||
MaxTextSize = values.TextSize.AdditonalDetails,
|
||||
})
|
||||
})
|
||||
end,
|
||||
})
|
||||
end)
|
||||
end
|
||||
|
||||
local function mapStateToProps(state)
|
||||
local promptState = state.promptState
|
||||
|
||||
local messageKey = nil
|
||||
local messageParams = nil
|
||||
|
||||
local price = state.productInfo.price
|
||||
local balance = state.accountInfo.balance
|
||||
|
||||
if promptState == PromptState.PromptPurchase then
|
||||
if price == 0 then
|
||||
messageKey = PURCHASE_DETAILS_KEY:format("BalanceUnaffected")
|
||||
elseif isMockingPurchases() then
|
||||
messageKey = PURCHASE_DETAILS_KEY:format("MockPurchase")
|
||||
else
|
||||
messageKey = PURCHASE_DETAILS_KEY:format("BalanceFuture")
|
||||
messageParams = {
|
||||
BALANCE_FUTURE = LocalizationService.numberParam(balance - price),
|
||||
}
|
||||
end
|
||||
elseif promptState == PromptState.RobuxUpsell then
|
||||
local upsellFlow = getUpsellFlow(UserInputService:GetPlatform())
|
||||
|
||||
if upsellFlow ~= UpsellFlow.Web then
|
||||
local upsellRobux = state.nativeUpsell.robuxPurchaseAmount
|
||||
local amountNeeded = price - balance
|
||||
|
||||
local amountRemaining = upsellRobux - amountNeeded
|
||||
messageKey = PURCHASE_DETAILS_KEY:format("RemainingAfterUpsell")
|
||||
messageParams = {
|
||||
REMAINING_ROBUX = LocalizationService.numberParam(amountRemaining),
|
||||
}
|
||||
end
|
||||
elseif promptState == PromptState.BuildersClubUpsell then
|
||||
local bcLevelRequired = state.productInfo.bcLevelRequired
|
||||
messageKey = PURCHASE_DETAILS_KEY:format("InvalidBuildersClub")
|
||||
messageParams = {
|
||||
BC_LEVEL = LocalizationService.nestedKeyParam(
|
||||
LocalizationService.getBuildersClubLevelKey(bcLevelRequired)
|
||||
)
|
||||
}
|
||||
elseif promptState == PromptState.PurchaseComplete then
|
||||
if isMockingPurchases() then
|
||||
messageKey = PURCHASE_DETAILS_KEY:format("MockPurchaseComplete")
|
||||
else
|
||||
messageKey = PURCHASE_DETAILS_KEY:format("BalanceNow")
|
||||
messageParams = {
|
||||
BALANCE_NOW = LocalizationService.numberParam(balance - price),
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
return {
|
||||
messageKey = messageKey,
|
||||
messageParams = messageParams,
|
||||
}
|
||||
end
|
||||
|
||||
AdditionalDetailLabel = connectToStore(
|
||||
mapStateToProps
|
||||
)(AdditionalDetailLabel)
|
||||
|
||||
return AdditionalDetailLabel
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
return function()
|
||||
local CorePackages = game:GetService("CorePackages")
|
||||
local Roact = require(CorePackages.Roact)
|
||||
|
||||
local UnitTestContainer = require(script.Parent.Parent.Parent.Test.UnitTestContainer)
|
||||
|
||||
local AdditionalDetailLabel = require(script.Parent.AdditionalDetailLabel)
|
||||
|
||||
AdditionalDetailLabel = AdditionalDetailLabel.getUnconnected()
|
||||
|
||||
it("should create and destroy without errors", function()
|
||||
local element = Roact.createElement(UnitTestContainer, nil, {
|
||||
Roact.createElement(AdditionalDetailLabel, {
|
||||
layoutOrder = 1,
|
||||
messageKey = "test",
|
||||
})
|
||||
})
|
||||
|
||||
local instance = Roact.mount(element)
|
||||
Roact.unmount(instance)
|
||||
end)
|
||||
|
||||
it("should create and destroy without errors when showing no text", function()
|
||||
local emptyMessageElement = Roact.createElement(UnitTestContainer, nil, {
|
||||
Roact.createElement(AdditionalDetailLabel, {
|
||||
layoutOrder = 1,
|
||||
})
|
||||
})
|
||||
|
||||
local instance = Roact.mount(emptyMessageElement)
|
||||
Roact.unmount(instance)
|
||||
end)
|
||||
end
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
local CorePackages = game:GetService("CorePackages")
|
||||
|
||||
local Roact = require(CorePackages.Roact)
|
||||
|
||||
local GRAY = Color3.fromRGB(184, 184, 184)
|
||||
local BLUE = Color3.fromRGB(0, 162, 255)
|
||||
|
||||
local function Dot(props)
|
||||
local layoutOrder = props.layoutOrder
|
||||
local time = props.time
|
||||
local size = 0.8
|
||||
local color = GRAY
|
||||
|
||||
if time >= layoutOrder -1 and time <= layoutOrder then
|
||||
local animationProgress = math.sin(math.pi * (time % 1))
|
||||
size = size + (1 - size) * animationProgress
|
||||
color = GRAY:lerp(BLUE, animationProgress)
|
||||
end
|
||||
|
||||
return Roact.createElement("Frame", {
|
||||
Size = UDim2.new(1/3, 0, 1, 0),
|
||||
BackgroundTransparency = 1,
|
||||
BorderSizePixel = 0,
|
||||
LayoutOrder = layoutOrder,
|
||||
}, {
|
||||
Dot = Roact.createElement("Frame", {
|
||||
Size = UDim2.new(0.7, 0, size, 0),
|
||||
SizeConstraint = Enum.SizeConstraint.RelativeYY,
|
||||
AnchorPoint = Vector2.new(0.5, 0.5),
|
||||
Position = UDim2.new(0.5, 0, 0.5, 0),
|
||||
BackgroundColor3 = color,
|
||||
BorderSizePixel = 0,
|
||||
})
|
||||
})
|
||||
end
|
||||
|
||||
return Dot
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
return function()
|
||||
local CorePackages = game:GetService("CorePackages")
|
||||
local Roact = require(CorePackages.Roact)
|
||||
|
||||
local AnimatedDot = require(script.Parent.AnimatedDot)
|
||||
|
||||
it("should create and destroy without errors", function()
|
||||
local element = Roact.createElement(AnimatedDot, {
|
||||
time = 1,
|
||||
layoutOrder = 1,
|
||||
})
|
||||
|
||||
local instance = Roact.mount(element)
|
||||
Roact.unmount(instance)
|
||||
end)
|
||||
end
|
||||
+81
@@ -0,0 +1,81 @@
|
||||
local CorePackages = game:GetService("CorePackages")
|
||||
|
||||
local Roact = require(CorePackages.Roact)
|
||||
local join = require(script.Parent.Parent.Parent.join)
|
||||
|
||||
local AutoResizeList = Roact.Component:extend("AutoResizeList")
|
||||
|
||||
function AutoResizeList:init()
|
||||
self.containerRef = Roact.createRef()
|
||||
self.listRef = Roact.createRef()
|
||||
|
||||
self.contentSizeCallback = function()
|
||||
if self.listRef.current and self.containerRef.current then
|
||||
self:resizeContainer()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function AutoResizeList:didMount()
|
||||
self:resizeContainer()
|
||||
end
|
||||
|
||||
function AutoResizeList:resizeContainer()
|
||||
self.containerRef.current.Size = UDim2.new(
|
||||
0, self.listRef.current.AbsoluteContentSize.X,
|
||||
0, self.listRef.current.AbsoluteContentSize.Y)
|
||||
end
|
||||
|
||||
function AutoResizeList:render()
|
||||
local layoutOrder = self.props.layoutOrder
|
||||
local position = self.props.position
|
||||
local anchorPoint = self.props.anchorPoint
|
||||
local backgroundImage = self.props.backgroundImage
|
||||
local sliceCenter = self.props.sliceCenter
|
||||
|
||||
local horizontalAlignment = self.props.horizontalAlignment
|
||||
local verticalAlignment = self.props.verticalAlignment
|
||||
local fillDirection = self.props.fillDirection
|
||||
local listPadding = self.props.listPadding
|
||||
|
||||
local children = join(self.props[Roact.Children] or {}, {
|
||||
["$ListLayout"] = Roact.createElement("UIListLayout", {
|
||||
HorizontalAlignment = horizontalAlignment,
|
||||
VerticalAlignment = verticalAlignment,
|
||||
FillDirection = fillDirection,
|
||||
Padding = listPadding,
|
||||
SortOrder = Enum.SortOrder.LayoutOrder,
|
||||
|
||||
[Roact.Ref] = self.listRef,
|
||||
[Roact.Change.AbsoluteContentSize] = self.contentSizeCallback,
|
||||
})
|
||||
})
|
||||
|
||||
if backgroundImage == nil then
|
||||
return Roact.createElement("Frame", {
|
||||
LayoutOrder = layoutOrder,
|
||||
BackgroundTransparency = 1,
|
||||
BorderSizePixel = 0,
|
||||
Position = position,
|
||||
AnchorPoint = anchorPoint,
|
||||
|
||||
[Roact.Ref] = self.containerRef,
|
||||
}, children)
|
||||
else
|
||||
local scaleType = (sliceCenter ~= nil) and Enum.ScaleType.Slice or Enum.ScaleType.Stretch
|
||||
return Roact.createElement("ImageLabel", {
|
||||
Image = backgroundImage,
|
||||
LayoutOrder = layoutOrder,
|
||||
BackgroundTransparency = 1,
|
||||
BorderSizePixel = 0,
|
||||
ScaleType = scaleType,
|
||||
SliceCenter = sliceCenter,
|
||||
Position = position,
|
||||
AnchorPoint = anchorPoint,
|
||||
|
||||
[Roact.Ref] = self.containerRef,
|
||||
}, children)
|
||||
end
|
||||
end
|
||||
|
||||
return AutoResizeList
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
return function()
|
||||
local CorePackages = game:GetService("CorePackages")
|
||||
local Roact = require(CorePackages.Roact)
|
||||
|
||||
local AutoResizeList = require(script.Parent.AutoResizeList)
|
||||
|
||||
it("should create and destroy without errors", function()
|
||||
local element = Roact.createElement(AutoResizeList, {
|
||||
layoutOrder = 1,
|
||||
})
|
||||
|
||||
local instance = Roact.mount(element)
|
||||
Roact.unmount(instance)
|
||||
end)
|
||||
end
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
local CorePackages = game:GetService("CorePackages")
|
||||
local TextService = game:GetService("TextService")
|
||||
|
||||
local Roact = require(CorePackages.Roact)
|
||||
local join = require(script.Parent.Parent.Parent.join)
|
||||
|
||||
local function AutoSizedTextLabel(props)
|
||||
assert(props.Text ~= nil, "Cannot autosize label with Text = nil")
|
||||
|
||||
local text = props.Text
|
||||
local textSize = props.TextSize
|
||||
local font = props.Font
|
||||
local width = props.width
|
||||
|
||||
local totalTextSize
|
||||
if text ~= nil then
|
||||
totalTextSize = TextService:GetTextSize(text, textSize, font, Vector2.new(width, 10000))
|
||||
else
|
||||
totalTextSize = Vector2.new(0, 0)
|
||||
end
|
||||
|
||||
local textLabelProps = join(props, {
|
||||
width = Roact.None,
|
||||
Size = UDim2.new(0, width, 0, totalTextSize.Y),
|
||||
})
|
||||
|
||||
return Roact.createElement("TextLabel", textLabelProps)
|
||||
end
|
||||
|
||||
return AutoSizedTextLabel
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
return function()
|
||||
local CorePackages = game:GetService("CorePackages")
|
||||
local Roact = require(CorePackages.Roact)
|
||||
|
||||
local AutoSizedTextLabel = require(script.Parent.AutoSizedTextLabel)
|
||||
|
||||
it("should create and destroy without errors", function()
|
||||
local element = Roact.createElement(AutoSizedTextLabel, {
|
||||
Text = "Hello",
|
||||
TextSize = 10,
|
||||
Font = Enum.Font.SourceSans,
|
||||
width = 100,
|
||||
})
|
||||
|
||||
local instance = Roact.mount(element)
|
||||
Roact.unmount(instance)
|
||||
end)
|
||||
|
||||
it("should throw when no text is provided", function()
|
||||
local element = Roact.createElement(AutoSizedTextLabel, {
|
||||
TextSize = 10,
|
||||
Font = Enum.Font.SourceSans,
|
||||
width = 100,
|
||||
})
|
||||
|
||||
expect(function()
|
||||
Roact.mount(element)
|
||||
end).to.throw()
|
||||
end)
|
||||
end
|
||||
@@ -0,0 +1,149 @@
|
||||
local CorePackages = game:GetService("CorePackages")
|
||||
local ContextActionService = game:GetService("ContextActionService")
|
||||
|
||||
local Roact = require(CorePackages.Roact)
|
||||
|
||||
local TextLocalizer = require(script.Parent.Parent.Connection.TextLocalizer)
|
||||
|
||||
local withLayoutValues = require(script.Parent.Parent.Connection.withLayoutValues)
|
||||
|
||||
local connectToStore = require(script.Parent.Parent.Parent.connectToStore)
|
||||
|
||||
local Button = Roact.PureComponent:extend("Button")
|
||||
|
||||
function Button:init()
|
||||
local onClick = self.props.onClick
|
||||
local imageDown = self.props.imageDown
|
||||
local imageUp = self.props.imageUp
|
||||
|
||||
self.state = {
|
||||
currentImage = imageUp
|
||||
}
|
||||
|
||||
self.inputBegan = function()
|
||||
self:setState({
|
||||
currentImage = imageDown
|
||||
})
|
||||
end
|
||||
|
||||
self.inputEnded = function()
|
||||
self:setState({
|
||||
currentImage = imageUp
|
||||
})
|
||||
end
|
||||
|
||||
self.activated = function()
|
||||
onClick()
|
||||
self:setState({
|
||||
currentImage = imageUp
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
function Button:didMount()
|
||||
-- Some buttons need to support additional button bindings
|
||||
local bindings = self.props.additionalBindings or {}
|
||||
table.insert(bindings, self.props.gamepadButton)
|
||||
|
||||
ContextActionService:BindCoreAction(
|
||||
self.props.stringKey,
|
||||
self.props.onClick,
|
||||
false,
|
||||
unpack(bindings)
|
||||
)
|
||||
end
|
||||
|
||||
function Button:willUnmount()
|
||||
ContextActionService:UnbindCoreAction(self.props.stringKey)
|
||||
end
|
||||
|
||||
function Button:render()
|
||||
assert(typeof(self.props.gamepadButton) == "EnumItem"
|
||||
and self.props.gamepadButton.EnumType == Enum.KeyCode,
|
||||
"Prop 'gamepadButton' is required and must be of type Enum.KeyCode")
|
||||
|
||||
return withLayoutValues(function(values)
|
||||
local stringKey = self.props.stringKey
|
||||
local font = self.props.font
|
||||
local size = self.props.size
|
||||
local position = self.props.position
|
||||
|
||||
local gamepadEnabled = self.props.gamepadEnabled
|
||||
local gamepadButton = self.props.gamepadButton
|
||||
|
||||
local imageData = values.Image[self.state.currentImage]
|
||||
|
||||
local buttonContents = {
|
||||
ButtonLabel = Roact.createElement(TextLocalizer, {
|
||||
key = stringKey,
|
||||
render = function(localizedText)
|
||||
return Roact.createElement("TextLabel", {
|
||||
Text = localizedText,
|
||||
Font = font,
|
||||
Size = UDim2.new(0.6, 0, 0.8, 0),
|
||||
Position = UDim2.new(0.2, 0, 0.1, 0),
|
||||
BackgroundTransparency = 1,
|
||||
BorderSizePixel = 0,
|
||||
TextColor3 = Color3.new(1, 1, 1),
|
||||
TextSize = values.TextSize.Button,
|
||||
TextScaled = true,
|
||||
TextWrapped = false,
|
||||
LayoutOrder = 2,
|
||||
}, {
|
||||
TextSizeConstraint = Roact.createElement("UITextSizeConstraint", {
|
||||
MaxTextSize = values.TextSize.Button,
|
||||
}),
|
||||
})
|
||||
end,
|
||||
})
|
||||
}
|
||||
|
||||
if gamepadEnabled then
|
||||
-- Using a frame allows the icon to be left-aligned and still
|
||||
-- be in a size-constrained section of the overall button
|
||||
buttonContents.ButtonIcon = Roact.createElement("Frame", {
|
||||
Size = UDim2.new(0.2, 0, 0.8, 0),
|
||||
Position = UDim2.new(0, 0, 0.1, 0),
|
||||
BackgroundTransparency = 1,
|
||||
BorderSizePixel = 0,
|
||||
}, {
|
||||
Icon = Roact.createElement("ImageLabel", {
|
||||
Size = UDim2.new(1, 0, 1, 0),
|
||||
Position = UDim2.new(0, values.Size.ButtonIconPadding, 0, values.Size.ButtonIconYOffset),
|
||||
SizeConstraint = Enum.SizeConstraint.RelativeYY,
|
||||
ScaleType = Enum.ScaleType.Fit,
|
||||
Image = values.Image[gamepadButton.Name].Path,
|
||||
BackgroundTransparency = 1,
|
||||
BorderSizePixel = 0,
|
||||
})
|
||||
})
|
||||
end
|
||||
|
||||
return Roact.createElement("ImageButton", {
|
||||
BackgroundTransparency = 1,
|
||||
BorderSizePixel = 0,
|
||||
AutoButtonColor = false,
|
||||
Modal = true,
|
||||
|
||||
Size = size,
|
||||
Position = position,
|
||||
ScaleType = Enum.ScaleType.Slice,
|
||||
Image = imageData.Path,
|
||||
SliceCenter = imageData.SliceCenter,
|
||||
|
||||
[Roact.Event.InputBegan] = self.inputBegan,
|
||||
[Roact.Event.InputEnded] = self.inputEnded,
|
||||
[Roact.Event.Activated] = self.activated,
|
||||
}, buttonContents)
|
||||
end)
|
||||
end
|
||||
|
||||
local function mapStateToProps(state)
|
||||
return {
|
||||
gamepadEnabled = state.gamepadEnabled
|
||||
}
|
||||
end
|
||||
|
||||
Button = connectToStore(mapStateToProps)(Button)
|
||||
|
||||
return Button
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
return function()
|
||||
local CorePackages = game:GetService("CorePackages")
|
||||
local Roact = require(CorePackages.Roact)
|
||||
|
||||
local UnitTestContainer = require(script.Parent.Parent.Parent.Test.UnitTestContainer)
|
||||
|
||||
local Button = require(script.Parent.Button)
|
||||
|
||||
Button = Button.getUnconnected()
|
||||
|
||||
it("should create and destroy without errors with gamepad disabled", function()
|
||||
local element = Roact.createElement(UnitTestContainer, nil, {
|
||||
Roact.createElement(Button, {
|
||||
gamepadEnabled = false,
|
||||
|
||||
stringKey = "testing123",
|
||||
gamepadButton = Enum.KeyCode.ButtonA,
|
||||
font = Enum.Font.SourceSans,
|
||||
imageUp = "ButtonUp",
|
||||
imageDown = "ButtonDown",
|
||||
onClick = function()
|
||||
end,
|
||||
})
|
||||
})
|
||||
|
||||
local instance = Roact.mount(element)
|
||||
Roact.unmount(instance)
|
||||
end)
|
||||
|
||||
it("should create and destroy without errors with gamepad enabled", function()
|
||||
local element = Roact.createElement(UnitTestContainer, nil, {
|
||||
Roact.createElement(Button, {
|
||||
gamepadEnabled = true,
|
||||
|
||||
stringKey = "testing123",
|
||||
gamepadButton = Enum.KeyCode.ButtonA,
|
||||
font = Enum.Font.SourceSans,
|
||||
imageUp = "ButtonUp",
|
||||
imageDown = "ButtonDown",
|
||||
onClick = function()
|
||||
end,
|
||||
})
|
||||
})
|
||||
|
||||
local instance = Roact.mount(element)
|
||||
Roact.unmount(instance)
|
||||
end)
|
||||
end
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
local CorePackages = game:GetService("CorePackages")
|
||||
|
||||
local Roact = require(CorePackages.Roact)
|
||||
|
||||
local Button = require(script.Parent.Button)
|
||||
|
||||
local withLayoutValues = require(script.Parent.Parent.Connection.withLayoutValues)
|
||||
|
||||
local function CancelButton(props)
|
||||
return withLayoutValues(function(values)
|
||||
local onClick = props.onClick
|
||||
|
||||
return Roact.createElement(Button, {
|
||||
font = Enum.Font.SourceSans,
|
||||
imageUp = "ButtonUpRight",
|
||||
imageDown = "ButtonDownRight",
|
||||
gamepadButton = Enum.KeyCode.ButtonB,
|
||||
|
||||
stringKey = "CoreScripts.PurchasePrompt.CancelPurchase.Cancel",
|
||||
size = UDim2.new(0.5, 0, 1, 0),
|
||||
position = UDim2.new(0.5, 0, 0, 0),
|
||||
|
||||
onClick = onClick,
|
||||
})
|
||||
end)
|
||||
end
|
||||
|
||||
return CancelButton
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
return function()
|
||||
local CorePackages = game:GetService("CorePackages")
|
||||
local Roact = require(CorePackages.Roact)
|
||||
|
||||
local UnitTestContainer = require(script.Parent.Parent.Parent.Test.UnitTestContainer)
|
||||
|
||||
local CancelButton = require(script.Parent.CancelButton)
|
||||
|
||||
it("should create and destroy without errors", function()
|
||||
local element = Roact.createElement(UnitTestContainer, nil, {
|
||||
Roact.createElement(CancelButton, {
|
||||
onClick = function()
|
||||
end,
|
||||
})
|
||||
})
|
||||
|
||||
local instance = Roact.mount(element)
|
||||
Roact.unmount(instance)
|
||||
end)
|
||||
end
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
local CorePackages = game:GetService("CorePackages")
|
||||
|
||||
local Roact = require(CorePackages.Roact)
|
||||
|
||||
local ClickScamDetector = require(script.Parent.Parent.Parent.ClickScamDetector)
|
||||
|
||||
local Button = require(script.Parent.Button)
|
||||
|
||||
local withLayoutValues = require(script.Parent.Parent.Connection.withLayoutValues)
|
||||
|
||||
local CONFIRM_BUTTON = Enum.KeyCode.ButtonA
|
||||
|
||||
local ConfirmButton = Roact.Component:extend("ConfirmButton")
|
||||
|
||||
function ConfirmButton:init()
|
||||
local onClick = self.props.onClick
|
||||
|
||||
self.activated = function()
|
||||
if self.clickScamDetector:isClickValid() then
|
||||
onClick()
|
||||
end
|
||||
end
|
||||
|
||||
self.clickScamDetector = ClickScamDetector.new({
|
||||
buttonInput = CONFIRM_BUTTON,
|
||||
initialDelay = 0.5,
|
||||
})
|
||||
end
|
||||
|
||||
function ConfirmButton:willUnmount()
|
||||
self.clickScamDetector:destroy()
|
||||
end
|
||||
|
||||
function ConfirmButton:render()
|
||||
return withLayoutValues(function(values)
|
||||
local stringKey = self.props.stringKey
|
||||
|
||||
return Roact.createElement(Button, {
|
||||
font = Enum.Font.SourceSansBold,
|
||||
imageUp = "ButtonUpLeft",
|
||||
imageDown = "ButtonDownLeft",
|
||||
gamepadButton = CONFIRM_BUTTON,
|
||||
|
||||
stringKey = stringKey,
|
||||
size = UDim2.new(0.5, 0, 1, 0),
|
||||
|
||||
onClick = self.activated,
|
||||
})
|
||||
end)
|
||||
end
|
||||
|
||||
return ConfirmButton
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
return function()
|
||||
local CorePackages = game:GetService("CorePackages")
|
||||
local Roact = require(CorePackages.Roact)
|
||||
|
||||
local UnitTestContainer = require(script.Parent.Parent.Parent.Test.UnitTestContainer)
|
||||
|
||||
local ConfirmButton = require(script.Parent.ConfirmButton)
|
||||
|
||||
it("should create and destroy without errors", function()
|
||||
local element = Roact.createElement(UnitTestContainer, nil, {
|
||||
Roact.createElement(ConfirmButton, {
|
||||
stringKey = "testing123",
|
||||
onClick = function()
|
||||
end,
|
||||
})
|
||||
})
|
||||
|
||||
local instance = Roact.mount(element)
|
||||
Roact.unmount(instance)
|
||||
end)
|
||||
end
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
local CorePackages = game:GetService("CorePackages")
|
||||
|
||||
local Roact = require(CorePackages.Roact)
|
||||
|
||||
local TextLocalizer = require(script.Parent.Parent.Connection.TextLocalizer)
|
||||
|
||||
local AutoSizedTextLabel = require(script.Parent.AutoSizedTextLabel)
|
||||
local PurchasingAnimation = require(script.Parent.PurchasingAnimation)
|
||||
|
||||
local withLayoutValues = require(script.Parent.Parent.Connection.withLayoutValues)
|
||||
|
||||
local function InProgressContents(props)
|
||||
return withLayoutValues(function(values)
|
||||
return Roact.createElement("ImageLabel", {
|
||||
Size = UDim2.new(1, 0, 1, 0),
|
||||
|
||||
ScaleType = Enum.ScaleType.Slice,
|
||||
Image = values.Image.InProgressBackground.Path,
|
||||
SliceCenter = values.Image.InProgressBackground.SliceCenter,
|
||||
|
||||
BackgroundTransparency = 1,
|
||||
BorderSizePixel = 0,
|
||||
}, {
|
||||
ListLayout = Roact.createElement("UIListLayout", {
|
||||
HorizontalAlignment = Enum.HorizontalAlignment.Center,
|
||||
VerticalAlignment = Enum.VerticalAlignment.Center,
|
||||
FillDirection = Enum.FillDirection.Vertical,
|
||||
SortOrder = Enum.SortOrder.LayoutOrder,
|
||||
Padding = UDim.new(0, 20)
|
||||
}),
|
||||
PurchasingText = Roact.createElement(TextLocalizer, {
|
||||
key = "CoreScripts.PurchasePrompt.Purchasing",
|
||||
render = function(localizedText)
|
||||
return Roact.createElement(AutoSizedTextLabel, {
|
||||
width = values.Size.Dialog.X.Offset,
|
||||
Text = localizedText,
|
||||
BackgroundTransparency = 1,
|
||||
BorderSizePixel = 0,
|
||||
TextColor3 = Color3.new(1, 1, 1),
|
||||
Font = Enum.Font.SourceSans,
|
||||
TextSize = values.TextSize.Purchasing,
|
||||
TextXAlignment = Enum.TextXAlignment.Center,
|
||||
TextYAlignment = Enum.TextYAlignment.Center,
|
||||
TextScaled = true,
|
||||
TextWrapped = true,
|
||||
LayoutOrder = 1,
|
||||
}, {
|
||||
TextSizeConstraint = Roact.createElement("UITextSizeConstraint", {
|
||||
MaxTextSize = values.TextSize.Purchasing,
|
||||
}),
|
||||
})
|
||||
end,
|
||||
}),
|
||||
PurchasingAnimation = Roact.createElement(PurchasingAnimation, {
|
||||
layoutOrder = 2,
|
||||
}),
|
||||
})
|
||||
end)
|
||||
end
|
||||
|
||||
return InProgressContents
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
return function()
|
||||
local CorePackages = game:GetService("CorePackages")
|
||||
local Roact = require(CorePackages.Roact)
|
||||
|
||||
local UnitTestContainer = require(script.Parent.Parent.Parent.Test.UnitTestContainer)
|
||||
|
||||
local InProgressContents = require(script.Parent.InProgressContents)
|
||||
|
||||
it("should create and destroy without errors", function()
|
||||
local element = Roact.createElement(UnitTestContainer, nil, {
|
||||
Roact.createElement(InProgressContents, {
|
||||
anchorPoint = Vector2.new(0, 0),
|
||||
position = UDim2.new(0, 0, 0, 0),
|
||||
})
|
||||
})
|
||||
|
||||
local instance = Roact.mount(element)
|
||||
Roact.unmount(instance)
|
||||
end)
|
||||
end
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
local CorePackages = game:GetService("CorePackages")
|
||||
|
||||
local Roact = require(CorePackages.Roact)
|
||||
|
||||
local connectToStore = require(script.Parent.Parent.Parent.connectToStore)
|
||||
|
||||
local withLayoutValues = require(script.Parent.Parent.Connection.withLayoutValues)
|
||||
|
||||
local PromptState = require(script.Parent.Parent.Parent.PromptState)
|
||||
|
||||
local function ItemPreviewImage(props)
|
||||
return withLayoutValues(function(values)
|
||||
local layoutOrder = props.layoutOrder
|
||||
local promptState = props.promptState
|
||||
local productImageUrl = props.productImageUrl
|
||||
|
||||
if promptState == PromptState.Error then
|
||||
productImageUrl = values.Image.ErrorIcon.Path
|
||||
end
|
||||
|
||||
return Roact.createElement("Frame", {
|
||||
Size = values.Size.ItemPreviewContainerFrame,
|
||||
BackgroundTransparency = 1,
|
||||
BorderSizePixel = 0,
|
||||
LayoutOrder = layoutOrder,
|
||||
}, {
|
||||
ItemPreviewImageContainer = Roact.createElement("Frame", {
|
||||
Size = values.Size.ItemPreviewWhiteFrame,
|
||||
BackgroundTransparency = 0,
|
||||
AnchorPoint = Vector2.new(0.5, 0.5),
|
||||
Position = UDim2.new(0.5, 0, 0.5, 0),
|
||||
BorderSizePixel = 0,
|
||||
BackgroundColor3 = Color3.new(1, 1, 1),
|
||||
}, {
|
||||
ItemImage = Roact.createElement("ImageLabel", {
|
||||
Size = values.Size.ItemPreview,
|
||||
BackgroundTransparency = 1,
|
||||
BorderSizePixel = 0,
|
||||
AnchorPoint = Vector2.new(0.5, 0.5),
|
||||
Position = UDim2.new(0.5, 0, 0.5, 0),
|
||||
Image = productImageUrl,
|
||||
})
|
||||
})
|
||||
})
|
||||
end)
|
||||
end
|
||||
|
||||
local function mapStateToProps(state)
|
||||
return {
|
||||
promptState = state.promptState,
|
||||
productImageUrl = state.productInfo.imageUrl,
|
||||
}
|
||||
end
|
||||
|
||||
ItemPreviewImage = connectToStore(
|
||||
mapStateToProps
|
||||
)(ItemPreviewImage)
|
||||
|
||||
return ItemPreviewImage
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
return function()
|
||||
local CorePackages = game:GetService("CorePackages")
|
||||
local Roact = require(CorePackages.Roact)
|
||||
|
||||
local UnitTestContainer = require(script.Parent.Parent.Parent.Test.UnitTestContainer)
|
||||
|
||||
local ItemPreviewImage = require(script.Parent.ItemPreviewImage)
|
||||
|
||||
ItemPreviewImage = ItemPreviewImage.getUnconnected()
|
||||
|
||||
it("should create and destroy without errors", function()
|
||||
local element = Roact.createElement(UnitTestContainer, nil, {
|
||||
Roact.createElement(ItemPreviewImage, {
|
||||
layoutOrder = 1,
|
||||
imageUrl = "",
|
||||
})
|
||||
})
|
||||
|
||||
local instance = Roact.mount(element)
|
||||
Roact.unmount(instance)
|
||||
end)
|
||||
end
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
local CorePackages = game:GetService("CorePackages")
|
||||
|
||||
local Roact = require(CorePackages.Roact)
|
||||
|
||||
local Button = require(script.Parent.Button)
|
||||
|
||||
local withLayoutValues = require(script.Parent.Parent.Connection.withLayoutValues)
|
||||
|
||||
local function OkButton(props)
|
||||
return withLayoutValues(function(values)
|
||||
local onClick = props.onClick
|
||||
|
||||
return Roact.createElement(Button, {
|
||||
font = Enum.Font.SourceSans,
|
||||
imageUp = "ButtonUp",
|
||||
imageDown = "ButtonDown",
|
||||
gamepadButton = Enum.KeyCode.ButtonA,
|
||||
additionalBindings = {
|
||||
Enum.KeyCode.ButtonB,
|
||||
},
|
||||
|
||||
stringKey = "CoreScripts.PurchasePrompt.Button.OK",
|
||||
size = UDim2.new(1, 0, 0, values.Size.ButtonHeight-4),
|
||||
|
||||
onClick = onClick
|
||||
})
|
||||
end)
|
||||
end
|
||||
|
||||
return OkButton
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
return function()
|
||||
local CorePackages = game:GetService("CorePackages")
|
||||
local Roact = require(CorePackages.Roact)
|
||||
|
||||
local UnitTestContainer = require(script.Parent.Parent.Parent.Test.UnitTestContainer)
|
||||
|
||||
local OkButton = require(script.Parent.OkButton)
|
||||
|
||||
it("should create and destroy without errors", function()
|
||||
local element = Roact.createElement(UnitTestContainer, nil, {
|
||||
Roact.createElement(OkButton, {
|
||||
onClick = function()
|
||||
end,
|
||||
})
|
||||
})
|
||||
|
||||
local instance = Roact.mount(element)
|
||||
Roact.unmount(instance)
|
||||
end)
|
||||
end
|
||||
@@ -0,0 +1,84 @@
|
||||
local CorePackages = game:GetService("CorePackages")
|
||||
|
||||
local Roact = require(CorePackages.Roact)
|
||||
|
||||
local PromptState = require(script.Parent.Parent.Parent.PromptState)
|
||||
|
||||
local NumberLocalizer = require(script.Parent.Parent.Connection.NumberLocalizer)
|
||||
|
||||
local AutoResizeList = require(script.Parent.AutoResizeList)
|
||||
|
||||
local withLayoutValues = require(script.Parent.Parent.Connection.withLayoutValues)
|
||||
|
||||
local connectToStore = require(script.Parent.Parent.Parent.connectToStore)
|
||||
|
||||
local function Price(props)
|
||||
return withLayoutValues(function(values)
|
||||
local layoutOrder = props.layoutOrder
|
||||
local showPrice = props.showPrice
|
||||
local price = props.price
|
||||
|
||||
return showPrice and Roact.createElement(AutoResizeList, {
|
||||
layoutOrder = layoutOrder,
|
||||
horizontalAlignment = Enum.HorizontalAlignment.Left,
|
||||
verticalAlignment = Enum.VerticalAlignment.Center,
|
||||
fillDirection = Enum.FillDirection.Horizontal,
|
||||
}, {
|
||||
RobuxIconContainer = Roact.createElement("Frame", {
|
||||
BorderSizePixel = 0,
|
||||
BackgroundTransparency = 1,
|
||||
Size = values.Size.RobuxIconContainerFrame,
|
||||
LayoutOrder = 1,
|
||||
}, {
|
||||
RobuxIcon = Roact.createElement("ImageLabel", {
|
||||
Size = values.Size.RobuxIcon,
|
||||
BackgroundTransparency = 1,
|
||||
BorderSizePixel = 0,
|
||||
AnchorPoint = Vector2.new(0, 0.5),
|
||||
Position = UDim2.new(0, 0, 0.5, 0),
|
||||
Image = values.Image.RobuxIcon.Path,
|
||||
}),
|
||||
}),
|
||||
PriceTextLabel = Roact.createElement(NumberLocalizer, {
|
||||
number = price,
|
||||
render = function(localizedNumber)
|
||||
return Roact.createElement("TextLabel", {
|
||||
Text = localizedNumber,
|
||||
LayoutOrder = 2,
|
||||
Size = values.Size.PriceTextLabel,
|
||||
BackgroundTransparency = 1,
|
||||
BorderSizePixel = 0,
|
||||
TextColor3 = Color3.fromRGB(2, 183, 87),
|
||||
Font = Enum.Font.SourceSansBold,
|
||||
TextSize = values.TextSize.Default,
|
||||
TextXAlignment = Enum.TextXAlignment.Left,
|
||||
TextScaled = true,
|
||||
TextWrapped = true,
|
||||
}, {
|
||||
TextSizeConstraint = Roact.createElement("UITextSizeConstraint", {
|
||||
MaxTextSize = values.TextSize.Default,
|
||||
})
|
||||
})
|
||||
end,
|
||||
})
|
||||
})
|
||||
end)
|
||||
end
|
||||
|
||||
local function mapStateToProps(state)
|
||||
local promptState = state.promptState
|
||||
local canPurchase = promptState ~= PromptState.CannotPurchase
|
||||
and promptState ~= PromptState.Error
|
||||
local free = state.productInfo.price == 0
|
||||
|
||||
return {
|
||||
showPrice = canPurchase and not free,
|
||||
price = state.productInfo.price,
|
||||
}
|
||||
end
|
||||
|
||||
Price = connectToStore(
|
||||
mapStateToProps
|
||||
)(Price)
|
||||
|
||||
return Price
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
return function()
|
||||
local CorePackages = game:GetService("CorePackages")
|
||||
local Roact = require(CorePackages.Roact)
|
||||
|
||||
local UnitTestContainer = require(script.Parent.Parent.Parent.Test.UnitTestContainer)
|
||||
|
||||
local Price = require(script.Parent.Price)
|
||||
|
||||
Price = Price.getUnconnected()
|
||||
|
||||
it("should create and destroy without errors", function()
|
||||
local element = Roact.createElement(UnitTestContainer, nil, {
|
||||
Roact.createElement(Price, {
|
||||
layoutOrder = 1,
|
||||
imageUrl = "",
|
||||
})
|
||||
})
|
||||
|
||||
local instance = Roact.mount(element)
|
||||
Roact.unmount(instance)
|
||||
end)
|
||||
end
|
||||
+135
@@ -0,0 +1,135 @@
|
||||
local CorePackages = game:GetService("CorePackages")
|
||||
|
||||
local Roact = require(CorePackages.Roact)
|
||||
|
||||
local PromptState = require(script.Parent.Parent.Parent.PromptState)
|
||||
local PurchaseError = require(script.Parent.Parent.Parent.PurchaseError)
|
||||
|
||||
local LocalizationService = require(script.Parent.Parent.Parent.Localization.LocalizationService)
|
||||
|
||||
local TextLocalizer = require(script.Parent.Parent.Connection.TextLocalizer)
|
||||
local AutoSizedTextLabel = require(script.Parent.AutoSizedTextLabel)
|
||||
local Price = require(script.Parent.Price)
|
||||
|
||||
local withLayoutValues = require(script.Parent.Parent.Connection.withLayoutValues)
|
||||
|
||||
local connectToStore = require(script.Parent.Parent.Parent.connectToStore)
|
||||
|
||||
local PURCHASE_MESSAGE_KEY = "CoreScripts.PurchasePrompt.PurchaseMessage.%s"
|
||||
|
||||
local function ProductDescription(props)
|
||||
return withLayoutValues(function(values)
|
||||
local layoutOrder = props.layoutOrder
|
||||
local descriptionKey = props.descriptionKey
|
||||
local descriptionParams = props.descriptionParams
|
||||
|
||||
return Roact.createElement("Frame", {
|
||||
BorderSizePixel = 0,
|
||||
Size = values.Size.ProductDescription,
|
||||
BackgroundTransparency = 1,
|
||||
LayoutOrder = layoutOrder,
|
||||
}, {
|
||||
ProductDescriptionPadding = Roact.createElement("UIPadding", {
|
||||
PaddingTop = UDim.new(0, values.Size.ProductDescriptionPaddingTop),
|
||||
}),
|
||||
ProductDescriptionListLayout = Roact.createElement("UIListLayout", {
|
||||
HorizontalAlignment = Enum.HorizontalAlignment.Left,
|
||||
VerticalAlignment = Enum.VerticalAlignment.Top,
|
||||
FillDirection = Enum.FillDirection.Vertical,
|
||||
SortOrder = Enum.SortOrder.LayoutOrder,
|
||||
}),
|
||||
ProductDescriptionText = Roact.createElement(TextLocalizer, {
|
||||
key = descriptionKey,
|
||||
params = descriptionParams,
|
||||
render = function(localizedText)
|
||||
return Roact.createElement(AutoSizedTextLabel, {
|
||||
width = values.Size.ProductDescription.X.Offset - values.Size.HorizontalPadding,
|
||||
Text = localizedText,
|
||||
BackgroundTransparency = 1,
|
||||
BorderSizePixel = 0,
|
||||
TextColor3 = Color3.new(1, 1, 1),
|
||||
Font = Enum.Font.SourceSans,
|
||||
TextSize = values.TextSize.ProductDescription,
|
||||
TextXAlignment = Enum.TextXAlignment.Left,
|
||||
TextYAlignment = Enum.TextYAlignment.Top,
|
||||
TextScaled = true,
|
||||
TextWrapped = true,
|
||||
LayoutOrder = 1,
|
||||
}, {
|
||||
TextSizeConstraint = Roact.createElement("UITextSizeConstraint", {
|
||||
MaxTextSize = values.TextSize.ProductDescription,
|
||||
}),
|
||||
})
|
||||
end,
|
||||
}),
|
||||
Price = Roact.createElement(Price, {
|
||||
layoutOrder = 2,
|
||||
}),
|
||||
})
|
||||
end)
|
||||
end
|
||||
|
||||
local function mapStateToProps(state)
|
||||
local promptState = state.promptState
|
||||
local isFree = state.productInfo.price == 0
|
||||
|
||||
local descriptionKey
|
||||
local descriptionParams
|
||||
|
||||
if promptState == PromptState.PurchaseComplete then
|
||||
descriptionKey = PURCHASE_MESSAGE_KEY:format("Succeeded")
|
||||
descriptionParams = {
|
||||
ITEM_NAME = state.productInfo.name,
|
||||
NEEDED_AMOUNT = LocalizationService.numberParam(
|
||||
state.productInfo.price - state.accountInfo.balance
|
||||
),
|
||||
ASSET_TYPE = LocalizationService.nestedKeyParam(
|
||||
LocalizationService.getAssetTypeKey(state.productInfo.assetTypeId)
|
||||
),
|
||||
}
|
||||
elseif promptState == PromptState.RobuxUpsell then
|
||||
descriptionKey = PURCHASE_MESSAGE_KEY:format("NeedMoreRobux")
|
||||
descriptionParams = {
|
||||
ITEM_NAME = state.productInfo.name,
|
||||
NEEDED_AMOUNT = LocalizationService.numberParam(
|
||||
state.productInfo.price - state.accountInfo.balance
|
||||
),
|
||||
ASSET_TYPE = LocalizationService.nestedKeyParam(
|
||||
LocalizationService.getAssetTypeKey(state.productInfo.assetTypeId)
|
||||
),
|
||||
}
|
||||
elseif promptState == PromptState.CannotPurchase or promptState == PromptState.Error then
|
||||
descriptionKey = LocalizationService.getErrorKey(state.purchaseError)
|
||||
if state.purchaseError == PurchaseError.UnknownFailure then
|
||||
descriptionParams = {
|
||||
ITEM_NAME = state.productInfo.name
|
||||
}
|
||||
end
|
||||
elseif promptState ~= PromptState.Hidden then
|
||||
if isFree then
|
||||
descriptionKey = PURCHASE_MESSAGE_KEY:format("Free")
|
||||
descriptionParams = {
|
||||
ITEM_NAME = state.productInfo.name,
|
||||
}
|
||||
else
|
||||
descriptionKey = PURCHASE_MESSAGE_KEY:format("Purchase")
|
||||
descriptionParams = {
|
||||
ASSET_TYPE = LocalizationService.nestedKeyParam(
|
||||
LocalizationService.getAssetTypeKey(state.productInfo.assetTypeId)
|
||||
),
|
||||
ITEM_NAME = state.productInfo.name,
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
return {
|
||||
descriptionKey = descriptionKey,
|
||||
descriptionParams = descriptionParams,
|
||||
}
|
||||
end
|
||||
|
||||
ProductDescription = connectToStore(
|
||||
mapStateToProps
|
||||
)(ProductDescription)
|
||||
|
||||
return ProductDescription
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
return function()
|
||||
local CorePackages = game:GetService("CorePackages")
|
||||
local Roact = require(CorePackages.Roact)
|
||||
local Rodux = require(CorePackages.Rodux)
|
||||
|
||||
local Reducer = require(script.Parent.Parent.Parent.Reducers.Reducer)
|
||||
local UnitTestContainer = require(script.Parent.Parent.Parent.Test.UnitTestContainer)
|
||||
|
||||
local ProductDescription = require(script.Parent.ProductDescription)
|
||||
|
||||
ProductDescription = ProductDescription.getUnconnected()
|
||||
|
||||
it("should create and destroy without errors", function()
|
||||
local element = Roact.createElement(UnitTestContainer, {
|
||||
overrideStore = Rodux.Store.new(Reducer, {
|
||||
productInfo = {
|
||||
price = 10,
|
||||
},
|
||||
})
|
||||
}, {
|
||||
Roact.createElement(ProductDescription, {
|
||||
descriptionKey = "CoreScripts.PurchasePrompt.PurchaseMessage.Purchase",
|
||||
})
|
||||
})
|
||||
|
||||
local instance = Roact.mount(element)
|
||||
Roact.unmount(instance)
|
||||
end)
|
||||
end
|
||||
+105
@@ -0,0 +1,105 @@
|
||||
local CorePackages = game:GetService("CorePackages")
|
||||
|
||||
local Roact = require(CorePackages.Roact)
|
||||
|
||||
local PromptState = require(script.Parent.Parent.Parent.PromptState)
|
||||
|
||||
local purchaseItem = require(script.Parent.Parent.Parent.Thunks.purchaseItem)
|
||||
local launchRobuxUpsell = require(script.Parent.Parent.Parent.Thunks.launchRobuxUpsell)
|
||||
local launchBuildersClubUpsell = require(script.Parent.Parent.Parent.Thunks.launchBuildersClubUpsell)
|
||||
|
||||
local ConfirmButton = require(script.Parent.ConfirmButton)
|
||||
local CancelButton = require(script.Parent.CancelButton)
|
||||
local OkButton = require(script.Parent.OkButton)
|
||||
|
||||
local withLayoutValues = require(script.Parent.Parent.Connection.withLayoutValues)
|
||||
|
||||
local connectToStore = require(script.Parent.Parent.Parent.connectToStore)
|
||||
|
||||
local CONFIRM_PURCHASE_KEY = "CoreScripts.PurchasePrompt.ConfirmPurchase.%s"
|
||||
|
||||
local PromptButtons = Roact.PureComponent:extend("PromptButtons")
|
||||
|
||||
function PromptButtons:render()
|
||||
return withLayoutValues(function(values)
|
||||
local layoutOrder = self.props.layoutOrder
|
||||
local onClose = self.props.onClose
|
||||
local promptState = self.props.promptState
|
||||
local price = self.props.price
|
||||
|
||||
local onBuy = self.props.onBuy
|
||||
local onRobuxUpsell = self.props.onRobuxUpsell
|
||||
local onBuildersClubUpsell = self.props.onBuildersClubUpsell
|
||||
|
||||
local children
|
||||
if promptState == PromptState.PurchaseComplete
|
||||
or promptState == PromptState.CannotPurchase
|
||||
or promptState == PromptState.Error
|
||||
then
|
||||
children = {
|
||||
UIPadding = Roact.createElement("UIPadding", {
|
||||
PaddingBottom = UDim.new(0, 4),
|
||||
}),
|
||||
OkButton = Roact.createElement(OkButton, {
|
||||
onClick = onClose,
|
||||
}),
|
||||
}
|
||||
else
|
||||
local confirmButtonStringKey = CONFIRM_PURCHASE_KEY:format("BuyNow")
|
||||
local leftButtonCallback = onBuy
|
||||
if price == 0 then
|
||||
confirmButtonStringKey = CONFIRM_PURCHASE_KEY:format("TakeFree")
|
||||
elseif promptState == PromptState.RobuxUpsell then
|
||||
confirmButtonStringKey = CONFIRM_PURCHASE_KEY:format("BuyRobux")
|
||||
leftButtonCallback = onRobuxUpsell
|
||||
elseif promptState == PromptState.BuildersClubUpsell then
|
||||
confirmButtonStringKey = CONFIRM_PURCHASE_KEY:format("UpgradeBuildersClub")
|
||||
leftButtonCallback = onBuildersClubUpsell
|
||||
end
|
||||
children = {
|
||||
ConfirmButton = Roact.createElement(ConfirmButton, {
|
||||
stringKey = confirmButtonStringKey,
|
||||
onClick = leftButtonCallback,
|
||||
}),
|
||||
CancelButton = Roact.createElement(CancelButton, {
|
||||
onClick = onClose,
|
||||
}),
|
||||
}
|
||||
end
|
||||
|
||||
return Roact.createElement("Frame", {
|
||||
LayoutOrder = layoutOrder,
|
||||
BackgroundTransparency = 1,
|
||||
BorderSizePixel = 0,
|
||||
Size = UDim2.new(1, 0, 0, values.Size.ButtonHeight)
|
||||
}, children)
|
||||
end)
|
||||
end
|
||||
|
||||
local function mapStateToProps(state)
|
||||
return {
|
||||
promptState = state.promptState,
|
||||
price = state.productInfo.price,
|
||||
}
|
||||
end
|
||||
|
||||
local function mapDispatchToProps(dispatch)
|
||||
return {
|
||||
onBuy = function()
|
||||
dispatch(purchaseItem())
|
||||
end,
|
||||
onRobuxUpsell = function()
|
||||
dispatch(launchRobuxUpsell())
|
||||
end,
|
||||
onBuildersClubUpsell = function()
|
||||
dispatch(launchBuildersClubUpsell())
|
||||
end,
|
||||
}
|
||||
end
|
||||
|
||||
PromptButtons = connectToStore(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(PromptButtons)
|
||||
|
||||
return PromptButtons
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
return function()
|
||||
local CorePackages = game:GetService("CorePackages")
|
||||
local Roact = require(CorePackages.Roact)
|
||||
|
||||
local PromptState = require(script.Parent.Parent.Parent.PromptState)
|
||||
|
||||
local UnitTestContainer = require(script.Parent.Parent.Parent.Test.UnitTestContainer)
|
||||
|
||||
local PromptButtons = require(script.Parent.PromptButtons)
|
||||
PromptButtons = PromptButtons.getUnconnected()
|
||||
|
||||
local function noop()
|
||||
end
|
||||
|
||||
it("should create and destroy without errors with one button", function()
|
||||
local element = Roact.createElement(UnitTestContainer, nil, {
|
||||
Roact.createElement(PromptButtons, {
|
||||
layoutOrder = 1,
|
||||
onClose = noop,
|
||||
promptState = PromptState.PurchaseComplete,
|
||||
price = 1,
|
||||
})
|
||||
})
|
||||
|
||||
local instance = Roact.mount(element)
|
||||
Roact.unmount(instance)
|
||||
end)
|
||||
|
||||
it("should create and destroy without errors with two buttons", function()
|
||||
local element = Roact.createElement(UnitTestContainer, nil, {
|
||||
Roact.createElement(PromptButtons, {
|
||||
layoutOrder = 1,
|
||||
onClose = noop,
|
||||
promptState = PromptState.PromptPurchase,
|
||||
price = 1,
|
||||
})
|
||||
})
|
||||
|
||||
local instance = Roact.mount(element)
|
||||
Roact.unmount(instance)
|
||||
end)
|
||||
end
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
local CorePackages = game:GetService("CorePackages")
|
||||
|
||||
local Roact = require(CorePackages.Roact)
|
||||
|
||||
local AutoResizeList = require(script.Parent.AutoResizeList)
|
||||
local ItemPreviewImage = require(script.Parent.ItemPreviewImage)
|
||||
local ProductDescription = require(script.Parent.ProductDescription)
|
||||
local PromptButtons = require(script.Parent.PromptButtons)
|
||||
local AdditionalDetailLabel = require(script.Parent.AdditionalDetailLabel)
|
||||
|
||||
local withLayoutValues = require(script.Parent.Parent.Connection.withLayoutValues)
|
||||
|
||||
local function PromptContents(props)
|
||||
return withLayoutValues(function(values)
|
||||
local onClose = props.onClose
|
||||
|
||||
return Roact.createElement("Frame", {
|
||||
Size = UDim2.new(1, 0, 1, 0),
|
||||
BorderSizePixel = 0,
|
||||
BackgroundTransparency = 1,
|
||||
}, {
|
||||
ListLayout = Roact.createElement("UIListLayout", {
|
||||
FillDirection = Enum.FillDirection.Vertical,
|
||||
SortOrder = Enum.SortOrder.LayoutOrder,
|
||||
}),
|
||||
PromptBody = Roact.createElement(AutoResizeList, {
|
||||
layoutOrder = 1,
|
||||
backgroundImage = values.Image.PromptBackground.Path,
|
||||
sliceCenter = values.Image.PromptBackground.SliceCenter,
|
||||
fillDirection = Enum.FillDirection.Vertical,
|
||||
}, {
|
||||
ProductInfo = Roact.createElement(AutoResizeList, {
|
||||
layoutOrder = 1,
|
||||
fillDirection = Enum.FillDirection.Horizontal,
|
||||
}, {
|
||||
ItemPreviewImage = Roact.createElement(ItemPreviewImage, {
|
||||
layoutOrder = 1,
|
||||
}),
|
||||
ProductDescription = Roact.createElement(ProductDescription, {
|
||||
layoutOrder = 2,
|
||||
})
|
||||
}),
|
||||
AdditionalDetails = Roact.createElement(AdditionalDetailLabel, {
|
||||
layoutOrder = 2,
|
||||
}),
|
||||
}),
|
||||
PromptButtons = Roact.createElement(PromptButtons, {
|
||||
layoutOrder = 2,
|
||||
onClose = onClose,
|
||||
}),
|
||||
})
|
||||
end)
|
||||
end
|
||||
|
||||
return PromptContents
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
return function()
|
||||
local CorePackages = game:GetService("CorePackages")
|
||||
local Roact = require(CorePackages.Roact)
|
||||
local Rodux = require(CorePackages.Rodux)
|
||||
|
||||
local Reducer = require(script.Parent.Parent.Parent.Reducers.Reducer)
|
||||
|
||||
local PromptState = require(script.Parent.Parent.Parent.PromptState)
|
||||
|
||||
local UnitTestContainer = require(script.Parent.Parent.Parent.Test.UnitTestContainer)
|
||||
|
||||
local PromptContents = require(script.Parent.PromptContents)
|
||||
|
||||
it("should create and destroy without errors", function()
|
||||
local element = Roact.createElement(UnitTestContainer, {
|
||||
promptState = PromptState.PromptPurchase,
|
||||
overrideStore = Rodux.Store.new(Reducer, {
|
||||
promptState = PromptState.PromptPurchase,
|
||||
accountInfo = {
|
||||
balance = 100,
|
||||
},
|
||||
productInfo = {
|
||||
assetTypeId = 2, -- T-shirt
|
||||
price = 10,
|
||||
},
|
||||
})
|
||||
}, {
|
||||
Roact.createElement(PromptContents, {
|
||||
layoutOrder = 1,
|
||||
onClose = function()
|
||||
end,
|
||||
})
|
||||
})
|
||||
|
||||
local instance = Roact.mount(element)
|
||||
Roact.unmount(instance)
|
||||
end)
|
||||
end
|
||||
+114
@@ -0,0 +1,114 @@
|
||||
local CorePackages = game:GetService("CorePackages")
|
||||
|
||||
local Roact = require(CorePackages.Roact)
|
||||
local Otter = require(CorePackages.Otter)
|
||||
|
||||
local PromptState = require(script.Parent.Parent.Parent.PromptState)
|
||||
local HidePrompt = require(script.Parent.Parent.Parent.Actions.HidePrompt)
|
||||
|
||||
local PromptContents = require(script.Parent.PromptContents)
|
||||
local InProgressContents = require(script.Parent.InProgressContents)
|
||||
local connectToStore = require(script.Parent.Parent.Parent.connectToStore)
|
||||
|
||||
local withLayoutValues = require(script.Parent.Parent.Connection.withLayoutValues)
|
||||
|
||||
local PurchasePrompt = Roact.Component:extend(script.Name)
|
||||
|
||||
local SPRING_CONFIG = {
|
||||
dampingRatio = 1,
|
||||
frequency = 1.6,
|
||||
}
|
||||
|
||||
function PurchasePrompt:init()
|
||||
local setPromptHidden = self.props.setPromptHidden
|
||||
|
||||
self.motor = Otter.createSingleMotor(0)
|
||||
self.motor:start()
|
||||
|
||||
self.ref = Roact.createRef()
|
||||
|
||||
self.motor:onStep(function(value)
|
||||
local frame = self.ref.current
|
||||
|
||||
if frame then
|
||||
frame.AnchorPoint = Vector2.new(0.5, 1 - 0.5 * value)
|
||||
frame.Position = UDim2.new(0.5, 0, 0.5 * value, 0)
|
||||
end
|
||||
end)
|
||||
|
||||
self.onClose = function()
|
||||
local onCompleteDisconnector
|
||||
onCompleteDisconnector = self.motor:onComplete(function()
|
||||
setPromptHidden()
|
||||
onCompleteDisconnector()
|
||||
|
||||
self.motor:stop()
|
||||
end)
|
||||
|
||||
self.motor:setGoal(Otter.spring(0, SPRING_CONFIG))
|
||||
end
|
||||
end
|
||||
|
||||
function PurchasePrompt:didUpdate(prevProps, prevState)
|
||||
if prevProps.promptState ~= self.props.promptState then
|
||||
|
||||
local goal = self.props.promptState == PromptState.Hidden and 0 or 1
|
||||
self.motor:setGoal(Otter.spring(goal, SPRING_CONFIG))
|
||||
|
||||
if prevProps.promptState == PromptState.Hidden then
|
||||
self.motor:start()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function PurchasePrompt:render()
|
||||
return withLayoutValues(function(values)
|
||||
local promptState = self.props.promptState
|
||||
|
||||
local contents
|
||||
if promptState == PromptState.Hidden then
|
||||
--[[
|
||||
When the prompt is hidden, we'd rather not keep unused Roblox
|
||||
instances for it around, so we don't render them
|
||||
]]
|
||||
contents = nil
|
||||
elseif promptState == PromptState.PurchaseInProgress or promptState == PromptState.UpsellInProgress then
|
||||
contents = Roact.createElement(InProgressContents)
|
||||
else
|
||||
contents = Roact.createElement(PromptContents, {
|
||||
onClose = self.onClose,
|
||||
})
|
||||
end
|
||||
|
||||
return Roact.createElement("Frame", {
|
||||
Size = values.Size.Dialog,
|
||||
BorderSizePixel = 0,
|
||||
BackgroundTransparency = 1,
|
||||
|
||||
[Roact.Ref] = self.ref
|
||||
}, {
|
||||
PromptContents = contents,
|
||||
})
|
||||
end)
|
||||
end
|
||||
|
||||
local function mapStateToProps(state)
|
||||
return {
|
||||
promptState = state.promptState
|
||||
}
|
||||
end
|
||||
|
||||
local function mapDispatchToProps(dispatch)
|
||||
return {
|
||||
setPromptHidden = function()
|
||||
dispatch(HidePrompt())
|
||||
end
|
||||
}
|
||||
end
|
||||
|
||||
PurchasePrompt = connectToStore(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(PurchasePrompt)
|
||||
|
||||
return PurchasePrompt
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
return function()
|
||||
local CorePackages = game:GetService("CorePackages")
|
||||
local Roact = require(CorePackages.Roact)
|
||||
local Rodux = require(CorePackages.Rodux)
|
||||
|
||||
local Reducer = require(script.Parent.Parent.Parent.Reducers.Reducer)
|
||||
|
||||
local PromptState = require(script.Parent.Parent.Parent.PromptState)
|
||||
|
||||
local UnitTestContainer = require(script.Parent.Parent.Parent.Test.UnitTestContainer)
|
||||
|
||||
local PurchasePrompt = require(script.Parent.PurchasePrompt)
|
||||
PurchasePrompt = PurchasePrompt.getUnconnected()
|
||||
|
||||
it("should create and destroy without errors", function()
|
||||
local element = Roact.createElement(UnitTestContainer, {
|
||||
overrideStore = Rodux.Store.new(Reducer, {
|
||||
promptState = PromptState.PromptPurchase,
|
||||
accountInfo = {
|
||||
balance = 100,
|
||||
},
|
||||
productInfo = {
|
||||
assetTypeId = 2, -- T-shirt
|
||||
price = 10,
|
||||
},
|
||||
})
|
||||
}, {
|
||||
Roact.createElement(PurchasePrompt, {
|
||||
promptState = PromptState.PromptPurchase,
|
||||
})
|
||||
})
|
||||
|
||||
local instance = Roact.mount(element)
|
||||
Roact.unmount(instance)
|
||||
end)
|
||||
end
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
local CorePackages = game:GetService("CorePackages")
|
||||
local RunService = game:GetService("RunService")
|
||||
local Workspace = game:GetService("Workspace")
|
||||
|
||||
local Roact = require(CorePackages.Roact)
|
||||
|
||||
local AnimatedDot = require(script.Parent.AnimatedDot)
|
||||
local ExternalEventConnection = require(script.Parent.Parent.Connection.ExternalEventConnection)
|
||||
|
||||
local withLayoutValues = require(script.Parent.Parent.Connection.withLayoutValues)
|
||||
|
||||
local ANIMATION_SPEED_MULTIPLIER = 2.00
|
||||
|
||||
local PurchasingAnimation = Roact.Component:extend("PurchasingAnimation")
|
||||
|
||||
function PurchasingAnimation:init()
|
||||
self.state = {
|
||||
gameTime = 0,
|
||||
}
|
||||
|
||||
self.onRenderStepped = function()
|
||||
self:setState({
|
||||
gameTime = Workspace.DistributedGameTime
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
function PurchasingAnimation:render()
|
||||
return withLayoutValues(function(values)
|
||||
local layoutOrder = self.props.layoutOrder
|
||||
|
||||
local gameTime = self.state.gameTime
|
||||
|
||||
local animationTime = (gameTime * ANIMATION_SPEED_MULTIPLIER) % 3
|
||||
|
||||
return Roact.createElement("Frame", {
|
||||
Size = values.Size.PurchasingAnimation,
|
||||
BackgroundTransparency = 1,
|
||||
BorderSizePixel = 0,
|
||||
LayoutOrder = layoutOrder,
|
||||
}, {
|
||||
RenderSteppedConnection = Roact.createElement(ExternalEventConnection, {
|
||||
event = RunService.RenderStepped,
|
||||
callback = self.onRenderStepped,
|
||||
}),
|
||||
ListLayout = Roact.createElement("UIListLayout", {
|
||||
HorizontalAlignment = Enum.HorizontalAlignment.Center,
|
||||
VerticalAlignment = Enum.VerticalAlignment.Center,
|
||||
FillDirection = Enum.FillDirection.Horizontal,
|
||||
SortOrder = Enum.SortOrder.LayoutOrder,
|
||||
}),
|
||||
AnimatedDot1 = Roact.createElement(AnimatedDot, {
|
||||
layoutOrder = 1,
|
||||
time = animationTime,
|
||||
}),
|
||||
AnimatedDot2 = Roact.createElement(AnimatedDot, {
|
||||
layoutOrder = 2,
|
||||
time = animationTime,
|
||||
}),
|
||||
AnimatedDot3 = Roact.createElement(AnimatedDot, {
|
||||
layoutOrder = 3,
|
||||
time = animationTime,
|
||||
}),
|
||||
})
|
||||
end)
|
||||
end
|
||||
|
||||
return PurchasingAnimation
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
return function()
|
||||
local CorePackages = game:GetService("CorePackages")
|
||||
local Roact = require(CorePackages.Roact)
|
||||
|
||||
local UnitTestContainer = require(script.Parent.Parent.Parent.Test.UnitTestContainer)
|
||||
|
||||
local PurchasingAnimation = require(script.Parent.PurchasingAnimation)
|
||||
|
||||
it("should create and destroy without errors", function()
|
||||
local element = Roact.createElement(UnitTestContainer, nil, {
|
||||
Roact.createElement(PurchasingAnimation, {
|
||||
layoutOrder = 1,
|
||||
})
|
||||
})
|
||||
|
||||
local instance = Roact.mount(element)
|
||||
Roact.unmount(instance)
|
||||
end)
|
||||
end
|
||||
Reference in New Issue
Block a user