mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-07-29 03:32:01 +08:00
chore(subscription): update the checkout and portal endpoints to use zeus (#7310)
### Summary - update the checkout and portal endpoints to use `zeus` instead of license server
This commit is contained in:
parent
458bd1171b
commit
c26277cd42
@ -7,6 +7,7 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"go.signoz.io/signoz/ee/query-service/constants"
|
"go.signoz.io/signoz/ee/query-service/constants"
|
||||||
|
"go.signoz.io/signoz/ee/query-service/integrations/signozio"
|
||||||
"go.signoz.io/signoz/ee/query-service/model"
|
"go.signoz.io/signoz/ee/query-service/model"
|
||||||
"go.signoz.io/signoz/pkg/http/render"
|
"go.signoz.io/signoz/pkg/http/render"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
@ -48,6 +49,10 @@ type details struct {
|
|||||||
BillTotal float64 `json:"billTotal"`
|
BillTotal float64 `json:"billTotal"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Redirect struct {
|
||||||
|
RedirectURL string `json:"redirectURL"`
|
||||||
|
}
|
||||||
|
|
||||||
type billingDetails struct {
|
type billingDetails struct {
|
||||||
Status string `json:"status"`
|
Status string `json:"status"`
|
||||||
Data struct {
|
Data struct {
|
||||||
@ -119,36 +124,31 @@ func (ah *APIHandler) refreshLicensesV3(w http.ResponseWriter, r *http.Request)
|
|||||||
render.Success(w, http.StatusNoContent, nil)
|
render.Success(w, http.StatusNoContent, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getCheckoutPortalResponse(redirectURL string) *Redirect {
|
||||||
|
return &Redirect{RedirectURL: redirectURL}
|
||||||
|
}
|
||||||
|
|
||||||
func (ah *APIHandler) checkout(w http.ResponseWriter, r *http.Request) {
|
func (ah *APIHandler) checkout(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
type checkoutResponse struct {
|
checkoutRequest := &model.CheckoutRequest{}
|
||||||
Status string `json:"status"`
|
if err := json.NewDecoder(r.Body).Decode(checkoutRequest); err != nil {
|
||||||
Data struct {
|
RespondError(w, model.BadRequest(err), nil)
|
||||||
RedirectURL string `json:"redirectURL"`
|
return
|
||||||
} `json:"data"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
hClient := &http.Client{}
|
license := ah.LM().GetActiveLicense()
|
||||||
req, err := http.NewRequest("POST", constants.LicenseSignozIo+"/checkout", r.Body)
|
if license == nil {
|
||||||
|
RespondError(w, model.BadRequestStr("cannot proceed with checkout without license key"), nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
redirectUrl, err := signozio.CheckoutSession(r.Context(), checkoutRequest, license.Key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
RespondError(w, model.InternalError(err), nil)
|
RespondError(w, err, nil)
|
||||||
return
|
|
||||||
}
|
|
||||||
req.Header.Add("X-SigNoz-SecretKey", constants.LicenseAPIKey)
|
|
||||||
licenseResp, err := hClient.Do(req)
|
|
||||||
if err != nil {
|
|
||||||
RespondError(w, model.InternalError(err), nil)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// decode response body
|
ah.Respond(w, getCheckoutPortalResponse(redirectUrl))
|
||||||
var resp checkoutResponse
|
|
||||||
if err := json.NewDecoder(licenseResp.Body).Decode(&resp); err != nil {
|
|
||||||
RespondError(w, model.InternalError(err), nil)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
ah.Respond(w, resp.Data)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ah *APIHandler) getBilling(w http.ResponseWriter, r *http.Request) {
|
func (ah *APIHandler) getBilling(w http.ResponseWriter, r *http.Request) {
|
||||||
@ -298,32 +298,23 @@ func (ah *APIHandler) listLicensesV2(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
func (ah *APIHandler) portalSession(w http.ResponseWriter, r *http.Request) {
|
func (ah *APIHandler) portalSession(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
type checkoutResponse struct {
|
portalRequest := &model.PortalRequest{}
|
||||||
Status string `json:"status"`
|
if err := json.NewDecoder(r.Body).Decode(portalRequest); err != nil {
|
||||||
Data struct {
|
RespondError(w, model.BadRequest(err), nil)
|
||||||
RedirectURL string `json:"redirectURL"`
|
return
|
||||||
} `json:"data"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
hClient := &http.Client{}
|
license := ah.LM().GetActiveLicense()
|
||||||
req, err := http.NewRequest("POST", constants.LicenseSignozIo+"/portal", r.Body)
|
if license == nil {
|
||||||
|
RespondError(w, model.BadRequestStr("cannot request the portal session without license key"), nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
redirectUrl, err := signozio.PortalSession(r.Context(), portalRequest, license.Key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
RespondError(w, model.InternalError(err), nil)
|
RespondError(w, err, nil)
|
||||||
return
|
|
||||||
}
|
|
||||||
req.Header.Add("X-SigNoz-SecretKey", constants.LicenseAPIKey)
|
|
||||||
licenseResp, err := hClient.Do(req)
|
|
||||||
if err != nil {
|
|
||||||
RespondError(w, model.InternalError(err), nil)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// decode response body
|
ah.Respond(w, getCheckoutPortalResponse(redirectUrl))
|
||||||
var resp checkoutResponse
|
|
||||||
if err := json.NewDecoder(licenseResp.Body).Decode(&resp); err != nil {
|
|
||||||
RespondError(w, model.InternalError(err), nil)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
ah.Respond(w, resp.Data)
|
|
||||||
}
|
}
|
||||||
|
@ -6,3 +6,11 @@ type ValidateLicenseResponse struct {
|
|||||||
Status status `json:"status"`
|
Status status `json:"status"`
|
||||||
Data map[string]interface{} `json:"data"`
|
Data map[string]interface{} `json:"data"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type CheckoutSessionRedirect struct {
|
||||||
|
RedirectURL string `json:"url"`
|
||||||
|
}
|
||||||
|
type CheckoutResponse struct {
|
||||||
|
Status status `json:"status"`
|
||||||
|
Data CheckoutSessionRedirect `json:"data"`
|
||||||
|
}
|
||||||
|
@ -126,10 +126,98 @@ func SendUsage(ctx context.Context, usage model.UsagePayload) *model.ApiError {
|
|||||||
case 200, 201:
|
case 200, 201:
|
||||||
return nil
|
return nil
|
||||||
case 400, 401:
|
case 400, 401:
|
||||||
return model.BadRequest(errors.Wrap(fmt.Errorf(string(body)),
|
return model.BadRequest(errors.Wrap(errors.New(string(body)),
|
||||||
"bad request error received from license.signoz.io"))
|
"bad request error received from license.signoz.io"))
|
||||||
default:
|
default:
|
||||||
return model.InternalError(errors.Wrap(fmt.Errorf(string(body)),
|
return model.InternalError(errors.Wrap(errors.New(string(body)),
|
||||||
"internal error received from license.signoz.io"))
|
"internal error received from license.signoz.io"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func CheckoutSession(ctx context.Context, checkoutRequest *model.CheckoutRequest, licenseKey string) (string, *model.ApiError) {
|
||||||
|
hClient := &http.Client{}
|
||||||
|
|
||||||
|
reqString, err := json.Marshal(checkoutRequest)
|
||||||
|
if err != nil {
|
||||||
|
return "", model.BadRequest(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := http.NewRequestWithContext(ctx, "POST", C.GatewayUrl+"/v2/subscriptions/me/sessions/checkout", bytes.NewBuffer(reqString))
|
||||||
|
if err != nil {
|
||||||
|
return "", model.BadRequest(err)
|
||||||
|
}
|
||||||
|
req.Header.Set("X-Signoz-Cloud-Api-Key", licenseKey)
|
||||||
|
|
||||||
|
response, err := hClient.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return "", model.BadRequest(err)
|
||||||
|
}
|
||||||
|
body, err := io.ReadAll(response.Body)
|
||||||
|
if err != nil {
|
||||||
|
return "", model.BadRequest(errors.Wrap(err, fmt.Sprintf("failed to read checkout response from %v", C.GatewayUrl)))
|
||||||
|
}
|
||||||
|
defer response.Body.Close()
|
||||||
|
|
||||||
|
switch response.StatusCode {
|
||||||
|
case 201:
|
||||||
|
a := CheckoutResponse{}
|
||||||
|
err = json.Unmarshal(body, &a)
|
||||||
|
if err != nil {
|
||||||
|
return "", model.BadRequest(errors.Wrap(err, "failed to unmarshal zeus checkout response"))
|
||||||
|
}
|
||||||
|
return a.Data.RedirectURL, nil
|
||||||
|
case 400:
|
||||||
|
return "", model.BadRequest(errors.Wrap(errors.New(string(body)),
|
||||||
|
fmt.Sprintf("bad request error received from %v", C.GatewayUrl)))
|
||||||
|
case 401:
|
||||||
|
return "", model.Unauthorized(errors.Wrap(errors.New(string(body)),
|
||||||
|
fmt.Sprintf("unauthorized request error received from %v", C.GatewayUrl)))
|
||||||
|
default:
|
||||||
|
return "", model.InternalError(errors.Wrap(errors.New(string(body)),
|
||||||
|
fmt.Sprintf("internal request error received from %v", C.GatewayUrl)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func PortalSession(ctx context.Context, checkoutRequest *model.PortalRequest, licenseKey string) (string, *model.ApiError) {
|
||||||
|
hClient := &http.Client{}
|
||||||
|
|
||||||
|
reqString, err := json.Marshal(checkoutRequest)
|
||||||
|
if err != nil {
|
||||||
|
return "", model.BadRequest(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := http.NewRequestWithContext(ctx, "POST", C.GatewayUrl+"/v2/subscriptions/me/sessions/portal", bytes.NewBuffer(reqString))
|
||||||
|
if err != nil {
|
||||||
|
return "", model.BadRequest(err)
|
||||||
|
}
|
||||||
|
req.Header.Set("X-Signoz-Cloud-Api-Key", licenseKey)
|
||||||
|
|
||||||
|
response, err := hClient.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return "", model.BadRequest(err)
|
||||||
|
}
|
||||||
|
body, err := io.ReadAll(response.Body)
|
||||||
|
if err != nil {
|
||||||
|
return "", model.BadRequest(errors.Wrap(err, fmt.Sprintf("failed to read portal response from %v", C.GatewayUrl)))
|
||||||
|
}
|
||||||
|
defer response.Body.Close()
|
||||||
|
|
||||||
|
switch response.StatusCode {
|
||||||
|
case 201:
|
||||||
|
a := CheckoutResponse{}
|
||||||
|
err = json.Unmarshal(body, &a)
|
||||||
|
if err != nil {
|
||||||
|
return "", model.BadRequest(errors.Wrap(err, "failed to unmarshal zeus portal response"))
|
||||||
|
}
|
||||||
|
return a.Data.RedirectURL, nil
|
||||||
|
case 400:
|
||||||
|
return "", model.BadRequest(errors.Wrap(errors.New(string(body)),
|
||||||
|
fmt.Sprintf("bad request error received from %v", C.GatewayUrl)))
|
||||||
|
case 401:
|
||||||
|
return "", model.Unauthorized(errors.Wrap(errors.New(string(body)),
|
||||||
|
fmt.Sprintf("unauthorized request error received from %v", C.GatewayUrl)))
|
||||||
|
default:
|
||||||
|
return "", model.InternalError(errors.Wrap(errors.New(string(body)),
|
||||||
|
fmt.Sprintf("internal request error received from %v", C.GatewayUrl)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -265,6 +265,10 @@ func (lm *Manager) ActivateV3(ctx context.Context, licenseKey string) (licenseRe
|
|||||||
return license, nil
|
return license, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (lm *Manager) GetActiveLicense() *model.LicenseV3 {
|
||||||
|
return lm.activeLicenseV3
|
||||||
|
}
|
||||||
|
|
||||||
// CheckFeature will be internally used by backend routines
|
// CheckFeature will be internally used by backend routines
|
||||||
// for feature gating
|
// for feature gating
|
||||||
func (lm *Manager) CheckFeature(featureKey string) error {
|
func (lm *Manager) CheckFeature(featureKey string) error {
|
||||||
|
@ -236,3 +236,11 @@ func ConvertLicenseV3ToLicenseV2(l *LicenseV3) *License {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type CheckoutRequest struct {
|
||||||
|
SuccessURL string `json:"url"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type PortalRequest struct {
|
||||||
|
SuccessURL string `json:"url"`
|
||||||
|
}
|
||||||
|
@ -12,9 +12,7 @@ const updateCreditCardApi = async (
|
|||||||
): Promise<SuccessResponse<CheckoutSuccessPayloadProps> | ErrorResponse> => {
|
): Promise<SuccessResponse<CheckoutSuccessPayloadProps> | ErrorResponse> => {
|
||||||
try {
|
try {
|
||||||
const response = await axios.post('/checkout', {
|
const response = await axios.post('/checkout', {
|
||||||
licenseKey: props.licenseKey,
|
url: props.url,
|
||||||
successURL: props.successURL,
|
|
||||||
cancelURL: props.cancelURL, // temp
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -12,8 +12,7 @@ const manageCreditCardApi = async (
|
|||||||
): Promise<SuccessResponse<CheckoutSuccessPayloadProps> | ErrorResponse> => {
|
): Promise<SuccessResponse<CheckoutSuccessPayloadProps> | ErrorResponse> => {
|
||||||
try {
|
try {
|
||||||
const response = await axios.post('/portal', {
|
const response = await axios.post('/portal', {
|
||||||
licenseKey: props.licenseKey,
|
url: props.url,
|
||||||
returnURL: props.successURL,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -4,33 +4,19 @@ import logEvent from 'api/common/logEvent';
|
|||||||
import { SOMETHING_WENT_WRONG } from 'constants/api';
|
import { SOMETHING_WENT_WRONG } from 'constants/api';
|
||||||
import { useNotifications } from 'hooks/useNotifications';
|
import { useNotifications } from 'hooks/useNotifications';
|
||||||
import { CreditCard, X } from 'lucide-react';
|
import { CreditCard, X } from 'lucide-react';
|
||||||
import { useAppContext } from 'providers/App/App';
|
import { useState } from 'react';
|
||||||
import { useEffect, useState } from 'react';
|
|
||||||
import { useMutation } from 'react-query';
|
import { useMutation } from 'react-query';
|
||||||
import { useLocation } from 'react-router-dom';
|
import { useLocation } from 'react-router-dom';
|
||||||
import { ErrorResponse, SuccessResponse } from 'types/api';
|
import { ErrorResponse, SuccessResponse } from 'types/api';
|
||||||
import { CheckoutSuccessPayloadProps } from 'types/api/billing/checkout';
|
import { CheckoutSuccessPayloadProps } from 'types/api/billing/checkout';
|
||||||
import { License } from 'types/api/licenses/def';
|
|
||||||
|
|
||||||
export default function ChatSupportGateway(): JSX.Element {
|
export default function ChatSupportGateway(): JSX.Element {
|
||||||
const { notifications } = useNotifications();
|
const { notifications } = useNotifications();
|
||||||
const [activeLicense, setActiveLicense] = useState<License | null>(null);
|
|
||||||
|
|
||||||
const [isAddCreditCardModalOpen, setIsAddCreditCardModalOpen] = useState(
|
const [isAddCreditCardModalOpen, setIsAddCreditCardModalOpen] = useState(
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
|
|
||||||
const { licenses, isFetchingLicenses } = useAppContext();
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!isFetchingLicenses && licenses) {
|
|
||||||
const activeValidLicense =
|
|
||||||
licenses.licenses?.find((license) => license.isCurrent === true) || null;
|
|
||||||
|
|
||||||
setActiveLicense(activeValidLicense);
|
|
||||||
}
|
|
||||||
}, [licenses, isFetchingLicenses]);
|
|
||||||
|
|
||||||
const handleBillingOnSuccess = (
|
const handleBillingOnSuccess = (
|
||||||
data: ErrorResponse | SuccessResponse<CheckoutSuccessPayloadProps, unknown>,
|
data: ErrorResponse | SuccessResponse<CheckoutSuccessPayloadProps, unknown>,
|
||||||
): void => {
|
): void => {
|
||||||
@ -66,9 +52,7 @@ export default function ChatSupportGateway(): JSX.Element {
|
|||||||
});
|
});
|
||||||
|
|
||||||
updateCreditCard({
|
updateCreditCard({
|
||||||
licenseKey: activeLicense?.key || '',
|
url: window.location.href,
|
||||||
successURL: window.location.href,
|
|
||||||
cancelURL: window.location.href,
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -11,12 +11,11 @@ import { useNotifications } from 'hooks/useNotifications';
|
|||||||
import { defaultTo } from 'lodash-es';
|
import { defaultTo } from 'lodash-es';
|
||||||
import { CreditCard, HelpCircle, X } from 'lucide-react';
|
import { CreditCard, HelpCircle, X } from 'lucide-react';
|
||||||
import { useAppContext } from 'providers/App/App';
|
import { useAppContext } from 'providers/App/App';
|
||||||
import { useEffect, useMemo, useState } from 'react';
|
import { useMemo, useState } from 'react';
|
||||||
import { useMutation } from 'react-query';
|
import { useMutation } from 'react-query';
|
||||||
import { useLocation } from 'react-router-dom';
|
import { useLocation } from 'react-router-dom';
|
||||||
import { ErrorResponse, SuccessResponse } from 'types/api';
|
import { ErrorResponse, SuccessResponse } from 'types/api';
|
||||||
import { CheckoutSuccessPayloadProps } from 'types/api/billing/checkout';
|
import { CheckoutSuccessPayloadProps } from 'types/api/billing/checkout';
|
||||||
import { License } from 'types/api/licenses/def';
|
|
||||||
|
|
||||||
export interface LaunchChatSupportProps {
|
export interface LaunchChatSupportProps {
|
||||||
eventName: string;
|
eventName: string;
|
||||||
@ -42,13 +41,11 @@ function LaunchChatSupport({
|
|||||||
const { notifications } = useNotifications();
|
const { notifications } = useNotifications();
|
||||||
const {
|
const {
|
||||||
licenses,
|
licenses,
|
||||||
isFetchingLicenses,
|
|
||||||
featureFlags,
|
featureFlags,
|
||||||
isFetchingFeatureFlags,
|
isFetchingFeatureFlags,
|
||||||
featureFlagsFetchError,
|
featureFlagsFetchError,
|
||||||
isLoggedIn,
|
isLoggedIn,
|
||||||
} = useAppContext();
|
} = useAppContext();
|
||||||
const [activeLicense, setActiveLicense] = useState<License | null>(null);
|
|
||||||
const [isAddCreditCardModalOpen, setIsAddCreditCardModalOpen] = useState(
|
const [isAddCreditCardModalOpen, setIsAddCreditCardModalOpen] = useState(
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
@ -104,14 +101,6 @@ function LaunchChatSupport({
|
|||||||
licenses,
|
licenses,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!isFetchingLicenses && licenses) {
|
|
||||||
const activeValidLicense =
|
|
||||||
licenses.licenses?.find((license) => license.isCurrent === true) || null;
|
|
||||||
setActiveLicense(activeValidLicense);
|
|
||||||
}
|
|
||||||
}, [isFetchingLicenses, licenses]);
|
|
||||||
|
|
||||||
const handleFacingIssuesClick = (): void => {
|
const handleFacingIssuesClick = (): void => {
|
||||||
if (showAddCreditCardModal) {
|
if (showAddCreditCardModal) {
|
||||||
logEvent('Disabled Chat Support: Clicked', {
|
logEvent('Disabled Chat Support: Clicked', {
|
||||||
@ -164,9 +153,7 @@ function LaunchChatSupport({
|
|||||||
});
|
});
|
||||||
|
|
||||||
updateCreditCard({
|
updateCreditCard({
|
||||||
licenseKey: activeLicense?.key || '',
|
url: window.location.href,
|
||||||
successURL: window.location.href,
|
|
||||||
cancelURL: window.location.href,
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -292,14 +292,10 @@ function AppLayout(props: AppLayoutProps): JSX.Element {
|
|||||||
}, [user.role]);
|
}, [user.role]);
|
||||||
|
|
||||||
const handleFailedPayment = useCallback((): void => {
|
const handleFailedPayment = useCallback((): void => {
|
||||||
if (activeLicenseV3?.key) {
|
|
||||||
manageCreditCard({
|
manageCreditCard({
|
||||||
licenseKey: activeLicenseV3?.key || '',
|
url: window.location.href,
|
||||||
successURL: window.location.origin,
|
|
||||||
cancelURL: window.location.origin,
|
|
||||||
});
|
});
|
||||||
}
|
}, [manageCreditCard]);
|
||||||
}, [activeLicenseV3?.key, manageCreditCard]);
|
|
||||||
|
|
||||||
const isHome = (): boolean => routeKey === 'HOME';
|
const isHome = (): boolean => routeKey === 'HOME';
|
||||||
|
|
||||||
|
@ -326,9 +326,7 @@ export default function BillingContainer(): JSX.Element {
|
|||||||
});
|
});
|
||||||
|
|
||||||
updateCreditCard({
|
updateCreditCard({
|
||||||
licenseKey: activeLicense?.key || '',
|
url: window.location.href,
|
||||||
successURL: window.location.href,
|
|
||||||
cancelURL: window.location.href,
|
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
logEvent('Billing : Manage Billing', {
|
logEvent('Billing : Manage Billing', {
|
||||||
@ -337,14 +335,11 @@ export default function BillingContainer(): JSX.Element {
|
|||||||
});
|
});
|
||||||
|
|
||||||
manageCreditCard({
|
manageCreditCard({
|
||||||
licenseKey: activeLicense?.key || '',
|
url: window.location.href,
|
||||||
successURL: window.location.href,
|
|
||||||
cancelURL: window.location.href,
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [
|
}, [
|
||||||
activeLicense?.key,
|
|
||||||
isFreeTrial,
|
isFreeTrial,
|
||||||
licenses?.trialConvertedToSubscription,
|
licenses?.trialConvertedToSubscription,
|
||||||
manageCreditCard,
|
manageCreditCard,
|
||||||
|
@ -20,7 +20,6 @@ import { useMutation } from 'react-query';
|
|||||||
import { useHistory, useLocation } from 'react-router-dom';
|
import { useHistory, useLocation } from 'react-router-dom';
|
||||||
import { ErrorResponse, SuccessResponse } from 'types/api';
|
import { ErrorResponse, SuccessResponse } from 'types/api';
|
||||||
import { CheckoutSuccessPayloadProps } from 'types/api/billing/checkout';
|
import { CheckoutSuccessPayloadProps } from 'types/api/billing/checkout';
|
||||||
import { License } from 'types/api/licenses/def';
|
|
||||||
|
|
||||||
const { Title, Text } = Typography;
|
const { Title, Text } = Typography;
|
||||||
|
|
||||||
@ -81,7 +80,6 @@ export default function Support(): JSX.Element {
|
|||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
const { notifications } = useNotifications();
|
const { notifications } = useNotifications();
|
||||||
const { licenses, featureFlags } = useAppContext();
|
const { licenses, featureFlags } = useAppContext();
|
||||||
const [activeLicense, setActiveLicense] = useState<License | null>(null);
|
|
||||||
const [isAddCreditCardModalOpen, setIsAddCreditCardModalOpen] = useState(
|
const [isAddCreditCardModalOpen, setIsAddCreditCardModalOpen] = useState(
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
@ -110,13 +108,6 @@ export default function Support(): JSX.Element {
|
|||||||
const showAddCreditCardModal =
|
const showAddCreditCardModal =
|
||||||
!isPremiumChatSupportEnabled && !licenses?.trialConvertedToSubscription;
|
!isPremiumChatSupportEnabled && !licenses?.trialConvertedToSubscription;
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const activeValidLicense =
|
|
||||||
licenses?.licenses?.find((license) => license.isCurrent === true) || null;
|
|
||||||
|
|
||||||
setActiveLicense(activeValidLicense);
|
|
||||||
}, [licenses?.licenses]);
|
|
||||||
|
|
||||||
const handleBillingOnSuccess = (
|
const handleBillingOnSuccess = (
|
||||||
data: ErrorResponse | SuccessResponse<CheckoutSuccessPayloadProps, unknown>,
|
data: ErrorResponse | SuccessResponse<CheckoutSuccessPayloadProps, unknown>,
|
||||||
): void => {
|
): void => {
|
||||||
@ -152,9 +143,7 @@ export default function Support(): JSX.Element {
|
|||||||
});
|
});
|
||||||
|
|
||||||
updateCreditCard({
|
updateCreditCard({
|
||||||
licenseKey: activeLicense?.key || '',
|
url: window.location.href,
|
||||||
successURL: window.location.href,
|
|
||||||
cancelURL: window.location.href,
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -23,10 +23,9 @@ import { useNotifications } from 'hooks/useNotifications';
|
|||||||
import history from 'lib/history';
|
import history from 'lib/history';
|
||||||
import { CircleArrowRight } from 'lucide-react';
|
import { CircleArrowRight } from 'lucide-react';
|
||||||
import { useAppContext } from 'providers/App/App';
|
import { useAppContext } from 'providers/App/App';
|
||||||
import { useCallback, useEffect, useState } from 'react';
|
import { useCallback, useEffect } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useMutation } from 'react-query';
|
import { useMutation } from 'react-query';
|
||||||
import { License } from 'types/api/licenses/def';
|
|
||||||
import { getFormattedDate } from 'utils/timeUtils';
|
import { getFormattedDate } from 'utils/timeUtils';
|
||||||
|
|
||||||
import CustomerStoryCard from './CustomerStoryCard';
|
import CustomerStoryCard from './CustomerStoryCard';
|
||||||
@ -41,7 +40,6 @@ import {
|
|||||||
export default function WorkspaceBlocked(): JSX.Element {
|
export default function WorkspaceBlocked(): JSX.Element {
|
||||||
const { user, licenses, isFetchingLicenses } = useAppContext();
|
const { user, licenses, isFetchingLicenses } = useAppContext();
|
||||||
const isAdmin = user.role === 'ADMIN';
|
const isAdmin = user.role === 'ADMIN';
|
||||||
const [activeLicense, setActiveLicense] = useState<License | null>(null);
|
|
||||||
const { notifications } = useNotifications();
|
const { notifications } = useNotifications();
|
||||||
|
|
||||||
const { t } = useTranslation(['workspaceLocked']);
|
const { t } = useTranslation(['workspaceLocked']);
|
||||||
@ -72,11 +70,6 @@ export default function WorkspaceBlocked(): JSX.Element {
|
|||||||
if (!shouldBlockWorkspace) {
|
if (!shouldBlockWorkspace) {
|
||||||
history.push(ROUTES.APPLICATION);
|
history.push(ROUTES.APPLICATION);
|
||||||
}
|
}
|
||||||
|
|
||||||
const activeValidLicense =
|
|
||||||
licenses?.licenses?.find((license) => license.isCurrent === true) || null;
|
|
||||||
|
|
||||||
setActiveLicense(activeValidLicense);
|
|
||||||
}
|
}
|
||||||
}, [isFetchingLicenses, licenses]);
|
}, [isFetchingLicenses, licenses]);
|
||||||
|
|
||||||
@ -103,12 +96,10 @@ export default function WorkspaceBlocked(): JSX.Element {
|
|||||||
logEvent('Workspace Blocked: User Clicked Update Credit Card', {});
|
logEvent('Workspace Blocked: User Clicked Update Credit Card', {});
|
||||||
|
|
||||||
updateCreditCard({
|
updateCreditCard({
|
||||||
licenseKey: activeLicense?.key || '',
|
url: window.location.href,
|
||||||
successURL: window.location.origin,
|
|
||||||
cancelURL: window.location.origin,
|
|
||||||
});
|
});
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [activeLicense?.key, updateCreditCard]);
|
}, [updateCreditCard]);
|
||||||
|
|
||||||
const handleExtendTrial = (): void => {
|
const handleExtendTrial = (): void => {
|
||||||
logEvent('Workspace Blocked: User Clicked Extend Trial', {});
|
logEvent('Workspace Blocked: User Clicked Extend Trial', {});
|
||||||
|
@ -51,11 +51,9 @@ function WorkspaceSuspended(): JSX.Element {
|
|||||||
|
|
||||||
const handleUpdateCreditCard = useCallback(async () => {
|
const handleUpdateCreditCard = useCallback(async () => {
|
||||||
manageCreditCard({
|
manageCreditCard({
|
||||||
licenseKey: activeLicenseV3?.key || '',
|
url: window.location.origin,
|
||||||
successURL: window.location.origin,
|
|
||||||
cancelURL: window.location.origin,
|
|
||||||
});
|
});
|
||||||
}, [activeLicenseV3?.key, manageCreditCard]);
|
}, [manageCreditCard]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!isFetchingActiveLicenseV3 && activeLicenseV3) {
|
if (!isFetchingActiveLicenseV3 && activeLicenseV3) {
|
||||||
|
@ -113,7 +113,6 @@ export function getAppContextMock(
|
|||||||
status: '',
|
status: '',
|
||||||
updated_at: '0',
|
updated_at: '0',
|
||||||
},
|
},
|
||||||
key: 'does-not-matter',
|
|
||||||
state: LicenseState.ACTIVE,
|
state: LicenseState.ACTIVE,
|
||||||
status: LicenseStatus.VALID,
|
status: LicenseStatus.VALID,
|
||||||
platform: LicensePlatform.CLOUD,
|
platform: LicensePlatform.CLOUD,
|
||||||
|
@ -3,7 +3,5 @@ export interface CheckoutSuccessPayloadProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface CheckoutRequestPayloadProps {
|
export interface CheckoutRequestPayloadProps {
|
||||||
licenseKey: string;
|
url: string;
|
||||||
successURL: string;
|
|
||||||
cancelURL: string;
|
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,6 @@ export type LicenseV3EventQueueResModel = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export type LicenseV3ResModel = {
|
export type LicenseV3ResModel = {
|
||||||
key: string;
|
|
||||||
status: LicenseStatus;
|
status: LicenseStatus;
|
||||||
state: LicenseState;
|
state: LicenseState;
|
||||||
event_queue: LicenseV3EventQueueResModel;
|
event_queue: LicenseV3EventQueueResModel;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user