diff --git a/package-lock.json b/package-lock.json index 32f6cb3..38595b1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,7 @@ "version": "0.1.0", "dependencies": { "firebase": "^11.0.2", - "next": "^14.0.0", + "next": "^14.2.18", "react": "^18.2.0", "react-dom": "^18.2.0" }, diff --git a/package.json b/package.json index 033ebd4..6ed7ef5 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,7 @@ "@mui/material": "^6.1.8", "@mui/material-nextjs": "^6.1.8", "firebase": "^11.0.2", - "next": "^14.0.0", + "next": "^14.2.18", "react": "^18.2.0", "react-dom": "^18.2.0" }, diff --git a/src/app/admin/page.tsx b/src/app/admin/page.tsx new file mode 100644 index 0000000..bb3235d --- /dev/null +++ b/src/app/admin/page.tsx @@ -0,0 +1,7 @@ +export default function dashboard() { + return ( +
+

Admin Dashboard

+
+ ); +} diff --git a/src/app/api/users/route.ts b/src/app/api/users/route.ts new file mode 100644 index 0000000..1ef587e --- /dev/null +++ b/src/app/api/users/route.ts @@ -0,0 +1,30 @@ +import { NextRequest, NextResponse } from 'next/server'; +import firebase_app from '@/firebase/config'; +import { getFirestore, addDoc, collection } from 'firebase/firestore'; + +const db = getFirestore(firebase_app); + +//POST request for creating an Admin user + +export async function POST(request: NextRequest) { + try { + const requestData = await request.json(); + + const newAdminRef = await addDoc(collection(db, 'admins'), { + name: { + first: requestData.name.first, + last: requestData.name.last, + }, + email: requestData.email, + role: requestData.role, + school_district: requestData.school_district, + }); + + return NextResponse.json({ + message: 'Admin user created successfully', + userId: newAdminRef.id, + }); + } catch { + //error checking to do + } +} diff --git a/src/app/login/eo-admin/page.tsx b/src/app/login/eo-admin/page.tsx new file mode 100644 index 0000000..0e722be --- /dev/null +++ b/src/app/login/eo-admin/page.tsx @@ -0,0 +1,75 @@ +'use client'; +import {useState} from 'react'; +import signIn from '@/firebase/auth/signIn'; +import { doc, getDoc } from 'firebase/firestore'; +import { getFirestore } from 'firebase/firestore'; +import { getAuth } from 'firebase/auth'; + +const EOAdminLogin = () => { + const [email, setEmail] = useState(''); + const [password, setPassword] = useState(''); + const [error, setError] = useState(''); + const [success, setSuccess] = useState(false); + + const handleSubmit = async (event: React.FormEvent) => { + event.preventDefault(); + const { result, error } = await signIn(email, password); + if (error) { + setError(error.message); + } else { + const auth = getAuth(); + const db = getFirestore(); + const user = auth.currentUser; + + if (user) { + const userDoc = await getDoc(doc(db, 'users', user.uid)); + if (userDoc.exists()) { + const role = userDoc.data().role; + console.log('Role:', role); + + if (role === 'eo-admin') { + setSuccess(true); + console.log('EO Admin signed in successfully:', result?.user); + } else { + setError('Unauthorized access: Not an EO admin.'); + } + } else { + setError('User data not found in Firestore.'); + } + } + } + }; + + return ( +
+

End Overdose Admin Login

