Skip to content

Commit

Permalink
feat: payment failed banners and ui block
Browse files Browse the repository at this point in the history
  • Loading branch information
vikrantgupta25 committed Nov 29, 2024
1 parent 2b8a610 commit 916698d
Show file tree
Hide file tree
Showing 10 changed files with 187 additions and 2 deletions.
1 change: 1 addition & 0 deletions ee/query-service/app/api/license.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ func convertLicenseV3ToListLicenseResponse(licensesV3 []*model.LicenseV3) []List
listLicenses := []ListLicenseResponse{}

for _, license := range licensesV3 {
license.Data["is_current"] = license.IsCurrent
listLicenses = append(listLicenses, license.Data)
}
return listLicenses
Expand Down
18 changes: 17 additions & 1 deletion frontend/src/AppRoutes/Private.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import Spinner from 'components/Spinner';
import { LOCALSTORAGE } from 'constants/localStorage';
import ROUTES from 'constants/routes';
import useLicense from 'hooks/useLicense';
import { LICENSE_STATUS } from 'hooks/useLicenseV3';
import useLicenseV3 from 'hooks/useLicenseV3/useLicenseV3';
import { useNotifications } from 'hooks/useNotifications';
import history from 'lib/history';
import { isEmpty, isNull } from 'lodash-es';
Expand Down Expand Up @@ -75,6 +77,11 @@ function PrivateRoute({ children }: PrivateRouteProps): JSX.Element {
isFetching: isFetchingLicensesData,
} = useLicense();

const {
data: licensesV3Data,
isFetching: isFetchingLicenseV3Data,
} = useLicenseV3();

const { t } = useTranslation(['common']);

const isCloudUserVal = isCloudUser();
Expand Down Expand Up @@ -247,7 +254,16 @@ function PrivateRoute({ children }: PrivateRouteProps): JSX.Element {
navigateToWorkSpaceBlocked(currentRoute);
}
}
}, [isFetchingLicensesData]);

if (!isFetchingLicenseV3Data) {
const activeLicense = licensesV3Data?.payload?.data?.find(
(license) => license.is_current,
);
if (activeLicense && activeLicense.status === LICENSE_STATUS.SUSPENDED) {
navigateToWorkSpaceBlocked(currentRoute);
}
}
}, [isFetchingLicensesData, isFetchingLicenseV3Data]);

useEffect(() => {
if (org && org.length > 0 && org[0].id !== undefined) {
Expand Down
23 changes: 23 additions & 0 deletions frontend/src/api/licenses/getAllLicensesV3.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { ApiV3Instance as axios } from 'api';
import { ErrorResponseHandler } from 'api/ErrorResponseHandler';
import { AxiosError } from 'axios';
import { ErrorResponse, SuccessResponse } from 'types/api';
import { LicenseV3ResponseModel } from 'types/api/licenses/getAll';

const getAllLicensesV3 = async (): Promise<
SuccessResponse<LicenseV3ResponseModel> | ErrorResponse
> => {
try {
const response = await axios.get('/licenses');
return {
statusCode: 200,
error: null,
message: response.data.status,
payload: response.data.data,
};
} catch (error) {
return ErrorResponseHandler(error as AxiosError);
}
};

export default getAllLicensesV3;
1 change: 1 addition & 0 deletions frontend/src/constants/reactQueryKeys.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export const REACT_QUERY_KEY = {
GET_ALL_LICENCES: 'GET_ALL_LICENCES',
GET_ALL_LICENCES_V3: 'GET_ALL_LICENCES_V3',
GET_QUERY_RANGE: 'GET_QUERY_RANGE',
GET_ALL_DASHBOARDS: 'GET_ALL_DASHBOARDS',
GET_TRIGGERED_ALERTS: 'GET_TRIGGERED_ALERTS',
Expand Down
43 changes: 43 additions & 0 deletions frontend/src/container/AppLayout/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ import TopNav from 'container/TopNav';
import { useIsDarkMode } from 'hooks/useDarkMode';
import useFeatureFlags from 'hooks/useFeatureFlag';
import useLicense from 'hooks/useLicense';
import { LICENSE_EVENTS } from 'hooks/useLicenseV3/constant';
import useLicenseV3 from 'hooks/useLicenseV3/useLicenseV3';
import { useNotifications } from 'hooks/useNotifications';
import history from 'lib/history';
import ErrorBoundaryFallback from 'pages/ErrorBoundaryFallback/ErrorBoundaryFallback';
Expand Down Expand Up @@ -54,6 +56,11 @@ function AppLayout(props: AppLayoutProps): JSX.Element {

const { data: licenseData, isFetching } = useLicense();

const {
data: licensesV3Data,
isFetching: isFetchingLicenseV3,
} = useLicenseV3();

const isPremiumChatSupportEnabled =
useFeatureFlags(FeatureKeys.PREMIUM_SUPPORT)?.active || false;

Expand Down Expand Up @@ -199,6 +206,7 @@ function AppLayout(props: AppLayoutProps): JSX.Element {
pathname === ROUTES.GET_STARTED_AZURE_MONITORING;

const [showTrialExpiryBanner, setShowTrialExpiryBanner] = useState(false);
const [showPaymentFailedBanner, setShowPaymentFailedBanner] = useState(false);

useEffect(() => {
if (
Expand All @@ -212,6 +220,20 @@ function AppLayout(props: AppLayoutProps): JSX.Element {
}
}, [licenseData, isFetching]);

useEffect(() => {
if (!isFetchingLicenseV3) {
const activeLicense = licensesV3Data?.payload?.data?.find(
(license) => license.is_current,
);
if (
activeLicense &&
activeLicense.event_queue.event === LICENSE_EVENTS.FAILED_PAYMENT
) {
setShowPaymentFailedBanner(true);
}
}
}, [isFetchingLicenseV3, licensesV3Data]);

useEffect(() => {
// after logging out hide the trial expiry banner
if (!isLoggedIn) {
Expand Down Expand Up @@ -290,6 +312,27 @@ function AppLayout(props: AppLayoutProps): JSX.Element {
</div>
)}

{showPaymentFailedBanner && (
<div className="trial-expiry-banner">
Your payment is due. Your workspace will get blocked on{' '}
<span>
{getFormattedDate(licenseData?.payload?.trialEnd || Date.now())}.
</span>
{role === 'ADMIN' ? (
<span>
{' '}
Please{' '}
<a className="upgrade-link" onClick={handleUpgrade}>
upgrade
</a>
to continue using SigNoz features.
</span>
) : (
'Please contact your administrator for upgrading to a paid plan.'
)}
</div>
)}

<Flex className={cx('app-layout', isDarkMode ? 'darkMode' : 'lightMode')}>
{isToDisplayLayout && !renderFullScreen && (
<SideNav licenseData={licenseData} isFetching={isFetching} />
Expand Down
20 changes: 20 additions & 0 deletions frontend/src/hooks/useLicenseV3/constant.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
export const LICENSE_STATE = {
ISSUED: 'ISSUED',
ACTIVE: 'ACTIVE',
TRIAL_ENDED: 'TRIAL_ENDED',
PAYMENT_FAILED: 'PAYMENT_FAILED',
EXPIRED: 'EXPIRED',
CANCELLED: 'CANCELLED',
INACTIVE: 'INACTIVE',
};

export const LICENSE_STATUS = {
VALID: 'VALID',
SUSPENDED: 'SUSPENDED',
INACTIVE: 'INACTIVE',
};

export const LICENSE_EVENTS = {
FAILED_PAYMENT: 'FAILED_PAYMENT',
END_FAILED_PAYMENT_GRACE: 'END_FAILED_PAYMENT_GRACE',
};
6 changes: 6 additions & 0 deletions frontend/src/hooks/useLicenseV3/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { LICENSE_STATE, LICENSE_STATUS } from './constant';
import useLicense from './useLicenseV3';

export default useLicense;

export { LICENSE_STATE, LICENSE_STATUS };
25 changes: 25 additions & 0 deletions frontend/src/hooks/useLicenseV3/useLicenseV3.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import getAllLicensesV3 from 'api/licenses/getAllLicensesV3';
import { REACT_QUERY_KEY } from 'constants/reactQueryKeys';
import { useQuery, UseQueryResult } from 'react-query';
import { useSelector } from 'react-redux';
import { AppState } from 'store/reducers';
import { ErrorResponse, SuccessResponse } from 'types/api';
import { LicenseV3ResponseModel } from 'types/api/licenses/getAll';
import AppReducer from 'types/reducer/app';

const useLicenseV3 = (): UseLicense => {
const { user } = useSelector<AppState, AppReducer>((state) => state.app);

return useQuery({
queryFn: getAllLicensesV3,
queryKey: [REACT_QUERY_KEY.GET_ALL_LICENCES_V3, user?.email],
enabled: !!user?.email,
});
};

type UseLicense = UseQueryResult<
SuccessResponse<LicenseV3ResponseModel> | ErrorResponse,
unknown
>;

export default useLicenseV3;
46 changes: 46 additions & 0 deletions frontend/src/types/api/licenses/def.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,49 @@ export interface License {
status: string;
isCurrent: boolean;
}

export interface Feature {
name: string;
active: boolean;
usage: number;
usage_limit: number;
route: string;
}

export interface Event {
event: string;
status: string;
scheduled_at: string;
created_at: string;
updated_at: string;
}

export interface Plan {
id: string;
name: string;
platform: string;
description: string;
is_active: boolean;
created_at: string;
updated_at: string;
}

export interface User {
email: string;
}

export interface LicenseV3 {
category: string;
valid_from: number;
valid_until: number;
status: string;
state: string;
created_at: string;
updated_at: string;
plan_id: string;
user: User;
plan: Plan;
features: Feature[];
event_queue: Event;
is_current: boolean;
}
6 changes: 5 additions & 1 deletion frontend/src/types/api/licenses/getAll.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { License } from './def';
import { License, LicenseV3 } from './def';

export type PayloadProps = {
trialStart: number;
Expand All @@ -9,3 +9,7 @@ export type PayloadProps = {
gracePeriodEnd: number;
licenses: License[];
};

export type LicenseV3ResponseModel = {
data: LicenseV3[];
};

0 comments on commit 916698d

Please sign in to comment.