Upload 3 files
Browse files- index.js +115 -0
- package-lock.json +0 -0
- package.json +20 -0
index.js
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
const express = require('express');
|
| 2 |
+
const cors = require('cors');
|
| 3 |
+
const { initializeApp, cert } = require('firebase-admin/app');
|
| 4 |
+
const { getFirestore } = require('firebase-admin/firestore');
|
| 5 |
+
require('dotenv').config();
|
| 6 |
+
|
| 7 |
+
const app = express();
|
| 8 |
+
|
| 9 |
+
// Middleware
|
| 10 |
+
app.use(cors());
|
| 11 |
+
app.use(express.json());
|
| 12 |
+
|
| 13 |
+
// --- FIREBASE ADMIN SETUP ---
|
| 14 |
+
// We check if we are in Production (HuggingFace) or Local
|
| 15 |
+
let serviceAccount;
|
| 16 |
+
|
| 17 |
+
if (process.env.FIREBASE_SERVICE_ACCOUNT) {
|
| 18 |
+
// In Production: We will store the JSON inside an ENV variable
|
| 19 |
+
serviceAccount = JSON.parse(process.env.FIREBASE_SERVICE_ACCOUNT);
|
| 20 |
+
} else {
|
| 21 |
+
// In Local: We read the file
|
| 22 |
+
try {
|
| 23 |
+
serviceAccount = require('./serviceAccountKey.json');
|
| 24 |
+
} catch (e) {
|
| 25 |
+
console.error("❌ Error: serviceAccountKey.json not found in server folder.");
|
| 26 |
+
}
|
| 27 |
+
}
|
| 28 |
+
|
| 29 |
+
if (serviceAccount) {
|
| 30 |
+
initializeApp({
|
| 31 |
+
credential: cert(serviceAccount)
|
| 32 |
+
});
|
| 33 |
+
console.log("✅ Firebase Admin Connected");
|
| 34 |
+
}
|
| 35 |
+
|
| 36 |
+
const db = getFirestore();
|
| 37 |
+
|
| 38 |
+
// --- ROUTES ---
|
| 39 |
+
|
| 40 |
+
// 1. Health Check (To verify server is running)
|
| 41 |
+
app.get('/', (req, res) => {
|
| 42 |
+
res.send('House of Ruqa API is Running 💎');
|
| 43 |
+
});
|
| 44 |
+
|
| 45 |
+
// 2. Get All Outfits
|
| 46 |
+
app.get('/api/outfits', async (req, res) => {
|
| 47 |
+
try {
|
| 48 |
+
const snapshot = await db.collection('outfits').get();
|
| 49 |
+
if (snapshot.empty) {
|
| 50 |
+
return res.json([]);
|
| 51 |
+
}
|
| 52 |
+
const outfits = snapshot.docs.map(doc => ({ id: doc.id, ...doc.data() }));
|
| 53 |
+
res.json(outfits);
|
| 54 |
+
} catch (error) {
|
| 55 |
+
res.status(500).json({ error: error.message });
|
| 56 |
+
}
|
| 57 |
+
});
|
| 58 |
+
|
| 59 |
+
// 3. Get Single Outfit by ID
|
| 60 |
+
app.get('/api/outfits/:id', async (req, res) => {
|
| 61 |
+
try {
|
| 62 |
+
const docRef = db.collection('outfits').doc(req.params.id);
|
| 63 |
+
const docSnap = await docRef.get();
|
| 64 |
+
if (!docSnap.exists) {
|
| 65 |
+
return res.status(404).json({ error: 'Outfit not found' });
|
| 66 |
+
}
|
| 67 |
+
res.json({ id: docSnap.id, ...docSnap.data() });
|
| 68 |
+
} catch (error) {
|
| 69 |
+
res.status(500).json({ error: error.message });
|
| 70 |
+
}
|
| 71 |
+
});
|
| 72 |
+
|
| 73 |
+
// 4. Create Booking Request (Status: Pending)
|
| 74 |
+
app.post('/api/request-booking', async (req, res) => {
|
| 75 |
+
try {
|
| 76 |
+
const { outfitId, userId, pickupDate, returnDate, totalAmount, outfitTitle } = req.body;
|
| 77 |
+
|
| 78 |
+
// Add to 'bookings' collection
|
| 79 |
+
const bookingRef = await db.collection('bookings').add({
|
| 80 |
+
outfitId,
|
| 81 |
+
outfitTitle,
|
| 82 |
+
userId,
|
| 83 |
+
pickupDate,
|
| 84 |
+
returnDate,
|
| 85 |
+
totalAmount,
|
| 86 |
+
status: 'pending', // Default status
|
| 87 |
+
paymentVerified: false,
|
| 88 |
+
timestamp: new Date().toISOString()
|
| 89 |
+
});
|
| 90 |
+
|
| 91 |
+
res.status(200).json({ success: true, bookingId: bookingRef.id });
|
| 92 |
+
} catch (error) {
|
| 93 |
+
res.status(500).json({ error: error.message });
|
| 94 |
+
}
|
| 95 |
+
});
|
| 96 |
+
|
| 97 |
+
// 5. Admin Confirm Booking
|
| 98 |
+
app.post('/api/confirm-booking/:id', async (req, res) => {
|
| 99 |
+
try {
|
| 100 |
+
const bookingId = req.params.id;
|
| 101 |
+
await db.collection('bookings').doc(bookingId).update({
|
| 102 |
+
status: 'confirmed',
|
| 103 |
+
paymentVerified: true
|
| 104 |
+
});
|
| 105 |
+
res.json({ success: true, message: "Booking confirmed" });
|
| 106 |
+
} catch (error) {
|
| 107 |
+
res.status(500).json({ error: error.message });
|
| 108 |
+
}
|
| 109 |
+
});
|
| 110 |
+
|
| 111 |
+
// --- SERVER START ---
|
| 112 |
+
const PORT = process.env.PORT || 7860; // 7860 is required for HuggingFace Spaces
|
| 113 |
+
app.listen(PORT, () => {
|
| 114 |
+
console.log(`🚀 Server running on port ${PORT}`);
|
| 115 |
+
});
|
package-lock.json
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
package.json
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"name": "server",
|
| 3 |
+
"version": "1.0.0",
|
| 4 |
+
"main": "index.js",
|
| 5 |
+
"scripts": {
|
| 6 |
+
"start": "node index.js",
|
| 7 |
+
"dev": "nodemon index.js"
|
| 8 |
+
},
|
| 9 |
+
"keywords": [],
|
| 10 |
+
"author": "",
|
| 11 |
+
"license": "ISC",
|
| 12 |
+
"description": "",
|
| 13 |
+
"dependencies": {
|
| 14 |
+
"cors": "^2.8.5",
|
| 15 |
+
"dotenv": "^17.2.3",
|
| 16 |
+
"express": "^5.2.1",
|
| 17 |
+
"firebase-admin": "^13.6.0",
|
| 18 |
+
"nodemon": "^3.1.11"
|
| 19 |
+
}
|
| 20 |
+
}
|