Day 7 [D&D Character Sheet]
Tags: 100daysofcode
Published: 2020-03-18 06:30:40

# 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:

```js
// 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
		});
	});
});
```

```js
// 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.

```js
// 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
					})
				}
			});
		}
	);
});
```

```js
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

{% github ApproachingApathy/100days-dnd-character-sheets %}

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.