skip to Main Content

I’m working on a MERN (MongoDB, Express, React, Node.js) stack application that uses React Big Calendar to display events. Everything works perfectly in my development environment, but in production, events do not show up in the calendar. However, tasks (another feature) work fine in both environments. I am using a DigitalOcean VPS to host the backend and database within Docker containers for production. First image is in production, second is in development.
Not sure what else to do anymore.

We can see there is no event in production, but there are tasks
In development, an event shows as well

Here is the setup:

server.js

const express = require("express")
const mongoose = require("mongoose")
const dotenv = require("dotenv")
const cors = require("cors");
const path = require("path")


dotenv.config()
const MONGO_URI = process.env.MONGO_URI
const PORT = process.env.PORT || 80;

const app = express()

app.use(express.json()); // Parses incoming JSON requests
app.use(
    cors({
        origin: (origin, callback) => {
            const allowedOrigins =
                process.env.NODE_ENV === "development"
                    ? ["http://localhost:5173", "http://127.0.0.1:5173"]
                    : [
                        "http://www.<sitename>.com",
                        "https://www.<sitename>.com",
                        "http://api.<sitename>.com",
                        "https://api.<sitename>.com",
                    ];
            // Allow no-origin requests for tools like Postman
            if (!origin || allowedOrigins.includes(origin)) {
                callback(null, true);
            } else {
                callback(new Error("Not allowed by CORS"));
            }
        },
        methods: ["GET", "POST", "PUT", "DELETE"],
        allowedHeaders: ["Content-Type", "Authorization"],
        credentials: true, // Allow credentials if needed
    })
);

const eventsRoutes = require("./routes/events");
app.use("/api/events", eventsRoutes);

const tasksRoutes = require("./routes/tasks");
app.use("/api/tasks", tasksRoutes);


// Connect to MongoDB and start backend server
mongoose
    .connect(MONGO_URI, { useNewUrlParser: true, useUnifiedTopology: true })
    .then(() => console.log("Connected to MongoDB"))
    .catch((error) => console.error("MongoDB connection error:", error));

// Start server
app.listen(PORT, () => console.log(`Server is running in ${process.env.NODE_ENV} mode on port ${PORT}`));

events.js

const express = require("express")
const Event = require("../models/Event")

const router = express.Router()

router.get("/", async (req, res) => {
    console.log("GET /api/events received")
    try {
        const events = await Event.find()
        console.log("Fetched events:", events); // Log the fetched events
        res.json(events)
    } catch (error) {
        console.error("Error fetching events:", error)
        res.status(500).json({message: "Server error"})
    }
})

router.post("/", async (req, res) => {
    try {
        const newEvent = new Event(req.body)
        const savedEvent = await newEvent.save()
        res.status(201).json(savedEvent)
    } catch (error) {
        console.error("Error saving event:", error)
        res.status(500).json({message: "Failed to save event"})
    }
})

router.put("/:id", async (req, res) => {
    try {
        const updatedEvent = await Event.findByIdAndUpdate(req.params.id, req.body, {new: true})
        res.json(updatedEvent)
    } catch (error) {
        console.error("Error updating event:", error)
        res.status(500).json({message: "Failed to update event"})
    }
})

router.delete("/:id", async (req, res) => {
    try {
        await Event.findByIdAndDelete(req.params.id)
        res.status(204).send()
    } catch (error) {
        console.error("Error deleting event:", error)
        res.status(500).json({message: "Failed to delete event"})
    }
})

module.exports = router

Event.js

const mongoose = require("mongoose")

const eventSchema = new mongoose.Schema({
    title: {type: String, required: true},
    start: {type: Date, required: true},
    end: {type: Date, required: true},
    allDay: {type: Boolean, default: false},
    description: {type: String},
    location: {type: String},
})

module.exports = mongoose.model("Event", eventSchema)

For comparison, here is tasks.js

const express = require("express")
const Task = require("../models/Task")

const router = express.Router()

// Get all tasks
router.get("/", async (req, res) => {
    console.log("GET /api/tasks received");
    try {
        const tasks = await Task.find();
        res.json(tasks);
    } catch (error) {
        console.error("Error fetching tasks:", error);
        res.status(500).json({ message: "Server Error" });
    }
});

// Add a new task
router.post("/", async (req, res) => {
    const newTask = new Task(req.body)
    const savedTask = await newTask.save()
    res.status(201).json(savedTask)
})

// Update a task
router.put("/:id", async (req, res) => {
    try {
        const updatedTask = await Task.findByIdAndUpdate(req.params.id, req.body, { new: true });
        res.json(updatedTask);
    } catch (error) {
        console.error("Error updating task:", error);
        res.status(500).json({ message: "Failed to update task" });
    }
});

// Delete a task
router.delete("/:id", async (req, res) => {
    await Task.findByIdAndDelete(req.params.id)
    res.status(204).send()
})

module.exports = router

Task.js

const mongoose = require("mongoose")

const taskSchema = new mongoose.Schema({
    name: { type: String, required: true },
    completed: { type: Boolean, default: false },
})

module.exports = mongoose.model("Task", taskSchema)

And fetchTasks in the TodoList component

// Base URL for API calls
const api = axios.create({
  baseURL:
    import.meta.env.MODE === "development" ? "/api" : import.meta.env.VITE_API_URL,
});

// Fetch tasks on component load
useEffect(() => {
    const fetchTasks = async () => {
      try {
        const { data } = await api.get("/tasks") // Fetch tasks from backend
        console.log("Fetched tasks:", data)

        // Separate tasks into pending and completed
        const pending = data.filter((task) => !task.completed)
        const completed = data.filter((task) => task.completed)
        setPendingTasks(pending)
        setCompletedTasks(completed)
      } catch (error) {
        console.error("Error fetching tasks:", error.response || error.message)
      }
    }

    fetchTasks()
}, []) // Runs only once on mount

2

Answers


  1. Based on the code provided, here’s what you can focus on to resolve the events not showing up in production. Since tasks are working correctly but events aren’t, and both use similar patterns, the key difference likely lies in how the events data is being handled in the frontend. First, verify that your events API endpoint is being called correctly in production by adding more detailed logging in your events route handler. Then, check that the date handling in your Event model is consistent between environments.

    Here’s what to implement: Add comprehensive logging in your events route to track the exact data being sent, ensure your frontend is using the correct API URL for events (similar to your tasks implementation), and verify that the date formats are being properly parsed when creating Event objects. You can also add a specific date format validation in your Event schema to ensure consistency across environments. The fact that tasks work while events don’t suggests the issue is specific to the event data handling rather than a general API connectivity problem.

    Login or Signup to reply.
  2. Here’s what I’d recommend for you to verify. Are you certain that your events are correctly returned from your prod environment? What happens if you try to open the GET endpoint in your browser directly? What do you see in your browser’s dev console? Are you using any rewrite rules in your prod environment? If yes, is your events endpoint routed the right way? Also, in such cases it’s worth to double check that you built and deployed your app correctly.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search