clc04 Tmhung Ass4
clc04 Tmhung Ass4
com/finetglazer/Project-Django
1. Customer The Customer actor represents end-users who utilize the e-commerce platform
to browse and purchase products. These individuals are the primary revenue generators for
the business and require a seamless, intuitive user experience. Customers may be either
anonymous (not logged in) with limited functionality or authenticated users with full access to
personalized features. They interact primarily with the front-end interface of the application
and require no special technical knowledge to operate the system effectively.
2. Staff The Staff actor encompasses employees of the organization who manage the
operational aspects of the e-commerce platform. This includes inventory managers, product
catalog administrators, order processors, and customer service representatives. Staff
members require administrative access to backend functionalities that are not exposed to
regular customers. They perform critical business operations that ensure the smooth
functioning of the e-commerce ecosystem.
3. System The System actor represents automated processes and background services that
operate independently without direct human intervention. These include scheduled tasks,
notification services, inventory management systems, and integration points with external
services such as payment gateways and shipping providers. The System actor ensures that
critical business processes continue to function reliably without requiring constant human
supervision.
CUST-00 Add to Cart Allows users to select products for potential purchase High
6 by adding them to a virtual shopping cart.
CUST-00 View Cart Displays all products currently in the user's cart, High
7 including quantities and calculated total prices.
CUST-00 Remove Enables users to remove unwanted items from their Mediu
8 from Cart shopping cart before proceeding to checkout. m
CUST-01 View Order Allows users to review their past purchases, including Mediu
1 History order statuses and delivery information. m
Staff Functions
Function Function Description Priorit
ID Name y
STAFF-0 Manage Enables staff to add, edit, or remove products from High
02 Products the catalog, including updating information such as
prices, descriptions, and images.
STAFF-0 Manage Allows staff to view, process, update the status of, High
03 Orders and potentially cancel customer orders.
STAFF-0 View Sales Provides access to analytical data regarding sales Mediu
04 Reports performance, popular products, and revenue m
metrics.
System Functions
Function Function Name Description Priorit
ID y
Register Account This use case begins when a new customer decides to create an account
on the e-commerce platform. The customer navigates to the registration page and provides
required information including username, email address, and password. The system
validates this information to ensure it meets the required criteria (e.g., unique username,
valid email format, password strength). If validation is successful, the system creates a new
user account and stores the information securely in the database. The system may also
send a confirmation email to verify the user's email address before fully activating the
account. This use case is essential for establishing unique identity and personalized
experiences for customers.
Login The Login use case is initiated when a returning customer wishes to access their
account. The customer enters their username and password credentials on the login page.
The system verifies these credentials against the stored information in the database. If the
credentials match, the system creates an authenticated session for the user, granting them
access to personalized features such as their order history, saved addresses, and shopping
cart. If authentication fails, the system provides appropriate error messages and may offer
password recovery options. This use case is critical for maintaining security and providing
personalized service.
Browse Products This use case represents a fundamental shopping activity where
customers explore available merchandise. The customer accesses the product catalog
through various entry points such as the homepage, category pages, or recommendation
sections. The system retrieves and displays products in an organized manner, potentially
implementing pagination for large catalogs. Customers may filter or sort products based on
various attributes such as price range, category, brand, or customer ratings. This browsing
experience should be optimized for both desktop and mobile interfaces, with consideration
for loading times and visual presentation.
Search Products The Search Products use case enables customers to quickly locate
specific items of interest. It begins when a customer enters keywords into the search field.
The system processes this query against product names, descriptions, categories, and
potentially other metadata. The search functionality may incorporate advanced features such
as autocomplete suggestions, spelling correction, or semantic understanding of search
intent. Results are presented in order of relevance, with options for further refinement. This
use case is critical for enhancing customer satisfaction by reducing the time and effort
needed to find desired products.
View Product Details This use case occurs when a customer selects a specific product to
learn more about it. The system displays comprehensive information including
high-resolution images, detailed descriptions, specifications, pricing, availability, shipping
information, and customer reviews if available. Additional features might be present for
certain product categories, such as size charts for clothing or compatibility information for
electronics. The product detail page should also provide clear calls to action such as "Add to
Cart" and potentially related product recommendations. This use case is essential for
providing customers with sufficient information to make informed purchasing decisions.
Add to Cart The Add to Cart use case represents a critical conversion point in the customer
journey. When a customer decides to purchase a product, they activate the "Add to Cart"
function, which may include specifying quantity or product variations (e.g., size, color). The
system validates product availability, adds the item to the customer's shopping cart, and
typically provides visual feedback confirming the action. The system may also update the
cart indicator in the navigation area to reflect the current number of items. This use case
bridges browsing behavior and purchasing intent, making it a key metric for e-commerce
performance.
View Cart This use case is initiated when a customer wishes to review the items they've
selected for potential purchase. The system displays all products currently in the customer's
cart, including images, names, selected options, quantities, individual prices, and the
calculated subtotal. Customers can review this information before proceeding to checkout.
The cart interface typically provides options to adjust quantities, remove items, or continue
shopping. The system recalculates totals whenever changes are made. This use case
provides transparency in the purchasing process and a final opportunity for customers to
review their selections.
Remove from Cart The Remove from Cart use case allows customers to eliminate
unwanted items from their selection. When a customer decides they no longer wish to
purchase a particular item, they activate the removal function associated with that product in
their cart view. The system immediately removes the item, updates the cart contents, and
recalculates the total price. This functionality gives customers control over their purchase
decisions and helps prevent abandoned carts due to unwanted items that customers cannot
remove.
Checkout This complex use case represents the final stage of the purchasing process. It
begins when a customer decides to complete their purchase by initiating the checkout
process from their shopping cart. The system guides the customer through a structured flow
that includes confirming or entering shipping address, selecting a shipping method, choosing
a payment method, and reviewing order details before final confirmation. The system
calculates additional costs such as shipping fees and taxes, presenting a comprehensive
total. This use case may include validation at each step and typically involves integration
with other use cases such as Make Payment.
Make Payment The Make Payment use case handles the critical financial transaction
aspect of e-commerce. After a customer has reviewed their order and proceeds to payment,
the system securely collects payment information appropriate to the selected payment
method (credit card details, PayPal authorization, etc.). The system communicates with
external payment processing services to validate and process the payment. This use case
includes error handling for declined payments and security measures such as encryption of
sensitive financial data. Upon successful payment, the system updates the order status and
triggers subsequent processes such as inventory updates and order confirmations.
View Order History This use case provides customers with access to information about
their previous transactions. When a customer navigates to their order history section, the
system retrieves and displays a chronological list of past orders, including order dates, total
amounts, and current statuses. Customers can select individual orders to view more details
such as the specific products purchased, shipping information, and payment methods used.
This functionality enhances customer service by giving users self-service access to their
purchase information and potentially reducing support inquiries about order status.
Login (Staff) The Staff Login use case is similar to customer login but provides access to
administrative functions. Staff members enter their credentials, which are authenticated
against staff accounts with appropriate permission levels. Upon successful authentication,
staff members are granted access to the administrative interface with functionality
appropriate to their role (e.g., inventory management, order processing). This use case
typically implements additional security measures such as stronger password requirements,
session timeouts, and potentially two-factor authentication for sensitive operations.
Manage Products This comprehensive use case encompasses all activities related to
maintaining the product catalog. Staff members can add new products by entering details
such as names, descriptions, pricing, categories, and uploading images. They can edit
existing product information to update prices, descriptions, or availability. They can also
temporarily or permanently remove products from the catalog when necessary. This use
case may include batch operations for efficient management of multiple products and
validation to ensure all required product information is provided.
Manage Orders The Manage Orders use case allows staff to oversee and process
customer transactions. Staff members can view all current orders with filtering options for
status, date range, or customer. They can update order statuses as orders progress through
fulfillment stages (processing, shipped, delivered, etc.). They can view detailed information
about specific orders including customer information, purchased products, payment status,
and shipping details. This use case may also include functionality to handle special
circumstances such as cancellations, modifications, or returns.
View Sales Reports This analytical use case provides staff with business intelligence
capabilities. Staff members can access predefined reports showing key metrics such as
revenue over time, bestselling products, sales by category, or geographic distribution of
customers. The system processes sales data to generate these reports with appropriate
visualizations such as charts and graphs. Staff may have options to customize date ranges
or other parameters and potentially export report data for further analysis in external tools.
This use case supports business decision-making by transforming raw transaction data into
meaningful insights.
Update Inventory The Update Inventory use case allows staff to maintain accurate stock
information. Staff members can manually adjust inventory levels for specific products,
potentially with batch operations for efficiency. This might be necessary due to physical
inventory counts, damaged goods, or receipt of new stock. The system records these
adjustments with appropriate timestamps and user identification for audit purposes. This use
case ensures that customers receive accurate availability information when browsing
products and helps prevent overselling of items that are out of stock.
Process Payment This automated use case handles the secure processing of financial
transactions. When a customer submits payment information during checkout, the system
securely transmits this data to appropriate payment processing services (credit card
processors, PayPal, etc.). The system handles authentication and authorization of the
payment, processes the response from the payment service, and updates the order
accordingly. In case of failures or declines, the system manages appropriate error handling
and customer notifications. This use case operates without human intervention but includes
logging and exception handling for administrative oversight.
Update Inventory (Automated) Unlike the staff version, this automated use case adjusts
inventory levels in response to system events. When an order is successfully placed, the
system automatically reduces available stock for the purchased products. Similarly, when
orders are canceled or items returned, the system may increase available stock accordingly.
The system may also include threshold notifications to alert staff when products are running
low and need reordering. This automation ensures that inventory information remains
accurate without requiring constant staff intervention.
Include Relationships:
● Checkout → Make Payment: The Checkout use case includes the Make Payment
use case because payment processing is an essential component of completing a
purchase.
● Checkout → Update Inventory: When a customer completes a purchase, the system
must update inventory levels to reflect the sold items.
● Register Account → Validate User Data: User registration inherently includes
validation of the provided information to ensure data integrity.
Extend Relationships:
● Browse Products → Add to Cart: The Add to Cart functionality extends the product
browsing experience when a customer decides to select a product for potential
purchase.
● View Cart → Remove from Cart: The ability to remove items extends the cart viewing
functionality when customers wish to modify their selections.
● View Product Details → Write Review: After viewing product details, customers may
optionally extend this interaction by writing reviews of products they've purchased.
This detailed use case diagram serves as a foundation for understanding the system's
requirements and guides the subsequent design and implementation phases of the
e-commerce project. It clearly defines the boundaries of the system and establishes the
expected interactions between users and the application, ensuring that development efforts
are aligned with business objectives and user needs.
This section delves into the analysis of the requirements for our proposed Online Course
Platform. The primary architectural decision made at this stage is to adopt a microservices
approach, utilizing the Django framework for the implementation of individual services. This
approach is chosen to promote modularity, scalability, and independent development cycles
for different parts of the platform, even though for this assignment, we aim for conceptual
simplicity rather than complex implementation. The following subsections detail the
decomposition into services, the data models within those services, the functions handling
business logic, the user interface templates, and the communication mechanisms between
services.
To structure the Online Course Platform effectively, we will decompose the system into
distinct, manageable microservices. Each microservice will handle a specific domain of the
application's functionality. While microservices allow for technological diversity, for simplicity
and consistency in this project, we will assume each service is built using the Django
framework.
Within each Django microservice, the `models.py` file defines the structure of the data that
the service manages. These models map directly to database tables, facilitated by Django's
Object-Relational Mapper (ORM).
1. **`UserService` Models**:
* `class User(models.Model):`
* `user_id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)`:
Unique identifier for the user. Using UUID is good practice in distributed systems to avoid ID
collisions.
* `username = models.CharField(max_length=150, unique=True)`: The user's chosen
username for login. Must be unique.
* `email = models.EmailField(unique=True)`: The user's email address, also unique.
Used for communication and potentially password recovery.
* `password_hash = models.CharField(max_length=128)`: Stores the securely hashed
version of the user's password (Django handles the hashing).
* `date_joined = models.DateTimeField(auto_now_add=True)`: Timestamp for when the
user account was created.
* `is_active = models.BooleanField(default=True)`: Flag to indicate if the account is
active.
2. **`CourseService` Models**:
* `class Course(models.Model):`
* `course_id = models.UUIDField(primary_key=True, default=uuid.uuid4,
editable=False)`: Unique identifier for the course.
* `title = models.CharField(max_length=200)`: The title of the course.
* `description = models.TextField()`: A detailed description of the course content.
* `instructor_name = models.CharField(max_length=100)`: Name of the course
instructor (kept simple here; could be a link to a User in `UserService` via API call in a real
scenario).
* `creation_date = models.DateTimeField(auto_now_add=True)`: Timestamp for when
the course was added to the platform.
* `last_updated = models.DateTimeField(auto_now=True)`: Timestamp for the last
modification of the course details.
3. **`EnrollmentService` Models**:
* `class Enrollment(models.Model):`
* `enrollment_id = models.UUIDField(primary_key=True, default=uuid.uuid4,
editable=False)`: Unique identifier for the enrollment record.
* `user_id = models.UUIDField()`: Stores the `user_id` (from `UserService`) of the
enrolled user. Note: This is not a direct Django `ForeignKey` across services but stores the
ID obtained via API communication.
* `course_id = models.UUIDField()`: Stores the `course_id` (from `CourseService`) of
the course the user is enrolled in. Again, not a direct `ForeignKey`.
* `enrollment_date = models.DateTimeField(auto_now_add=True)`: Timestamp for
when the enrollment occurred.
* `status = models.CharField(max_length=50, default='active')`: Could represent
enrollment status (e.g., 'active', 'completed', 'cancelled').
These models define the core data entities managed by each service, providing a clear
structure for storing information within their respective databases.
The `views.py` file in each Django service contains the logic to handle incoming HTTP
requests, interact with the service's models (and potentially other services via API calls), and
return HTTP responses. For simplicity, we can outline function-based views.
1. **`UserService` Views**:
* `register(request)`: Handles POST requests to create a new user account based on
provided username, email, and password. Interacts with the `User` model.
* `login(request)`: Handles POST requests to authenticate a user based on
username/password. If successful, might return an authentication token (e.g., JWT).
* `get_user_profile(request, user_id)`: Handles GET requests to retrieve the profile details
(username, email, date joined) for a specific `user_id`. Interacts with the `User` model.
* `update_user_profile(request, user_id)`: Handles PUT or PATCH requests to update
user details (e.g., email). Requires authentication.
2. **`CourseService` Views**:
* `list_courses(request)`: Handles GET requests to return a list of all available courses (or
a paginated list). Interacts with the `Course` model.
* `get_course_details(request, course_id)`: Handles GET requests to retrieve detailed
information for a specific `course_id`. Interacts with the `Course` model.
* `create_course(request)`: Handles POST requests (likely requiring admin privileges) to
add a new course to the catalog. Interacts with the `Course` model.
* `update_course(request, course_id)`: Handles PUT or PATCH requests (admin privilege)
to modify details of an existing course. Interacts with the `Course` model.
3. **`EnrollmentService` Views**:
* `enroll_in_course(request)`: Handles POST requests (requires authenticated user) to
create an `Enrollment` record linking a `user_id` (from token/session) and a `course_id`
(from request body). It would first potentially verify user existence with `UserService` and
course existence with `CourseService` via API calls. Interacts with the `Enrollment` model.
* `list_user_enrollments(request, user_id)`: Handles GET requests (requires authenticated
user, checking if the requestor matches `user_id` or is admin) to list all `course_id`s a
specific user is enrolled in. Interacts with the `Enrollment` model. It might then need to call
`CourseService` to get details for these `course_id`s to present meaningful data.
* `unenroll_from_course(request, enrollment_id)`: Handles DELETE requests (requires
authenticated user) to remove an `Enrollment` record.
These views define the core business logic endpoints for each microservice.
Django templates (`.html` files typically stored in a `templates` directory) are used to render
the User Interface (UI) presented to the end-user in a web browser. In a microservices
architecture, UI rendering can be handled in a few ways: each service renders its own
pages, a dedicated Frontend service/application handles all UI, or an API Gateway
aggregates data for a frontend. For simplicity, let's assume some services might render basic
HTML, or that there's an implied simple frontend interacting with the APIs.
These templates provide the visual interface for users to interact with the platform's
functionalities, using data supplied by the backend microservices.
**Interaction Example**: When a user clicks "Enroll" on `course_detail.html` for course `C1`:
1. The frontend (or relevant service) makes a `POST` request to `/api/enrollments` on the
`EnrollmentService`, sending the `course_id` `C1` and the user's authentication token.
2. `EnrollmentService` receives the request.
3. It might call `GET /api/users/me` (or similar endpoint) on `UserService`, passing the token
to validate the user and get their `user_id`.
4. It might call `GET /api/courses/C1` on `CourseService` to confirm the course exists.
5. If both checks pass, it creates a new `Enrollment` record in its database with the `user_id`
and `course_id` `C1`.
6. It returns a success response (e.g., `201 Created`).
These REST APIs form the connective tissue of the microservice architecture, enabling
decoupled services to collaborate to fulfill user requests.
---
**1.3 Conclusion**
The analysis phase has resulted in a proposed architecture for the Online Course Platform
based on microservices implemented with Django. The system is decomposed into three
core services: `UserService`, `CourseService`, and `EnrollmentService`, each managing a
distinct functional domain. For each service, the primary data models (`models.py`),
business logic handlers (`views.py`), potential user interface templates (`templates`), and
inter-service communication mechanisms via REST APIs have been outlined.
This decomposition provides a foundation for building a modular and potentially scalable
system. While kept simple for this assignment, this structure highlights the benefits of
separating concerns. Each service can be developed, deployed, and scaled independently.
The reliance on well-defined REST APIs ensures that services interact in a standardized
way.
1. Accounts Service
This service manages user authentication and profile management, operating as an
independent domain with its own data storage.
Responsibilities:
● User registration
● User authentication (login/logout)
● Profile management
● Session handling
The accounts service has been implemented as a Django app with its own models, views,
templates, and URL configurations, ensuring separation of concerns. It provides
authentication services that other components can leverage.
Responsibilities:
● Product information management
● Product categorization
● Product search functionality
● Image handling for products
The product service (implemented as the "book" app) maintains its own data model and
provides interfaces for retrieving product information, which is consumed by both the user
interface and other services.
3. Cart Service
Responsibilities:
The cart service references products from the product service but maintains its own model
for cart state, demonstrating the loose coupling between microservices.
Service Interaction Pattern
This pattern enables independent scaling and development of each service while
maintaining necessary integration points.
○ Extends BaseUserManager
○ Methods for creating standard and admin users
○ Handles password hashing and validation
3. AuthService
Key Methods:
The accounts service implements the Repository pattern through Django's ORM, separating
data access from business logic.
Core Classes:
Key Methods:
The product service uses Query Objects pattern in its search implementation, encapsulating
complex query logic.
Cart Service Design
Core Classes:
The cart service implements the Aggregate pattern, with Cart acting as the root entity that
encapsulates a collection of CartItems.
URL Structure
1. Django Views - Function-based views that handle HTTP requests and responses
2. CSRF Protection - Security measures for form submissions
3. JSON Responses - For asynchronous operations (particularly in the registration
form)
4. URL Namespacing - With app_name specification to avoid naming conflicts
Cross-Service Communication
1. Direct Model References - CartItem references Item model from the product service
2. Context Processors - The cart service provides a cart_count context processor for
use in templates
3. Django's Authentication Middleware - For user context sharing
The API design follows RESTful principles with resources identified by URLs, HTTP
methods determining operations, and appropriate status codes for responses.
2.4 Conclusion
The microservices architecture implemented in this Django e-commerce system offers
several advantages:
The system also has some design considerations that warrant attention:
1. Data Consistency - With separate databases, ensuring consistency across services
requires careful design
2. Deployment Complexity - Microservices bring increased deployment and
operational complexity
3. Transaction Management - Cross-service transactions are challenging and not fully
addressed
CHAPTER 3: AI IN E-COMMERCE
3.1 Application of Deep Learning in E-Commerce
Deep learning technology has transformed modern e-commerce platforms by enabling
sophisticated data analysis and personalization capabilities. For our Django-based
microservices e-commerce system, integrating deep learning presents strategic
opportunities to enhance user experience and business outcomes.
The key deep learning applications relevant to our e-commerce system include:
Product Image Analysis: Convolutional Neural Networks (CNNs) can analyze product
images to extract features for improved search, similarity matching, and automated
categorization. This would enhance our existing product service by adding visual search
capabilities, allowing users to find products similar to those they are viewing.
User Behavior Prediction: Recurrent Neural Networks (RNNs) and Long Short-Term
Memory (LSTM) networks can analyze sequential user interactions to predict likely next
actions, enabling proactive recommendations and personalized user journeys.
Dynamic Pricing Optimization: Deep learning models can analyze market conditions,
competitor pricing, demand patterns, and user willingness-to-pay to suggest optimal pricing
strategies for products.
Architectural Considerations
1. AI Service Layer: A new microservice that encapsulates all deep learning
functionality, exposing APIs for other services to consume
2. Data Pipeline: A system for collecting, preprocessing, and feeding data to the deep
learning models
3. Model Repository: A storage and versioning system for trained models
4. Inference Engine: A scalable system for executing predictions based on the trained
models
Aspect-Based Analysis: Extracting specific product aspects (e.g., "battery life," "user
interface") and the associated sentiments to provide granular insights into product strengths
and weaknesses.
Emotion Detection: Going beyond basic sentiment polarity to detect specific emotions (joy,
anger, disappointment) for more nuanced understanding of customer responses.
Technical Design
The sentiment analysis system will be designed with the following components:
1. Data Collection Module: Interfaces with the product service to access reviews,
comments, and other user-generated content
2. Preprocessing Pipeline: Handles text normalization, tokenization, and cleaning
3. Feature Extraction: Transforms text into numerical representations using
embeddings
4. Sentiment Classification Models: A combination of models including:
○ Fine-tuned transformer model (e.g., RoBERTa) for high-accuracy
classification
○ Lightweight models for real-time analysis
5. Results Storage: A database schema for storing and querying sentiment analysis
results
The sentiment analysis capability will be exposed through APIs that other services can
consume, maintaining the loose coupling principle of our microservices architecture.
1. User Preference Model: Captures explicit preferences (ratings) and implicit
preferences (browsing behavior)
2. Sentiment-Augmented Product Representation: Enriches product profiles with
sentiment data extracted from reviews
3. Aspect-Based Matching: Matches users to products based on aspects they have
positively mentioned in previous reviews
4. Sentiment-Aware Ranking: Adjusts recommendation scores based on sentiment
trends
Architectural Integration
The recommendation system will be integrated with our existing microservices through:
1. Data Integration Layer: Collects user activity data from the accounts service,
product information from the product service, and cart information from the cart
service
2. Recommendation API: Provides endpoints for:
○ Personalized product recommendations
○ "Customers also bought" recommendations
○ Category-specific recommendations
3. Real-Time Event Processing: Captures and processes user actions to update
recommendations dynamically
The recommendation service will maintain its own data store for user preferences and
precomputed recommendations, while accessing sentiment data through APIs provided by
the sentiment analysis component.
3.4 Deployment
Deploying AI capabilities within our microservices architecture requires careful planning to
ensure performance, scalability, and maintainability.
Deployment Strategy
Infrastructure Design
Performance Considerations
3.5 Conclusion
The integration of AI capabilities, particularly deep learning, sentiment analysis, and
recommendation systems, represents a significant enhancement to our e-commerce
platform. These technologies enable a more personalized, responsive, and intelligent
shopping experience.
The proposed design adheres to the microservices principles established in our architecture
while introducing new capabilities through well-defined interfaces. By maintaining separation
of concerns and loose coupling, we ensure that our AI components can evolve
independently of the core e-commerce functionality.
The sentiment analysis and recommendation systems will work together to create a virtuous
cycle of data collection, insight generation, and improved user experience. By understanding
customer sentiments at a granular level, we can provide more relevant recommendations,
which in turn leads to higher engagement and more sentiment data.
Looking forward, this architecture provides a foundation for future AI enhancements, such as
conversational interfaces, fraud detection systems, and predictive inventory management.
The modular nature of our design ensures that we can continue to add capabilities as
technologies mature and business needs evolve.
● Uses NLTK's VADER (Valence Aware Dictionary and Sentiment Reasoner) for
sentiment analysis
● Processes text by removing stopwords and punctuation
● Analyzes the sentiment of product reviews and assigns scores between -1 (very
negative) and +1 (very positive)
2. Recommendation Service
3. Integration Points
● When users submit reviews (item_detail view), their reviews are analyzed for
sentiment
● The recommendations view provides personalized product suggestions
● The search page shows recommended items alongside search results
● You display sentiment indicators on reviews (positive/neutral/negative tags)
● Helping users discover products they're likely to enjoy based on sentiment patterns
● Highlighting products with positive sentiment across all users
● Visually indicating the sentiment of reviews to help users quickly assess product
quality
● Creating a more personalized shopping experience
1. The Review model with a sentiment_score field to store analysis results
2. The SentimentService class that handles text preprocessing and analysis
3. The RecommendationService class that generates personalized
recommendations
4. Template integration showing sentiment indicators and recommended products
The system is well integrated with your Django application, with dedicated views for
recommendations and sentiment analysis logic that's applied when reviews are submitted.
This is a sophisticated feature that adds real value to your e-commerce site by leveraging AI
to improve product discovery and user satisfaction.
1.Backend code
def __str__(self):
return self.name
def get_price_as_decimal(self):
# If self.price is a Decimal128
if hasattr(self.price, 'to_decimal'):
return Decimal(self.price.to_decimal())
return self.price
class Review(models.Model):
item = models.ForeignKey(Item, on_delete=models.CASCADE,
related_name='reviews')
user = models.ForeignKey(settings.AUTH_USER_MODEL,
on_delete=models.CASCADE)
text = models.TextField()
rating = models.IntegerField(choices=[(1, '1'), (2, '2'), (3, '3'), (4,
'4'), (5, '5')])
sentiment_score = models.FloatField(default=0.0) # Will store our
sentiment analysis result
created_at = models.DateTimeField(auto_now_add=True)
def __str__(self):
return f"Review by {self.user.username} for {self.item.name}"
logger = logging.getLogger('book')
# The search function you already have
# Modify the search function in book/views.py
def search(request):
keyword = request.GET.get('keyword', '')
items = []
try:
if keyword:
# Filter items by name or category that contain the keyword
(case-insensitive)
items = Item.objects.filter(
Q(name__icontains=keyword) | Q(category__icontains=keyword)
)
else:
# If no keyword provided, display all items
items = Item.objects.all()
except Exception as e:
logger.error(f"Database error in search view: {str(e)}")
messages.error(request, "Sorry, we encountered a problem connecting
to our database. Please try again later.")
return render(request, 'search.html', {
'items': [],
'recommended_items': [],
'error': "Database connection error. Please try again later."
})
def item_detail(request, item_id):
"""View for displaying item details and reviews"""
item = get_object_or_404(Item, pk=item_id)
reviews = item.reviews.all().order_by('-created_at')
review_form = ReviewForm()
# Analyze sentiment
sentiment_score =
SentimentService.analyze_sentiment(review.text)
review.sentiment_score = sentiment_score
review.save()
context = {
'item': item,
'reviews': reviews,
'review_form': review_form,
'similar_items': similar_items
}
context = {
'recommended_items': recommended_items,
'trending_items': trending_items,
}
return JsonResponse({
'status': db_status,
'engine': connections['default'].settings_dict['ENGINE'],
'name': connections['default'].settings_dict['NAME'],
'timestamp': timezone.now().isoformat(),
}, status=status_code)
# book/services/recommendation_service.py
from django.db.models import Avg, Count
from book.models import Item, Review
class RecommendationService:
"""Service for generating product recommendations based on sentiment
analysis"""
@staticmethod
def get_top_rated_items(limit=5, category=None):
"""
Get items with the highest average ratings
Args:
limit: Number of items to return
category: Optional category to filter by
Returns:
List of items sorted by average rating
"""
try:
items_query = Item.objects.all()
if category:
items_query = items_query.filter(category__iexact=category)
# Order by average_rating
return items_query.order_by('-average_rating')[:limit]
except Exception as e:
# If anything goes wrong, return an empty list
return []
@staticmethod
def get_recommendations_for_user(user, limit=5):
"""
Get personalized recommendations for a user
Args:
user: User object to get recommendations for
limit: Number of items to recommend
Returns:
List of recommended items
"""
try:
# For simplicity, just return top-rated items
return RecommendationService.get_top_rated_items(limit)
except Exception as e:
# If anything goes wrong, return an empty list
return []
urlpatterns = [
path('item/search', views.search, name='search'),
path('item/<int:item_id>/', views.item_detail, name='item_detail'),
path('recommendations/', views.recommendations, name='recommendations'),
path('db-health/', views.db_health_check, name='db_health_check'),
]
class ReviewForm(forms.ModelForm):
class Meta:
model = Review
fields = ['text', 'rating']
widgets = {
'text': forms.Textarea(attrs={'rows': 4, 'placeholder': 'Write
your review here...'}),
'rating': forms.Select(choices=[(1, '1 - Poor'), (2, '2 -
Fair'), (3, '3 - Good'), (4, '4 - Very Good'), (5, '5 - Excellent')])
}
labels = {
'text': 'Your Review',
'rating': 'Rating'
}
2.Frontend code
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,
initial-scale=1.0">
<title>Personalized Recommendations | ECom2 Shop</title>
<link
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/a
ll.min.css" rel="stylesheet">
<style>
:root {
--primary-color: #1e3a8a;
--secondary-color: #3b82f6;
--accent-color: #f43f5e;
--success-color: #10b981;
--background-color: #f3f4f6;
--card-background: #ffffff;
--text-color: #1f2937;
--border-radius: 8px;
--shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', system-ui, sans-serif;
background-color: var(--background-color);
color: var(--text-color);
line-height: 1.6;
}
.header {
background: var(--primary-color);
padding: 1rem 0;
position: sticky;
top: 0;
z-index: 100;
box-shadow: var(--shadow);
}
.header-content {
max-width: 1400px;
margin: 0 auto;
padding: 0 2rem;
display: flex;
justify-content: space-between;
align-items: center;
}
.logo {
color: white;
font-size: 1.5rem;
font-weight: bold;
text-decoration: none;
display: flex;
align-items: center;
gap: 0.5rem;
}
.nav-links {
display: flex;
gap: 1.5rem;
}
.nav-link {
color: white;
text-decoration: none;
transition: all 0.3s ease;
}
.nav-link:hover {
color: var(--accent-color);
}
.container {
max-width: 1200px;
margin: 2rem auto;
padding: 0 1rem;
}
.hero {
background: linear-gradient(135deg, var(--primary-color),
var(--secondary-color));
color: white;
padding: 3rem 2rem;
border-radius: var(--border-radius);
margin-bottom: 2rem;
box-shadow: var(--shadow);
text-align: center;
}
.hero h1 {
font-size: 2.5rem;
margin-bottom: 1rem;
}
.hero p {
font-size: 1.1rem;
max-width: 700px;
margin: 0 auto;
opacity: 0.9;
}
.section {
margin-bottom: 3rem;
}
.section-title {
display: flex;
align-items: center;
gap: 0.5rem;
font-size: 1.5rem;
color: var(--primary-color);
margin-bottom: 1.5rem;
padding-bottom: 0.5rem;
border-bottom: 2px solid var(--secondary-color);
}
.products-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(280px,
1fr));
gap: 2rem;
}
.product-card {
background: white;
border-radius: var(--border-radius);
overflow: hidden;
box-shadow: var(--shadow);
transition: all 0.3s ease;
height: 100%;
display: flex;
flex-direction: column;
}
.product-card:hover {
transform: translateY(-5px);
box-shadow: 0 10px 15px rgba(0, 0, 0, 0.1);
}
.product-card-image {
width: 100%;
height: 200px;
object-fit: cover;
}
.product-card-content {
padding: 1.5rem;
flex-grow: 1;
display: flex;
flex-direction: column;
}
.product-category {
font-size: 0.8rem;
color: var(--secondary-color);
text-transform: uppercase;
letter-spacing: 1px;
margin-bottom: 0.5rem;
}
.product-card-title {
font-size: 1.2rem;
margin-bottom: 0.5rem;
color: var(--primary-color);
}
.product-card-price {
font-weight: bold;
color: var(--primary-color);
margin-bottom: 1rem;
}
.product-card-rating {
display: flex;
align-items: center;
gap: 0.3rem;
margin-bottom: 1rem;
}
.star {
color: #fbbf24;
}
.product-card-button {
width: 100%;
background: var(--secondary-color);
color: white;
border: none;
padding: 0.75rem;
border-radius: var(--border-radius);
cursor: pointer;
transition: all 0.3s ease;
text-align: center;
text-decoration: none;
display: block;
margin-top: auto;
}
.product-card-button:hover {
background: #2563eb;
}
.no-items {
text-align: center;
padding: 2rem;
background: white;
border-radius: var(--border-radius);
box-shadow: var(--shadow);
}
.no-items i {
font-size: 3rem;
color: var(--secondary-color);
margin-bottom: 1rem;
}
.sentiment-tag {
display: inline-block;
padding: 0.25rem 0.5rem;
border-radius: 999px;
font-size: 0.75rem;
font-weight: 600;
margin-left: 0.5rem;
}
.sentiment-positive {
background-color: rgba(16, 185, 129, 0.1);
color: #10b981;
}
.sentiment-neutral {
background-color: rgba(107, 114, 128, 0.1);
color: #6b7280;
}
.sentiment-negative {
background-color: rgba(239, 68, 68, 0.1);
color: #ef4444;
}
.info-box {
background: white;
border-radius: var(--border-radius);
padding: 1.5rem;
box-shadow: var(--shadow);
margin-bottom: 2rem;
}
.info-box h3 {
color: var(--primary-color);
margin-bottom: 0.5rem;
display: flex;
align-items: center;
gap: 0.5rem;
}
.info-box p {
color: #4b5563;
}
.hero h1 {
font-size: 1.8rem;
}
}
</style>
</head>
<body>
<header class="header">
<div class="header-content">
<a href="{% url 'accounts:index' %}" class="logo">
<i class="fas fa-shopping-bag"></i>
ECom2 Shop
</a>
<div class="nav-links">
<a href="{% url 'search' %}" class="nav-link">
<i class="fas fa-search"></i> Shop
</a>
<a href="{% url 'cart:cart_view' %}" class="nav-link">
<i class="fas fa-shopping-cart"></i>
<span class="cart-count">{{ cart_count|default:"0"
}}</span>
</a>
</div>
</div>
</header>
<div class="container">
<div class="hero">
<h1>Personalized Recommendations</h1>
<p>Discover products tailored to your interests based on
our sentiment analysis AI</p>
</div>
<div class="info-box">
<h3><i class="fas fa-robot"></i> Powered by AI</h3>
<p>Our recommendations are powered by sentiment analysis
AI that analyzes customer reviews to understand what products people
truly love. The more you interact with our store, the better our
recommendations become!</p>
</div>
<div class="section">
<h2 class="section-title"><i class="fas fa-thumbs-up"></i>
Recommended for You</h2>
<!-- Modify the section that displays recommendations in
book/templates/book/recommendations.html -->
{% if recommended_items %}
<div class="products-grid">
{% for item in recommended_items %}
<div class="product-card">
<img src="{{ item.product_image.url }}" alt="{{
item.name }}" class="product-card-image">
<div class="product-card-content">
<div class="product-category">{{ item.category
}}</div>
<h3 class="product-card-title">{{ item.name
}}</h3>
<p class="product-card-price">${{ item.price
}}</p>
<div class="product-card-rating">
{% for i in "12345" %}
{% if forloop.counter <=
item.average_rating %}
<i class="fas fa-star star"></i>
{% elif forloop.counter <=
item.average_rating|add:0.5 %}
<i class="fas fa-star-half-alt star"></i>
{% else %}
<i class="far fa-star star"></i>
{% endif %}
{% endfor %}
{% if item.average_rating >= 4 %}
<span class="sentiment-tag
sentiment-positive">Highly Rated</span>
{% endif %}
</div>
<a href="{% url 'item_detail' item.id %}"
class="product-card-button">View Details</a>
</div>
</div>
{% endfor %}
</div>
{% else %}
<div class="no-items">
<i class="fas fa-search"></i>
<h3>No recommendations yet</h3>
<p>Browse and review some products to get personalized
recommendations</p>
</div>
{% endif %}
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,
initial-scale=1.0">
<title>Shop | EcoShop</title>
<link
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/a
ll.min.css" rel="stylesheet">
<style>
/* Base Styles */
#cartNotification {
z-index: 9999;
}
:root {
--primary-color: #1e3a8a; /* Navy blue */
--secondary-color: #3b82f6; /* Sky blue */
--accent-color: #f43f5e; /* Coral pink */
--success-color: #10b981; /* Green */
--background-color: #f3f4f6; /* Light grey */
--card-background: #ffffff;
--text-color: #1f2937; /* Dark grey */
--border-radius: 8px;
--shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', system-ui, sans-serif;
background-color: var(--background-color);
color: var(--text-color);
line-height: 1.6;
}
.header-content {
max-width: 1400px;
margin: 0 auto;
padding: 0 2rem;
display: flex;
justify-content: space-between;
align-items: center;
}
.logo {
color: white;
font-size: 1.5rem;
font-weight: bold;
text-decoration: none;
display: flex;
align-items: center;
gap: 0.5rem;
}
.search-container {
background: white;
border-radius: var(--border-radius);
padding: 1rem 2rem;
margin: 2rem auto;
max-width: 800px;
box-shadow: var(--shadow);
}
.search-form {
display: flex;
gap: 1rem;
}
.search-input {
flex: 1;
padding: 0.8rem 1.2rem;
border: 2px solid #e5e7eb;
border-radius: var(--border-radius);
font-size: 1rem;
transition: all 0.3s ease;
}
.search-input:focus {
border-color: var(--secondary-color);
outline: none;
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.2);
}
.search-btn {
background: var(--secondary-color);
color: white;
border: none;
padding: 0 2rem;
border-radius: var(--border-radius);
cursor: pointer;
transition: all 0.3s ease;
}
.search-btn:hover {
background: #2563eb;
transform: translateY(-2px);
}
/* Main Content */
.container {
max-width: 1400px;
margin: 0 auto;
padding: 2rem;
}
/* Grid Layout */
.items-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(280px,
1fr));
gap: 2rem;
margin-top: 2rem;
}
/* Item Card */
.item-card {
background: var(--card-background);
border-radius: var(--border-radius);
overflow: hidden;
box-shadow: var(--shadow);
transition: all 0.3s ease;
animation: fadeInUp 0.5s ease-out backwards;
}
.item-card:hover {
transform: translateY(-5px);
box-shadow: 0 8px 15px rgba(0, 0, 0, 0.1);
}
.item-image {
width: 100%;
height: auto; /* Maintain aspect ratio */
aspect-ratio: 4 / 3; /* Optional: Helps keep consistent
sizing across images */
object-fit: cover; /* Ensure images fill area without
stretching */
border-bottom: 2px solid var(--secondary-color); /*
Optional: Add a border for better separation */
}
.item-content {
padding: 1.5rem;
}
.item-category {
font-size: 0.8rem;
color: var(--secondary-color);
text-transform: uppercase;
letter-spacing: 1px;
margin-bottom: 0.5rem;
}
.item-title {
font-size: 1.2rem;
margin-bottom: 0.5rem;
color: var(--text-color);
}
.item-price {
font-size: 1.3rem;
font-weight: bold;
color: var(--primary-color);
margin-bottom: 1rem;
}
.item-meta {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 1rem;
font-size: 0.9rem;
color: #6b7280;
}
.rating {
display: flex;
align-items: center;
gap: 0.3rem;
}
.star {
color: #fbbf24;
}
.comments {
display: flex;
align-items: center;
gap: 0.3rem;
}
.add-to-cart:hover {
background: #1e40af;
}
/* Cart Notification */
.cart-notification {
position: fixed;
top: 2rem;
right: 2rem;
background: var(--success-color);
color: white;
padding: 1rem 2rem;
border-radius: var(--border-radius);
box-shadow: var(--shadow);
display: flex;
align-items: center;
gap: 0.5rem;
transform: translateX(200%);
transition: transform 0.3s ease;
}
.cart-notification.show {
transform: translateX(0);
}
/* Animations */
@keyframes fadeInUp {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.item-card {
animation-delay: calc(var(--animation-order) * 0.1s);
}
/* Responsive Design */
@media (max-width: 768px) {
.header-content {
flex-direction: column;
gap: 1rem;
padding: 1rem;
}
.search-container {
margin: 1rem;
padding: 1rem;
}
.search-form {
flex-direction: column;
}
.search-btn {
width: 100%;
padding: 0.8rem;
}
.container {
padding: 1rem;
}
.items-grid {
grid-template-columns: 1fr;
gap: 1rem;
}
}
</style>
</head>
<body>
<header class="header">
<div class="header-content">
<a href="{% url 'accounts:index' %}" class="logo">
<i class="fas fa-shopping-bag"></i>
ECom2 Shop
</a>
<a href="{% url 'cart:cart_view' %}" style="color: white;
text-decoration: none;">
<i class="fas fa-shopping-cart"></i>
<span class="cart-count">{{ cart_count|default:"0"
}}</span>
</a>
</div>
</header>
<div class="search-container">
<form class="search-form" action="{% url 'search' %}"
method="get">
<input type="text" name="keyword" class="search-input"
placeholder="Search for items...">
<button type="submit" class="search-btn">
<i class="fas fa-search"></i> Search
</button>
</form>
</div>
<main class="container">
<div class="items-grid">
{% for item in items %}
<div class="item-card">
{% comment %}
<a href="{% url 'item_detail' item.id %}">
{% endcomment %}
<img class="item-image" src="{{ item.product_image.url
}}" alt="Item Image">
{% comment %}
</a>
{% endcomment %}
<div class="item-content">
<div class="item-category">{{
item.category|default:"Book" }}</div>
<h3 class="item-title">{{ item.name }}</h3>
<div class="item-meta">
<div class="rating">
<i class="fas fa-star star"></i>
<span>{{ item.average_rating|default:"No
ratings" }}</span>
<!-- You can add a count for ratings if
available -->
</div>
<div class="comments">
<i class="fas fa-comment"></i>
<span>12</span>
</div>
</div>
<div class="item-price">$ {{ item.price }}</div>
<form action="{% url 'cart:add_to_cart' item.id %}"
method="post" class="add-to-cart-form">
{% csrf_token %}
<button type="submit" class="add-to-cart">
<i class="fas fa-cart-plus"></i>
Add to Cart
</button>
</form>
</div>
</div>
{% endfor %}
</div>
# This is a code snippet to add to book/templates/search.html
# Add this section just before the closing </main> tag
{% if recommended_items %}
<div class="section">
<h2 class="section-title" style="font-size: 1.5rem; color:
var(--primary-color); margin-top: 2rem; padding-bottom: 0.5rem;
border-bottom: 2px solid var(--secondary-color);">
<i class="fas fa-thumbs-up"></i> Recommended for You
</h2>
<div class="items-grid">
{% for item in recommended_items %}
<div class="item-card">
<a href="{% url 'item_detail' item.id %}">
<img class="item-image" src="{{
item.product_image.url }}" alt="Item Image">
</a>
<div class="item-content">
<div class="item-category">{{
item.category|default:"Book" }}</div>
<h3 class="item-title">{{ item.name }}</h3>
<div class="item-meta">
<div class="rating">
<i class="fas fa-star star"></i>
<span>{{ item.average_rating|default:"No
ratings" }}</span>
</div>
<div class="comments">
<i class="fas fa-comment"></i>
<span>{{ item.reviews.count }}</span>
</div>
</div>
<div class="item-price">$ {{ item.price }}</div>
<form action="{% url 'cart:add_to_cart' item.id
%}" method="post" class="add-to-cart-form">
{% csrf_token %}
<button type="submit" class="add-to-cart">
<i class="fas fa-cart-plus"></i>
Add to Cart
</button>
</form>
</div>
</div>
{% endfor %}
</div>
</div>
{% endif %}
</main>
<script>
// JavaScript for handling cart notifications and animations
document.querySelectorAll('.add-to-cart-form').forEach(form => {
form.addEventListener('submit', async (e) => {
e.preventDefault();
try {
const response = await fetch(form.action, {
method: 'POST',
body: new FormData(form),
headers: {
'X-CSRFToken':
form.querySelector('[name=csrfmiddlewaretoken]').value
}
});
if (response.ok) {
const notification =
document.getElementById('cartNotification');
notification.classList.add('show');
const cartCount =
document.querySelector('.cart-count');
cartCount.textContent =
parseInt(cartCount.textContent) + 1;
setTimeout(() => {
notification.classList.remove('show');
}, 3000);
}
} catch (error) {
console.error('Error adding item to cart:', error);
}
});
});
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,
initial-scale=1.0">
<title>ECom2 Shop - Welcome</title>
<link
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/a
ll.min.css" rel="stylesheet">
<style>
:root {
--primary-color: #1a237e; /* Dark Indigo */
--secondary-color: #3949ab; /* Indigo */
--accent-color: #ff6f61; /* Coral Red */
--success-color: #81c784; /* Light Green */
--background-color: #e8eaf6; /* Light Lavender */
--card-background: white;
--text-color: #1a237e;
--border-radius: 12px;
--shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
--transition: all 0.3s ease;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', system-ui, sans-serif;
background-color: var(--background-color);
color: var(--text-color);
line-height: 1.6;
}
.header {
background: var(--primary-color);
color: white;
padding: 1rem;
position: sticky;
top: 0;
z-index: 100;
box-shadow: var(--shadow);
}
.header-content {
max-width: 1200px;
margin: 0 auto;
display: flex;
justify-content: space-between;
align-items: center;
}
.logo {
font-size: 1.5rem;
font-weight: bold;
display: flex;
align-items: center;
gap: 0.5rem;
}
.hero {
background: linear-gradient(135deg, var(--primary-color),
var(--secondary-color));
color: white;
padding: 4rem 1rem;
text-align: center;
}
.hero h1 {
font-size: 2.5rem;
margin-bottom: 1rem;
}
.hero p {
font-size: 1.2rem;
opacity: 0.9;
max-width: 600px;
margin: 0 auto;
}
.container {
max-width: 1200px;
margin: 0 auto;
padding: 2rem 1rem;
}
.quick-actions {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px,
1fr));
gap: 1.5rem;
margin-top: -3rem;
}
.action-card {
background: var(--card-background);
border-radius: var(--border-radius);
padding: 2rem;
text-align: center;
box-shadow: var(--shadow);
transition: var(--transition);
cursor: pointer;
}
.action-card:hover {
transform: translateY(-5px);
box-shadow: 0 8px 15px rgba(0, 0, 0, 0.1);
}
.action-card i {
font-size: 2.5rem;
color: var(--secondary-color);
margin-bottom: 1rem;
}
.action-card h3 {
margin-bottom: 0.5rem;
color: var(--primary-color);
}
.action-card p {
color: #666;
font-size: 0.9rem;
}
.features {
margin-top: 4rem;
}
.section-title {
text-align: center;
margin-bottom: 2rem;
}
.feature-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px,
1fr));
gap: 2rem;
margin-top: 2rem;
}
.feature-card {
background: var(--card-background);
border-radius: var(--border-radius);
padding: 2rem;
box-shadow: var(--shadow);
transition: var(--transition);
}
.feature-card:hover {
transform: translateY(-3px);
}
.feature-card i {
font-size: 2rem;
color: var(--accent-color);
margin-bottom: 1rem;
}
.stats {
background: linear-gradient(135deg, var(--primary-color),
var(--secondary-color));
color: white;
padding: 4rem 1rem;
margin-top: 4rem;
}
.stats-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px,
1fr));
gap: 2rem;
text-align: center;
}
.stat-item h3 {
font-size: 2.5rem;
margin-bottom: 0.5rem;
}
.footer {
background: var(--primary-color);
color: white;
padding: 2rem 1rem;
margin-top: 4rem;
}
.footer-content {
max-width: 1200px;
margin: 0 auto;
text-align: center;
}
.user-menu i {
font-size: 1.5rem;
cursor: pointer;
}
.dropdown-menu {
display: none;
position: absolute;
right: 0;
background-color: var(--card-background);
min-width: 120px;
box-shadow: var(--shadow);
border-radius: var(--border-radius);
z-index: 1;
}
.dropdown-menu a {
color: var(--text-color);
padding: 12px 16px;
text-decoration: none;
display: block;
border-bottom: 1px solid #f1f1f1;
transition: var(--transition);
}
.dropdown-menu a:last-child {
border-bottom: none;
}
.dropdown-menu a:hover {
background-color: var(--background-color);
color: white;
}
/* Additional styles */
/*.btn-login {*/
/* color: white;*/
/* background-color: var(--accent-color);*/
/* padding: 0.5rem 1rem;*/
/* border-radius: var(--border-radius);*/
/* text-decoration: none;*/
/* transition: var(--transition);*/
/*}*/
/*.btn-login:hover {*/
/* background-color: #ff856e;*/
/*}*/
.quick-actions {
margin-top: -2rem;
}
.stats-grid {
grid-template-columns: 1fr;
}
}
</style>
</head>
<body>
<header class="header">
<div class="header-content">
<div class="logo">
<i class="fas fa-shopping-bag"></i>
ECom2 Shop
</div>
<nav>
<!-- Conditionally display the user menu if the user is
logged in -->
<div th:if="${session.loggedInCustomer != null}"
class="user-menu">
<i class="fas fa-user" id="userIcon"></i>
<div class="dropdown-menu" id="dropdownMenu">
<a href="/accounts/logout">Logout</a>
</div>
</div>
<!-- If the user is not logged in, show a login link -->
<!-- <div th:if="${session.loggedInCustomer == null}">-->
<!-- <a href="/login" class="btn-login">Login</a>-->
<!-- </div>-->
</nav>
</div>
</header>
<section class="hero">
<h1>Welcome to ECom2 Shop</h1>
<p>Discover amazing products with great deals and secure shopping
experience</p>
</section>
<div class="container">
{% comment %}
The quick-actions section with proper card components
{% endcomment %}
<div class="quick-actions">
<div class="action-card"
onclick="window.location.href='http://127.0.0.1:8000/book/recommendat
ions/'">
<i class="fas fa-thumbs-up"></i>
<h3>Recommendations</h3>
<p>Discover products tailored for you</p>
</div>
<div class="action-card"
onclick="window.location.href='http://127.0.0.1:8000/book/item/search
'">
<i class="fas fa-store"></i>
<h3>Browse Products</h3>
<p>Explore our wide range of products</p>
</div>
<div class="action-card"
onclick="window.location.href='http://127.0.0.1:8000/cart'">
<i class="fas fa-shopping-cart"></i>
<h3>Your Cart</h3>
<p>View and manage your shopping cart</p>
</div>
<div class="action-card"
onclick="window.location.href='/order/1'">
<i class="fas fa-box"></i>
<h3>Orders</h3>
<p>Track your orders and view history</p>
</div>
</div>
</div>
<div class="features">
<div class="section-title">
<h2>Why Choose Us</h2>
</div>
<div class="feature-grid">
<div class="feature-card">
<i class="fas fa-shipping-fast"></i>
<h3>Fast Delivery</h3>
<p>Get your orders delivered quickly and safely to
your doorstep</p>
</div>
<div class="feature-card">
<i class="fas fa-shield-alt"></i>
<h3>Secure Shopping</h3>
<p>Shop with confidence with our secure payment
system</p>
</div>
<div class="feature-card">
<i class="fas fa-headset"></i>
<h3>24/7 Support</h3>
<p>Our customer support team is always here to help
you</p>
</div>
</div>
</div>
</div>
<section class="stats">
<div class="container">
<div class="stats-grid">
<div class="stat-item">
<h3>10k+</h3>
<p>Happy Customers</p>
</div>
<div class="stat-item">
<h3>5k+</h3>
<p>Products</p>
</div>
<div class="stat-item">
<h3>99%</h3>
<p>Satisfaction Rate</p>
</div>
<div class="stat-item">
<h3>24/7</h3>
<p>Customer Support</p>
</div>
</div>
</div>
</section>
<footer class="footer">
<div class="footer-content">
<p>© 2024 ECom2 Shop. All rights reserved.</p>
</div>
</footer>
<script>
// Smooth scrolling for anchor links
document.querySelectorAll('a[href^="#"]').forEach(anchor => {
anchor.addEventListener('click', function (e) {
e.preventDefault();
document.querySelector(this.getAttribute('href')).scrollIntoView({
behavior: 'smooth'
});
});
});
if (userIcon) {
userIcon.addEventListener('click', function(event) {
event.stopPropagation();
dropdownMenu.style.display =
dropdownMenu.style.display === 'block' ? 'none' : 'block';
});