Streamline user experience with cleaner UI and improved authentication flow

- Remove special styling for career navigator button, unify all Try Now buttons
- Clean up authentication messaging system to prevent message confusion
- Replace immediate success messages with direct redirections for smoother UX
- Add session-based post-login messaging for better redirect handling
- Improve login page with verification resend button and cleaner message display
- Remove redundant payment success messages for free agents

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Claude 2025-08-05 09:22:13 +05:30
parent bc662e6af0
commit 54d64f5927
4 changed files with 83 additions and 52 deletions

View File

@ -7,23 +7,7 @@
<link rel="stylesheet" href="{% static 'css/agent-base.css' %}"> <link rel="stylesheet" href="{% static 'css/agent-base.css' %}">
<link rel="stylesheet" href="{% static 'css/marketplace.css' %}"> <link rel="stylesheet" href="{% static 'css/marketplace.css' %}">
<style> <style>
/* Special styling for Career Navigator button */ /* All Try Now buttons now use consistent styling from marketplace.css */
.career-nav-btn {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%) !important;
color: white !important;
border: none !important;
font-weight: 600 !important;
box-shadow: 0 4px 15px rgba(102, 126, 234, 0.3) !important;
transition: all 0.3s ease !important;
}
.career-nav-btn:hover {
transform: translateY(-2px) !important;
box-shadow: 0 6px 20px rgba(102, 126, 234, 0.4) !important;
color: white !important;
}
/* Career nav card styling removed pulse animation for consistency */
</style> </style>
{% endblock %} {% endblock %}
@ -92,12 +76,12 @@
<div class="agent-footer"> <div class="agent-footer">
{% if user.is_authenticated %} {% if user.is_authenticated %}
{% if agent.slug == 'cybersec-career-navigator' %} {% if agent.slug == 'cybersec-career-navigator' %}
<a href="{% url 'agents:career_navigator_access' %}" class="try-btn career-nav-btn"> <a href="{% url 'agents:career_navigator_access' %}" class="try-btn">
🎓 Try Now → Try Now →
</a> </a>
{% elif agent.slug == 'ai-brand-strategist' %} {% elif agent.slug == 'ai-brand-strategist' %}
<a href="{% url 'agents:ai_brand_strategist_access' %}" class="try-btn"> <a href="{% url 'agents:ai_brand_strategist_access' %}" class="try-btn">
🧠 Try Now → Try Now →
</a> </a>
{% else %} {% else %}
<a href="{% url 'agents:detail' agent.slug %}" class="try-btn">Try Now →</a> <a href="{% url 'agents:detail' agent.slug %}" class="try-btn">Try Now →</a>

View File

@ -196,10 +196,12 @@ def execute_agent(request):
def career_navigator_access(request): def career_navigator_access(request):
"""Handle Try Now button click - charge wallet and redirect to form""" """Handle Try Now button click - charge wallet and redirect to form"""
if not request.user.is_authenticated: if not request.user.is_authenticated:
# Clear any existing messages to prevent confusion # Clear all existing messages before adding login message
storage = messages.get_messages(request) storage = messages.get_messages(request)
storage.used = True for _ in storage:
messages.error(request, 'Please login to access the Career Navigator.') pass # Consume all messages
# Add login message to session for after login redirect
request.session['post_login_message'] = 'Please complete your login to access the Career Navigator.'
return redirect('authentication:login') return redirect('authentication:login')
# Get the career navigator agent # Get the career navigator agent
@ -240,21 +242,19 @@ def career_navigator_access(request):
completed_at=timezone.now() completed_at=timezone.now()
) )
# Success message and redirect to form # Redirect directly to form - no message needed
if agent.price > 0:
messages.success(request, f'Welcome to your {agent.name} consultation.')
else:
messages.success(request, f'Welcome to your {agent.name} consultation.')
return redirect('agents:career_navigator') return redirect('agents:career_navigator')
def career_navigator_view(request): def career_navigator_view(request):
"""Display the career navigator form page""" """Display the career navigator form page"""
if not request.user.is_authenticated: if not request.user.is_authenticated:
# Clear any existing messages to prevent confusion # Clear all existing messages before adding login message
storage = messages.get_messages(request) storage = messages.get_messages(request)
storage.used = True for _ in storage:
messages.error(request, 'Please login to access the Career Navigator.') pass # Consume all messages
# Add login message to session for after login redirect
request.session['post_login_message'] = 'Please complete your login to access the Career Navigator.'
return redirect('authentication:login') return redirect('authentication:login')
# Get the career navigator agent # Get the career navigator agent
@ -292,10 +292,12 @@ def career_navigator_view(request):
def ai_brand_strategist_view(request): def ai_brand_strategist_view(request):
"""Display the AI Brand Strategist form page""" """Display the AI Brand Strategist form page"""
if not request.user.is_authenticated: if not request.user.is_authenticated:
# Clear any existing messages to prevent confusion # Clear all existing messages before adding login message
storage = messages.get_messages(request) storage = messages.get_messages(request)
storage.used = True for _ in storage:
messages.error(request, 'Please login to access the AI Brand Strategist.') pass # Consume all messages
# Add login message to session for after login redirect
request.session['post_login_message'] = 'Please complete your login to access the AI Brand Strategist.'
return redirect('authentication:login') return redirect('authentication:login')
# Get the AI Brand Strategist agent # Get the AI Brand Strategist agent
@ -333,10 +335,12 @@ def ai_brand_strategist_view(request):
def ai_brand_strategist_access(request): def ai_brand_strategist_access(request):
"""Handle Try Now button click - charge wallet and redirect to form""" """Handle Try Now button click - charge wallet and redirect to form"""
if not request.user.is_authenticated: if not request.user.is_authenticated:
# Clear any existing messages to prevent confusion # Clear all existing messages before adding login message
storage = messages.get_messages(request) storage = messages.get_messages(request)
storage.used = True for _ in storage:
messages.error(request, 'Please login to access the AI Brand Strategist.') pass # Consume all messages
# Add login message to session for after login redirect
request.session['post_login_message'] = 'Please complete your login to access the AI Brand Strategist.'
return redirect('authentication:login') return redirect('authentication:login')
# Get the AI Brand Strategist agent # Get the AI Brand Strategist agent
@ -377,11 +381,7 @@ def ai_brand_strategist_access(request):
completed_at=timezone.now() completed_at=timezone.now()
) )
# Success message and redirect to form # Redirect directly to form - no message needed
if agent.price > 0:
messages.success(request, f'Welcome to your {agent.name} consultation.')
else:
messages.success(request, f'Welcome to your {agent.name} consultation.')
return redirect('agents:ai_brand_strategist') return redirect('agents:ai_brand_strategist')
@ -1123,13 +1123,11 @@ def direct_access_handler(request, slug):
description=f'Payment for {agent.name}', description=f'Payment for {agent.name}',
agent_slug=agent.slug agent_slug=agent.slug
) )
messages.success(request, f'Payment of {agent.price} AED processed successfully.')
except Exception as e: except Exception as e:
messages.error(request, 'Payment processing failed. Please try again.') messages.error(request, 'Payment processing failed. Please try again.')
return redirect('agents:agent_detail', slug=slug) return redirect('agents:agent_detail', slug=slug)
# Grant access - redirect to display page # Grant access - redirect directly to display page
messages.success(request, f'Access granted to {agent.name}. Redirecting to consultation form...')
return redirect('agents:direct_access_display', slug=slug) return redirect('agents:direct_access_display', slug=slug)

View File

