Next.js Full-Stack App
A complete example showing authentication, protected routes, and billing integration:
app/layout.tsx
import { SylphxProvider } from '@sylphx/platform-sdk/react'
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>
<SylphxProvider appId={process.env.NEXT_PUBLIC_SYLPHX_APP_ID!}>
{children}
</SylphxProvider>
</body>
</html>
)
}app/dashboard/page.tsx
import { auth, currentUser } from '@sylphx/platform-sdk/nextjs'
import { redirect } from 'next/navigation'
export default async function DashboardPage() {
const user = await currentUser()
if (!user) {
redirect('/login')
}
return (
<div>
<h1>Welcome, {user.name}!</h1>
<p>Email: {user.email}</p>
</div>
)
}components/user-menu.tsx
'use client'
import { useUser, useAuth } from '@sylphx/platform-sdk/react'
export function UserMenu() {
const { user, isLoading } = useUser()
const { signOut } = useAuth()
if (isLoading) return <div>Loading...</div>
if (!user) return <a href="/login">Sign In</a>
return (
<div>
<span>{user.name}</span>
<button onClick={() => signOut()}>Sign Out</button>
</div>
)
}Subscription Gating
Check subscription status to gate premium features:
Server Component
import { platform } from '@/lib/platform'
import { currentUser } from '@sylphx/platform-sdk/nextjs'
export default async function PremiumFeature() {
const user = await currentUser()
if (!user) {
return <div>Please sign in to access this feature.</div>
}
const subscription = await platform.billing.getSubscription(user.id)
if (subscription?.status !== 'active') {
return (
<div>
<p>This is a premium feature.</p>
<a href="/pricing">Upgrade to Pro</a>
</div>
)
}
return <div>Premium content here!</div>
}Client Component
'use client'
import { useUser, useBilling } from '@sylphx/platform-sdk/react'
export function PremiumContent() {
const { user } = useUser()
const { subscription, isLoading } = useBilling()
if (isLoading) return <div>Loading...</div>
if (!subscription || subscription.status !== 'active') {
return <button onClick={() => window.location.href = '/pricing'}>
Upgrade to Pro
</button>
}
return <div>Premium content!</div>
}Event Tracking
Track user behavior and custom events:
Track button clicks
'use client'
import { useAnalytics } from '@sylphx/platform-sdk/react'
export function CTAButton() {
const { track } = useAnalytics()
const handleClick = () => {
track('cta_clicked', {
location: 'hero',
variant: 'primary',
})
// Continue with action...
}
return <button onClick={handleClick}>Get Started</button>
}Track purchases (server)
import { platform } from '@/lib/platform'
export async function completePurchase(userId: string, orderId: string, amount: number) {
// Process order...
// Track the event
await platform.analytics.track({
userId,
event: 'purchase_completed',
properties: {
orderId,
amount,
currency: 'USD',
},
})
}AI Chat Integration
Build an AI-powered chat feature:
app/api/chat/route.ts
import { platform } from '@/lib/platform'
import { currentUser } from '@sylphx/platform-sdk/nextjs'
import { NextRequest } from 'next/server'
export async function POST(req: NextRequest) {
const user = await currentUser()
if (!user) {
return new Response('Unauthorized', { status: 401 })
}
const { messages } = await req.json()
const response = await platform.ai.chat({
model: 'gpt-4',
messages: [
{ role: 'system', content: 'You are a helpful assistant.' },
...messages,
],
})
return Response.json({ message: response.message.content })
}components/chat.tsx
'use client'
import { useState } from 'react'
export function Chat() {
const [messages, setMessages] = useState<Array<{ role: string; content: string }>>([])
const [input, setInput] = useState('')
const sendMessage = async () => {
const userMessage = { role: 'user', content: input }
setMessages(prev => [...prev, userMessage])
setInput('')
const res = await fetch('/api/chat', {
method: 'POST',
body: JSON.stringify({ messages: [...messages, userMessage] }),
})
const { message } = await res.json()
setMessages(prev => [...prev, { role: 'assistant', content: message }])
}
return (
<div>
<div>
{messages.map((m, i) => (
<div key={i} className={m.role === 'user' ? 'text-right' : ''}>
{m.content}
</div>
))}
</div>
<input value={input} onChange={e => setInput(e.target.value)} />
<button onClick={sendMessage}>Send</button>
</div>
)
}File Upload
Upload files with the storage API:
components/avatar-upload.tsx
'use client'
import { useStorage } from '@sylphx/platform-sdk/react'
import { useState } from 'react'
export function AvatarUpload() {
const { upload } = useStorage()
const [uploading, setUploading] = useState(false)
const handleFileChange = async (e: React.ChangeEvent<HTMLInputElement>) => {
const file = e.target.files?.[0]
if (!file) return
setUploading(true)
try {
const result = await upload(file, {
path: 'avatars',
public: true,
})
console.log('Uploaded:', result.url)
} catch (error) {
console.error('Upload failed:', error)
} finally {
setUploading(false)
}
}
return (
<div>
<input type="file" accept="image/*" onChange={handleFileChange} disabled={uploading} />
{uploading && <span>Uploading...</span>}
</div>
)
}