loading...

Day 7 [D&D Character Sheet]

approachingapathy profile image Ephriam Henderson ・3 min read

Report

Today I finished my seeder and refactored my database and characters router modules.

The database module contained a lot of cruft. It was like a meandering drunkard stumbling through completing a basic task. This was mainly because I was figuring out mongoose as I wrote it. I did a small refactor to clear some of the unnessary code and improve readability a bit. Here's a before and after of the refactored connect promise:

// db/index.js
// before
let connect = new Promise((resolve, reject) => {
    mongoose.connect("mongodb://localhost/dnd-sheets", {
        useNewUrlParser: true,
        useUnifiedTopology: true
    });

    const db = mongoose.connection;
    db.on("error", () => { 
        // what? why these event handlers? I got them from the docs i think, what 
        // is this doing that can't be done with then-catches?
        logger.error("Couldn't connect to mongodb");
        reject("Failed to connect to mongodb.");
    });

    db.once("open", () => {
        let connectTime = new Date();
        logger.info(
            `Connected to mongodb at ${connectTime.toLocaleDateString()}  
            ${connectTime.toLocaleTimeString()}`
        );
        let models = buildModels();

        /**
         * Close connection to mongo db.
         */
        let close = () => 
        // OMG Why? I don't even think this would've worked.
            db.close(() => {
                let dcTime = new Date();
                logger.info(
                    `Disconnected from mongodb at ${dcTime.toLocaleDateString()} 
                    ${dcTime.toLocaleTimeString()}.`
                );
            });
        resolve({ 
                // This is bad and I should feel bad. I'm passing my own frankenstein 
                // db object and not the thing from mongoose. Again, why?
            mongoose,
            models,
            close
        });
    });
});
// db/index.js
// after 
let connect = new Promise((resolve, reject) => {
    mongoose
        .connect("mongodb://localhost/dnd-sheets", {
            useNewUrlParser: true,
            useUnifiedTopology: true
        })
        .then(db => { 
            // Use .then instead of those weird event handlers
            let connectTime = new Date();
            logger.info(
                `Connected to mongodb at ${connectTime.toLocaleDateString()} 
                 ${connectTime.toLocaleTimeString()}`
            );
            buildModels();

            resolve(db); 
            // Resolve with the db object that mongoose provides,
            // not... whatever that thing was.
        })
        .catch(err => { 
            // Use a .catch for errors.
            logger.error("Couldn't connect to mongodb");
            reject("Failed to connect to mongodb.");
        });
});

I also refactored my characters route. I got rid of some of the routes and refactored the "characters/:id" route. The main thing here was making the code a bit more readable. I find it eaiser to think in .then() but find async/awaits much more readable. Often-times when I'm in a hurry I'll write code using .then() and refactor it to use async/await later.

// router/characters/index.js
// before
router.get("/:id", async (req, res) => {
    console.log(req.params.id);
    req.context.models.Character.findOne({ _id: req.params.id }).then(
        async result => {
            if (result == null) res.redirect("/404");
            console.log(result);
            res.render("characterSheet", {
                data: {
                    character: result,
                    player: await req.context.models.Player.findOne({
                        _id: result.player
                    })
                }
            });
        }
    );
});
router.get("/:id", async (req, res) => {
    const character = await req.context.db.models.Character.findOne({
        _id: req.params.id
    });

    if (character == null) {
        res.redirect("/404");
        return false;
    }

    const player = await req.context.db.models.Player.findOne({
        _id: character.player
    });

    res.render("characterSheet", {
        data: {
            character,
            player
        }
    });
});

That was it for today, thanks for reading!

Project

[100days] The DND Character Sheet App

This is the first project of my 100 days of coding This is an app to keep D&D character sheets.

Stack

I'll be using Node.js and building a full-stack Express app with MongoDB.

Requirements

Minimum Viable

  • Present a D&D Character Sheet
    • The sheet should display all the same info as the first page of the 5e Official sheet.
  • Users should be able to log in and create player-characters.
  • Users should be able to edit character sheets.
  • Users should be able to organize character sheets into groups (parties/tables)
  • Sheets should auto calculate basic stats like ability modifiers
    • Support Proficiency Bonuses

Cake

  • Extend character creation to allow the user to use any of the three common stat gen methods
    • Point Buy
    • Standard Array
    • Roll
  • Extend the character sheet to all the info in the 5e official sheet.
  • Allow for image uploads for character portraits.
  • Allow for…

The First project will be an app to keep D&D character sheets.

Stack

I'll be using Node.js and building a full-stack Express app with MongoDB.

Requirements

Minimum Viable

  • [ ] Investigate automating or finding a source of info for the data in the SRD.
  • [ ] Present a D&D Character Sheet
    • [ ] The sheet should display all the same info as the first page of the 5e Official sheet.
  • [ ] Users should be able to log in and create player-characters.
  • [ ] Users should be able to edit character sheets.
  • [ ] Users should be able to organize character sheets into groups (parties/tables)
  • [ ] Sheets should auto calculate basic stats like ability modifiers.
    • [ ] Support Proficiency Bonuses

Cake

  • [ ] Extend character creation to allow the user to use any of the three common stat gen methods.
    • [ ] Point Buy
    • [ ] Standard Array
    • [ ] Roll
  • [ ] Extend the character sheet to all the info in the 5e official sheet.
  • [ ] Allow for image uploads for character portraits.
  • [ ] Allow for extended descriptions/backstories.
    • [ ] Characters should have nice full page backstories.
    • [ ] Preferably use a markdown editor.

Posted on by:

approachingapathy profile

Ephriam Henderson

@approachingapathy

I'm a Full-Stack Developer and recent Bootcamp Graduate. I'm most experienced with JavaScript, but I'm a python enthusiast and an all-around nerd. When I'm not coding I love anime, sci-fi, d&d.

Discussion

markdown guide