Skip to content

Referrals feature#12

Open
tedthavisin wants to merge 23 commits intomainfrom
referrals-feature
Open

Referrals feature#12
tedthavisin wants to merge 23 commits intomainfrom
referrals-feature

Conversation

@tedthavisin
Copy link
Copy Markdown

Implemented Referrals Card, List, and Form Dialog that works with our Firebase Database. Currently, it is being displayed on referrals.tsx since we eventually want it on the same page as messages so for now it will remain separate until we can merge. The Edit, Add, and Delete functions work for the referrals. For now, we are using a static variable to keep track of the current user which will be changed later on using route params.

tedthavisin and others added 23 commits November 1, 2025 17:13
…ctioning sorting for Patient Name, Assigned Social Worker, and Last Contact.
Implemented _index.tsx (home page) using temporary JSON data with fun…
…t, and add functionality. Updated styling.Added website button.
Copilot AI review requested due to automatic review settings March 26, 2026 15:57
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds Firebase-backed authentication and a new referrals UI flow (list/cards + add/edit/delete dialog), wiring them into the React Router app structure and updating project config/dependencies to support local Firebase development.

Changes:

  • Added Firebase Auth context/provider plus auth flows (login, create account, verify email, forgot password) and route guards.
  • Implemented referrals UI (page, list, cards, form dialog) and Firestore hook for CRUD operations.
  • Updated build/runtime config (SPA mode, Vite polling watch), dependencies, lint ignores, and environment templates.

Reviewed changes

Copilot reviewed 28 out of 32 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
vite.config.ts Enables polling file watcher for dev server stability.
tsconfig.json Suppresses TypeScript deprecation warnings.
react-router.config.ts Switches app to SPA mode by disabling SSR.
package.json Adds Firebase + lucide-react and router deps/types.
package-lock.json Locks new dependencies and transitive packages.
eslint.config.ts Ignores generated build/** output in ESLint.
app/types/user.ts Adds typed user model for Firestore/user data.
app/types/referral.ts Adds typed referral + joined referral-with-provider model.
app/services/firebase_provider.tsx Introduces AuthProvider and useAuth() context hook.
app/services/firebase_app.ts Initializes Firebase app and exports Auth instance.
app/services/auth_service.ts Wraps sign-up/login flows with persistence + verification.
app/routes/verify_email.tsx Adds verify-email UI and resend/continue actions.
app/routes/starter.tsx Removes starter template landing page route.
app/routes/require_guest.tsx Adds guest-only route guard (redirects logged-in users).
app/routes/require_auth.tsx Adds auth-required route guard (redirects unauth/ unverified).
app/routes/referrals.tsx Adds standalone referrals page wiring list + dialog + hook.
app/routes/login.tsx Adds login UI wired to Firebase Auth.
app/routes/forgot_pass.tsx Adds forgot-password UI using Firebase reset email flow.
app/routes/create_account.tsx Adds create-account UI + terms gating + verification flow.
app/routes/change_password.tsx Adds (currently unused) change password page placeholder.
app/routes/_index.tsx Replaces home page with a dashboard UI using auth context.
app/routes.ts Replaces route config with guarded auth/guest routing layout.
app/root.tsx Wraps app layout in AuthProvider.
app/hooks/useReferrals.ts Adds Firestore-backed referrals query + CRUD helpers.
app/firebase.js Adds Firestore db initialization module.
app/components/ReferralsList.tsx Adds referrals list UI and “Add” action.
app/components/ReferralFormDialog.tsx Adds add/edit referral modal form UI.
app/components/ReferralCard.tsx Adds referral card UI with edit/delete actions.
app/app.css Improves default text colors for light/dark mode.
.gitignore Ignores .env (and keeps build/react-router ignores).
.env.template Adds Firebase env var template for local setup.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +3 to +16
export default [
//protected routes
route("", "routes/require_auth.tsx", [index("routes/_index.tsx")]),

//routes require user to not be logged in
route("", "routes/require_guest.tsx", [
route("login", "routes/login.tsx"),
route("create-account", "routes/create_account.tsx"),
]),

//routes available to anyone
route("forgot-pass", "routes/forgot_pass.tsx"),
route("verify-email", "routes/verify_email.tsx"),
] satisfies RouteConfig;
Copy link

Copilot AI Mar 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PR description says the referrals UI is currently displayed on referrals.tsx, but there is no route configured for it here, so it won't be reachable in the app. Add a route for routes/referrals.tsx (likely under require_auth) or update the PR description to match the actual navigation.

Copilot uses AI. Check for mistakes.
Comment on lines +82 to +87
<a
href="#"
className="font-medium text-gray-900 underline underline-offset-2"
>
Logout
</a>
Copy link

Copilot AI Mar 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The "Logout" UI is a dead link (href="#") and doesn't call the auth logout() function, so users can't actually sign out (and clicking it will also jump to the top of the page). Replace this with a button that calls logout() from useAuth() and then navigates to /login (or relies on RequireGuest/RequireAuth redirects).

Suggested change
<a
href="#"
className="font-medium text-gray-900 underline underline-offset-2"
>
Logout
</a>
<button
type="button"
onClick={async () => {
await logout();
navigate("/login");
}}
className="font-medium text-gray-900 underline underline-offset-2"
>
Logout
</button>

Copilot uses AI. Check for mistakes.
{/* Header Title */}
<div className="mb-3 flex items-center justify-between">
<h2 className="text-[20px] font-semibold text-black">
David Thompsons Referrals
Copy link

