get-frontend/webshop_app/mvc-emne2/README.md
2025-07-01 20:42:02 +02:00

452 lines
No EOL
14 KiB
Markdown

# MVC Webshop Application
A pure JavaScript implementation of a webshop using the Model-View-Controller (MVC) architectural pattern. This educational project demonstrates core web development concepts without external frameworks.
## 🏗️ Architecture Overview
This application follows the MVC pattern with a centralized view rendering system:
- **Model**: Handles data management and business logic
- **View**: Manages HTML generation and DOM manipulation
- **Controller**: Coordinates user interactions and data flow
## 📊 UML Diagrams
### Class Diagram
```mermaid
classDiagram
class Model {
-products: Array~Product~
-cart: Array~CartItem~
+getAllProducts() Array~Product~
+getProductById(id) Product
+addToCart(productId, quantity) boolean
+removeFromCart(productId) void
+updateCartQuantity(productId, quantity) void
+getCart() Array~CartItem~
+getCartTotal() number
+getCartItemCount() number
+clearCart() void
+saveCartToStorage() void
+loadCartFromStorage() Array~CartItem~
+initializeCart() void
}
class View {
-currentPage: string
-cartCount: number
+updateView(viewType, data) void
+generateNavbar() string
+generateProductsPage(products) string
+generateProductDetailPage(product) string
+generateCartPage(cartItems, total, itemCount) string
+createProductCard(product) string
+createCartItem(item) string
+attachEventListeners() void
+updateCartCountInNav() void
+showNotification(message) void
}
class Controller {
+loadProducts() void
+showProductDetail(productId) void
+handleAddToCart(productId) void
+handleRemoveFromCart(productId) void
+changeQuantity(productId, change) void
+handleClearCart() void
+navigateToProducts() void
+navigateToCart() void
+updateCartDisplay() void
}
class Product {
+id: number
+name: string
+price: number
+description: string
+image: string
+category: string
}
class CartItem {
+productId: number
+quantity: number
+product: Product
}
class App {
+initialize() void
}
Controller --> Model : uses
Controller --> View : updates
View --> Controller : sends events
Model --> Product : contains
Model --> CartItem : manages
CartItem --> Product : references
App --> Controller : initializes
App --> Model : sets up
App --> View : starts
```
### Sequence Diagram - Add to Cart Flow
```mermaid
sequenceDiagram
participant U as User
participant V as View
participant C as Controller
participant M as Model
U->>V: Click "Add to Cart"
V->>C: handleAddToCart(productId)
C->>M: addToCart(productId)
M->>M: getProductById(productId)
M->>M: Find existing item or create new
M->>M: saveCartToStorage()
M-->>C: return true/false
alt Success
C->>M: getProductById(productId)
M-->>C: return product
C->>V: updateView('notification', {message})
C->>C: updateCartDisplay()
C->>M: getCart()
M-->>C: return cart
C->>M: getCartTotal()
M-->>C: return total
C->>M: getCartItemCount()
M-->>C: return itemCount
C->>V: updateView('cart', {cartItems, total, itemCount})
C->>V: updateView('cart-count', {count})
V->>V: generateCartPage() or updateCartCountInNav()
V-->>U: Updated UI with notification
else Failure
C->>V: updateView('notification', {message: 'Error'})
V-->>U: Error message
end
```
## 📁 Project Structure
```
mvc-emne2/
├── index.html # Main HTML file with single app container
├── styles.css # Application styling
├── js/
│ ├── app.js # Application initialization
│ ├── model.js # Data layer and business logic
│ ├── view.js # UI rendering and HTML generation
│ └── controller.js # User interaction handling
├── flow-diagram.md # Application flow visualization
└── README.md # This documentation
```
## 🔧 Key Components
### 1. Model (`model.js`)
**Purpose**: Manages application data and persistence
**Key Functions**:
- `getAllProducts()` - Returns product catalog
- `getProductById(id)` - Retrieves specific product
- `addToCart(productId, quantity)` - Adds items to cart
- `removeFromCart(productId)` - Removes items from cart
- `updateCartQuantity(productId, quantity)` - Updates item quantities
- `getCart()` - Returns current cart contents
- `getCartTotal()` - Calculates cart total price
- `getCartItemCount()` - Returns total item count
- `clearCart()` - Empties the cart
- `saveCartToStorage()` / `loadCartFromStorage()` - LocalStorage persistence
**Data Structure**:
```javascript
// Product
{
id: number,
name: string,
price: number,
description: string,
image: string (emoji),
category: string
}
// Cart Item
{
productId: number,
quantity: number,
product: Product
}
```
### 2. View (`view.js`)
**Purpose**: Handles all UI rendering through a centralized `updateView` function
**Core Architecture**:
```javascript
function updateView(viewType, data = {}) {
switch (viewType) {
case 'products': // Render product listing
case 'product-detail': // Render single product
case 'cart': // Render shopping cart
case 'cart-count': // Update cart badge
case 'notification': // Show user messages
}
}
```
**Key Features**:
- **Single Entry Point**: All rendering goes through `updateView()`
- **Complete Page Generation**: Generates entire page HTML including navigation
- **Event Listener Management**: Automatically attaches event listeners after each render
- **Template Functions**: Modular HTML generation functions
**HTML Generation Functions**:
- `generateNavbar()` - Creates navigation header
- `generateProductsPage(products)` - Product listing page
- `generateProductDetailPage(product)` - Product detail page
- `generateCartPage(cartItems, total, itemCount)` - Shopping cart page
- `createProductCard(product)` - Individual product card
- `createCartItem(item)` - Individual cart item
### 3. Controller (`controller.js`)
**Purpose**: Handles user interactions and coordinates between Model and View
**Navigation Functions**:
- `navigateToProducts()` - Shows product listing
- `navigateToCart()` - Shows shopping cart
- `showProductDetail(productId)` - Shows product details
**Cart Management**:
- `handleAddToCart(productId)` - Adds product to cart
- `handleRemoveFromCart(productId)` - Removes product from cart
- `changeQuantity(productId, change)` - Updates product quantity
- `handleClearCart()` - Empties entire cart
- `updateCartDisplay()` - Refreshes cart view and counter
**Key Design Patterns**:
- All functions call `updateView()` for UI updates
- User notifications are handled consistently
- Cart state is automatically persisted after changes
### 4. Application Initialization (`app.js`)
**Purpose**: Bootstraps the application
**Initialization Flow**:
1. Wait for DOM to load
2. Initialize cart from localStorage
3. Load products from model
4. Render initial products page
5. Update cart counter
```javascript
document.addEventListener('DOMContentLoaded', function() {
initializeCart();
const products = getAllProducts();
const itemCount = getCartItemCount();
updateView('products', { products });
updateView('cart-count', { count: itemCount });
console.log('Nettbutikk MVC Demo initialisert!');
});
```
## 🔄 Data Flow
### 1. Application Startup
```
HTML Load → DOMContentLoaded → initializeCart() → loadCartFromStorage() →
getAllProducts() → updateView('products') → generateProductsPage() → attachEventListeners()
```
### 2. User Interactions
```
User Click → Controller Function → Model Operation → updateView() →
HTML Generation → Event Listener Attachment → UI Update
```
### 3. Cart Operations
```
Add to Cart → addToCart() → saveCartToStorage() → updateCartDisplay() →
updateView('cart') + updateView('cart-count') → showNotification()
```
## 🎨 View Rendering System
### Centralized Rendering
All UI updates flow through the single `updateView()` function:
```javascript
updateView('products', { products: [...] });
updateView('product-detail', { product: {...} });
updateView('cart', { cartItems: [...], total: 0, itemCount: 0 });
updateView('cart-count', { count: 0 });
updateView('notification', { message: 'Success!' });
```
### Complete Page Generation
Unlike traditional DOM manipulation, this system generates complete page HTML:
```javascript
function generateProductsPage(products) {
return `
${generateNavbar()}
<main>
<section class="page active">
<h2>Våre Produkter</h2>
<div class="products-grid">
${products.map(product => createProductCard(product)).join('')}
</div>
</section>
</main>
`;
}
```
### Event Listener Management
After each render, event listeners are reattached:
```javascript
function attachEventListeners() {
const productsLink = document.querySelector('[data-page="products"]');
const cartLink = document.querySelector('[data-page="cart"]');
if (productsLink) {
productsLink.addEventListener('click', function(e) {
e.preventDefault();
navigateToProducts();
});
}
// ... more listeners
}
```
## 💾 Data Persistence
### LocalStorage Integration
Cart data is automatically persisted:
```javascript
function saveCartToStorage() {
try {
localStorage.setItem('webstore_cart', JSON.stringify(cart));
} catch (error) {
console.error('Feil ved lagring av handlekurv til localStorage:', error);
}
}
function loadCartFromStorage() {
try {
const savedCart = localStorage.getItem('webstore_cart');
if (savedCart) {
const parsedCart = JSON.parse(savedCart);
return parsedCart.map(item => ({
...item,
product: products.find(p => p.id === item.productId) ||
{ id: item.productId, name: 'Ukjent Produkt', price: 0 }
}));
}
} catch (error) {
console.error('Feil ved lasting av handlekurv fra localStorage:', error);
}
return [];
}
```
## 🚀 Usage
### Running the Application
1. Open `index.html` in a web browser
2. The application initializes automatically
3. Navigate between products, product details, and cart
4. Cart state persists across browser sessions
### Key Features
- **Product Browsing**: View all products in a grid layout
- **Product Details**: Click any product for detailed view
- **Shopping Cart**: Add, remove, and modify quantities
- **Persistent Cart**: Cart contents saved in localStorage
- **Responsive Design**: Works on desktop and mobile
- **User Notifications**: Feedback for all user actions
## 🎯 Educational Benefits
### MVC Pattern Demonstration
- Clear separation of concerns
- Model handles data, View handles presentation, Controller handles logic
- Demonstrates how components interact in MVC architecture
### Modern JavaScript Features
- ES6+ syntax (arrow functions, template literals, destructuring)
- LocalStorage API usage
- Event handling patterns
- Functional programming concepts
### Web Development Fundamentals
- DOM manipulation techniques
- Event listener management
- Client-side state management
- HTML generation and templating
- CSS styling integration
## 🔧 Technical Decisions
### Why Centralized Rendering?
- **Consistency**: All UI updates follow the same pattern
- **Maintainability**: Easy to track and debug UI changes
- **Scalability**: Simple to add new view types
- **State Management**: Clear data flow from model to view
### Why Complete Page Generation?
- **Simplicity**: No complex DOM diffing or state tracking
- **Reliability**: Fresh render eliminates stale state issues
- **Performance**: Modern browsers handle innerHTML efficiently
- **Debugging**: Easy to see exactly what HTML is generated
### Why LocalStorage?
- **Persistence**: Cart survives browser restarts
- **Simplicity**: No server-side complexity
- **Performance**: Instant load times
- **Educational**: Demonstrates client-side storage concepts
## 🎨 Styling Architecture
The application uses a clean, modern CSS design:
- Responsive grid layouts
- Card-based product display
- Consistent button and form styling
- Mobile-friendly navigation
- Smooth transitions and hover effects
## 🔮 Future Enhancements
This MVC implementation serves as a foundation for progressive enhancement:
1. **Phase 2**: Add TypeScript for type safety
2. **Phase 3**: Implement Vue.js for reactive UI
3. **Phase 4**: Add user authentication
4. **Phase 5**: Integrate payment processing
5. **Phase 6**: Add product search and filtering
6. **Phase 7**: Implement real backend API
## 📚 Learning Outcomes
By studying this codebase, you'll understand:
- MVC architectural pattern implementation
- Client-side state management techniques
- Modern JavaScript development practices
- HTML generation and templating approaches
- Event-driven programming patterns
- LocalStorage API usage
- Responsive web design principles
---
*This project is part of the GET Frontend Development curriculum, demonstrating core web development concepts through practical implementation.*