009b7d896b
- New GET route and template for reviewing individual connection requests
- Optional personal message field when sending connection requests
- Message visible to recipient on review page and connection list
- Dashboard "Review" button links to per-connection review page
- QR scan flow shows message prompt before sending request
- Fix accepted connections query: include both sent and received
- Fix url_for('uploaded_file') -> url_for('static', 'uploads/')
- Fix request.json -> request.is_json to avoid 415 on form POST
- Remove card from DOM on approve/reject instead of page reload
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
104 lines
5.1 KiB
HTML
104 lines
5.1 KiB
HTML
{% extends "base.html" %}
|
|
|
|
{% block title %}{{ 'attendees'|t }} - NetEvents{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="attendees-page">
|
|
{% if event %}
|
|
<div class="event-info-header">
|
|
<h1>{{ event.name }}</h1>
|
|
<div class="event-meta">
|
|
{% if event.location %}
|
|
<span class="event-location">{{ event.location }}</span>
|
|
{% endif %}
|
|
{% if event.start_time %}
|
|
<span class="event-date">{{ event.start_time|localized_date }}</span>
|
|
{% endif %}
|
|
</div>
|
|
{% if event.description %}
|
|
<p class="event-description">{{ event.description }}</p>
|
|
{% endif %}
|
|
</div>
|
|
{% endif %}
|
|
|
|
<p class="page-subtitle">{{ 'connect_with_attendees'|t }}</p>
|
|
|
|
<div class="attendee-search">
|
|
<form method="GET" action="{{ url_for('list_attendees') }}">
|
|
<input type="text" name="q" value="{{ search_query }}" placeholder="{{ 'search_attendees'|t }}">
|
|
<button type="submit" class="btn btn-primary">{{ 'search'|t }}</button>
|
|
</form>
|
|
<p class="search-hint">{{ 'search_min_chars'|t|format(min_chars) }}</p>
|
|
</div>
|
|
|
|
{% if search_query and search_query|length >= min_chars %}
|
|
{% if too_broad %}
|
|
<p class="search-too-broad">{{ 'search_too_broad'|t }}</p>
|
|
{% elif attendees %}
|
|
<div class="attendees-grid">
|
|
{% for att in attendees %}
|
|
<div class="attendee-card">
|
|
<div class="attendee-photo">
|
|
{% if att.profile_picture %}
|
|
<img src="{{ url_for('static', filename='uploads/' + att.profile_picture) }}" alt="Photo">
|
|
{% else %}
|
|
<div class="no-photo"><span class="first-name">{{ att.first_name[0] }}</span><span class="last-name">{{ att.last_name[0] }}</span></div>
|
|
{% endif %}
|
|
</div>
|
|
<div class="attendee-info">
|
|
<h3><span class="first-name">{{ att.first_name }}</span> <span class="last-name">{{ att.last_name }}</span></h3>
|
|
<p class="attendee-org">{{ att.organisation if att.organisation else '' }}</p>
|
|
<p class="attendee-role">{{ att.role if att.role else '' }}</p>
|
|
{% if att.introduction %}
|
|
<p class="attendee-intro">{{ att.introduction[:100] }}{% if att.introduction|length > 100 %}...{% endif %}</p>
|
|
{% endif %}
|
|
</div>
|
|
<div class="attendee-actions">
|
|
{% if att.my_status == 'accepted' %}
|
|
<span class="badge badge-success">{{ 'connected'|t }}</span>
|
|
{% elif att.my_status == 'pending' %}
|
|
<span class="badge badge-pending">{{ 'request_pending'|t }}</span>
|
|
{% elif att.my_status == 'rejected' %}
|
|
<span class="badge badge-rejected">{{ 'rejected'|t }}</span>
|
|
{% else %}
|
|
<button type="button" class="btn btn-sm btn-primary connect-toggle-btn" data-attendee-id="{{ att.id }}">{{ 'connect'|t }}</button>
|
|
<form method="POST" action="{{ url_for('create_connection') }}" class="connect-form hidden" id="connect-form-{{ att.id }}">
|
|
<input type="hidden" name="connected_attendee_id" value="{{ att.id }}">
|
|
<textarea name="message" class="connect-message-input" placeholder="{{ 'optional_message'|t }}" rows="2" maxlength="500"></textarea>
|
|
<div class="connect-form-actions">
|
|
<button type="submit" class="btn btn-sm btn-primary">{{ 'send_request'|t }}</button>
|
|
<button type="button" class="btn btn-sm btn-ghost connect-cancel-btn">{{ 'cancel'|t }}</button>
|
|
</div>
|
|
</form>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
{% endfor %}
|
|
</div>
|
|
{% else %}
|
|
<p class="no-attendees">{{ 'no_attendees_found'|t }}</p>
|
|
{% endif %}
|
|
{% endif %}
|
|
</div>
|
|
{% endblock %}
|
|
|
|
{% block scripts %}
|
|
<script>
|
|
document.querySelectorAll('.connect-toggle-btn').forEach(btn => {
|
|
btn.addEventListener('click', function() {
|
|
const attendeeId = this.dataset.attendeeId;
|
|
this.classList.add('hidden');
|
|
document.getElementById('connect-form-' + attendeeId).classList.remove('hidden');
|
|
});
|
|
});
|
|
|
|
document.querySelectorAll('.connect-cancel-btn').forEach(btn => {
|
|
btn.addEventListener('click', function() {
|
|
const form = this.closest('.connect-form');
|
|
form.classList.add('hidden');
|
|
form.closest('.attendee-actions').querySelector('.connect-toggle-btn').classList.remove('hidden');
|
|
});
|
|
});
|
|
</script>
|
|
{% endblock %}
|