+ {error &&

{error}

} + {success && ( +

EO Admin Signup successful!

+ )} +
+ + setEmail(e.target.value)} + required + /> +
+ + setPassword(e.target.value)} + required + /> +
+ +
+
+ ); +} + +export default EOAdminLogin; \ No newline at end of file diff --git a/src/app/login/page.tsx b/src/app/login/page.tsx new file mode 100644 index 0000000..b644563 --- /dev/null +++ b/src/app/login/page.tsx @@ -0,0 +1,21 @@ +'use client'; +import Link from 'next/link'; + +const LoginPage = () => { + return ( +
+

Login

+ + + + + + + + + +
+ ); +}; + +export default LoginPage; diff --git a/src/app/login/school-admin/page.tsx b/src/app/login/school-admin/page.tsx new file mode 100644 index 0000000..2e4ec9c --- /dev/null +++ b/src/app/login/school-admin/page.tsx @@ -0,0 +1,77 @@ +'use client'; +import {useState} from 'react'; +import signIn from '@/firebase/auth/signIn'; +import { doc, getDoc } from 'firebase/firestore'; +import { getFirestore } from 'firebase/firestore'; +import { getAuth } from 'firebase/auth'; + +const SchoolAdminLogin = () => { + const [email, setEmail] = useState(''); + const [password, setPassword] = useState(''); + const [error, setError] = useState(''); + const [success, setSuccess] = useState(false); + + const handleSubmit = async (event: React.FormEvent) => { + event.preventDefault(); + const { result, error } = await signIn(email, password); + if (error) { + setError(error.message); + } else { + const auth = getAuth(); + const db = getFirestore(); + const user = auth.currentUser; + + if (user) { + const userDoc = await getDoc(doc(db, 'users', user.uid)); + if (userDoc.exists()) { + const role = userDoc.data().role; + console.log('Role:', role); + + if (role === 'school-admin') { + setSuccess(true); + console.log('School Admin signed in successfully:', result?.user); + } else { + setError('Unauthorized access: Not a school admin.'); + } + } else { + setError('User data not found in Firestore.'); + } + } + } + }; + + return ( +
+

School Admin Login

+ {error &&

{error}

} + {success && ( +

+ School Admin Signup successful! +

+ )} +
+ + setEmail(e.target.value)} + required + /> +
+ + setPassword(e.target.value)} + required + /> +
+ +
+
+ ); +} + +export default SchoolAdminLogin; diff --git a/src/app/login/students/page.tsx b/src/app/login/students/page.tsx new file mode 100644 index 0000000..8341cf6 --- /dev/null +++ b/src/app/login/students/page.tsx @@ -0,0 +1,42 @@ +'use client'; +import {useState} from 'react'; + +const StudentLogin = () => { + const [schoolId, setSchoolId] = useState(''); + const [schoolName, setSchoolName] = useState(''); + + const handleSubmit = async (event: React.FormEvent) => { + event.preventDefault(); + console.log('Logging in as Student:', {schoolId, schoolName}); + //call the firebase sign-in function here + }; + + return ( +
+

Student Login

+
+ + setSchoolId(e.target.value)} + required + /> +
+ + setSchoolName(e.target.value)} + required + /> +
+ +
+
+ ); +} + +export default StudentLogin; \ No newline at end of file diff --git a/src/app/signup/eo-admin/page.tsx b/src/app/signup/eo-admin/page.tsx new file mode 100644 index 0000000..1fc249a --- /dev/null +++ b/src/app/signup/eo-admin/page.tsx @@ -0,0 +1,100 @@ +'use client'; +import { useState } from 'react'; +import signUp from '@/firebase/auth/signUp'; +import { doc, setDoc } from 'firebase/firestore'; +import { getFirestore } from 'firebase/firestore'; + +const EOAdminSignup = () => { + const [name, setName] = useState(''); + const [email, setEmail] = useState(''); + const [password, setPassword] = useState(''); + const [confirmPassword, setConfirmPassword] = useState(''); + const [error, setError] = useState(''); + const [success, setSuccess] = useState(false); + + const handleSubmit = async (event: React.FormEvent) => { + event.preventDefault(); + + // Check if passwords match + if (password !== confirmPassword) { + setError('Passwords do not match.'); + return; + } + + const { result, error } = await signUp(email, password); + if (error) { + setError(error.message); + } else { + try { + const db = getFirestore(); + //save user role in Firestore + if (result?.user?.uid) { + await setDoc(doc(db, 'users', result.user.uid), { + name, + email, + role: 'eo-admin', // Assign the role + }); + } else { + setError('Failed to retrieve user ID. Please try again.'); + console.error('No user ID found in the result.'); + } + setSuccess(true); + console.log('EO Admin signed up successfully:', result?.user); + } catch (e) { + setError('Failed to save user role. Please try again.'); + console.error(e); + } + } + }; + + return ( +
+

End Overdose Admin Signup

+ {error &&

{error}

} + {success && ( +

EO Admin Signup successful!

+ )} +
+ + setName(e.target.value)} + required + /> +
+ + setEmail(e.target.value)} + required + /> +
+ + setPassword(e.target.value)} + required + /> +
+ + setConfirmPassword(e.target.value)} + required + /> +
+ +
+
+ ); +}; + +export default EOAdminSignup; diff --git a/src/app/signup/page.tsx b/src/app/signup/page.tsx new file mode 100644 index 0000000..a820e89 --- /dev/null +++ b/src/app/signup/page.tsx @@ -0,0 +1,21 @@ +'use client'; +import Link from 'next/link'; + +const SignupPage = () => { + return ( +
+

Signup

+ + + + + + + + + +
+ ); +}; + +export default SignupPage; diff --git a/src/app/signup/school-admin/page.tsx b/src/app/signup/school-admin/page.tsx new file mode 100644 index 0000000..7adec3b --- /dev/null +++ b/src/app/signup/school-admin/page.tsx @@ -0,0 +1,102 @@ +'use client'; +import { useState } from 'react'; +import signUp from '@/firebase/auth/signUp'; +import { doc, setDoc } from 'firebase/firestore'; +import { getFirestore } from 'firebase/firestore'; + +const SchoolAdminSignup = () => { + const [name, setName] = useState(''); + const [email, setEmail] = useState(''); + const [password, setPassword] = useState(''); + const [confirmPassword, setConfirmPassword] = useState(''); + const [error, setError] = useState(''); + const [success, setSuccess] = useState(false); + + const handleSubmit = async (event: React.FormEvent) => { + event.preventDefault(); + + // Check if passwords match + if (password !== confirmPassword) { + setError('Passwords do not match.'); + return; + } + + const { result, error } = await signUp(email, password); + if (error) { + setError(error.message); + } else { + try { + const db = getFirestore(); + //save user role in Firestore + if (result?.user?.uid) { + await setDoc(doc(db, 'users', result.user.uid), { + name, + email, + role: 'school-admin', // Assign the role + }); + } else { + setError('Failed to retrieve user ID. Please try again.'); + console.error('No user ID found in the result.'); + } + setSuccess(true); + console.log('School Admin signed up successfully:', result?.user); + } catch (e) { + setError('Failed to save user role. Please try again.'); + console.error(e); + } + } + }; + + return ( +
+

School Admin Signup

+ {error &&

{error}

} + {success && ( +

+ School Admin Signup successful! +

+ )} +
+ + setName(e.target.value)} + required + /> +
+ + setEmail(e.target.value)} + required + /> +
+ + setPassword(e.target.value)} + required + /> +
+ + setConfirmPassword(e.target.value)} + required + /> +
+ +
+
+ ); +}; + +export default SchoolAdminSignup; diff --git a/src/firebase/auth/logout.ts b/src/firebase/auth/logout.ts new file mode 100644 index 0000000..e4a6c54 --- /dev/null +++ b/src/firebase/auth/logout.ts @@ -0,0 +1,13 @@ +import firebase_app from '@/firebase/config'; +import { getAuth, signOut } from 'firebase/auth'; + +const auth = getAuth(firebase_app); + +export default async function logout(): Promise<{ error: Error | null }> { + try { + await signOut(auth); + return { error: null }; + } catch (error) { + return { error: error as Error }; + } +} diff --git a/src/firebase/auth/signIn.ts b/src/firebase/auth/signIn.ts new file mode 100644 index 0000000..9b93505 --- /dev/null +++ b/src/firebase/auth/signIn.ts @@ -0,0 +1,20 @@ +import firebase_app from '@/firebase/config'; +import { + getAuth, + signInWithEmailAndPassword, + UserCredential, +} from 'firebase/auth'; + +const auth = getAuth(firebase_app); + +export default async function signIn( + email: string, + password: string +): Promise<{ result: UserCredential | null; error: Error | null }> { + try { + const result = await signInWithEmailAndPassword(auth, email, password); + return { result, error: null }; + } catch (error) { + return { result: null, error: error as Error }; + } +} diff --git a/src/firebase/auth/signUp.ts b/src/firebase/auth/signUp.ts new file mode 100644 index 0000000..cc455cf --- /dev/null +++ b/src/firebase/auth/signUp.ts @@ -0,0 +1,24 @@ +import firebase_app from '@/firebase/config'; +import { + getAuth, + createUserWithEmailAndPassword, + UserCredential, +} from 'firebase/auth'; + +const auth = getAuth(firebase_app); + +export default async function signUp( + email: string, + password: string +): Promise<{ result: UserCredential | null; error: Error | null }> { + try { + const result = await createUserWithEmailAndPassword( + auth, + email, + password + ); + return { result, error: null }; + } catch (error) { + return { result: null, error: error as Error }; + } +}