Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Firebase Authentication -- Login + Sign Up Pages #38

Open
wants to merge 28 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
43a7af2
firebase auth config
meganleongg Apr 5, 2024
289e6a5
login frontend
meganleongg Apr 8, 2024
3f929e0
login button styling + search icon
meganleongg Apr 8, 2024
117b5d9
sign up page + auth log in works now
meganleongg Apr 16, 2024
8d2b455
sign up requires email invite + formatted error messages
meganleongg Apr 21, 2024
8dc59d1
can add admins from website
meganleongg Apr 30, 2024
c66638f
adjustable for smaller screen sizes
meganleongg May 7, 2024
7bc712d
merge
meganleongg May 7, 2024
11df264
merge
meganleongg May 7, 2024
bb7ca49
added persisting login logic to remember user
meganleongg May 7, 2024
9876b35
package
meganleongg May 7, 2024
e256843
Merge branch 'main' of https://github.com/TritonSE/DFM-Sideline-Sidek…
meganleongg May 7, 2024
96f6d81
added nav bars to layout
meganleongg May 7, 2024
3139938
added nav bars to layout
meganleongg May 7, 2024
b328044
added nav bars to layout
meganleongg May 7, 2024
9f68712
added nav bars to layout
meganleongg May 7, 2024
69ca44b
commented out nav bars
meganleongg May 15, 2024
c0de51d
add a new admin pop up form
meganleongg May 15, 2024
ded7323
Merge branch 'main' into login
Anthonyp0329 May 17, 2024
3ef926d
linting fixes
Anthonyp0329 May 17, 2024
49ca384
admin cards view, connected to firebase
meganleongg May 20, 2024
49dbc36
Merge branch 'login' of https://github.com/TritonSE/DFM-Sideline-Side…
meganleongg May 20, 2024
c3483e7
forgot password page
meganleongg May 28, 2024
f2a4087
merging main
Anthonyp0329 Jun 4, 2024
c50601b
merging main pt2
Anthonyp0329 Jun 4, 2024
ba74db1
finished designs for forgot password frontend
meganleongg Jun 4, 2024
3c8a03c
Merge branch 'main' into login
Anthonyp0329 Jun 4, 2024
081caab
package.json fixes
Anthonyp0329 Jun 4, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions admin-portal-frontend/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,5 @@ yarn-error.log*
# typescript
*.tsbuildinfo
next-env.d.ts

dfm-sideline-sidekick-app-firebase-adminsdk-mqgtq-32d66e30cf.json
957 changes: 945 additions & 12 deletions admin-portal-frontend/package-lock.json

Large diffs are not rendered by default.

