diff --git a/llmstack/client/src/components/SubscriptionUpdateModal.jsx b/llmstack/client/src/components/SubscriptionUpdateModal.jsx new file mode 100644 index 00000000000..eb93c49f64e --- /dev/null +++ b/llmstack/client/src/components/SubscriptionUpdateModal.jsx @@ -0,0 +1,117 @@ +import { useEffect, useState } from "react"; + +import { + TextField, + Button, + FormGroup, + InputLabel, + Paper, + Stack, + Dialog, + DialogTitle, + DialogContent, + DialogActions, + MenuItem, + Select, +} from "@mui/material"; +import { axios } from "../data/axios"; +import { LoadingButton } from "@mui/lab"; +import { enqueueSnackbar } from "notistack"; + +const SubscriptionUpdateModal = ({ open, handleCloseCb, userEmail }) => { + const [subscriptionPrices, setSubscriptionPrices] = useState([]); + const [subscription, setSubscription] = useState(""); + const [updateButtonLoading, setUpdateButtonLoading] = useState(false); + const [updateButtonDisabled, setUpdateButtonDisabled] = useState(false); + const [cancelButtonDisabled, setCancelButtonDisabled] = useState(false); + + useEffect(() => { + axios() + .get("/api/subscriptions/prices") + .then((res) => { + setSubscriptionPrices(res.data.prices || []); + }) + .catch((err) => { + enqueueSnackbar("Error loading subscription prices", { + variant: "error", + }); + }); + }, []); + + return ( + + {"Manage Subscription"} + + + + + + + + Subscription + + + + + + + + { + setCancelButtonDisabled(true); + setUpdateButtonDisabled(true); + setUpdateButtonLoading(true); + axios() + .post("/api/subscriptions/checkout", { + price_id: subscription, + }) + .then((res) => { + enqueueSnackbar("Loading Checkout Page", { + variant: "success", + }); + window.location.href = res.data.checkout_session_url; + }) + .catch((err) => {}) + .finally(() => { + setCancelButtonDisabled(false); + setUpdateButtonDisabled(false); + setUpdateButtonLoading(false); + }); + }} + variant="contained" + > + Update + + + + ); +}; + +export default SubscriptionUpdateModal; diff --git a/llmstack/client/src/pages/setting.jsx b/llmstack/client/src/pages/setting.jsx index 1fadb1e07ed..81559f65b62 100644 --- a/llmstack/client/src/pages/setting.jsx +++ b/llmstack/client/src/pages/setting.jsx @@ -12,12 +12,14 @@ import { Paper, Stack, } from "@mui/material"; + import { styled } from "@mui/material/styles"; import FileUpload from "@mui/icons-material/FileUpload"; import ContentCopy from "@mui/icons-material/ContentCopy"; import { useEffect, useState } from "react"; import { enqueueSnackbar } from "notistack"; import Connections from "../components/Connections"; +import SubscriptionUpdateModal from "../components/SubscriptionUpdateModal"; import { fetchData, patchData } from "./dataUtil"; import { organizationState, profileFlagsState } from "../data/atoms"; import { useRecoilValue } from "recoil"; @@ -140,6 +142,8 @@ const SettingPage = () => { logo: "", }); const [loading, setLoading] = useState(true); + const [subscriptionUpdateModalOpen, setSubscriptionUpdateModalOpen] = + useState(false); const [updateKeys, setUpdateKeys] = useState(new Set()); const profileFlags = useRecoilValue(profileFlagsState); const organization = useRecoilValue(organizationState); @@ -169,6 +173,13 @@ const SettingPage = () => { setLoading(false); }, ); + + const searchParams = new URLSearchParams(window.location.search); + if (searchParams.get("showNotification")) { + enqueueSnackbar(searchParams.get("notificationMessage") || "", { + variant: searchParams.get("notificationType") || "info", + }); + } }, []); const handleUpdate = (update_keys) => { @@ -386,12 +397,6 @@ const SettingPage = () => { {process.env.REACT_APP_ENABLE_SUBSCRIPTION_MANAGEMENT === "true" && ( @@ -411,6 +419,15 @@ const SettingPage = () => { )} + {subscriptionUpdateModalOpen && ( + { + setSubscriptionUpdateModalOpen(false); + }} + userEmail={formData.user_email} + /> + )} ); };