mirror of
https://github.com/Litlyx/litlyx
synced 2025-12-10 15:58:38 +01:00
fix payment service + appsumo + ui
This commit is contained in:
@@ -109,6 +109,9 @@ const avgSessionDuration = computed(() => {
|
|||||||
seconds += avg * 60;
|
seconds += avg * 60;
|
||||||
while (seconds >= 60) { seconds -= 60; minutes += 1; }
|
while (seconds >= 60) { seconds -= 60; minutes += 1; }
|
||||||
while (minutes >= 60) { minutes -= 60; hours += 1; }
|
while (minutes >= 60) { minutes -= 60; hours += 1; }
|
||||||
|
|
||||||
|
|
||||||
|
if (hours == 0 && minutes == 0 && seconds < 10) return `0m ~10s`
|
||||||
return `${hours > 0 ? hours + 'h ' : ''}${minutes}m ${seconds.toFixed()}s`
|
return `${hours > 0 ? hours + 'h ' : ''}${minutes}m ${seconds.toFixed()}s`
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ const { data: pendingInvites, refresh: refreshInvites } = useFetch('/api/project
|
|||||||
headers: useComputedHeaders({})
|
headers: useComputedHeaders({})
|
||||||
});
|
});
|
||||||
|
|
||||||
const { userRoles } = useLoggedUser();
|
const { userRoles, isPremium } = useLoggedUser();
|
||||||
const { projectList } = useProject();
|
const { projectList } = useProject();
|
||||||
|
|
||||||
const debugMode = process.dev;
|
const debugMode = process.dev;
|
||||||
@@ -94,6 +94,9 @@ async function generatePDF() {
|
|||||||
|
|
||||||
const { actions } = useProject();
|
const { actions } = useProject();
|
||||||
|
|
||||||
|
const { showDrawer } = useDrawer();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const modal = useModal();
|
const modal = useModal();
|
||||||
|
|
||||||
@@ -138,13 +141,6 @@ function openPendingInvites() {
|
|||||||
}">
|
}">
|
||||||
<div class="py-4 pb-2 px-2 gap-6 flex flex-col w-full">
|
<div class="py-4 pb-2 px-2 gap-6 flex flex-col w-full">
|
||||||
|
|
||||||
<!-- <div class="flex px-2" v-if="!isPremium">
|
|
||||||
<LyxUiButton type="primary" class="w-full text-center text-[.8rem] font-medium" @click="pricingDrawer.visible.value = true;">
|
|
||||||
Upgrade plan
|
|
||||||
</LyxUiButton>
|
|
||||||
</div> -->
|
|
||||||
|
|
||||||
|
|
||||||
<div class="flex px-2 flex-col">
|
<div class="flex px-2 flex-col">
|
||||||
|
|
||||||
<div class="flex items-center gap-2 w-full">
|
<div class="flex items-center gap-2 w-full">
|
||||||
@@ -304,6 +300,16 @@ function openPendingInvites() {
|
|||||||
|
|
||||||
<div class="grow"></div>
|
<div class="grow"></div>
|
||||||
|
|
||||||
|
<LyxUiCard class="w-full mb-4" v-if="!isPremium">
|
||||||
|
<div class="flex flex-col gap-3">
|
||||||
|
<div class="text-center"> Upgrade to premium </div>
|
||||||
|
<LyxUiButton type="primary" class="w-full text-center text-[.8rem] font-medium"
|
||||||
|
@click="showDrawer('PRICING')">
|
||||||
|
Upgrade
|
||||||
|
</LyxUiButton>
|
||||||
|
</div>
|
||||||
|
</LyxUiCard>
|
||||||
|
|
||||||
<div v-if="pendingInvites && pendingInvites.length > 0" @click="openPendingInvites()"
|
<div v-if="pendingInvites && pendingInvites.length > 0" @click="openPendingInvites()"
|
||||||
class="w-full bg-[#fbbf2422] p-4 rounded-lg text-[.9rem] flex flex-col justify-center cursor-pointer">
|
class="w-full bg-[#fbbf2422] p-4 rounded-lg text-[.9rem] flex flex-col justify-center cursor-pointer">
|
||||||
<div class="poppins font-medium dark:text-lyx-text text-lyx-lightmode-text">
|
<div class="poppins font-medium dark:text-lyx-text text-lyx-lightmode-text">
|
||||||
@@ -316,13 +322,18 @@ function openPendingInvites() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<LyxUiSeparator class="px-4 mb-2"></LyxUiSeparator>
|
<!-- <LyxUiSeparator class="px-4 mb-2"></LyxUiSeparator> -->
|
||||||
|
|
||||||
<div class="flex px-1 w-full">
|
|
||||||
|
|
||||||
<LayoutVerticalBottomMenu></LayoutVerticalBottomMenu>
|
|
||||||
|
|
||||||
|
<LyxUiCard class="flex py-1 px-1 w-full relative">
|
||||||
|
<div class="absolute top-[-22%] right-0">
|
||||||
|
<div @click="showDrawer('PRICING')"
|
||||||
|
class="flex items-center gap-1 poppins text-[.5rem] bg-[#fbbe244f] outline outline-[1px] outline-[#fbbf24] px-3 py-[.12rem] rounded-sm">
|
||||||
|
<i class="far fa-crown mb-[2px]"></i>
|
||||||
|
<div>Premium</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
<LayoutVerticalBottomMenu></LayoutVerticalBottomMenu>
|
||||||
|
</LyxUiCard>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ async function redeemCode() {
|
|||||||
Redeemed codes: {{ valid_codes.data.value?.count || '0' }}
|
Redeemed codes: {{ valid_codes.data.value?.count || '0' }}
|
||||||
</div>
|
</div>
|
||||||
<div class="poppins text-[1.1rem] text-lyx-lightmode-text dark:text-yellow-400 mb-2">
|
<div class="poppins text-[1.1rem] text-lyx-lightmode-text dark:text-yellow-400 mb-2">
|
||||||
*Plan upgrades are applicable exclusively to this project(workspace).
|
*Plan upgrades are applied to account level.
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</SettingsTemplate>
|
</SettingsTemplate>
|
||||||
|
|||||||
@@ -6,7 +6,8 @@ const selfhosted = useSelfhosted();
|
|||||||
|
|
||||||
const items = [
|
const items = [
|
||||||
{ label: 'General', slot: 'general', tab: 'general' },
|
{ label: 'General', slot: 'general', tab: 'general' },
|
||||||
{ label: 'Domains', slot: 'domains', tab: 'domains' }
|
{ label: 'Domains', slot: 'domains', tab: 'domains' },
|
||||||
|
{ label: 'Codes', slot: 'codes', tab: 'codes' },
|
||||||
]
|
]
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
@@ -30,7 +31,7 @@ const items = [
|
|||||||
Billing disabled in self-host mode
|
Billing disabled in self-host mode
|
||||||
</div>
|
</div>
|
||||||
</template> -->
|
</template> -->
|
||||||
<!-- <template #codes>
|
<template #codes>
|
||||||
<SettingsCodes v-if="!selfhosted" :key="refreshKey"></SettingsCodes>
|
<SettingsCodes v-if="!selfhosted" :key="refreshKey"></SettingsCodes>
|
||||||
<div class="flex popping text-[1.2rem] font-semibold justify-center mt-[20vh] text-lyx-lightmode-text dark:text-lyx-text"
|
<div class="flex popping text-[1.2rem] font-semibold justify-center mt-[20vh] text-lyx-lightmode-text dark:text-lyx-text"
|
||||||
v-if="selfhosted">
|
v-if="selfhosted">
|
||||||
@@ -39,7 +40,7 @@ const items = [
|
|||||||
</template>
|
</template>
|
||||||
<template #account>
|
<template #account>
|
||||||
<SettingsAccount :key="refreshKey"></SettingsAccount>
|
<SettingsAccount :key="refreshKey"></SettingsAccount>
|
||||||
</template> -->
|
</template>
|
||||||
</CustomTab>
|
</CustomTab>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,17 +1,13 @@
|
|||||||
import { getPlanFromId, PREMIUM_PLAN } from "@data/PREMIUM";
|
import { getPlanFromId, PREMIUM_PLAN } from "@data/PREMIUM";
|
||||||
import { canTryAppsumoCode, checkAppsumoCode, useAppsumoCode, useTryAppsumoCode } from "~/server/services/AppsumoService";
|
import { canTryAppsumoCode, checkAppsumoCode, useAppsumoCode, useTryAppsumoCode } from "~/server/services/AppsumoService";
|
||||||
|
import { PaymentServiceHelper } from "~/server/services/PaymentServiceHelper";
|
||||||
|
import { PremiumModel } from "~/shared/schema/PremiumSchema";
|
||||||
|
|
||||||
|
|
||||||
function getPlanToActivate(current_plan_id: number) {
|
function getPlanToActivate(current_plan_id: number) {
|
||||||
if (current_plan_id === PREMIUM_PLAN.FREE.ID) {
|
if (current_plan_id === PREMIUM_PLAN.FREE.ID) {
|
||||||
return PREMIUM_PLAN.APPSUMO_INCUBATION;
|
return PREMIUM_PLAN.APPSUMO_INCUBATION;
|
||||||
}
|
}
|
||||||
// if (current_plan_id === PREMIUM_PLAN.INCUBATION.ID) {
|
|
||||||
// return PREMIUM_PLAN.APPSUMO_ACCELERATION;
|
|
||||||
// }
|
|
||||||
// if (current_plan_id === PREMIUM_PLAN.ACCELERATION.ID) {
|
|
||||||
// return PREMIUM_PLAN.APPSUMO_GROWTH;
|
|
||||||
// }
|
|
||||||
if (current_plan_id === PREMIUM_PLAN.APPSUMO_INCUBATION.ID) {
|
if (current_plan_id === PREMIUM_PLAN.APPSUMO_INCUBATION.ID) {
|
||||||
return PREMIUM_PLAN.APPSUMO_ACCELERATION;
|
return PREMIUM_PLAN.APPSUMO_ACCELERATION;
|
||||||
}
|
}
|
||||||
@@ -38,13 +34,18 @@ export default defineEventHandler(async event => {
|
|||||||
const valid = await checkAppsumoCode(code);
|
const valid = await checkAppsumoCode(code);
|
||||||
if (!valid) return setResponseStatus(event, 400, 'Code not valid');
|
if (!valid) return setResponseStatus(event, 400, 'Code not valid');
|
||||||
|
|
||||||
// const currentPlan = getPlanFromId(project.premium_type);
|
const currentPremiumData = await PremiumModel.findOne({ user_id: user.id });
|
||||||
// if (!currentPlan) return setResponseStatus(event, 400, 'Current plan not found');
|
if (!currentPremiumData) return setResponseStatus(event, 400, 'Error finding user');
|
||||||
// const planToActivate = getPlanToActivate(currentPlan.ID);
|
|
||||||
// if (!planToActivate) return setResponseStatus(event, 400, 'Cannot use code on current plan');
|
|
||||||
|
|
||||||
// await StripeService.createSubscription(project.customer_id, planToActivate.ID);
|
const currentPlan = getPlanFromId(currentPremiumData.premium_type);
|
||||||
|
if (!currentPlan) return setResponseStatus(event, 400, 'Current plan not found');
|
||||||
|
|
||||||
// await useAppsumoCode(pid, code);
|
const planToActivate = getPlanToActivate(currentPlan.ID);
|
||||||
|
if (!planToActivate) return setResponseStatus(event, 400, 'Cannot use code on current plan');
|
||||||
|
|
||||||
|
const sub = await PaymentServiceHelper.create_subscription(user.id, planToActivate.TAG);
|
||||||
|
console.log(sub);
|
||||||
|
|
||||||
|
await useAppsumoCode(pid, code);
|
||||||
|
|
||||||
});
|
});
|
||||||
@@ -15,6 +15,8 @@ import { TeamMemberModel } from "~/shared/schema/TeamMemberSchema";
|
|||||||
import { PasswordModel } from "~/shared/schema/PasswordSchema";
|
import { PasswordModel } from "~/shared/schema/PasswordSchema";
|
||||||
import { PremiumModel } from "~/shared/schema/PremiumSchema";
|
import { PremiumModel } from "~/shared/schema/PremiumSchema";
|
||||||
import { PaymentServiceHelper } from "~/server/services/PaymentServiceHelper";
|
import { PaymentServiceHelper } from "~/server/services/PaymentServiceHelper";
|
||||||
|
import { VisitModel } from "~/shared/schema/metrics/VisitSchema";
|
||||||
|
import { EventModel } from "~/shared/schema/metrics/EventSchema";
|
||||||
|
|
||||||
export default defineEventHandler(async event => {
|
export default defineEventHandler(async event => {
|
||||||
|
|
||||||
@@ -24,9 +26,8 @@ export default defineEventHandler(async event => {
|
|||||||
const projects = await ProjectModel.find({ owner: userData.id });
|
const projects = await ProjectModel.find({ owner: userData.id });
|
||||||
|
|
||||||
const premium = await PremiumModel.findOne({ user_id: userData.id });
|
const premium = await PremiumModel.findOne({ user_id: userData.id });
|
||||||
if (!premium) return;
|
|
||||||
|
|
||||||
if (premium.premium_type > 0) return setResponseStatus(event, 400, 'Cannot delete an account with a premium project');
|
if (premium && premium.premium_type > 0) return setResponseStatus(event, 400, 'Cannot delete an account with a premium project');
|
||||||
|
|
||||||
const membersDeletation = await TeamMemberModel.deleteMany({ user_id: userData.id });
|
const membersDeletation = await TeamMemberModel.deleteMany({ user_id: userData.id });
|
||||||
const membersEmailDeletation = await TeamMemberModel.deleteMany({ email: userData.user.email });
|
const membersEmailDeletation = await TeamMemberModel.deleteMany({ email: userData.user.email });
|
||||||
@@ -36,24 +37,31 @@ export default defineEventHandler(async event => {
|
|||||||
const limitdeletation = await UserLimitModel.deleteMany({ user_id: userData.id });
|
const limitdeletation = await UserLimitModel.deleteMany({ user_id: userData.id });
|
||||||
const notifiesDeletation = await LimitNotifyModel.deleteMany({ user_id: userData.id });
|
const notifiesDeletation = await LimitNotifyModel.deleteMany({ user_id: userData.id });
|
||||||
|
|
||||||
await PaymentServiceHelper.delete_customer(premium.customer_id);
|
if (premium) PaymentServiceHelper.delete_customer(premium.customer_id);
|
||||||
|
|
||||||
|
|
||||||
for (const project of projects) {
|
for (const project of projects) {
|
||||||
const project_id = project._id;
|
const project_id = project._id;
|
||||||
|
|
||||||
const projectDeletation = await ProjectModel.deleteOne({ _id: project_id });
|
const projectDeletation = await ProjectModel.deleteOne({ _id: project_id });
|
||||||
const userSettingsDeletation = await UserSettingsModel.deleteOne({ project_id });
|
const userSettingsDeletation = await UserSettingsModel.deleteOne({ project_id });
|
||||||
const countDeletation = await ProjectCountModel.deleteMany({ project_id });
|
const countDeletation = await ProjectCountModel.deleteMany({ project_id });
|
||||||
const sessionsDeletation = await SessionModel.deleteMany({ project_id });
|
|
||||||
const aiChatsDeletation = await AiChatModel.deleteMany({ project_id });
|
const sessionsDeletation = SessionModel.deleteMany({ project_id });
|
||||||
|
const visitsDeletation = VisitModel.deleteMany({ project_id });
|
||||||
|
const eventsDeletation = EventModel.deleteMany({ project_id });
|
||||||
|
|
||||||
|
const aiChatsDeletation = AiChatModel.deleteMany({ project_id });
|
||||||
|
|
||||||
//Shields
|
//Shields
|
||||||
const addressBlacklistDeletation = await AddressBlacklistModel.deleteMany({ project_id });
|
const addressBlacklistDeletation = AddressBlacklistModel.deleteMany({ project_id });
|
||||||
const botTrafficOptionsDeletation = await BotTrafficOptionModel.deleteMany({ project_id });
|
const botTrafficOptionsDeletation = BotTrafficOptionModel.deleteMany({ project_id });
|
||||||
const countryBlacklistDeletation = await CountryBlacklistModel.deleteMany({ project_id });
|
const countryBlacklistDeletation = CountryBlacklistModel.deleteMany({ project_id });
|
||||||
const domainWhitelistDeletation = await DomainWhitelistModel.deleteMany({ project_id });
|
const domainWhitelistDeletation = DomainWhitelistModel.deleteMany({ project_id });
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const premiumDeletation = await PremiumModel.deleteOne({ user_id: userData.id });
|
||||||
const userDeletation = await UserModel.deleteOne({ _id: userData.id });
|
const userDeletation = await UserModel.deleteOne({ _id: userData.id });
|
||||||
|
|
||||||
return { ok: true };
|
return { ok: true };
|
||||||
|
|||||||
@@ -31,6 +31,10 @@ export class PaymentServiceHelper {
|
|||||||
return await this.send('/create_customer', { user_id });
|
return await this.send('/create_customer', { user_id });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static async create_subscription(user_id: string, plan_tag: string): PaymentServiceResponse<{ ok: true }> {
|
||||||
|
return await this.send('/create_subscription', { user_id, plan_tag });
|
||||||
|
}
|
||||||
|
|
||||||
static async create_payment(user_id: string, plan_id: number): PaymentServiceResponse<{ url: string }> {
|
static async create_payment(user_id: string, plan_id: number): PaymentServiceResponse<{ url: string }> {
|
||||||
return await this.send('/create_payment', { user_id, plan_id });
|
return await this.send('/create_payment', { user_id, plan_id });
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,8 @@ if (!TOKEN || TOKEN.length == 0) {
|
|||||||
process.exit();
|
process.exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
app.use('/webhook', webhookRouter);
|
||||||
|
|
||||||
app.use((req, res, next) => {
|
app.use((req, res, next) => {
|
||||||
const token = req.header('x-litlyx-token');
|
const token = req.header('x-litlyx-token');
|
||||||
if (token != TOKEN) {
|
if (token != TOKEN) {
|
||||||
@@ -34,8 +36,6 @@ app.use((req, res, next) => {
|
|||||||
next();
|
next();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
app.use('/webhook', webhookRouter);
|
|
||||||
app.use('/payment', paymentRouter);
|
app.use('/payment', paymentRouter);
|
||||||
|
|
||||||
const port = parseInt(process.env.PORT);
|
const port = parseInt(process.env.PORT);
|
||||||
|
|||||||
@@ -162,3 +162,29 @@ paymentRouter.post('/delete_customer', json(), async (req, res) => {
|
|||||||
res.status(500).json({ error: ex.message });
|
res.status(500).json({ error: ex.message });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
export const ZBodyCreateSubscription = z.object({
|
||||||
|
user_id: z.string(),
|
||||||
|
plan_tag: z.string()
|
||||||
|
});
|
||||||
|
|
||||||
|
paymentRouter.post('/create_subscription', json(), async (req, res) => {
|
||||||
|
try {
|
||||||
|
const createSubscriptionData = ZBodyCreateSubscription.parse(req.body);
|
||||||
|
|
||||||
|
const premiumData = await PremiumModel.findOne({ user_id: createSubscriptionData.user_id });
|
||||||
|
if (!premiumData) return sendJson(res, 400, { error: 'user not found' });
|
||||||
|
if (!premiumData.customer_id) return sendJson(res, 400, { error: 'user have no customer_id' });
|
||||||
|
|
||||||
|
await StripeService.createSubscription(
|
||||||
|
premiumData.customer_id,
|
||||||
|
createSubscriptionData.plan_tag
|
||||||
|
);
|
||||||
|
return sendJson(res, 200, { ok: true });
|
||||||
|
|
||||||
|
} catch (ex) {
|
||||||
|
console.error(ex);
|
||||||
|
res.status(500).json({ error: ex.message });
|
||||||
|
}
|
||||||
|
});
|
||||||
@@ -153,22 +153,21 @@ class StripeService {
|
|||||||
// return false;
|
// return false;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// async createSubscription(customer_id: string, planId: number) {
|
async createSubscription(customer_id: string, planTag: string) {
|
||||||
// if (this.disabledMode) return;
|
if (!this.stripe) throw Error('Stripe not initialized');
|
||||||
// if (!this.stripe) throw Error('Stripe not initialized');
|
|
||||||
|
|
||||||
// const PLAN = getPlanFromId(planId);
|
const PLAN_DATA = getPlanFromTag(planTag as any);
|
||||||
// if (!PLAN) throw Error('Plan not found');
|
if (!PLAN_DATA) throw Error('Plan not found');
|
||||||
|
|
||||||
// const subscription = await this.stripe.subscriptions.create({
|
const subscription = await this.stripe.subscriptions.create({
|
||||||
// customer: customer_id,
|
customer: customer_id,
|
||||||
// items: [
|
items: [
|
||||||
// { price: this.testMode ? PLAN.PRICE_TEST : PLAN.PRICE, quantity: 1 }
|
{ price: this.testMode ? PLAN_DATA.PRICE_TEST : PLAN_DATA.PRICE, quantity: 1 }
|
||||||
// ],
|
],
|
||||||
// });
|
});
|
||||||
|
|
||||||
// return subscription;
|
return subscription;
|
||||||
// }
|
}
|
||||||
|
|
||||||
// async createOneTimeSubscriptionDummy(customer_id: string, planId: number) {
|
// async createOneTimeSubscriptionDummy(customer_id: string, planId: number) {
|
||||||
// if (this.disabledMode) return;
|
// if (this.disabledMode) return;
|
||||||
|
|||||||
@@ -610,6 +610,8 @@ function isBot(userAgent: string) {
|
|||||||
|
|
||||||
export async function isAllowedToLog(project_id: string, website: string, ip: string, userAgent: string) {
|
export async function isAllowedToLog(project_id: string, website: string, ip: string, userAgent: string) {
|
||||||
|
|
||||||
|
console.log({ userAgent });
|
||||||
|
|
||||||
const blacklistData = await AddressBlacklistModel.find({ project_id }, { address: 1 });
|
const blacklistData = await AddressBlacklistModel.find({ project_id }, { address: 1 });
|
||||||
for (const blacklistedData of blacklistData) {
|
for (const blacklistedData of blacklistData) {
|
||||||
if (blacklistedData.address == ip) return false;
|
if (blacklistedData.address == ip) return false;
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ const streamName = requireEnv('STREAM_NAME');
|
|||||||
import DeprecatedRouter from "./deprecated";
|
import DeprecatedRouter from "./deprecated";
|
||||||
import { isAllowedToLog } from "./controller";
|
import { isAllowedToLog } from "./controller";
|
||||||
import { connectDatabase } from "./shared/services/DatabaseService";
|
import { connectDatabase } from "./shared/services/DatabaseService";
|
||||||
|
|
||||||
app.use('/v1', DeprecatedRouter);
|
app.use('/v1', DeprecatedRouter);
|
||||||
|
|
||||||
app.post('/event', express.json(jsonOptions), async (req, res) => {
|
app.post('/event', express.json(jsonOptions), async (req, res) => {
|
||||||
|
|||||||
@@ -144,7 +144,7 @@ export const PREMIUM_PLAN: Record<PLAN_TAG, PLAN_DATA> = {
|
|||||||
COUNT_LIMIT: 50_000,
|
COUNT_LIMIT: 50_000,
|
||||||
AI_MESSAGE_LIMIT: 30,
|
AI_MESSAGE_LIMIT: 30,
|
||||||
PRICE: 'price_1QIXwbB2lPUiVs9VKSsoksaU',
|
PRICE: 'price_1QIXwbB2lPUiVs9VKSsoksaU',
|
||||||
PRICE_TEST: '',
|
PRICE_TEST: 'price_1RBIUsB2lPUiVs9VojGan6WH',
|
||||||
COST: 0,
|
COST: 0,
|
||||||
TAG: 'APPSUMO_INCUBATION'
|
TAG: 'APPSUMO_INCUBATION'
|
||||||
},
|
},
|
||||||
@@ -153,7 +153,7 @@ export const PREMIUM_PLAN: Record<PLAN_TAG, PLAN_DATA> = {
|
|||||||
COUNT_LIMIT: 150_000,
|
COUNT_LIMIT: 150_000,
|
||||||
AI_MESSAGE_LIMIT: 100,
|
AI_MESSAGE_LIMIT: 100,
|
||||||
PRICE: 'price_1QIXxRB2lPUiVs9VrjaVRoOl',
|
PRICE: 'price_1QIXxRB2lPUiVs9VrjaVRoOl',
|
||||||
PRICE_TEST: '',
|
PRICE_TEST: 'price_1RBIV5B2lPUiVs9VKQyxvhst',
|
||||||
COST: 0,
|
COST: 0,
|
||||||
TAG: 'APPSUMO_ACCELERATION'
|
TAG: 'APPSUMO_ACCELERATION'
|
||||||
},
|
},
|
||||||
@@ -162,7 +162,7 @@ export const PREMIUM_PLAN: Record<PLAN_TAG, PLAN_DATA> = {
|
|||||||
COUNT_LIMIT: 500_000,
|
COUNT_LIMIT: 500_000,
|
||||||
AI_MESSAGE_LIMIT: 3_000,
|
AI_MESSAGE_LIMIT: 3_000,
|
||||||
PRICE: 'price_1QIXy8B2lPUiVs9VQBOUPAoE',
|
PRICE: 'price_1QIXy8B2lPUiVs9VQBOUPAoE',
|
||||||
PRICE_TEST: '',
|
PRICE_TEST: 'price_1RBIVFB2lPUiVs9VsMoldAu3',
|
||||||
COST: 0,
|
COST: 0,
|
||||||
TAG: 'APPSUMO_GROWTH'
|
TAG: 'APPSUMO_GROWTH'
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user