Day 17 [D&D Character Sheet]
Tags: 100daysofcode
Published: 2020-04-02 05:48:15

# Report
Today I finished the character sheet page, It will probably change in the future but this is good to continue development with.
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/y2dcm877b2s2lad32rpj.png)
I still need to add saving throws to the skills section. There are also places where data doesn't exist in the database yet. I'm happy enough that I consider it pretty far along to my first requirement.

After I finished that I worked on something else that interested me.
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/j1j2lwn714xbo93w5oww.png)
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/24626zgmm9udyozn25be.png)
The character Writer will be a utility to help players think about character backstories. It will ask questions about a character appearance, personality, and history providing a few preselected choices and custom inputs (soon&trade;). Eventually I'd like to be be able to save or output those choices somehow, far down the road they could even be used to provide suggestions for mechanical character building like selecting a class, and distributing stats. 

Here's some front end code.
```html
<div class="col-md bg-info d-flex h-100">
	<div class="d-flex align-items-center justify-content-center w-100">
		<div id="writer-container" class="d-flex flex-column">
			<h1 id="writer-question" class="text-center">
				Welcome to The Character Writer
			</h1>
			<br />
			<div id="writer-options" class="d-flex justify-content-around"></div>
			<div class="d-flex justify-content-around">
				<button id="prev-button" class="btn" hidden>Previous</button>
				<button id="next-button" class="btn">Next</button>
			</div>
		</div>
	</div>
</div>
```

The Writer class is the controller for this page. I use a class to interact with the writer page to keep the code contained and separate from any other logic I may write. The Writer functionality is stored in one object. This keeps code organized and the global scope clean.
```js
class Writer {
			constructor(init) {
				this.$container = $("#writer-container");
				this.page = -1;
				this.$question = $("#writer-question");
				this.$options = $("#writer-options");
				this.questions = init.questions || [];
				this.choices = {};
				$("#next-button").on("click", e => this.advance());
				$("#prev-button").on("click", e => this.reverse());
				$("#writer-options").on("click", e => {
					const $target = $(e.target);
					if ($target.prop("tagName") == "BUTTON") {
						this.choices[$target.attr("data-question")] = $target.attr(
							"data-choice"
						);
						this.advance();
					}
					console.log(this.choices);
				});
			}

			_createOptionButtons() {
				return this.questions[this.page].options.map((option, index) => {
					return $("<button>")
						.addClass("btn myOption")
						.attr("id", `option-${index}`)
						.attr("data-choice", index)
						.attr("data-question", this.page)
						.text(option.text);
				});
			}

			advance() {
				console.log("Start");
				if (this.page < this.questions.length - 1) {
					this.page++;
					this.$container.attr("data-page", this.page);
					this.$question.text(this.questions[this.page].question);
					this.$options.empty();
					let optionButtons = this._createOptionButtons();
					this.$options.append(optionButtons);
					if (this.page > 0) $("#prev-button").removeAttr("hidden");
					if (this.page >= this.questions.length - 1)
						$("#next-button").attr("hidden", true);
				}
			}

			reverse() {
				if (this.page > 0) {
					this.page--;
					this.$container.attr("data-page", this.page);
					this.$question.text(this.questions[this.page].question);
					this.$options.empty();
					let optionButtons = this._createOptionButtons();
					this.$options.append(optionButtons);
					if (this.page < 1) $("#prev-button").attr("hidden", true);
					if (this.page < this.questions.length - 1)
						$("#next-button").removeAttr("hidden");
				}
			}
		}
```

I could improve this by refactoring the reverse and advance methods to move the repeated code into its own method. The code below could be moved into a new method that advance and reverse could call. I could also keep the nav buttons on the object rather than retrieving them from the DOM each time. 
```js
this.$container.attr("data-page", this.page);
this.$question.text(this.questions[this.page].question);
this.$options.empty();
let optionButtons = this._createOptionButtons();
this.$options.append(optionButtons);
```

# 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.
- [X] 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.