ReactJS-The Beginner Master Class
  • React In the Beginning
    • Lesson 1 - Demo: Build a Simple React App - Fast
    • Lesson 2 - HTML Review
    • Lesson 3 - CSS Review
    • Lesson 4 - Modern JavaScript (JSX) Patterns
    • Lesson 5 - Set up Dev Environment
    • Hands-on Practice
  • React Fundamentals
    • Lesson 1 - Understanding Old vs New Way of Building Web Apps - SPAs
    • Lesson 2 - Motivation for Using React as the Solution to Vanilla JS
    • Lesson 3 - What is ReactJS - How it Works
    • React Code Along from Scratch
    • Lesson 4 - Create and Run a React Project with Vite - Full Overview
    • Lesson 5 - Create Hook by State Management in React
    • Lesson 6 - React Project File and Folder Walkthrough
    • Lesson 7 - JSX and How React Treats the DOM & JSX Compilation(by Babeljs) - Overview
    • Lesson 8 - Understanding the Main Files - App.jsx and main.jsx
    • Lesson 9 - Props and One-Way Data Flow - Overview
    • Lesson 10 - Google Bookshelf App - Ver 1.0
    • Hands-on Practice I
    • Hands-on Practice II
  • React State and Styling
    • Lesson 1 - Pulling Book Data from a Different Data File
    • Lesson 2 - Overview of How State Works in React
    • Lesson 3 - RandomQuote App
    • Lesson 4 - Lifting State Up - React Pattern Overview
    • Hands-On - Simple Counter
  • Forms and Interactivity - Grocery List App
    • Lesson 1 - Setup a Simple Form and Input
    • Lesson 2 - Build Form Profile App Using Multi-input Form Data
    • Hands-on : Build a Grocery List App
  • Connecting to the Backend - Consuming APIs - UseEffect Hook
    • Lesson 1 - Connecting to the Back End - Understanding Side Effects, Hooks and useEffect - Overview
    • Lesson 2 - Fetching Data from the Backend the Right Way with useEffect Hook
    • Lesson 3 - Setting Up Loading State
    • Hands-on :Use Dependency Array and Adding Values that Control Side Effects
  • Solo Project 1
  • RESTful APIs :Build a BookSearch App -Ver 2.0
    • Lesson 1: Build and test RESTful APIs with Postman
    • Lesson 2 - BookShelf App Structure
    • Lesson 3 - Create NavBar.jsx Component
    • Lesson 4 - Create Footer Component
    • Lesson 5 - Create BookList.jsx Component
    • Lesson 6 - Create BookCard.jsx Component
    • Lesson 7 - Creating Custom Hooks - useBooks and api-client
    • Lesson 8 - Controlling Network Activities in React with AbortController
    • Lesson 9 - Show Book Details in a Modal - Working
    • Lesson 10 - Bookshelf App Summary
  • Multi-Page Applications (MPAs)
    • Build a Multi-Page React Application
    • Multi-Page React Application
    • Hands-on Practice
  • Backend Frameworks-NEXT.JS
    • Migrating from React to Next.js
    • Lesson 1: Key Concepts of NodeJS and Express for Backend Web Development
    • Lesson 2: How to set up a new Next.js project
    • Lesson 3: How to create Layouts and Pages
    • Hands-on Practice 1
    • Hands on Practice 2
      • New Project & Folder Structure
      • File-Based Routing
      • Server vs Client Components & Router Hooks
      • Start On The Navbar
      • Navbar Links, Dropdowns & React Icons
      • Active Links & Conditional Rendering
      • Homepage Components
      • Properties Page
      • Property Card Dynamic Data
      • Home Property Listings
      • Custom Not Found & Loading Pages
  • Git and GitHubs
    • Git Installation
    • Git Commands
    • GitHub Repository
    • Hands-on Practice
  • Database in Application
    • React Supabase CRUD
    • Hands-on: Note Taking App
  • NoSQL Database
    • Installing MongoDB Community Edition
    • System Env Path Setting
    • How to use MongoDB Shell
    • How to Connect and Use Mongosh in VS Code via MongoDB Extension
    • MongoDB Guide
  • Solo Project 2
  • Deployment and Web Hosting
    • Lesson 1. React+Vite+TS+Shadcn Project
    • Lesson 2. Deploying a React Vite App to Vercel from Vercel CLI
    • Lesson 3 Connecting to GitHub Repo and Automate Deployment
  • Solo Project 3
  • Final Term Project
    • Level 1 Team Project
    • Level 1 Team Project
    • Level 1 Team Project
    • Level 1 Team Project
    • Level 2 Team Project
    • Level 2 Team Project
    • Level 3 Team Project
    • Level 3 Team Project
Powered by GitBook
On this page
  • Level 1 Projects
  • 1. ATM Bank Terminal Simulator
  • Step 1: Initialize the Project
  • Step 2: Set Up Project Structure
  • Step 3: Build Components
  • Step 4: Complete App.jsx Logic
  • Step 5: Apply Styling
  • Step 6: Add Background Image
  • Step 7: Test the App
  • Step 8 (Optional): Improvements 🚀
  • Step 9: Add PIN Entry Animations
  • Step 10: Add Auto-Tab Functionality
  • Step 11: Test New Features 🚀
  • Step 12: Update Footer Component to Display Balance and Icons
  1. Final Term Project

Level 1 Team Project

PreviousFinal Term ProjectNextLevel 1 Team Project

Last updated 1 month ago

Level 1 Projects

1. ATM Bank Terminal Simulator

This guide is tailored for students who want to build an ATM terminal-like application using React and Vite frameworks, based on the files and designs you've shared.

Step 1: Initialize the Project

1. Create a new React + Vite project:

npm create vite@latest million-dollar-bank -- --template react
cd million-dollar-bank
npm install

2. Install dependencies (if you use additional ones like React Router or icons):

Step 2: Set Up Project Structure

  1. Structure your folders as follows:

/src
  /components
    Header.jsx
    Footer.jsx
    Message.jsx
  App.jsx
  main.jsx
/style.css
/index.html
  1. Add the provided App.jsx and style.css into your /src and root respectively.

// App.jsx
import React from "react"
import Message from "./components/Message"
import Header from "./components/Header"
import Footer from "./components/Footer"

export default function App() {
	const passCode = "1001"

	const [userInput, setUserInput] = React.useState({
		charOne: "",
		charTwo: "",
		charThree: "",
		charFour: "",
	})
	
	const [verified, setVerified] = React.useState(undefined)

	function handleChange(event) {
		setUserInput(prev => ({...prev, [event.target.name]: event.target.value }))
	}
	
	function handleSubmit(event) {
		event.preventDefault()
		const combinedInput = Object.values(userInput).join("")
		setVerified(combinedInput === passCode)
	}

	return (
    <div className="wrapper">
      <Header />

      <form onSubmit={handleSubmit}>
        <div>
          <input
            required
            type="password"
            name="charOne"
            maxLength="1"
            onChange={handleChange}
          />

          <input
            required
            type="password"
            name="charTwo"
            maxLength="1"
            onChange={handleChange}
          />

          <input
            required
            type="password"
            name="charThree"
            maxLength="1"
            onChange={handleChange}
          />

          <input
            required
            type="password"
            name="charFour"
            maxLength="1"
            onChange={handleChange}
          />
        </div>

        <button disabled={verified}>Submit</button>
        <Message status={verified} />
      </form>

      <Footer />
    </div>
  )
}
* {
    box-sizing: border-box;
}

body {
    margin: 0;
}

.wrapper {
    width: 100vw;
    height: 100vh;
    display: flex;
    justify-content: center;
    align-items: center;
    background: url(./images/bady-abbas-c4XoMGxfsVU-unsplash.jpg);
    background-size: cover;
    background-position: center;

}

header,
footer {
    position: absolute;
    width: 100%;
    background: #474056;
    height: 70px;
    color: #f7ece1;
    display: flex;
    justify-content: center;
    align-items: center;
    z-index: 5;
}

header {
    top: 0;
}

footer {
    bottom: 0;
}

h1 {
    margin: 0;
    font-size: 20px;
    text-align: center;
    color: #f9f8f8;
    letter-spacing: 1px;
}

span {
    color: #f9f8f8;
    font-weight: 700;
}

form {
    width: 350px;
    height: 350px;
    display: flex;
    flex-direction: column;
    align-items: center;
    border-radius: 15px;
    background: #111111bc;
    transition: 0.4s ease-in-out;
    position: relative;
}

.message-container {
    display: flex;
    flex-direction: column;
}

.message {
    position: relative;
    text-align: center;
    color: #222222;
    background: ghostwhite;
    top: 3em;
    padding: 6px;
    border-radius: 5px;
    width: 300px;
    font-weight: bold;
}

.check {
    position: relative;
    align-self: center;
    top: 24px;
    width: 130px;
    margin: 0;
}

input {
    position: relative;
    width: 2.5em;
    height: 2.5em;
    margin: 1em;
    border-radius: 5px;
    border: none;
    outline: none;
    background-color: rgb(235, 235, 235);
    box-shadow: inset 3px 3px 6px #d1d1d1, inset -3px -3px 6px #ffffff;
    top: 0.6em;
    padding-left: 15px;
    transition: 0.4s ease-in-out;
}

input:hover {
    box-shadow: inset 0px 0px 0px #d1d1d1, inset 0px 0px 0px #ffffff;
    background-color: lightgrey;
}

input:focus {
    box-shadow: inset 0px 0px 0px #d1d1d1, inset 0px 0px 0px #ffffff;
    background-color: lightgrey;
}

button {
    font-size: 17px;
    padding: 0.5em 2em;
    border: transparent;
    box-shadow: 2px 2px 4px rgba(0, 0, 0, 0.4);
    background-image: linear-gradient(to bottom, #3891a6, #1d93b7, #0094c8, #1393d9, #3c91e6);
    margin-top: 20px;
    border-radius: 4px;
}

button:hover:not(:disabled) {
    background: rgb(2, 0, 36);
    background: linear-gradient(to top, rgba(30, 144, 255, 1) 0%, rgba(0, 212, 255, 1) 100%);
    cursor: pointer;
}

button:active:not(:disabled) {
    transform: scale(0.96)
}

button:focus:not(:focus-visible) {
    outline: 0;
}

button:disabled {
    pointer-events: none;
    opacity: 0.3;
}

@media (max-height: 500px) {
    header, footer {
        display: none;
    }
}

Step 3: Build Components

  1. Header.jsx

// Header.jsx
export default function Header() {
    return <header><h1>KOIDA Financial Services</h1></header>;
}
  1. Footer.jsx

// Footer.jsx
export default function Footer() {
    return <footer><h1>Current Balance: $1,000,000</h1></footer>;
}
  1. Message.jsx

// Message.jsx
export default function Message({ status }) {
    if (status === undefined) return null;
    return (
        <div className="message-container">
            <p className="message">
                {status ? 'Access Granted. Welcome!' : 'Access Denied. Try Again.'}
            </p>
        </div>
    );
}

Step 4: Complete App.jsx Logic

Your App.jsx file is already well-implemented based on the challenge!

  • ✅ State management for user inputs.

  • ✅ handleChange() function updates state dynamically.

  • ✅ handleSubmit() prevents page reload, checks input against passCode, and sets verification state.

  • ✅ DRY (Don't Repeat Yourself) principle is followed by using common handlers.

Step 5: Apply Styling

Use the provided style.css. Add it to your main.jsx:

// main.jsx
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App.jsx';
import './style.css';

ReactDOM.createRoot(document.getElementById('root')).render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
);

Step 6: Add Background Image

Place the background image in /public/images/ folder, and ensure the path in style.css matches:

// Some code
background: url(./images/bady-abbas-c4XoMGxfsVU-unsplash.jpg);

Step 7: Test the App

Run the development server:

npm run dev

Output

Check if:

  • ✅ You can enter the 4-digit code.

  • ✅ The correct code (1001) grants access.

  • ✅ Any other code denies access.

  • ✅ Styling matches the provided screenshot.

Step 8 (Optional): Improvements 🚀

  • Auto-focus to the next input box after typing.

  • Add animations or transitions on success/fail.

  • Add sound effects for success/error.

  • Save "verified" state in localStorage.

Let's expand the app with two exciting features: PIN entry animations and auto-tab functionality!

Step 9: Add PIN Entry Animations

  1. Update the CSS for Input Animations

In your style.css, add:

@keyframes pulse {
  0% { transform: scale(1); }
  50% { transform: scale(1.1); }
  100% { transform: scale(1); }
}

input:focus {
  animation: pulse 0.3s ease-in-out;
}

This gives a nice pulse effect when typing PIN numbers.

  1. Add Shake Animation for Incorrect PIN

In style.css, add:

@keyframes shake {
  0%, 100% { transform: translateX(0); }
  25% { transform: translateX(-5px); }
  75% { transform: translateX(5px); }
}

.shake {
  animation: shake 0.3s;
}
  1. Apply Class Conditionally in App.jsx

Update your <form> tag in App.jsx to conditionally apply the shake animation:

// App.jsx snippet
<form onSubmit={handleSubmit} className={verified === false ? 'shake' : ''}>

Step 10: Add Auto-Tab Functionality

  1. Enhance handleChange() function in App.jsx:

// App.jsx snippet
function handleChange(event) {
  const { name, value, nextSibling } = event.target;

  setUserInput(prev => ({ ...prev, [name]: value }));

  if (value && nextSibling && nextSibling.tagName === 'INPUT') {
    nextSibling.focus();
  }
}

Step 11: Test New Features 🚀

Run your app and test:

  • ✅ Inputs pulse on focus.

  • ✅ Form shakes when the wrong PIN is entered.

  • ✅ Cursor auto-moves to the next input.

Modify the Footer component so as to display the balance when correct pin is entered. If PIN is entered incorrectly, warning red shield icon is displayed. If PIN is correctly verified, green shieled icon is displayed.

Step 12: Update Footer Component to Display Balance and Icons

  1. Install React Icons Library (optional but recommended):

npm install react-icons
  1. Update Footer.jsx Component:

// Updated Footer.jsx
import { FaShieldAlt } from 'react-icons/fa';
import { MdWarning } from 'react-icons/md';

export default function Footer({ status }) {
    return (
        <footer>
            {status === undefined && <h1>Please enter your PIN</h1>}
            {status === true && (
                <h1>
                    Current Balance: $1,000,000 {' '}
                    <FaShieldAlt style={{ color: 'limegreen' }} />
                </h1>
            )}
            {status === false && (
                <h1>
                    Access Denied {' '}
                    <MdWarning style={{ color: 'red' }} />
                </h1>
            )}
        </footer>
    );
}
  1. Pass Status Prop from App.jsx:

In App.jsx, update your Footer component usage:

// App.jsx snippet
<Footer status={verified} />
  1. Test:

  • ✅ Enter correct PIN → Balance with green shield icon.

  • ✅ Enter incorrect PIN → Warning with red icon.

  • ✅ Before input → Prompt message "Please enter your PIN".

Output: