PHP Classes

File: templates/profile.twig

Recommend this page to a friend!
  Packages of Matthew Asham   Binkterm PHP   templates/profile.twig   Download  
File: templates/profile.twig
Role: Auxiliary data
Content type: text/plain
Description: Auxiliary data
Class: Binkterm PHP
Bulletin board system based on the Web
Author: By
Last change:
Date: 5 days ago
Size: 15,565 bytes
 

Contents

Class file image Download
{% extends "base.twig" %} {% block title %}{{ t('ui.profile.title', {}, 'common') }} - {{ parent() }}{% endblock %} {% block content %} <div class="d-flex justify-content-between align-items-center mb-4"> <h2> <i class="fas fa-user"></i> {{ t('ui.profile.my_profile', {}, 'common') }} </h2> <a href="/profile/{{ user_username|url_encode }}" class="btn btn-sm btn-outline-secondary"> <i class="fas fa-id-card me-1"></i> {{ t('ui.profile.view_profile', {}, 'common') }} </a> </div> <div class="row"> <div class="col-lg-8"> <div class="card"> <div class="card-header"> <h5 class="mb-0">{{ t('ui.profile.profile_information', {}, 'common') }}</h5> </div> <div class="card-body"> <form id="profileForm"> <div class="mb-3"> <label for="username" class="form-label">{{ t('ui.profile.username', {}, 'common') }}</label> <input type="text" class="form-control" id="username" name="username" value="{{ user_username }}" readonly> <div class="form-text">{{ t('ui.profile.username_readonly_help', {}, 'common') }}</div> </div> <div class="mb-3"> <label for="realName" class="form-label">{{ t('ui.profile.real_name', {}, 'common') }}</label> <input type="text" class="form-control" id="realName" name="real_name" value="{{ user_real_name }}" readonly maxlength="100"> <div class="form-text">{{ t('ui.profile.real_name_help', {}, 'common') }}</div> </div> <div class="mb-3"> <label for="email" class="form-label">{{ t('ui.profile.email_address', {}, 'common') }}</label> <input type="email" class="form-control" id="email" name="email" value="{{ user_email }}" maxlength="100"> <div class="form-text">{{ t('ui.profile.email_help', {}, 'common') }}</div> </div> <div class="mb-3"> <label for="location" class="form-label">{{ t('ui.profile.location', {}, 'common') }}</label> <input type="text" class="form-control" id="location" name="location" value="{{ user_location }}" maxlength="100" placeholder="{{ t('ui.profile.location_placeholder', {}, 'common') }}"> <div class="form-text">{{ t('ui.profile.location_help', {}, 'common') }}</div> </div> <div class="mb-3"> <label for="aboutMe" class="form-label">{{ t('ui.profile.about_me', {}, 'common') }}</label> <textarea class="form-control" id="aboutMe" name="about_me" rows="5" maxlength="2000" placeholder="{{ t('ui.profile.about_me_placeholder', {}, 'common') }}">{{ user_about_me }}</textarea> <div class="form-text">{{ t('ui.profile.about_me_help', {}, 'common') }}</div> </div> <div class="mb-4"> <h6>{{ t('ui.profile.change_password', {}, 'common') }}</h6> <div class="row"> <div class="col-md-6"> <div class="mb-3"> <label for="currentPassword" class="form-label">{{ t('ui.profile.current_password', {}, 'common') }}</label> <input type="password" class="form-control" id="currentPassword" name="current_password"> </div> </div> <div class="col-md-6"> <div class="mb-3"> <label for="newPassword" class="form-label">{{ t('ui.profile.new_password', {}, 'common') }}</label> <input type="password" class="form-control" id="newPassword" name="new_password"> </div> </div> </div> <div class="form-text">{{ t('ui.profile.password_blank_keep_help', {}, 'common') }}</div> </div> <div class="d-flex justify-content-between"> <div> <small class="text-muted"> {{ t('ui.profile.account_created', {}, 'common') }}: {{ user_created_at|date('F j, Y') }}<br> {{ t('ui.profile.last_login', {}, 'common') }}: {{ user_last_login ? user_last_login|date('F j, Y g:i A') : t('ui.profile.never', {}, 'common') }} </small> </div> <button type="submit" class="btn btn-fidonet"> <i class="fas fa-save"></i> {{ t('ui.profile.update_profile', {}, 'common') }} </button> </div> </form> <div id="profileStatus" class="mt-3" style="display: none;"></div> </div> </div> </div> <div class="col-lg-4"> <div class="card"> <div class="card-header"> <h6 class="mb-0">{{ t('ui.profile.your_network_information', {}, 'common') }}</h6> </div> <div class="card-body"> {% if network_addresses|length > 0 %} <div class="row g-1 mb-3"> {% for net in network_addresses %} <div class="col-3"><span class="badge bg-secondary w-100 text-truncate" title="{{ net.domain }}">{{ net.domain }}</span></div> <div class="col-3"><small class="text-muted">{{ net.address }}</small></div> {% endfor %} </div> {% else %} <p class="text-muted small mb-3">{{ t('ui.profile.no_networks_configured', {}, 'common') }}</p> {% endif %} <button type="button" class="btn btn-outline-secondary btn-sm w-100" data-bs-toggle="modal" data-bs-target="#netmailAddressesModal"> <i class="fas fa-address-card me-1"></i> {{ t('ui.profile.show_netmail_addresses', {}, 'common') }} </button> </div> </div> <div class="card mt-3"> <div class="card-header"> <h6 class="mb-0">{{ t('ui.profile.activity_summary', {}, 'common') }}</h6> </div> <div class="card-body"> <dl class="row mb-0"> <dt class="col-8">{{ t('ui.profile.credits', {}, 'common') }}:</dt> <dd class="col-4"> {% if credits_enabled %} {{ credits_symbol }}{{ credit_balance }} {% else %} <span class="text-muted">{{ t('ui.profile.disabled', {}, 'common') }}</span> {% endif %} </dd> <dt class="col-8">{{ t('ui.profile.netmail_sent', {}, 'common') }}:</dt> <dd class="col-4"><span id="netmailCount">-</span></dd> <dt class="col-8">{{ t('ui.profile.echomail_posted', {}, 'common') }}:</dt> <dd class="col-4"><span id="echomailCount">-</span></dd> <dt class="col-8">{{ t('ui.profile.total_messages', {}, 'common') }}:</dt> <dd class="col-4"><strong><span id="totalCount">-</span></strong></dd> <dt class="col-8">{{ t('ui.profile.files_downloaded', {}, 'common') }}:</dt> <dd class="col-4"><span id="filesDownloaded">-</span></dd> <dt class="col-8">{{ t('ui.profile.files_uploaded', {}, 'common') }}:</dt> <dd class="col-4"><span id="filesUploaded">-</span></dd> <dt class="col-8">{{ t('ui.profile.transfer_ratio', {}, 'common') }}:</dt> <dd class="col-4"><span id="transferRatio">-</span></dd> </dl> </div> </div> {% if credits_enabled %} <div class="card mt-3"> <div class="card-header"> <h6 class="mb-0">{{ t('ui.profile.credit_system', {}, 'common') }}</h6> </div> <div class="card-body"> <small class="text-muted d-block mb-2">{{ t('ui.profile.credit_costs_rewards', {}, 'common') }}</small> <dl class="row mb-2 small"> <dt class="col-8">{{ t('ui.profile.daily_login', {}, 'common') }}:</dt> <dd class="col-4 text-success">+{{ credits_config.daily_amount|default(25) }}</dd> <dt class="col-8">{{ t('ui.profile.netmail_sent', {}, 'common') }}:</dt> <dd class="col-4 text-danger">-{{ credits_config.netmail_cost|default(1) }}</dd> <dt class="col-8">{{ t('ui.profile.crashmail', {}, 'common') }}:</dt> <dd class="col-4 text-danger">-{{ credits_config.crashmail_cost|default(10) }}</dd> <dt class="col-8">{{ t('ui.profile.echomail_posted', {}, 'common') }}:</dt> <dd class="col-4 text-success">+{{ credits_config.echomail_reward|default(3) }}</dd> </dl> <small class="text-muted fst-italic"> <i class="fas fa-info-circle me-1"></i> {{ t('ui.profile.credit_note', {}, 'common') }} </small> </div> </div> {% endif %} </div> </div> <!-- Netmail Addresses Modal --> <div class="modal fade" id="netmailAddressesModal" tabindex="-1" aria-labelledby="netmailAddressesModalLabel" aria-hidden="true"> <div class="modal-dialog modal-dialog-centered"> <div class="modal-content"> <div class="modal-header"> <h5 class="modal-title" id="netmailAddressesModalLabel"> <i class="fas fa-address-card me-2"></i> {{ t('ui.profile.netmail_addresses_title', {}, 'common') }} </h5> <button type="button" class="btn-close" data-bs-dismiss="modal"></button> </div> <div class="modal-body p-0"> {% if network_addresses|length > 0 %} <div class="table-responsive"> <table class="table table-striped mb-0"> <thead> <tr> <th>{{ t('ui.profile.netmail_col_network', {}, 'common') }}</th> <th>{{ t('ui.profile.netmail_col_address', {}, 'common') }}</th> </tr> </thead> <tbody> {% for net in network_addresses %} <tr> <td>{{ net.domain }}</td> <td class="font-monospace">{{ user_real_name }}@{{ net.address }}</td> </tr> {% endfor %} </tbody> </table> </div> {% else %} <p class="text-muted p-3 mb-0">{{ t('ui.profile.no_networks_configured', {}, 'common') }}</p> {% endif %} </div> {% if network_addresses|length > 0 %} <div class="modal-footer"> <small class="text-muted"><i class="fas fa-info-circle me-1"></i>{{ t('ui.profile.netmail_username_note', {'username': user_username}, 'common') }}</small> </div> {% endif %} </div> </div> </div> {% endblock %} {% block scripts %} <script> function uiT(key, fallback, params = {}) { if (window.t) { return window.t(key, params, fallback); } return fallback; } $(document).ready(function() { loadActivityStats(); $('#profileForm').on('submit', function(e) { e.preventDefault(); updateProfile(); }); }); function loadActivityStats() { $.get('/api/user/stats') .done(function(data) { const netmail = data.netmail_count || 0; const echomail = data.echomail_count || 0; const dl = data.files_downloaded || 0; const ul = data.files_uploaded || 0; $('#netmailCount').text(netmail); $('#echomailCount').text(echomail); $('#totalCount').text(netmail + echomail); $('#filesDownloaded').text(dl); $('#filesUploaded').text(ul); let ratio; if (ul === 0 && dl === 0) { ratio = uiT('ui.profile.ratio_na', 'N/A'); } else if (ul === 0) { ratio = uiT('ui.profile.ratio_na', 'N/A'); } else { ratio = (dl / ul).toFixed(2) + ':1'; } $('#transferRatio').text(ratio); }) .fail(function() { $('#netmailCount, #echomailCount, #totalCount, #filesDownloaded, #filesUploaded, #transferRatio').text('?'); }); } function updateProfile() { const formData = new FormData($('#profileForm')[0]); // Show loading status $('#profileStatus').show().html(` <div class="alert alert-info"> <i class="fas fa-spinner fa-spin me-2"></i> ${uiT('ui.profile.updating_profile', 'Updating profile...')} </div> `); $.ajax({ url: '/api/user/profile', method: 'POST', data: formData, processData: false, contentType: false, success: function(response) { const successMessage = window.getApiMessage ? window.getApiMessage(response, uiT('ui.profile.updated_successfully', 'Profile updated successfully!')) : uiT('ui.profile.updated_successfully', 'Profile updated successfully!'); $('#profileStatus').html(` <div class="alert alert-success"> <i class="fas fa-check me-2"></i> ${escapeHtml(successMessage)} </div> `); // Clear password fields $('#currentPassword, #newPassword').val(''); // Update displayed name in navbar if it changed if (response.real_name) { // The navbar shows username, not real name, so no update needed } // Hide success message after 3 seconds setTimeout(function() { $('#profileStatus').fadeOut(); }, 3000); }, error: function(xhr) { const error = window.getApiErrorMessage ? window.getApiErrorMessage(xhr.responseJSON, uiT('errors.user.profile.update_failed', 'Failed to update profile')) : uiT('errors.user.profile.update_failed', 'Failed to update profile'); $('#profileStatus').html(` <div class="alert alert-danger"> <i class="fas fa-exclamation-triangle me-2"></i> ${escapeHtml(error)} </div> `); } }); } </script> {% endblock %}