- Add Google Analytics tracking (G-ZDZ26XYN2P) to frontend - Create comprehensive analytics utility with event tracking - Track URL submissions, analysis results, and user authentication - Add route tracking for SPA navigation - Fix CORS configuration to support both localhost and production - Fix home page tracking form to display results instead of auto-redirect - Add service management scripts for easier deployment - Update database migrations for enhanced analysis features Key Features: - Anonymous and authenticated user tracking - SSL/SEO/Security analysis event tracking - Error tracking for debugging - Page view tracking for SPA routes - Multi-origin CORS support for development and production
714 lines
26 KiB
TypeScript
714 lines
26 KiB
TypeScript
/**
|
|
* Home Page - Landing page and quick start interface
|
|
*/
|
|
|
|
import { useState } from 'react';
|
|
import { trackUrlSubmission, trackAnalysisResult, trackError } from '../utils/analytics';
|
|
import {
|
|
Box,
|
|
Heading,
|
|
Text,
|
|
Container,
|
|
VStack,
|
|
HStack,
|
|
Card,
|
|
CardBody,
|
|
CardHeader,
|
|
SimpleGrid,
|
|
Button,
|
|
Badge,
|
|
Input,
|
|
Icon,
|
|
useToast,
|
|
useColorModeValue,
|
|
Stat,
|
|
StatLabel,
|
|
StatNumber,
|
|
StatHelpText,
|
|
FormControl,
|
|
FormLabel,
|
|
Select,
|
|
Switch,
|
|
FormHelperText,
|
|
Slider,
|
|
SliderTrack,
|
|
SliderFilledTrack,
|
|
SliderThumb,
|
|
NumberInput,
|
|
NumberInputField,
|
|
NumberInputStepper,
|
|
NumberIncrementStepper,
|
|
NumberDecrementStepper,
|
|
Textarea,
|
|
Collapse,
|
|
Divider,
|
|
Alert,
|
|
AlertIcon,
|
|
// StatArrow,
|
|
// Flex,
|
|
// Stack,
|
|
// Image,
|
|
// Center,
|
|
} from '@chakra-ui/react';
|
|
import { Link as RouterLink } from 'react-router-dom';
|
|
import { useMutation } from '@tanstack/react-query';
|
|
import { useForm } from 'react-hook-form';
|
|
import { zodResolver } from '@hookform/resolvers/zod';
|
|
import { z } from 'zod';
|
|
import {
|
|
FiTrendingUp,
|
|
FiActivity,
|
|
FiLock,
|
|
FiSearch,
|
|
FiShield,
|
|
FiUpload,
|
|
FiBarChart,
|
|
FiZap,
|
|
// FiGlobe,
|
|
FiArrowRight,
|
|
FiCheckCircle,
|
|
} from 'react-icons/fi';
|
|
|
|
import { trackingApi, TrackRequestV2 } from '../services/api';
|
|
import { useAuth } from '../contexts/AuthContext';
|
|
import { TrackingResults } from '../components/Tracking/TrackingResults';
|
|
|
|
const trackingSchema = z.object({
|
|
url: z.string().min(1, 'URL is required').url('Invalid URL format'),
|
|
method: z.enum(['GET', 'POST', 'HEAD']),
|
|
userAgent: z.string().optional(),
|
|
maxHops: z.number().min(1).max(20),
|
|
timeout: z.number().min(1000).max(30000),
|
|
enableSSLAnalysis: z.boolean(),
|
|
enableSEOAnalysis: z.boolean(),
|
|
enableSecurityAnalysis: z.boolean(),
|
|
customHeaders: z.string().optional(),
|
|
});
|
|
|
|
type TrackingFormData = z.infer<typeof trackingSchema>;
|
|
|
|
export function HomePage() {
|
|
const [showAdvanced, setShowAdvanced] = useState(false);
|
|
const [trackingResult, setTrackingResult] = useState<any>(null);
|
|
const { isAuthenticated } = useAuth();
|
|
const toast = useToast();
|
|
|
|
const cardBg = useColorModeValue('white', 'gray.800');
|
|
const borderColor = useColorModeValue('gray.200', 'gray.700');
|
|
const bgGradient = useColorModeValue(
|
|
'linear(to-br, blue.50, purple.50, pink.50)',
|
|
'linear(to-br, gray.900, blue.900, purple.900)'
|
|
);
|
|
|
|
const {
|
|
register,
|
|
handleSubmit,
|
|
watch,
|
|
setValue,
|
|
formState: { errors },
|
|
} = useForm<TrackingFormData>({
|
|
resolver: zodResolver(trackingSchema),
|
|
defaultValues: {
|
|
method: 'GET',
|
|
maxHops: 10,
|
|
timeout: 15000,
|
|
enableSSLAnalysis: true,
|
|
enableSEOAnalysis: true,
|
|
enableSecurityAnalysis: true,
|
|
},
|
|
});
|
|
|
|
const maxHops = watch('maxHops');
|
|
const timeout = watch('timeout');
|
|
|
|
// Tracking mutation
|
|
const trackingMutation = useMutation({
|
|
mutationFn: async (data: TrackRequestV2) => {
|
|
// Track URL submission
|
|
trackUrlSubmission(data.url, isAuthenticated);
|
|
return await trackingApi.trackUrlV2(data);
|
|
},
|
|
onSuccess: (result) => {
|
|
setTrackingResult(result);
|
|
toast({
|
|
title: 'Tracking completed',
|
|
description: `Found ${result.check.redirectCount} redirects`,
|
|
status: 'success',
|
|
duration: 3000,
|
|
isClosable: true,
|
|
});
|
|
|
|
// Track analysis results
|
|
const analysis = (result as any).check?.analysis;
|
|
if (analysis) {
|
|
trackAnalysisResult(
|
|
(result as any).check.redirectCount || 0,
|
|
analysis.ssl?.warningsJson?.length > 0 || false,
|
|
!analysis.seo?.robotsTxtStatus || analysis.seo?.noindex || false,
|
|
analysis.security?.mixedContent === 'PRESENT' || analysis.security?.safeBrowsingStatus !== 'safe' || false
|
|
);
|
|
}
|
|
|
|
// Don't auto-navigate on home page to allow users to see results
|
|
// They can manually navigate to their dashboard to see saved results
|
|
},
|
|
onError: (error: any) => {
|
|
// Track errors
|
|
trackError('tracking_failed', error.response?.data?.message || error.message || 'Unknown error');
|
|
|
|
toast({
|
|
title: 'Tracking failed',
|
|
description: error.response?.data?.message || 'An error occurred',
|
|
status: 'error',
|
|
duration: 5000,
|
|
isClosable: true,
|
|
});
|
|
},
|
|
});
|
|
|
|
const onSubmit = (data: TrackingFormData) => {
|
|
let headers: Record<string, string> = {};
|
|
|
|
// Parse custom headers if provided
|
|
if (data.customHeaders) {
|
|
try {
|
|
const lines = data.customHeaders.split('\n').filter(line => line.trim());
|
|
for (const line of lines) {
|
|
const [key, ...valueParts] = line.split(':');
|
|
if (key && valueParts.length > 0) {
|
|
headers[key.trim()] = valueParts.join(':').trim();
|
|
}
|
|
}
|
|
} catch (error) {
|
|
toast({
|
|
title: 'Invalid headers format',
|
|
description: 'Please use format: Header-Name: Header-Value',
|
|
status: 'error',
|
|
duration: 3000,
|
|
isClosable: true,
|
|
});
|
|
return;
|
|
}
|
|
}
|
|
|
|
const trackRequest: TrackRequestV2 = {
|
|
url: data.url,
|
|
method: data.method,
|
|
userAgent: data.userAgent,
|
|
headers: Object.keys(headers).length > 0 ? headers : undefined,
|
|
maxHops: data.maxHops,
|
|
timeout: data.timeout,
|
|
enableSSLAnalysis: data.enableSSLAnalysis,
|
|
enableSEOAnalysis: data.enableSEOAnalysis,
|
|
enableSecurityAnalysis: data.enableSecurityAnalysis,
|
|
};
|
|
|
|
trackingMutation.mutate(trackRequest);
|
|
};
|
|
|
|
const features = [
|
|
{
|
|
icon: FiActivity,
|
|
title: 'Real-time Tracking',
|
|
description: 'Track redirects in real-time with comprehensive hop analysis and performance metrics.',
|
|
color: 'blue',
|
|
},
|
|
{
|
|
icon: FiLock,
|
|
title: 'SSL Analysis',
|
|
description: 'Comprehensive SSL certificate analysis with expiry warnings and security insights.',
|
|
color: 'green',
|
|
},
|
|
{
|
|
icon: FiSearch,
|
|
title: 'SEO Optimization',
|
|
description: 'Check meta tags, robots.txt, canonical URLs, and other SEO factors.',
|
|
color: 'purple',
|
|
},
|
|
{
|
|
icon: FiShield,
|
|
title: 'Security Scanning',
|
|
description: 'Detect security vulnerabilities, mixed content, and safe browsing status.',
|
|
color: 'red',
|
|
},
|
|
{
|
|
icon: FiUpload,
|
|
title: 'Bulk Processing',
|
|
description: 'Upload CSV files to track thousands of URLs with background processing.',
|
|
color: 'orange',
|
|
},
|
|
{
|
|
icon: FiBarChart,
|
|
title: 'Advanced Analytics',
|
|
description: 'Generate detailed reports with Mermaid diagrams and export to PDF/Markdown.',
|
|
color: 'teal',
|
|
},
|
|
];
|
|
|
|
const stats = [
|
|
{
|
|
label: 'Redirect Hops Tracked',
|
|
value: '10M+',
|
|
helpText: 'Total redirect hops analyzed',
|
|
icon: FiTrendingUp,
|
|
},
|
|
{
|
|
label: 'SSL Certificates Analyzed',
|
|
value: '2.5M+',
|
|
helpText: 'Certificates checked for security',
|
|
icon: FiLock,
|
|
},
|
|
{
|
|
label: 'Security Scans',
|
|
value: '1M+',
|
|
helpText: 'Vulnerability assessments performed',
|
|
icon: FiShield,
|
|
},
|
|
{
|
|
label: 'Average Response Time',
|
|
value: '<500ms',
|
|
helpText: 'Lightning-fast analysis',
|
|
icon: FiZap,
|
|
},
|
|
];
|
|
|
|
return (
|
|
<Box>
|
|
{/* Hero Section */}
|
|
<Box bgGradient={bgGradient} py={{ base: 16, md: 24 }}>
|
|
<Container maxW="6xl">
|
|
<VStack spacing={8} textAlign="center">
|
|
<Badge colorScheme="brand" variant="subtle" px={4} py={2} borderRadius="full">
|
|
🚀 URL Tracker Tool V2 - Now Available
|
|
</Badge>
|
|
|
|
<VStack spacing={4}>
|
|
<Heading
|
|
as="h1"
|
|
size={{ base: "xl", md: "2xl" }}
|
|
bgGradient="linear(to-r, brand.400, purple.400, pink.400)"
|
|
bgClip="text"
|
|
fontWeight="bold"
|
|
>
|
|
URL Redirect Tracking & Analysis
|
|
</Heading>
|
|
<Text fontSize={{ base: "lg", md: "xl" }} color="gray.600" maxW="2xl">
|
|
Track redirect chains, analyze SSL certificates, optimize SEO, and scan for security vulnerabilities with our comprehensive platform.
|
|
</Text>
|
|
</VStack>
|
|
|
|
{/* Advanced Tracking Form */}
|
|
<Card bg={cardBg} border="1px solid" borderColor={borderColor} maxW="4xl" w="full">
|
|
<CardHeader>
|
|
<HStack justify="space-between">
|
|
<Heading as="h3" size="md">
|
|
URL Redirect Tracker
|
|
</Heading>
|
|
<Badge colorScheme="brand">Enhanced v2</Badge>
|
|
</HStack>
|
|
</CardHeader>
|
|
|
|
<CardBody>
|
|
<form onSubmit={handleSubmit(onSubmit)}>
|
|
<VStack spacing={6} align="stretch">
|
|
{/* URL Input */}
|
|
<FormControl isInvalid={!!errors.url}>
|
|
<FormLabel>URL to Track</FormLabel>
|
|
<Input
|
|
{...register('url')}
|
|
placeholder="https://example.com or example.com"
|
|
size="lg"
|
|
/>
|
|
{errors.url && (
|
|
<Text color="red.500" fontSize="sm" mt={1}>
|
|
{errors.url.message}
|
|
</Text>
|
|
)}
|
|
<FormHelperText>
|
|
Enter the URL you want to track. Protocol (http/https) is optional.
|
|
</FormHelperText>
|
|
</FormControl>
|
|
|
|
{/* Method Selection */}
|
|
<FormControl>
|
|
<FormLabel>HTTP Method</FormLabel>
|
|
<Select {...register('method')}>
|
|
<option value="GET">GET</option>
|
|
<option value="HEAD">HEAD</option>
|
|
<option value="POST">POST</option>
|
|
</Select>
|
|
<FormHelperText>
|
|
HTTP method to use for the initial request
|
|
</FormHelperText>
|
|
</FormControl>
|
|
|
|
{/* Analysis Options */}
|
|
<FormControl>
|
|
<FormLabel>Analysis Options</FormLabel>
|
|
<VStack align="start" spacing={3}>
|
|
<HStack justify="space-between" w="full">
|
|
<Text>SSL Certificate Analysis</Text>
|
|
<Switch {...register('enableSSLAnalysis')} colorScheme="brand" />
|
|
</HStack>
|
|
<HStack justify="space-between" w="full">
|
|
<Text>SEO Optimization Analysis</Text>
|
|
<Switch {...register('enableSEOAnalysis')} colorScheme="brand" />
|
|
</HStack>
|
|
<HStack justify="space-between" w="full">
|
|
<Text>Security Vulnerability Scan</Text>
|
|
<Switch {...register('enableSecurityAnalysis')} colorScheme="brand" />
|
|
</HStack>
|
|
</VStack>
|
|
<FormHelperText>
|
|
Enable advanced analysis features (recommended)
|
|
</FormHelperText>
|
|
</FormControl>
|
|
|
|
{/* Advanced Options Toggle */}
|
|
<Button
|
|
variant="ghost"
|
|
onClick={() => setShowAdvanced(!showAdvanced)}
|
|
size="sm"
|
|
>
|
|
{showAdvanced ? 'Hide' : 'Show'} Advanced Options
|
|
</Button>
|
|
|
|
{/* Advanced Options */}
|
|
<Collapse in={showAdvanced}>
|
|
<VStack spacing={6} align="stretch">
|
|
<Divider />
|
|
|
|
{/* Max Hops */}
|
|
<FormControl>
|
|
<FormLabel>Maximum Hops: {maxHops}</FormLabel>
|
|
<Slider
|
|
value={maxHops}
|
|
onChange={(value) => setValue('maxHops', value)}
|
|
min={1}
|
|
max={20}
|
|
step={1}
|
|
colorScheme="brand"
|
|
>
|
|
<SliderTrack>
|
|
<SliderFilledTrack />
|
|
</SliderTrack>
|
|
<SliderThumb />
|
|
</Slider>
|
|
<FormHelperText>
|
|
Maximum number of redirects to follow (1-20)
|
|
</FormHelperText>
|
|
</FormControl>
|
|
|
|
{/* Timeout */}
|
|
<FormControl>
|
|
<FormLabel>Timeout (milliseconds)</FormLabel>
|
|
<NumberInput
|
|
value={timeout}
|
|
onChange={(valueString) => setValue('timeout', parseInt(valueString) || 15000)}
|
|
min={1000}
|
|
max={30000}
|
|
step={1000}
|
|
>
|
|
<NumberInputField />
|
|
<NumberInputStepper>
|
|
<NumberIncrementStepper />
|
|
<NumberDecrementStepper />
|
|
</NumberInputStepper>
|
|
</NumberInput>
|
|
<FormHelperText>
|
|
Request timeout in milliseconds (1000-30000)
|
|
</FormHelperText>
|
|
</FormControl>
|
|
|
|
{/* User Agent */}
|
|
<FormControl>
|
|
<FormLabel>Custom User Agent</FormLabel>
|
|
<Input
|
|
{...register('userAgent')}
|
|
placeholder="Mozilla/5.0 (compatible; RedirectTracker/2.0)"
|
|
/>
|
|
<FormHelperText>
|
|
Custom User-Agent header (optional)
|
|
</FormHelperText>
|
|
</FormControl>
|
|
|
|
{/* Custom Headers */}
|
|
<FormControl>
|
|
<FormLabel>Custom Headers</FormLabel>
|
|
<Textarea
|
|
{...register('customHeaders')}
|
|
placeholder="Accept: application/json X-Custom-Header: value"
|
|
rows={4}
|
|
resize="vertical"
|
|
/>
|
|
<FormHelperText>
|
|
Custom headers, one per line in format: Header-Name: Header-Value
|
|
</FormHelperText>
|
|
</FormControl>
|
|
</VStack>
|
|
</Collapse>
|
|
|
|
{/* Rate Limiting Warning */}
|
|
{!isAuthenticated && (
|
|
<Alert status="info" borderRadius="md">
|
|
<AlertIcon />
|
|
<VStack align="start" spacing={1}>
|
|
<Text fontWeight="medium">Anonymous Usage</Text>
|
|
<Text fontSize="sm">
|
|
Anonymous users are limited to 50 requests per hour.
|
|
<Text as="span" color="brand.500" fontWeight="medium">
|
|
{' '}Sign up for higher limits and saved results.
|
|
</Text>
|
|
</Text>
|
|
</VStack>
|
|
</Alert>
|
|
)}
|
|
|
|
{/* Submit Button */}
|
|
<Button
|
|
type="submit"
|
|
colorScheme="brand"
|
|
size="lg"
|
|
isLoading={trackingMutation.isPending}
|
|
loadingText="Tracking..."
|
|
>
|
|
Track URL
|
|
</Button>
|
|
</VStack>
|
|
</form>
|
|
</CardBody>
|
|
</Card>
|
|
|
|
|
|
</VStack>
|
|
</Container>
|
|
</Box>
|
|
|
|
<Container maxW="7xl" py={16}>
|
|
<VStack spacing={16}>
|
|
{/* Stats Section */}
|
|
<Box w="full">
|
|
<VStack spacing={8} textAlign="center">
|
|
<Heading as="h2" size="xl">
|
|
Trusted by Professionals Worldwide
|
|
</Heading>
|
|
<SimpleGrid columns={{ base: 2, md: 4 }} spacing={8} w="full">
|
|
{stats.map((stat, index) => (
|
|
<Card key={index} bg={cardBg} border="1px solid" borderColor={borderColor}>
|
|
<CardBody textAlign="center">
|
|
<Stat>
|
|
<VStack spacing={2}>
|
|
<Icon as={stat.icon} size="2rem" color="brand.500" />
|
|
<StatNumber fontSize="2xl" color="brand.600">
|
|
{stat.value}
|
|
</StatNumber>
|
|
<StatLabel fontSize="sm">{stat.label}</StatLabel>
|
|
<StatHelpText fontSize="xs">{stat.helpText}</StatHelpText>
|
|
</VStack>
|
|
</Stat>
|
|
</CardBody>
|
|
</Card>
|
|
))}
|
|
</SimpleGrid>
|
|
</VStack>
|
|
</Box>
|
|
|
|
{/* Features Section */}
|
|
<Box w="full">
|
|
<VStack spacing={12} textAlign="center">
|
|
<VStack spacing={4}>
|
|
<Heading as="h2" size="xl">
|
|
Comprehensive Analysis Platform
|
|
</Heading>
|
|
<Text fontSize="lg" color="gray.600" maxW="3xl">
|
|
Everything you need to understand, optimize, and secure your redirect chains with professional-grade tools and insights.
|
|
</Text>
|
|
</VStack>
|
|
|
|
<SimpleGrid columns={{ base: 1, md: 2, lg: 3 }} spacing={8} w="full">
|
|
{features.map((feature, index) => (
|
|
<Card key={index} bg={cardBg} border="1px solid" borderColor={borderColor} h="full">
|
|
<CardBody>
|
|
<VStack spacing={4} align="start" h="full">
|
|
<HStack>
|
|
<Icon as={feature.icon} size="1.5rem" color={`${feature.color}.500`} />
|
|
<Heading as="h3" size="md">
|
|
{feature.title}
|
|
</Heading>
|
|
</HStack>
|
|
<Text color="gray.600" flex="1">
|
|
{feature.description}
|
|
</Text>
|
|
<Button
|
|
variant="ghost"
|
|
size="sm"
|
|
rightIcon={<Icon as={FiArrowRight} />}
|
|
colorScheme={feature.color}
|
|
>
|
|
Learn More
|
|
</Button>
|
|
</VStack>
|
|
</CardBody>
|
|
</Card>
|
|
))}
|
|
</SimpleGrid>
|
|
</VStack>
|
|
</Box>
|
|
|
|
{/* Use Cases Section */}
|
|
<Box w="full">
|
|
<VStack spacing={12}>
|
|
<VStack spacing={4} textAlign="center">
|
|
<Heading as="h2" size="xl">
|
|
Perfect for Every Use Case
|
|
</Heading>
|
|
<Text fontSize="lg" color="gray.600" maxW="3xl">
|
|
From individual developers to enterprise teams, our platform scales to meet your redirect tracking needs.
|
|
</Text>
|
|
</VStack>
|
|
|
|
<SimpleGrid columns={{ base: 1, lg: 3 }} spacing={8} w="full">
|
|
<Card bg={cardBg} border="1px solid" borderColor={borderColor}>
|
|
<CardBody>
|
|
<VStack spacing={4} align="start">
|
|
<Badge colorScheme="blue" variant="subtle">
|
|
Developers
|
|
</Badge>
|
|
<Heading as="h3" size="md">
|
|
Debug & Optimize
|
|
</Heading>
|
|
<Text color="gray.600">
|
|
Track redirect chains, identify performance bottlenecks, and ensure proper HTTP status codes for your applications.
|
|
</Text>
|
|
<VStack align="start" spacing={2} fontSize="sm">
|
|
<HStack>
|
|
<Icon as={FiCheckCircle} color="green.500" />
|
|
<Text>Real-time redirect analysis</Text>
|
|
</HStack>
|
|
<HStack>
|
|
<Icon as={FiCheckCircle} color="green.500" />
|
|
<Text>Performance metrics</Text>
|
|
</HStack>
|
|
<HStack>
|
|
<Icon as={FiCheckCircle} color="green.500" />
|
|
<Text>API integration</Text>
|
|
</HStack>
|
|
</VStack>
|
|
</VStack>
|
|
</CardBody>
|
|
</Card>
|
|
|
|
<Card bg={cardBg} border="1px solid" borderColor={borderColor}>
|
|
<CardBody>
|
|
<VStack spacing={4} align="start">
|
|
<Badge colorScheme="green" variant="subtle">
|
|
SEO Teams
|
|
</Badge>
|
|
<Heading as="h3" size="md">
|
|
SEO Monitoring
|
|
</Heading>
|
|
<Text color="gray.600">
|
|
Monitor redirect chains for SEO impact, track canonical URLs, and ensure proper meta tag implementation.
|
|
</Text>
|
|
<VStack align="start" spacing={2} fontSize="sm">
|
|
<HStack>
|
|
<Icon as={FiCheckCircle} color="green.500" />
|
|
<Text>Meta tag analysis</Text>
|
|
</HStack>
|
|
<HStack>
|
|
<Icon as={FiCheckCircle} color="green.500" />
|
|
<Text>Canonical URL tracking</Text>
|
|
</HStack>
|
|
<HStack>
|
|
<Icon as={FiCheckCircle} color="green.500" />
|
|
<Text>Bulk URL processing</Text>
|
|
</HStack>
|
|
</VStack>
|
|
</VStack>
|
|
</CardBody>
|
|
</Card>
|
|
|
|
<Card bg={cardBg} border="1px solid" borderColor={borderColor}>
|
|
<CardBody>
|
|
<VStack spacing={4} align="start">
|
|
<Badge colorScheme="red" variant="subtle">
|
|
Security Teams
|
|
</Badge>
|
|
<Heading as="h3" size="md">
|
|
Security Audits
|
|
</Heading>
|
|
<Text color="gray.600">
|
|
Scan for security vulnerabilities, track SSL certificates, and monitor for malicious redirects.
|
|
</Text>
|
|
<VStack align="start" spacing={2} fontSize="sm">
|
|
<HStack>
|
|
<Icon as={FiCheckCircle} color="green.500" />
|
|
<Text>SSL certificate monitoring</Text>
|
|
</HStack>
|
|
<HStack>
|
|
<Icon as={FiCheckCircle} color="green.500" />
|
|
<Text>Security vulnerability scans</Text>
|
|
</HStack>
|
|
<HStack>
|
|
<Icon as={FiCheckCircle} color="green.500" />
|
|
<Text>Malicious redirect detection</Text>
|
|
</HStack>
|
|
</VStack>
|
|
</VStack>
|
|
</CardBody>
|
|
</Card>
|
|
</SimpleGrid>
|
|
</VStack>
|
|
</Box>
|
|
|
|
{/* CTA Section */}
|
|
<Box w="full">
|
|
<Card bg="brand.50" border="1px solid" borderColor="brand.200">
|
|
<CardBody py={12}>
|
|
<VStack spacing={6} textAlign="center">
|
|
<Heading as="h2" size="xl" color="brand.700">
|
|
Ready to Get Started?
|
|
</Heading>
|
|
<Text fontSize="lg" color="brand.600" maxW="2xl">
|
|
Join thousands of developers, SEO professionals, and security teams who trust our platform for comprehensive redirect analysis.
|
|
</Text>
|
|
<HStack spacing={4}>
|
|
<Button
|
|
as={RouterLink}
|
|
to={isAuthenticated ? "/dashboard" : "/register"}
|
|
colorScheme="brand"
|
|
size="lg"
|
|
leftIcon={<Icon as={FiZap} />}
|
|
>
|
|
{isAuthenticated ? "Go to Dashboard" : "Start Free Trial"}
|
|
</Button>
|
|
<Button
|
|
as={RouterLink}
|
|
to="/track"
|
|
variant="outline"
|
|
colorScheme="brand"
|
|
size="lg"
|
|
>
|
|
Try Demo
|
|
</Button>
|
|
</HStack>
|
|
<Text fontSize="sm" color="brand.600">
|
|
No credit card required • Free tier available • Enterprise plans from $99/month
|
|
</Text>
|
|
</VStack>
|
|
</CardBody>
|
|
</Card>
|
|
</Box>
|
|
</VStack>
|
|
</Container>
|
|
|
|
{/* Results */}
|
|
{trackingResult && (
|
|
<Container maxW="7xl" py={16}>
|
|
<TrackingResults result={trackingResult} />
|
|
</Container>
|
|
)}
|
|
</Box>
|
|
);
|
|
}
|