diff --git a/backend/prisma/schema.prisma b/backend/prisma/schema.prisma index f6db193..01a3299 100644 --- a/backend/prisma/schema.prisma +++ b/backend/prisma/schema.prisma @@ -2,7 +2,8 @@ // Database: PostgreSQL 15 generator client { - provider = "prisma-client-js" + provider = "prisma-client-js" + binaryTargets = ["native", "linux-musl-openssl-3.0.x"] } datasource db { diff --git a/backend/src/controllers/wsdc.js b/backend/src/controllers/wsdc.js index ba882f6..375ce3c 100644 --- a/backend/src/controllers/wsdc.js +++ b/backend/src/controllers/wsdc.js @@ -3,6 +3,7 @@ * Provides proxy endpoint for World Swing Dance Council (WSDC) dancer lookup */ +const { prisma } = require('../utils/db'); const WSDC_API_BASE = 'https://points.worldsdc.com/lookup2020/find'; /** @@ -61,9 +62,15 @@ exports.lookupDancer = async (req, res) => { dominateRole: data.dominate_data?.short_dominate_role || null }; + // Check if user with this WSDC ID already exists in our database + const existingUser = await prisma.user.findUnique({ + where: { wsdcId: String(data.dancer_wsdcid) } + }); + return res.status(200).json({ success: true, - dancer: dancerData + dancer: dancerData, + accountExists: !!existingUser }); } catch (error) { diff --git a/frontend/src/pages/RegisterPage.jsx b/frontend/src/pages/RegisterPage.jsx index 6837280..4691020 100644 --- a/frontend/src/pages/RegisterPage.jsx +++ b/frontend/src/pages/RegisterPage.jsx @@ -1,8 +1,8 @@ -import { useState } from 'react'; +import { useState, useEffect } from 'react'; import { useNavigate, Link } from 'react-router-dom'; import { useAuth } from '../contexts/AuthContext'; import { wsdcAPI } from '../services/api'; -import { Video, Mail, Lock, User, Hash, ArrowRight, ArrowLeft, Loader2 } from 'lucide-react'; +import { Video, Mail, Lock, User, Hash, ArrowRight, ArrowLeft, Loader2, CheckCircle, XCircle, AlertCircle } from 'lucide-react'; import PasswordStrengthIndicator from '../components/common/PasswordStrengthIndicator'; const RegisterPage = () => { @@ -13,6 +13,8 @@ const RegisterPage = () => { const [hasWsdcId, setHasWsdcId] = useState(null); const [wsdcId, setWsdcId] = useState(''); const [wsdcData, setWsdcData] = useState(null); + const [wsdcPreview, setWsdcPreview] = useState(null); // Preview data after 4+ digits + const [accountExists, setAccountExists] = useState(false); // Check if account exists const [wsdcLoading, setWsdcLoading] = useState(false); const [wsdcError, setWsdcError] = useState(''); @@ -31,35 +33,68 @@ const RegisterPage = () => { const { register } = useAuth(); const navigate = useNavigate(); - // Handle WSDC ID lookup - const handleWsdcLookup = async () => { - if (!wsdcId || wsdcId.trim() === '') { - setWsdcError('Please enter your WSDC ID'); + // Auto-lookup WSDC ID after 4+ digits are entered + useEffect(() => { + const lookupWsdcId = async () => { + if (wsdcId.length >= 4 && /^\d+$/.test(wsdcId)) { + setWsdcLoading(true); + setWsdcError(''); + setWsdcPreview(null); + setAccountExists(false); + + try { + const response = await wsdcAPI.lookupDancer(wsdcId); + + if (response.success && response.dancer) { + setWsdcPreview(response.dancer); + setAccountExists(response.accountExists || false); + + if (!response.accountExists) { + setWsdcError(''); + } + } + } catch (err) { + setWsdcPreview(null); + setAccountExists(false); + if (err.status === 404) { + setWsdcError('WSDC ID not found in the registry'); + } else { + setWsdcError(''); + } + } finally { + setWsdcLoading(false); + } + } else { + setWsdcPreview(null); + setAccountExists(false); + setWsdcError(''); + } + }; + + const timeoutId = setTimeout(lookupWsdcId, 500); // Debounce 500ms + return () => clearTimeout(timeoutId); + }, [wsdcId]); + + // Handle WSDC ID confirmation and continue to registration + const handleWsdcContinue = () => { + if (!wsdcPreview) { + setWsdcError('Please enter a valid WSDC ID'); return; } - setWsdcLoading(true); - setWsdcError(''); - - try { - const response = await wsdcAPI.lookupDancer(wsdcId); - - if (response.success && response.dancer) { - setWsdcData(response.dancer); - setFormData(prev => ({ - ...prev, - firstName: response.dancer.firstName, - lastName: response.dancer.lastName, - })); - setStep(2); - } else { - setWsdcError('WSDC ID not found. Please check and try again.'); - } - } catch (err) { - setWsdcError(err.data?.message || 'Failed to lookup WSDC ID. Please try again.'); - } finally { - setWsdcLoading(false); + if (accountExists) { + setWsdcError('An account with this WSDC ID already exists'); + return; } + + // Set data and move to registration form + setWsdcData(wsdcPreview); + setFormData(prev => ({ + ...prev, + firstName: wsdcPreview.firstName, + lastName: wsdcPreview.lastName, + })); + setStep(2); }; // Handle "No WSDC ID" option @@ -158,39 +193,84 @@ const RegisterPage = () => { setWsdcId(e.target.value)} + onChange={(e) => setWsdcId(e.target.value.replace(/\D/g, ''))} className="pl-10 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:ring-primary-500 focus:border-primary-500" placeholder="26997" - disabled={wsdcLoading} + maxLength={10} /> + {wsdcLoading && ( +
+ +
+ )} - {wsdcError && ( -

{wsdcError}

+ + {/* Preview dropdown - shows after 4 digits */} + {wsdcId.length >= 4 && wsdcPreview && !wsdcLoading && ( +
+
+
+
+ + Dancer found +
+
+

WSDC ID: {wsdcPreview.wsdcId}

+

Name: {wsdcPreview.firstName} {wsdcPreview.lastName}

+
+
+
+ + {accountExists && ( +
+ +
+

Account already exists

+

+ An account with this WSDC ID is already registered. + Sign in instead +

+
+
+ )} + + {!accountExists && ( +
+ +

+ Looks good! Click Continue to proceed. +

+
+ )} +
+ )} + + {wsdcError && !wsdcPreview && ( +
+ +

{wsdcError}

+
)}