File size: 8,449 Bytes
5752a28
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
import { useState } from 'react';
import { Upload, Image as ImageIcon, Loader2, Shield } from 'lucide-react';
import { Button } from './ui/button';
import { Card } from './ui/card';
import { API_BASE_URL } from '../config';

interface UploadSectionProps {
  onAnalyze: (imageUrl: string) => void;
  isAnalyzing: boolean;
}

const SAMPLE_IMAGES = [
  {
    id: '1',
    name: 'Urgency & Scarcity Checkout',
    url: `${API_BASE_URL}/api/samples/checkout_urgency.png`,
    description: 'Fintech checkout with a countdown timer, fake spot scarcity, live-viewer social proof and a confirmshaming opt-out.'
  },
  {
    id: '2',
    name: 'Confirmshaming Cancellation',
    url: `${API_BASE_URL}/api/samples/cancel_confirmshaming.png`,
    description: 'Subscription cancellation modal using guilt-inducing copy, loss framing and a buried 6-step cancel flow.'
  },
  {
    id: '3',
    name: 'Pre-Selected Fees Signup',
    url: `${API_BASE_URL}/api/samples/signup_sneaking.png`,
    description: 'Loan account signup with pre-checked paid add-ons, a trial that silently converts, and sneaked data sharing.'
  }
];

