Skip to content

Commit be8a681

Browse files
committed
refactor: enhance pricing sections for display-only mode
- Updated RestApiTiersSection, LiteserversTiersSection, and WebhooksPricingSection to support a displayOnly prop, allowing for static content rendering without data fetching. - Adjusted internal logic to manage disabled states based on the displayOnly prop, improving user experience and clarity in pricing interactions. - Refactored related components to ensure consistent handling of user interactions and visual feedback when in display-only mode. These changes collectively improve the flexibility and usability of the pricing sections in the application.
1 parent ec879f4 commit be8a681

File tree

4 files changed

+82
-34
lines changed

4 files changed

+82
-34
lines changed

src/features/tonapi/pricing/ui/LiteserversTiersSection.tsx

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,13 @@ interface LiteserverTierWithUnspent extends DTOLiteproxyTier {
2727
unspentMoney?: UsdCurrencyAmount;
2828
}
2929

30-
export const LiteserversTiersSection: FC = () => {
30+
interface LiteserversTiersSectionProps {
31+
displayOnly?: boolean;
32+
}
33+
34+
export const LiteserversTiersSection: FC<LiteserversTiersSectionProps> = ({
35+
displayOnly = false
36+
}) => {
3137
const navigate = useNavigate();
3238
const [selectedLiteserverTier, setSelectedLiteserverTier] =
3339
useState<LiteserverTierWithUnspent | null>(null);
@@ -38,6 +44,7 @@ export const LiteserversTiersSection: FC = () => {
3844
const { mutateAsync: checkValidChangeTier } = useCheckValidChangeLiteproxyTierMutation();
3945

4046
const isLiteserversInactive = !currentLiteserverTier && !isCurrentLiteserverTierLoading;
47+
const isDisabled = !displayOnly && isLiteserversInactive;
4148

4249
const handleActivateLiteservers = () => {
4350
navigate('../liteservers');
@@ -91,7 +98,7 @@ export const LiteserversTiersSection: FC = () => {
9198
<Text textStyle="h4" fontWeight={600}>
9299
Liteservers
93100
</Text>
94-
{isLiteserversInactive && (
101+
{!displayOnly && isLiteserversInactive && (
95102
<Badge fontSize="xs" colorScheme="gray">
96103
Inactive
97104
</Badge>
@@ -107,7 +114,7 @@ export const LiteserversTiersSection: FC = () => {
107114
>
108115
Learn more about Liteservers
109116
</Link>
110-
{isLiteserversInactive && (
117+
{isDisabled && (
111118
<>
112119
. To get started with Liteservers, activate the service in the{' '}
113120
<Link
@@ -136,9 +143,9 @@ export const LiteserversTiersSection: FC = () => {
136143
rps={tier.rps}
137144
priceDescription="Monthly"
138145
isCurrent={isCurrent}
139-
isDisabled={isLiteserversInactive}
146+
isDisabled={isDisabled}
140147
onSelect={
141-
!isCurrent && !isLiteserversInactive
148+
!isDisabled && !isCurrent
142149
? () => handleSelectLiteserverTier(tier)
143150
: undefined
144151
}
@@ -151,11 +158,9 @@ export const LiteserversTiersSection: FC = () => {
151158
price="Custom"
152159
rps="∞"
153160
priceDescription="Contact us"
154-
isDisabled={isLiteserversInactive}
161+
isDisabled={isDisabled}
155162
onSelect={
156-
!isLiteserversInactive
157-
? openFeedbackModal('unlimited-liteservers')
158-
: undefined
163+
!isDisabled ? openFeedbackModal('unlimited-liteservers') : undefined
159164
}
160165
buttonText="Request"
161166
buttonVariant="contrast"

src/features/tonapi/pricing/ui/RestApiTiersSection.tsx

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,11 @@ import { RefillModal } from 'src/entities';
1313
import { Link as RouterLink } from 'react-router-dom';
1414
import { openFeedbackModal } from 'src/features/feedback/model/feedback';
1515

16-
export const RestApiTiersSection: FC = () => {
16+
interface RestApiTiersSectionProps {
17+
displayOnly?: boolean;
18+
}
19+
20+
export const RestApiTiersSection: FC<RestApiTiersSectionProps> = ({ displayOnly = false }) => {
1721
const [selectedTier, setSelectedTier] = useState<RestApiTier | null>(null);
1822
const { data: tiers, isLoading: isRestApiTiersLoading } = useRestApiTiers();
1923
const { data: currentRestApiTier } = useSelectedRestApiTier();
@@ -97,6 +101,7 @@ export const RestApiTiersSection: FC = () => {
97101
const isCurrent = currentTierId === tier.id;
98102
const isFree = tier.price.amount.eq(0);
99103
const isPayAsYouGo = tier.type === 'pay-as-you-go';
104+
const isDisabled = displayOnly || isCurrent;
100105

101106
return (
102107
<SimpleTierCard
@@ -108,12 +113,12 @@ export const RestApiTiersSection: FC = () => {
108113
isPayAsYouGo
109114
? 'per 1K requests'
110115
: tier.type === 'monthly'
111-
? 'Monthly'
112-
: undefined
116+
? 'Monthly'
117+
: undefined
113118
}
114119
isCurrent={isCurrent}
115120
onSelect={
116-
!isCurrent ? () => handleSelectRestApiTier(tier) : undefined
121+
!isDisabled ? () => handleSelectRestApiTier(tier) : undefined
117122
}
118123
/>
119124
);
@@ -124,7 +129,7 @@ export const RestApiTiersSection: FC = () => {
124129
price="Custom"
125130
rps="∞"
126131
priceDescription="Contact us"
127-
onSelect={openFeedbackModal('unlimited-restapi')}
132+
onSelect={!displayOnly ? openFeedbackModal('unlimited-restapi') : undefined}
128133
buttonText="Request"
129134
buttonVariant="contrast"
130135
/>

src/features/tonapi/pricing/ui/WebhooksPricingSection.tsx

Lines changed: 55 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -175,18 +175,21 @@ export const WebhooksPricingCalculator: FC<{ isDisabled?: boolean }> = ({ isDisa
175175
);
176176
};
177177

178-
export const WebhooksPricingSection: FC = () => {
179-
const navigate = useNavigate();
180-
const { data: webhooks = [], isLoading, error } = useWebhooksQuery(Network.MAINNET);
181-
182-
const isWebhooksUnavailable = Boolean(error);
183-
const isWebhooksInactive = webhooks.length === 0 && !isLoading && !isWebhooksUnavailable;
184-
185-
const handleTryWebhooks = () => {
186-
navigate('../webhooks');
187-
};
188-
189-
// Loading state
178+
/**
179+
* Reusable content component for webhooks pricing section
180+
* Separates rendering logic from data-fetching concerns
181+
*
182+
* Props:
183+
* - isLoading: Show loading spinner (only when fetching data)
184+
* - isInactive: Show Inactive badge and Try Webhooks button
185+
* - onTryWebhooks: Callback for Try Webhooks button
186+
*/
187+
const WebhooksPricingContent: FC<{
188+
isLoading?: boolean;
189+
isInactive?: boolean;
190+
onTryWebhooks?: () => void;
191+
}> = ({ isLoading = false, isInactive = false, onTryWebhooks }) => {
192+
// Show loading state
190193
if (isLoading) {
191194
return (
192195
<Center py="8">
@@ -197,19 +200,19 @@ export const WebhooksPricingSection: FC = () => {
197200

198201
return (
199202
<Box>
200-
{/* Header with Inactive badge */}
203+
{/* Header with optional Inactive badge */}
201204
<Flex align="baseline" gap="3" mb="4">
202205
<Text textStyle="h4" fontWeight={600}>
203206
Webhooks
204207
</Text>
205-
{isWebhooksInactive && (
208+
{isInactive && (
206209
<Badge fontSize="xs" colorScheme="gray">
207210
Inactive
208211
</Badge>
209212
)}
210213
</Flex>
211214

212-
{/* Main content: Pricing diagram and calculator */}
215+
{/* Pricing diagram and calculator */}
213216
<Flex align="flex-start" wrap="wrap" gap="6">
214217
<Box flex="3 1 300px" minW="300px">
215218
<Text textStyle="body2" mb="3" color="text.secondary">
@@ -220,8 +223,8 @@ export const WebhooksPricingSection: FC = () => {
220223
</Box>
221224
<Box flex="1 1 308px" minW="280px">
222225
<WebhooksPricingCalculator />
223-
{isWebhooksInactive && (
224-
<Button w="100%" mt="4" onClick={handleTryWebhooks} variant="primary">
226+
{isInactive && onTryWebhooks && (
227+
<Button w="100%" mt="4" onClick={onTryWebhooks} variant="primary">
225228
Try Webhooks
226229
</Button>
227230
)}
@@ -230,3 +233,38 @@ export const WebhooksPricingSection: FC = () => {
230233
</Box>
231234
);
232235
};
236+
237+
interface WebhooksPricingSectionProps {
238+
displayOnly?: boolean;
239+
}
240+
241+
export const WebhooksPricingSection: FC<WebhooksPricingSectionProps> = ({
242+
displayOnly = false
243+
}) => {
244+
// Hooks must be called unconditionally at top level (React hooks rules)
245+
const navigate = useNavigate();
246+
const {
247+
data: webhooks = [],
248+
isLoading,
249+
error
250+
} = displayOnly
251+
? { data: [], isLoading: false, error: null }
252+
: useWebhooksQuery(Network.MAINNET);
253+
254+
// Display-only mode: render static content without using data-fetching result
255+
if (displayOnly) {
256+
return <WebhooksPricingContent />;
257+
}
258+
259+
// Normal mode: compute state from fetched data and render with callbacks
260+
const isWebhooksUnavailable = Boolean(error);
261+
const isWebhooksInactive = webhooks.length === 0 && !isLoading && !isWebhooksUnavailable;
262+
263+
return (
264+
<WebhooksPricingContent
265+
isLoading={isLoading}
266+
isInactive={isWebhooksInactive}
267+
onTryWebhooks={() => navigate('../webhooks')}
268+
/>
269+
);
270+
};

src/pages/landing/TonApiPricing.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,11 @@ const TonApiPricing = forwardRef<HTMLDivElement, BoxProps>((props, ref) => {
1111
</H3>
1212

1313
<Box maxW="960px" mx="auto">
14-
<RestApiTiersSection />
14+
<RestApiTiersSection displayOnly />
1515
<Divider my="8" />
16-
<LiteserversTiersSection />
16+
<LiteserversTiersSection displayOnly />
1717
<Divider my="8" />
18-
<WebhooksPricingSection />
18+
<WebhooksPricingSection displayOnly />
1919
</Box>
2020
</Box>
2121
);

0 commit comments

Comments
 (0)