A simple SEO inspecter Tool, to get social media card previews
1import { useState } from 'react';
2import { Button } from '@/components/ui/button';
3import { Input } from '@/components/ui/input';
4import { Card } from '@/components/ui/card';
5import { Loader2, Play, Copy, Check } from 'lucide-react';
6import { toast } from 'sonner';
7
8export const APIPlayground = () => {
9 const [testUrl, setTestUrl] = useState('https://example.com');
10 const [loading, setLoading] = useState(false);
11 const [response, setResponse] = useState<any>(null);
12 const [copied, setCopied] = useState(false);
13
14 const handleTest = async () => {
15 setLoading(true);
16 try {
17 const res = await fetch(`${import.meta.env.VITE_SUPABASE_URL}/functions/v1/analyze-seo`, {
18 method: 'POST',
19 headers: {
20 'Content-Type': 'application/json',
21 'Authorization': `Bearer ${import.meta.env.VITE_SUPABASE_ANON_KEY}`
22 },
23 body: JSON.stringify({ url: testUrl })
24 });
25
26 const data = await res.json();
27 setResponse(data);
28
29 if (data.success) {
30 toast.success('Analysis completed!');
31 } else {
32 toast.error(data.error || 'Analysis failed');
33 }
34 } catch (error) {
35 toast.error('Failed to call API');
36 setResponse({ error: 'Network error' });
37 } finally {
38 setLoading(false);
39 }
40 };
41
42 const copyResponse = () => {
43 navigator.clipboard.writeText(JSON.stringify(response, null, 2));
44 setCopied(true);
45 toast.success('Copied to clipboard!');
46 setTimeout(() => setCopied(false), 2000);
47 };
48
49 return (
50 <div className="space-y-4">
51 <Card className="p-6 bg-card border-border">
52 <h3 className="text-lg font-semibold mb-4 text-foreground">Try it out</h3>
53 <div className="flex gap-2">
54 <Input
55 value={testUrl}
56 onChange={(e) => setTestUrl(e.target.value)}
57 placeholder="Enter URL to analyze"
58 className="flex-1"
59 />
60 <Button
61 onClick={handleTest}
62 disabled={loading}
63 className="bg-primary text-primary-foreground hover:bg-primary/90"
64 >
65 {loading ? (
66 <Loader2 className="h-4 w-4 animate-spin" />
67 ) : (
68 <Play className="h-4 w-4" />
69 )}
70 </Button>
71 </div>
72 </Card>
73
74 {response && (
75 <Card className="p-6 bg-muted border-border">
76 <div className="flex justify-between items-center mb-4">
77 <h4 className="font-semibold text-foreground">Response</h4>
78 <Button
79 variant="ghost"
80 size="sm"
81 onClick={copyResponse}
82 className="text-muted-foreground hover:text-foreground"
83 >
84 {copied ? <Check className="h-4 w-4" /> : <Copy className="h-4 w-4" />}
85 </Button>
86 </div>
87 <pre className="text-xs overflow-auto max-h-96 bg-background p-4 rounded border border-border text-foreground">
88 {JSON.stringify(response, null, 2)}
89 </pre>
90 </Card>
91 )}
92 </div>
93 );
94};