PluginProbe
The Innovative Form Builder – IvyForms / 0.8.1
The Innovative Form Builder – IvyForms v0.8.1
1.5.1 1.5 1.4.1 1.4 trunk 0.1.2 0.2 0.2.1 0.3 0.3.1 0.4 0.5 0.6 0.6.1 0.6.1-backup 0.6.1.1 0.7 0.8 0.8.1 0.8.2 0.9 0.9.1 1.0 1.1 1.1.1 All 27 releases
ivyforms / frontend / src / composables / useProFeatureUpgrade.ts

useProFeatureUpgrade.ts in The Innovative Form Builder – IvyForms 0.8.1, at frontend/src/composables/useProFeatureUpgrade.ts

273 lines 8.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /**
2 * Pro Feature Upgrade Dialog Composable
3 *
4 * Shows appropriate upgrade dialogs based on Pro plugin status:
5 * 1. Pro NOT installed/active -> Notification Pop-up (simple)
6 * 2. Pro installed but license not activated -> Activation Pop-up (detailed)
7 */
8
9 import { useProUpgradeDialogStore } from '@/stores/proUpgradeDialogStore'
10 import { useLabels } from '@/composables/useLabels'
11 import { useSettingsStore } from '@/stores/useSettingsStore'
12 import { IVYFORMS_WEBSITE_PRICING, IVYFORMS_WEBSITE } from '@/constants/links'
13
14 type ProFeatureType = string
15
16 /**
17 * Open pricing page in a new tab with proper security attributes
18 * Centralized function to handle all pricing page navigation
19 */
20 export function openPricingPage() {
21 const link = document.createElement('a')
22 link.href = IVYFORMS_WEBSITE_PRICING
23 link.target = '_blank'
24 link.rel = 'noopener noreferrer nofollow'
25 link.click()
26 }
27
28 export function useProFeatureUpgrade() {
29 const proUpgradeDialog = useProUpgradeDialogStore()
30 const { getLabel } = useLabels()
31 const settingsStore = useSettingsStore()
32
33 /**
34 * Get all available Pro field features from the plan
35 * These are loaded from the backend plan configuration
36 */
37 const getProFieldFeatures = (): Record<string, ProFeatureType> => {
38 const proFeatures = window.IvyForms?.pro?.features?.fields || {}
39 return proFeatures as Record<string, ProFeatureType>
40 }
41
42 /**
43 * Check if a field type is a Pro feature field
44 * Dynamically checks against available Pro features from the plan
45 */
46 const isProFieldFeature = (fieldType: string): boolean => {
47 const proFieldFeatures = getProFieldFeatures()
48 return Object.values(proFieldFeatures).includes(fieldType)
49 }
50
51 /**
52 * Get the feature slug for a given field type
53 * Maps field type to its corresponding feature slug from the plan
54 */
55 const getFeatureSlugForFieldType = (fieldType: string): ProFeatureType | null => {
56 const proFieldFeatures = getProFieldFeatures()
57 for (const [, featureSlug] of Object.entries(proFieldFeatures)) {
58 if (featureSlug === fieldType) {
59 return featureSlug
60 }
61 }
62 return null
63 }
64
65 /**
66 * Get all available Pro field option features from the plan
67 * These are loaded from the backend plan configuration
68 */
69 const getProFieldOptionFeatures = (): Record<string, ProFeatureType> => {
70 const proFeatures = window.IvyForms?.pro?.features?.field_options || {}
71 return proFeatures as Record<string, ProFeatureType>
72 }
73
74 /**
75 * Check if a field option slug is a Pro feature
76 * Dynamically checks against available Pro features from the plan
77 */
78 const isProFieldOption = (slug: string): boolean => {
79 const proFieldOptions = getProFieldOptionFeatures()
80 return Object.values(proFieldOptions).includes(slug)
81 }
82
83 /**
84 * Get all available Pro integration features from the plan
85 * These are loaded from the backend plan configuration
86 */
87 const getProIntegrationFeatures = (): Record<string, ProFeatureType> => {
88 const proFeatures = window.IvyForms?.pro?.features?.integrations || {}
89 return proFeatures as Record<string, ProFeatureType>
90 }
91
92 /**
93 * Check if an integration slug is a Pro feature
94 * Dynamically checks against available Pro features from the plan
95 */
96 const isProIntegration = (slug: string): boolean => {
97 const proIntegrations = getProIntegrationFeatures()
98 return Object.values(proIntegrations).includes(slug)
99 }
100
101 /**
102 * Check if Pro plugin is installed and activated
103 * Pro plugin must be both installed AND activated for this to return true
104 */
105 const isProInstalled = (): boolean => {
106 // First check: Pro scripts must be loaded by WordPress
107 // This is the most reliable indicator that Pro plugin is ACTIVE
108 const proScriptsLoaded =
109 (window as { ivyFormsProScripts?: Record<string, string> }).ivyFormsProScripts !== undefined
110
111 if (!proScriptsLoaded) {
112 return false
113 }
114
115 // Second check: Pro object must exist
116 if (!window.IvyForms?.pro) {
117 return false
118 }
119
120 // Third check: Pro must be loaded or have features
121 const isLoaded = window.IvyForms.pro.loaded === true
122 const hasFeatures =
123 window.IvyForms.pro.features !== undefined &&
124 window.IvyForms.pro.features !== null &&
125 Object.keys(window.IvyForms.pro.features).length > 0
126
127 return isLoaded || hasFeatures
128 }
129
130 /**
131 * Check if Pro license is active
132 * Checks if license settings exist and are valid in the settings store
133 */
134 const isProLicenseActive = (): boolean => {
135 if (!isProInstalled()) return false
136
137 // Check if allSettings has been loaded
138 const settings = settingsStore.allSettings
139 if (!settings) return false
140
141 // Check if Pro license settings exist
142 const proSettings = (settings as Record<string, unknown>).pro as
143 | Record<string, unknown>
144 | undefined
145 if (!proSettings || !proSettings.license) return false
146
147 const licenseInfo = proSettings.license as { status?: string; plan?: string }
148
149 // License is active if status is 'valid' and plan is not 'lite'
150 return licenseInfo.status === 'valid' && licenseInfo.plan !== 'lite'
151 }
152
153 /**
154 * Show upgrade dialog based on current Pro status
155 */
156 const showUpgradeDialog = () => {
157 const proInstalled = isProInstalled()
158 const licenseActive = isProLicenseActive()
159
160 // Scenario 1: Pro plugin NOT installed/active
161 // Show simple "Notification Pop-up" from Figma
162 if (!proInstalled) {
163 proUpgradeDialog.showDialog({
164 iconName: 'pro-lightning-alt',
165 title: getLabel('pro_feature_available'),
166 subtitle: '',
167 buttons: {
168 close: {
169 type: 'tertiary',
170 text: getLabel('learn_more'),
171 //TODO: Update URL to specific feature page if available
172 function: () => {
173 const link = document.createElement('a')
174 link.href = IVYFORMS_WEBSITE
175 link.target = '_blank'
176 link.rel = 'noopener noreferrer nofollow'
177 link.click()
178 },
179 },
180 confirm: {
181 type: 'primary',
182 text: getLabel('upgrade_to_pro'),
183 function: () => {
184 window.open(IVYFORMS_WEBSITE_PRICING, '_blank')
185 },
186 },
187 },
188 })
189 }
190 // Scenario 2: Pro installed but license NOT activated
191 // Show detailed "Pop-up" with activation message from Figma
192 else if (!licenseActive) {
193 proUpgradeDialog.showDialog({
194 iconName: 'pro-lightning',
195 title: getLabel('pro_feature_requires_activation'),
196 subtitle: getLabel('pro_feature_activation_subtitle'),
197 buttons: {
198 confirm: {
199 type: 'primary',
200 text: getLabel('activate_license'),
201 function: () => {
202 //TODO: Update URL to specific license activation page if available
203 const currentUrl = new URL(window.location.href)
204 currentUrl.searchParams.set('page', 'ivyforms-settings')
205 currentUrl.hash = '/license'
206 window.location.href = currentUrl.toString()
207 },
208 },
209 },
210 })
211 }
212 // Scenario 3: Pro active but feature not in current plan - Later for different plan tiers
213 else {
214 proUpgradeDialog.showDialog({
215 iconName: 'pro-lightning-alt',
216 title: getLabel('pro_feature_available'),
217 subtitle: '',
218 buttons: {
219 close: {
220 type: 'tertiary',
221 text: getLabel('learn_more'),
222 function: () => {
223 openPricingPage()
224 },
225 },
226 confirm: {
227 type: 'primary',
228 text: getLabel('upgrade_plan'),
229 function: () => {
230 openPricingPage()
231 },
232 },
233 },
234 })
235 }
236 }
237
238 /**
239 * Check if a feature is available and show upgrade dialog if not
240 * @returns true if feature is available, false if upgrade dialog was shown
241 */
242 const checkFeatureAccess = (featureType: ProFeatureType): boolean => {
243 // If Pro is not installed or license is not active, show upgrade dialog
244 if (!isProInstalled() || !isProLicenseActive()) {
245 showUpgradeDialog()
246 return false
247 }
248
249 // Check if specific feature is available (for different plan tiers)
250 const hasFeature = window.IvyForms?.pro?.features?.[featureType]
251 if (!hasFeature) {
252 showUpgradeDialog()
253 return false
254 }
255
256 return true
257 }
258
259 return {
260 isProInstalled,
261 isProLicenseActive,
262 showUpgradeDialog,
263 checkFeatureAccess,
264 getProFieldFeatures,
265 isProFieldFeature,
266 getFeatureSlugForFieldType,
267 getProFieldOptionFeatures,
268 isProFieldOption,
269 getProIntegrationFeatures,
270 isProIntegration,
271 }
272 }
273