@ -89,10 +89,17 @@ def handle_ratelimited(request, exception):
@ratelimit(key='ip', rate='5/m', method=UNSAFE, block=False) @ratelimit(key='ip', rate='5/m', method=UNSAFE, block=False)
def login_view(request): def login_view(request):
"""User login view with rate limiting (5 attempts per minute per IP)""" """User login view with rate limiting (5 attempts per minute per IP)"""
# Handle post-login session messages
if 'post_login_message' in request.session:
messages.info(request, request.session.pop('post_login_message'))
# Check if rate limited # Check if rate limited
if getattr(request, 'limited', False): if getattr(request, 'limited', False):
# Use session to avoid repeated rate limit messages
if not request.session.get('rate_limit_shown'):
logger.warning(f"Login rate limit exceeded for IP {request.META.get('REMOTE_ADDR')}") logger.warning(f"Login rate limit exceeded for IP {request.META.get('REMOTE_ADDR')}")
messages.error(request, 'Too many login attempts. Please try again in a few minutes.') messages.error(request, 'Too many login attempts. Please wait before trying again.')
request.session['rate_limit_shown'] = True
return render(request, 'authentication/login.html') return render(request, 'authentication/login.html')
if request.method == 'POST': if request.method == 'POST':
@ -103,12 +110,14 @@ def login_view(request):
if user is not None: if user is not None:
# Check if email is verified (only if email verification is required) # Check if email is verified (only if email verification is required)
if settings.REQUIRE_EMAIL_VERIFICATION and not user.email_verified: if settings.REQUIRE_EMAIL_VERIFICATION and not user.email_verified:
from django.urls import reverse messages.warning(request, 'Please verify your email address before logging in. Check your inbox for the verification link.')
resend_url = reverse('authentication:resend_verification') # Store resend URL in context for template
messages.warning(request, f'Please verify your email address before logging in. Check your inbox for the verification link, or <a href="{resend_url}">resend verification email</a>.') context = {'show_resend_verification': True}
return render(request, 'authentication/login.html') return render(request, 'authentication/login.html', context)
login(request, user) login(request, user)
# Clear rate limit flag on successful login
request.session.pop('rate_limit_shown', None)
# Redirect to 'next' parameter if provided, otherwise homepage # Redirect to 'next' parameter if provided, otherwise homepage
next_url = request.GET.get('next') or request.POST.get('next') next_url = request.GET.get('next') or request.POST.get('next')
if next_url: if next_url:
@ -116,6 +125,8 @@ def login_view(request):
return redirect('core:homepage') return redirect('core:homepage')
else: else:
messages.error(request, 'Invalid email or password') messages.error(request, 'Invalid email or password')
# Clear rate limit flag on any POST attempt (failed login)
request.session.pop('rate_limit_shown', None)
return render(request, 'authentication/login.html') return render(request, 'authentication/login.html')

View File

@ -104,6 +104,37 @@
text-decoration: underline; text-decoration: underline;
} }
.verification-actions {
text-align: center;
margin-bottom: var(--spacing-lg);
padding: var(--spacing-md);
background: var(--surface-variant);
border-radius: var(--radius-sm);
border: 1px solid var(--outline);
}
.verification-text {
margin: 0 0 var(--spacing-sm) 0;
color: var(--on-surface-variant);
font-size: 14px;
}
.btn-outline {
background: transparent;
border: 1px solid var(--primary);
color: var(--primary);
}
.btn-outline:hover {
background: var(--primary);
color: var(--on-primary);
}
.btn-sm {
padding: var(--spacing-xs) var(--spacing-md);
font-size: 14px;
}
/* Responsive */ /* Responsive */
@media (max-width: 480px) { @media (max-width: 480px) {
.login-page { .login-page {
@ -132,11 +163,18 @@
{% if messages %} {% if messages %}
<div class="messages"> <div class="messages">
{% for message in messages %} {% for message in messages %}
<div class="message {{ message.tags }}">{{ message|safe }}</div> <div class="message {{ message.tags }}">{{ message }}</div>
{% endfor %} {% endfor %}
</div> </div>
{% endif %} {% endif %}
{% if show_resend_verification %}
<div class="verification-actions">
<p class="verification-text">Need to resend verification email?</p>
<a href="{% url 'authentication:resend_verification' %}" class="btn btn-outline btn-sm">Resend Verification</a>
</div>
{% endif %}
<form method="post" class="login-form"> <form method="post" class="login-form">
{% csrf_token %} {% csrf_token %}
{% if request.GET.next %} {% if request.GET.next %}