Skip to content

Commit 12c6654

Browse files
author
FalkWolsky
committed
Subscription Description content
1 parent 381663b commit 12c6654

File tree

5 files changed

+242
-61
lines changed

5 files changed

+242
-61
lines changed

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,7 @@ export const InitializeSubscription = () => {
302302
const [subscriptionDataError, setSubscriptionDataError] = useState<boolean>(false);
303303
const [checkoutLinkDataLoaded, setCheckoutLinkDataLoaded] = useState<boolean>(false);
304304
const [checkoutLinkDataError, setCheckoutLinkDataError] = useState<boolean>(false);
305+
305306
const [products, setProducts] = useState<Product[]>([
306307
{
307308
pricingType: "Monthly, per User",

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

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,8 @@ import {
33
ALL_APPLICATIONS_URL,
44
DATASOURCE_URL,
55
FOLDER_URL,
6-
FOLDER_URL_PREFIX,
76
FOLDERS_URL,
87
MARKETPLACE_URL,
9-
// MODULE_APPLICATIONS_URL,
108
QUERY_LIBRARY_URL,
119
SETTING_URL,
1210
SUPPORT_URL,
@@ -296,7 +294,7 @@ export default function ApplicationHome() {
296294
],
297295
} : { items: [] },
298296

299-
/* supportSubscription ? {
297+
supportSubscription ? {
300298
items: [
301299
{
302300
text: <TabLabel>{trans("home.support")}</TabLabel>,
@@ -306,7 +304,7 @@ export default function ApplicationHome() {
306304
icon: ({ selected, ...otherProps }) => selected ? <SupportIcon {...otherProps} width={"24px"}/> : <SupportIcon {...otherProps} width={"24px"}/>,
307305
},
308306
],
309-
} : { items: [] }, */
307+
} : { items: [] },
310308

311309
{
312310
items: [

client/packages/lowcoder/src/pages/setting/settingHome.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,11 @@ export function SettingHome() {
129129
!currentOrgAdmin(user) ||
130130
!enableCustomBrand(config) ||
131131
(!isSelfDomain(config) && !isEnterpriseMode(config)),
132+
},
133+
{
134+
key: SettingPageEnum.Subscription,
135+
label: trans("settings.subscription"),
136+
icon: <SubscriptionIcon width={"20px"}/>,
132137
}
133138
];
134139

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
const ProductDescriptions: ProductDescription = {
2+
3+
// Support & Ticket System Subscription
4+
5+
SupportProduct : {
6+
"en" : `
7+
# Lowcoder Support Subscription
8+
9+
## Overview
10+
11+
**Support** is a "per Workspace" (Organization) subscription. This means that all Admins and Editing Users (Developers) within the Workspace, but not "Members" (viewers only), can automatically use this subscription and create their own support tickets. Typically, a Workspace Admin activates the Support Subscription.
12+
13+
The subscription is **calculated monthly** based on the number of Admins & Editing Users. Normal App Viewers are **not charged** and cannot access the Support Center.
14+
15+
## Support Center
16+
17+
The **Support Center** provides an overview of all your support tickets, including the current status of each ticket and the assigned Lowcoder support staff. Each ticket has a detailed page where you can:
18+
- View and edit the full ticket description
19+
- Add attachments
20+
- Leave comments
21+
22+
## Commitment to Your Success
23+
24+
We offer a support system because we are **dedicated to the success** of Lowcoder users! It’s a key value for us, and we will always strive to provide the best support possible.
25+
26+
## Support SLA
27+
28+
We keep our **Service Level Agreement (SLA)** simple:
29+
- We aim to **respond within 1 business day**.
30+
- Our business hours are from **8am to 10pm GMT**.
31+
32+
## Support Levels
33+
34+
1. **First Level Support**: Our initial response aims to resolve your questions quickly.
35+
2. **Second Level Support**: If a deeper technical issue arises, we escalate it to Second Level Support. This is reflected in the ticket's status.
36+
37+
## Bug Fixing Policy
38+
39+
For bug fixes, we aim to resolve issues **within a workweek or faster**. We provide a \`/dev\` or \`/latest\` tagged Docker image for self-hosted installations to quickly apply updates. The actual update process is not in our hands.
40+
41+
For users on \`app.lowcoder.cloud\`, updates are typically done during regular releases, which occur every **two months**. Only in exceptional cases do we apply updates outside of these scheduled releases.
42+
43+
## Platform Focus
44+
45+
We do not develop custom apps for companies, as our primary focus is improving the Lowcoder platform. However, through our support system, we welcome all **questions and suggestions** that help Lowcoder users create their own apps.
46+
47+
## Pricing Table
48+
49+
| User Type | Monthly Price Per User |
50+
|----------------------|------------------------|
51+
| Admin & Editor | €2.90 |
52+
| More than 10 Users | €1.90 |
53+
| More than 100 Users | €0.90 |
54+
| More than 500 Users | €0.49 |
55+
| More than 1,000 Users | €0.29 |
56+
| More than 10,000 Users| €0.19 |
57+
`,
58+
59+
"de": `
60+
# Lowcoder Support-Abonnement
61+
62+
## Übersicht
63+
64+
**Support** ist ein "pro Workspace" (Organisation) Abonnement. Das bedeutet, dass alle Administratoren und Bearbeiter (Entwickler) innerhalb des Workspaces, aber nicht "Mitglieder" (nur Zuschauer), automatisch dieses Abonnement nutzen und ihre eigenen Support-Tickets erstellen können. Typischerweise aktiviert ein Workspace-Administrator das Support-Abonnement.
65+
66+
Das Abonnement wird **monatlich** basierend auf der Anzahl der Administratoren und Bearbeiter berechnet. Normale App-Zuschauer **werden nicht berechnet** und können auf das Support-Center nicht zugreifen.
67+
68+
## Support-Center
69+
70+
Das **Support-Center** bietet einen Überblick über alle Ihre Support-Tickets, einschließlich des aktuellen Status jedes Tickets und des zugewiesenen Lowcoder-Supportmitarbeiters. Jedes Ticket hat eine Detailseite, auf der Sie:
71+
- die vollständige Ticketbeschreibung anzeigen und bearbeiten können
72+
- Anhänge hinzufügen
73+
- Kommentare hinterlassen
74+
75+
## Engagement für Ihren Erfolg
76+
77+
Wir bieten ein Support-System an, weil wir **engagiert für den Erfolg** der Lowcoder-Nutzer sind! Es ist ein zentraler Wert für uns, und wir werden immer versuchen, den bestmöglichen Support zu bieten.
78+
79+
## Support-SLA
80+
81+
Wir halten unser **Service Level Agreement (SLA)** einfach:
82+
- Wir versuchen, **innerhalb eines Geschäftstags zu antworten**.
83+
- Unsere Geschäftszeiten sind von **8 Uhr bis 22 Uhr GMT**.
84+
85+
## Support-Levels
86+
87+
1. **Erster Level-Support**: Unser erster Kontakt versucht, Ihre Fragen schnell zu klären.
88+
2. **Zweiter Level-Support**: Wenn ein tiefergehendes technisches Problem auftritt, eskalieren wir es zum Zweiten Level-Support. Dies spiegelt sich im Status des Tickets wider.
89+
90+
## Fehlerbehebungspolitik
91+
92+
Bei Fehlerbehebungen versuchen wir, Probleme **innerhalb einer Arbeitswoche oder schneller** zu lösen. Wir bieten ein \`/dev\` oder \`/latest\` getaggtes Docker-Image für selbst gehostete Installationen an, um Updates schnell anzuwenden. Der tatsächliche Update-Prozess liegt nicht in unserer Hand.
93+
94+
Für Benutzer auf \`app.lowcoder.cloud\` werden Updates in der Regel während regulärer Releases durchgeführt, die alle **zwei Monate** stattfinden. Nur in außergewöhnlichen Fällen wenden wir Updates außerhalb dieser geplanten Releases an.
95+
96+
## Plattformfokus
97+
98+
Wir entwickeln keine benutzerdefinierten Apps für Unternehmen, da unser Hauptfokus auf der Verbesserung der Lowcoder-Plattform liegt. Durch unser Support-System heißen wir jedoch alle **Fragen und Vorschläge** willkommen, die Lowcoder-Nutzern helfen, ihre eigenen Apps zu erstellen.
99+
100+
## Preistabelle
101+
102+
| Benutzerart | Monatlicher Preis pro Benutzer |
103+
|------------------------|--------------------------------|
104+
| Administrator & Bearbeiter | €2.90 |
105+
| Mehr als 10 Benutzer | €1.90 |
106+
| Mehr als 100 Benutzer | €0.90 |
107+
| Mehr als 500 Benutzer | €0.49 |
108+
| Mehr als 1.000 Benutzer | €0.29 |
109+
| Mehr als 10.000 Benutzer| €0.19 |
110+
`
111+
},
112+
113+
// Media Package Subscription
114+
115+
MediaPackageProduct: {
116+
"en": `
117+
# Media Package Subscription
118+
119+
## Overview
120+
121+
... (Add English description)
122+
`,
123+
"de": `
124+
# Medienpaket-Abonnement
125+
126+
## Übersicht
127+
128+
... (Add German description)
129+
`
130+
}
131+
};
132+
133+
export type Translations = {
134+
[key: string]: string; // Each language key maps to a string
135+
};
136+
137+
export type ProductDescription = {
138+
[productId: string]: Translations; // Each product ID maps to its translations
139+
};
140+
141+
export default ProductDescriptions;
142+

client/packages/lowcoder/src/pages/setting/subscriptions/subscriptionInfo.tsx

Lines changed: 92 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,36 @@
11
import { ArrowIcon } from "lowcoder-design";
22
import styled from "styled-components";
3-
import { trans } from "i18n";
3+
import { trans } from "i18n"; // Assuming this is how you get the user's language
44
import { useParams } from "react-router-dom";
55
import { HeaderBack } from "../permission/styledComponents";
66
import history from "util/history";
77
import { SUBSCRIPTION_SETTING } from "constants/routesURL";
8-
import { getProduct } from '@lowcoder-ee/api/subscriptionApi';
8+
import { getProduct } from '@lowcoder-ee/api/subscriptionApi';
99
import { useState, useEffect } from 'react';
10-
import { Card, Tag, List, Button } from 'antd';
10+
import { Card, Tag, List } from 'antd';
1111
import { CheckCircleOutlined } from '@ant-design/icons';
12-
import { Level1SettingPageContent, Level1SettingPageTitle } from "../styled";
12+
import { Level1SettingPageContent } from "../styled";
13+
import { TacoMarkDown } from "lowcoder-design";
14+
import ProductDescriptions, {Translations, ProductDescription} from "./ProductDescriptions";
1315

1416
const { Meta } = Card;
1517

1618
const Wrapper = styled.div`
1719
padding: 32px 24px;
1820
`;
1921

20-
export function SubscriptionInfo() {
22+
const ContentWrapper = styled.div`
23+
display: flex;
24+
gap: 24px;
25+
`;
2126

22-
const { productId } = useParams<{ productId: string }>();
27+
const FullWidthCard = styled(Card)`
28+
flex-grow: 1;
29+
width: 65%;
30+
`;
31+
32+
// Hook for loading product details
33+
const useProduct = (productId: string) => {
2334
const [product, setProduct] = useState<any>(null);
2435
const [loading, setLoading] = useState<boolean>(true);
2536
const [error, setError] = useState<string | null>(null);
@@ -42,25 +53,55 @@ export function SubscriptionInfo() {
4253
}
4354
}, [productId]);
4455

56+
return { product, loading, error };
57+
};
58+
59+
// Hook for loading markdown content
60+
const useMarkdown = (productId: string | null, userLanguage: string) => {
61+
const [markdownContent, setMarkdownContent] = useState<string>("");
62+
63+
useEffect(() => {
64+
if (productId && userLanguage) {
65+
66+
let descriptionContent : Translations | false;
67+
68+
switch (productId) {
69+
case "QW8L3WPMiNjQjI":
70+
descriptionContent = ProductDescriptions["SupportProduct"];
71+
break;
72+
case "QW8MpIBHxieKXd":
73+
descriptionContent = ProductDescriptions["MediaPackageProduct"];
74+
break;
75+
default:
76+
descriptionContent = false;
77+
break;
78+
}
79+
80+
if (descriptionContent) {
81+
setMarkdownContent(descriptionContent[userLanguage] || descriptionContent.en);
82+
} else {
83+
setMarkdownContent("");
84+
}
85+
}
86+
}, [productId, userLanguage]);
87+
88+
return markdownContent;
89+
};
90+
91+
export function SubscriptionInfo() {
92+
const { productId } = useParams<{ productId: string }>();
93+
const userLanguage = localStorage.getItem('lowcoder_uiLanguage');
94+
const { product, loading, error } = useProduct(productId);
95+
const markdownContent = useMarkdown(productId || null, userLanguage || "en");
96+
4597
if (loading) {
46-
return <div>Loading...</div>;
98+
return <div style={{margin: "40px"}}>Loading...</div>;
4799
}
48100

49101
if (error) {
50102
return <div>{error}</div>;
51103
}
52104

53-
const pricingTable = productId == "QW8L3WPMiNjQjI" && [
54-
{ type: "Admin & Editor", amount: "€2.90 per user, per month" },
55-
{ type: "> 10 Users", amount: "€1.90 per user, per month" },
56-
{ type: "> 100 Users", amount: "€0.90 per user, per month" },
57-
{ type: "> 500 Users", amount: "€0.49 per user, per month" },
58-
{ type: "> 1.000 Users", amount: "€0.29 per user, per month" },
59-
{ type: "> 10.000 Users", amount: "€0.19 per user, per month" },
60-
] || productId == "QW8MpIBHxieKXd" && [
61-
{ type: "User", amount: "$29.00 per month" }
62-
] || [];
63-
64105
return (
65106
<Wrapper>
66107
<HeaderBack>
@@ -69,47 +110,41 @@ export function SubscriptionInfo() {
69110
<span>{product.name}</span>
70111
</HeaderBack>
71112
<Level1SettingPageContent>
72-
<Card
73-
hoverable
74-
style={{ width: 400 }}
75-
cover={<img alt={product.name} src={product.images[0]} />}
76-
actions={[]}
77-
>
78-
<Meta
79-
title={product.name}
80-
description={product.description}
81-
/>
82-
<div style={{ marginTop: 16 }}>
83-
<Tag icon={<CheckCircleOutlined />} color="green">
84-
{product.type.toUpperCase()}
85-
</Tag>
86-
{product.active && (
87-
<Tag icon={<CheckCircleOutlined />} color="blue">
88-
Active
89-
</Tag>
90-
)}
91-
<List
92-
size="small"
93-
header={<h3>What you get:</h3>}
94-
bordered
95-
dataSource={product.marketing_features}
96-
renderItem={(item: { name: string }) => <List.Item>{item.name}</List.Item>}
97-
style={{ marginTop: 16 }}
113+
<ContentWrapper>
114+
<Card
115+
hoverable
116+
style={{ minWidth: "350px", width: "35%" }}
117+
cover={<img alt={product.name} src={product.images[0]} />}
118+
actions={[]}
119+
>
120+
<Meta
121+
title={product.name}
122+
description={product.description}
98123
/>
99-
<List
100-
size="small"
101-
header={<h3>Pricing:</h3>}
102-
bordered
103-
dataSource={pricingTable}
104-
renderItem={(item: { type: string, amount: string }) => (
105-
<List.Item>
106-
<strong>{item.type}:</strong> {item.amount}
107-
</List.Item>
124+
<div style={{ marginTop: 16 }}>
125+
<Tag icon={<CheckCircleOutlined />} color="green">
126+
{product.type.toUpperCase()}
127+
</Tag>
128+
{product.active && (
129+
<Tag icon={<CheckCircleOutlined />} color="blue">
130+
Active
131+
</Tag>
108132
)}
109-
style={{ marginTop: 16 }}
110-
/>
111-
</div>
112-
</Card>
133+
<List
134+
size="small"
135+
header={<h3>What you get:</h3>}
136+
bordered
137+
dataSource={product.marketing_features}
138+
renderItem={(item: { name: string }) => <List.Item>{item.name}</List.Item>}
139+
style={{ marginTop: 16 }}
140+
/>
141+
</div>
142+
</Card>
143+
144+
<FullWidthCard title="Product Documentation">
145+
<TacoMarkDown>{markdownContent}</TacoMarkDown>
146+
</FullWidthCard>
147+
</ContentWrapper>
113148
</Level1SettingPageContent>
114149
</Wrapper>
115150
);

0 commit comments

Comments
 (0)