Git Product home page Git Product logo

vhs-frontend-lab's Introduction

VHS Rental shop - Blast from the past

Welcome to our frontend laboratory exercise deisgned for aspiring frontend developers like you who want to work with us on amazing projects. :) Here you will find the task description along with its requirements. At the end, there is a guidance section where you will find notes on what to do before you start working on the task and technologies you may use.

Keep in mind that it's not neccessary for you to fulfill all the requirements for us to consider you as a worthy candidate. We understand that sometimes you might have other pressing issues or you just have a lot of hobbies or even tasks you're doing for other interviews. Of course, the more you deliver and the cleaner your solution is, we will be able to assess your level of knowledge and experience better.

Let's go on with the task description now. We wish you happy coding and good luck with this assignment! :D

We are creating a cutting edge VHS rental application management system for our special clients that value the old time retro VHS experience.

img_1.png

VHS Rental Application

Think of this application as a digital VHS shop. We would expect such an application to provide an interface where users could browse the VHS catalogue, see details on specific items and maybe even be able to search through the catalogue by typing a term in a text input.

If you were the manager of such VHS shop, an application like this would be expected to provide functionality of creating new VHS items for the catalogue, as well as being able to update existing VHS items or deleting them from the catalogue altogether.

We will make things a little bit simpler for this version of the lab by not including user management in the frontend. That means that functionalities like login, registration, forgotten/reset password or logout are not necessary. Every user can access all the functionalities.

Additionally, we will provide you with a finished VHS backend service that you can just run and start sending HTTP requests to it and it will just work (unless it doesn't, in which case just email us and will solve the issue :D).

This brings us to the question of what then needs to be done exactly? Well, here is a list of requirements.

Requirements

  • make a screen that represents the VHS catalogue (list all VHS items available)
  • make a screen where the user can see details of a specific VHS item (screen where the user ends up when they click on an item in the catalogue)
  • make a screen where the user can create a new VHS item that will be submitted to the catalogue (there needs to be a form that the user fills out and then submits it)
  • when creating a new VHS item, allow the user to upload a thumbnail image of the movie (see additional info below)
  • make a screen where the user can edit an existing VHS item (same form as when creating a new VHS item, but this time the form is automatically filled with existing data and the user can edit it)
  • make it possible for the user to delete an existing VHS item
  • add a simple search input on the VHS list page where the user will be able to search the catalogue by item title
  • all of above operations need to communicate with the provided backend service (e.g. using axios)
  • don't forget to do simple routing between pages (selecting a VHS item goes to details page, but user should be able to return to the homepage by clicking some navigation button etc.)

Additional info:

  • when creating new VHS items, you need to have the following fields
    • title (movie name)
    • description (short description of the movie, like a synopsis)
    • genre (movie genre)
    • duration (movie length, in minutes)
    • releasedAt (year of movie release)
    • rentalPrice (price of rental, an integer)
    • rentalDuration (length of one rental in days, e.g. 3 days)
    • quantity (how many tapes of this item are currently available in the shop)
    • thumbnail (small image that represents the movie, it needs to be uploadable from the user's computer)
  • all of those fields need to be editable as well as show up on the details page of a VHS item

Bonus requirements related to UI/UX Design

This is an optional list of requirements that you can try to fulfill if you have some past experience with UI/UX Design. Sometimes we need to work out what our screens are going to look like before implementation and it's always a bonus if you can help out in this manner. Keep in mind that the development part is of the highest priority here, so if you don't have too much time it's better to deliver more code than design. :)

For making screen designs, you can use whatever you see fit. Some of us who tried working with UI/UX used Figma, so this is our preference.

You can do whatever you want considering the design. You have full freedom here. :)

  • create a Figma design for each screen mentioned in the main requirements
    • VHS item list
    • VHS item details
    • create new VHS item form
    • edit existing VHS item form

Guidance:

Setup your account and repository

  1. Setup your GitHub account if you don't already have it
  2. Fork your own repository from the original one
  3. Create your own branch
  4. Add your mentor as member to your repository with role Maintainer

Run provided backend service

In this repo you can see the vhs-backend folder which contains a finished VHS backend application written in NestJS (a backend framework based on NodeJS). For details on how to run it, you can check out the README.md file in vhs-backend folder. You will need to have Docker and NodeJS 16 installed for that, but you will find more details in the backend readme file.

The backend also contains the REST API specification you will need to complete this assignment. It uses Swagger UI which is available at http://localhost:3000/api once you run the backend server. There you will find all API routes you can call from your frontend as well as their detailed description (what they take as input in the request and return as a response).

If you're not able to run the backend or something doesn't work, contact us and we will help you with it.

Tech stack

We use React + Typescript to write frontend for our projects so we would prefer if you also used React. However, it is not necessary at all. If you have more experience writing in Vue.js, Angular, Svelte, or just pure JavaScript that's good as well, feel free to implement the solution however you know.

Usage of Typescript is a bonus, but also not necessary. Additionally, your application can be a classic Single Page Application (SPA), but you can also use technologies like NextJS which allows server side rendering or incremental site regeneration and other cool features.

Just don't write a mobile app, we're targeting browsers, so the only requirement is that your build uses HTML, CSS and JavaScript. :)

vhs-frontend-lab's People

Contributors

ipetk avatar frle10 avatar

Stargazers

 avatar

vhs-frontend-lab's Issues

Filter VHS using backend query params

{searching
? filteredList.map(
(item) =>
item.id && (
<VhsThumbnail
key={item.id}
image={
item.thumbnail
? item.thumbnail.replace(/\\/g, "/")
: placeholder
}
vhsId={item.id}
vhsTitle={item.title}
/>
)
)
: vhsList.map(
(item) =>
item.id && (
<VhsThumbnail
key={item.id}
image={
item.thumbnail
? item.thumbnail.replace(/\\/g, "/")
: placeholder
}
vhsId={item.id}
vhsTitle={item.title}
/>
)
)}

  • backend GET route for all VHS takes query params with which you can filter VHS tapes by name, description, genre and such, look it up and use it so that you can get rid of filteredVHS

Set up and fully implement i18n

I18n or internationalization is a technique we use in coding projects that solves the issue of "content shouldn't live in code".

When we have components that show some textual content we never want to hardcode strings into the code, but rather extract them into structured JSON files where we can put them under certain keys and then we use the keys in the code.

This way it's possible to make several JSON objects with the same keys but different values depending on the active language on user's system for example, and that's localization.

Set up i18n in your project and implement it (extract all strings you have hardcoded). Use https://react.i18next.com/getting-started

Migrate from CRA to Vite

This app uses create-react-app as dev tooling. Let's migrate that to Vite to get all the benefits of faster performance when hot reloading, bundling and cold starting the app.

Use finally in try/catch if running identical logic

const deleteEntry = async () => {
try {
const response = await axios.delete(`/api/vhs/${VHS.id}`);
console.log(response);
navigate('/explore');
} catch (error) {
console.error(error);
navigate('/explore');
}
};

You have the same navigate statement called both in try and catch. Use the finally clause to run the shared statement.

https://www.w3schools.com/jsref/jsref_try_catch.asp

Clean up package.json

