Pricing Upgrade Flow changes (#514)
* Pricing Upgrade Flow changes * remove extra code * Refactor subscription plan selection and billing management * Polish the new pricing modal --------- Co-authored-by: Julien Nahum <julien@nahum.net>
This commit is contained in:
@@ -4,18 +4,18 @@
|
||||
<div
|
||||
v-if="show"
|
||||
ref="backdrop"
|
||||
class="fixed z-30 top-0 inset-0 px-4 sm:px-0 flex items-top justify-center bg-gray-700/75 w-full h-screen overflow-y-scroll"
|
||||
class="fixed z-30 top-0 inset-0 px-2 sm:px-4 flex items-top justify-center bg-gray-700/75 w-full h-screen overflow-y-scroll"
|
||||
:class="{ 'backdrop-blur-sm': backdropBlur }"
|
||||
@click.self="close"
|
||||
>
|
||||
<div
|
||||
ref="content"
|
||||
class="self-start bg-white dark:bg-notion-dark w-full relative my-6 rounded-xl shadow-xl"
|
||||
class="self-start bg-white dark:bg-notion-dark w-full relative my-2 sm:my-6 rounded-xl shadow-xl"
|
||||
:class="maxWidthClass"
|
||||
>
|
||||
<div
|
||||
v-if="closeable"
|
||||
class="absolute top-4 right-4 z-10"
|
||||
class="absolute top-4 right-4"
|
||||
>
|
||||
<button
|
||||
class="text-gray-500 hover:text-gray-900 cursor-pointer"
|
||||
@@ -93,84 +93,85 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { watch } from "vue"
|
||||
import { default as _has } from "lodash/has"
|
||||
import { watch } from 'vue'
|
||||
import { default as _has } from 'lodash/has'
|
||||
|
||||
const props = defineProps({
|
||||
show: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
default: false
|
||||
},
|
||||
backdropBlur: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
default: false
|
||||
},
|
||||
iconColor: {
|
||||
type: String,
|
||||
default: "blue",
|
||||
default: 'blue'
|
||||
},
|
||||
maxWidth: {
|
||||
type: String,
|
||||
default: "2xl",
|
||||
default: '2xl'
|
||||
},
|
||||
innerPadding: {
|
||||
type: String,
|
||||
default: "p-6",
|
||||
default: 'p-6'
|
||||
},
|
||||
headerInnerPadding: {
|
||||
type: String,
|
||||
default: "p-6",
|
||||
default: 'p-6'
|
||||
},
|
||||
footerInnerPadding: {
|
||||
type: String,
|
||||
default: "p-6",
|
||||
default: 'p-6'
|
||||
},
|
||||
closeable: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
default: true
|
||||
},
|
||||
compactHeader: {
|
||||
default: false,
|
||||
type: Boolean,
|
||||
},
|
||||
type: Boolean
|
||||
}
|
||||
})
|
||||
|
||||
const emit = defineEmits(["close"])
|
||||
const emit = defineEmits(['close'])
|
||||
|
||||
useHead({
|
||||
bodyAttrs: computed(() => {
|
||||
return {
|
||||
class: {
|
||||
"overflow-hidden": props.show,
|
||||
},
|
||||
'overflow-hidden': props.show
|
||||
}
|
||||
}
|
||||
}),
|
||||
})
|
||||
})
|
||||
|
||||
const closeOnEscape = (e) => {
|
||||
if (e.key === "Escape" && props.show) {
|
||||
if (e.key === 'Escape' && props.show) {
|
||||
close()
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
if (import.meta.server) return
|
||||
document.addEventListener("keydown", closeOnEscape)
|
||||
document.addEventListener('keydown', closeOnEscape)
|
||||
initMotions()
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
if (import.meta.server) return
|
||||
document.removeEventListener("keydown", closeOnEscape)
|
||||
document.removeEventListener('keydown', closeOnEscape)
|
||||
})
|
||||
|
||||
const maxWidthClass = computed(() => {
|
||||
return {
|
||||
sm: "sm:max-w-sm",
|
||||
md: "sm:max-w-md",
|
||||
lg: "sm:max-w-lg",
|
||||
xl: "sm:max-w-xl",
|
||||
"2xl": "sm:max-w-2xl",
|
||||
sm: 'sm:max-w-sm',
|
||||
md: 'sm:max-w-md',
|
||||
lg: 'sm:max-w-lg',
|
||||
xl: 'sm:max-w-xl',
|
||||
'2xl': 'max-w-2xl',
|
||||
'screen-lg': 'max-w-screen-lg'
|
||||
}[props.maxWidth]
|
||||
})
|
||||
|
||||
@@ -180,15 +181,15 @@ const motionFadeIn = {
|
||||
transition: {
|
||||
delay: 100,
|
||||
duration: 200,
|
||||
ease: "easeIn",
|
||||
},
|
||||
ease: 'easeIn'
|
||||
}
|
||||
},
|
||||
enter: {
|
||||
opacity: 1,
|
||||
transition: {
|
||||
duration: 200,
|
||||
},
|
||||
},
|
||||
duration: 200
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const motionSlideBottom = {
|
||||
@@ -196,19 +197,19 @@ const motionSlideBottom = {
|
||||
y: 150,
|
||||
opacity: 0,
|
||||
transition: {
|
||||
ease: "easeIn",
|
||||
duration: 200,
|
||||
},
|
||||
ease: 'easeIn',
|
||||
duration: 200
|
||||
}
|
||||
},
|
||||
enter: {
|
||||
y: 0,
|
||||
opacity: 1,
|
||||
transition: {
|
||||
duration: 250,
|
||||
ease: "easeOut",
|
||||
delay: 100,
|
||||
},
|
||||
},
|
||||
ease: 'easeOut',
|
||||
delay: 100
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const onLeave = (el, done) => {
|
||||
@@ -218,7 +219,7 @@ const onLeave = (el, done) => {
|
||||
|
||||
const close = () => {
|
||||
if (props.closeable) {
|
||||
emit("close")
|
||||
emit('close')
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,73 +1,45 @@
|
||||
<template>
|
||||
<div
|
||||
<UTooltip
|
||||
v-if="shouldDisplayProTag"
|
||||
class="inline"
|
||||
:text="upgradeModalTitle??'You need a Pro plan to use this feature'"
|
||||
class="inline normal-case"
|
||||
>
|
||||
<UTooltip text="Upgrade to use this feature">
|
||||
<div
|
||||
role="button"
|
||||
class="bg-nt-blue text-white px-2 text-xs uppercase inline rounded-full font-semibold cursor-pointer"
|
||||
@click="showPremiumModal = true"
|
||||
>
|
||||
PRO
|
||||
</div>
|
||||
<modal
|
||||
:show="showPremiumModal"
|
||||
@close="showPremiumModal = false"
|
||||
>
|
||||
<h2 class="text-nt-blue">
|
||||
OpnForm PRO
|
||||
</h2>
|
||||
<h4
|
||||
v-if="user && user.is_subscribed"
|
||||
class="text-center mt-5"
|
||||
>
|
||||
We're happy to have you as a Pro customer. If you're having any issue
|
||||
with OpnForm, or if you have a feature request, please
|
||||
<a href="mailto:contact@opnform.com">contact us</a>.
|
||||
</h4>
|
||||
<div
|
||||
v-if="!user || !user.is_subscribed"
|
||||
class="mt-4"
|
||||
>
|
||||
<p>
|
||||
All the features with a<span
|
||||
class="bg-nt-blue text-white px-2 text-xs uppercase inline rounded-full font-semibold mx-1"
|
||||
>
|
||||
PRO
|
||||
</span>
|
||||
tag are available in the Pro plan of OpnForm.
|
||||
<b>You can play around and try all Pro features within the form
|
||||
editor, but you can't use them in your real forms</b>. You can subscribe now to gain unlimited access to all our pro
|
||||
features!
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="my-4 text-center">
|
||||
<v-button
|
||||
color="white"
|
||||
@click="showPremiumModal = false"
|
||||
>
|
||||
Close
|
||||
</v-button>
|
||||
</div>
|
||||
</modal>
|
||||
</UTooltip>
|
||||
</div>
|
||||
<div
|
||||
v-track.pro_tag_click="{title:upgradeModalTitle}"
|
||||
class="bg-nt-blue text-white px-2 text-xs uppercase inline rounded-full font-semibold cursor-pointer"
|
||||
@click.stop="onClick"
|
||||
>
|
||||
PRO
|
||||
</div>
|
||||
</UTooltip>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed } from "vue"
|
||||
|
||||
const props = defineProps({
|
||||
upgradeModalTitle: {
|
||||
type: String
|
||||
},
|
||||
upgradeModalDescription: {
|
||||
type: String
|
||||
}
|
||||
})
|
||||
|
||||
const subscriptionModalStore = useSubscriptionModalStore()
|
||||
const authStore = useAuthStore()
|
||||
const workspacesStore = useWorkspacesStore()
|
||||
const user = computed(() => authStore.user)
|
||||
const workspace = computed(() => workspacesStore.getCurrent)
|
||||
const showPremiumModal = ref(false)
|
||||
|
||||
const shouldDisplayProTag = computed(() => {
|
||||
if (!useRuntimeConfig().public.paidPlansEnabled) return false
|
||||
if (!user.value || !workspace.value) return true
|
||||
return !workspace.value.is_pro
|
||||
})
|
||||
|
||||
function onClick () {
|
||||
subscriptionModalStore.setModalContent(props.upgradeModalTitle, props.upgradeModalDescription)
|
||||
subscriptionModalStore.openModal()
|
||||
}
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user