Skip to content

Commit e955af0

Browse files
show free/premium assets + redirect to subscription page on clicking premium asset
1 parent 3d41e3f commit e955af0

File tree

4 files changed

+89
-31
lines changed

4 files changed

+89
-31
lines changed

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ export interface SearchParams {
99
per_page: number;
1010
page: 1;
1111
sort: string;
12-
formats: string;
12+
formats?: string;
13+
price?: string;
1314
}
1415

1516
export type ResponseType = {
@@ -57,7 +58,6 @@ class IconscoutApi extends Api {
5758
withCredentials: false,
5859
params: {
5960
...params,
60-
'formats[]': params.formats,
6161
},
6262
});
6363
} catch (error) {

client/packages/lowcoder/src/comps/comps/meetingComp/controlButton.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -342,13 +342,13 @@ let ButtonTmpComp = (function () {
342342
{children.iconSize.propertyView({
343343
label: trans("button.iconSize"),
344344
})}
345-
</Section>
346-
<Section name={sectionNames.style}>
347-
{children.style.getPropertyView()}
348345
{children.aspectRatio.propertyView({
349346
label: trans("style.aspectRatio"),
350347
})}
351348
</Section>
349+
<Section name={sectionNames.style}>
350+
{children.style.getPropertyView()}
351+
</Section>
352352
</>
353353
)}
354354
</>

client/packages/lowcoder/src/comps/controls/iconscoutControl.tsx

Lines changed: 75 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
import {
66
BlockGrayLabel,
77
ControlPropertyViewWrapper,
8+
CustomModal,
89
DeleteInputIcon,
910
TacoButton,
1011
TacoInput,
@@ -25,6 +26,9 @@ import { getBase64 } from "@lowcoder-ee/util/fileUtils";
2526
import Flex from "antd/es/flex";
2627
import Typography from "antd/es/typography";
2728
import LoadingOutlined from "@ant-design/icons/LoadingOutlined";
29+
import Badge from "antd/es/badge";
30+
import { CrownFilled } from "@ant-design/icons";
31+
import { SUBSCRIPTION_SETTING } from "@lowcoder-ee/constants/routesURL";
2832

2933
const ButtonWrapper = styled.div`
3034
width: 100%;
@@ -125,7 +129,7 @@ const IconList = styled(List)`
125129
`;
126130

127131
const IconRow = styled.div`
128-
padding: 0 6px;
132+
padding: 6px;
129133
display: flex;
130134
align-items: flex-start; /* Align items to the start to allow different heights */
131135
justify-content: space-between;
@@ -134,37 +138,56 @@ const IconRow = styled.div`
134138
gap: 8px;
135139
justify-content: flex-start;
136140
}
141+
142+
.ant-badge {
143+
height: 100%;
144+
}
137145
`;
138146

139147
const IconItemContainer = styled.div`
140148
width: 60px;
149+
height: 60px;
141150
display: flex;
142151
flex-direction: column;
143152
align-items: center;
144153
justify-content: flex-start;
145154
cursor: pointer;
146155
font-size: 28px;
147-
margin-bottom: 24px;
156+
border-radius: 4px;
157+
background: #fafafa;
148158
149159
&:hover {
150-
border: 1px solid #315efb;
151-
border-radius: 4px;
160+
box-shadow: 0 8px 24px #1a29470a,0 2px 8px #1a294714;
152161
}
153162
154163
&:focus {
155164
border: 1px solid #315efb;
156-
border-radius: 4px;
157165
box-shadow: 0 0 0 2px #d6e4ff;
158166
}
159167
`;
160168

161-
const IconWrapper = styled.div`
162-
height: auto;
169+
const IconWrapper = styled.div<{$isPremium?: boolean}>`
170+
height: 100%;
163171
display: flex;
164172
align-items: center;
165173
justify-content: center;
174+
${props => props.$isPremium && 'opacity: 0.25' };
175+
`;
176+
177+
const StyledPreviewIcon = styled.img`
178+
width: auto;
179+
height: auto;
180+
max-width: 100%;
181+
max-height: 100%;
166182
`;
167183

184+
const StyledPreviewLotte = styled.video`
185+
width: auto;
186+
height: auto;
187+
max-width: 100%;
188+
max-height: 100%;
189+
`
190+
168191
export enum AssetType {
169192
ICON = "icon",
170193
ILLUSTRATION = "illustration",
@@ -182,9 +205,8 @@ const IconScoutSearchParams: SearchParams = {
182205
query: '',
183206
product_type: 'item',
184207
asset: 'icon',
185-
per_page: 50,
208+
per_page: 25,
186209
page: 1,
187-
formats: 'svg',
188210
sort: 'relevant',
189211
};
190212

@@ -216,13 +238,20 @@ export const IconPicker = (props: {
216238

217239
const fetchResults = async (query: string) => {
218240
setLoading(true);
219-
const result = await IconscoutApi.search({
241+
const freeResult = await IconscoutApi.search({
220242
...IconScoutSearchParams,
221243
asset: props.assetType,
244+
price: 'free',
245+
query,
246+
});
247+
const premiumResult = await IconscoutApi.search({
248+
...IconScoutSearchParams,
249+
asset: props.assetType,
250+
price: 'premium',
222251
query,
223252
});
224253
setLoading(false);
225-
setSearchResults(result.data);
254+
setSearchResults([...freeResult.data, ...premiumResult.data]);
226255
};
227256

228257
const downloadAsset = async (
@@ -271,33 +300,53 @@ export const IconPicker = (props: {
271300
key={icon.uuid}
272301
tabIndex={0}
273302
onClick={() => {
303+
// check if premium content then show subscription popup
304+
// TODO: if user has subscription then skip this if block
305+
if (icon.price !== 0) {
306+
CustomModal.confirm({
307+
title: trans("iconScout.buySubscriptionTitle"),
308+
content: trans("iconScout.buySubscriptionContent"),
309+
onConfirm: () =>{
310+
window.open(SUBSCRIPTION_SETTING, "_blank");
311+
},
312+
confirmBtnType: "primary",
313+
okText: trans("iconScout.buySubscriptionButton"),
314+
})
315+
return;
316+
}
317+
274318
fetchDownloadUrl(
275319
icon.uuid,
276320
props.assetType === AssetType.ICON ? icon.urls.png_64 : icon.urls.thumb,
277321
);
278322
}}
279323
>
280-
<IconWrapper>
281-
{props.assetType === AssetType.ICON && (
282-
<img style={{'width': '100%'}} src={icon.urls.png_64} />
283-
)}
284-
{props.assetType === AssetType.ILLUSTRATION && (
285-
<img style={{'width': '100%'}} src={icon.urls.thumb} />
286-
)}
287-
{props.assetType === AssetType.LOTTIE && (
288-
<video style={{'width': '100%'}} src={icon.urls.thumb} autoPlay />
289-
)}
290-
</IconWrapper>
324+
<Badge
325+
count={icon.price !== 0 ? <CrownFilled style={{color: "#e7b549"}} /> : undefined}
326+
size='small'
327+
>
328+
<IconWrapper $isPremium={icon.price !== 0}>
329+
{props.assetType === AssetType.ICON && (
330+
<StyledPreviewIcon src={icon.urls.png_64} />
331+
)}
332+
{props.assetType === AssetType.ILLUSTRATION && (
333+
<StyledPreviewIcon src={icon.urls.thumb} />
334+
)}
335+
{props.assetType === AssetType.LOTTIE && (
336+
<StyledPreviewLotte src={icon.urls.thumb} autoPlay />
337+
)}
338+
</IconWrapper>
339+
</Badge>
291340
</IconItemContainer>
292341
))}
293342
</IconRow>
294343
),[searchResults]
295344
);
296345

297346
const popupTitle = useMemo(() => {
298-
if (props.assetType === AssetType.ILLUSTRATION) return 'Search Image';
299-
if (props.assetType === AssetType.LOTTIE) return 'Search Animation';
300-
return 'Search Icon';
347+
if (props.assetType === AssetType.ILLUSTRATION) return trans("iconScout.searchImage");
348+
if (props.assetType === AssetType.LOTTIE) return trans("iconScout.searchAnimation");
349+
return trans("iconScout.searchIcon");
301350
}, [props.assetType]);
302351

303352
return (
@@ -337,7 +386,7 @@ export const IconPicker = (props: {
337386
{!loading && Boolean(searchText) && !searchResults?.length && (
338387
<Flex align="center" justify="center" style={{flex: 1}}>
339388
<Typography.Text type="secondary">
340-
No results found.
389+
{trans("iconScout.noResults")}
341390
</Typography.Text>
342391
</Flex>
343392
)}

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4068,6 +4068,15 @@ export const en = {
40684068
discord: "https://discord.com/invite/qMG9uTmAx2",
40694069
},
40704070

4071+
iconScout: {
4072+
"searchImage": "Search Image",
4073+
"searchAnimation": "Search Animation",
4074+
"searchIcon": "Search Icon",
4075+
"noResults": "No results found.",
4076+
"buySubscriptionTitle": "Unlock Premium Assets",
4077+
"buySubscriptionContent": "This asset is exclusive to Media Package Subscribers. Subscribe to Media Package and download high-quality assets without limits!",
4078+
"buySubscriptionButton": "Subscribe Now",
4079+
}
40714080
};
40724081

40734082
// const jsonString = JSON.stringify(en, null, 2);

0 commit comments

Comments
 (0)