-
-
Notifications
You must be signed in to change notification settings - Fork 148
feat: add a prototype for the Guild Loot Tracker workshop #1078
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
Sebastian-Wlo
wants to merge
21
commits into
freeCodeCamp:main
Choose a base branch
from
Sebastian-Wlo:lab-nutrient-tracker-dictionary
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
21 commits
Select commit
Hold shift + click to select a range
7da31bd
feat: add prototype for Nutrient Tracker Dictionary lab prototype
Sebastian-Wlo c2ca3e7
feat: add user-stories.md to the nutrient tracker prototype
Sebastian-Wlo fba7edb
chore: renamed "lab-nutrient-tracker-dictionary" directory
Sebastian-Wlo 492458a
docs: change "nutrient tracker" references in lab's "user-stories.md"
Sebastian-Wlo d790e41
refactor: rewrite of "nutrient tracker" functions
Sebastian-Wlo d510dcb
docs: changed the lab's summary section to be more descriptive
Sebastian-Wlo b59a232
refactor: change "listTopMembers" function to "listMembers"
Sebastian-Wlo 789a19f
docs: remove the "listTopMembers" mentions from "user-stories.md", ad…
Sebastian-Wlo 615c8a5
refactor: removed users stories for Guild Loot Tracker
Sebastian-Wlo c1777d2
refactor: restructured Guild Loot Tracker prototype
Sebastian-Wlo 686091e
chore: remove the "lab-" prefix from the prototype's directory name
Sebastian-Wlo 3b7695f
feat: add listMemberNames() function that introduces Object.keys() me…
Sebastian-Wlo cb705ae
refactor: rewrite getMemberTotal() to return an object or `false`
Sebastian-Wlo 77284da
refactor: rewrite 'listMembers', 'getMemberTotals', and 'addLootEntry…
Sebastian-Wlo 16cace1
refactor: change the guild members' names
Sebastian-Wlo 529235e
refactor: changes the loop in listMemberNames function to 'for...in' …
Sebastian-Wlo fd83374
refactor: change loops in addLootEntry() to 'for...in', fix the order…
Sebastian-Wlo 2a4c46e
feat: use 'getMemberTotals()' function to introduce 'Object.entries()…
Sebastian-Wlo e15cac6
refactor: use 'listMembers()' to introduce only the 'Object.values()'…
Sebastian-Wlo ad044a5
style: format the script for consistency and readability
Sebastian-Wlo 4f63860
chore: update comments to reflect steps of the workshop
Sebastian-Wlo File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
174 changes: 174 additions & 0 deletions
174
fullstack-cert/js-projects/guild-loot-tracker/script.js
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,174 @@ | ||
| // This will be a workshop for the Loops section, probably after the "Build a Profile Lookup" lab. Probably around 32 steps. | ||
|
|
||
| // The "guild" object could be already provided, or created over 3 or so steps (creating "guild" object itself and adding the first "guild member" object as the first property - rest of the "guild members" can be filled out somewhere between the next steps to avoid too much repetition). | ||
| let guild = { | ||
| ethan: { | ||
| gold: 31, | ||
| silver: 48, | ||
| reputation: 9, | ||
| experience: 198, | ||
| }, | ||
| elara: { | ||
| gold: 78, | ||
| silver: 64, | ||
| reputation: 12, | ||
| experience: 111, | ||
| }, | ||
| brandon: { | ||
| gold: 41, | ||
| silver: 7, | ||
| reputation: 7, | ||
| experience: 70, | ||
| }, | ||
| dylan: { | ||
| gold: 81, | ||
| silver: 2, | ||
| reputation: 20, | ||
| experience: 220, | ||
| }, | ||
| lucas: { | ||
| gold: 34, | ||
| silver: 28, | ||
| reputation: 10, | ||
| experience: 179, | ||
| }, | ||
| natalie: { | ||
| gold: 36, | ||
| silver: 81, | ||
| reputation: 12, | ||
| experience: 82, | ||
| }, | ||
| }; | ||
|
|
||
| /* NOTE: | ||
| This method seemed like a good addition before I refactored `listMembers()` - it still might be a good(?), isolated example of `Object.keys()` use, but otherwise seems slightly redundant. | ||
| */ | ||
| // 'listMemberNames()` introduces `Object.keys()` static method, and provides a list of current members of the guild. Could be 3 steps: | ||
| // 1. create a function, | ||
| // 2. assign the array returned by the `Object.keys()` to a variable + explanation of the method, | ||
| // 3. for loop and `console.log()` methods for the name, | ||
| function listMemberNames(guildObject) { | ||
| console.log("Current Guild Members:"); | ||
| const guildMembers = Object.keys(guildObject); | ||
| for (const member in guildMembers) { | ||
| console.log(`${parseInt(member) + 1}. ${guildMembers[member]}`); | ||
| } | ||
| } | ||
|
|
||
| listMemberNames(guild); | ||
|
|
||
| // `listMembers()` introduces `Object.values()`. Probably good for about 4 steps: | ||
| // 1. Create a new function and add a `console.log()` with the function's description, | ||
| // 2. Create a `for()` loop, and log the `Object.values()`, | ||
| // 3. Replace the `console.log()` for the `Object.values()` with destructuring, | ||
| // 4. add the 3 `console.log()` for the member's name, value names and the destructured values | ||
| function listMembers(guildObject) { | ||
| console.log("Guild Member's Resources:"); | ||
| for (const member in guildObject) { | ||
| const [gold, silver, reputation, experience] = Object.values( | ||
| guildObject[member], | ||
| ); | ||
|
|
||
| console.log(`${member}:`); | ||
| console.log("gold\tsilver\treputation\texperience"); | ||
| console.log(`${gold}\t${silver}\t${reputation}\t\t${experience}`); | ||
| } | ||
| } | ||
|
|
||
| listMembers(guild); | ||
|
|
||
| // 'getMemberTotals()` introduces `Object.entries() method. | ||
| // 1. Create a function and assign `Object.entries()` to a variable, | ||
| // 2. Use `console.log()` to see what has been assigned to the variable | ||
| // 3. Remove the `console.log()` and create a `for()` loop, add `return false` statement, | ||
| // 4. Destructure `guildMember` inside the `if()` conditional, add `return entry` | ||
| function getMemberTotals(guildObject, member) { | ||
| const guildMembers = Object.entries(guildObject); | ||
|
|
||
| for (const guildMember of guildMembers) { | ||
| const [name, entry] = guildMember; | ||
| if (member === name) { | ||
| return entry; | ||
| } | ||
| } | ||
| return false; | ||
| } | ||
|
|
||
| // Checks for validating `getMemberTotals()` is working correctly - can be one of the steps and removed later | ||
| console.log(getMemberTotals(guild, "natalie")); | ||
| console.log(getMemberTotals(guild, "francis")); | ||
|
|
||
| // "cloneGuildData()" can be broken into multiple (4?) steps, showing that using the spread syntax creates a shallow copy of the object (and explaining how it prevents accidental mutations) for example: | ||
| // 1. Write the function and assign the input parameter to one variable directly, and via the spread operator to a second variable, then call the function, | ||
| // 2. Modify the content of the first variable, then use `console.log()` to compare the original input parameter, and both variables, showing that modifying the direct copy modified the original as well, | ||
| // 3. Modify the shallow copy to show it didn't affect the original | ||
| // 4. Remove the variables and the function call, write the final version of the function. | ||
| function cloneGuildData(guildObject) { | ||
| return { ...guildObject }; | ||
| } | ||
|
|
||
| function addLootEntry(guildObject, entry) { | ||
| // 1. Use cloneGuildData() to get a copy of the first input parameter, | ||
| const clonedGuild = cloneGuildData(guildObject); | ||
| // 2. Use `Object.keys() to get a list of guild member's names, and use the spread operator to separate data from the second parameter | ||
| const guildMemberNames = Object.keys(guildObject); | ||
| const { member: memberName, ...newMemberTotals } = entry; | ||
| // 3, 4. Write conditional checking to validate the member's name exists, and is a string | ||
| if (!memberName) { | ||
| console.log("New entry must include a name of the guild member!"); | ||
| return; | ||
| } else if (typeof memberName !== "string") { | ||
| console.log("Member name must be a string!"); | ||
| return; | ||
| } | ||
| // 5. Add a `for()` loop iterating over the guild member's names, add the `console.log()` and a return statement after it (I just realized that `return` is kind of pointless...), Check if the guildObject includes a record of the provided member, | ||
| for (const guildMember in guildMemberNames) { | ||
| // 6. Write a `if()` statement for finding the name provided in the second input parameter, then get this guild member's data with `getMemberTotals()` and assign it to a variable for readability (we're not making a copy of the object! it could be worth pointing out the difference in the steps), | ||
| if (guildMemberNames[guildMember] === memberName) { | ||
| const currentMemberTotals = getMemberTotals(clonedGuild, memberName); | ||
| // 7. Add a `for()` loop to iterate over the member's resources, | ||
| for (const resource in currentMemberTotals) { | ||
| // 8. Add a `if()` statement to check if the new data is missing one of the values - if it does, end the function execution if it does, | ||
| if (!Object.hasOwn(newMemberTotals, resource)) { | ||
| console.log(`Updated data is missing an entry for "${resource}"!`); | ||
| return; | ||
| } else if ( | ||
| // 9. Add the else if statement to check if the new value is of the same type as the current one, return early if it isn't | ||
| typeof newMemberTotals[resource] !== | ||
| typeof currentMemberTotals[resource] | ||
| ) { | ||
| console.log( | ||
| `"${resource}" must be a ${typeof currentMemberTotals[resource]}!`, | ||
| ); | ||
| return; | ||
| } | ||
| // 10., 11. Then, check if the new entry has ONLY the required resources (could be just one step, but it might be a bit too confusing), | ||
| for (const resource in newMemberTotals) { | ||
| if (!Object.hasOwn(currentMemberTotals, resource)) { | ||
| console.log(`Updated data has an unknown entry "${resource}!`); | ||
| return; | ||
| } | ||
| } | ||
| // 12. Since at this point the new data passed all of the guard clauses, we can overwrite the old data | ||
| currentMemberTotals[resource] = newMemberTotals[resource]; | ||
| } | ||
| // 13. Finally, now we're sure our input was correct, we can overwrite the old data, inform the user the operation was successful, and exit the function. | ||
| guild = clonedGuild; | ||
| console.log("Guild roster updated."); | ||
| return; | ||
| } | ||
| } | ||
| console.log(`${memberName} is not a member of this guild!`); | ||
| return; | ||
| } | ||
|
|
||
| // Last step: use `AddLootEntry() to change the guild member's resources, and use `listMembers()` to see if it worked. | ||
| addLootEntry(guild, { | ||
| member: "natalie", | ||
| gold: 1, | ||
| silver: 2, | ||
| reputation: 3, | ||
| experience: 4, | ||
| }); | ||
|
|
||
| listMembers(guild); | ||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.