Skip to content

Commit 41affd4

Browse files
author
FalkWolsky
committed
Introducing Subscription Overview and Support Handling
1 parent eb7c77f commit 41affd4

File tree

14 files changed

+636
-87
lines changed

14 files changed

+636
-87
lines changed

client/packages/lowcoder/src/api/subscriptionApi.ts

Lines changed: 53 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -70,11 +70,11 @@ export interface Pricing {
7070
}
7171

7272
export interface Product {
73-
title: string;
74-
description: string;
75-
image: string;
73+
title?: string;
74+
description?: string;
75+
image?: string;
7676
pricingType: string;
77-
pricing: Pricing[];
77+
product: string;
7878
activeSubscription: boolean;
7979
accessLink: string;
8080
subscriptionId: string;
@@ -235,6 +235,38 @@ export const createCustomer = async (subscriptionCustomer: LowcoderNewCustomer)
235235
}
236236
};
237237

238+
export const getProduct = async (productId : string) => {
239+
const apiBody = {
240+
path: "webhook/secure/get-product",
241+
method: "post",
242+
data: {"productId" : productId},
243+
headers: lcHeaders
244+
};
245+
try {
246+
const result = await SubscriptionApi.secureRequest(apiBody);
247+
return result?.data as any;
248+
} catch (error) {
249+
console.error("Error fetching product:", error);
250+
throw error;
251+
}
252+
};
253+
254+
export const getProducts = async () => {
255+
const apiBody = {
256+
path: "webhook/secure/get-products",
257+
method: "post",
258+
data: {},
259+
headers: lcHeaders
260+
};
261+
try {
262+
const result = await SubscriptionApi.secureRequest(apiBody);
263+
return result?.data as any;
264+
} catch (error) {
265+
console.error("Error fetching product:", error);
266+
throw error;
267+
}
268+
};
269+
238270
export const createCheckoutLink = async (customer: StripeCustomer, priceId: string, quantity: number, discount?: number) => {
239271
const domain = window.location.protocol + "//" + window.location.hostname + (window.location.port ? ':' + window.location.port : '');
240272

@@ -272,40 +304,38 @@ export const InitializeSubscription = () => {
272304
const [checkoutLinkDataError, setCheckoutLinkDataError] = useState<boolean>(false);
273305
const [products, setProducts] = useState<Product[]>([
274306
{
275-
title: "Support Subscription",
276-
description: "Support Ticket System and SLAs to guarantee response time and your project success.",
277-
image: "https://gw.alipayobjects.com/zos/rmsportal/JiqGstEfoWAOHiTxclqi.png",
278307
pricingType: "Monthly, per User",
279-
pricing: [
280-
{ type: "User", amount: "$3.49 (user, month)" },
281-
{ type: "> 10 Users", amount: "$2.49 (user, month)" },
282-
{ type: "> 100 Users", amount: "$1.49 (user, month)" }
283-
],
284308
activeSubscription: false,
285309
accessLink: "1PhH38DDlQgecLSfSukEgIeV",
310+
product: "QW8L3WPMiNjQjI",
286311
subscriptionId: "",
287312
checkoutLink: "",
288313
checkoutLinkDataLoaded: false,
289314
type: "org",
290315
quantity_entity: "orgUser",
291316
},
292317
{
293-
title: "Premium Media Subscription",
294-
description: "Access to all features.",
295-
image: "https://gw.alipayobjects.com/zos/rmsportal/JiqGstEfoWAOHiTxclqi.png",
296318
pricingType: "Monthly, per User",
297-
pricing: [
298-
{ type: "Volume Price", amount: "$20/month" },
299-
{ type: "Single Price", amount: "$25/month" }
300-
],
301319
activeSubscription: false,
302320
accessLink: "1Pf65wDDlQgecLSf6OFlbsD5",
321+
product: "QW8MpIBHxieKXd",
303322
checkoutLink: "",
304323
checkoutLinkDataLoaded: false,
305324
subscriptionId: "",
306325
type: "user",
307326
quantity_entity: "singleItem",
308-
}
327+
},
328+
{
329+
pricingType: "Monthly, per User",
330+
activeSubscription: false,
331+
accessLink: "1PttHIDDlQgecLSf0XP27tXt",
332+
product: "QlQ7cdOh8Lv4dy",
333+
subscriptionId: "",
334+
checkoutLink: "",
335+
checkoutLinkDataLoaded: false,
336+
type: "org",
337+
quantity_entity: "singleItem",
338+
},
309339
]);
310340

311341
const user = useSelector(getUser);
@@ -328,7 +358,7 @@ export const InitializeSubscription = () => {
328358
orgId: orgID,
329359
userId: user.id,
330360
userName: user.username,
331-
type: admin ? "admin" : "user",
361+
type: admin,
332362
companyName: currentOrg?.name || "Unknown",
333363
};
334364

@@ -418,12 +448,13 @@ export const InitializeSubscription = () => {
418448
checkoutLinkDataLoaded,
419449
checkoutLinkDataError,
420450
products,
451+
admin,
421452
};
422453
};
423454

