Find blood donation centers, see live stock levels, and get routed to where your blood type is needed most.
Built with React + Vite, Firebase, and the ArcGIS Maps SDK for JavaScript.
Blood+ is a web application that maps blood donation centers in Bucharest, Romania, and shows the current blood-stock situation for each one in real time. Visitors can explore the map without an account; registered donors get personalized routing and recommendations based on their blood group; administrators manage centers and update stock levels.
Every center is color-coded by how critical its supply is, so users can see at a glance where blood is urgently needed — and donors can be guided straight to the center where their donation will have the most impact.
The user interface is in Romanian.
- Interactive map of donation centers centered on Bucharest (ArcGIS basemap).
- Color-coded markers reflecting each center's stock status:
- 🔴 Critical — at least one blood group is at 0 units
- 🟠 Warning — at least one blood group is below 10 units
- 🟢 Normal — all groups have 10+ units
- Center details popup: address, email, phone, opening hours, and a full breakdown of all 8 blood groups with per-group quantities.
- Address search & routing: search any address, drop a pin, and click "Find the nearest center" to compute a driving route with distance and travel time.
- Email/password authentication (Firebase Auth).
- Personalized recommendation: a scoring algorithm suggests the best center to donate at for your blood group, balancing stock urgency (70%) and proximity (30%), then routes you there.
- Need heatmap: an intensity overlay across Bucharest + Ilfov highlighting where your blood group is most scarce (red hotspots = critical, green = well-stocked).
- Filters: limit centers by maximum distance (1–50 km) and by blood group below a chosen stock threshold.
- Account page: view your profile, change your password, or delete your account.
- Center management panel: edit any center's details (name, address, coordinates, contact info, hours) and adjust per-group blood-stock quantities inline.
- Add new centers: new centers are automatically initialized with all 8 blood groups at 0 units.
- Delete centers (including their stock subcollection).
| Area | Technology |
|---|---|
| UI | React 19 |
| Build tool | Vite 7 |
| Routing | React Router 7 |
| Maps / geocoding / routing / heatmap | ArcGIS Maps SDK for JavaScript 4 (@arcgis/core) |
| Auth & database | Firebase 12 (Authentication + Cloud Firestore) |
| Data seeding | Firebase Admin SDK 13 |
| Linting | ESLint 9 |
The application lives in the blood+/ directory.
blood+/
├── index.html
├── package.json
├── vite.config.js
├── seed.js # Entry point for seeding Firestore (npm run seed)
├── public/
│ └── bloodplus_logo_wo_text.png
└── src/
├── main.jsx # App entry + React Router routes
├── App.jsx # Auth/guest gate + map screen
├── AuthPage.jsx # Login / register / continue-as-guest
├── MapComponent.jsx # The core ArcGIS map: markers, search,
│ # routing, recommendation, heatmap, filters
├── AdminPage.jsx # Admin: list & edit centers + stock
├── AddCentersPage.jsx # Admin: add a new center
├── UserPage.jsx # Donor: profile, change password, delete account
├── utils/
│ └── getNextCenterId.js # Generates the next sequential center ID
└── firebase/
├── firebaseConfig.js # Firebase web app initialization (Firestore + Auth)
├── firebaseCollections.js # Collection / subcollection name constants
├── firebaseService.js # Firestore collection references
├── models.js # Documented data shapes (centers, users, stock)
├── seedCenters.js # Sample Bucharest centers + stock seed data
└── firebaseAdmin.js # Firebase Admin init (Node, service account)
| Path | Page | Audience |
|---|---|---|
/ |
Auth gate, then the map | Everyone |
/account |
Donor profile | Donors |
/admin |
Center management | Admins |
/admin/add-center |
Add a new center | Admins |
centers (collection)
└── {centerId} (document)
├── name: string
├── address: string
├── latitude: number
├── longitude: number
├── contact_phone: string
├── contact_email: string
├── program: string # opening hours, e.g. "L-V 07:30 - 13:30"
└── blood_stock (subcollection)
└── {stockId} (document)
├── stock_id: string
├── blood_group: string # A+, A-, B+, B-, AB+, AB-, 0+, 0-
└── quantity: number
users (collection)
└── {uid} (document) # uid = Firebase Auth user id
├── name: string
├── email: string
├── role: "donor" | "admin"
├── blood_group: string
└── createdAt: number
Anyone who registers is created with the donor role. To grant a user the admin role (which reveals the Admin Panel button), change their role field to "admin" directly in the Firestore console.
- Node.js (with npm)
- A Firebase project with Cloud Firestore and Email/Password authentication enabled
- An ArcGIS API key (developers.arcgis.com) for the basemap, geocoding, and routing services
cd blood+
npm installThe map reads the key from import.meta.env.VITE_ARCGIS_API_KEY. Create a .env.local file inside blood+/:
VITE_ARCGIS_API_KEY=your_arcgis_api_key_hereFirebase web configuration is currently set in src/firebase/firebaseConfig.js. To use your own Firebase project, replace the firebaseConfig object there with your project's values, then enable Email/Password auth and Cloud Firestore in the Firebase console.
Firebase web API keys are safe to expose in client code — access is controlled by your Firestore security rules, so be sure to configure those for production.
npm run devVite prints a local URL (default http://localhost:5173). Open it in your browser.
Run these from the blood+/ directory:
| Command | Description |
|---|---|
npm run dev |
Start the Vite development server with hot-reload |
npm run build |
Build the production bundle into dist/ |
npm run preview |
Serve the production build locally |
npm run lint |
Run ESLint over the project |
npm run seed |
Populate Firestore with the sample centers from seedCenters.js |
The repo ships with sample data for four real Bucharest transfusion centers (with per-group stock) in src/firebase/seedCenters.js. To load it into Firestore:
npm run seedThis writes each center and its blood_stock subcollection to your configured Firebase project. Make sure your Firestore security rules allow the writes (or run it against a development project).
- Auth & mode —
App.jsxstores the chosen mode inlocalStorage(app_mode = "guest" | "user"). Authenticated sessions are tracked with Firebase'sonAuthStateChanged, which loads the matchingusers/{uid}document to determine role and blood group. - Map rendering —
MapComponent.jsxloads every center (and its stock) from Firestore, builds a client-side ArcGISFeatureLayer, and renders each center with a unique-value symbol based on its computed criticality level. - Routing — uses the ArcGIS World Route service to draw the driving route from the searched location to the chosen center, returning distance and estimated travel time.
- Recommendation — scores every center as
0.7 × stock_urgency + 0.3 × proximityfor the donor's blood group and routes to the highest-scoring one. - Heatmap — builds a weighted ArcGIS heatmap layer (more overlapping points where stock is lower) restricted to the Bucharest + Ilfov area, shown only to logged-in users who have a blood group.
- Tudor Crețu (@tudor-cretu)
- Ruxandra Diaconu
- Diana Chelaru
No license has been specified for this project. If you intend to reuse or distribute it, please contact the authors.