{
"name": "vhs-frontend",
"version": "0.1.0",
"private": true,
"proxy": "http://localhost:3000",
"dependencies": {
"@hookform/resolvers": "^2.9.10",
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
"@types/jest": "^27.5.2",
"@types/node": "^16.18.3",
"@types/react": "^18.0.25",
"@types/react-dom": "^18.0.9",
"axios": "^1.1.3",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-hook-form": "^7.40.0",
"react-router-dom": "^6.4.3",
"react-scripts": "5.0.1",
"typescript": "^4.9.3",
"web-vitals": "^2.1.4",
"zod": "^3.20.2"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}

  • install prettier to dev dependencies and set up .prettierrc.json file and .prettierignore file in project root
  • move all @types/* packages to dev dependencies

Handle non existing routes with the NotFound component

Currently you have a dedicated route for /not-found. What happens if the user enters your domain and inputs a path that your router doesn't handle, like /denfiuaebrfur? React-router enables us to handle such a case as well. Make it so that non existing routes all navigate to the NotFound component.

Error when deleting VHS entry

When using a DELETE request to delete a VHS that doesn't have a thumbnail, server responds with 500 - works fine when deleting a VHS that has a thumbnail.

WTR:
Make a DELETE request for a VHS that doesn't have a thumbnail. Observe server response.

Expected result:
Server responds with 204, as it does when deleting a VHS with a thumbnail, deletes VHS.

Actual result:
Server responds with 500, "Internal server error", deletes VHS.

Additional info:

[Nest] 5084  - 11/22/2022, 11:58:24 AM   ERROR [ExceptionsHandler] The "path" argument must be of type string or an instance of Buffer or URL. Received null
TypeError: The "path" argument must be of type string or an instance of Buffer or URL. Received null
    at Object.unlink (node:fs:1752:10)
    at VhsService.deleteVhs (F:\Frontend\Projects\vhs-frontend-lab\vhs-backend\src\vhs\vhs.service.ts:62:8)
    at processTicksAndRejections (node:internal/process/task_queues:96:5)
    at F:\Frontend\Projects\vhs-frontend-lab\vhs-backend\node_modules\@nestjs\core\router\router-execution-context.js:46:28
    at F:\Frontend\Projects\vhs-frontend-lab\vhs-backend\node_modules\@nestjs\core\router\router-proxy.js:9:17

fs.unlink(vhs.thumbnail, (error) => {

Add eslint configuration to the project

It's important to use linters in coding projects because they make sure your codebase follows a set of rules that will make it consistent, more readable and follow some best practice guidelines.

For frontend projects, we use a tool called ESLint: https://eslint.org/

Do some research on how this works and how it is configured and then configure some eslint rules on the project. Feel free to use any guides online and extend existing plugins for eslint rules.

Improve Header component

import React from "react";
import { Link } from "react-router-dom";
type Props = {};
export default function Header({}: Props) {
return (
<div>
<Link to="/">Home</Link> <br />
<Link to="/explore">Discovery</Link> <br />
<Link to="/create">Create new VHS</Link> <br />
</div>
);
}

Remove Props if not used. If used, make it an interface instead of type.
Additionally, links are separated with a <br> tag, let's change that and make a flex container with horizontal direction and beautify the navbar with CSS. :)

Add husky

In order to make sure that our whole project is properly linted and formatted, especially when working in a team, we sometimes need to run some actions on our codebase while performing a git commit or git push.

There is a tool that enables us to do this in Node based projects and it's called Husky: https://typicode.github.io/husky/#/

Read about how it works and set it up in your project. On all commits, run eslint and prettier to lint and format the whole project.

Add Dockerfile to frontend project

It's common practice nowadays to use containerization for all services we deploy to the web. Since this is a new topic for you, I will route you to Docker's getting started documentation: https://docs.docker.com/get-started/

This section has 10 parts in the sidebar which you should read to start understanding the basics of containerizing an application. Also, this video is a gem: https://www.youtube.com/watch?v=d-PPOS-VsC8&list=PLvjWHH6VW-WJJHRLp9kdpupCi6O9QXn2I&index=31

When you get to know Docker a bit, try to construct a Dockerfile for your frontend application. Also, include a .dockerignore file.

Improve VHS Details component

import React, { useEffect, useState } from "react";
import { Link, useParams, useNavigate } from "react-router-dom";
import { VHS } from "../types";
import axios from "axios";
import Edit from "./Edit";
// @ts-ignore
import placeholder from "../assets/placeholder.jpg";
type Props = {};
export default function VHSDetails({}) {
function convertDuration(duration: number) {
const hours = Math.floor(duration / 60);
const minutes = duration % 60;
return `${hours}:${minutes}`;
}
const { vhsId } = useParams();
const notFoundLink = useNavigate();
const [vhsInfo, setVhsInfo] = useState<VHS>();
const fetchSingleVHS = async () => {
try {
const response = await axios.get(`/api/vhs/${vhsId}`);
setVhsInfo(response.data);
} catch (err) {
console.log(err);
notFoundLink("/notfound");
}
};
useEffect(() => {
fetchSingleVHS();
}, []);
return (
<div>
{vhsInfo && (
<div>
<h1>{vhsInfo.title}</h1>
<div>Description: {vhsInfo.description}</div>
<div>Duration: {convertDuration(vhsInfo.duration)}</div>
<div>Genre: {vhsInfo.genre}</div>
<div>Release year: {vhsInfo.releasedAt}</div>
<div>Rental price: {vhsInfo.rentalPrice} coins</div>
<img
src={
vhsInfo.thumbnail
? vhsInfo.thumbnail.replace(/\\/g, "/")
: placeholder
}
alt=""
/>
<Link to="/edit" state={vhsInfo}>
<button>EDIT</button>
</Link>
</div>
)}
</div>
);
}

  • find another image that is either SVG or PNG and get rid of that ts-ignore
  • move convertDuration function outside of component somewhere to utils

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.