revops + onboarding
This commit is contained in:
@@ -7,12 +7,15 @@ import { StatsGrid } from '@/components/dashboard/StatsGrid';
|
||||
import { QRCodeCard } from '@/components/dashboard/QRCodeCard';
|
||||
import { Card, CardHeader, CardTitle, CardContent } from '@/components/ui/Card';
|
||||
import { Button } from '@/components/ui/Button';
|
||||
import { Badge } from '@/components/ui/Badge';
|
||||
import { useTranslation } from '@/hooks/useTranslation';
|
||||
import { useCsrf } from '@/hooks/useCsrf';
|
||||
import { showToast } from '@/components/ui/Toast';
|
||||
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter } from '@/components/ui/Dialog';
|
||||
import { QrCode } from 'lucide-react';
|
||||
import { Badge } from '@/components/ui/Badge';
|
||||
import { useTranslation } from '@/hooks/useTranslation';
|
||||
import { useCsrf } from '@/hooks/useCsrf';
|
||||
import { showToast } from '@/components/ui/Toast';
|
||||
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter } from '@/components/ui/Dialog';
|
||||
import { QrCode } from 'lucide-react';
|
||||
import { trackEvent, identifyUser } from '@/components/PostHogProvider';
|
||||
import { FREE_DYNAMIC_QR_LIMIT } from '@/lib/plans';
|
||||
import { OnboardingChecklist } from '@/components/dashboard/OnboardingChecklist';
|
||||
|
||||
interface QRCodeData {
|
||||
id: string;
|
||||
@@ -44,7 +47,8 @@ export default function DashboardPage() {
|
||||
conversionRate: 0,
|
||||
uniqueScans: 0,
|
||||
});
|
||||
const [analyticsData, setAnalyticsData] = useState<any>(null);
|
||||
const [analyticsData, setAnalyticsData] = useState<any>(null);
|
||||
const [onboardingState, setOnboardingState] = useState<any>(null);
|
||||
|
||||
|
||||
const blogPosts = [
|
||||
@@ -117,12 +121,11 @@ export default function DashboardPage() {
|
||||
// Store in localStorage for consistency
|
||||
localStorage.setItem('user', JSON.stringify(user));
|
||||
|
||||
const { identifyUser, trackEvent } = await import('@/components/PostHogProvider');
|
||||
identifyUser(user.id, {
|
||||
email: user.email,
|
||||
name: user.name,
|
||||
plan: user.plan || 'FREE',
|
||||
provider: 'google',
|
||||
identifyUser(user.id, {
|
||||
email: user.email,
|
||||
name: user.name,
|
||||
plan: user.plan || 'FREE',
|
||||
provider: 'google',
|
||||
});
|
||||
|
||||
trackEvent(isNewUser ? 'user_signup' : 'user_login', {
|
||||
@@ -143,25 +146,35 @@ export default function DashboardPage() {
|
||||
}, [searchParams, router]);
|
||||
|
||||
// Check for successful payment and verify session
|
||||
useEffect(() => {
|
||||
const success = searchParams.get('success');
|
||||
if (success === 'true') {
|
||||
const verifySession = async () => {
|
||||
try {
|
||||
const response = await fetch('/api/stripe/verify-session', {
|
||||
method: 'POST',
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
const data = await response.json();
|
||||
setUserPlan(data.plan);
|
||||
setUpgradedPlan(data.plan);
|
||||
setShowUpgradeDialog(true);
|
||||
// Remove success parameter from URL
|
||||
router.replace('/dashboard');
|
||||
} else {
|
||||
console.error('Failed to verify session:', await response.text());
|
||||
}
|
||||
useEffect(() => {
|
||||
const success = searchParams.get('success');
|
||||
const sessionId = searchParams.get('session_id');
|
||||
|
||||
if (success === 'true' && sessionId) {
|
||||
const verifySession = async () => {
|
||||
try {
|
||||
const response = await fetch('/api/stripe/verify-session', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({ sessionId }),
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
const data = await response.json();
|
||||
setUserPlan(data.plan);
|
||||
setUpgradedPlan(data.plan);
|
||||
setShowUpgradeDialog(true);
|
||||
trackEvent('upgrade_completed', {
|
||||
plan: data.plan,
|
||||
source: 'stripe_checkout',
|
||||
});
|
||||
// Remove success parameter from URL
|
||||
router.replace('/dashboard');
|
||||
} else {
|
||||
console.error('Failed to verify session:', await response.text());
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error verifying session:', error);
|
||||
}
|
||||
@@ -212,13 +225,19 @@ export default function DashboardPage() {
|
||||
setUserPlan(userData.plan || 'FREE');
|
||||
}
|
||||
|
||||
// Fetch analytics data for trends (last 30 days = month comparison)
|
||||
const analyticsResponse = await fetch('/api/analytics/summary?range=30');
|
||||
if (analyticsResponse.ok) {
|
||||
const analytics = await analyticsResponse.json();
|
||||
setAnalyticsData(analytics);
|
||||
}
|
||||
} catch (error) {
|
||||
// Fetch analytics data for trends (last 30 days = month comparison)
|
||||
const analyticsResponse = await fetch('/api/analytics/summary?range=30');
|
||||
if (analyticsResponse.ok) {
|
||||
const analytics = await analyticsResponse.json();
|
||||
setAnalyticsData(analytics);
|
||||
}
|
||||
|
||||
const onboardingResponse = await fetch('/api/onboarding');
|
||||
if (onboardingResponse.ok) {
|
||||
const onboardingData = await onboardingResponse.json();
|
||||
setOnboardingState(onboardingData);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error fetching data:', error);
|
||||
setQrCodes([]);
|
||||
setStats({
|
||||
@@ -341,9 +360,11 @@ export default function DashboardPage() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Stats Grid */}
|
||||
<StatsGrid
|
||||
stats={stats}
|
||||
{/* Stats Grid */}
|
||||
<OnboardingChecklist state={onboardingState} />
|
||||
|
||||
<StatsGrid
|
||||
stats={stats}
|
||||
trends={{
|
||||
totalScans: analyticsData?.summary.scansTrend,
|
||||
comparisonPeriod: analyticsData?.summary.comparisonPeriod || 'month'
|
||||
@@ -393,8 +414,8 @@ export default function DashboardPage() {
|
||||
<QrCode className="w-12 h-12 text-gray-300 mx-auto mb-4" />
|
||||
<h3 className="text-lg font-semibold text-gray-700 mb-2">Create your first QR code</h3>
|
||||
<p className="text-gray-500 mb-6 max-w-sm mx-auto">
|
||||
You have 3 free dynamic QR codes. They redirect wherever you want and track every scan.
|
||||
</p>
|
||||
You have {FREE_DYNAMIC_QR_LIMIT} free dynamic QR codes. They redirect wherever you want and track every scan.
|
||||
</p>
|
||||
<Link href="/create">
|
||||
<Button>Create QR Code — it takes 90 seconds</Button>
|
||||
</Link>
|
||||
@@ -521,4 +542,4 @@ export default function DashboardPage() {
|
||||
</Dialog>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user