Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { TemplateCardSkeleton } from './template-card-skeleton';
import cn from 'classnames';

// Marketplace link
const MARKETPLACE_LINK = `${window.location.origin}`;
const MARKETPLACE_LINK = `${window.location.origin}/marketplace`;

// Custom EndMessage component for template list
const EndMessage = memo(() => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { logEvent } from '@refly/telemetry-web';
// styles
import './index.scss';
import { Spin } from '@refly-packages/ai-workspace-common/components/common/spin';
import { Checked, Wait } from 'refly-icons';
import { Checked, Subscription, Wait } from 'refly-icons';
import { IconLightning01 } from '@refly-packages/ai-workspace-common/components/common/icon';
import getClient from '@refly-packages/ai-workspace-common/requests/proxiedRequest';
import {
Expand Down Expand Up @@ -66,8 +66,8 @@ const PriceOption = memo(({ type, isSelected, price, yearlyTotal, onSelect }: Pr
relative flex-1 p-4 rounded-xl cursor-pointer transition-all duration-200
${
isSelected
? 'border-2 border-[#0E9F77] bg-white'
: 'border-[1.5px] border-gray-200 bg-[#FAFAFA] hover:border-[#0E9F77]'
? 'border-2 !border-solid !border-black bg-white'
: 'border-2 !border-solid !border-gray-200 bg-[#FAFAFA] hover:border-[#0E9F77]'
}
`}
onClick={handleClick}
Expand All @@ -77,7 +77,10 @@ const PriceOption = memo(({ type, isSelected, price, yearlyTotal, onSelect }: Pr
{type === 'monthly' ? t('subscription.monthly') : t('subscription.yearly')}
</span>
{type === 'yearly' && (
<Tag className="!m-0 !px-2 !py-0.5 !text-xs !font-medium !rounded" color="orange">
<Tag
className="!m-0 !px-2 !py-0.5 !text-xs !font-medium !rounded-full !border-0"
color="orange"
>
{t('subscription.save20')}
</Tag>
)}
Expand Down Expand Up @@ -105,62 +108,79 @@ interface FeatureItemProps {
feature: Feature;
isEnterprise?: boolean;
isLast?: boolean;
planType?: string;
featureIndex?: number;
}

const FeatureItem = memo(({ feature, isEnterprise, isLast }: FeatureItemProps) => {
const parts = feature.name.split('\n');
const name = parts[0];
const description = parts.length > 1 ? parts.slice(1).join('\n') : null;
const FeatureItem = memo(
({ feature, isEnterprise, isLast, planType, featureIndex }: FeatureItemProps) => {
const parts = feature.name.split('\n');
const name = parts[0];
const description = parts.length > 1 ? parts.slice(1).join('\n') : null;

// For plus plan, make the 2nd and 3rd description green
const isGreenDescription =
planType === 'plus' &&
featureIndex !== undefined &&
(featureIndex === 1 || featureIndex === 2);

// Handle pointFreeTools type with special display logic
if (feature.type === 'pointFreeTools' && feature.items && feature.items.length > 0) {
return (
<div className="flex flex-col gap-2">
{/* Header with check icon */}
<div className="flex items-start gap-3">
<div className="flex-shrink-0 mt-0.5">
<Checked size={16} color="#0E9F77" />
</div>
<span className="text-sm leading-5 text-gray-900 font-semibold">{name}</span>
</div>
{/* Sub-items list */}
<div className="ml-7 p-3 rounded-lg bg-transparent flex flex-col gap-2">
{feature.items.map((item, index) => (
<div key={index} className="flex items-center justify-between">
<div className="flex items-center gap-2">
<span className="w-1.5 h-1.5 rounded-full bg-[#0E9F77] flex-shrink-0" />
<span className="text-sm text-gray-700">{item}</span>
</div>
{feature.duration && (
<span className="text-xs font-medium text-gray-500 bg-white px-2 py-0.5 rounded">
{feature.duration}
</span>
)}
</div>
))}
</div>
</div>
);
}
Comment on lines +128 to +156
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash

# Search for pointFreeTools references in i18n files
echo "=== Searching for pointFreeTools in i18n files ==="
rg "pointFreeTools" packages/i18n/src -g "*.{ts,json}" -C 2

# Search for pointFreeTools in the entire packages directory
echo -e "\n=== Searching for pointFreeTools in entire packages ==="
rg "pointFreeTools" packages -g "*.{ts,tsx,js,jsx,json}" -C 1

# Check the zh-Hans translation file specifically
echo -e "\n=== Checking zh-Hans UI file ==="
cat packages/i18n/src/zh-Hans/ui.ts | head -170 | tail -40

Repository: refly-ai/refly

Length of output: 2784


Remove dead code for pointFreeTools feature rendering.

The rendering logic for pointFreeTools type features (lines 128-156) is dead code. The corresponding feature data is commented out in all translation files (both en-US and zh-Hans), so this branch will never execute. Remove this unused rendering logic to reduce code complexity and maintenance burden.

🤖 Prompt for AI Agents
In
packages/ai-workspace-common/src/components/settings/subscribe-modal/priceContent.tsx
around lines 128 to 156, the JSX branch that renders features of type
'pointFreeTools' is dead code because the corresponding feature data is removed
from all translation files; delete this entire conditional block (the if
(feature.type === 'pointFreeTools' && feature.items && feature.items.length > 0)
{ ... } section) and any now-unused imports or variables that become redundant
as a result; after removal, run a build/type-check and search translation/usage
to ensure no remaining references to 'pointFreeTools' remain.


// Handle pointFreeTools type with special display logic
if (feature.type === 'pointFreeTools' && feature.items && feature.items.length > 0) {
return (
<div className="flex flex-col gap-2">
{/* Header with check icon */}
<div className="flex items-start gap-3">
<div className="flex-shrink-0 mt-0.5">
<div className="flex items-start gap-3">
<div className="flex-shrink-0 mt-0.5">
{isEnterprise && isLast ? (
<Wait size={16} color="rgba(28, 31, 35, 0.6)" />
) : (
<Checked size={16} color="#0E9F77" />
</div>
<span className="text-sm leading-5 text-gray-900 font-semibold">{name}</span>
)}
</div>
{/* Sub-items list */}
<div className="ml-7 p-3 rounded-lg bg-transparent flex flex-col gap-2">
{feature.items.map((item, index) => (
<div key={index} className="flex items-center justify-between">
<div className="flex items-center gap-2">
<span className="w-1.5 h-1.5 rounded-full bg-[#0E9F77] flex-shrink-0" />
<span className="text-sm text-gray-700">{item}</span>
</div>
{feature.duration && (
<span className="text-xs font-medium text-gray-500 bg-white px-2 py-0.5 rounded">
{feature.duration}
</span>
)}
</div>
))}
<div className="flex flex-col gap-0.5">
<span className="text-sm leading-5 text-gray-900 font-semibold">
{name}
{description && (
<span
className={`font-normal ${isGreenDescription ? 'text-green-600' : 'text-gray-500'}`}
>
{' '}
{description}
</span>
)}
</span>
</div>
</div>
);
}

return (
<div className="flex items-start gap-3">
<div className="flex-shrink-0 mt-0.5">
{isEnterprise && isLast ? (
<Wait size={16} color="rgba(28, 31, 35, 0.6)" />
) : (
<Checked size={16} color="#0E9F77" />
)}
</div>
<div className="flex flex-col gap-0.5">
<span className="text-sm leading-5 text-gray-900 font-semibold">
{name}
{description && <span className="font-normal text-gray-500"> {description}</span>}
</span>
</div>
</div>
);
});
},
);

FeatureItem.displayName = 'FeatureItem';

Expand Down Expand Up @@ -195,6 +215,7 @@ const PlanItem = memo((props: PlanItemProps) => {
PlanPriorityMap[PlanPriorityMap[currentPlan as keyof typeof PlanPriorityMap] + 1] ||
'enterprise';
const isUpgrade = upgradePlan === planType;
const [isHovered, setIsHovered] = useState(false);
const isDowngrade =
PlanPriorityMap[currentPlan as keyof typeof PlanPriorityMap] >
PlanPriorityMap[planType as keyof typeof PlanPriorityMap];
Expand Down Expand Up @@ -253,7 +274,7 @@ const PlanItem = memo((props: PlanItemProps) => {
}
return (
<span className="flex items-center justify-center gap-2">
<IconLightning01 size={16} />
<IconLightning01 size={20} color="#0E9F77" />
{t('subscription.plans.upgrade', {
planType: planType.charAt(0).toUpperCase() + planType.slice(1),
})}
Expand All @@ -276,6 +297,12 @@ const PlanItem = memo((props: PlanItemProps) => {
</div>
<p className="text-sm text-gray-500 mb-4">{description}</p>

{/* Price */}
<div className="flex items-baseline gap-2 mb-4">
<span className="text-2xl font-bold text-gray-900">$0</span>
<span className="text-sm text-gray-500">/month</span>
</div>

{/* Button */}
<button
type="button"
Expand All @@ -299,7 +326,7 @@ const PlanItem = memo((props: PlanItemProps) => {
{t('subscription.plans.memberBenefits')}
</span>
{features.map((feature, index) => (
<FeatureItem key={index} feature={feature} />
<FeatureItem key={index} feature={feature} planType={planType} featureIndex={index} />
))}
</div>
</div>
Expand All @@ -314,11 +341,16 @@ const PlanItem = memo((props: PlanItemProps) => {
background:
isCurrentPlan || isUpgrade
? 'linear-gradient(180deg, rgba(14, 159, 119, 0.08) 0%, rgba(255, 255, 255, 0) 30%), #ffffff'
: 'linear-gradient(180deg, #1FC99615, #45BEFF10), #ffffff',
: isHovered
? 'linear-gradient(180deg, #A4FFF6, #CFFFD3), #ffffff'
: '#ffffff',
}}
onMouseEnter={() => setIsHovered(true)}
onMouseLeave={() => setIsHovered(false)}
>
{/* Header */}
<div className="flex items-center gap-2 mb-1">
<Subscription size={24} className="text-gray-900" />
<span className="text-xl font-semibold text-gray-900">{title}</span>
{isCurrentPlan && (
<Tag className="!m-0 !px-2 !py-0.5 !text-xs !font-medium !rounded !bg-gray-100 !text-gray-600 !border-gray-200">
Expand Down Expand Up @@ -386,6 +418,8 @@ const PlanItem = memo((props: PlanItemProps) => {
feature={feature}
isEnterprise={planType === 'enterprise'}
isLast={index === features.length - 1}
planType={planType}
featureIndex={index}
/>
))}
</div>
Expand Down Expand Up @@ -422,7 +456,7 @@ export const PriceContent = memo((props: { source: PriceSource }) => {
}, [currentPlan]);

const plansData = useMemo(() => {
const planTypes = ['free', 'starter', 'maker', 'enterprise'];
const planTypes = ['free', 'plus'];
const data: Record<string, { title: string; description: string; features: Feature[] }> = {};
for (const planType of planTypes) {
const rawFeatures =
Expand Down
25 changes: 13 additions & 12 deletions packages/i18n/src/en-US/ui.ts
Original file line number Diff line number Diff line change
Expand Up @@ -888,7 +888,7 @@ const translations = {
endMessage: {
title: "Didn't find the workflow automation template you need?",
subtitle: "Join our Discord and tell us what you're looking for",
goToMarketplace: 'Go to Marketplace',
goToMarketplace: 'Explore More Templates',
},
},
agentInputPlaceholder: 'Enter task description, Agent will generate reusable workflows',
Expand Down Expand Up @@ -2704,7 +2704,7 @@ const translations = {
getStarted: 'Get Started',
subscribeNow: 'Subscribe Now',
manage: 'Manage Subscription',
currentPlan: 'Current Plan',
currentPlan: 'Your Current Plan',
t1Requests: 'T1 Requests',
t1RequestsDescription:
'T1 models include Claude 3.7 Sonnet (Thinking), DeepSeek R1, o3 Mini, GPT-4o and others. Each successful skill call to T1 models counts as one request.',
Expand Down Expand Up @@ -3591,7 +3591,7 @@ const translations = {
},
},
subscription: {
modalTitle: 'Upgrade to Get More Credits',
modalTitle: 'Upgrade Your Plan to Get More Credits',
cancelAnytime: "Cancel anytime. By subscribing, you agree to Refly's",
privacy: 'Privacy',
terms: 'Terms',
Expand Down Expand Up @@ -3621,14 +3621,15 @@ const translations = {
priceMonthly: '{{price}}/month',
priceYearly: '{{price}}/month',
priceYearlyTotal: '{{price}}/year Save 20%',
upgrade: 'Upgrade to {{planType}}',
upgrade: 'Get {{planType}}',
cannotChangeTo: 'Cannot change to {{planType}}',
currentPlan: 'Current Plan',
currentPlan: 'Your Current Plan',
cannotSwitchTo:
"Legacy plans can't be switched to Plus directly.Please contact [email protected]",
memberBenefits: 'Member Benefits',
free: {
title: 'Free Plan',
description: 'A welcoming gateway to explore the power of AI—completely free',
title: 'Free',
description: 'Ideal for beginners exploring workflow automation',
price: 'Free forever',
buttonText: 'Continue for free',
buttonTextDowngrade: 'Downgrade to Free',
Expand All @@ -3644,9 +3645,9 @@ const translations = {
features: [
'Daily new credits\n300 credits',
'Monthly credits\n2,000 credits',
'New subscribers receive an extra\n2,000 bonus credits',
//'New subscribers receive an extra\n2,000 bonus credits',
'Access to a vast library of tools',
{
/*{
name: 'Credit-free tools',
type: 'pointFreeTools',
items: [
Expand All @@ -3660,7 +3661,7 @@ const translations = {
'X',
],
duration: '365 DAYS',
},
},*/
'Service support\nHigh priority support',
],
},
Expand Down Expand Up @@ -3825,7 +3826,7 @@ const translations = {
storageFullModal: {
free: {
title: 'Free Plan',
titleCn: 'Current Plan',
titleCn: 'Your Current Plan',
description: 'A welcoming gateway to explore the power of AI—completely free',
price: 'Free forever',
buttonText: 'Continue for free',
Expand Down Expand Up @@ -3880,7 +3881,7 @@ const translations = {
'More enterprise features coming soon',
],
},
currentPlan: 'Current Plan',
currentPlan: 'Your Current Plan',
},
},
onboarding: {
Expand Down
8 changes: 4 additions & 4 deletions packages/i18n/src/zh-Hans/ui.ts
Original file line number Diff line number Diff line change
Expand Up @@ -138,9 +138,9 @@ const translations = {
features: [
'每日可获取新积分\n100点',
'每月积分\n2000点',
'首次订阅额外赠送\n2000点',
//'首次订阅额外赠送\n2000点',
'访问丰富的工具库',
{
/*{
name: '免积分使用工具',
type: 'pointFreeTools',
items: [
Expand All @@ -154,7 +154,7 @@ const translations = {
'X',
],
duration: '365 DAYS',
},
},*/
'服务支持\n高优邮件支持',
],
},
Expand Down Expand Up @@ -968,7 +968,7 @@ const translations = {
endMessage: {
title: '没有找到你需要的工作流自动化模板?',
subtitle: '加入我们的 Discord 社区,告诉我们你想要什么',
goToMarketplace: '前往 Marketplace',
goToMarketplace: '探索更多模板',
},
},
agentInputPlaceholder: '输入任务描述,Agent 将生成可复用的工作流',
Expand Down