second commit
This commit is contained in:
parent
0d337a818f
commit
bffdcf4bdf
16 changed files with 2366 additions and 4 deletions
452
webshop_app/mvc-emne2/README.md
Normal file
452
webshop_app/mvc-emne2/README.md
Normal file
|
@ -0,0 +1,452 @@
|
|||
# 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.*
|
Loading…
Add table
Add a link
Reference in a new issue