8 changes: 7 additions & 1 deletion admin-portal-frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,18 @@
"dependencies": {
"@emotion/react": "^11.11.4",
"@emotion/styled": "^11.11.5",
"@fortawesome/fontawesome-svg-core": "^6.5.2",
"@fortawesome/free-solid-svg-icons": "^6.5.2",
"@fortawesome/react-fontawesome": "^0.2.2",
"bootstrap": "^5.3.3",
"dotenv": "^16.4.5",
"firebase": "^10.10.0",
"fontawesome": "^5.6.3",
"next": "14.1.4",
"react": "^18",
"react-bootstrap": "^2.10.2",
"react-dom": "^18"
"react-dom": "^18",
"react-router-dom": "^6.23.0"
},
"devDependencies": {
"@svgr/webpack": "^8.1.0",
Expand Down
40 changes: 40 additions & 0 deletions admin-portal-frontend/src/app/components/Popup.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import React from "react";

type PopupProps = {
message: string;
onClose: () => void;
};

const Popup: React.FC<PopupProps> = ({ message, onClose }) => {
return (
<div className="fixed inset-0 flex items-center justify-center bg-black bg-opacity-50">
<div className="bg-white p-12 px-36 rounded-lg shadow-lg relative">
<button
className="absolute text-2xl top-2 right-4 text-gray-400 hover:text-gray-600"
onClick={onClose}
aria-label="Close"
>
&times;
</button>
<div className="flex items-center space-x-2">
<svg
className="h-6 w-6 text-green-500"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M5 13l4 4L19 7" />
</svg>
<p className="text-green-500 font-semibold text-lg">{message}</p>
</div>
<div className="mt-6 flex justify-center">
<button className="bg-dfm-blue text-white py-2 px-8 rounded" onClick={onClose}>
Close
</button>
</div>
</div>
</div>
);
};

export default Popup;
114 changes: 114 additions & 0 deletions admin-portal-frontend/src/app/components/admin-cards.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
"use client";

import { faTrash } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { collection, deleteDoc, doc, getDocs, getFirestore } from "firebase/firestore";
import React, { useEffect, useState } from "react";

import Popup from "./Popup";

type Admin = {
firstName: string;
lastName: string;
title: string;
email: string;
phone: string;
};

const AdminCards: React.FC = () => {
const [admins, setAdmins] = useState<Admin[]>([]);
const [showModal, setShowModal] = useState(false);

Check failure on line 20 in admin-portal-frontend/src/app/components/admin-cards.tsx

View workflow job for this annotation

GitHub Actions / Admin portal frontend lint and style check

'showModal' is assigned a value but never used. Allowed unused elements of array destructuring patterns must match /^_/u

Check failure on line 20 in admin-portal-frontend/src/app/components/admin-cards.tsx

View workflow job for this annotation

GitHub Actions / Admin portal frontend lint and style check

'setShowModal' is assigned a value but never used. Allowed unused elements of array destructuring patterns must match /^_/u
const [showPopup, setShowPopup] = useState(false);
const [popupMessage, setPopupMessage] = useState("");
const db = getFirestore();

useEffect(() => {
const fetchAdmins = async () => {
try {
const querySnapshot = await getDocs(collection(db, "invitations"));
const adminsList = querySnapshot.docs.map((doc) => doc.data() as Admin);

Check failure on line 29 in admin-portal-frontend/src/app/components/admin-cards.tsx

View workflow job for this annotation

GitHub Actions / Admin portal frontend lint and style check

'doc' is already declared in the upper scope on line 5 column 33
setAdmins(adminsList);
} catch (error) {
console.error("Error fetching admins: ", error);
}
};

fetchAdmins();

Check failure on line 36 in admin-portal-frontend/src/app/components/admin-cards.tsx

View workflow job for this annotation

GitHub Actions / Admin portal frontend lint and style check

Promises must be awaited, end with a call to .catch, end with a call to .then with a rejection handler or be explicitly marked as ignored with the `void` operator
}, [db]);

const deleteAdmin = async (id: string) => {
try {
await deleteDoc(doc(db, "invitations", id));
setAdmins(admins.filter((admin) => admin.email !== id));
setPopupMessage("Physician deleted!");
setShowPopup(true);
} catch (error) {
console.error("Error deleting admin: ", error);
}
};

//having trouble with deleting account from firebase auth
// const deleteAdmin = async (email: string) => {
// try {
// const response = await fetch('/api/deleteAdmin', {
// method: 'DELETE',
// headers: {
// 'Content-Type': 'application/json',
// },
// body: JSON.stringify({ email }),
// });

// if (!response.ok) {
// console.log('deletion error')
// throw new Error('Failed to delete admin');
// }

// setAdmins(admins.filter(admin => admin.email !== email));
// setPopupMessage('Physician deleted!');
// setShowPopup(true);
// } catch (error) {
// console.error("Error deleting admin:", error);
// }
// };

return (
<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-4 p-4">
{admins.map((admin, index) => (
<div key={index} className="bg-white shadow-md rounded-lg p-4 py-3">
<button
className="flex justify-end pt-1 w-full text-gray-500 hover:text-gray-900"
onClick={() => deleteAdmin(admin.email)}

Check failure on line 80 in admin-portal-frontend/src/app/components/admin-cards.tsx

View workflow job for this annotation

GitHub Actions / Admin portal frontend lint and style check

Promise-returning function provided to attribute where a void return was expected
>
<FontAwesomeIcon icon={faTrash} />
</button>
<div className="flex items-center space-x-4">
{/* <div className="w-16 h-16 rounded-full overflow-hidden">
<img src="" alt="admin picture" />
</div> */}
<div>
<h2 className="text-xl font-semibold text-gray-800">
{admin.firstName} {admin.lastName}
</h2>
<p className="text-gray-600">{admin.title}</p>
</div>
</div>
<div className="mt-4">
<p className="text-gray-600 truncate mb-0.5">{admin.email}</p>
<p className="text-gray-600">{admin.phone}</p>
</div>
</div>
))}

{showPopup && (
<Popup
message={popupMessage}
onClose={() => {
setShowPopup(false);
}}
/>
)}
</div>
);
};

export default AdminCards;
158 changes: 158 additions & 0 deletions admin-portal-frontend/src/app/components/invite-admin.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
"use client";

import { doc, setDoc } from "firebase/firestore";
import React, { ChangeEvent, FormEvent, useState } from "react";

import { db } from "../firebase-config";

const InviteAdmin = () => {
const [adminForm, setAdminForm] = useState({
firstName: "",
lastName: "",
title: "",
email: "",
phone: "",
});
const [error, setError] = useState("");
const [showModal, setShowModal] = useState(false);

const handleInputChange = (e: ChangeEvent<HTMLInputElement>) => {
const { name, value } = e.target;
setAdminForm({ ...adminForm, [name]: value });
};

const handleSubmit = async (e: FormEvent<HTMLFormElement>) => {
e.preventDefault();
const { firstName, lastName, title, email, phone } = adminForm;

try {
await setDoc(doc(db, "invitations", email), { firstName, lastName, title, email, phone });
setShowModal(false);
setAdminForm({ firstName: "", lastName: "", title: "", email: "", phone: "" });
} catch (err) {
if (err instanceof Error) {
setError(err.message);
} else {
setError("An unexpected error occurred");
}
}
};

return (
<div className="flex items-center justify-end w-full p-4">
<button
className="bg-dfm-blue text-white py-2 px-4 rounded"
onClick={() => {
setShowModal(true);
}}
>
Add Admin
</button>

{showModal && (
<div className="fixed inset-0 bg-black bg-opacity-50 flex justify-center items-center">
<div className="relative bg-white shadow-xl rounded-lg p-8 flex flex-col w-full max-w-md">
<button
onClick={() => {
setShowModal(false);
}}
className="absolute top-4 right-5 text-2xl text-gray-400 hover:text-gray-600"
aria-label="Close"
>
&times;
</button>
<h2 className="text-xl text-dfm-navy font-bold">Add a new Admin</h2>
<p className="mb-4 text-dfm-navy">
Register a physician to your admin directory below.
</p>
{/*eslint-disable-next-line @typescript-eslint/no-misused-promises*/}
<form onSubmit={handleSubmit} className="w-full">
<p className="font-semibold text-dfm-navy text-lg mb-1">Physician Details</p>
<div className="mb-4">
<label htmlFor="firstName" className="text-slate-600 block font-sm">
First Name*
</label>
<input
type="text"
name="firstName"
id="firstName"
className="p-2 border w-full rounded border-gray-300 focus:border-blue-500 focus:ring focus:ring-blue-500 focus:ring-opacity-50"
onChange={handleInputChange}
required
/>
</div>
<div className="mb-4">
<label htmlFor="lastName" className="block text-slate-600 font-sm">
Last Name*
</label>
<input
type="text"
name="lastName"
id="lastName"
className="p-2 border w-full rounded border-gray-300 focus:border-blue-500 focus:ring focus:ring-blue-500 focus:ring-opacity-50"
onChange={handleInputChange}
required
/>
</div>
<div className="mb-4">
<label htmlFor="title" className="block text-slate-600 font-sm">
Title (ex. HS Clinical Professor)
</label>
<input
type="text"
name="title"
id="title"
className="p-2 border w-full rounded border-gray-300 focus:border-blue-500 focus:ring focus:ring-blue-500 focus:ring-opacity-50"
onChange={handleInputChange}
/>
</div>
<p className="font-semibold text-lg mb-2 text-dfm-navy">Contact Info</p>
<div className="mb-4">
<label htmlFor="email" className="block text-slate-600 font-sm">
Email*
</label>
<input
type="email"
name="email"
id="email"
className="p-2 border w-full rounded border-gray-300 focus:border-blue-500 focus:ring focus:ring-blue-500 focus:ring-opacity-50"
onChange={handleInputChange}
required
/>
</div>
<div className="mb-4">
<label htmlFor="phone" className="block text-slate-600 font-sm">
Phone Number (format: xxx-xxx-xxxx)
</label>
<input
type="tel"
name="phone"
id="phone"
className="p-2 border w-full rounded border-gray-300 focus:border-blue-500 focus:ring focus:ring-blue-500 focus:ring-opacity-50 mb-4"
onChange={handleInputChange}
/>
</div>
<div className="flex justify-end space-x-2">
<button
type="button"
className="text-dfm-blue py-2 px-4 rounded hover:bg-gray-600"
onClick={() => {
setShowModal(false);
}}
>
Cancel
</button>
<button type="submit" className="bg-dfm-blue text-white py-2 px-4 rounded">
Save
</button>
</div>
{error && <p className="text-red-600 text-sm mt-4">{error}</p>}
</form>
</div>
</div>
)}
</div>
);
};

export default InviteAdmin;
Binary file removed admin-portal-frontend/src/app/favicon.ico
Binary file not shown.
12 changes: 12 additions & 0 deletions admin-portal-frontend/src/app/firebase-admin.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import admin from "firebase-admin";

Check failure on line 1 in admin-portal-frontend/src/app/firebase-admin.tsx

View workflow job for this annotation

GitHub Actions / Admin portal frontend lint and style check

Unable to resolve path to module 'firebase-admin'

const serviceAccount = require("./dfm-sideline-sidekick-app-firebase-adminsdk-mqgtq-32d66e30cf.json");

Check failure on line 3 in admin-portal-frontend/src/app/firebase-admin.tsx

View workflow job for this annotation

GitHub Actions / Admin portal frontend lint and style check

Unsafe assignment of an `any` value

Check failure on line 3 in admin-portal-frontend/src/app/firebase-admin.tsx

View workflow job for this annotation

GitHub Actions / Admin portal frontend lint and style check

Require statement not part of import statement

if (!admin.apps.length) {

Check failure on line 5 in admin-portal-frontend/src/app/firebase-admin.tsx

View workflow job for this annotation

GitHub Actions / Admin portal frontend lint and style check

Unsafe member access .apps on an `any` value
admin.initializeApp({

Check failure on line 6 in admin-portal-frontend/src/app/firebase-admin.tsx

View workflow job for this annotation

GitHub Actions / Admin portal frontend lint and style check

Unsafe call of an `any` typed value
credential: admin.credential.cert(serviceAccount),
});
}

export const auth = admin.auth();
export const firestore = admin.firestore();
18 changes: 18 additions & 0 deletions admin-portal-frontend/src/app/firebase-config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { initializeApp } from "firebase/app";
import { getAuth } from "firebase/auth";
import { getFirestore } from "firebase/firestore";

const firebaseConfig = {
apiKey: process.env.NEXT_PUBLIC_FIREBASE_API_KEY,
authDomain: process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN,
projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID,
storageBucket: process.env.NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET,
messagingSenderId: process.env.NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID,
appId: process.env.NEXT_PUBLIC_FIREBASE_APP_ID,
};

const app = initializeApp(firebaseConfig);
const auth = getAuth(app);
const db = getFirestore();

export { auth, db };
Loading
Loading