import React, { useState, useEffect } from 'react';
import ReactGA from 'react-ga4';
import { useNavigate, Link } from "react-router-dom";
import {isMobile} from "react-device-detect";
import { toast } from "react-toastify"
import {
Done as DoneIcon,
Clear as ClearIcon,
AddTask as AddTaskIcon,
} from '@mui/icons-material';
import {
Slider,
Divider,
List,
ListItem,
ListItemText,
Card,
CardContent,
Grid,
Typography,
Button,
ButtonGroup,
FormControl,
Dialog,
DialogTitle,
DialogActions,
DialogContent,
Tooltip
} from '@mui/material';
import FAQ from "./Faq.jsx";
import Newsletter from "../components/Newsletter.jsx";
import Services from "./Services.jsx";
export const typecost = 0.0018
export const typecost_single = (typecost * 1.33).toFixed(4)
export const handlePayasyougo = (userdata) => {
var billingurl = "https://billing.stripe.com/p/login/bIY5lo5bMbWs9Py5kk"
if (userdata !== undefined && userdata !== null) {
if (userdata.org_email !== undefined && userdata.org_email !== null && userdata.org_email !== "") {
billingurl += `?prefilled_email=${userdata.org_email}`
} else if (userdata.username !== undefined && userdata.username !== null && userdata.username !== "") {
billingurl += `?prefilled_email=${userdata.username}`
}
}
toast("Redirecting in 2 seconds. Use the organization owner email.")
setTimeout(() => {
window.location = billingurl
}, 2500)
}
// 1. Create 2-3 payment tiers (slider?)
// 2. Create a way to show them anywhere
//
// Site references:
// https://logz.io/pricing/
// https://www.avanan.com/pricing
const PaymentField = (props) => {
const { maxFields, theme, removeAdditions, isLoggedIn } = props
const isCloud =
window.location.host === "localhost:3002" ||
window.location.host === "shuffler.io";
// Multiple unused variables here
let navigate = useNavigate();
const parsedFields = maxFields === undefined ? 300 : maxFields
const [variant, setVariant] = useState(0)
const [shuffleVariant, setShuffleVariant] = useState(isCloud ? 0 : 1)
const [paymentType, setPaymentType] = useState(0)
const [modalOpen, setModalOpen] = useState(false)
const [showPricing, ] = useState(true)
const [currentPrice, setCurrentPrice] = useState(129)
const [isLoaded, setIsLoaded] = useState(false)
const [errorMessage, setErrorMessage] = useState("")
// Cloud
const [calculatedApps, setCalculatedApps] = useState(600)
const [calculatedCost, setCalculatedCost] = useState("$600")
const [selectedValue, setSelectedValue] = useState(100)
// Onprem
const [calculatedCores, setCalculatedCores] = useState(600)
const [onpremSelectedValue, setOnpremSelectedValue] = useState(8)
useEffect(() => {
console.log("New variant: ", shuffleVariant)
if (shuffleVariant === 1) {
setCalculatedCost("$600")
setSelectedValue(8)
} else {
setCalculatedCost("$180")
setSelectedValue(100)
}
}, [shuffleVariant])
if (typeof window === 'undefined' || window.location === undefined) {
return null
}
/*
const valuetext = (value, variant) => {
console.log("Valuetext: ", value, variant)
if (value === 32 || value === 1000) {
if (variant === 1) {
setCalculatedCores("Get A Quote")
setOnpremSelectedValue(value)
} else {
setCalculatedApps(`Get A Quote`)
setSelectedValue(value)
}
} else {
if (variant === 1) {
setCalculatedCores(`$${value*75}`)
setOnpremSelectedValue(value)
} else {
setCalculatedApps(`$${value*1000*0.0018}`)
setSelectedValue(value)
}
}
}
*/
const handleChange = (event, newValue) => {
console.log("Event, value: ", event.target, newValue)
if (shuffleVariant === 1) {
setSelectedValue(newValue)
if (newValue === 32) {
setCalculatedCost(`Get A Quote`)
} else {
setCalculatedCost(`$${newValue*75}`)
}
} else {
setSelectedValue(newValue)
if (newValue === 1000) {
setCalculatedCost(`Get A Quote`)
} else {
setCalculatedCost(`$${newValue*1000*typecost}`)
}
}
}
// return `${value}`;
//}
if (!isLoaded) {
setIsLoaded(true)
const tmpsearch = typeof window === 'undefined' || window.location === undefined ? "" : window.location.search
const tmpVar = new URLSearchParams(tmpsearch).get("variant")
if (tmpVar !== undefined && tmpVar !== null && tmpVar < 3) {
setVariant(parseInt(tmpVar))
}
const tmpType = new URLSearchParams(tmpsearch).get("payment_type")
if (tmpType !== undefined && tmpType !== null && tmpType < 2) {
setPaymentType(parseInt(tmpType))
}
const modal = new URLSearchParams(tmpsearch).get("payment_modal")
if (modal !== undefined && modal !== null && modal === "open") {
setModalOpen(true)
}
const tmpView = new URLSearchParams(tmpsearch).get("view")
if (tmpView !== undefined && tmpView !== null && tmpView === "failure") {
setErrorMessage("Something went wrong with your payment. Please try again.")
}
const urlSearchParams = new URLSearchParams(window.location.search);
const params = Object.fromEntries(urlSearchParams.entries());
const foundTab = params["tab"];
if (foundTab !== null && foundTab !== undefined) {
if (foundTab === "onprem") {
//valuetext(8, 1)
setShuffleVariant(1)
//setCalculatedCores(`$${8*75}`)
}
}
}
const billingInfo = Billed anually or monthly at 1.2x the cost
//const skipFreemode = window.location.pathname.startsWith("/admin")
const skipFreemode = false
const maxwidth = isMobile ? "91%" : skipFreemode ? 1100 : 1200
const activeIcon =
const inActiveIcon =
// All triggers
const features = [
{
"name": "Users",
"basic": "No limit",
"community": "No limit",
"pro": "No limit",
"enterprise": "",
"active": true,
},
{
"name": "Apps",
"basic": "No limit",
"community": "No limit",
"pro": "No limit",
"enterprise": "",
"active": true,
},
{
"name": "Workflows",
"basic": "No limit",
"community": "No limit",
"pro": "No limit",
"enterprise": "",
"active": true,
},
{
"name": "Workflow App Runs",
"basic": "10.000 / month",
"community": "10.000 / month",
"pro": "Pay as you go",
"enterprise": "",
"active": true,
"onprem": false,
},
{
"name": "Workflow App Runs",
"basic": "No limit",
"community": "No limit",
"pro": "No limit",
"enterprise": "",
"active": true,
"cloud": false,
},
{
"name": "Shuffle Datastore (cache)",
"basic": "Max 1GB",
"community": "Yes",
"pro": "Yes",
"enterprise": "",
"active": true,
"onprem": false,
},
{
"name": "Shuffle Datastore (cache)",
"basic": "Yes",
"community": "Yes",
"pro": "Yes",
"enterprise": "",
"active": true,
"cloud": false,
},
{
"name": "File Storage",
"basic": "Max 1GB",
"community": "Yes",
"pro": "Yes",
"enterprise": "",
"active": true,
"onprem": false,
},
{
"name": "File Storage",
"basic": "Yes",
"community": "Yes",
"pro": "Yes",
"enterprise": "",
"active": true,
"cloud": false,
},
{
"name": "Multi-Tenant",
"basic": "No",
"community": "Yes",
"pro": "Add-on",
"enterprise": "",
"active": true,
"onprem": false,
},
{
"name": "Multi-Tenant",
"basic": "Yes",
"community": "Yes",
"pro": "Yes",
"enterprise": "",
"active": true,
"cloud": false,
},
{
"name": "Region Control",
"basic": "No",
"community": "Yes",
"pro": "Add-on",
"enterprise": "",
"active": true,
"onprem": false,
},
{
"name": "Per-CPU-core support",
"basic": "0 / month",
"community": "0 / month",
"pro": "Pay as you go",
"enterprise": "8 / month",
"active": true,
"cloud": false,
},
{
"name": "Shuffle SMS alerting",
"basic": "30 / month",
"community": "Yes",
"pro": "300 / month",
"enterprise": "300 / month",
"active": true,
},
{
"name": "Shuffle Email alerting",
"basic": "100 / month",
"community": "Yes",
"pro": "10.000 / month",
"enterprise": "",
"active": true,
},
{
"name": "Priority Support",
"basic": "No",
"community": "No",
"pro": "Yes",
"enterprise": "",
"active": true,
"title": "Support & Success",
},
{
"name": "Maintenance & Updates",
"basic": "No",
"community": "",
"pro": "Yes",
"enterprise": "",
"active": true,
"cloud": false,
},
{
"name": "Documentation & Community Support",
"basic": "Yes",
"community": "Yes",
"pro": "Yes",
"enterprise": "",
"active": true,
},
{
"name": "Email & Chat Support",
"basic": "support@shuffler.io",
"community": "No",
"pro": "Prioritized + Critical issue SLA",
"enterprise": "",
"active": true,
},
{
"name": "Personal onboarding",
"basic": "No",
"community": "",
"pro": "Yes",
"enterprise": "",
"active": true,
},
{
"name": "Shuffle Academy",
"basic": "Yes",
"community": "No",
"pro": "Yes",
"enterprise": "",
"active": false,
},
{
"name": "Workflow editor",
"basic": "Yes",
"community": "Yes",
"pro": "Yes",
"enterprise": "",
"active": true,
"title": "Basic features",
},
{
"name": "App editor",
"basic": "Yes",
"community": "Yes",
"pro": "Yes",
"enterprise": "",
"active": true,
},
{
"name": "Private Apps",
"basic": "Yes",
"community": "Yes",
"pro": "Yes",
"enterprise": "",
"active": true,
},
{
"name": "Default & Shared playbooks",
"basic": "Yes",
"community": "Yes",
"pro": "Yes",
"enterprise": "",
"active": true,
},
{
"name": "Organization control",
"basic": "Yes",
"community": "Yes",
"pro": "Yes",
"enterprise": "",
"active": true,
},
{
"name": "Autocomplete features",
"basic": "Yes",
"community": "Yes",
"pro": "Yes",
"enterprise": "",
"active": true,
},
{
"name": "Hybrid Webhook trigger",
"basic": "Yes",
"community": "Yes",
"pro": "Yes",
"enterprise": "",
"active": true,
},
{
"name": "Hybrid User Input trigger",
"basic": "Yes",
"community": "Yes",
"pro": "Yes",
"enterprise": "",
"active": true,
},
{
"name": "Hybrid Email trigger",
"basic": "Yes",
"community": "Yes",
"pro": "Yes",
"enterprise": "",
"active": true,
},
{
"name": "Hybrid Schedule",
"basic": "Yes",
"community": "Yes",
"pro": "Yes",
"enterprise": "",
"active": true,
},
{
"name": "Failure Notifications",
"basic": "Yes",
"community": "No",
"pro": "Yes",
"enterprise": "",
"active": true,
},
{
"name": "Hybrid Executions",
"basic": "Yes",
"community": "Yes",
"pro": "Yes",
"enterprise": "",
"active": true,
},
{
"name": "Use of Public Workflows",
"basic": "Yes",
"community": "Yes",
"pro": "Yes",
"enterprise": "",
"active": true,
},
{
"name": "Multiple Environments",
"basic": "Yes",
"community": "Yes",
"pro": "Yes",
"enterprise": "",
"active": true,
},
{
"name": "Shuffle creates integration",
"basic": "No",
"community": "Yes",
"pro": "Yes",
"enterprise": "",
"active": true,
},
{
"name": "Uptime SLA",
"basic": "No",
"community": "No",
"pro": "99.9%",
"enterprise": "",
"active": true,
"onprem": false,
},
{
"name": "Automated backups",
"basic": "No",
"community": "Yes",
"pro": "Yes",
"enterprise": "",
"active": true,
"onprem": false,
},
{
"name": "MSSP org overview",
"basic": "No",
"community": "No",
"pro": "Add-on",
"enterprise": "",
"active": true,
},
{
"name": "MSSP org control",
"basic": "No",
"community": "No",
"pro": "Add-on",
"enterprise": "",
"active": true,
},
{
"name": "Automatic Platform updates",
"basic": "Yes",
"community": "Yes",
"pro": "Yes",
"enterprise": "",
"active": true,
"onprem": false,
},
{
"name": "Audit logging",
"basic": "No",
"community": "No",
"pro": "Yes",
"enterprise": "",
"active": false,
},
{
"name": "2-factor authentication",
"basic": "Yes",
"community": "Yes",
"pro": "Yes",
"enterprise": "",
"active": true,
"title": "Security & Development",
},
{
"name": "SAML / SSO",
"basic": "Yes",
"community": "Yes",
"pro": "Yes",
"enterprise": "",
"active": true,
},
{
"name": "API-key management",
"basic": "yes",
"community": "Yes",
"pro": "Yes",
"enterprise": "",
"active": false,
},
{
"name": "Role-based access control (RBAC)",
"basic": "Yes",
"community": "Yes",
"pro": "Yes",
"enterprise": "",
"active": false,
},
{
"name": "Workflow recommendations",
"basic": "Yes",
"community": "Yes",
"pro": "Yes",
"enterprise": "",
"active": true,
"title": "Additional Features",
},
{
"name": "Standardized app categories",
"basic": "Yes",
"community": "Yes",
"pro": "Yes",
"enterprise": "",
"active": true,
},
{
"name": "App Framework",
"basic": "Yes",
"community": "Yes",
"pro": "Yes",
"enterprise": "",
"active": true,
},
{
"name": "Hybrid search engine",
"basic": "Yes",
"community": "Yes",
"pro": "Yes",
"enterprise": "",
"active": true,
},
{
"name": "Hybrid App syncronization",
"basic": "Yes",
"community": "Yes",
"pro": "Yes",
"enterprise": "",
"active": true,
},
{
"name": "Execution Retention",
"basic": "1 Month",
"community": "Yes",
"pro": "1 Year default",
"enterprise": "",
"active": true,
"onprem": false,
},
{
"name": "Detection Management",
"basic": "Yes",
"community": "Yes",
"pro": "Yes",
"enterprise": "",
"active": false,
},
{
"name": "Mitre Att&ck integrations",
"basic": "No",
"community": "Yes",
"pro": "Yes",
"enterprise": "",
"active": false,
},
{
"name": "Open Source account rollback",
"basic": "No",
"community": "Yes",
"pro": "Yes",
"enterprise": "",
"active": false,
},
{
"name": "Data LOCATION control",
"basic": "No",
"community": "No",
"pro": "Yes",
"enterprise": "",
"active": false,
},
{
"name": "Data RETENTION control",
"basic": "No",
"community": "No",
"pro": "Yes",
"enterprise": "",
"active": false,
},
{
"name": "Shuffle IoC search",
"basic": "No",
"community": "No",
"pro": "Yes",
"enterprise": "",
"active": false,
},
{
"name": "Controllable Reporting",
"basic": "No",
"community": "No",
"pro": "Yes",
"enterprise": "",
"active": false,
},
{
"name": "Management dashboard",
"basic": "No",
"community": "No",
"pro": "Yes",
"enterprise": "",
"active": false,
},
{
"name": "Risk based overview",
"basic": "No",
"community": "No",
"pro": "Yes",
"enterprise": "",
"active": false,
},
{
"name": "Compliance dashboard",
"basic": "No",
"community": "No",
"pro": "Yes",
"enterprise": "",
"active": false,
},
{
"name": "App & Workflow Training",
"basic": "$4999 / 5 people",
"community": "No",
"pro": "$1499 / 5 people",
"enterprise": "",
"active": true,
"title": "Professional Services",
},
{
"name": "Developer Training",
"basic": "$4999 / 5 people",
"community": "No",
"pro": "$1499 / 5 people",
"enterprise": "",
"active": true,
},
{
"name": "Custom App Development",
"basic": "Contact us",
"community": "No",
"pro": "Contact us",
"enterprise": "",
"active": true,
},
{
"name": "Custom Workflow Development",
"basic": "Contact us",
"community": "No",
"pro": "Contact us",
"enterprise": "",
"active": true,
},
{
"name": "Shuffle Custom Modifications",
"basic": "Contact us",
"community": "No",
"pro": "Contact us",
"enterprise": "",
"active": true,
},
]
const defaultTaskIcon =
const stripe = typeof window === 'undefined' || window.location === undefined ? "" : props.stripeKey === undefined ? "" : window.Stripe ? window.Stripe(props.stripeKey) : ""
const handleStripeRedirect = (payment_type, recurrence) => {
console.log("REDIRECT: ", payment_type, recurrence)
// FIXME: Proper redirect cycle here
if (props.userdata === undefined || props.userdata.username === undefined || props.userdata.active_org === undefined || props.userdata.active_org.id === undefined) {
console.log("User must sign in and have an organization first. Current: ", props.userdata)
// 1. Add query parameters: Yearly / monthly, Community / pro
navigate(`/register?view=pricing&variant=${variant}&payment_type=${paymentType}&payment_modal=open&message=You need to create a user to continue`)
return
} else {
console.log("Username is ", props.userdata.username)
}
//payment_type = community(0), pro(1)
//recurrence = yearly(0), monthly(1)
var priceItem = "price_1Hh8ecDzMUgUjxHSPEdeueyu"
var text = "enterprise_yearly_pay_click"
// recurrence = 0 = yearly
// recurrence = 1 = monthly
//
if (payment_type === 0) {
console.log("Handling payment type 0: hybrid")
priceItem = recurrence === 0 ? isCloud ? "price_1HhAOgDzMUgUjxHSmesUZkNU" : "price_1HhAOgDzMUgUjxHSmesUZkNU" : isCloud ? "price_1HhAOgDzMUgUjxHSfU8XzQ84" : "price_1HhAOgDzMUgUjxHSfU8XzQ84"
ReactGA.event({
category: "pricing",
action: `hybrid_pay_click`,
label: "",
})
} else if (payment_type === 1) {
console.log("Handling payment type 1: enterprise")
priceItem = recurrence === 0 ? isCloud ? "price_1HhAdrDzMUgUjxHSsIDOCYgm" : "price_1HhAdrDzMUgUjxHSsIDOCYgm" : isCloud ? "price_1HhAdrDzMUgUjxHS7Cu5vF95" : "price_1HhAdrDzMUgUjxHS7Cu5vF95"
if (recurrence === 1) {
text = "enterprise_monthly_pay_click"
}
ReactGA.event({
category: "pricing",
action: text,
label: "",
})
} else if (payment_type === 2) {
console.log("Handling payment type 2: basic")
priceItem = recurrence === 0 ? isCloud ? "price_1HnPmWDzMUgUjxHSzEHV5e6t" : "price_1HlvuPDzMUgUjxHS1pvtPONJ" : isCloud ? "price_1HnPmWDzMUgUjxHSGC3Yiact" : "price_1HlvuPDzMUgUjxHSrp7Ws8iu"
ReactGA.event({
category: "pricing",
action: `mssp_pay_click`,
label: "",
})
} else {
console.log(`No handler for redirect ${payment_type} yet`)
return
}
// Current URL + status = Success/fail
const successUrl = `${window.location.origin}/admin?payment=success`
const failUrl = `${window.location.origin}/pricing?view=failure&variant=${variant}&payment_type=${paymentType}`
var checkoutObject = {
lineItems: [
{price: priceItem, quantity: 1},
],
mode: "subscription",
billingAddressCollection: "auto",
successUrl: successUrl,
cancelUrl: failUrl,
submitType: "donate",
clientReferenceId: props.userdata.active_org.id,
}
stripe.redirectToCheckout(checkoutObject)
.then(function (result) {
console.log("SUCCESS STRIPE?: ", result)
text += "_success"
ReactGA.event({
category: "pricing",
action: text,
label: "",
})
})
.catch(function(error) {
console.error("STRIPE ERROR: ", error)
text += "_fail"
ReactGA.event({
category: "pricing",
action: text,
label: "",
})
});
console.log("Done with payment!")
}
const buttonBackground = "linear-gradient(to right, #f86a3e, #f34079)"
const level1Button =
{
setMonthlyCost(0, paymentType)
setVariant(0)
setModalOpen(true)
ReactGA.event({
category: "pricing",
action: `hybrid_click`,
label: "",
})
}}>
Get hybrid access
const level2Button =
{
//setMonthlyCost(1, paymentType)
//setVariant(1)
//setModalOpen(true)
ReactGA.event({
category: "pricing",
action: `enterprise_click`,
label: "",
})
ReactGA.event({
category: "pricing",
action: `demo_click`,
label: "",
})
if (window.drift !== undefined) {
window.drift.api.startInteraction({ interactionId: 340045 })
}
}}>
Get a demo
const level3Button = skipFreemode ? null :
{
ReactGA.event({
category: "pricing",
action: `getting_started_click`,
label: "",
})
if (shuffleVariant === 0) {
navigate("/register?message=Get started for free")
} else {
window.location.href = "https://github.com/Shuffle/Shuffle/blob/master/.github/install-guide.md"
}
//setMonthlyCost(2, paymentType)
//setVariant(2)
//setModalOpen(true)
}}>
Start building!
const cardStyle = {
height: "100%",
width: "100%",
textAlign: "center",
backgroundColor: theme.palette.surfaceColor,
color: "white",
}
var indexskip = 0
const topRet =
Pricing
{/*
Find pricing, focused on shuffler.io and self-hosted */}
{/*
These prices are likely to change */}
{
event.preventDefault()
setShuffleVariant(0)
ReactGA.event({
category: "pricing",
action: `saas_normal_click`,
label: "",
})
navigate("/pricing?tab=cloud")
}}>Cloud
{
event.preventDefault()
setShuffleVariant(1)
navigate("/pricing?tab=onprem")
ReactGA.event({
category: "pricing",
action: `self_hosted_normal_click`,
label: "",
})
}}>Self-Hosted
{errorMessage.length > 0 ?
Error: {errorMessage} : null}
{skipFreemode ? null :
Free
{shuffleVariant === 0 ?
"shuffler.io / Cloud"
:
Open Source
}
{paymentType === 0 ? "Free" : "Free"}
{shuffleVariant === 0 ?
"Includes 10k App Executions. Refreshes every month."
:
"Unlimited use, self-hosted."
}
{defaultTaskIcon} Use any app
{defaultTaskIcon} Unlimited users
{defaultTaskIcon} Unlimited workflows
{defaultTaskIcon} {
if (window.drift !== undefined) {
window.drift.api.startInteraction({ interactionId: 340043, })
} else {
console.log("Couldn't find drift in window.drift and not .drift-open-chat with querySelector: ", window.drift)
}
}}>Free Support & Discord access
{level3Button}
}
{shuffleVariant === 1 ? "Scale" : "Enterprise"}
{shuffleVariant === 0 ?
"SaaS / Cloud"
:
"Open Source + Scale License"
}
{
if (calculatedCores === "Get A Quote") {
console.log("Clicked on get a quote")
if (window.drift !== undefined) {
window.drift.api.startInteraction({ interactionId: 340785 })
}
}
}}>{calculatedCost}
Per month for {shuffleVariant === 1 ? `${selectedValue} CPU cores` : `${selectedValue}k App Executions`}:
{
handleChange(event, newValue)
}}
marks
value={selectedValue}
step={shuffleVariant === 0 ? 100 : 4}
min={shuffleVariant === 0 ? 100 : 8}
max={shuffleVariant === 0 ? 1000 : 32}
valueLabelDisplay="auto"
/>
{defaultTaskIcon} Priority Support
{defaultTaskIcon} {shuffleVariant === 0 ?
"Multi-Tenant"
:
"Scalable Orborus"
}
{shuffleVariant === 0 ?
{defaultTaskIcon} Multi-Region Tenants
:
{defaultTaskIcon} High Availability
}
{defaultTaskIcon} Help with Workflow and App development
{/*billingInfo*/}
{level2Button}
{shuffleVariant === 0 ?
{
if (isLoggedIn) {
console.log("Redirecting to Stripe!")
const priceItem = window.location.origin === "https://shuffler.io" ? "app_executions" : "price_1MROFrDzMUgUjxHShcSxgHO1"
const successUrl = `${window.location.origin}/admin?admin_tab=billing&payment=success`
const failUrl = `${window.location.origin}/pricing?admin_tab=billing&payment=failure`
var checkoutObject = {
lineItems: [
{
price: priceItem,
quantity: selectedValue/100,
},
],
mode: "subscription",
billingAddressCollection: "auto",
successUrl: successUrl,
cancelUrl: failUrl,
clientReferenceId: props.userdata.active_org.id,
}
stripe.redirectToCheckout(checkoutObject)
.then(function (result) {
console.log("SUCCESS STRIPE?: ", result)
ReactGA.event({
category: "pricing",
action: "add_card_success",
label: "",
})
})
.catch(function(error) {
console.error("STRIPE ERROR: ", error)
ReactGA.event({
category: "pricing",
action: "add_card_error",
label: "",
})
});
} else {
console.log("Pay now")
navigate(`/register?view=pricing&message=You need to create a user to continue`)
//navigate("/login?redirect=/pricing")
//to={`/register?app_one=${app.name}&app_two=${secondaryApp.name}&message=You need to login first to connect ${app.name} and ${secondaryApp.name}`}
}
}}>
Get {selectedValue}k App Run Units
:
null}
{/*
{
if (window.drift !== undefined) {
window.drift.api.startInteraction({ interactionId: 340785 })
} else {
console.log("Couldn't find drift in window.drift and not .drift-open-chat with querySelector: ", window.drift)
}
}}>
Or get a quote
*/}
{/*shuffleVariant === 1 ? null :
MSSP
Cross-Customer automation
${paymentType === 0 ? 1999 : 2399}
Per month{paymentType === 0 ? ", billed yearly" : null}
- All previous tiers
- Extra Customer control
- Sub-organization access
- Build Shuffle into your product
{
ReactGA.event({
category: "pricing",
action: `quote_mssp_click`,
label: "",
})
if (window.drift !== undefined) {
window.drift.api.startInteraction({ interactionId: 340785 })
} else {
console.log("Couldn't find drift in window.drift and not .drift-open-chat with querySelector: ", window.drift)
}
}}>
Get a Quote
*/}
{shuffleVariant === 0 ?
"- 100k Executions per month can handle about 500 Assets, and scales linearly."
:
"- 8 CPU-cores (default) can handle about 1500 Assets and scales linearly."
}
- All prices are in USD and exclude VAT
{/*
Shuffle is an Open Source project. Gives access to support, development and features not otherwise available. This applies to both Open Source & Cloud/SaaS. After the transaction is finished, you will immediately have full access to our support team, and you organization will automatically get upgraded resources assigned.
*/}
Pay-as-you-go-pricing
Simple usage based pricing with no long-term commitments
Volume Discounts
Discounts trigger as your usage grows, so you always get a fair price.
Committed-use discounts
Get additional discounts for annual or multi-year commitments
{!showPricing ?
null :
Features ({shuffleVariant === 0 ? "Cloud" : "Self-Hosted"})
{isMobile ? "F" : "Free"}
style={{ textAlign: "left", flex: 2}}
/>
{/*{isMobile ? "H" : "Hybrid"}
style={{ textAlign: "left", flex: 2}}
/>*/}
{isMobile ? "E" : "Enterprise / Scale"}
style={{ textAlign: "left", flex: 2}}
/>
{features.slice(0, parsedFields).map((data, index) => {
//const activeData = data.active ? activeIcon : data.basic === "No" || data.basic === false ? inActiveIcon : data.basic
const basicData = data.basic === "Yes" || data.basic === true ? activeIcon : data.basic === "No" || data.basic === false ? inActiveIcon : data.basic
const communityData = data.community === "Yes" || data.community === true ? activeIcon : data.community === "No" || data.community === false ? inActiveIcon : data.community
const proData = data.pro === "Yes" || data.pro === true ? activeIcon : data.pro === "No" || data.pro === false ? inActiveIcon : data.pro
if (shuffleVariant === 0 && data.cloud === false) {
indexskip += 1
return null
}
if (shuffleVariant === 1 && data.onprem === false) {
indexskip += 1
return null
}
const newindex = index-indexskip
return (
{data.title !== undefined ?
{data.title}
: null}
{data.active === true ?
:
}
{/*
*/}
)
})}
{features.length > parsedFields ?
{
ReactGA.event({
category: "pricing",
action: `see_all_features_click`,
label: "",
})
}}>
See all features
: null
}
{/*isMobile ? null :
{level3Button}
{level1Button}
{level2Button}
*/}
{/*
*/}
}
Scalable models for MSSPs
Need support and automation help for diverse and scalable environments? Our Enterprise and MSSP offerings can help you whether Onprem or in our cloud.
Open Source
CPU-core-based
8 cores included in sub
$75 /
CPU-core
Per month
Cloud
App-Execution based
Pay-as-you-go
${typecost_single} /
app-runs
Per month
Cloud, Hybrid & Onprem
Our support model is built for both the Cloud and Onpremises version of Shuffle, and can be managed between both. Contact us for more info, or to get a quote from one of our verified resellers.
{removeAdditions === true ? null :
Got other questions?
If you got more questions about our pricing and plans, please contact us so we can help
}
const setMonthlyCost = (variant, paymentType) => {
setErrorMessage("")
if (variant === 0 && paymentType === 0) {
setCurrentPrice(129)
} else if (variant === 0 && paymentType === 1) {
setCurrentPrice(155)
} else if (variant === 1 && paymentType === 0) {
setCurrentPrice(999)
} else if (variant === 1 && paymentType === 1) {
setCurrentPrice(1199)
} else if (variant === 2 && paymentType === 0) {
setCurrentPrice(15)
} else if (variant === 2 && paymentType === 1) {
setCurrentPrice(18)
}
}
const modalView = modalOpen ?
{
setModalOpen(false)
ReactGA.event({
category: "pricing",
action: `close_window_outside_click`,
label: "",
})
}}
PaperProps={{
style: {
backgroundColor: "#1f2023",
color: "white",
minWidth: isMobile ? "100%" :500,
padding: 30,
},
}}
>
Shuffle payments
Choose recurrence
{
setPaymentType(0)
setMonthlyCost(variant, 0)
ReactGA.event({
category: "pricing",
action: `yearly_modal_click`,
label: "",
})
}}>Yearly
{
setPaymentType(1)
setMonthlyCost(variant, 1)
ReactGA.event({
category: "pricing",
action: `monthly_modal_click`,
label: "",
})
}}>Monthly
Your plan:
Shuffle {variant === 0 ? "Community" : variant === 2 ? "Free" : "Pro"} Edition
Monthly subtotal:
${currentPrice}
Discount:
{paymentType === 0 ? "20%" : "0%"}
Beta opt-in:
Extra features
What you'll pay now:
${paymentType === 0 ? currentPrice*12 : currentPrice}
{
handleStripeRedirect(variant, paymentType)
}}>
Pay now
Your plan will renew each {paymentType === 0 ? "year" : "month"}.
{/* */}
{
setModalOpen(false)
ReactGA.event({
category: "pricing",
action: `close_window_cancel_click`,
label: "",
})
}} color="primary">
Cancel
: null
return (
{topRet}
{modalView}
)
}
export default PaymentField;