export function UploadSection({ onAnalyze, isAnalyzing }: UploadSectionProps) {
  const [selectedSample, setSelectedSample] = useState<string | null>(null);
  const [uploadedImage, setUploadedImage] = useState<string | null>(null);

  const handleFileUpload = (event: React.ChangeEvent<HTMLInputElement>) => {
    const file = event.target.files?.[0];
    if (file) {
      const reader = new FileReader();
      reader.onload = (e) => {
        const result = e.target?.result as string;
        setUploadedImage(result);
        setSelectedSample(null);
      };
      reader.readAsDataURL(file);
    }
  };

  const handleSampleSelect = (url: string) => {
    setSelectedSample(url);
    setUploadedImage(null);
  };

  const handleAnalyze = () => {
    const imageUrl = uploadedImage || selectedSample;
    if (imageUrl) {
      onAnalyze(imageUrl);
    }
  };

  const activeImage = uploadedImage || selectedSample;

  return (
    <div className="space-y-6">

      <Card className="p-8 bg-card/40 backdrop-blur-md border border-border shadow-xl rounded-2xl relative overflow-hidden transition-colors duration-300">

        {/* Glow overlay */}

        <div className="absolute top-0 right-0 w-80 h-80 bg-indigo-500/10 rounded-full blur-3xl -z-10 pointer-events-none" />

        <div className="absolute bottom-0 left-0 w-80 h-80 bg-purple-500/5 rounded-full blur-3xl -z-10 pointer-events-none" />

        

        <h2 className="text-xl font-bold text-foreground mb-6 flex items-center gap-2">

          <Upload className="w-5 h-5 text-indigo-500 dark:text-indigo-400" />

          Audit New UI Interface

        </h2>

        

        <div className="grid md:grid-cols-2 gap-8">

          {/* Upload Area (Fits target image directly inside) */}

          <div className="space-y-4">

            <label

              htmlFor="file-upload"

              className={`relative flex flex-col items-center justify-center w-full h-72 border-2 border-dashed rounded-xl cursor-pointer overflow-hidden transition-all duration-300 ${

                isAnalyzing 

                  ? 'border-border bg-muted/10 cursor-not-allowed'

                  : activeImage

                    ? 'border-indigo-500/50 bg-slate-900/10 dark:bg-slate-950/40 shadow-inner'

                    : 'border-border bg-muted/20 hover:border-indigo-500/50 hover:bg-muted/40'

              }`}

            >

              {activeImage ? (

                <>

                  <img

                    src={activeImage}

                    alt="Uploaded UI Target"

                    className="w-full h-full object-contain p-2"

                  />

                  {/* Hover Overlay */}

                  <div className="absolute inset-0 bg-slate-950/50 opacity-0 hover:opacity-100 transition-opacity duration-300 flex flex-col items-center justify-center text-center p-4">

                    <Upload className="w-8 h-8 text-indigo-400 mb-2" />

                    <span className="text-xs font-extrabold text-white">Click or Drop to Replace Screenshot</span>

                  </div>

                  {/* Bottom Indicator badge */}

                  <div className="absolute bottom-2 left-2">

                    <span className="text-[9px] font-mono bg-indigo-600 text-white px-2.5 py-1 rounded-md uppercase tracking-wider font-extrabold shadow-lg border border-indigo-500/20">

                      Target Interface Loaded

                    </span>

                  </div>

                </>

              ) : (

                <div className="flex flex-col items-center justify-center pt-5 pb-6 px-4 text-center">

                  <div className="p-4 bg-indigo-500/5 rounded-2xl mb-4 border border-indigo-500/10">

                    <Upload className="w-10 h-10 text-indigo-500 dark:text-indigo-400 animate-pulse" />

                  </div>

                  <p className="mb-2 text-sm text-foreground/80">

                    <span className="font-semibold text-indigo-500 dark:text-indigo-400">Click to upload</span> or drag and drop

                  </p>

                  <p className="text-xs text-muted-foreground">PNG, JPG or GIF (MAX. 10MB)</p>

                </div>

              )}

              <input

                id="file-upload"

                type="file"

                className="hidden"

                accept="image/*"

                onChange={handleFileUpload}

                disabled={isAnalyzing}

              />

            </label>

          </div>



          {/* Sample Images */}

          <div className="space-y-4">

            <div className="flex items-center gap-2 mb-4">

              <ImageIcon className="w-5 h-5 text-indigo-500 dark:text-indigo-400" />

              <h3 className="font-semibold text-foreground">Select Fintech Sample Screen</h3>

            </div>

            

            <div className="space-y-3">

              {SAMPLE_IMAGES.map((sample) => (

                <button

                  key={sample.id}

                  onClick={() => handleSampleSelect(sample.url)}

                  disabled={isAnalyzing}

                  className={`w-full text-left p-4 rounded-xl border transition-all duration-300 relative overflow-hidden group ${

                    selectedSample === sample.url

                      ? 'border-indigo-500 bg-indigo-500/5 shadow-md shadow-indigo-500/5'

                      : 'border-border bg-muted/10 hover:border-slate-400 dark:hover:border-slate-700 hover:bg-muted/20'

                  } ${isAnalyzing ? 'opacity-50 cursor-not-allowed' : ''}`}

                >

                  <div className="font-bold text-sm text-foreground mb-1 group-hover:text-indigo-500 dark:group-hover:text-indigo-400 transition-colors">

                    {sample.name}

                  </div>

                  <div className="text-xs text-muted-foreground line-clamp-2 leading-relaxed">

                    {sample.description}

                  </div>

                </button>

              ))}

            </div>

          </div>

        </div>



        {/* Analyze Button */}

        <div className="mt-8 flex justify-center border-t border-border pt-6">

          <Button

            onClick={handleAnalyze}

            disabled={!activeImage || isAnalyzing}

            size="lg"

            className={`min-w-[240px] h-12 rounded-xl text-xs font-bold uppercase tracking-wider transition-all duration-300 ${

              !activeImage 

                ? 'bg-muted text-muted-foreground cursor-not-allowed border border-border' 

                : 'bg-gradient-to-r from-indigo-600 via-indigo-500 to-purple-600 hover:from-indigo-500 hover:to-purple-500 text-white shadow-[0_0_20px_rgba(99,102,241,0.3)] hover:scale-[1.03]'

            }`}

          >

            {isAnalyzing ? (

              <>

                <Loader2 className="w-5 h-5 mr-2 animate-spin text-white" />

                Processing AI Auditing...

              </>

            ) : (

              <>

                <Shield className="w-5 h-5 mr-2 text-white" />

                Analyze Deceptive Copywriting

              </>

            )}

          </Button>
        </div>
      </Card>
    </div>
  );
}