424455
export enum SubscriptionProducts {
425456
SUPPORT = "QW8L3WPMiNjQjI",
426-
MEDIAPACKAGE = 'standard',
457+
MEDIAPACKAGE = 'QW8MpIBHxieKXd',
427458
AZUREAPIS = 'premium',
428459
GOOGLEAPIS = 'enterprise',
429460
AWSAPIS = 'enterprise-global',
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
import Api from "api/api";
2+
import axios, { AxiosInstance, AxiosRequestConfig } from "axios";
3+
import { useSelector } from "react-redux";
4+
import { getUser, getCurrentUser } from "redux/selectors/usersSelectors";
5+
import { useEffect, useState } from "react";
6+
import { calculateFlowCode } from "./apiUtils";
7+
8+
export type ResponseType = {
9+
response: any;
10+
};
11+
12+
export interface Ticket {
13+
key: string;
14+
id: string;
15+
created: string; // ISO date string
16+
priority: {
17+
name: string;
18+
number: string;
19+
};
20+
assignee: {
21+
email: string;
22+
avatar: string;
23+
active: boolean;
24+
timeZone: string;
25+
};
26+
status: {
27+
name: string;
28+
};
29+
updated: string; // ISO date string
30+
title: string;
31+
description: string;
32+
lowcoder_userId: string;
33+
lowcoder_orgId: string;
34+
lowcoder_host: string;
35+
lowcoder_subscription: string;
36+
}
37+
38+
export type TicketList = Ticket[];
39+
40+
// Axios Configuration
41+
const lcHeaders = {
42+
"Lowcoder-Token": calculateFlowCode(),
43+
"Content-Type": "application/json"
44+
};
45+
46+
let axiosIns: AxiosInstance | null = null;
47+
48+
const getAxiosInstance = (clientSecret?: string) => {
49+
if (axiosIns && !clientSecret) {
50+
return axiosIns;
51+
}
52+
53+
const headers: Record<string, string> = {
54+
"Content-Type": "application/json",
55+
};
56+
57+
const apiRequestConfig: AxiosRequestConfig = {
58+
baseURL: "http://localhost:8080/api/flow",
59+
headers,
60+
};
61+
62+
axiosIns = axios.create(apiRequestConfig);
63+
return axiosIns;
64+
};
65+
66+
class SupportApi extends Api {
67+
68+
static async secureRequest(body: any): Promise<any> {
69+
let response;
70+
try {
71+
response = await getAxiosInstance().request({
72+
method: "POST",
73+
withCredentials: true,
74+
data: body,
75+
});
76+
} catch (error) {
77+
console.error("Error at Support Flow Request:", error);
78+
}
79+
return response;
80+
}
81+
82+
}
83+
84+
// API Functions
85+
86+
export const searchCustomerTickets = async (orgID : string, currentUserId : string, domain : string) => {
87+
88+
const apiBody = {
89+
path: "webhook/support/get-issues",
90+
data: {host : domain, orgId : orgID, userId : currentUserId, supportsubscriptionId : "1PostVDDlQgecLSfhG52o5rB"},
91+
method: "post",
92+
headers: lcHeaders
93+
};
94+
try {
95+
const result = await SupportApi.secureRequest(apiBody);
96+
return result.data as TicketList;
97+
} catch (error) {
98+
console.error("Error searching customer:", error);
99+
throw error;
100+
}
101+
};
102+
103+
export const getTicket = async (orgID : string, currentUserId : string, domain : string) => {
104+
105+
const apiBody = {
106+
path: "webhook/support/get-issues",
107+
data: {host : domain, orgId : orgID, userId : currentUserId, supportsubscriptionId : "1PostVDDlQgecLSfhG52o5rB"},
108+
method: "post",
109+
headers: lcHeaders
110+
};
111+
try {
112+
const result = await SupportApi.secureRequest(apiBody);
113+
return result?.data?.data?.length === 1 ? result.data.data as TicketList : null;
114+
} catch (error) {
115+
console.error("Error searching customer:", error);
116+
throw error;
117+
}
118+
};
119+
120+
121+
export default SupportApi;

client/packages/lowcoder/src/app.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212
DATASOURCE_CREATE_URL,
1313
DATASOURCE_EDIT_URL,
1414
DATASOURCE_URL,
15+
SUPPORT_URL,
1516
FOLDER_URL,
1617
FOLDERS_URL,
1718
IMPORT_APP_FROM_TEMPLATE_URL,
@@ -320,6 +321,7 @@ class AppIndex extends React.Component<AppIndexProps, any> {
320321
DATASOURCE_CREATE_URL,
321322
DATASOURCE_EDIT_URL,
322323
DATASOURCE_URL,
324+
SUPPORT_URL,
323325
QUERY_LIBRARY_URL,
324326
FOLDERS_URL,
325327
FOLDER_URL,

client/packages/lowcoder/src/constants/routesURL.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,9 @@ export const PERMISSION_SETTING_DETAIL = `${PERMISSION_SETTING}/:groupId`;
2626
export const ORGANIZATION_SETTING_DETAIL = `${ORGANIZATION_SETTING}/:orgId`;
2727
export const SUBSCRIPTION_SUCCESS = `${SUBSCRIPTION_SETTING}/success`;
2828
export const SUBSCRIPTION_ERROR = `${SUBSCRIPTION_SETTING}/error`;
29-
export const SUBSCRIPTION_DETAIL = `${SUBSCRIPTION_SETTING}/details/:subscriptionId`;
29+
export const SUBSCRIPTION_DETAIL = `${SUBSCRIPTION_SETTING}/details/:subscriptionId/:productId`;
3030
export const SUBSCRIPTION_INFO = `${SUBSCRIPTION_SETTING}/info/:productId`;
31+
export const SUPPORT_DETAIL = `${SUPPORT_URL}/details/:ticketId`;
3132

3233
export const ALL_APPLICATIONS_URL = "/apps";
3334
export const ADMIN_APP_URL = "/ee/:applicationId/:viewMode";
@@ -106,5 +107,5 @@ export const buildGroupId = (groupId: string) => `${PERMISSION_SETTING}/${groupI
106107

107108
export const buildOrgId = (orgId: string) => `${ORGANIZATION_SETTING}/${orgId}`;
108109

109-
export const buildSubscriptionSettingsLink = (subscriptionId: string) => `${SUBSCRIPTION_SETTING}/details/${subscriptionId}`;
110+
export const buildSubscriptionSettingsLink = (subscriptionId: string, productId : string) => `${SUBSCRIPTION_SETTING}/details/${subscriptionId}/${productId}`;
110111
export const buildSubscriptionInfoLink = (productId: string) => `${SUBSCRIPTION_SETTING}/info/${productId}`;

client/packages/lowcoder/src/i18n/locales/en.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3137,6 +3137,7 @@ export const en = {
31373137
"support": "Support",
31383138
"supportTitle": "Lowcoder Support",
31393139
"supportContent": "If you have any questions or need help, please use the ticket system get your issue solved fast.",
3140+
"newSupportTicket": "New Support Ticket",
31403141
},
31413142
"carousel": {
31423143
"dotPosition": "Navigation Dots position",

client/packages/lowcoder/src/pages/ApplicationV2/index.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ import { fetchFolderElements, updateFolder } from "../../redux/reduxActions/fold
6262
import { trans } from "../../i18n";
6363
import { foldersSelector } from "../../redux/selectors/folderSelector";
6464
import Setting from "pages/setting";
65+
import { Support } from "pages/support";
6566
// import { TypographyText } from "../../components/TypographyText";
6667
// import { messageInstance } from "lowcoder-design/src/components/GlobalInstances";
6768
import { isEE } from "util/envUtils";
@@ -300,7 +301,7 @@ export default function ApplicationHome() {
300301
{
301302
text: <TabLabel>{trans("home.support")}</TabLabel>,
302303
routePath: SUPPORT_URL,
303-
routeComp: TrashView,
304+
routeComp: Support,
304305
icon: ({ selected, ...otherProps }) => selected ? <SupportIcon {...otherProps} width={"24px"}/> : <SupportIcon {...otherProps} width={"24px"}/>,
305306
},
306307
],

0 commit comments

Comments
 (0)