@nextsparkjs/core 0.1.0-beta.128 → 0.1.0-beta.129
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/billing/ConfirmPlanChangeModal.d.ts +29 -0
- package/dist/components/billing/ConfirmPlanChangeModal.d.ts.map +1 -0
- package/dist/components/billing/ConfirmPlanChangeModal.js +100 -0
- package/dist/components/billing/PricingTable.d.ts +3 -0
- package/dist/components/billing/PricingTable.d.ts.map +1 -1
- package/dist/components/billing/PricingTable.js +146 -71
- package/dist/components/billing/QuotaGate.d.ts +21 -0
- package/dist/components/billing/QuotaGate.d.ts.map +1 -0
- package/dist/components/billing/QuotaGate.js +33 -0
- package/dist/components/billing/index.d.ts +2 -0
- package/dist/components/billing/index.d.ts.map +1 -1
- package/dist/components/billing/index.js +4 -0
- package/dist/components/dashboard/block-editor/dynamic-form.d.ts.map +1 -1
- package/dist/components/dashboard/block-editor/dynamic-form.js +7 -5
- package/dist/contexts/SubscriptionContext.d.ts +2 -0
- package/dist/contexts/SubscriptionContext.d.ts.map +1 -1
- package/dist/contexts/SubscriptionContext.js +2 -0
- package/dist/hooks/index.d.ts +1 -0
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +1 -0
- package/dist/hooks/useQuotaCheck.d.ts +26 -0
- package/dist/hooks/useQuotaCheck.d.ts.map +1 -0
- package/dist/hooks/useQuotaCheck.js +33 -0
- package/dist/lib/api/entity/generic-handler.d.ts.map +1 -1
- package/dist/lib/api/entity/generic-handler.js +54 -6
- package/dist/lib/oauth/index.d.ts +1 -1
- package/dist/messages/de/billing.json +10 -0
- package/dist/messages/de/index.d.ts +9 -0
- package/dist/messages/de/index.d.ts.map +1 -1
- package/dist/messages/en/billing.json +21 -0
- package/dist/messages/en/index.d.ts +19 -0
- package/dist/messages/en/index.d.ts.map +1 -1
- package/dist/messages/es/billing.json +21 -0
- package/dist/messages/es/index.d.ts +19 -0
- package/dist/messages/es/index.d.ts.map +1 -1
- package/dist/messages/fr/billing.json +10 -0
- package/dist/messages/fr/index.d.ts +9 -0
- package/dist/messages/fr/index.d.ts.map +1 -1
- package/dist/messages/it/billing.json +10 -0
- package/dist/messages/it/index.d.ts +9 -0
- package/dist/messages/it/index.d.ts.map +1 -1
- package/dist/messages/pt/billing.json +10 -0
- package/dist/messages/pt/index.d.ts +9 -0
- package/dist/messages/pt/index.d.ts.map +1 -1
- package/dist/styles/classes.json +6 -2
- package/dist/styles/ui.css +1 -1
- package/dist/templates/app/api/v1/billing/cancel/route.ts +1 -1
- package/dist/templates/app/api/v1/billing/change-plan/route.ts +1 -1
- package/dist/templates/app/api/v1/billing/check-action/route.ts +7 -6
- package/dist/templates/app/api/v1/billing/checkout/route.ts +35 -7
- package/dist/templates/app/api/v1/billing/portal/route.ts +1 -1
- package/dist/templates/app/dashboard/settings/billing/page.tsx +9 -4
- package/dist/templates/app/dashboard/settings/plans/page.tsx +29 -7
- package/dist/templates/blocks/hero/component.tsx +6 -3
- package/dist/templates/blocks/hero/schema.ts +2 -1
- package/dist/templates/blocks/testimonials/component.tsx +2 -2
- package/dist/templates/blocks/testimonials/schema.ts +2 -2
- package/dist/templates/features/pages/blocks/hero/component.tsx +6 -3
- package/dist/templates/features/pages/blocks/hero/schema.ts +2 -1
- package/dist/types/blocks.d.ts +24 -0
- package/dist/types/blocks.d.ts.map +1 -1
- package/dist/types/blocks.js +17 -1
- package/package.json +2 -2
- package/templates/app/api/v1/billing/cancel/route.ts +1 -1
- package/templates/app/api/v1/billing/change-plan/route.ts +1 -1
- package/templates/app/api/v1/billing/check-action/route.ts +7 -6
- package/templates/app/api/v1/billing/checkout/route.ts +35 -7
- package/templates/app/api/v1/billing/portal/route.ts +1 -1
- package/templates/app/dashboard/settings/billing/page.tsx +9 -4
- package/templates/app/dashboard/settings/plans/page.tsx +29 -7
- package/templates/blocks/hero/component.tsx +6 -3
- package/templates/blocks/hero/schema.ts +2 -1
- package/templates/blocks/testimonials/component.tsx +2 -2
- package/templates/blocks/testimonials/schema.ts +2 -2
- package/templates/features/pages/blocks/hero/component.tsx +6 -3
- package/templates/features/pages/blocks/hero/schema.ts +2 -1
|
@@ -51,7 +51,7 @@ export const POST = withRateLimitTier(async (request: NextRequest) => {
|
|
|
51
51
|
|
|
52
52
|
// 3. Permission check using MembershipService
|
|
53
53
|
const membership = await MembershipService.get(authResult.user.id, teamId)
|
|
54
|
-
const actionResult = membership.canPerformAction('billing.
|
|
54
|
+
const actionResult = membership.canPerformAction('team.billing.manage')
|
|
55
55
|
|
|
56
56
|
if (!actionResult.allowed) {
|
|
57
57
|
return NextResponse.json(
|
|
@@ -49,7 +49,7 @@ export const POST = withRateLimitTier(async (request: NextRequest) => {
|
|
|
49
49
|
|
|
50
50
|
// 3. Permission check using MembershipService
|
|
51
51
|
const membership = await MembershipService.get(authResult.user.id, teamId)
|
|
52
|
-
const actionResult = membership.canPerformAction('billing.
|
|
52
|
+
const actionResult = membership.canPerformAction('team.billing.manage')
|
|
53
53
|
|
|
54
54
|
if (!actionResult.allowed) {
|
|
55
55
|
return NextResponse.json(
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
|
|
12
12
|
import { NextRequest, NextResponse } from 'next/server'
|
|
13
13
|
import { authenticateRequest, createAuthError } from '@nextsparkjs/core/lib/api/auth/dual-auth'
|
|
14
|
-
import {
|
|
14
|
+
import { SubscriptionService } from '@nextsparkjs/core/lib/services'
|
|
15
15
|
import { z } from 'zod'
|
|
16
16
|
import { withRateLimitTier } from '@nextsparkjs/core/lib/api/rate-limit'
|
|
17
17
|
|
|
@@ -69,11 +69,12 @@ export const POST = withRateLimitTier(async (request: NextRequest) => {
|
|
|
69
69
|
)
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
-
// 4. Check action
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
72
|
+
// 4. Check action using SubscriptionService (RBAC + features + quotas)
|
|
73
|
+
const result = await SubscriptionService.canPerformAction(
|
|
74
|
+
authResult.user.id,
|
|
75
|
+
teamId,
|
|
76
|
+
action
|
|
77
|
+
)
|
|
77
78
|
|
|
78
79
|
return NextResponse.json({
|
|
79
80
|
success: true,
|
|
@@ -69,7 +69,7 @@ export const POST = withRateLimitTier(async (request: NextRequest) => {
|
|
|
69
69
|
|
|
70
70
|
// 4. Permission check using MembershipService
|
|
71
71
|
const membership = await MembershipService.get(authResult.user.id, teamId)
|
|
72
|
-
const actionResult = membership.canPerformAction('billing.
|
|
72
|
+
const actionResult = membership.canPerformAction('team.billing.manage')
|
|
73
73
|
|
|
74
74
|
if (!actionResult.allowed) {
|
|
75
75
|
return NextResponse.json(
|
|
@@ -83,16 +83,44 @@ export const POST = withRateLimitTier(async (request: NextRequest) => {
|
|
|
83
83
|
)
|
|
84
84
|
}
|
|
85
85
|
|
|
86
|
-
// 5. Check existing subscription
|
|
86
|
+
// 5. Check existing subscription
|
|
87
87
|
try {
|
|
88
|
-
const subscription = await SubscriptionService.getActive(teamId)
|
|
88
|
+
const subscription = await SubscriptionService.getActive(teamId, authResult.user.id)
|
|
89
89
|
|
|
90
|
-
//
|
|
90
|
+
// If already subscribed with an active provider subscription,
|
|
91
|
+
// use changePlan (immediate proration) instead of creating a new checkout.
|
|
92
|
+
// This prevents double-billing by updating the existing subscription in Stripe.
|
|
93
|
+
if (subscription?.externalSubscriptionId) {
|
|
94
|
+
const result = await SubscriptionService.changePlan(
|
|
95
|
+
teamId,
|
|
96
|
+
planSlug,
|
|
97
|
+
billingPeriod,
|
|
98
|
+
authResult.user.id
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
if (!result.success) {
|
|
102
|
+
return NextResponse.json(
|
|
103
|
+
{ success: false, error: result.error },
|
|
104
|
+
{ status: 400 }
|
|
105
|
+
)
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// No redirect needed — plan changed immediately via API
|
|
109
|
+
return NextResponse.json({
|
|
110
|
+
success: true,
|
|
111
|
+
data: {
|
|
112
|
+
changed: true,
|
|
113
|
+
subscription: result.subscription,
|
|
114
|
+
warnings: result.downgradeWarnings,
|
|
115
|
+
}
|
|
116
|
+
})
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// No existing provider subscription — create a new checkout session
|
|
91
120
|
const appUrl = process.env.NEXT_PUBLIC_APP_URL || 'http://localhost:5173'
|
|
92
121
|
const successUrl = `${appUrl}/dashboard/settings/billing?success=true`
|
|
93
122
|
const cancelUrl = `${appUrl}/dashboard/settings/billing?canceled=true`
|
|
94
123
|
|
|
95
|
-
// Create checkout session via billing gateway
|
|
96
124
|
const session = await getBillingGateway().createCheckoutSession({
|
|
97
125
|
teamId,
|
|
98
126
|
planSlug,
|
|
@@ -111,11 +139,11 @@ export const POST = withRateLimitTier(async (request: NextRequest) => {
|
|
|
111
139
|
}
|
|
112
140
|
})
|
|
113
141
|
} catch (error) {
|
|
114
|
-
console.error('[checkout] Error
|
|
142
|
+
console.error('[checkout] Error:', error)
|
|
115
143
|
return NextResponse.json(
|
|
116
144
|
{
|
|
117
145
|
success: false,
|
|
118
|
-
error: error instanceof Error ? error.message : 'Failed to
|
|
146
|
+
error: error instanceof Error ? error.message : 'Failed to process checkout'
|
|
119
147
|
},
|
|
120
148
|
{ status: 500 }
|
|
121
149
|
)
|
|
@@ -38,7 +38,7 @@ export const POST = withRateLimitTier(async (request: NextRequest) => {
|
|
|
38
38
|
|
|
39
39
|
// 3. Permission check using MembershipService
|
|
40
40
|
const membership = await MembershipService.get(authResult.user.id, teamId)
|
|
41
|
-
const actionResult = membership.canPerformAction('billing.
|
|
41
|
+
const actionResult = membership.canPerformAction('team.billing.manage')
|
|
42
42
|
|
|
43
43
|
if (!actionResult.allowed) {
|
|
44
44
|
return NextResponse.json(
|
|
@@ -18,6 +18,7 @@ import { sel } from '@nextsparkjs/core/selectors'
|
|
|
18
18
|
import { useTranslations } from 'next-intl'
|
|
19
19
|
import { getTemplateOrDefaultClient } from '@nextsparkjs/registries/template-registry.client'
|
|
20
20
|
import { useInvoices } from '@nextsparkjs/core/hooks/useInvoices'
|
|
21
|
+
import { useSubscription } from '@nextsparkjs/core/hooks/useSubscription'
|
|
21
22
|
import { InvoicesTable } from '@nextsparkjs/core/components/billing'
|
|
22
23
|
import { usePermission } from '@nextsparkjs/core/lib/permissions/hooks'
|
|
23
24
|
import type { Permission } from '@nextsparkjs/core/lib/permissions/types'
|
|
@@ -25,9 +26,11 @@ import type { Permission } from '@nextsparkjs/core/lib/permissions/types'
|
|
|
25
26
|
function BillingPage() {
|
|
26
27
|
const router = useRouter()
|
|
27
28
|
const canAccessBilling = usePermission('settings.billing' as Permission)
|
|
29
|
+
const { planSlug, plan, isActive, isReady } = useSubscription()
|
|
28
30
|
const [statusMessage, setStatusMessage] = useState('')
|
|
29
|
-
const [invoicesLimit, setInvoicesLimit] = useState(3)
|
|
31
|
+
const [invoicesLimit, setInvoicesLimit] = useState(3)
|
|
30
32
|
const t = useTranslations('settings')
|
|
33
|
+
const tb = useTranslations('billing')
|
|
31
34
|
|
|
32
35
|
// Fetch invoices for current team (must be before early return)
|
|
33
36
|
const {
|
|
@@ -107,7 +110,9 @@ function BillingPage() {
|
|
|
107
110
|
{t('billing.currentPlan.description')}
|
|
108
111
|
</CardDescription>
|
|
109
112
|
</div>
|
|
110
|
-
<Badge variant=
|
|
113
|
+
<Badge variant={isActive ? 'default' : 'secondary'}>
|
|
114
|
+
{isReady && planSlug ? tb(`plans.${planSlug}.name`) : t('billing.currentPlan.free')}
|
|
115
|
+
</Badge>
|
|
111
116
|
</div>
|
|
112
117
|
</CardHeader>
|
|
113
118
|
<CardContent>
|
|
@@ -136,7 +141,7 @@ function BillingPage() {
|
|
|
136
141
|
{t('billing.upgrade.description')}
|
|
137
142
|
</p>
|
|
138
143
|
</div>
|
|
139
|
-
<Link href="/
|
|
144
|
+
<Link href="/dashboard/settings/plans">
|
|
140
145
|
<Button
|
|
141
146
|
onClick={handleUpgrade}
|
|
142
147
|
data-cy={sel('settings.billing.currentPlan.upgradeButton')}
|
|
@@ -263,7 +268,7 @@ function BillingPage() {
|
|
|
263
268
|
</p>
|
|
264
269
|
</div>
|
|
265
270
|
<div className="flex gap-3">
|
|
266
|
-
<Link href="/
|
|
271
|
+
<Link href="/dashboard/settings/plans">
|
|
267
272
|
<Button variant="outline">
|
|
268
273
|
{t('billing.upgrade.viewPricing')}
|
|
269
274
|
</Button>
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
'use client'
|
|
2
2
|
|
|
3
|
-
import { useCallback } from 'react'
|
|
3
|
+
import { useCallback, useState } from 'react'
|
|
4
4
|
import { useTranslations } from 'next-intl'
|
|
5
5
|
import { getTemplateOrDefaultClient } from '@nextsparkjs/registries/template-registry.client'
|
|
6
6
|
import { PricingTable } from '@nextsparkjs/core/components/billing'
|
|
7
|
-
import {
|
|
7
|
+
import { fetchWithTeam } from '@nextsparkjs/core/lib/api/entities'
|
|
8
|
+
import { toast } from 'sonner'
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
11
|
* Plans Settings Page
|
|
@@ -14,12 +15,33 @@ import { useRouter } from 'next/navigation'
|
|
|
14
15
|
*/
|
|
15
16
|
function PlansPage() {
|
|
16
17
|
const t = useTranslations('settings')
|
|
17
|
-
const
|
|
18
|
+
const [loading, setLoading] = useState<string | null>(null)
|
|
18
19
|
|
|
19
|
-
const handleSelectPlan = useCallback((planSlug: string) => {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
20
|
+
const handleSelectPlan = useCallback(async (planSlug: string) => {
|
|
21
|
+
setLoading(planSlug)
|
|
22
|
+
try {
|
|
23
|
+
const res = await fetchWithTeam('/api/v1/billing/checkout', {
|
|
24
|
+
method: 'POST',
|
|
25
|
+
headers: { 'Content-Type': 'application/json' },
|
|
26
|
+
body: JSON.stringify({ planSlug, billingPeriod: 'monthly' }),
|
|
27
|
+
})
|
|
28
|
+
const data = await res.json()
|
|
29
|
+
if (data.success && data.data?.url) {
|
|
30
|
+
// New subscription — redirect to provider checkout
|
|
31
|
+
window.location.href = data.data.url
|
|
32
|
+
} else if (data.success && data.data?.changed) {
|
|
33
|
+
// Plan changed via proration (existing subscription)
|
|
34
|
+
toast.success('Plan changed successfully')
|
|
35
|
+
window.location.reload()
|
|
36
|
+
} else {
|
|
37
|
+
toast.error(data.error || 'Failed to process plan change')
|
|
38
|
+
}
|
|
39
|
+
} catch {
|
|
40
|
+
toast.error('Failed to start checkout')
|
|
41
|
+
} finally {
|
|
42
|
+
setLoading(null)
|
|
43
|
+
}
|
|
44
|
+
}, [])
|
|
23
45
|
|
|
24
46
|
return (
|
|
25
47
|
<div className="max-w-6xl" data-cy="plans-settings-main">
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
2
|
import { Button } from '@/core/components/ui/button'
|
|
3
3
|
import { cn } from '@/core/lib/utils'
|
|
4
|
-
import { buildSectionClasses } from '@/core/types/blocks'
|
|
4
|
+
import { buildSectionClasses, resolveMediaUrl } from '@/core/types/blocks'
|
|
5
5
|
import type { HeroBlockProps } from './schema'
|
|
6
6
|
|
|
7
7
|
/**
|
|
@@ -43,6 +43,9 @@ export function HeroBlock({
|
|
|
43
43
|
// Handle legacy subtitle/description props for backward compatibility
|
|
44
44
|
const displayContent = content || legacyProps.subtitle || legacyProps.description
|
|
45
45
|
|
|
46
|
+
// Resolve media ref to URL (handles both legacy string and new object format)
|
|
47
|
+
const backgroundImageUrl = resolveMediaUrl(backgroundImage)
|
|
48
|
+
|
|
46
49
|
// Build section classes with background and custom className
|
|
47
50
|
const sectionClasses = buildSectionClasses(
|
|
48
51
|
cn(
|
|
@@ -55,11 +58,11 @@ export function HeroBlock({
|
|
|
55
58
|
return (
|
|
56
59
|
<section id={id} className={sectionClasses} data-cy="block-hero">
|
|
57
60
|
{/* Background Image */}
|
|
58
|
-
{
|
|
61
|
+
{backgroundImageUrl && (
|
|
59
62
|
<div
|
|
60
63
|
className="absolute inset-0 z-0"
|
|
61
64
|
style={{
|
|
62
|
-
backgroundImage: `url(${
|
|
65
|
+
backgroundImage: `url(${backgroundImageUrl})`,
|
|
63
66
|
backgroundSize: 'cover',
|
|
64
67
|
backgroundPosition: 'center',
|
|
65
68
|
}}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { z } from 'zod'
|
|
2
2
|
import {
|
|
3
3
|
baseBlockSchema,
|
|
4
|
+
mediaRefSchema,
|
|
4
5
|
type BaseBlockProps,
|
|
5
6
|
} from '@/core/types/blocks'
|
|
6
7
|
|
|
@@ -16,7 +17,7 @@ import {
|
|
|
16
17
|
*/
|
|
17
18
|
export const heroSpecificSchema = z.object({
|
|
18
19
|
// Hero-specific design fields
|
|
19
|
-
backgroundImage:
|
|
20
|
+
backgroundImage: mediaRefSchema.optional(),
|
|
20
21
|
textColor: z.enum(['light', 'dark']).default('light'),
|
|
21
22
|
})
|
|
22
23
|
|
|
@@ -2,7 +2,7 @@ import React from 'react'
|
|
|
2
2
|
import { Quote } from 'lucide-react'
|
|
3
3
|
import { Avatar, AvatarFallback, AvatarImage } from '@/core/components/ui/avatar'
|
|
4
4
|
import { cn } from '@/core/lib/utils'
|
|
5
|
-
import { buildSectionClasses } from '@/core/types/blocks'
|
|
5
|
+
import { buildSectionClasses, resolveMediaUrl } from '@/core/types/blocks'
|
|
6
6
|
import type { TestimonialsBlockProps, TestimonialItem } from './schema'
|
|
7
7
|
|
|
8
8
|
/**
|
|
@@ -77,7 +77,7 @@ export function TestimonialsBlock({
|
|
|
77
77
|
|
|
78
78
|
<div className="flex items-center gap-3">
|
|
79
79
|
<Avatar>
|
|
80
|
-
<AvatarImage src={item.avatar} alt={item.author} />
|
|
80
|
+
<AvatarImage src={resolveMediaUrl(item.avatar)} alt={item.author} />
|
|
81
81
|
<AvatarFallback>
|
|
82
82
|
{item.author.split(' ').map((n: string) => n[0]).join('')}
|
|
83
83
|
</AvatarFallback>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { z } from 'zod'
|
|
2
|
-
import { baseBlockSchema } from '@/core/types/blocks'
|
|
2
|
+
import { baseBlockSchema, mediaRefSchema } from '@/core/types/blocks'
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Testimonial Item Schema
|
|
@@ -9,7 +9,7 @@ const testimonialItemSchema = z.object({
|
|
|
9
9
|
quote: z.string().min(1, 'Quote is required').max(500),
|
|
10
10
|
author: z.string().min(1, 'Author name is required').max(100),
|
|
11
11
|
role: z.string().max(100).optional(),
|
|
12
|
-
avatar:
|
|
12
|
+
avatar: mediaRefSchema.optional(),
|
|
13
13
|
})
|
|
14
14
|
|
|
15
15
|
export type TestimonialItem = z.infer<typeof testimonialItemSchema>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
2
|
import { Button } from '@nextsparkjs/core/components/ui/button'
|
|
3
3
|
import { cn } from '@nextsparkjs/core/lib/utils'
|
|
4
|
-
import { buildSectionClasses } from '@nextsparkjs/core/types/blocks'
|
|
4
|
+
import { buildSectionClasses, resolveMediaUrl } from '@nextsparkjs/core/types/blocks'
|
|
5
5
|
import { sel } from '../../lib/selectors'
|
|
6
6
|
import type { HeroBlockProps } from './schema'
|
|
7
7
|
|
|
@@ -45,6 +45,9 @@ export function HeroBlock({
|
|
|
45
45
|
// Handle legacy subtitle/description props for backward compatibility
|
|
46
46
|
const displayContent = content || legacyProps.subtitle || legacyProps.description
|
|
47
47
|
|
|
48
|
+
// Resolve media ref to URL (handles both legacy string and new object format)
|
|
49
|
+
const backgroundImageUrl = resolveMediaUrl(backgroundImage)
|
|
50
|
+
|
|
48
51
|
// Alignment classes mapping
|
|
49
52
|
const alignmentClasses = {
|
|
50
53
|
left: 'text-left items-start',
|
|
@@ -64,11 +67,11 @@ export function HeroBlock({
|
|
|
64
67
|
return (
|
|
65
68
|
<section id={id} className={sectionClasses} data-cy={sel('blocks.hero.container')}>
|
|
66
69
|
{/* Background Image */}
|
|
67
|
-
{
|
|
70
|
+
{backgroundImageUrl && (
|
|
68
71
|
<div
|
|
69
72
|
className="absolute inset-0 z-0"
|
|
70
73
|
style={{
|
|
71
|
-
backgroundImage: `url(${
|
|
74
|
+
backgroundImage: `url(${backgroundImageUrl})`,
|
|
72
75
|
backgroundSize: 'cover',
|
|
73
76
|
backgroundPosition: 'center',
|
|
74
77
|
}}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { z } from 'zod'
|
|
2
2
|
import {
|
|
3
3
|
baseBlockSchema,
|
|
4
|
+
mediaRefSchema,
|
|
4
5
|
type BaseBlockProps,
|
|
5
6
|
} from '@nextsparkjs/core/types/blocks'
|
|
6
7
|
|
|
@@ -17,7 +18,7 @@ import {
|
|
|
17
18
|
*/
|
|
18
19
|
export const heroSpecificSchema = z.object({
|
|
19
20
|
// Hero-specific design fields
|
|
20
|
-
backgroundImage:
|
|
21
|
+
backgroundImage: mediaRefSchema.optional(),
|
|
21
22
|
textColor: z.enum(['light', 'dark']).default('light'),
|
|
22
23
|
alignment: z.enum(['left', 'center', 'right']).default('center'),
|
|
23
24
|
})
|
package/dist/types/blocks.d.ts
CHANGED
|
@@ -5,6 +5,30 @@
|
|
|
5
5
|
* Supports WordPress/Webflow-style page building with reusable blocks.
|
|
6
6
|
*/
|
|
7
7
|
import { z } from 'zod';
|
|
8
|
+
/**
|
|
9
|
+
* Media Reference Schema
|
|
10
|
+
*
|
|
11
|
+
* Blocks can store media references in two formats:
|
|
12
|
+
* - Legacy: plain URL string (backward compatible)
|
|
13
|
+
* - New: object with mediaId + url (enables future URL re-resolution)
|
|
14
|
+
*
|
|
15
|
+
* Use `resolveMediaUrl()` in components to safely extract the URL from either format.
|
|
16
|
+
*/
|
|
17
|
+
export declare const mediaRefObjectSchema: z.ZodObject<{
|
|
18
|
+
mediaId: z.ZodString;
|
|
19
|
+
url: z.ZodString;
|
|
20
|
+
}, z.core.$strip>;
|
|
21
|
+
export declare const mediaRefSchema: z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
|
|
22
|
+
mediaId: z.ZodString;
|
|
23
|
+
url: z.ZodString;
|
|
24
|
+
}, z.core.$strip>]>;
|
|
25
|
+
export type MediaRef = z.infer<typeof mediaRefSchema>;
|
|
26
|
+
export type MediaRefObject = z.infer<typeof mediaRefObjectSchema>;
|
|
27
|
+
/**
|
|
28
|
+
* Resolve a MediaRef value to a plain URL string.
|
|
29
|
+
* Handles both legacy string URLs and new { mediaId, url } objects.
|
|
30
|
+
*/
|
|
31
|
+
export declare function resolveMediaUrl(ref: MediaRef | null | undefined): string | undefined;
|
|
8
32
|
/**
|
|
9
33
|
* CTA (Call-to-Action) Schema
|
|
10
34
|
* Used for buttons/links in Content tab
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"blocks.d.ts","sourceRoot":"","sources":["../../src/types/blocks.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"blocks.d.ts","sourceRoot":"","sources":["../../src/types/blocks.ts"],"names":[],"mappings":"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"}
|
package/dist/types/blocks.js
CHANGED
|
@@ -1,4 +1,17 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
+
const mediaRefObjectSchema = z.object({
|
|
3
|
+
mediaId: z.string(),
|
|
4
|
+
url: z.string()
|
|
5
|
+
});
|
|
6
|
+
const mediaRefSchema = z.union([
|
|
7
|
+
z.string(),
|
|
8
|
+
mediaRefObjectSchema
|
|
9
|
+
]);
|
|
10
|
+
function resolveMediaUrl(ref) {
|
|
11
|
+
if (!ref) return void 0;
|
|
12
|
+
if (typeof ref === "string") return ref || void 0;
|
|
13
|
+
return ref.url || void 0;
|
|
14
|
+
}
|
|
2
15
|
const ctaSchema = z.object({
|
|
3
16
|
text: z.string().min(1, "CTA text is required"),
|
|
4
17
|
link: z.string().url("Must be a valid URL").or(z.string().startsWith("/")),
|
|
@@ -199,5 +212,8 @@ export {
|
|
|
199
212
|
getBackgroundClasses,
|
|
200
213
|
getSectionAttributes,
|
|
201
214
|
isBlockConfig,
|
|
202
|
-
isBlockInstance
|
|
215
|
+
isBlockInstance,
|
|
216
|
+
mediaRefObjectSchema,
|
|
217
|
+
mediaRefSchema,
|
|
218
|
+
resolveMediaUrl
|
|
203
219
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nextsparkjs/core",
|
|
3
|
-
"version": "0.1.0-beta.
|
|
3
|
+
"version": "0.1.0-beta.129",
|
|
4
4
|
"description": "NextSpark - The complete SaaS framework for Next.js",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "NextSpark <hello@nextspark.dev>",
|
|
@@ -462,7 +462,7 @@
|
|
|
462
462
|
"tailwind-merge": "^3.3.1",
|
|
463
463
|
"uuid": "^13.0.0",
|
|
464
464
|
"zod": "^4.1.5",
|
|
465
|
-
"@nextsparkjs/testing": "0.1.0-beta.
|
|
465
|
+
"@nextsparkjs/testing": "0.1.0-beta.129"
|
|
466
466
|
},
|
|
467
467
|
"scripts": {
|
|
468
468
|
"postinstall": "node scripts/postinstall.mjs || true",
|
|
@@ -51,7 +51,7 @@ export const POST = withRateLimitTier(async (request: NextRequest) => {
|
|
|
51
51
|
|
|
52
52
|
// 3. Permission check using MembershipService
|
|
53
53
|
const membership = await MembershipService.get(authResult.user.id, teamId)
|
|
54
|
-
const actionResult = membership.canPerformAction('billing.
|
|
54
|
+
const actionResult = membership.canPerformAction('team.billing.manage')
|
|
55
55
|
|
|
56
56
|
if (!actionResult.allowed) {
|
|
57
57
|
return NextResponse.json(
|
|
@@ -49,7 +49,7 @@ export const POST = withRateLimitTier(async (request: NextRequest) => {
|
|
|
49
49
|
|
|
50
50
|
// 3. Permission check using MembershipService
|
|
51
51
|
const membership = await MembershipService.get(authResult.user.id, teamId)
|
|
52
|
-
const actionResult = membership.canPerformAction('billing.
|
|
52
|
+
const actionResult = membership.canPerformAction('team.billing.manage')
|
|
53
53
|
|
|
54
54
|
if (!actionResult.allowed) {
|
|
55
55
|
return NextResponse.json(
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
|
|
12
12
|
import { NextRequest, NextResponse } from 'next/server'
|
|
13
13
|
import { authenticateRequest, createAuthError } from '@nextsparkjs/core/lib/api/auth/dual-auth'
|
|
14
|
-
import {
|
|
14
|
+
import { SubscriptionService } from '@nextsparkjs/core/lib/services'
|
|
15
15
|
import { z } from 'zod'
|
|
16
16
|
import { withRateLimitTier } from '@nextsparkjs/core/lib/api/rate-limit'
|
|
17
17
|
|
|
@@ -69,11 +69,12 @@ export const POST = withRateLimitTier(async (request: NextRequest) => {
|
|
|
69
69
|
)
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
-
// 4. Check action
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
72
|
+
// 4. Check action using SubscriptionService (RBAC + features + quotas)
|
|
73
|
+
const result = await SubscriptionService.canPerformAction(
|
|
74
|
+
authResult.user.id,
|
|
75
|
+
teamId,
|
|
76
|
+
action
|
|
77
|
+
)
|
|
77
78
|
|
|
78
79
|
return NextResponse.json({
|
|
79
80
|
success: true,
|
|
@@ -69,7 +69,7 @@ export const POST = withRateLimitTier(async (request: NextRequest) => {
|
|
|
69
69
|
|
|
70
70
|
// 4. Permission check using MembershipService
|
|
71
71
|
const membership = await MembershipService.get(authResult.user.id, teamId)
|
|
72
|
-
const actionResult = membership.canPerformAction('billing.
|
|
72
|
+
const actionResult = membership.canPerformAction('team.billing.manage')
|
|
73
73
|
|
|
74
74
|
if (!actionResult.allowed) {
|
|
75
75
|
return NextResponse.json(
|
|
@@ -83,16 +83,44 @@ export const POST = withRateLimitTier(async (request: NextRequest) => {
|
|
|
83
83
|
)
|
|
84
84
|
}
|
|
85
85
|
|
|
86
|
-
// 5. Check existing subscription
|
|
86
|
+
// 5. Check existing subscription
|
|
87
87
|
try {
|
|
88
|
-
const subscription = await SubscriptionService.getActive(teamId)
|
|
88
|
+
const subscription = await SubscriptionService.getActive(teamId, authResult.user.id)
|
|
89
89
|
|
|
90
|
-
//
|
|
90
|
+
// If already subscribed with an active provider subscription,
|
|
91
|
+
// use changePlan (immediate proration) instead of creating a new checkout.
|
|
92
|
+
// This prevents double-billing by updating the existing subscription in Stripe.
|
|
93
|
+
if (subscription?.externalSubscriptionId) {
|
|
94
|
+
const result = await SubscriptionService.changePlan(
|
|
95
|
+
teamId,
|
|
96
|
+
planSlug,
|
|
97
|
+
billingPeriod,
|
|
98
|
+
authResult.user.id
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
if (!result.success) {
|
|
102
|
+
return NextResponse.json(
|
|
103
|
+
{ success: false, error: result.error },
|
|
104
|
+
{ status: 400 }
|
|
105
|
+
)
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// No redirect needed — plan changed immediately via API
|
|
109
|
+
return NextResponse.json({
|
|
110
|
+
success: true,
|
|
111
|
+
data: {
|
|
112
|
+
changed: true,
|
|
113
|
+
subscription: result.subscription,
|
|
114
|
+
warnings: result.downgradeWarnings,
|
|
115
|
+
}
|
|
116
|
+
})
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// No existing provider subscription — create a new checkout session
|
|
91
120
|
const appUrl = process.env.NEXT_PUBLIC_APP_URL || 'http://localhost:5173'
|
|
92
121
|
const successUrl = `${appUrl}/dashboard/settings/billing?success=true`
|
|
93
122
|
const cancelUrl = `${appUrl}/dashboard/settings/billing?canceled=true`
|
|
94
123
|
|
|
95
|
-
// Create checkout session via billing gateway
|
|
96
124
|
const session = await getBillingGateway().createCheckoutSession({
|
|
97
125
|
teamId,
|
|
98
126
|
planSlug,
|
|
@@ -111,11 +139,11 @@ export const POST = withRateLimitTier(async (request: NextRequest) => {
|
|
|
111
139
|
}
|
|
112
140
|
})
|
|
113
141
|
} catch (error) {
|
|
114
|
-
console.error('[checkout] Error
|
|
142
|
+
console.error('[checkout] Error:', error)
|
|
115
143
|
return NextResponse.json(
|
|
116
144
|
{
|
|
117
145
|
success: false,
|
|
118
|
-
error: error instanceof Error ? error.message : 'Failed to
|
|
146
|
+
error: error instanceof Error ? error.message : 'Failed to process checkout'
|
|
119
147
|
},
|
|
120
148
|
{ status: 500 }
|
|
121
149
|
)
|
|
@@ -38,7 +38,7 @@ export const POST = withRateLimitTier(async (request: NextRequest) => {
|
|
|
38
38
|
|
|
39
39
|
// 3. Permission check using MembershipService
|
|
40
40
|
const membership = await MembershipService.get(authResult.user.id, teamId)
|
|
41
|
-
const actionResult = membership.canPerformAction('billing.
|
|
41
|
+
const actionResult = membership.canPerformAction('team.billing.manage')
|
|
42
42
|
|
|
43
43
|
if (!actionResult.allowed) {
|
|
44
44
|
return NextResponse.json(
|