We will use what we have learned to build the logic to handle the data for a video store. We will do this in JS and make a node project for it.
Depending on your experience level this may be a big assignment, but it builds up in logical steps. Do not worry if you don't complete every step.
If you do finish this assignment and have time on your hands, continue adding features to the video store following the patterns you have been shown here. Feel free to reach out to an Instructor or TA if you would like additional guidance on how to do this.
- Create a new node project named "my-video-store", or, whatever you want.
- In
app.jsimportvideo-store-inventory.jsoninto a variable namedinventoryJson.
We need to do some work to use our inventory. First, each video needs a unique ID that we create (imagine this is a database primary key). The existing id attribute for each video is actually it's ID on imdb.com - which is great, but not what we need. So:
-
Use
.map()to renameidtoimdbId. -
Install the npm package uuid. An UUID (universally unique id) is an alphanumeric string generated by some sort of fancy math that is guaranteed to be unique throught the entire universe. The perfect way to make sure two videos don't have the same ID in our system!
-
Take 5 - 10 minutes to test out uuid and read the docs before doing work with it.
-
Use
.map()and for each video create a property namedid-- which should be a UUID. So each video has anidwhich is an unique UUID.
We want to know when the video was added to our system. To do this we'll want to add a createdAt property with a datetime value. To help keep our data organized, we are going to add it inside a _meta property. Here is an example of what a video record will look like now:
{
id: "8c0cf063-d505-4ff6-be5f-b90f19b97008",
imdbId: "tt6615224",
title: "A Snowy Day in Oakland",
imgUrl: "https://images.fandango.com/ImageRenderer/200/0/redesign/static/img/default_poster.png/0/images/MasterRepository/fandango/231006/asnowydayinoakland-posterart.jpg",
copiesAvailable: 0,
totalAvailable: 4,
rating: "PG-13",
description: "It snows one dat in Oakland and everybody is talking about it! Wow, it snowed! In Oakland? Wow! Someone should make a movie about this. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
_meta: {
createdAt: "2023-10-01T01:17:26.103Z"
}
}You could do this in the same .map() operation as before, or if you prefer, chain two map operations together like so:
const inventory = inventoryJson
.map(video => /* do stuff to rename `id` to `imdbId` */ )
.map(video => /* do stuff add the new `id` prop and give it a UUID */ )
.map(video => /* do stuff to add the `_meta` property with a `createdDate` to each video */ )The above approach is worth trying. Even if it is overkill in this specific case, method-chaining like this is a technique you will see used more and more, and, it offers the advantage of being able think about each step in smaller chunks - which is easier to do and easier to implement. You're less likely to make errors.
Instead of using JS's built-in Date() function by itself, use the date-fns npm module. dayjs is a popular alternative as well. Note that you'll have to install them with npm.
We need some users. We want something like the following:
const customers = [
{
id: "abxasj23498h245h", // THIS IS A UUID!!!!
name: "Alice",
email: "alice@gmail.com",
},
{
id: "s29dafor2h8h245h", // THIS IS A UUID!!!!
name: "Bob",
email: "alice@gmail.com",
},
]- Create a
makeCustomerfunction which returns a new customer object like above. - Use it to build an array like the one above.
- Go wild - add whatever other fields you want, etc.
Our program now has two kinds of data - videos and customers.
As new customers are added, old customers leave, and videos are checked out and returned, the state of our program changes. "State" is simply a term for "a snapshot of your program in a current moment."
Which means:
- The values of all the variables
- Including iterators for loops, etc
You will see why a bit more when we start using React, but it is often best with JS programs to manage state by putting it all together in a single object. We want something like:
const state = {
users: [
{ // alice },
{ // bob },
{ // bob },
// ... and so on
],
videos: [
{ // one video here },
{ // another video here },
// ... and so on
]
}Task: Create a state object for you program like the one above.
Write a function to get a customer by id. It must accept our state object as input, along with the desired customerId. It must use .filter(). It should look like this:
function getCustomerById(state, customerId) {
// does stuff with state.filter()
// returns a customer object
}- Now write a
findCustomerByEmail()function that works the same way. - Now write a
findCustomerByName()function that works the same way.
Follow the above pattern and:
- Write a
findVideoById()function - Write a
findVideoByImdbID()function - Write a
findVideoByTitle()function
- How do we know if a video has at least one copy checked out?
- Write a
findAllVideosWithCheckouts()function that follows the above patterns.
Lets add an array, checkedOut, to our customer object. It will hold the ID (our id, NOT imdbId) of each video a customer checks out.
Edge case -- w/the above system, a customer cannot check out multiple copies of the same video. This is OK, but, if you want, think of an alternate approach
Our customer object should now look like this:
{
id: "abxasj23498h245h", // THIS IS A UUID!!!!
name: "Alice",
email: "alice@gmail.com",
checkedOut: [
"8c0cf063-d505-4ff6-be5f-b90f19b97008",
"bcasdf0h2388w0yef", // <-- I made this up, this should be a UUID
]
},
{
id: "s29dafor2h8h245h", // THIS IS A UUID!!!!
name: "Bob",
email: "alice@gmail.com",
checkedOut: [], // If no videos are checked out the array is empty
},Create a checkoutVideo function. It must look like this:
function checkoutVideo(state, customerId, videoId) {
}Question: What should it return?
Answer:
- If no copies of the video are available, it returns
false. Checkout attempt failed. - If a copy is available, it returns
true. Checkout attempt was a success.
It also must update the video and customer info, so we are tracking how many copies of the video are left "in stock", and which customer checked out what video!
Now, write a returnVideo() function that returns the same way.
Refactor your program, so that it logs, in our customer object:
- A history of all videos ever checked out by the customer
- The datetime when a video was checked out.
- The datetime when a video was return.
Write a function using .filter() to get an array of all customers who have 1 or more videos checked out. Then, modify your function so that it gets all customers with at least 2 videos checked out, or at least 5 videos checked out, etc.
Then, modify your function so it it also sorts the array of customers by number of checked-out videos. The person with the most videos checked out should be first!
Add a genre to each movie. Feel free to make them up. It is up to you if a movie can have one or more genres.
Write a findVideosByGenre() function. It should follow the same pattern as our previous functions. Important: You should assume this function will sometimes return more than one video, as there normally many videos of the same genre!
Use .map() to get an array listing all genres. Make sure it is a flat array, meaning this:
['western', 'romance', 'drama', 'adventure']... and not this:
[['western', 'drama'], ['romance', 'adventure']]Use reduce() to create an object which has each genre as a property, and then an array of movie ids belonging to that genre. It should look something like this:
{
western: [ "abc123" ],
drama: [ "abc123", "xyz456", ],
romance: [ "xyz456", "dd344" ],
adventure: ["dd344"],
}
Note that a film ID may be listed under multiple genres here.