Add recent conversations
This commit is contained in:
parent
e32e46a7a2
commit
2cc5bc7765
4 changed files with 290 additions and 11 deletions
|
@ -1,9 +1,10 @@
|
|||
from flask import request, jsonify, render_template, redirect, url_for, flash, session
|
||||
from flask import request, jsonify, render_template, redirect, url_for, flash, session, make_response
|
||||
from . import app, db, limiter, csrf, webhooks
|
||||
from .webhooks import WebhookError
|
||||
from .models import Inquiry, Message, Settings, Admin
|
||||
import os
|
||||
from datetime import datetime, timedelta
|
||||
import json
|
||||
from datetime import datetime, timedelta, timezone
|
||||
|
||||
# Import admin routes (these will be registered with the app)
|
||||
from . import admin_routes
|
||||
|
@ -13,7 +14,50 @@ from .admin_routes import is_admin
|
|||
|
||||
@app.route('/', methods=['GET'])
|
||||
def index():
|
||||
return render_template('create_inquiry.html')
|
||||
# Get recent inquiries from cookie
|
||||
recent_inquiries = []
|
||||
read_status = {}
|
||||
|
||||
if request.cookies.get('recent_inquiries'):
|
||||
try:
|
||||
inquiry_ids = json.loads(request.cookies.get('recent_inquiries'))
|
||||
recent_inquiries = Inquiry.query.filter(Inquiry.id.in_(inquiry_ids)).all()
|
||||
|
||||
# Get read status for each inquiry
|
||||
if request.cookies.get('read_messages'):
|
||||
read_status = json.loads(request.cookies.get('read_messages'))
|
||||
except:
|
||||
# If there's an error parsing the cookie, just ignore it
|
||||
pass
|
||||
|
||||
# Create a list to store inquiries with their data
|
||||
inquiries_with_data = []
|
||||
|
||||
for inquiry_id in (inquiry_ids if 'inquiry_ids' in locals() else []):
|
||||
for inquiry in recent_inquiries:
|
||||
if inquiry.id == inquiry_id:
|
||||
# Get last message for the inquiry
|
||||
last_message = Message.query.filter_by(inquiry_id=inquiry.id).order_by(Message.message_number.desc()).first()
|
||||
|
||||
# Check if there are unread messages
|
||||
is_unread = False
|
||||
if last_message:
|
||||
last_read = read_status.get(inquiry.id, 0)
|
||||
if last_message.message_number > last_read and last_message.is_admin:
|
||||
is_unread = True
|
||||
|
||||
inquiries_with_data.append({
|
||||
'inquiry': inquiry,
|
||||
'last_message': last_message,
|
||||
'is_unread': is_unread,
|
||||
'position': inquiry_ids.index(inquiry.id) # Keep track of original position
|
||||
})
|
||||
break
|
||||
|
||||
# Sort inquiries - unread first, then by original position (recency)
|
||||
inquiries_with_data.sort(key=lambda x: (0 if x['is_unread'] else 1, x['position']))
|
||||
|
||||
return render_template('create_inquiry.html', recent_inquiries=inquiries_with_data)
|
||||
|
||||
@app.route('/', methods=['POST'])
|
||||
@limiter.limit("5 per hour")
|
||||
|
@ -40,7 +84,8 @@ def create_inquiry():
|
|||
webhooks.inquiry_created(new_inquiry.id, initial_message)
|
||||
except WebhookError as e:
|
||||
app.logger.error(f"Error sending webhook for new inquiry: {str(e)}")
|
||||
|
||||
|
||||
# Add to recent inquiries cookie
|
||||
return redirect(url_for('inquiry', inquiry_id=new_inquiry.id))
|
||||
|
||||
@app.route('/inquiry/<inquiry_id>', methods=['GET', 'POST'])
|
||||
|
@ -48,7 +93,7 @@ def create_inquiry():
|
|||
def inquiry(inquiry_id):
|
||||
inquiry = Inquiry.query.get_or_404(inquiry_id)
|
||||
is_admin_user = is_admin()
|
||||
|
||||
|
||||
if request.method == 'POST':
|
||||
# Handle closed inquiry differently for admin vs non-admin
|
||||
if inquiry.is_closed:
|
||||
|
@ -81,10 +126,57 @@ def inquiry(inquiry_id):
|
|||
except WebhookError as e:
|
||||
app.logger.error(f"Error sending webhook for message: {str(e)}")
|
||||
|
||||
return redirect(url_for('inquiry', inquiry_id=inquiry_id))
|
||||
response = redirect(url_for('inquiry', inquiry_id=inquiry_id))
|
||||
return add_inquiry_to_cookie(response, inquiry_id) if not is_admin_user else response
|
||||
|
||||
messages = Message.query.filter_by(inquiry_id=inquiry_id).order_by(Message.message_number).all()
|
||||
return render_template('inquiry.html', inquiry=inquiry, messages=messages)
|
||||
|
||||
# Update the recent inquiries cookie when viewing an inquiry
|
||||
response = make_response(render_template('inquiry.html', inquiry=inquiry, messages=messages))
|
||||
if not is_admin_user: # Only track inquiries for regular users, not admins
|
||||
response = add_inquiry_to_cookie(response, inquiry_id)
|
||||
|
||||
# Mark all messages in this inquiry as read
|
||||
if messages:
|
||||
last_message_number = messages[-1].message_number
|
||||
read_status = {}
|
||||
|
||||
if request.cookies.get('read_messages'):
|
||||
try:
|
||||
read_status = json.loads(request.cookies.get('read_messages'))
|
||||
except:
|
||||
pass
|
||||
|
||||
# Store directly as inquiry_id: last_read_message_number mapping
|
||||
read_status[inquiry_id] = last_message_number
|
||||
expires = datetime.now(timezone.utc) + timedelta(days=30)
|
||||
response.set_cookie('read_messages', json.dumps(read_status), expires=expires, httponly=True)
|
||||
|
||||
return response
|
||||
|
||||
# Helper function to add an inquiry to the recent inquiries cookie
|
||||
def add_inquiry_to_cookie(response, inquiry_id):
|
||||
recent_inquiries = []
|
||||
if request.cookies.get('recent_inquiries'):
|
||||
try:
|
||||
recent_inquiries = json.loads(request.cookies.get('recent_inquiries'))
|
||||
except:
|
||||
recent_inquiries = []
|
||||
|
||||
# Add the current inquiry to the front of the list if it's not already there
|
||||
if inquiry_id in recent_inquiries:
|
||||
recent_inquiries.remove(inquiry_id)
|
||||
recent_inquiries.insert(0, inquiry_id)
|
||||
|
||||
# Keep only the 5 most recent inquiries
|
||||
recent_inquiries = recent_inquiries[:5]
|
||||
|
||||
# Set the cookie to expire in 30 days
|
||||
expires = datetime.now(timezone.utc) + timedelta(days=30)
|
||||
|
||||
# Set the cookie
|
||||
response.set_cookie('recent_inquiries', json.dumps(recent_inquiries), expires=expires, httponly=True)
|
||||
return response
|
||||
|
||||
@app.route('/inquiry/<inquiry_id>/delete', methods=['POST'])
|
||||
@limiter.limit("10 per hour", deduct_when=lambda response: response.status_code != 200)
|
||||
|
@ -181,4 +273,18 @@ def reopen_inquiry(inquiry_id):
|
|||
if referrer and 'admin/dashboard' in referrer:
|
||||
return redirect(url_for('admin_dashboard'))
|
||||
else:
|
||||
return redirect(url_for('inquiry', inquiry_id=inquiry_id))
|
||||
return redirect(url_for('inquiry', inquiry_id=inquiry_id))
|
||||
|
||||
@app.route('/forget_inquiries', methods=['POST'])
|
||||
def forget_inquiries():
|
||||
# Create a response that redirects to the index page
|
||||
response = redirect(url_for('index'))
|
||||
|
||||
# Clear the recent inquiries cookie by setting it to empty and expiring immediately
|
||||
response.set_cookie('recent_inquiries', '', expires=0)
|
||||
|
||||
# Also clear the read messages status cookie
|
||||
response.set_cookie('read_messages', '', expires=0)
|
||||
|
||||
flash('Your recent conversations have been forgotten.')
|
||||
return response
|
|
@ -142,4 +142,140 @@ th {
|
|||
.btn-primary:hover {
|
||||
background-color: #2d6c30;
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
|
||||
/* Recent Inquiries Styles */
|
||||
.recent-inquiries {
|
||||
margin-top: 2rem;
|
||||
padding-top: 1.5rem;
|
||||
border-top: 1px solid #444;
|
||||
}
|
||||
|
||||
.recent-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.recent-header h3 {
|
||||
margin: 0;
|
||||
color: #bbb;
|
||||
}
|
||||
|
||||
.recent-header form {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.forget-button {
|
||||
background-color: #8c3b3b;
|
||||
color: white;
|
||||
padding: 0.4rem 0.8rem;
|
||||
font-size: 0.9rem;
|
||||
margin-left: 1rem;
|
||||
}
|
||||
|
||||
.forget-button:hover {
|
||||
background-color: #a04343;
|
||||
}
|
||||
|
||||
.inquiry-list {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.inquiry-list li {
|
||||
margin-bottom: 0.8rem;
|
||||
}
|
||||
|
||||
.inquiry-list a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.inquiry-list a:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.inquiry-item {
|
||||
padding: 1rem;
|
||||
background-color: #333;
|
||||
border-radius: 4px;
|
||||
transition: background-color 0.2s ease;
|
||||
border-left: 3px solid transparent;
|
||||
}
|
||||
|
||||
.inquiry-item:hover {
|
||||
background-color: #3a3a3a;
|
||||
}
|
||||
|
||||
/* Unread inquiry styling */
|
||||
.inquiry-item.unread {
|
||||
border-left: 3px solid #3b8c3e;
|
||||
background-color: #383f38;
|
||||
}
|
||||
|
||||
.inquiry-item.unread:hover {
|
||||
background-color: #404a40;
|
||||
}
|
||||
|
||||
.inquiry-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.inquiry-id {
|
||||
font-weight: bold;
|
||||
display: inline-block;
|
||||
margin-right: 0.5rem;
|
||||
}
|
||||
|
||||
.inquiry-status {
|
||||
font-size: 0.8rem;
|
||||
padding: 2px 6px;
|
||||
border-radius: 3px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.inquiry-status.open {
|
||||
background-color: #3b8c3e;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.inquiry-status.closed {
|
||||
background-color: #8c3b3b;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.unread-badge {
|
||||
margin-left: auto;
|
||||
background-color: #3b8c3e;
|
||||
color: white;
|
||||
padding: 2px 8px;
|
||||
border-radius: 10px;
|
||||
font-size: 0.75rem;
|
||||
font-weight: bold;
|
||||
animation: pulse 2s infinite;
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0% {
|
||||
box-shadow: 0 0 0 0 rgba(59, 140, 62, 0.4);
|
||||
}
|
||||
70% {
|
||||
box-shadow: 0 0 0 6px rgba(59, 140, 62, 0);
|
||||
}
|
||||
100% {
|
||||
box-shadow: 0 0 0 0 rgba(59, 140, 62, 0);
|
||||
}
|
||||
}
|
||||
|
||||
.inquiry-message {
|
||||
margin: 0.4rem 0;
|
||||
color: #bbb;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
h2, h3 {
|
||||
padding-left: 1rem;
|
||||
}
|
|
@ -19,4 +19,41 @@
|
|||
<button type="submit">Create New Inquiry</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
{% if recent_inquiries %}
|
||||
<div class="recent-inquiries">
|
||||
<div class="recent-header">
|
||||
<h3>Your Recent Conversations</h3>
|
||||
<form method="POST" action="{{ url_for('forget_inquiries') }}">
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/>
|
||||
<button type="submit" class="forget-button">Forget All</button>
|
||||
</form>
|
||||
</div>
|
||||
<ul class="inquiry-list">
|
||||
{% for item in recent_inquiries %}
|
||||
<li>
|
||||
<a href="{{ url_for('inquiry', inquiry_id=item.inquiry.id) }}">
|
||||
<div class="inquiry-item {% if item.is_unread %}unread{% endif %}">
|
||||
<div class="inquiry-header">
|
||||
<span class="inquiry-id">Inquiry #{{ item.inquiry.id[:8] }}</span>
|
||||
<span class="inquiry-status {% if item.inquiry.is_closed %}closed{% else %}open{% endif %}">
|
||||
{% if item.inquiry.is_closed %}Closed{% else %}Open{% endif %}
|
||||
</span>
|
||||
{% if item.is_unread %}
|
||||
<span class="unread-badge">New Message</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% if item.last_message %}
|
||||
<p class="inquiry-message">
|
||||
<strong>{% if item.last_message.is_admin %}Admin:{% else %}You:{% endif %}</strong>
|
||||
{{ item.last_message.content[:50] }}{% if item.last_message.content|length > 50 %}...{% endif %}
|
||||
</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
|
@ -1,10 +1,10 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Inquiry #{{ inquiry.id[:6] }}{% endblock %}
|
||||
{% block title %}Inquiry #{{ inquiry.id[:8] }}{% endblock %}
|
||||
|
||||
{% block header %}
|
||||
<h2>
|
||||
Inquiry #{{ inquiry.id[:6] }}
|
||||
Inquiry #{{ inquiry.id[:8] }}
|
||||
|
||||
{% if inquiry.is_closed %}
|
||||
<span style="color: #6c757d; font-size: 0.9rem; padding: 0.3rem 0.6rem; background-color: #e9ecef; border-radius: 0.25rem; margin-left: 0.5rem;">CLOSED</span>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue