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,
List,
ListItemText,
ListItem,
Dialog,
DialogTitle,
DialogContent,
TextField,
InputAdornment,
IconButton,
Chip,
Checkbox,
Tooltip,
DialogContentText,
DialogActions,
LinearProgress
} from "@mui/material";
import { useNavigate, Link, json } 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,
Delete,
RestaurantRounded,
} from "@mui/icons-material";
//import { useAlert
import { typecost, typecost_single, } from "../views/HandlePaymentNew.jsx";
import BillingStats from "../components/BillingStats.jsx";
import { handlePayasyougo } from "../views/HandlePaymentNew.jsx"
import DeleteIcon from '@mui/icons-material/Delete';
const Billing = (props) => {
const { globalUrl, userdata, serverside, billingInfo, stripeKey, selectedOrganization, handleGetOrg, clickedFromOrgTab } = props;
//const alert = useAlert();
let navigate = useNavigate();
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 [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 [openChangeEmailBox, setOpenChangeEmailBox] = useState(false);
const [isMouseOverOnChangeEmail, setIsMouseOverOnChangeEmail] = useState(false);
const [currentAppRunsInPercentage, setCurrentAppRunsInPercentage] = useState(0);
const [currentAppRunsInNumber, setCurrentAppRunsInNumber] = useState(0);
const [alertThresholds, setAlertThresholds] = useState(selectedOrganization.Billing !== undefined && selectedOrganization.Billing.AlertThreshold !== undefined && selectedOrganization.Billing.AlertThreshold !== null ? selectedOrganization.Billing.AlertThreshold : [{ percentage: '', count: '', Email_send: false }]);
const [currentIndex, setCurrentIndex] = useState(0);
useEffect(() => {
if (userdata.app_execution_limit !== undefined && userdata.app_execution_usage !== undefined) {
const percentage = (userdata.app_execution_usage / userdata.app_execution_limit) * 100;
setCurrentAppRunsInPercentage(Math.round(percentage));
setCurrentAppRunsInNumber(userdata.app_execution_limit - userdata.app_execution_usage);
}
}, [userdata]);
const [BillingEmail, setBillingEmail] = useState(selectedOrganization.Billing !== undefined && selectedOrganization.Billing.Email !== undefined && selectedOrganization.Billing.Email != null && selectedOrganization.Billing.Email.length > 0 ? selectedOrganization.Billing.Email : selectedOrganization.org);
useState(() => {
// Set the billing email
setBillingEmail(
selectedOrganization.Billing !== undefined &&
selectedOrganization.Billing.Email !== undefined &&
selectedOrganization.Billing.Email.length > 0
? selectedOrganization.Billing.Email
: selectedOrganization.org
);
// Set and sort the alert thresholds
const alertThresholds = selectedOrganization.Billing !== undefined &&
selectedOrganization.Billing.AlertThreshold !== undefined &&
selectedOrganization.Billing.AlertThreshold !== null
? selectedOrganization.Billing.AlertThreshold
: [{ percentage: '', count: '', Email_send: false }];
const sortedAlertThresholds = alertThresholds.sort((a, b) => {
const countA = parseFloat(a.count);
const countB = parseFloat(b.count);
if (isNaN(countA)) return 1;
if (isNaN(countB)) return -1;
return countA - countB;
});
setAlertThresholds(sortedAlertThresholds);
const findCurrentIndex = sortedAlertThresholds.some(threshold => threshold.Email_send === false);
setCurrentIndex(findCurrentIndex ? sortedAlertThresholds.findIndex(threshold => threshold.Email_send === false) : - 1);
}, [selectedOrganization]);
const stripe = typeof window === 'undefined' || window.location === undefined ? "" : props.stripeKey === undefined ? "" : window.Stripe ? window.Stripe(props.stripeKey) : ""
const products = [
{ code: "", label: "MSSP", phone: "" },
{ code: "", label: "Enterprise", phone: "" },
{ code: "", label: "Consultancy", phone: "" },
{ code: "", label: "Support", phone: "" },
];
const handleGetDeals = (orgId) => {
console.log("Get deals!");
if (orgId.length === 0) {
toast(
"Organization ID not defined (get deals). Please contact us on https://shuffler.io if this persists logout."
);
return;
}
const url = `${globalUrl}/api/v1/orgs/${orgId}/deals`;
fetch(url, {
method: "GET",
credentials: "include",
headers: {
"Content-Type": "application/json",
},
})
.then((response) => {
if (response.status !== 200) {
console.log("Bad status code in get deals: ", response.status);
}
return response.json();
})
.then((responseJson) => {
console.log("Got deals: ", responseJson);
if (responseJson.success === false) {
toast("Failed loading deals. Contact support if this persists");
} else {
setDealList(responseJson);
}
})
.catch((error) => {
console.log("Error getting org deals: ", error);
toast(
"Failed getting deals for your org. Contact support if this persists."
);
});
};
useEffect(() => {
if (isCloud && selectedOrganization.partner_info !== undefined && selectedOrganization.partner_info.reseller === true) {
handleGetDeals(selectedOrganization.id);
}
}, [])
const paperStyle = {
padding: 20,
height: "100%",
minHeight: 280,
maxWidth: 400,
width: "100%",
backgroundColor: theme.palette.platformColor,
borderRadius: theme.palette.borderRadius * 2,
border: "1px solid rgba(255,255,255,0.3)",
marginRight: 10,
marginTop: 15,
}
const isCloud =
window.location.host === "localhost:3002" ||
window.location.host === "shuffler.io";
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": [
"Includes 10.000 app run/month for free. ",
"Pay for what you use with no minimum commitment and cancel anytime.",
],
"limit": 10000,
}
const handleStripeRedirect = () => {
//var priceItem = "price_1MRNF1DzMUgUjxHSfFTUb2Xh"
if (stripe == "") {
console.log("Stripe not loaded")
return
}
var priceItem = "price_1MROFrDzMUgUjxHShcSxgHO1"
const successUrl = `${window.location.origin}/admin?admin_tab=billing&payment=success`
const failUrl = `${window.location.origin}/admin?admin_tab=billing&payment=failure`
var checkoutObject = {
lineItems: [
{
price: priceItem,
quantity: 1
},
],
mode: "subscription",
billingAddressCollection: "auto",
successUrl: successUrl,
cancelUrl: failUrl,
clientReferenceId: props.userdata.active_org.id,
}
//submitType: "donate",
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: "",
})
});
}
const cancelSubscriptions = (subscription_id) => {
const orgId = selectedOrganization.id;
const data = {
subscription_id: subscription_id,
action: "cancel",
org_id: selectedOrganization.id,
};
const url = globalUrl + `/api/v1/orgs/${orgId}/cancel`;
fetch(url, {
mode: "cors",
method: "POST",
body: JSON.stringify(data),
credentials: "include",
crossDomain: true,
withCredentials: true,
headers: {
"Content-Type": "application/json; charset=utf-8",
},
})
.then(function (response) {
if (response.status !== 200) {
console.log("Error in response");
}
if (handleGetOrg != undefined) {
handleGetOrg(selectedOrganization.id);
}
return response.json();
})
.then(function (responseJson) {
if (responseJson.success !== undefined && responseJson.success) {
toast("Successfully stopped subscription!");
} else {
toast("Failed stopping subscription. Please contact us.");
}
})
.catch(function (error) {
console.log("Error: ", error);
toast("Failed stopping subscription. Please contact us.");
});
};
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)
const [newBillingEmail, setNewBillingEmail] = useState('');
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"
}
if (hovered) {
newPaperstyle.backgroundColor = theme.palette.surfaceColor
}
const handleClickOpen = () => {
setOpenChangeEmailBox(true);
};
const handleCloseChangeEmailBox = () => {
setOpenChangeEmailBox(false);
};
const getCircularReplacer = () => {
const seen = new WeakSet();
return (key, value) => {
if (typeof value === 'object' && value !== null) {
if (seen.has(value)) {
return;
}
seen.add(value);
}
return value;
};
};
const HandleChangeBillingEmail = (orgId) => {
const email = newBillingEmail;
const emailPattern = /^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,6}$/;
console.log("Pattern matches: ", emailPattern.test(email));
if (!emailPattern.test(email)) {
toast("Please enter a valid email address");
return;
} else {
setNewBillingEmail(email);
}
toast("Updating billing email. Please Wait")
const data = {
org_id: orgId,
email: newBillingEmail,
billing: {
email: newBillingEmail,
},
};
const url = `${globalUrl}/api/v1/orgs/${orgId}/billing`;
fetch(url, {
method: "POST",
body: JSON.stringify(data),
credentials: "include",
headers: {
"Content-Type": "application/json",
},
})
.then((response) => {
if (response.status !== 200) {
console.log("Bad status code in get org:", response.status);
}
return response.json();
}).then((responseJson) => {
console.log("Got org:", responseJson);
if (responseJson.success === true) {
toast.success("Successfully updated billing email");
setBillingEmail(newBillingEmail);
setOpenChangeEmailBox(false);
} else {
toast.error("Failed to update billing email. Please try again.");
}
})
.catch((error) => {
console.log("Error getting org:", error);
});
}
return (
: null}
{isCloud && highlight === true && top_text !== "Base Cloud Access" ?
{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 =