Ryan Christian D. Deniega commited on
Commit
ed3755c
Β·
1 Parent(s): 7ba7fea

fix(frontend): block social URL preview + better error card for social URLs

Browse files
Files changed (1) hide show
  1. frontend/src/pages/VerifyPage.jsx +37 -10
frontend/src/pages/VerifyPage.jsx CHANGED
@@ -271,6 +271,8 @@ export default function VerifyPage() {
271
  useEffect(() => {
272
  if (tab !== 'url' || !input.trim()) { setUrlPreview(null); setUrlPreviewLoading(false); return }
273
  try { new URL(input.trim()) } catch { setUrlPreview(null); setUrlPreviewLoading(false); return }
 
 
274
  setUrlPreviewLoading(true)
275
  const timer = setTimeout(async () => {
276
  try {
@@ -287,9 +289,23 @@ export default function VerifyPage() {
287
 
288
  const canSubmit = !loading && (tab === 'text' || tab === 'url' ? input.trim() : file)
289
 
 
 
 
 
 
 
 
290
  async function handleSubmit(e) {
291
  e.preventDefault()
292
  if (!canSubmit) return
 
 
 
 
 
 
 
293
  /* Capture what the user submitted before any state resets */
294
  const previewUrl = (tab === 'image' || tab === 'video') && file
295
  ? URL.createObjectURL(file)
@@ -598,18 +614,29 @@ export default function VerifyPage() {
598
  {error && (
599
  <div id={errorId} role="alert"
600
  className="card p-4 flex items-start gap-2"
601
- style={{ borderColor: 'rgba(220,38,38,0.4)' }}>
602
- <AlertCircle size={15} style={{ color: '#f87171', marginTop: 1, flexShrink: 0 }} aria-hidden="true" />
603
  <div>
604
- <p className="text-sm font-semibold" style={{ color: '#f87171', fontFamily: 'var(--font-display)' }}>
605
- Verification failed
606
- </p>
607
- <p className="text-xs mt-0.5" style={{ color: 'var(--text-secondary)', fontFamily: 'var(--font-body)' }}>
608
- {error}
609
- {/failed to fetch|network|ERR_/i.test(error) && (
610
- <> β€” Make sure the backend is running at <code>localhost:8000</code>.</>
611
- )}
612
  </p>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
613
  </div>
614
  </div>
615
  )}
 
271
  useEffect(() => {
272
  if (tab !== 'url' || !input.trim()) { setUrlPreview(null); setUrlPreviewLoading(false); return }
273
  try { new URL(input.trim()) } catch { setUrlPreview(null); setUrlPreviewLoading(false); return }
274
+ // Don't attempt to preview social media URLs β€” they're login-protected
275
+ if (isSocialUrl(input.trim())) { setUrlPreview(null); setUrlPreviewLoading(false); return }
276
  setUrlPreviewLoading(true)
277
  const timer = setTimeout(async () => {
278
  try {
 
289
 
290
  const canSubmit = !loading && (tab === 'text' || tab === 'url' ? input.trim() : file)
291
 
292
+ function isSocialUrl(s) {
293
+ try {
294
+ const h = new URL(s).hostname
295
+ return h.includes('facebook.com') || h.includes('x.com') || h.includes('twitter.com')
296
+ } catch { return false }
297
+ }
298
+
299
  async function handleSubmit(e) {
300
  e.preventDefault()
301
  if (!canSubmit) return
302
+
303
+ /* Block social media URLs β€” backend can't scrape them */
304
+ if (tab === 'url' && isSocialUrl(input)) {
305
+ setError('Facebook, X, and Twitter URLs cannot be scraped β€” the page is login-protected.\n\nInstead: copy the post\'s text/caption and paste it into the Text tab.')
306
+ return
307
+ }
308
+
309
  /* Capture what the user submitted before any state resets */
310
  const previewUrl = (tab === 'image' || tab === 'video') && file
311
  ? URL.createObjectURL(file)
 
614
  {error && (
615
  <div id={errorId} role="alert"
616
  className="card p-4 flex items-start gap-2"
617
+ style={{ borderColor: isSocialUrl(input) ? 'rgba(220,150,38,0.4)' : 'rgba(220,38,38,0.4)' }}>
618
+ <AlertCircle size={15} style={{ color: isSocialUrl(input) ? '#fb923c' : '#f87171', marginTop: 1, flexShrink: 0 }} aria-hidden="true" />
619
  <div>
620
+ <p className="text-sm font-semibold" style={{ color: isSocialUrl(input) ? '#fb923c' : '#f87171', fontFamily: 'var(--font-display)' }}>
621
+ {isSocialUrl(input) ? 'Social media URLs are not supported' : 'Verification failed'}
 
 
 
 
 
 
622
  </p>
623
+ {isSocialUrl(input) ? (
624
+ <>
625
+ <p className="text-xs mt-1" style={{ color: 'var(--text-secondary)', fontFamily: 'var(--font-body)' }}>
626
+ Facebook, X, and Twitter block server-side scraping β€” the page requires a login.
627
+ </p>
628
+ <p className="text-xs mt-1.5 font-semibold" style={{ color: 'var(--text-primary)', fontFamily: 'var(--font-body)' }}>
629
+ Instead: copy the post caption/text and paste it into the <strong>Text</strong> tab.
630
+ </p>
631
+ </>
632
+ ) : (
633
+ <p className="text-xs mt-0.5" style={{ color: 'var(--text-secondary)', fontFamily: 'var(--font-body)' }}>
634
+ {error}
635
+ {/failed to fetch|network|ERR_/i.test(error) && (
636
+ <> β€” Make sure the backend is running at <code>localhost:8000</code>.</>
637
+ )}
638
+ </p>
639
+ )}
640
  </div>
641
  </div>
642
  )}