Copilot AI Mar 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Grammatical typo in the header: "David Thompsons Referrals" is missing the apostrophe. Consider "David Thompson's Referrals" (or make this dynamic once patient data is available).

Suggested change
David Thompsons Referrals
David Thompson's Referrals

Copilot uses AI. Check for mistakes.
"@types/node": "^20",
"@types/react": "^19.1.2",
"@types/react-dom": "^19.1.2",
"@types/react-router-dom": "^5.3.3",
Copy link

Copilot AI Mar 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@types/react-router-dom is pinned to v5.3.3, but this repo is using React Router v7 (react-router/react-router-dom 7.x). The v5 DefinitelyTyped package is incompatible and can cause incorrect types or conflicts. Remove @types/react-router-dom (and @types/react-router) and rely on the built-in types shipped with React Router v7, or align to the correct major versions consistently.

Suggested change
"@types/react-router-dom": "^5.3.3",

Copilot uses AI. Check for mistakes.
Comment on lines +45 to +68
// Perform the "join" by fetching associated users
const populatedReferrals = await Promise.all(
baseReferrals.map(async (ref) => {
let socialWorker: User | undefined;

// Fetch referring Social Worker
if (ref.socialWorkerId) {
const swDoc = await getDoc(
doc(db, "users", ref.socialWorkerId)
);
if (swDoc.exists()) {
socialWorker = {
uid: swDoc.id,
...swDoc.data(),
} as User;
}
}

return {
...ref,
socialWorker,
};
})
);
Copy link

Copilot AI Mar 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

useReferrals performs a per-referral getDoc() for the social worker on every snapshot update. This creates an N+1 pattern and can become slow/expensive as referrals grow. Consider caching users by id, denormalizing the needed social worker fields onto the referral document, or batching lookups (e.g., where(documentId(), 'in', ...) in chunks) instead of fetching each doc individually.

Copilot uses AI. Check for mistakes.
referralPhone?: string;

type: string;
status: string;
Copy link

Copilot AI Mar 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ReferralFormData.status is typed as string, but Referral.status is a constrained union (pending/accepted/completed/rejected). As-is, invalid status values can be submitted and stored without TypeScript catching it. Type this field as Referral["status"] (or the explicit union) to keep form inputs and persisted data consistent.

Suggested change
status: string;
status: Referral["status"];

Copilot uses AI. Check for mistakes.
addDoc,
Timestamp,
} from "firebase/firestore";
import { db } from "~/firebase";
Copy link

Copilot AI Mar 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

useReferrals imports db from "~/firebase", but the file added is app/firebase.js. With the current tsconfig.json (no allowJs), TypeScript builds/typecheck will fail to resolve/compile JS modules. Rename the Firebase module to app/firebase.ts (or app/firebase_app.ts) and export db from there, or enable allowJs (less preferred).

Suggested change
import { db } from "~/firebase";
import { db } from "../firebase";

Copilot uses AI. Check for mistakes.
Comment on lines +1 to +15
import { initializeApp } from "firebase/app";
import { getFirestore } from "firebase/firestore";

const firebaseConfig = {
apiKey: import.meta.env.VITE_FIREBASE_API_KEY,
authDomain: import.meta.env.VITE_FIREBASE_AUTH_DOMAIN,
projectId: import.meta.env.VITE_FIREBASE_PROJECT_ID,
storageBucket: import.meta.env.VITE_FIREBASE_STORAGE_BUCKET,
messagingSenderId: import.meta.env.VITE_FIREBASE_MESSAGING_SENDER_ID,
appId: import.meta.env.VITE_FIREBASE_APP_ID,
measurementId: import.meta.env.VITE_FIREBASE_MEASUREMENT_ID,
};

const app = initializeApp(firebaseConfig);
export const db = getFirestore(app);
Copy link

Copilot AI Mar 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file calls initializeApp(firebaseConfig) even though app/services/firebase_app.ts also initializes the default Firebase app. Importing both modules in the same bundle will throw "Firebase App named '[DEFAULT]' already exists" at runtime. Consolidate initialization into a single module and have both auth and firestore use the same app instance (e.g., getApps().length ? getApp() : initializeApp(...)).

Copilot uses AI. Check for mistakes.
Comment on lines +8 to +25
// Your web app's Firebase configuration
// For Firebase JS SDK v7.20.0 and later, measurementId is optional
const firebaseConfig = {
apiKey: import.meta.env.VITE_FIREBASE_API_KEY,
authDomain: import.meta.env.VITE_FIREBASE_AUTH_DOMAIN,
projectId: import.meta.env.VITE_FIREBASE_PROJECT_ID,
storageBucket: import.meta.env.VITE_FIREBASE_STORAGE_BUCKET,
messagingSenderId: import.meta.env.VITE_FIREBASE_MESSAGING_SENDER_ID,
appId: import.meta.env.VITE_FIREBASE_APP_ID,
measurementId: import.meta.env.VITE_FIREBASE_MEASUREMENT_ID,
};

// Initialize Firebase
const app = initializeApp(firebaseConfig);
//const analytics = getAnalytics(app);
const auth = getAuth(app);

export { app, auth };
Copy link

Copilot AI Mar 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This module initializes the default Firebase app. Since app/firebase.js also initializes the default app, importing auth + firestore together will cause a duplicate-app runtime error. Prefer a single shared initializer that exports app, auth, and db, using getApps()/getApp() guards if needed.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants