mirror of
https://github.com/Litlyx/litlyx
synced 2025-12-10 15:58:38 +01:00
add pricing plans
This commit is contained in:
@@ -1,58 +1,70 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
|
||||||
|
export type PricingCardProp = {
|
||||||
type Prop = {
|
|
||||||
title: string,
|
title: string,
|
||||||
icon: string,
|
cost: string,
|
||||||
list: { text: string, icon: string }[],
|
features: string[],
|
||||||
price: string,
|
desc: string,
|
||||||
|
active: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = defineProps<Prop>();
|
const props = defineProps<{ data: PricingCardProp }>();
|
||||||
|
|
||||||
|
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
|
function onUpgradeClick() {
|
||||||
|
router.push('/book_demo')
|
||||||
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="bg-menu py-6 rounded-lg w-full h-full flex flex-col items-center justify-normal px-6 relative">
|
<div class="p-6 bg-[#303030] rounded-xl pricing-card flex flex-col">
|
||||||
|
|
||||||
<div
|
<div class="flex flex-col">
|
||||||
class="absolute rounded-full top-[-2.1rem] bg-accent w-[4.2rem] h-[4.2rem] flex items-center justify-center">
|
<div class="text-[1.1rem] font-semibold mb-4">
|
||||||
<i :class="icon" class="text-[2.5rem]"></i>
|
{{ data.title }}
|
||||||
</div>
|
</div>
|
||||||
|
<div class="flex gap-1 items-end mb-2">
|
||||||
<div class="poppins mt-6 font-semibold text-[1.4rem]">
|
<div class="text-[1.1rem] font-semibold">
|
||||||
{{ title }}
|
€{{ data.cost }}
|
||||||
</div>
|
</div>
|
||||||
|
<div class="text-text-sub text-[.9rem] mb-[.15rem]">
|
||||||
<div class="bg-gray-400/50 h-[1px] w-full mt-6 mb-10"></div>
|
per month
|
||||||
|
|
||||||
<div class="flex flex-col gap-4">
|
|
||||||
<div class="flex gap-3 items-center" v-for="element of list">
|
|
||||||
|
|
||||||
<div class="shrink-0 flex items-center bg-accent w-[2rem] h-[2rem] justify-center rounded-full">
|
|
||||||
<i :class="element.icon" class="text-[.9rem]"></i>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="poppins">
|
|
||||||
{{ element.text }}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div v-if="data.active" class="text-[1rem] bg-[#1f1f22] rounded-md py-2 text-center">
|
||||||
|
Current active plan
|
||||||
|
</div>
|
||||||
|
<div @click="onUpgradeClick()" v-if="!data.active" class="cursor-pointer text-[1rem] font-semibold bg-[#3a3af5] rounded-md py-2 text-center">
|
||||||
|
Upgrade
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="bg-gray-400/50 h-[1px] w-full mt-10 mb-6"></div>
|
<div class="bg-gray-400 h-[1px] w-full my-4"></div>
|
||||||
|
|
||||||
<div class="flex gap-2 justify-between w-full">
|
|
||||||
<div class="flex gap-2 items-end">
|
|
||||||
<div class="manrope text-[2.5rem] font-bold text-text"> {{ price }} </div>
|
|
||||||
<div class="poppins text-text-sub/90 mb-1">/month</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
<div class="flex flex-col gap-1 grow">
|
||||||
|
<div class="flex gap-2 items-center" v-for="feature of data.features">
|
||||||
|
<i class="fas fa-check"></i>
|
||||||
<div>
|
<div>
|
||||||
Tasto bello
|
{{ feature }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="bg-gray-400 h-[1px] w-full my-4"></div>
|
||||||
|
|
||||||
|
<div class="text-text-sub text-[.9rem] h-[20%]">
|
||||||
|
{{ data.desc }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.pricing-card * {
|
||||||
|
font-family: "Poppins";
|
||||||
|
}
|
||||||
|
</style>
|
||||||
58
dashboard/components/pricing/PricingCard_old.vue
Normal file
58
dashboard/components/pricing/PricingCard_old.vue
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
|
||||||
|
|
||||||
|
type Prop = {
|
||||||
|
title: string,
|
||||||
|
icon: string,
|
||||||
|
list: { text: string, icon: string }[],
|
||||||
|
price: string,
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = defineProps<Prop>();
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="bg-menu py-6 rounded-lg w-full h-full flex flex-col items-center justify-normal px-6 relative">
|
||||||
|
|
||||||
|
<div
|
||||||
|
class="absolute rounded-full top-[-2.1rem] bg-accent w-[4.2rem] h-[4.2rem] flex items-center justify-center">
|
||||||
|
<i :class="icon" class="text-[2.5rem]"></i>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="poppins mt-6 font-semibold text-[1.4rem]">
|
||||||
|
{{ title }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="bg-gray-400/50 h-[1px] w-full mt-6 mb-10"></div>
|
||||||
|
|
||||||
|
<div class="flex flex-col gap-4">
|
||||||
|
<div class="flex gap-3 items-center" v-for="element of list">
|
||||||
|
|
||||||
|
<div class="shrink-0 flex items-center bg-accent w-[2rem] h-[2rem] justify-center rounded-full">
|
||||||
|
<i :class="element.icon" class="text-[.9rem]"></i>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="poppins">
|
||||||
|
{{ element.text }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="bg-gray-400/50 h-[1px] w-full mt-10 mb-6"></div>
|
||||||
|
|
||||||
|
<div class="flex gap-2 justify-between w-full">
|
||||||
|
<div class="flex gap-2 items-end">
|
||||||
|
<div class="manrope text-[2.5rem] font-bold text-text"> {{ price }} </div>
|
||||||
|
<div class="poppins text-text-sub/90 mb-1">/month</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
Tasto bello
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</template>
|
||||||
89
dashboard/components/pricing/PricingDrawer.vue
Normal file
89
dashboard/components/pricing/PricingDrawer.vue
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
import type { PricingCardProp } from './PricingCard.vue';
|
||||||
|
|
||||||
|
|
||||||
|
const activeProject = useActiveProject();
|
||||||
|
|
||||||
|
|
||||||
|
const starterTierCardData = ref<PricingCardProp>({
|
||||||
|
title: 'STARTER',
|
||||||
|
cost: '0',
|
||||||
|
features: [
|
||||||
|
"3K visits/events per month",
|
||||||
|
"10 AI Interaction per month",
|
||||||
|
"1 month data retention",
|
||||||
|
"Limited reports",
|
||||||
|
"1 Team member",
|
||||||
|
"Limited Automatic Email Report",
|
||||||
|
"Shared Server & DB",
|
||||||
|
"Low priority email support",
|
||||||
|
],
|
||||||
|
desc: `Free project are not reliable and sometimes
|
||||||
|
can experience some data loss.To have a
|
||||||
|
dedicated server we suggest to upgrade the
|
||||||
|
plan to an higher one!`,
|
||||||
|
active: activeProject.value?.premium === false
|
||||||
|
});
|
||||||
|
|
||||||
|
const accelerationTierCardData = ref<PricingCardProp>({
|
||||||
|
title: 'ACCELERATION',
|
||||||
|
cost: '9.99',
|
||||||
|
features: [
|
||||||
|
"150K visits/events per month",
|
||||||
|
"100 AI Interaction per month",
|
||||||
|
"6 months data retention",
|
||||||
|
"Limited reports",
|
||||||
|
"1 Team member",
|
||||||
|
"Limited Automatic Email Report",
|
||||||
|
"Shared Server & DB",
|
||||||
|
"Low priority email support"
|
||||||
|
],
|
||||||
|
desc: `Your project is entering a growth phase. We simplify data analysis for you. For more support, try our Expansion plan—it's worth it!`,
|
||||||
|
active: activeProject.value?.premium_type === 1
|
||||||
|
});
|
||||||
|
|
||||||
|
const expansionTierCardData = ref<PricingCardProp>({
|
||||||
|
title: 'EXPANSION',
|
||||||
|
cost: '39.99',
|
||||||
|
features: [
|
||||||
|
"500K visits/events per month",
|
||||||
|
"5000 AI Interaction per month",
|
||||||
|
"2 years data retention",
|
||||||
|
"Unlimited reports",
|
||||||
|
"10 Team member",
|
||||||
|
"Unlimited Automatic Email Report",
|
||||||
|
"Dedicated Server & DB",
|
||||||
|
"high priority email support"
|
||||||
|
],
|
||||||
|
desc: `We will support you with everything we can offer and give you the full power of our service. If you need more space and are growing, contact us for a custom offer!`,
|
||||||
|
active: activeProject.value?.premium_type === 2
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="p-8">
|
||||||
|
|
||||||
|
<div class="flex gap-8 h-max">
|
||||||
|
<PricingCard class="flex-1" :data="starterTierCardData"></PricingCard>
|
||||||
|
<PricingCard class="flex-1" :data="accelerationTierCardData"></PricingCard>
|
||||||
|
<PricingCard class="flex-1" :data="expansionTierCardData"></PricingCard>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex justify-between items-center mt-10">
|
||||||
|
<div class="flex flex-col gap-2">
|
||||||
|
<div class="poppins text-[2rem] font-semibold">
|
||||||
|
Do you need help ?
|
||||||
|
</div>
|
||||||
|
<div class="poppins text-[1.2rem] text-text/90">
|
||||||
|
We respond in max. 1-2 days
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="py-4 px-20 bg-[#303030] rounded-lg">
|
||||||
|
<a href="mailto:helplitlyx@gmail.com" class="poppins text-[1.3rem]">
|
||||||
|
helplitlyx@gmail.com
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
@@ -35,7 +35,7 @@ const sections: Section[] = [
|
|||||||
action() { Lit.event('docs_clicked') },
|
action() { Lit.event('docs_clicked') },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Github', to: 'https://github.com/botkalista/litlyx-javascript-lib', icon: 'fab fa-github', external: true,
|
label: 'Github', to: 'https://github.com/litlyx/litlyx', icon: 'fab fa-github', external: true,
|
||||||
action() { Lit.event('git_clicked') },
|
action() { Lit.event('git_clicked') },
|
||||||
},
|
},
|
||||||
{ label: 'Plans', to: '/plans', icon: 'far fa-wallet' },
|
{ label: 'Plans', to: '/plans', icon: 'far fa-wallet' },
|
||||||
|
|||||||
@@ -46,7 +46,10 @@ async function sendMessage() {
|
|||||||
|
|
||||||
} catch (ex: any) {
|
} catch (ex: any) {
|
||||||
if (ex.message.includes('CHAT_LIMIT_REACHED')) {
|
if (ex.message.includes('CHAT_LIMIT_REACHED')) {
|
||||||
currentChatMessages.value.push({ role: 'assistant', content: 'You have reached your free tier chat limit.\n Upgrade to an higher tier.' });
|
currentChatMessages.value.push({
|
||||||
|
role: 'assistant',
|
||||||
|
content: 'You have reached your current tier chat limit.\n Upgrade to an higher tier. <a style="color: blue; text-decoration: underline;" href="/plans"> Upgrade now. </a>',
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -36,15 +36,28 @@ const prettyExpireDate = computed(() => {
|
|||||||
return dayjs(planData.value.billing_expire_at).format('DD/MM/YYYY');
|
return dayjs(planData.value.billing_expire_at).format('DD/MM/YYYY');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
const showPricingDrawer = ref<boolean>(false);
|
||||||
function onPlanUpgradeClick() {
|
function onPlanUpgradeClick() {
|
||||||
router.push('/book_demo');
|
showPricingDrawer.value = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|
||||||
<div class="w-full h-full p-8 overflow-y-auto pb-40 lg:pb-0">
|
<div class="w-full h-full p-8 overflow-y-auto pb-40 lg:pb-0 relative overflow-x-hidden">
|
||||||
|
|
||||||
|
<Transition name="pdrawer">
|
||||||
|
<PricingDrawer class="bg-black absolute right-0 top-0 w-[60vw] min-w-[65rem] h-full z-[20]"
|
||||||
|
v-if=showPricingDrawer>
|
||||||
|
</PricingDrawer>
|
||||||
|
</Transition>
|
||||||
|
|
||||||
|
<div @click="showPricingDrawer = false" v-if="showPricingDrawer"
|
||||||
|
class="barrier absolute left-0 top-0 w-full h-full z-[19] bg-black/40 backdrop-blur-[1px]">
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="poppins font-semibold text-[1.8rem]">
|
<div class="poppins font-semibold text-[1.8rem]">
|
||||||
Billing
|
Billing
|
||||||
@@ -147,6 +160,27 @@ function onPlanUpgradeClick() {
|
|||||||
|
|
||||||
<CardTitled title="Invoices" sub="No invoices yet" class="p-4 mt-8 max-w-[72rem]">
|
<CardTitled title="Invoices" sub="No invoices yet" class="p-4 mt-8 max-w-[72rem]">
|
||||||
</CardTitled>
|
</CardTitled>
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.pdrawer-enter-active,
|
||||||
|
.pdrawer-leave-active {
|
||||||
|
transition: all .5s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pdrawer-enter-from,
|
||||||
|
.pdrawer-leave-to {
|
||||||
|
transform: translateX(100%)
|
||||||
|
}
|
||||||
|
|
||||||
|
.pdrawer-enter-to,
|
||||||
|
.pdrawer-leave-from {
|
||||||
|
transform: translateX(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
import { getUserProjectFromId } from "~/server/LIVE_DEMO_DATA";
|
import { getUserProjectFromId } from "~/server/LIVE_DEMO_DATA";
|
||||||
import { ProjectCountModel } from "@schema/ProjectsCounts";
|
|
||||||
|
|
||||||
import { checkProjectCount } from '@functions/UtilsProjectCounts';
|
import { checkProjectCount } from '@functions/UtilsProjectCounts';
|
||||||
|
|
||||||
export async function getAiChatRemainings(project_id: string) {
|
export async function getAiChatRemainings(project_id: string) {
|
||||||
|
|||||||
Reference in New Issue
Block a user