Numan Saeed commited on
Commit
2be3111
·
1 Parent(s): 6e47663

Fix: Use native select for better viewport handling

Browse files

- Replaced custom dropdown with native <select>
- Automatically handles viewport boundaries
- Cancel button now visible
- More compact layout

frontend/src/components/FeedbackSection.tsx CHANGED
@@ -1,5 +1,5 @@
1
  import { useState } from 'react';
2
- import { Check, X, ChevronDown, Send, MessageSquare } from 'lucide-react';
3
  import { FETAL_VIEW_LABELS, submitFeedback, FeedbackCreate, ClassificationResult } from '../lib/api';
4
 
5
  interface FeedbackSectionProps {
@@ -30,7 +30,6 @@ export function FeedbackSection({
30
  const [notes, setNotes] = useState<string>('');
31
  const [isSubmitting, setIsSubmitting] = useState(false);
32
  const [submitted, setSubmitted] = useState(false);
33
- const [showDropdown, setShowDropdown] = useState(false);
34
 
35
  const handleFeedback = async (isCorrect: boolean) => {
36
  if (disabled || !topPrediction) return;
@@ -42,7 +41,6 @@ export function FeedbackSection({
42
  } else {
43
  // Show correction form for incorrect predictions
44
  setFeedbackState('incorrect');
45
- setShowDropdown(true);
46
  }
47
  };
48
 
@@ -142,40 +140,25 @@ export function FeedbackSection({
142
  {/* Correction form */}
143
  {feedbackState === 'incorrect' && (
144
  <div className="space-y-3 pt-2 border-t border-border">
145
- {/* Label dropdown */}
146
- <div className="relative">
147
  <label className="block text-xs font-medium text-gray-600 mb-1.5">Correct Label</label>
148
- <button
149
- onClick={() => setShowDropdown(!showDropdown)}
150
- className="w-full flex items-center justify-between px-3 py-2.5 bg-white border border-gray-300 rounded-lg text-sm text-left hover:border-primary/50 focus:outline-none focus:ring-2 focus:ring-primary/20 transition-all"
 
151
  >
152
- <span className={correctLabel ? 'text-gray-800 font-medium' : 'text-gray-400'}>
153
- {correctLabel || 'Select correct view...'}
154
- </span>
155
- <ChevronDown className={`w-4 h-4 text-gray-400 transition-transform ${showDropdown ? 'rotate-180' : ''}`} />
156
- </button>
157
-
158
- {showDropdown && (
159
- <div className="absolute z-50 w-full mt-1 bg-white border border-gray-200 rounded-lg shadow-xl max-h-60 overflow-y-auto">
160
- {FETAL_VIEW_LABELS.map((label) => (
161
- <button
162
- key={label}
163
- onClick={() => {
164
- setCorrectLabel(label);
165
- setShowDropdown(false);
166
- }}
167
- className={`w-full px-3 py-2.5 text-sm text-left transition-colors border-b border-gray-100 last:border-b-0
168
- ${label === correctLabel ? 'bg-primary/10 text-primary font-medium' : 'text-gray-700 hover:bg-gray-50'}
169
- ${label === topPrediction?.label ? 'opacity-50 bg-gray-50' : ''}`}
170
- >
171
- {label}
172
- {label === topPrediction?.label && (
173
- <span className="text-xs text-gray-400 ml-2">(predicted)</span>
174
- )}
175
- </button>
176
- ))}
177
- </div>
178
- )}
179
  </div>
180
 
181
  {/* Notes input */}
@@ -184,34 +167,34 @@ export function FeedbackSection({
184
  <textarea
185
  value={notes}
186
  onChange={(e) => setNotes(e.target.value)}
187
- placeholder="Any additional notes about this case..."
188
- className="w-full px-3 py-2.5 bg-white border border-gray-300 rounded-lg text-sm text-gray-800 resize-none h-16 focus:outline-none focus:ring-2 focus:ring-primary/20 focus:border-primary/50 transition-all"
189
  />
190
  </div>
191
 
192
- {/* Submit button */}
193
- <div className="flex gap-2">
194
  <button
195
  onClick={() => {
196
  setFeedbackState('none');
197
  setCorrectLabel('');
198
  setNotes('');
199
  }}
200
- className="px-3 py-1.5 text-sm text-text-muted hover:text-text-primary transition-colors"
201
  >
202
  Cancel
203
  </button>
204
  <button
205
  onClick={handleSubmitCorrection}
206
  disabled={!correctLabel || isSubmitting}
207
- className="flex-1 flex items-center justify-center gap-2 px-3 py-1.5 bg-primary hover:bg-primary-hover text-white rounded-md text-sm font-medium disabled:opacity-50 disabled:cursor-not-allowed transition-colors"
208
  >
209
  {isSubmitting ? (
210
  <span>Submitting...</span>
211
  ) : (
212
  <>
213
  <Send className="w-3.5 h-3.5" />
214
- <span>Submit Correction</span>
215
  </>
216
  )}
217
  </button>
 
1
  import { useState } from 'react';
2
+ import { Check, X, Send, MessageSquare } from 'lucide-react';
3
  import { FETAL_VIEW_LABELS, submitFeedback, FeedbackCreate, ClassificationResult } from '../lib/api';
4
 
5
  interface FeedbackSectionProps {
 
30
  const [notes, setNotes] = useState<string>('');
31
  const [isSubmitting, setIsSubmitting] = useState(false);
32
  const [submitted, setSubmitted] = useState(false);
 
33
 
34
  const handleFeedback = async (isCorrect: boolean) => {
35
  if (disabled || !topPrediction) return;
 
41
  } else {
42
  // Show correction form for incorrect predictions
43
  setFeedbackState('incorrect');
 
44
  }
45
  };
46
 
 
140
  {/* Correction form */}
141
  {feedbackState === 'incorrect' && (
142
  <div className="space-y-3 pt-2 border-t border-border">
143
+ {/* Native select - handles viewport boundaries automatically */}
144
+ <div>
145
  <label className="block text-xs font-medium text-gray-600 mb-1.5">Correct Label</label>
146
+ <select
147
+ value={correctLabel}
148
+ onChange={(e) => setCorrectLabel(e.target.value)}
149
+ className="w-full px-3 py-2.5 bg-white border border-gray-300 rounded-lg text-sm text-gray-800 focus:outline-none focus:ring-2 focus:ring-primary/20 focus:border-primary/50 transition-all cursor-pointer"
150
  >
151
+ <option value="" disabled>Select correct view...</option>
152
+ {FETAL_VIEW_LABELS.map((label) => (
153
+ <option
154
+ key={label}
155
+ value={label}
156
+ disabled={label === topPrediction?.label}
157
+ >
158
+ {label}{label === topPrediction?.label ? ' (predicted)' : ''}
159
+ </option>
160
+ ))}
161
+ </select>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
162
  </div>
163
 
164
  {/* Notes input */}
 
167
  <textarea
168
  value={notes}
169
  onChange={(e) => setNotes(e.target.value)}
170
+ placeholder="Any additional notes..."
171
+ className="w-full px-3 py-2 bg-white border border-gray-300 rounded-lg text-sm text-gray-800 resize-none h-14 focus:outline-none focus:ring-2 focus:ring-primary/20 focus:border-primary/50 transition-all"
172
  />
173
  </div>
174
 
175
+ {/* Action buttons - inline */}
176
+ <div className="flex gap-2 items-center">
177
  <button
178
  onClick={() => {
179
  setFeedbackState('none');
180
  setCorrectLabel('');
181
  setNotes('');
182
  }}
183
+ className="px-4 py-2 text-sm text-gray-600 hover:text-gray-800 bg-gray-100 hover:bg-gray-200 rounded-lg transition-colors font-medium"
184
  >
185
  Cancel
186
  </button>
187
  <button
188
  onClick={handleSubmitCorrection}
189
  disabled={!correctLabel || isSubmitting}
190
+ className="flex-1 flex items-center justify-center gap-2 px-4 py-2 bg-primary hover:bg-primary-hover text-white rounded-lg text-sm font-medium disabled:opacity-50 disabled:cursor-not-allowed transition-colors"
191
  >
192
  {isSubmitting ? (
193
  <span>Submitting...</span>
194
  ) : (
195
  <>
196
  <Send className="w-3.5 h-3.5" />
197
+ <span>Submit</span>
198
  </>
199
  )}
200
  </button>