Passa al contenuto principale

Cash Register

Anteprima Cash Register Project Mobile UI Anteprima Cash Register Project Desktop UI

Il Progetto

Cash Register sviluppato con JavaScript vanilla e architettura OOP, implementando algoritmi greedy, calcoli precisi con interi e gestione completa dello stato della cassa. Un'applicazione che dimostra pattern di validazione, calcolo del resto ottimale e design skeuomorfico.

Codice Sorgente

<!-- DESIGN
------
* This file contains the HTML structure of the Cash Register application.
* The architecture follows this flow:
* - Head with meta tags and the Google Font 'Roboto Mono', was chosen as the font to realistically simulate the
* monospaced, dot-matrix style of a thermal receipt printer
* - Body containing a <main> element
* - Inside <main>, a primary <div> ".receipt-container" is used to display the SVG background (the paper receipt)
* - A child <div> ".receipt-content" is nested inside the container to hold all the actual UI content (text, form, etc.).

* The UI content itself is semantically structured into three main blocks:
* - .receipt-header: Contains the main title and terminal ID
* - .receipt-body: Contains the core interactive elements (form, input, button) and the output area (#change-due)
* - .receipt-footer: Contains the closing messages and transaction ID.
-->

<!DOCTYPE html>
<html lang="en">
<head>
<title>Cash Register</title>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="styles.css">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Roboto+Mono:wght@300;400;700&display=swap" rel="stylesheet">
</head>

<body>

<!--
* freeCodeCamp instructions:
* - You should have an input element with an id of "cash"
* - You should have a div, span, or p element with an id of "change-due"
* - You should have a button element with an id of "purchase-btn"
-->

<main>

<div class="receipt-container">
<div class="receipt-content">
<div class="receipt-header">
<h1>CASH REGISTER</h1>
<p>TERMINAL #09-FCC</p>
</div>
<div class="receipt-body">
<div class="total">
<p>TOTAL</p>
<p>$19.50</p>
</div>
<p>-------------------------------</p>
<form id="cash-register-form">
<label for="cash">CASH PAID</label>
<div class="user-input">
<input type="number" id="cash" name="cash" placeholder="0.00" step="0.01" min="0" required>
</div>
<button type="button" id="purchase-btn" class="cta-button">PROCESS PAYMENT</button>
</form>
<p>-------------------------------</p>
<div id="change-due"></div>
<p>-------------------------------</p>
</div>
<div class="receipt-footer">
<p class="tribute"><a href="https://www.freecodecamp.org/" target="_blank" rel="noopener noreferrer" aria-label="Visit freeCodeCamp website (opens in new tab)">Trans. ID: FCC-CERT-PROJECT-09</a></p>
<p>THANKS FOR VISITING!</p>
</div>
</div>
</div>

</main>

<script src="script.js"></script>
</body>

</html>

Il Traguardo: Google UX Certificate

Ho conseguito il Google UX Certificate completando gli ultimi 2 corsi che mi mancavano e realizzando altri 2 progetti richiesti per ottenerlo.
Sono state due settimane molto intense e sono veramente contento di quanto fatto.

Il Cash Register Project

Nei certification project, come questo, documento la maggior parte delle scelte tecniche direttamente nel codice, incluse le scoperte fatte durante lo sviluppo. Non c'è quindi molto da aggiungere qui.
Nonostante ciò, ci tengo però a evidenziare alcuni aspetti. In primo luogo sono entusiasta di aver creato immagini incredibilmente leggere senza sacrificare la grafica.

Lo scontrino SVG - 2 KB:
Il risultato è stato ottenuto grazie a Figma, dove ho creato lo scontrino con un rettangolo e lo strumento penna. Essendo SVG nativi, ho semplicemente raggruppato i vari elementi ed esportato come SVG. Risultato: 2 KB!

Il background ottimizzato - 70 KB:
Inizialmente avevo scelto un'immagine diversa: un tavolo con una fetta di pane e foglia d'insalata. Purtroppo non offriva un buon contrasto e pesava ben 2 MB. Ho quindi effettuato una nuova ricerca nelle librerie di stock fotografico, cogliendo l'occasione per aggiornare la mia cartella Tools sul desktop con i migliori strumenti per immagini.
Ho preso ispirazione da un'illustrazione e ho utilizzato Imagen (tool nel workspace Gemini). Dato che la qualità iniziale era scarsa, ho applicato upscaling con uno dei tool nella cartella. Dopodiché, grazie a ImageOptim, l'immagine è scesa ulteriormente di peso mantenendo l'estetica intatta.
Risultato: qualità altissima e peso di soli 70 KB!

La logica con classi OOP:
Ho documentato tutto all'interno del codice. Ho voluto utilizzare le classi per esercitarmi e fortunatamente si è rivelata un'ottima scelta, sebbene sia una soluzione più complessa del necessario rispetto a quanto richiesto per superare i test freeCodeCamp.

Gli Altri Due Progetti per Google UX

Maintenance App Website:
Il primo è stato un semplice sito web. Ho deciso di non seguire altre tracce, bensì di riprendere la Maintenance App immaginando di vendere quel servizio. Ecco il risultato:

Maintenance App Website, versione desktop e mobile

Versione Desktop

Maintenance App Desktop Website


Versione Mobile

Maintenance App Mobile Website

Mosaic: Il Progetto del Cuore

Il terzo progetto per la certificazione è stato il più significativo: Mosaic, un tool AI per psicoterapeuti. Considerata la profondità del visual design (analisi del Liquid Glass, Accessibilità) e la filosofia Open Source, l'ho trattato come un UI Design Concept a sé stante.

Vai al Concept di Mosaic

Cosa Ho Imparato

Architettura OOP Avanzata:

  • Classi ES6 per incapsulare logica operativa complessa
  • constructor() per inizializzazione e preparazione dati
  • Metodi privati (#calculateChange) per proteggere logica interna
  • Separazione responsabilità tra preparazione e calcolo

Strutture Dati Moderne:

  • Map invece di oggetti per gestione chiave-valore più consistente
  • Accesso uniforme ai dati: .get() e .set() vs notazioni miste
  • Iterazione con .forEach() su Map per logica più pulita

Algoritmi Greedy:

  • Strategia "best choice at the moment" per calcolo resto ottimale
  • Pre-sorting delle denominazioni da maggiore a minore
  • Loop while per dispensare massimo numero di ogni denominazione
  • Comprensione limiti: funziona solo con sistemi monetari standard

Calcoli Precisi con Interi:

  • Problema floating-point: 0.1 + 0.2 !== 0.3 in JavaScript
  • Conversione dollari → centesimi all'input per precisione
  • Math.round() per arrotondamento sicuro
  • Riconversione centesimi → dollari solo all'output

Validazione Input Robusta:

  • Guard clauses per controlli precondizione
  • isNaN() per validare numeri
  • Gestione casi edge: cash esatto, insufficiente, maggiore
  • Alert informativi per feedback immediato

Gestione Stati Transazione:

  • Status INSUFFICIENT_FUNDS quando impossibile dare resto
  • Status CLOSED quando resto svuota completamente il cassetto
  • Status OPEN per transazioni standard con resto parziale
  • Return di oggetti strutturati: {status, change}

Ottimizzazione Immagini:

  • SVG nativi da Figma: 2 KB per grafica vettoriale
  • Imagen (Gemini) per generazione illustrazioni
  • Upscaling AI per migliorare qualità senza peso
  • ImageOptim per compressione finale: 2 MB → 70 KB

Design Skeuomorfico:

  • Radial gradient per simulare input dots su receipt
  • background-size e background-repeat per pattern
  • Font Roboto Mono per simulare stampante termica
  • Transform rotate per imperfezioni realistiche

Mobile-First con Variabili CSS:

  • Tutti i valori centralizzati in :root variables
  • Media query che sovrascrive solo le variabili necessarie
  • Fallback 100vh + 100dvh per gestire barra URL dinamica iOS
  • Conditional loading: SVG receipt diversi per mobile/desktop

Event Handling Avanzato:

  • blur event per fix scroll iOS dopo input focus
  • keydown con Enter per submit alternativo
  • preventDefault() per controllare comportamento form
  • Istanza classe ricreata ad ogni click per test freeCodeCamp

Array Methods Funzionali:

  • .find() per cercare valore denominazione in DENOMINATIONS
  • .forEach() per iterare su Map cashInDrawer
  • .map() per formattare array change in stringa
  • .join() per concatenare stringhe di output

Prossimo Progetto: Imparare Fetch e Promises costruendo una pagina degli autori di freeCodeCamp