mirror of
https://github.com/ellite/Wallos.git
synced 2026-01-06 13:19:54 -06:00
feat: add maintenance tasks to admin page
feat: add support to upload svg logos
This commit is contained in:
70
admin.php
70
admin.php
@@ -224,6 +224,76 @@ $loginDisabledAllowed = $userCount == 1 && $settings['registrations_open'] == 0;
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<?php
|
||||
// find unused upload logos
|
||||
|
||||
// Get all logos in the subscriptions table
|
||||
$query = 'SELECT logo FROM subscriptions';
|
||||
$stmt = $db->prepare($query);
|
||||
$result = $stmt->execute();
|
||||
|
||||
$logosOnDB = [];
|
||||
while ($row = $result->fetchArray(SQLITE3_ASSOC)) {
|
||||
$logosOnDB[] = $row['logo'];
|
||||
}
|
||||
|
||||
// Get all logos in the payment_methods table
|
||||
$query = 'SELECT icon FROM payment_methods';
|
||||
$stmt = $db->prepare($query);
|
||||
$result = $stmt->execute();
|
||||
|
||||
while ($row = $result->fetchArray(SQLITE3_ASSOC)) {
|
||||
if (!strstr($row['icon'], "images/uploads/icons/")) {
|
||||
$logosOnDB[] = $row['icon'];
|
||||
}
|
||||
}
|
||||
|
||||
$logosOnDB = array_unique($logosOnDB);
|
||||
|
||||
// Get all logos in the uploads folder
|
||||
$uploadDir = 'images/uploads/logos/';
|
||||
$uploadFiles = scandir($uploadDir);
|
||||
|
||||
foreach ($uploadFiles as $file) {
|
||||
if ($file != '.'&& $file != '..' && $file != 'avatars') {
|
||||
$logosOnDisk[] = ['logo' => $file];
|
||||
}
|
||||
}
|
||||
|
||||
// Find unused logos
|
||||
$unusedLogos = [];
|
||||
foreach ($logosOnDisk as $disk) {
|
||||
$found = false;
|
||||
foreach ($logosOnDB as $dbLogo) {
|
||||
if ($disk['logo'] == $dbLogo) {
|
||||
$found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!$found) {
|
||||
$unusedLogos[] = $disk;
|
||||
}
|
||||
}
|
||||
|
||||
$logosToDelete = count($unusedLogos);
|
||||
|
||||
?>
|
||||
|
||||
<section class="account-section">
|
||||
<header>
|
||||
<h2>
|
||||
<?= translate('maintenance_tasks', $i18n) ?>
|
||||
</h2>
|
||||
</header>
|
||||
<div class="maintenance-tasks">
|
||||
<h3><?= translate('orphaned_logos', $i18n) ?></h3>
|
||||
<div class="form-group-inline">
|
||||
<input type="button" class="button thin mobile-grow" value="<?= translate('delete', $i18n) ?>" id="deleteUnusedLogos"
|
||||
onClick="deleteUnusedLogos()" <?= $logosToDelete == 0 ? 'disabled' : '' ?> />
|
||||
<span class="number-of-logos bold"><?= $logosToDelete ?></span> <?= translate('orphaned_logos', $i18n) ?>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="account-section">
|
||||
<header>
|
||||
|
||||
76
endpoints/admin/deleteunusedlogos.php
Normal file
76
endpoints/admin/deleteunusedlogos.php
Normal file
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
|
||||
require_once '../../includes/connect_endpoint.php';
|
||||
|
||||
if (!isset($_SESSION['loggedin']) || $_SESSION['loggedin'] !== true) {
|
||||
die(json_encode([
|
||||
"success" => false,
|
||||
"message" => translate('session_expired', $i18n)
|
||||
]));
|
||||
}
|
||||
|
||||
// Check that user is an admin
|
||||
if ($userId !== 1) {
|
||||
die(json_encode([
|
||||
"success" => false,
|
||||
"message" => translate('error', $i18n)
|
||||
]));
|
||||
}
|
||||
|
||||
$query = 'SELECT logo FROM subscriptions';
|
||||
$stmt = $db->prepare($query);
|
||||
$result = $stmt->execute();
|
||||
|
||||
$logosOnDB = [];
|
||||
while ($row = $result->fetchArray(SQLITE3_ASSOC)) {
|
||||
$logosOnDB[] = $row['logo'];
|
||||
}
|
||||
|
||||
$logosOnDB = array_unique($logosOnDB);
|
||||
|
||||
$uploadDir = '../../images/uploads/logos/';
|
||||
$uploadFiles = scandir($uploadDir);
|
||||
|
||||
foreach ($uploadFiles as $file) {
|
||||
if ($file != '.' && $file != '..' && $file != 'avatars') {
|
||||
$logosOnDisk[] = ['logo' => $file];
|
||||
}
|
||||
}
|
||||
|
||||
// Get all logos in the payment_methods table
|
||||
$query = 'SELECT icon FROM payment_methods';
|
||||
$stmt = $db->prepare($query);
|
||||
$result = $stmt->execute();
|
||||
|
||||
while ($row = $result->fetchArray(SQLITE3_ASSOC)) {
|
||||
if (!strstr($row['icon'], "images/uploads/icons/")) {
|
||||
$logosOnDB[] = $row['icon'];
|
||||
}
|
||||
}
|
||||
|
||||
$logosOnDB = array_unique($logosOnDB);
|
||||
|
||||
// Find and delete unused logos
|
||||
$count = 0;
|
||||
foreach ($logosOnDisk as $disk) {
|
||||
foreach ($logosOnDB as $db) {
|
||||
$found = false;
|
||||
if ($disk['logo'] == $db) {
|
||||
$found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!$found) {
|
||||
unlink($uploadDir . $disk['logo']);
|
||||
$count++;
|
||||
}
|
||||
}
|
||||
|
||||
echo json_encode([
|
||||
"success" => true,
|
||||
"message" => translate('success', $i18n),
|
||||
'count' => $count
|
||||
]);
|
||||
|
||||
|
||||
?>
|
||||
@@ -297,6 +297,8 @@ $i18n = [
|
||||
"create_user" => "Benutzer erstellen",
|
||||
"smtp_settings" => "SMTP Einstellungen",
|
||||
"smtp_usage_info" => "Wird für die Passwortwiederherstellung und andere System-E-Mails verwendet",
|
||||
"maintenance_tasks" => "Wartungsaufgaben",
|
||||
"orphaned_logos" => "Verwaiste Logos",
|
||||
// Email Verification
|
||||
"email_verified" => "E-Mail verifiziert",
|
||||
"email_verification_failed" => "E-Mail konnte nicht verifiziert werden",
|
||||
|
||||
@@ -297,6 +297,8 @@ $i18n = [
|
||||
"create_user" => "Δημιουργία χρήστη",
|
||||
"smtp_settings" => "SMTP ρυθμίσεις",
|
||||
"smtp_usage_info" => "Θα χρησιμοποιηθεί για ανάκτηση κωδικού πρόσβασης και άλλα μηνύματα ηλεκτρονικού ταχυδρομείου συστήματος.",
|
||||
"maintenance_tasks" => "Εργασίες συντήρησης",
|
||||
"orphaned_logos" => "Ορφανά λογότυπα",
|
||||
// Email Verification
|
||||
"email_verified" => "Το email επιβεβαιώθηκε",
|
||||
"email_verification_failed" => "Η επαλήθευση email απέτυχε",
|
||||
|
||||
@@ -297,6 +297,8 @@ $i18n = [
|
||||
"create_user" => "Create User",
|
||||
"smtp_settings" => "SMTP Settings",
|
||||
"smtp_usage_info" => "Will be used for password recovery and other system emails.",
|
||||
"maintenance_tasks" => "Maintenance Tasks",
|
||||
"orphaned_logos" => "Orphaned Logos",
|
||||
// Email Verification
|
||||
"email_verified" => "Email verified successfully",
|
||||
"email_verification_failed" => "Email verification failed",
|
||||
|
||||
@@ -297,6 +297,8 @@ $i18n = [
|
||||
"create_user" => "Crear Usuario",
|
||||
"smtp_settings" => "Configuración SMTP",
|
||||
"smtp_usage_info" => "Se utilizará para recuperar contraseñas y otros correos electrónicos del sistema.",
|
||||
"maintenance_tasks" => "Tareas de Mantenimiento",
|
||||
"orphaned_logos" => "Logotipos huérfanos",
|
||||
// Email Verification
|
||||
"email_verified" => "Correo electrónico verificado",
|
||||
"email_verification_failed" => "Error al verificar el correo electrónico",
|
||||
|
||||
@@ -297,6 +297,8 @@ $i18n = [
|
||||
"create_user" => "Créer un utilisateur",
|
||||
"smtp_settings" => "Paramètres SMTP",
|
||||
"smtp_usage_info" => "Sera utilisé pour la récupération du mot de passe et d'autres e-mails système.",
|
||||
"maintenance_tasks" => "Tâches de maintenance",
|
||||
"orphaned_logos" => "Logos orphelins",
|
||||
// Email Verification
|
||||
"email_verified" => "Votre adresse courriel a été vérifiée avec succès",
|
||||
"email_verification_failed" => "La vérification de l'adresse courriel a échoué",
|
||||
|
||||
@@ -315,6 +315,8 @@ $i18n = [
|
||||
"create_user" => "Crea utente",
|
||||
"smtp_settings" => "Impostazioni SMTP",
|
||||
"smtp_usage_info" => "Verrà utilizzato per il recupero della password e altre e-mail di sistema.",
|
||||
"maintenance_tasks" => "Compiti di manutenzione",
|
||||
"orphaned_logos" => "Loghi orfani",
|
||||
|
||||
// Email Verification
|
||||
"email_verified" => "L'indirizzo email è stato verificato con successo",
|
||||
|
||||
@@ -297,6 +297,8 @@ $i18n = [
|
||||
"create_user" => "ユーザーを作成",
|
||||
"smtp_settings" => "SMTP設定",
|
||||
"smtp_usage_info" => "パスワードの回復やその他のシステム電子メールに使用されます。",
|
||||
"maintenance_tasks" => "メンテナンスタスク",
|
||||
"orphaned_logos" => "孤立したロゴ",
|
||||
// Email Verification
|
||||
"email_verified" => "メールアドレスが確認されました",
|
||||
"email_verification_failed" => "メールアドレスの確認に失敗しました",
|
||||
|
||||
@@ -298,6 +298,8 @@ $i18n = [
|
||||
"create_user" => "유저 생성",
|
||||
"smtp_settings" => "SMTP 설정",
|
||||
"smtp_usage_info" => "비밀번호 복구 및 기타 시스템 이메일에 사용됩니다.",
|
||||
"maintenance_tasks" => "유지보수 작업",
|
||||
"orphaned_logos" => "고아 로고",
|
||||
// Email Verification
|
||||
"email_verified" => "이메일 인증 완료",
|
||||
"email_verification_failed" => "이메일 인증 실패",
|
||||
|
||||
@@ -297,6 +297,8 @@ $i18n = [
|
||||
"create_user" => "Utwórz użytkownika",
|
||||
"smtp_settings" => "Ustawienia SMTP",
|
||||
"smtp_usage_info" => "Będzie używany do odzyskiwania hasła i innych e-maili systemowych.",
|
||||
"maintenance_tasks" => "Zadania konserwacyjne",
|
||||
"orphaned_logos" => "Osierocone logo",
|
||||
// Email Verification
|
||||
"email_verified" => "E-mail został zweryfikowany",
|
||||
"email_verification_failed" => "Weryfikacja e-maila nie powiodła się",
|
||||
|
||||
@@ -297,6 +297,8 @@ $i18n = [
|
||||
"create_user" => "Criar Utilizador",
|
||||
"smtp_settings" => "Definições SMTP",
|
||||
"smtp_usage_info" => "Será usado para recuperações de password e outros emails do sistema.",
|
||||
"maintenance_tasks" => "Tarefas de Manutenção",
|
||||
"orphaned_logos" => "Logos Órfãos",
|
||||
// Email Verification
|
||||
"email_verified" => "Email verificado",
|
||||
"email_verification_failed" => "Verificação de email falhou",
|
||||
|
||||
@@ -297,6 +297,8 @@ $i18n = [
|
||||
"create_user" => "Criar usuário",
|
||||
"smtp_settings" => "Configurações SMTP",
|
||||
"smtp_usage_info" => "Será usado para recuperação de senha e outros e-mails do sistema.",
|
||||
"maintenance_tasks" => "Tarefas de manutenção",
|
||||
"orphaned_logos" => "Logos órfãos",
|
||||
// Email Verification
|
||||
"email_verified" => "Email verificado",
|
||||
"email_verification_failed" => "Falha na verificação do email",
|
||||
|
||||
@@ -297,6 +297,8 @@ $i18n = [
|
||||
"create_user" => "Создать пользователя",
|
||||
"smtp_settings" => "Настройки SMTP",
|
||||
"smtp_usage_info" => "Будет использоваться для восстановления пароля и других системных писем.",
|
||||
"maintenance_tasks" => "Задачи обслуживания",
|
||||
"orphaned_logos" => "Одинокие логотипы",
|
||||
// Email Verification
|
||||
"email_verified" => "Ваш адрес электронной почты подтвержден. Теперь вы можете войти.",
|
||||
"email_verification_failed" => "Не удалось подтвердить ваш адрес электронной почты.",
|
||||
|
||||
@@ -297,6 +297,8 @@ $i18n = [
|
||||
"create_user" => "Ustvari uporabnika",
|
||||
"smtp_settings" => "Nastavitve SMTP",
|
||||
"smtp_usage_info" => "Uporabljeno bo za obnovitev gesla in druge sistemske e-pošte.",
|
||||
"maintenance_tasks" => "Vzdrževalne naloge",
|
||||
"orphaned_logos" => "Osamljeni logotipi",
|
||||
// Email Verification
|
||||
"email_verified" => "E-pošta je bila uspešno preverjena",
|
||||
"email_verification_failed" => "Preverjanje e-pošte ni uspelo",
|
||||
|
||||
@@ -297,6 +297,8 @@ $i18n = [
|
||||
"create_user" => "Креирај корисника",
|
||||
"smtp_settings" => "SMTP подешавања",
|
||||
"smtp_usage_info" => "SMTP се користи за слање е-поште за обавештења.",
|
||||
"maintenance_tasks" => "Одржавање",
|
||||
"orphaned_logos" => "Породични логотипови",
|
||||
// Email Verification
|
||||
"email_verified" => "Е-пошта је верификована",
|
||||
"email_verification_failed" => "Верификација е-поште није успела",
|
||||
|
||||
@@ -297,6 +297,8 @@ $i18n = [
|
||||
"create_user" => "Kreiraj korisnika",
|
||||
"smtp_settings" => "SMTP podešavanja",
|
||||
"smtp_usage_info" => "Koristiće se za oporavak lozinke i druge sistemske e-poruke.",
|
||||
"maintenance_tasks" => "Održavanje",
|
||||
"orphaned_logos" => "Nepovezani logotipi",
|
||||
// Email Verification
|
||||
"email_verified" => "E-pošta je uspešno verifikovana",
|
||||
"email_verification_failed" => "Verifikacija e-pošte nije uspela",
|
||||
|
||||
@@ -297,6 +297,8 @@ $i18n = [
|
||||
"create_user" => "Kullanıcı Oluştur",
|
||||
"smtp_settings" => "SMTP Ayarları",
|
||||
"smtp_usage_info" => "Şifre kurtarma ve diğer sistem e-postaları için kullanılacaktır.",
|
||||
"maintenance_tasks" => "Bakım Görevleri",
|
||||
"orphaned_logos" => "Yetim Logolar",
|
||||
// Email Verification
|
||||
"email_verified" => "E-posta doğrulandı",
|
||||
"email_verification_failed" => "E-posta doğrulaması başarısız oldu",
|
||||
|
||||
@@ -315,6 +315,8 @@ $i18n = [
|
||||
"create_user" => "创建用户",
|
||||
"smtp_settings" => "SMTP 设置",
|
||||
"smtp_usage_info" => "将用于密码恢复和其他系统电子邮件。",
|
||||
"maintenance_tasks" => "维护任务",
|
||||
"orphaned_logos" => "孤立的 Logo",
|
||||
|
||||
// Email Verification
|
||||
"email_verified" => "电子邮件已验证",
|
||||
|
||||
@@ -297,6 +297,8 @@ $i18n = [
|
||||
"create_user" => "建立使用者",
|
||||
"smtp_settings" => "SMTP 設定",
|
||||
"smtp_usage_info" => "將用於密碼恢復和其他系統電子郵件。",
|
||||
"maintenance_tasks" => "維護任務",
|
||||
"orphaned_logos" => "孤立的圖示",
|
||||
// Email Verification
|
||||
"email_verified" => "電子郵件已驗證",
|
||||
"email_verification_failed" => "電子郵件驗證失敗",
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
<?php
|
||||
$version = "v2.14.2";
|
||||
$version = "v2.15.0";
|
||||
?>
|
||||
@@ -237,7 +237,7 @@ $headerClass = count($subscriptions) > 0 ? "main-actions" : "main-actions hidden
|
||||
<label for="logo" class="logo-preview">
|
||||
<img src="" alt="<?= translate('logo_preview', $i18n) ?>" id="form-logo">
|
||||
</label>
|
||||
<input type="file" id="logo" name="logo" accept="image/jpeg, image/png, image/gif, image/webp"
|
||||
<input type="file" id="logo" name="logo" accept="image/jpeg, image/png, image/gif, image/webp, image/svg+xml"
|
||||
onchange="handleFileSelect(event)" class="hidden-input">
|
||||
<input type="hidden" id="logo-url" name="logo-url">
|
||||
<div id="logo-search-button" class="image-button medium disabled" title="<?= translate('search_logo', $i18n) ?>"
|
||||
|
||||
@@ -262,4 +262,26 @@ function addUserButton() {
|
||||
showErrorMessage(error);
|
||||
button.disabled = false;
|
||||
});
|
||||
}
|
||||
|
||||
function deleteUnusedLogos() {
|
||||
const button = document.getElementById('deleteUnusedLogos');
|
||||
button.disabled = true;
|
||||
|
||||
fetch('endpoints/admin/deleteunusedlogos.php')
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
showSuccessMessage(data.message);
|
||||
const numberOfLogos = document.querySelector('.number-of-logos');
|
||||
numberOfLogos.innerText = '0';
|
||||
} else {
|
||||
showErrorMessage(data.message);
|
||||
button.disabled = false;
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
showErrorMessage(error);
|
||||
button.disabled = false;
|
||||
});
|
||||
}
|
||||
@@ -20,27 +20,27 @@ function toggleNotificationDays() {
|
||||
}
|
||||
|
||||
function resetForm() {
|
||||
const id = document.querySelector("#id");
|
||||
id.value = "";
|
||||
const formTitle = document.querySelector("#form-title");
|
||||
formTitle.textContent = translate('add_subscription');
|
||||
const logo = document.querySelector("#form-logo");
|
||||
logo.src = "";
|
||||
logo.style = 'display: none';
|
||||
const logoUrl = document.querySelector("#logo-url");
|
||||
logoUrl.value = "";
|
||||
const logoSearchButton = document.querySelector("#logo-search-button");
|
||||
logoSearchButton.classList.add("disabled");
|
||||
const submitButton = document.querySelector("#save-button");
|
||||
submitButton.disabled = false;
|
||||
const notifyDaysBefore = document.querySelector("#notify_days_before");
|
||||
notifyDaysBefore.disabled = true;
|
||||
const form = document.querySelector("#subs-form");
|
||||
form.reset();
|
||||
closeLogoSearch();
|
||||
const deleteButton = document.querySelector("#deletesub");
|
||||
deleteButton.style = 'display: none';
|
||||
deleteButton.removeAttribute("onClick");
|
||||
const id = document.querySelector("#id");
|
||||
id.value = "";
|
||||
const formTitle = document.querySelector("#form-title");
|
||||
formTitle.textContent = translate('add_subscription');
|
||||
const logo = document.querySelector("#form-logo");
|
||||
logo.src = "";
|
||||
logo.style = 'display: none';
|
||||
const logoUrl = document.querySelector("#logo-url");
|
||||
logoUrl.value = "";
|
||||
const logoSearchButton = document.querySelector("#logo-search-button");
|
||||
logoSearchButton.classList.add("disabled");
|
||||
const submitButton = document.querySelector("#save-button");
|
||||
submitButton.disabled = false;
|
||||
const notifyDaysBefore = document.querySelector("#notify_days_before");
|
||||
notifyDaysBefore.disabled = true;
|
||||
const form = document.querySelector("#subs-form");
|
||||
form.reset();
|
||||
closeLogoSearch();
|
||||
const deleteButton = document.querySelector("#deletesub");
|
||||
deleteButton.style = 'display: none';
|
||||
deleteButton.removeAttribute("onClick");
|
||||
}
|
||||
|
||||
function fillEditFormFields(subscription) {
|
||||
@@ -106,12 +106,12 @@ function fillEditFormFields(subscription) {
|
||||
}
|
||||
|
||||
function openEditSubscription(event, id) {
|
||||
event.stopPropagation();
|
||||
scrollTopBeforeOpening = window.scrollY;
|
||||
const body = document.querySelector('body');
|
||||
body.classList.add('no-scroll');
|
||||
const url = `endpoints/subscription/get.php?id=${id}`;
|
||||
fetch(url)
|
||||
event.stopPropagation();
|
||||
scrollTopBeforeOpening = window.scrollY;
|
||||
const body = document.querySelector('body');
|
||||
body.classList.add('no-scroll');
|
||||
const url = `endpoints/subscription/get.php?id=${id}`;
|
||||
fetch(url)
|
||||
.then((response) => {
|
||||
if (response.ok) {
|
||||
return response.json();
|
||||
@@ -133,41 +133,41 @@ function openEditSubscription(event, id) {
|
||||
}
|
||||
|
||||
function addSubscription() {
|
||||
resetForm();
|
||||
const modal = document.getElementById('subscription-form');
|
||||
modal.classList.add("is-open");
|
||||
const body = document.querySelector('body');
|
||||
body.classList.add('no-scroll');
|
||||
resetForm();
|
||||
const modal = document.getElementById('subscription-form');
|
||||
modal.classList.add("is-open");
|
||||
const body = document.querySelector('body');
|
||||
body.classList.add('no-scroll');
|
||||
}
|
||||
|
||||
function closeAddSubscription() {
|
||||
const modal = document.getElementById('subscription-form');
|
||||
modal.classList.remove("is-open");
|
||||
const body = document.querySelector('body');
|
||||
body.classList.remove('no-scroll');
|
||||
if (shouldScroll) {
|
||||
window.scrollTo(0, scrollTopBeforeOpening);
|
||||
}
|
||||
resetForm();
|
||||
const modal = document.getElementById('subscription-form');
|
||||
modal.classList.remove("is-open");
|
||||
const body = document.querySelector('body');
|
||||
body.classList.remove('no-scroll');
|
||||
if (shouldScroll) {
|
||||
window.scrollTo(0, scrollTopBeforeOpening);
|
||||
}
|
||||
resetForm();
|
||||
}
|
||||
|
||||
function handleFileSelect(event) {
|
||||
const fileInput = event.target;
|
||||
const logoPreview = document.querySelector('.logo-preview');
|
||||
const logoImg = logoPreview.querySelector('img');
|
||||
const logoUrl = document.querySelector("#logo-url");
|
||||
logoUrl.value = "";
|
||||
const fileInput = event.target;
|
||||
const logoPreview = document.querySelector('.logo-preview');
|
||||
const logoImg = logoPreview.querySelector('img');
|
||||
const logoUrl = document.querySelector("#logo-url");
|
||||
logoUrl.value = "";
|
||||
|
||||
if (fileInput.files && fileInput.files[0]) {
|
||||
const reader = new FileReader();
|
||||
if (fileInput.files && fileInput.files[0]) {
|
||||
const reader = new FileReader();
|
||||
|
||||
reader.onload = function (e) {
|
||||
logoImg.src = e.target.result;
|
||||
logoImg.style.display = 'block';
|
||||
};
|
||||
reader.onload = function (e) {
|
||||
logoImg.src = e.target.result;
|
||||
logoImg.style.display = 'block';
|
||||
};
|
||||
|
||||
reader.readAsDataURL(fileInput.files[0]);
|
||||
}
|
||||
reader.readAsDataURL(fileInput.files[0]);
|
||||
}
|
||||
}
|
||||
|
||||
function deleteSubscription(event, id) {
|
||||
@@ -177,7 +177,7 @@ function deleteSubscription(event, id) {
|
||||
fetch(`endpoints/subscription/delete.php?id=${id}`, {
|
||||
method: 'DELETE',
|
||||
})
|
||||
.then(response => {
|
||||
.then(response => {
|
||||
if (response.ok) {
|
||||
showSuccessMessage(translate('subscription_deleted'));
|
||||
fetchSubscriptions();
|
||||
@@ -185,10 +185,10 @@ function deleteSubscription(event, id) {
|
||||
} else {
|
||||
showErrorMessage(translate('error_deleting_subscription'));
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error:', error);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -216,7 +216,7 @@ function cloneSubscription(event, id) {
|
||||
.catch(error => {
|
||||
showErrorMessage(error.message || translate('error'));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function setSearchButtonStatus() {
|
||||
|
||||
@@ -239,17 +239,17 @@ function searchLogo() {
|
||||
logoSearchPopup.classList.add("is-open");
|
||||
const imageSearchUrl = `endpoints/logos/search.php?search=${searchTerm}`;
|
||||
fetch(imageSearchUrl)
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.imageUrls) {
|
||||
displayImageResults(data.imageUrls);
|
||||
} else if (data.error) {
|
||||
console.error(data.error);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error(translate('error_fetching_image_results'), error);
|
||||
});
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.imageUrls) {
|
||||
displayImageResults(data.imageUrls);
|
||||
} else if (data.error) {
|
||||
console.error(data.error);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error(translate('error_fetching_image_results'), error);
|
||||
});
|
||||
} else {
|
||||
nameInput.focus();
|
||||
}
|
||||
@@ -260,15 +260,15 @@ function displayImageResults(imageSources) {
|
||||
logoResults.innerHTML = "";
|
||||
|
||||
imageSources.forEach(src => {
|
||||
const img = document.createElement("img");
|
||||
img.src = src;
|
||||
img.onclick = function() {
|
||||
selectWebLogo(src);
|
||||
};
|
||||
img.onerror = function() {
|
||||
this.parentNode.removeChild(this);
|
||||
};
|
||||
logoResults.appendChild(img);
|
||||
const img = document.createElement("img");
|
||||
img.src = src;
|
||||
img.onclick = function () {
|
||||
selectWebLogo(src);
|
||||
};
|
||||
img.onerror = function () {
|
||||
this.parentNode.removeChild(this);
|
||||
};
|
||||
logoResults.appendChild(img);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -323,7 +323,7 @@ function fetchSubscriptions() {
|
||||
function setSortOption(sortOption) {
|
||||
const sortOptionsContainer = document.querySelector("#sort-options");
|
||||
const sortOptionsList = sortOptionsContainer.querySelectorAll("li");
|
||||
sortOptionsList.forEach((option) => {
|
||||
sortOptionsList.forEach((option) => {
|
||||
if (option.getAttribute("id") === "sort-" + sortOption) {
|
||||
option.classList.add("selected");
|
||||
} else {
|
||||
@@ -339,21 +339,46 @@ function setSortOption(sortOption) {
|
||||
toggleSortOptions();
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const subscriptionForm = document.querySelector("#subs-form");
|
||||
const submitButton = document.querySelector("#save-button");
|
||||
const endpoint = "endpoints/subscription/add.php";
|
||||
function convertSvgToPng(file, callback) {
|
||||
const reader = new FileReader();
|
||||
|
||||
subscriptionForm.addEventListener("submit", function (e) {
|
||||
e.preventDefault();
|
||||
|
||||
submitButton.disabled = true;
|
||||
const formData = new FormData(subscriptionForm);
|
||||
reader.onload = function (e) {
|
||||
const img = new Image();
|
||||
img.src = e.target.result;
|
||||
img.onload = function() {
|
||||
const canvas = document.createElement('canvas');
|
||||
canvas.width = img.width;
|
||||
canvas.height = img.height;
|
||||
const ctx = canvas.getContext('2d');
|
||||
ctx.drawImage(img, 0, 0);
|
||||
const pngDataUrl = canvas.toDataURL('image/png');
|
||||
const pngFile = dataURLtoFile(pngDataUrl, file.name.replace(".svg", ".png"));
|
||||
callback(pngFile);
|
||||
};
|
||||
};
|
||||
|
||||
fetch(endpoint, {
|
||||
method: "POST",
|
||||
body: formData,
|
||||
})
|
||||
reader.readAsDataURL(file);
|
||||
}
|
||||
|
||||
function dataURLtoFile(dataurl, filename) {
|
||||
let arr = dataurl.split(','),
|
||||
mime = arr[0].match(/:(.*?);/)[1],
|
||||
bstr = atob(arr[1]),
|
||||
n = bstr.length,
|
||||
u8arr = new Uint8Array(n);
|
||||
|
||||
while(n--){
|
||||
u8arr[n] = bstr.charCodeAt(n);
|
||||
}
|
||||
|
||||
return new File([u8arr], filename, {type:mime});
|
||||
}
|
||||
|
||||
function submitFormData(formData, submitButton, endpoint) {
|
||||
fetch(endpoint, {
|
||||
method: "POST",
|
||||
body: formData,
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then((data) => {
|
||||
if (data.status === "Success") {
|
||||
@@ -363,45 +388,69 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
showErrorMessage(error);
|
||||
submitButton.disabled = false;
|
||||
});
|
||||
showErrorMessage(error);
|
||||
submitButton.disabled = false;
|
||||
});
|
||||
}
|
||||
|
||||
document.addEventListener('mousedown', function(event) {
|
||||
const sortOptions = document.querySelector('#sort-options');
|
||||
const sortButton = document.querySelector("#sort-button");
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
const subscriptionForm = document.querySelector("#subs-form");
|
||||
const submitButton = document.querySelector("#save-button");
|
||||
const endpoint = "endpoints/subscription/add.php";
|
||||
|
||||
if (!sortOptions.contains(event.target) && !sortButton.contains(event.target) && isSortOptionsOpen) {
|
||||
sortOptions.classList.remove('is-open');
|
||||
isSortOptionsOpen = false;
|
||||
}
|
||||
});
|
||||
subscriptionForm.addEventListener("submit", function (e) {
|
||||
e.preventDefault();
|
||||
|
||||
submitButton.disabled = true;
|
||||
const formData = new FormData(subscriptionForm);
|
||||
|
||||
document.querySelector('#sort-options').addEventListener('focus', function() {
|
||||
isSortOptionsOpen = true;
|
||||
});
|
||||
const fileInput = document.querySelector("#logo");
|
||||
const file = fileInput.files[0];
|
||||
|
||||
if (file && file.type === "image/svg+xml") {
|
||||
convertSvgToPng(file, function(pngFile) {
|
||||
formData.set("logo", pngFile);
|
||||
submitFormData(formData, submitButton, endpoint);
|
||||
});
|
||||
} else {
|
||||
submitFormData(formData, submitButton, endpoint);
|
||||
}
|
||||
});
|
||||
|
||||
document.addEventListener('mousedown', function (event) {
|
||||
const sortOptions = document.querySelector('#sort-options');
|
||||
const sortButton = document.querySelector("#sort-button");
|
||||
|
||||
if (!sortOptions.contains(event.target) && !sortButton.contains(event.target) && isSortOptionsOpen) {
|
||||
sortOptions.classList.remove('is-open');
|
||||
isSortOptionsOpen = false;
|
||||
}
|
||||
});
|
||||
|
||||
document.querySelector('#sort-options').addEventListener('focus', function () {
|
||||
isSortOptionsOpen = true;
|
||||
});
|
||||
});
|
||||
|
||||
function searchSubscriptions() {
|
||||
const searchInput = document.querySelector("#search");
|
||||
const searchTerm = searchInput.value.trim().toLowerCase();
|
||||
const searchInput = document.querySelector("#search");
|
||||
const searchTerm = searchInput.value.trim().toLowerCase();
|
||||
|
||||
const subscriptions = document.querySelectorAll(".subscription");
|
||||
subscriptions.forEach(subscription => {
|
||||
const name = subscription.getAttribute('data-name').toLowerCase();
|
||||
if (!name.includes(searchTerm)) {
|
||||
subscription.classList.add("hide");
|
||||
} else {
|
||||
subscription.classList.remove("hide");
|
||||
}
|
||||
});
|
||||
const subscriptions = document.querySelectorAll(".subscription");
|
||||
subscriptions.forEach(subscription => {
|
||||
const name = subscription.getAttribute('data-name').toLowerCase();
|
||||
if (!name.includes(searchTerm)) {
|
||||
subscription.classList.add("hide");
|
||||
} else {
|
||||
subscription.classList.remove("hide");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function closeSubMenus() {
|
||||
var subMenus = document.querySelectorAll('.filtermenu-submenu-content');
|
||||
subMenus.forEach(subMenu => {
|
||||
subMenu.classList.remove('is-open');
|
||||
subMenu.classList.remove('is-open');
|
||||
});
|
||||
|
||||
}
|
||||
@@ -411,84 +460,84 @@ activeFilters['category'] = "";
|
||||
activeFilters['member'] = "";
|
||||
activeFilters['payment'] = "";
|
||||
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
var filtermenu = document.querySelector('#filtermenu-button');
|
||||
filtermenu.addEventListener('click', function() {
|
||||
this.parentElement.querySelector('.filtermenu-content').classList.toggle('is-open');
|
||||
closeSubMenus();
|
||||
filtermenu.addEventListener('click', function () {
|
||||
this.parentElement.querySelector('.filtermenu-content').classList.toggle('is-open');
|
||||
closeSubMenus();
|
||||
});
|
||||
|
||||
document.addEventListener('click', function(e) {
|
||||
var filtermenuContent = document.querySelector('.filtermenu-content');
|
||||
if (filtermenuContent.classList.contains('is-open')) {
|
||||
var subMenus = document.querySelectorAll('.filtermenu-submenu');
|
||||
var clickedInsideSubmenu = Array.from(subMenus).some(subMenu => subMenu.contains(e.target) || subMenu === e.target);
|
||||
document.addEventListener('click', function (e) {
|
||||
var filtermenuContent = document.querySelector('.filtermenu-content');
|
||||
if (filtermenuContent.classList.contains('is-open')) {
|
||||
var subMenus = document.querySelectorAll('.filtermenu-submenu');
|
||||
var clickedInsideSubmenu = Array.from(subMenus).some(subMenu => subMenu.contains(e.target) || subMenu === e.target);
|
||||
|
||||
if (!filtermenu.contains(e.target) && !clickedInsideSubmenu) {
|
||||
closeSubMenus();
|
||||
filtermenuContent.classList.remove('is-open');
|
||||
}
|
||||
if (!filtermenu.contains(e.target) && !clickedInsideSubmenu) {
|
||||
closeSubMenus();
|
||||
filtermenuContent.classList.remove('is-open');
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
function toggleSubMenu(subMenu) {
|
||||
var subMenu = document.getElementById("filter-" + subMenu);
|
||||
if (subMenu.classList.contains("is-open")) {
|
||||
closeSubMenus();
|
||||
closeSubMenus();
|
||||
} else {
|
||||
closeSubMenus();
|
||||
subMenu.classList.add("is-open");
|
||||
closeSubMenus();
|
||||
subMenu.classList.add("is-open");
|
||||
}
|
||||
}
|
||||
|
||||
document.querySelectorAll('.filter-item').forEach(function(item) {
|
||||
item.addEventListener('click', function(e) {
|
||||
document.querySelectorAll('.filter-item').forEach(function (item) {
|
||||
item.addEventListener('click', function (e) {
|
||||
const searchInput = document.querySelector("#search");
|
||||
searchInput.value = "";
|
||||
|
||||
if (this.hasAttribute('data-categoryid')) {
|
||||
const categoryId = this.getAttribute('data-categoryid');
|
||||
if (activeFilters['category'] === categoryId) {
|
||||
activeFilters['category'] = "";
|
||||
this.classList.remove('selected');
|
||||
} else {
|
||||
activeFilters['category'] = categoryId;
|
||||
Array.from(this.parentNode.children).forEach(sibling => {
|
||||
sibling.classList.remove('selected');
|
||||
});
|
||||
this.classList.add('selected');
|
||||
}
|
||||
const categoryId = this.getAttribute('data-categoryid');
|
||||
if (activeFilters['category'] === categoryId) {
|
||||
activeFilters['category'] = "";
|
||||
this.classList.remove('selected');
|
||||
} else {
|
||||
activeFilters['category'] = categoryId;
|
||||
Array.from(this.parentNode.children).forEach(sibling => {
|
||||
sibling.classList.remove('selected');
|
||||
});
|
||||
this.classList.add('selected');
|
||||
}
|
||||
} else if (this.hasAttribute('data-memberid')) {
|
||||
const memberId = this.getAttribute('data-memberid');
|
||||
if (activeFilters['member'] === memberId) {
|
||||
activeFilters['member'] = "";
|
||||
this.classList.remove('selected');
|
||||
} else {
|
||||
activeFilters['member'] = memberId;
|
||||
Array.from(this.parentNode.children).forEach(sibling => {
|
||||
sibling.classList.remove('selected');
|
||||
});
|
||||
this.classList.add('selected');
|
||||
}
|
||||
const memberId = this.getAttribute('data-memberid');
|
||||
if (activeFilters['member'] === memberId) {
|
||||
activeFilters['member'] = "";
|
||||
this.classList.remove('selected');
|
||||
} else {
|
||||
activeFilters['member'] = memberId;
|
||||
Array.from(this.parentNode.children).forEach(sibling => {
|
||||
sibling.classList.remove('selected');
|
||||
});
|
||||
this.classList.add('selected');
|
||||
}
|
||||
} else if (this.hasAttribute('data-paymentid')) {
|
||||
const paymentId = this.getAttribute('data-paymentid');
|
||||
if (activeFilters['payment'] === paymentId) {
|
||||
activeFilters['payment'] = "";
|
||||
this.classList.remove('selected');
|
||||
} else {
|
||||
activeFilters['payment'] = paymentId;
|
||||
Array.from(this.parentNode.children).forEach(sibling => {
|
||||
sibling.classList.remove('selected');
|
||||
});
|
||||
this.classList.add('selected');
|
||||
}
|
||||
const paymentId = this.getAttribute('data-paymentid');
|
||||
if (activeFilters['payment'] === paymentId) {
|
||||
activeFilters['payment'] = "";
|
||||
this.classList.remove('selected');
|
||||
} else {
|
||||
activeFilters['payment'] = paymentId;
|
||||
Array.from(this.parentNode.children).forEach(sibling => {
|
||||
sibling.classList.remove('selected');
|
||||
});
|
||||
this.classList.add('selected');
|
||||
}
|
||||
}
|
||||
|
||||
if (activeFilters['category'] !== "" || activeFilters['member'] !== "" || activeFilters['payment'] !== "") {
|
||||
document.querySelector('#clear-filters').classList.remove('hide');
|
||||
document.querySelector('#clear-filters').classList.remove('hide');
|
||||
} else {
|
||||
document.querySelector('#clear-filters').classList.add('hide');
|
||||
document.querySelector('#clear-filters').classList.add('hide');
|
||||
}
|
||||
|
||||
fetchSubscriptions();
|
||||
@@ -501,7 +550,7 @@ function clearFilters() {
|
||||
activeFilters['category'] = "";
|
||||
activeFilters['member'] = "";
|
||||
activeFilters['payment'] = "";
|
||||
document.querySelectorAll('.filter-item').forEach(function(item) {
|
||||
document.querySelectorAll('.filter-item').forEach(function (item) {
|
||||
item.classList.remove('selected');
|
||||
});
|
||||
document.querySelector('#clear-filters').classList.add('hide');
|
||||
@@ -510,7 +559,7 @@ function clearFilters() {
|
||||
|
||||
let currentActions = null;
|
||||
|
||||
document.addEventListener('click', function(event) {
|
||||
document.addEventListener('click', function (event) {
|
||||
// Check if click was outside currentActions
|
||||
if (currentActions && !currentActions.contains(event.target)) {
|
||||
// Click was outside currentActions, close currentActions
|
||||
|
||||
@@ -117,7 +117,7 @@ header .logo .logo-image svg {
|
||||
.dropbtn > img {
|
||||
width: 35px;
|
||||
height: 35px;
|
||||
object-fit: contain;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.dropdown-content {
|
||||
@@ -630,7 +630,7 @@ header #avatar {
|
||||
cursor: pointer;
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
object-fit: contain;
|
||||
object-fit: cover;
|
||||
max-width: 80px;
|
||||
border-radius: 50%;
|
||||
border: 1px solid #ccc;
|
||||
@@ -701,7 +701,7 @@ header #avatar {
|
||||
.avatar-select .avatar-list .avatar-container > img {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
object-fit: contain;
|
||||
object-fit: cover;
|
||||
cursor: pointer;
|
||||
border: 1px solid #ccc;
|
||||
box-sizing: border-box
|
||||
@@ -2249,6 +2249,10 @@ button.dark-theme-button i {
|
||||
}
|
||||
}
|
||||
|
||||
.bold {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
/* Checkbox */
|
||||
input[type="checkbox"] {
|
||||
opacity: 0;
|
||||
|
||||
Reference in New Issue
Block a user