import React, { useState, useEffect } from "react"; import ReactGA from 'react-ga4'; import theme from "../theme.jsx"; import { useTheme } from "@mui/styles"; import countries from "../components/Countries.jsx"; import { Box, Paper, Typography, Divider, Button, Grid, Card, Dialog, DialogTitle, DialogContent, TextField, InputAdornment, IconButton, Chip, Checkbox, Tooltip, Slider, DialogActions, CardContent, ButtonGroup, } from "@mui/material"; import { useNavigate, Link } from "react-router-dom"; import { Autocomplete } from "@mui/material"; import { toast } from "react-toastify" import { Cached as CachedIcon, ContentCopy as ContentCopyIcon, Draw as DrawIcon, Close as CloseIcon, Done as DoneIcon, Clear as ClearIcon, AddTask as AddTaskIcon, } from "@mui/icons-material"; import { typecost, typecost_single, } from "../views/HandlePaymentNew.jsx"; import { handlePayasyougo } from "../views/HandlePaymentNew.jsx" const LicencePopup = (props) => { const { globalUrl, userdata, serverside, billingInfo, stripeKey, setModalOpen, isLoggedIn, isMobile } = props; //const alert = useAlert(); let navigate = useNavigate(); const isCloud = typeof window === 'undefined' || window === undefined || window.location === undefined ? true : window.location.host === "localhost:3002" || window.location.host === "shuffler.io"; const [selectedDealModalOpen, setSelectedDealModalOpen] = React.useState(false); const [dealList, setDealList] = React.useState([]); const [dealName, setDealName] = React.useState(""); const [dealAddress, setDealAddress] = React.useState(""); const [dealType, setDealType] = React.useState("MSSP"); const [selectedOrganization, setSelectedOrganization] = React.useState({}); const [dealCountry, setDealCountry] = React.useState("United States"); const [dealCurrency, setDealCurrency] = React.useState("USD"); const [dealStatus, setDealStatus] = React.useState("initiated"); const [dealValue, setDealValue] = React.useState(""); const [dealDiscount, setDealDiscount] = React.useState(""); const [dealerror, setDealerror] = React.useState(""); const [variant, setVariant] = useState(0) const [shuffleVariant, setShuffleVariant] = useState(isCloud ? 0 : 1) // const parsedFields = maxFields === undefined ? 300 : maxFields const initialShuffleVariant = isCloud ? 0 : 1; const [paymentType, setPaymentType] = useState(0) const [currentPrice, setCurrentPrice] = useState(129) const [isLoaded, setIsLoaded] = useState(false) const [errorMessage, setErrorMessage] = useState("") const [highlight, setHighlight] = useState(false) // 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) const payasyougo = "Pay as you go" const stripe = typeof window === 'undefined' || window.location === undefined ? "" : props.stripeKey === undefined ? "" : window.Stripe ? window.Stripe(props.stripeKey) : "" const paperStyle = { padding: 20, borderRadius: theme.palette.borderRadius, height: "100%", } billingInfo.subscription = { "active": true, "name": "Pay as you go", "price": typecost_single, "currency": "USD", "currency_text": "$", "interval": "app run / month", "description": "Pay as you go", "features": [ "Basic Support", "Limited App Runs (10.000)", ], "limit": 10000, } const sendSignatureRequest = (subscription) => { const url = `${globalUrl}/api/v1/orgs/${selectedOrganization.id}`; fetch(url, { body: JSON.stringify({ org_id: selectedOrganization.id, subscription: subscription, }), mode: "cors", method: "POST", credentials: "include", crossDomain: true, withCredentials: true, headers: { "Content-Type": "application/json; charset=utf-8", }, }) .then((response) => { if (response.status !== 200) { console.log("Error in response"); } return response.json(); }) .then((responseJson) => { console.log("Response from signature request: ", responseJson); }) .catch((error) => { console.log("Error: ", error); }) } const SubscriptionObject = (props) => { const { globalUrl, index, userdata, serverside, billingInfo, stripeKey, selectedOrganization, handleGetOrg, subscription, highlight, } = props; const [signatureOpen, setSignatureOpen] = React.useState(false); const [tosChecked, setTosChecked] = React.useState(subscription.eula_signed) const [hovered, setHovered] = React.useState(false) var top_text = "Base Cloud Access" if (subscription.limit === undefined && subscription.level === undefined || subscription.level === null || subscription.level === 0) { subscription.name = "Enterprise" subscription.currency_text = "$" subscription.price = subscription.level * 180 subscription.limit = subscription.level * 100000 subscription.interval = subscription.recurrence subscription.features = [ "Includes " + subscription.limit + " app runs/month. ", "Multi-Tenancy and Region-Selection", "And all other features from /pricing", ] } var newPaperstyle = JSON.parse(JSON.stringify(paperStyle)) if (subscription.name === "Enterprise" && subscription.active === true) { top_text = "Current Plan" newPaperstyle.border = "1px solid #f85a3e" } var showSupport = false if (subscription.name.includes("default")) { top_text = "Custom Contract" newPaperstyle.border = "1px solid #f85a3e" showSupport = true } if (subscription.name.includes("App Run Units")) { top_text = "Cloud Access" showSupport = true } if (subscription.name.includes("Open Source")) { top_text = "Open Source" showSupport = true } if (subscription.name.includes("Scale")) { top_text = "Scale access" } if (highlight === true) { // Add an "Upgrade now" button // newPaperstyle.border = "1px solid #f85a3e" } return (
setHovered(true)} // onMouseLeave={() => setHovered(false)} > { e.preventDefault(); setSignatureOpen(false); setTosChecked(false) }} > Read and Accept the EULA { setTosChecked(e.target.checked) }} inputProps={{ 'aria-label': 'primary checkbox' }} /> { setTosChecked(!tosChecked) }}> Accept By clicking the “accept” button, you are signing the document, electronically agreeing that it has the same legal validity and effects as a handwritten signature, and that you have the competent authority to represent and sign on behalf an entity. Need support or have questions? Contact us at support@shuffler.io.
{top_text === "Base Cloud Access" && userdata.has_card_available === true ? { console.log("Clicked chip") }} variant="outlined" color="primary" /> : null} {top_text} {top_text === "Base Cloud Access" && userdata.has_card_available === false ? : null} {isCloud && highlight === true && top_text !== "Base Cloud Access" ? { setSignatureOpen(true) }} > : null}
{subscription.name} {subscription.currency_text !== undefined ?
{subscription.currency_text}{subscription.price} / {subscription.interval}
: null} Features
    {subscription.features !== undefined && subscription.features !== null ? subscription.features.map((feature, index) => { var parsedFeature = feature if (feature.includes("Documentation: ")) { parsedFeature = Documentation to get started } if (feature.includes("Worker License: ")) { const fieldId = "webhook_uri_field_" + index parsedFeature = Use the {feature.split("Worker License: ")[0]} Worker { }} InputProps={{ endAdornment: { var copyText = document.getElementById(fieldId); if (copyText !== undefined && copyText !== null) { console.log("NAVIGATOR: ", navigator); const clipboard = navigator.clipboard; if (clipboard === undefined) { toast("Can only copy over HTTPS (port 3443)"); return; } navigator.clipboard.writeText(copyText.value); copyText.select(); copyText.setSelectionRange( 0, 99999 ); /* For mobile devices */ /* Copy the text inside the text field */ document.execCommand("copy"); toast("Copied Webhook URL"); } else { console.log("Couldn't find webhook URI field: ", copyText); } }} edge="end" > }} fullWidth /> } return (
  • {parsedFeature}
  • ) }) : null}
{isCloud ? Billing email: {selectedOrganization.org} : null}
{/*
Schedule Call Now
*/}
) } useEffect(() => { console.log("New variant: ", shuffleVariant) if (shuffleVariant === 1) { setCalculatedCost("$600") setSelectedValue(8) } else { setCalculatedCost("$540") setSelectedValue(300) } }, [shuffleVariant]) if (typeof window === 'undefined' || window.location === undefined) { return null } 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 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 < 300) { setCalculatedCost(`Pay as you go`) } else if (newValue === 1000) { setCalculatedCost(`Get A Quote`) } else { setCalculatedCost(`$${newValue * 1000 * typecost}`) } } } 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") { setShuffleVariant(1); } else if (foundTab === "cloud") { setShuffleVariant(0); } } const foundHighlight = params["highlight"]; if (foundHighlight !== null && foundHighlight !== undefined) { setHighlight(true) } } //const skipFreemode = window.location.pathname.startsWith("/admin") const skipFreemode = false const maxwidth = isMobile ? "91%" : skipFreemode ? 1100 : 1200 const activeIcon = const inActiveIcon = const defaultTaskIcon = const buttonBackground = "linear-gradient(to right, #f86a3e, #f34079)" const level1Button = const level2Button = const level3Button = skipFreemode ? null : const cardStyle = { // height: "100%", // width: "100%", // textAlign: "center", color: "white", } const isLoggedInHandler = () => { if (calculatedCost === payasyougo) { handlePayasyougo(props.userdata) return } const priceItem = window.location.origin === "https://shuffler.io" ? shuffleVariant === 0 ? "app_executions" : "cores" : shuffleVariant === 0 ? "price_1MROFrDzMUgUjxHShcSxgHO1" : "price_1NXjQqDzMUgUjxHSg690R4FP" const successUrl = `${window.location.origin}/admin?admin_tab=billing&payment=success` const failUrl = `${window.location.origin}/pricing?admin_tab=billing&payment=failure` console.log("Priceitem: ", priceItem, shuffleVariant) var checkoutObject = { lineItems: [ { price: priceItem, quantity: shuffleVariant === 0 ? selectedValue / 100 : selectedValue, }, ], mode: "subscription", billingAddressCollection: "auto", successUrl: successUrl, cancelUrl: failUrl, clientReferenceId: props.userdata.active_org.id, } if (stripe === undefined || stripe === null || stripe.redirectToCheckout === undefined) { window.open("https://shuffler.io/admin?admin_tab=billing&payment=stripe_error", "_self") } 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: "", }) }) } return (
{isCloud && billingInfo.subscription !== undefined && billingInfo.subscription !== null ? : !isCloud ? {/* */} : null} {isCloud && selectedOrganization.subscriptions !== undefined && selectedOrganization.subscriptions !== null && selectedOrganization.subscriptions.length > 0 ? selectedOrganization.subscriptions .reverse() .map((sub, index) => { return ( ) }) : null} {errorMessage.length > 0 ? Error: {errorMessage} : null}
{shuffleVariant === 1 ? "Scale" : "Enterprise"} {shuffleVariant === 0 ? "SaaS / Cloud - Per Month" : "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} For {shuffleVariant === 1 ? `${selectedValue} CPU cores` : `${selectedValue}k App Runs`}:
{ 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" : "Lightning-Fast Workflows"}
{defaultTaskIcon} {shuffleVariant === 0 ? "Multi-Region Tenants" : "High Availability"}
{defaultTaskIcon} Help with Workflow and App development
) } export default LicencePopup;