From 34f00378a62a98b5e02ca628dda8730302df6d8c Mon Sep 17 00:00:00 2001 From: NoamElisha Date: Mon, 13 Oct 2025 17:51:41 +0300 Subject: [PATCH 1/2] divie between register to sort day and regesteration to the website --- src/App.js | 2 +- src/config/firebase-config.js | 16 +- src/data/index.js | 19 +- src/hooks/useSheets.jsx | 27 +- src/lib/auth/pages/SignUpPage/SignUpPage.jsx | 400 ++++++++++-------- src/lib/landing/LandingRouter.jsx | 5 +- .../components/ProjectCard/ProjectCard.js | 11 +- src/lib/landing/pages/HomePage/SectionOne.jsx | 2 +- .../TryoutRegistration/TryoutRegistration.jsx | 146 +++++++ .../TryoutRegistration/TryoutSuccess.jsx | 41 ++ src/ui/Navbar/MobileNavbar.js | 52 ++- src/utils/index.js | 100 ++++- src/utils/tryoutValidation.js | 61 +++ 13 files changed, 628 insertions(+), 254 deletions(-) create mode 100644 src/lib/landing/pages/TryoutRegistration/TryoutRegistration.jsx create mode 100644 src/lib/landing/pages/TryoutRegistration/TryoutSuccess.jsx create mode 100644 src/utils/tryoutValidation.js diff --git a/src/App.js b/src/App.js index 82caa1c..69d6939 100644 --- a/src/App.js +++ b/src/App.js @@ -9,7 +9,7 @@ import { ToastContainer } from 'react-toastify'; import 'react-toastify/dist/ReactToastify.css'; const queryClient = new QueryClient(); -const manage = true; +const manage = false; const App = () => { return ( diff --git a/src/config/firebase-config.js b/src/config/firebase-config.js index 1181cf4..7538396 100644 --- a/src/config/firebase-config.js +++ b/src/config/firebase-config.js @@ -1,13 +1,13 @@ import { initializeApp } from 'firebase/app'; -import { getAnalytics } from 'firebase/analytics'; -import { getFirestore } from '@firebase/firestore'; +import { getAnalytics, isSupported } from 'firebase/analytics'; +import { getFirestore } from 'firebase/firestore'; import { getStorage } from 'firebase/storage'; import { getAuth, FacebookAuthProvider } from 'firebase/auth'; const firebaseConfig = { apiKey: process.env.REACT_APP_API_KEY, authDomain: process.env.REACT_APP_AUTH_DOMAIN, - databaseURL: process.env.REACT_APP_DATABASE_URL, + databaseURL: process.env.REACT_APP_DATABASE_URL, projectId: process.env.REACT_APP_PROJECT_ID, storageBucket: process.env.REACT_APP_STORAGE_BUCKET, messagingSenderId: process.env.REACT_APP_MESSAGING_SENDERID, @@ -16,7 +16,15 @@ const firebaseConfig = { }; const app = initializeApp(firebaseConfig); -export const analytics = getAnalytics(app); + + +export let analytics; +if (typeof window !== 'undefined') { + isSupported().then((ok) => { + if (ok) analytics = getAnalytics(app); + }); +} + export const db = getFirestore(app); export const storage = getStorage(app); export const auth = getAuth(app); diff --git a/src/data/index.js b/src/data/index.js index 94cecc4..ae989ac 100644 --- a/src/data/index.js +++ b/src/data/index.js @@ -1,5 +1,4 @@ -import { emailValidation, idValidation, experienceValidation, numberValidation, selectionValidation, stringValidation } from '../utils'; - +import { emailValidation, idValidation, experienceValidation, numberValidation, selectionValidation, stringValidation, passwordValidation } from '../utils'; export const labels = [ { @@ -23,13 +22,13 @@ export const labels = [ key: 'id', validator: idValidation, }, - // { - // label: "Password", - // type: "TextField", - // showInput: "false", - // key: "password", - // validator: passwordValidation, - // }, + { + label: "Password", + type: "TextField", + showInput: "false", + key: "password", + validator: passwordValidation, + }, { label: 'Phone Number', type: 'TextField', @@ -96,5 +95,5 @@ export const errorMessages = { phoneNumber: 'Phone number must contain 10 digits', email: 'Email is not valid', fullName: 'Must be in English! min 3 characters', - // password: "Password must contain atleast 6 chars.", + password: "Password must contain atleast 6 chars.", }; diff --git a/src/hooks/useSheets.jsx b/src/hooks/useSheets.jsx index aa43666..9756111 100644 --- a/src/hooks/useSheets.jsx +++ b/src/hooks/useSheets.jsx @@ -7,21 +7,36 @@ const fetchDataFromCsv = async () => { ); if (!response.ok) { - throw new Error('Failed to fetch data from Google Sheets'); + throw new Error('Failed to fetch data from Google Sheets. status=' + response.status); } const csvData = await response.text(); - const parsedData = parseCsv(csvData); - return parsedData; - } catch (error) {} + const parsed = parseCsv(csvData); + console.log('[useSheets] parsed rows:', parsed.length, parsed.slice(0, 3)); + return parsed; + } catch (error) { + console.error('[useSheets] fetch failed:', error); + return []; + } }; const parseCsv = (csvData) => { - return csvData.split('\n').map((row) => row.split(/","/)); + return csvData + .replace(/\r/g, '') + .split('\n') + .map((row) => row.replace(/^"?|"?$/g, '')) + .filter((row) => row.trim() !== '') + .map((row) => row.split(/","/).map((cell) => cell.trim())); }; + const useGoogleSheetsData = () => { - return useQuery({queryKey:'googleSheetsData',queryFn: fetchDataFromCsv}); + return useQuery({ + queryKey: ['googleSheetsData'], + queryFn: fetchDataFromCsv, + refetchOnWindowFocus: false, + staleTime: 5 * 60 * 1000, + }); }; export default useGoogleSheetsData; diff --git a/src/lib/auth/pages/SignUpPage/SignUpPage.jsx b/src/lib/auth/pages/SignUpPage/SignUpPage.jsx index bcbb9a4..e702694 100644 --- a/src/lib/auth/pages/SignUpPage/SignUpPage.jsx +++ b/src/lib/auth/pages/SignUpPage/SignUpPage.jsx @@ -1,5 +1,5 @@ import * as React from 'react'; -import { useNavigate } from 'react-router'; +import { useNavigate } from 'react-router-dom'; import { Box, Checkbox, Container, Grid, Typography } from '@mui/material'; import css from './style.module.css'; import FormInputField from 'src/ui/FormInputField'; @@ -11,6 +11,10 @@ import SignUpMethod from './components/SignUpMethod'; import Avatar from '@mui/material/Avatar'; import { useCreateUser } from 'src/hooks/firebase.hooks'; +// ✅ ייבוא ישיר לבדיקה יעילה ב-Firestore +import { collection, getDocs, query, where, limit } from 'firebase/firestore'; +import { db } from 'src/config/firebase-config'; + const FIELDS_MAP = { TextField: FormInputField, Select: FormSelectField, @@ -28,7 +32,10 @@ const SignUpPage = () => { const [email, setEmail] = React.useState(''); const [name, setName] = React.useState(''); + const createUser = useCreateUser(); + const onSignupHandler = async () => { + const validationState = labels.reduce((obj, { key, validator }) => { obj[key] = !validator(formValues[key]); return obj; @@ -37,23 +44,46 @@ const SignUpPage = () => { setValidationErrors(validationState); if (Object.keys(validationState).length === 0) return; + for (const key in validationState) { + if (key === 'experienceDetails' && formValues['experience'] !== 'כן') { validationState[key] = validationState['experience']; } + if (validationErrors[key]) return; + } + + if (!rules) return; + + try { + const emailToCheck = String(formValues.email || '').trim().toLowerCase(); + if (!emailToCheck) return; - if (validationState[key]) { + const q = query( + collection(db, 'users'), + where('email', '==', emailToCheck), + limit(1) + ); + const snap = await getDocs(q); + if (!snap.empty) { + alert('משתמש קיים במערכת'); + navigate('/'); return; } - } - if (!rules) return; - if ((await fetchData('users')).find((user) => user.formValues?.email === formValues['email'])) { - alert('משתמש קיים במערכת'); - navigate('/'); + } catch (e) { + console.error('[SignUpPage] email duplicate check failed:', e); + return; } + + setOpenModal(true); - const newUser = { ...formValues, date: new Date().toLocaleDateString() }; + const newUser = { + ...formValues, + email: String(formValues.email || '').trim().toLowerCase(), + date: new Date().toLocaleDateString(), + profilePic: profilePic || null, + }; createUser.mutate(newUser); }; @@ -67,9 +97,7 @@ const SignUpPage = () => { const handleUploadClick = (event) => { const file = event.target.files[0]; - if (file) { - setProfilePic(file); - } + if (file) setProfilePic(file); }; const goHome = () => { @@ -81,11 +109,7 @@ const SignUpPage = () => { { > Submit Application + +
- {!methodClicked && } + {!methodClicked && ( + + )}
+
- {methodClicked && (<> - - - - - - Upload Image - - - + {methodClicked && ( + <> + + + + + Upload Image + + + - {labels.map(({ type, label, key, options, validator }, index) => { - const FieldComponent = FIELDS_MAP[type]; - return label === 'Experience Details' && formValues['experience'] !== 'כן' ? null : ( - - + {labels.map(({ type, label, key, options, validator }, index) => { + const FieldComponent = FIELDS_MAP[type]; + if (label === 'Experience Details' && formValues['experience'] !== 'כן') { + return null; + } + return ( + - { - setFormValues((prev) => { - return { ...prev, [key]: event.target.value }; - }); - inputHandler(validator, key, event.target.value); + marginBottom: { xs: '0.75rem' }, }} - error={validationErrors[key]} - /> - + > + { + setFormValues((prev) => ({ ...prev, [key]: event.target.value })); + inputHandler(validator, key, event.target.value); + }} + error={validationErrors[key]} + /> + + + {validationErrors[key] ? errorMessages[key] : ''} + + + ); + })} + + + {/* מודל הצלחה */} + + + - {validationErrors[key] ? errorMessages[key] : ''} + מוזמנים להצטרף לקבוצת הוואטספ שלנו - - ); - })} - - - - - - מוזמנים להצטרף לקבוצת הוואטספ שלנו - - + לחץ כאן + + + + + setOpenRulesModal(false)} > - לחץ כאן - - +
    + {allRules.map((rule) => ( +
  • {rule}
  • + ))} +
+ +
- setOpenRulesModal(false)} - > -
    - {allRules.map((rule) => { - return
  • {rule}
  • ; - })} -
+ -
- - { - setRules((prev) => !prev); - setOpenRulesModal(false); + marginBottom: '30px', }} - sx={{ color: 'white' }} - /> - - אני מאשר\ת את תנאי{' '} - setOpenRulesModal((prev) => !prev)}> - התקנון - - - - {rules && ( -
- - Submit - -
- ) - } + > + { + setRules((prev) => !prev); + setOpenRulesModal(false); + }} + sx={{ color: 'white' }} + /> + + אני מאשר\ת את תנאי{' '} + setOpenRulesModal((prev) => !prev)}> + התקנון + + + + + + {rules && ( +
+ + Submit + +
+ )} +
- - - )} + + + )}
diff --git a/src/lib/landing/LandingRouter.jsx b/src/lib/landing/LandingRouter.jsx index 3984c04..53f9043 100644 --- a/src/lib/landing/LandingRouter.jsx +++ b/src/lib/landing/LandingRouter.jsx @@ -8,7 +8,8 @@ import { Footer } from './components'; import { SignInPage, SignUpPage } from '../auth/pages'; import { AuthContextProvider } from '../auth/authContext'; // import ProtectedRoute from 'src/utils/protectedRoutes'; - +import TryoutRegistrationPage from './pages/TryoutRegistration/TryoutRegistration'; +import TryoutSuccess from './pages/TryoutRegistration/TryoutSuccess'; const LandingRouter = () => { return ( @@ -23,6 +24,8 @@ const LandingRouter = () => { } /> } /> } /> + } /> + } />