feat: added custom payment methods (#173)
This commit is contained in:
parent
cb5ce49202
commit
e739622606
183
endpoints/payments/add.php
Normal file
183
endpoints/payments/add.php
Normal file
@ -0,0 +1,183 @@
|
||||
<?php
|
||||
error_reporting(E_ERROR | E_PARSE);
|
||||
require_once '../../includes/connect_endpoint.php';
|
||||
require_once '../../includes/inputvalidation.php';
|
||||
require_once '../../includes/getsettings.php';
|
||||
|
||||
session_start();
|
||||
|
||||
function sanitizeFilename($filename) {
|
||||
$filename = preg_replace("/[^a-zA-Z0-9\s]/", "", $filename);
|
||||
$filename = str_replace(" ", "-", $filename);
|
||||
return $filename;
|
||||
}
|
||||
|
||||
function getLogoFromUrl($url, $uploadDir, $name) {
|
||||
|
||||
$ch = curl_init($url);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
||||
|
||||
$imageData = curl_exec($ch);
|
||||
|
||||
if ($imageData !== false) {
|
||||
$timestamp = time();
|
||||
$fileName = $timestamp . '-payments-' . sanitizeFilename($name) . '.png';
|
||||
$uploadDir = '../../images/uploads/logos/';
|
||||
$uploadFile = $uploadDir . $fileName;
|
||||
|
||||
if (saveLogo($imageData, $uploadFile, $name)) {
|
||||
return $fileName;
|
||||
} else {
|
||||
echo translate('error_fetching_image', $i18n) . ": " . curl_error($ch);
|
||||
return "";
|
||||
}
|
||||
|
||||
curl_close($ch);
|
||||
} else {
|
||||
echo translate('error_fetching_image', $i18n) . ": " . curl_error($ch);
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
function saveLogo($imageData, $uploadFile, $name) {
|
||||
$image = imagecreatefromstring($imageData);
|
||||
$removeBackground = isset($settings['removeBackground']) && $settings['removeBackground'] === 'true';
|
||||
if ($image !== false) {
|
||||
$tempFile = tempnam(sys_get_temp_dir(), 'logo');
|
||||
imagepng($image, $tempFile);
|
||||
imagedestroy($image);
|
||||
|
||||
$imagick = new Imagick($tempFile);
|
||||
if ($removeBackground) {
|
||||
$fuzz = Imagick::getQuantum() * 0.1; // 10%
|
||||
$imagick->transparentPaintImage("rgb(247, 247, 247)", 0, $fuzz, false);
|
||||
}
|
||||
$imagick->setImageFormat('png');
|
||||
$imagick->writeImage($uploadFile);
|
||||
|
||||
$imagick->clear();
|
||||
$imagick->destroy();
|
||||
unlink($tempFile);
|
||||
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function resizeAndUploadLogo($uploadedFile, $uploadDir, $name) { $targetWidth = 70;
|
||||
$targetHeight = 48;
|
||||
|
||||
$timestamp = time();
|
||||
$originalFileName = $uploadedFile['name'];
|
||||
$fileExtension = pathinfo($originalFileName, PATHINFO_EXTENSION);
|
||||
$fileName = $timestamp . '-payments-' . sanitizeFilename($name) . '.' . $fileExtension;
|
||||
$uploadFile = $uploadDir . $fileName;
|
||||
|
||||
if (move_uploaded_file($uploadedFile['tmp_name'], $uploadFile)) {
|
||||
$fileInfo = getimagesize($uploadFile);
|
||||
|
||||
if ($fileInfo !== false) {
|
||||
$width = $fileInfo[0];
|
||||
$height = $fileInfo[1];
|
||||
|
||||
// Load the image based on its format
|
||||
if ($fileExtension === 'png') {
|
||||
$image = imagecreatefrompng($uploadFile);
|
||||
} elseif ($fileExtension === 'jpg' || $fileExtension === 'jpeg') {
|
||||
$image = imagecreatefromjpeg($uploadFile);
|
||||
} else {
|
||||
// Handle other image formats as needed
|
||||
return "";
|
||||
}
|
||||
|
||||
// Enable alpha channel (transparency) for PNG images
|
||||
if ($fileExtension === 'png') {
|
||||
imagesavealpha($image, true);
|
||||
}
|
||||
|
||||
$newWidth = $width;
|
||||
$newHeight = $height;
|
||||
|
||||
if ($width > $targetWidth) {
|
||||
$newWidth = $targetWidth;
|
||||
$newHeight = ($targetWidth / $width) * $height;
|
||||
}
|
||||
|
||||
if ($newHeight > $targetHeight) {
|
||||
$newWidth = ($targetHeight / $newHeight) * $newWidth;
|
||||
$newHeight = $targetHeight;
|
||||
}
|
||||
|
||||
$resizedImage = imagecreatetruecolor($newWidth, $newHeight);
|
||||
imagesavealpha($resizedImage, true);
|
||||
$transparency = imagecolorallocatealpha($resizedImage, 0, 0, 0, 127);
|
||||
imagefill($resizedImage, 0, 0, $transparency);
|
||||
imagecopyresampled($resizedImage, $image, 0, 0, 0, 0, $newWidth, $newHeight, $width, $height);
|
||||
|
||||
if ($fileExtension === 'png') {
|
||||
imagepng($resizedImage, $uploadFile);
|
||||
} elseif ($fileExtension === 'jpg' || $fileExtension === 'jpeg') {
|
||||
imagejpeg($resizedImage, $uploadFile);
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
|
||||
imagedestroy($image);
|
||||
imagedestroy($resizedImage);
|
||||
return $fileName;
|
||||
}
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
if (isset($_SESSION['loggedin']) && $_SESSION['loggedin'] === true) {
|
||||
if ($_SERVER["REQUEST_METHOD"] === "POST") {
|
||||
$enabled = 1;
|
||||
$name = validate($_POST["paymentname"]);
|
||||
$iconUrl = validate($_POST['icon-url']);
|
||||
|
||||
if ($name === "" || ($iconUrl === "" && empty($_FILES['paymenticon']['name']))) {
|
||||
$response = [
|
||||
"success" => false,
|
||||
"errorMessage" => translate('fill_all_fields', $i18n)
|
||||
];
|
||||
echo json_encode($response);
|
||||
exit();
|
||||
}
|
||||
|
||||
|
||||
$icon = "";
|
||||
|
||||
if($iconUrl !== "") {
|
||||
$icon = getLogoFromUrl($iconUrl, '../../images/uploads/logos/', $name);
|
||||
} else {
|
||||
if (!empty($_FILES['paymenticon']['name'])) {
|
||||
$icon = resizeAndUploadLogo($_FILES['paymenticon'], '../../images/uploads/logos/', $name);
|
||||
}
|
||||
}
|
||||
|
||||
$sql = "INSERT INTO payment_methods (name, icon, enabled) VALUES (:name, :icon, :enabled)";
|
||||
|
||||
$stmt = $db->prepare($sql);
|
||||
|
||||
$stmt->bindParam(':name', $name, SQLITE3_TEXT);
|
||||
$stmt->bindParam(':icon', $icon, SQLITE3_TEXT);
|
||||
$stmt->bindParam(':enabled', $enabled, SQLITE3_INTEGER);
|
||||
|
||||
if ($stmt->execute()) {
|
||||
$success['success'] = true;
|
||||
$success['message'] = translate('payment_method_added_successfuly', $i18n);
|
||||
$json = json_encode($success);
|
||||
header('Content-Type: application/json');
|
||||
echo $json;
|
||||
exit();
|
||||
} else {
|
||||
echo translate('error', $i18n) . ": " . $db->lastErrorMsg();
|
||||
}
|
||||
}
|
||||
}
|
||||
$db->close();
|
||||
|
||||
?>
|
||||
29
endpoints/payments/delete.php
Normal file
29
endpoints/payments/delete.php
Normal file
@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
require_once '../../includes/connect_endpoint.php';
|
||||
session_start();
|
||||
if (isset($_SESSION['loggedin']) && $_SESSION['loggedin'] === true) {
|
||||
if ($_SERVER["REQUEST_METHOD"] === "DELETE") {
|
||||
$paymentMethodId = $_GET["id"];
|
||||
$deleteQuery = "DELETE FROM payment_methods WHERE id = :paymentMethodId";
|
||||
$deleteStmt = $db->prepare($deleteQuery);
|
||||
$deleteStmt->bindParam(':paymentMethodId', $paymentMethodId, SQLITE3_INTEGER);
|
||||
|
||||
if ($deleteStmt->execute()) {
|
||||
$success['success'] = true;
|
||||
$success['message'] = translate('payment_method_added_successfuly', $i18n);
|
||||
$json = json_encode($success);
|
||||
header('Content-Type: application/json');
|
||||
echo $json;
|
||||
} else {
|
||||
http_response_code(500);
|
||||
echo json_encode(array("message" => translate('error', $i18n)));
|
||||
}
|
||||
} else {
|
||||
http_response_code(405);
|
||||
echo json_encode(array("message" => translate('invalid_request_method', $i18n)));
|
||||
}
|
||||
}
|
||||
$db->close();
|
||||
|
||||
?>
|
||||
59
endpoints/payments/get.php
Normal file
59
endpoints/payments/get.php
Normal file
@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
require_once '../../includes/connect_endpoint.php';
|
||||
session_start();
|
||||
|
||||
if (isset($_SESSION['loggedin']) && $_SESSION['loggedin'] === true) {
|
||||
$paymentsInUseQuery = $db->query('SELECT id FROM payment_methods WHERE id IN (SELECT DISTINCT payment_method_id FROM subscriptions)');
|
||||
$paymentsInUse = [];
|
||||
while ($row = $paymentsInUseQuery->fetchArray(SQLITE3_ASSOC)) {
|
||||
$paymentsInUse[] = $row['id'];
|
||||
}
|
||||
|
||||
$sql = "SELECT * FROM payment_methods";
|
||||
|
||||
$result = $db->query($sql);
|
||||
if ($result) {
|
||||
$payments = array();
|
||||
while ($row = $result->fetchArray(SQLITE3_ASSOC)) {
|
||||
$payments[] = $row;
|
||||
}
|
||||
} else {
|
||||
http_response_code(500);
|
||||
echo json_encode(array("message" => translate('error', $i18n)));
|
||||
exit();
|
||||
}
|
||||
|
||||
foreach ($payments as $payment) {
|
||||
$paymentIconFolder = $payment['id'] <= 31 ? 'images/uploads/icons/' : 'images/uploads/logos/';
|
||||
$inUse = in_array($payment['id'], $paymentsInUse);
|
||||
?>
|
||||
<div class="payments-payment"
|
||||
data-enabled="<?= $payment['enabled']; ?>"
|
||||
data-in-use="<?= $inUse ? 'yes' : 'no' ?>"
|
||||
data-paymentid="<?= $payment['id'] ?>"
|
||||
title="<?= $inUse ? translate('cant_delete_payment_method_in_use', $i18n) : ($payment['enabled'] ? translate('disable', $i18n) : translate('enable', $i18n)) ?>"
|
||||
onClick="togglePayment(<?= $payment['id'] ?>)">
|
||||
<img src="<?= $paymentIconFolder.$payment['icon'] ?>" alt="Logo" />
|
||||
<span class="payment-name">
|
||||
<?= $payment['name'] ?>
|
||||
</span>
|
||||
<?php
|
||||
if ($payment['id'] > 31 && !$inUse) {
|
||||
?>
|
||||
<div class="delete-payment-method" title="<?= translate('delete', $i18n) ?>" data-paymentid="<?= $payment['id'] ?>" onclick="deletePaymentMethod(<?= $payment['id'] ?>)">
|
||||
x
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
} else {
|
||||
http_response_code(401);
|
||||
echo json_encode(array("message" => translate('error', $i18n)));
|
||||
exit();
|
||||
}
|
||||
|
||||
?>
|
||||
81
endpoints/payments/search.php
Normal file
81
endpoints/payments/search.php
Normal file
@ -0,0 +1,81 @@
|
||||
<?php
|
||||
if (isset($_GET['search'])) {
|
||||
$searchTerm = urlencode($_GET['search'] . " logo");
|
||||
|
||||
$url = "https://www.google.com/search?q={$searchTerm}&tbm=isch";
|
||||
$backupUrl = "https://search.brave.com/search?q={$searchTerm}";
|
||||
|
||||
$ch = curl_init();
|
||||
curl_setopt($ch, CURLOPT_URL, $url);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
|
||||
// Convert all environment variable keys to lowercase
|
||||
$envVars = array_change_key_case($_SERVER, CASE_LOWER);
|
||||
|
||||
// Check for http_proxy or https_proxy environment variables
|
||||
$httpProxy = isset($envVars['http_proxy']) ? $envVars['http_proxy'] : null;
|
||||
$httpsProxy = isset($envVars['https_proxy']) ? $envVars['https_proxy'] : null;
|
||||
|
||||
if (!empty($httpProxy)) {
|
||||
curl_setopt($ch, CURLOPT_PROXY, $httpProxy);
|
||||
} elseif (!empty($httpsProxy)) {
|
||||
curl_setopt($ch, CURLOPT_PROXY, $httpsProxy);
|
||||
}
|
||||
|
||||
$response = curl_exec($ch);
|
||||
|
||||
if ($response === false) {
|
||||
// If cURL fails to access google images, use brave image search as a backup
|
||||
$ch = curl_init();
|
||||
curl_setopt($ch, CURLOPT_URL, $backupUrl);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
$envVars = array_change_key_case($_SERVER, CASE_LOWER);
|
||||
$httpProxy = isset($envVars['http_proxy']) ? $envVars['http_proxy'] : null;
|
||||
$httpsProxy = isset($envVars['https_proxy']) ? $envVars['https_proxy'] : null;
|
||||
if (!empty($httpProxy)) {
|
||||
curl_setopt($ch, CURLOPT_PROXY, $httpProxy);
|
||||
} elseif (!empty($httpsProxy)) {
|
||||
curl_setopt($ch, CURLOPT_PROXY, $httpsProxy);
|
||||
}
|
||||
$response = curl_exec($ch);
|
||||
if ($response === false) {
|
||||
echo json_encode(['error' => 'Failed to fetch data from Google.']);
|
||||
} else {
|
||||
$imageUrls = extractImageUrlsFromPage($response);
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode(['imageUrls' => $imageUrls]);
|
||||
}
|
||||
} else {
|
||||
// Parse the HTML response to extract image URLs
|
||||
$imageUrls = extractImageUrlsFromPage($response);
|
||||
|
||||
// Pass the image URLs to the client
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode(['imageUrls' => $imageUrls]);
|
||||
}
|
||||
|
||||
curl_close($ch);
|
||||
} else {
|
||||
echo json_encode(['error' => 'Invalid request.']);
|
||||
}
|
||||
|
||||
function extractImageUrlsFromPage($html) {
|
||||
$imageUrls = [];
|
||||
|
||||
$doc = new DOMDocument();
|
||||
@$doc->loadHTML($html);
|
||||
|
||||
$imgTags = $doc->getElementsByTagName('img');
|
||||
foreach ($imgTags as $imgTag) {
|
||||
$src = $imgTag->getAttribute('src');
|
||||
if (!strstr($imgTag->getAttribute('class'), "favicon") && !strstr($imgTag->getAttribute('class'), "logo")) {
|
||||
if (filter_var($src, FILTER_VALIDATE_URL)) {
|
||||
$imageUrls[] = $src;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $imageUrls;
|
||||
}
|
||||
|
||||
?>
|
||||
@ -50,7 +50,8 @@
|
||||
$print[$id]['currency_code'] = $currencies[$subscription['currency_id']]['code'];
|
||||
$currencyId = $subscription['currency_id'];
|
||||
$print[$id]['next_payment'] = date('M d, Y', strtotime($subscription['next_payment']));
|
||||
$print[$id]['payment_method_icon'] = "images/uploads/icons/" . $payment_methods[$paymentMethodId]['icon'];
|
||||
$paymentIconFolder = $paymentMethodId <= 31 ? 'images/uploads/icons/' : 'images/uploads/logos/';
|
||||
$print[$id]['payment_method_icon'] = $paymentIconFolder . $payment_methods[$paymentMethodId]['icon'];
|
||||
$print[$id]['payment_method_name'] = $payment_methods[$paymentMethodId]['name'];
|
||||
$print[$id]['payment_method_id'] = $paymentMethodId;
|
||||
$print[$id]['category_id'] = $subscription['category_id'];
|
||||
|
||||
@ -137,6 +137,9 @@ $i18n = [
|
||||
"payment_methods" => "Zahlungsmethoden",
|
||||
"payment_methods_info" => "Zahlungsmethode zum (de-)aktivieren anklicken.",
|
||||
"cant_delete_payment_method_in_use" => "Genutzte Zahlungsmethoden können nicht deaktiviert werden",
|
||||
"add_custom_payment" => "Eigene Zahlungsmethode hinzufügen",
|
||||
"payment_method_name" => "Name der Zahlungsmethode",
|
||||
"payment_method_added_successfuly" => "Zahlungsmethode erfolgreich hinzugefügt",
|
||||
"disable" => "Deaktivieren",
|
||||
"enable" => "Aktivieren",
|
||||
"test" => "Test",
|
||||
|
||||
@ -137,6 +137,9 @@ $i18n = [
|
||||
"payment_methods" => "Τρόποι πληρωμής",
|
||||
"payment_methods_info" => "Κάνε κλικ σε μια μέθοδο πληρωμής για να την απενεργοποιήσεις/ενεργοποιήσεις.",
|
||||
"cant_delete_payment_method_in_use" => "Δεν είναι εφικτό να απενεργοποιηθεί η χρησιμοποιούμενη μέθοδο πληρωμής",
|
||||
"add_custom_payment" => "Προσθήκη προσαρμοσμένης μεθόδου πληρωμής",
|
||||
"payment_method_name" => "Όνομα μεθόδου πληρωμής",
|
||||
"payment_method_added_successfuly" => "Η μέθοδος πληρωμής προστέθηκε με επιτυχία",
|
||||
"disable" => "Ανενεργό",
|
||||
"enable" => "Ενεργό",
|
||||
"test" => "Δοκιμή",
|
||||
|
||||
@ -137,6 +137,9 @@ $i18n = [
|
||||
"payment_methods" => "Payment Methods",
|
||||
"payment_methods_info" => "Click a payment method to disable / enable it.",
|
||||
"cant_delete_payment_method_in_use" => "Can't disable used payment method",
|
||||
"add_custom_payment" => "Add Custom Payment Method",
|
||||
"payment_method_name" => "Payment Method Name",
|
||||
"payment_method_added_successfuly" => "Payment method added successfully",
|
||||
"disable" => "Disable",
|
||||
"enable" => "Enable",
|
||||
"test" => "Test",
|
||||
|
||||
@ -137,6 +137,9 @@ $i18n = [
|
||||
"payment_methods" => "Métodos de Pago",
|
||||
"payment_methods_info" => "Haz clic en un método de pago para deshabilitarlo/habilitarlo.",
|
||||
"cant_delete_payment_method_in_use" => "No se puede desactivar el método de pago utilizado",
|
||||
"add_custom_payment" => "Añadir método de pago personalizado",
|
||||
"payment_method_name" => "Nombre del método de pago",
|
||||
"payment_method_added_successfuly" => "Método de pago añadido con éxito",
|
||||
"disable" => "Desactivar",
|
||||
"enable" => "Activar",
|
||||
"test" => "Probar",
|
||||
|
||||
@ -137,6 +137,9 @@ $i18n = [
|
||||
"payment_methods" => "Méthodes de paiement",
|
||||
"payment_methods_info" => "Cliquez sur une méthode de paiement pour la désactiver / l'activer.",
|
||||
"cant_delete_payment_method_in_use" => "Impossible de désactiver la méthode de paiement utilisée",
|
||||
"add_custom_payment" => "Ajouter un paiement personnalisé",
|
||||
"payment_method_name" => "Nom de la méthode de paiement",
|
||||
"payment_method_added_successfuly" => "Méthode de paiement ajoutée avec succès",
|
||||
"disable" => "Désactiver",
|
||||
"enable" => "Activer",
|
||||
"test" => "Test",
|
||||
|
||||
@ -137,6 +137,9 @@ $i18n = [
|
||||
"payment_methods" => "支払い方法",
|
||||
"payment_methods_info" => "支払い方法をクリックして無効/有効を切り替えます。",
|
||||
"cant_delete_payment_method_in_use" => "支払い方法が使用中のため無効にできません。",
|
||||
"add_custom_payment" => "カスタム支払い方法を追加",
|
||||
"payment_method_name" => "支払い方法名",
|
||||
"payment_method_added_successfuly" => "支払い方法が追加されました",
|
||||
"disable" => "無効",
|
||||
"enable" => "有効",
|
||||
"test" => "テスト",
|
||||
|
||||
@ -137,6 +137,9 @@ $i18n = [
|
||||
"payment_methods" => "Métodos de Pagamento",
|
||||
"payment_methods_info" => "Clique num método de pagamento para o activar / desactivar.",
|
||||
"cant_delete_payment_method_in_use" => "Não pode desactivar metodo de pagamento em uso",
|
||||
"add_custom_payment" => "Adicionar método de pagamento personalizado",
|
||||
"payment_method_name" => "Nome do método de pagamento",
|
||||
"payment_method_added_successfuly" => "Método de pagamento adicionado com sucesso",
|
||||
"disable" => "Desactivar",
|
||||
"enable" => "Activar",
|
||||
"test" => "Testar",
|
||||
|
||||
@ -137,6 +137,9 @@ $i18n = [
|
||||
"payment_methods" => "Ödeme Yöntemleri",
|
||||
"payment_methods_info" => "Bir ödeme yöntemini devre dışı bırakmak / etkinleştirmek için tıklayın.",
|
||||
"cant_delete_payment_method_in_use" => "Kullanımda olan ödeme yöntemini devre dışı bırakamazsınız",
|
||||
"add_custom_payment" => "Özel ödeme yöntemi ekle",
|
||||
"payment_method_name" => "Ödeme Yöntemi Adı",
|
||||
"payment_method_added_successfuly" => "Ödeme yöntemi başarıyla eklendi",
|
||||
"disable" => "Devre Dışı Bırak",
|
||||
"enable" => "Etkinleştir",
|
||||
"test" => "Test Et",
|
||||
|
||||
@ -144,6 +144,9 @@ $i18n = [
|
||||
"payment_methods" => "支付方式",
|
||||
"payment_methods_info" => "点击支付方式以禁用/启用。",
|
||||
"cant_delete_payment_method_in_use" => "不能禁用正在使用的支付方式",
|
||||
"add_custom_payment" => "添加自定义支付方式",
|
||||
"payment_method_name" => "支付方式名称",
|
||||
"payment_method_added_successfuly" => "支付方式已成功添加",
|
||||
"disable" => "禁用",
|
||||
"enable" => "启用",
|
||||
"test" => "测试",
|
||||
|
||||
@ -137,6 +137,9 @@ $i18n = [
|
||||
"payment_methods" => "付款方式",
|
||||
"payment_methods_info" => "點選付款方式以停用/啟用。",
|
||||
"cant_delete_payment_method_in_use" => "無法停用正在使用的付款方式",
|
||||
"add_custom_payment" => "新增自訂付款方式",
|
||||
"payment_method_name" => "付款方式名稱",
|
||||
"payment_method_added_successfuly" => "付款方式已成功新增",
|
||||
"disable" => "停用",
|
||||
"enable" => "啟用",
|
||||
"test" => "測試",
|
||||
|
||||
@ -1,3 +1,3 @@
|
||||
<?php
|
||||
$version = "v1.10.0";
|
||||
$version = "v1.11.0";
|
||||
?>
|
||||
@ -81,7 +81,8 @@
|
||||
$print[$id]['currency_code'] = $currencies[$subscription['currency_id']]['code'];
|
||||
$currencyId = $subscription['currency_id'];
|
||||
$print[$id]['next_payment'] = date('M d, Y', strtotime($subscription['next_payment']));
|
||||
$print[$id]['payment_method_icon'] = "images/uploads/icons/" . $payment_methods[$paymentMethodId]['icon'];
|
||||
$paymentIconFolder = $paymentMethodId <= 31 ? 'images/uploads/icons/' : 'images/uploads/logos/';
|
||||
$print[$id]['payment_method_icon'] = $paymentIconFolder . $payment_methods[$paymentMethodId]['icon'];
|
||||
$print[$id]['payment_method_name'] = $payment_methods[$paymentMethodId]['name'];
|
||||
$print[$id]['payment_method_id'] = $paymentMethodId;
|
||||
$print[$id]['category_id'] = $subscription['category_id'];
|
||||
|
||||
@ -449,6 +449,171 @@ function togglePayment(paymentId) {
|
||||
});
|
||||
}
|
||||
|
||||
function handleFileSelect(event) {
|
||||
const fileInput = event.target;
|
||||
const iconPreview = document.querySelector('.icon-preview');
|
||||
const iconImg = iconPreview.querySelector('img');
|
||||
const iconUrl = document.querySelector("#icon-url");
|
||||
iconUrl.value = "";
|
||||
|
||||
if (fileInput.files && fileInput.files[0]) {
|
||||
const reader = new FileReader();
|
||||
|
||||
reader.onload = function (e) {
|
||||
iconImg.src = e.target.result;
|
||||
iconImg.style.display = 'block';
|
||||
};
|
||||
|
||||
reader.readAsDataURL(fileInput.files[0]);
|
||||
}
|
||||
}
|
||||
|
||||
function setSearchButtonStatus() {
|
||||
|
||||
const nameInput = document.querySelector("#paymentname");
|
||||
const hasSearchTerm = nameInput.value.trim().length > 0;
|
||||
const iconSearchButton = document.querySelector("#icon-search-button");
|
||||
if (hasSearchTerm) {
|
||||
iconSearchButton.classList.remove("disabled");
|
||||
} else {
|
||||
iconSearchButton.classList.add("disabled");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function searchPaymentIcon() {
|
||||
const nameInput = document.querySelector("#paymentname");
|
||||
const searchTerm = nameInput.value.trim();
|
||||
if (searchTerm !== "") {
|
||||
const iconSearchPopup = document.querySelector("#icon-search-results");
|
||||
iconSearchPopup.classList.add("is-open");
|
||||
const imageSearchUrl = `endpoints/payments/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);
|
||||
});
|
||||
} else {
|
||||
nameInput.focus();
|
||||
}
|
||||
}
|
||||
|
||||
function displayImageResults(imageSources) {
|
||||
const iconResults = document.querySelector("#icon-search-images");
|
||||
iconResults.innerHTML = "";
|
||||
|
||||
imageSources.forEach(src => {
|
||||
const img = document.createElement("img");
|
||||
img.src = src;
|
||||
img.onclick = function() {
|
||||
selectWebIcon(src);
|
||||
};
|
||||
img.onerror = function() {
|
||||
this.parentNode.removeChild(this);
|
||||
};
|
||||
iconResults.appendChild(img);
|
||||
});
|
||||
}
|
||||
|
||||
function selectWebIcon(url) {
|
||||
closeIconSearch();
|
||||
const iconPreview = document.querySelector("#form-icon");
|
||||
const iconUrl = document.querySelector("#icon-url");
|
||||
iconPreview.src = url;
|
||||
iconPreview.style.display = 'block';
|
||||
iconUrl.value = url;
|
||||
}
|
||||
|
||||
function closeIconSearch() {
|
||||
const iconSearchPopup = document.querySelector("#icon-search-results");
|
||||
iconSearchPopup.classList.remove("is-open");
|
||||
const iconResults = document.querySelector("#icon-search-images");
|
||||
iconResults.innerHTML = "";
|
||||
}
|
||||
|
||||
function resetFormIcon() {
|
||||
const iconPreview = document.querySelector("#form-icon");
|
||||
iconPreview.src = "";
|
||||
iconPreview.style.display = 'none';
|
||||
}
|
||||
|
||||
function reloadPaymentMethods() {
|
||||
const paymentsContainer = document.querySelector("#payments-list");
|
||||
const paymentMethodsEndpoint = "endpoints/payments/get.php";
|
||||
|
||||
fetch(paymentMethodsEndpoint)
|
||||
.then(response => response.text())
|
||||
.then(data => {
|
||||
paymentsContainer.innerHTML = data;
|
||||
});
|
||||
}
|
||||
|
||||
function addPaymentMethod() {
|
||||
closeIconSearch();
|
||||
const addPaymentMethodEndpoint = "endpoints/payments/add.php";
|
||||
const paymentMethodForm = document.querySelector("#payments-form");
|
||||
const submitButton = document.querySelector("#add-payment-button");
|
||||
|
||||
submitButton.disabled = true;
|
||||
const formData = new FormData(paymentMethodForm);
|
||||
|
||||
fetch(addPaymentMethodEndpoint, {
|
||||
method: "POST",
|
||||
body: formData
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
showSuccessMessage(data.message);
|
||||
paymentMethodForm.reset();
|
||||
resetFormIcon();
|
||||
reloadPaymentMethods();
|
||||
} else {
|
||||
showErrorMessage(data.errorMessage);
|
||||
}
|
||||
submitButton.disabled = false;
|
||||
})
|
||||
.catch(error => {
|
||||
showErrorMessage(translate('unknown_error'));
|
||||
submitButton.disabled = false;
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
function deletePaymentMethod(paymentId) {
|
||||
fetch(`endpoints/payments/delete.php?id=${paymentId}`, {
|
||||
method: 'DELETE',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({ id: paymentId }),
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
showSuccessMessage(data.message);
|
||||
var paymentToRemove = document.querySelector('.payments-payment[data-paymentid="' + paymentId + '"]');
|
||||
if (paymentToRemove) {
|
||||
paymentToRemove.remove();
|
||||
}
|
||||
} else {
|
||||
showErrorMessage(data.errorMessage);
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('Error:', error);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
|
||||
document.getElementById("userForm").addEventListener("submit", function(event) {
|
||||
@ -478,7 +643,17 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
.catch(error => {
|
||||
showErrorMessage(translate('unknown_error'));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
var removePaymentButtons = document.querySelectorAll(".delete-payment-method");
|
||||
removePaymentButtons.forEach(function(button) {
|
||||
button.addEventListener('click', function(event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
let paymentId = event.target.getAttribute('data-paymentid');
|
||||
deletePaymentMethod(paymentId);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
47
settings.php
47
settings.php
@ -2,6 +2,11 @@
|
||||
require_once 'includes/header.php';
|
||||
?>
|
||||
|
||||
<style>
|
||||
.logo-preview:after {
|
||||
content: '<?= translate('upload_logo', $i18n) ?>';
|
||||
}
|
||||
</style>
|
||||
<section class="contain settings">
|
||||
<section class="account-section">
|
||||
<header>
|
||||
@ -476,7 +481,7 @@
|
||||
<header>
|
||||
<h2><?= translate('payment_methods', $i18n) ?></h2>
|
||||
</header>
|
||||
<div class="payments-list">
|
||||
<div class="payments-list" id="payments-list">
|
||||
<?php
|
||||
$paymentsInUseQuery = $db->query('SELECT id FROM payment_methods WHERE id IN (SELECT DISTINCT payment_method_id FROM subscriptions)');
|
||||
$paymentsInUse = [];
|
||||
@ -485,6 +490,7 @@
|
||||
}
|
||||
|
||||
foreach ($payments as $payment) {
|
||||
$paymentIconFolder = $payment['id'] <= 31 ? 'images/uploads/icons/' : 'images/uploads/logos/';
|
||||
$inUse = in_array($payment['id'], $paymentsInUse);
|
||||
?>
|
||||
<div class="payments-payment"
|
||||
@ -493,10 +499,19 @@
|
||||
data-paymentid="<?= $payment['id'] ?>"
|
||||
title="<?= $inUse ? translate('cant_delete_payment_method_in_use', $i18n) : ($payment['enabled'] ? translate('disable', $i18n) : translate('enable', $i18n)) ?>"
|
||||
onClick="togglePayment(<?= $payment['id'] ?>)">
|
||||
<img src="images/uploads/icons/<?= $payment['icon'] ?>" alt="Logo" />
|
||||
<img src="<?= $paymentIconFolder.$payment['icon'] ?>" alt="Logo" />
|
||||
<span class="payment-name">
|
||||
<?= $payment['name'] ?>
|
||||
</span>
|
||||
<?php
|
||||
if ($payment['id'] > 31 && !$inUse) {
|
||||
?>
|
||||
<div class="delete-payment-method" title="<?= translate('delete', $i18n) ?>" data-paymentid="<?= $payment['id'] ?>">
|
||||
x
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
@ -508,6 +523,34 @@
|
||||
<?= translate('payment_methods_info', $i18n) ?>
|
||||
</p>
|
||||
</div>
|
||||
<header>
|
||||
<h2 class="second-header"><?= translate("add_custom_payment", $i18n) ?></h2>
|
||||
</header>
|
||||
<div>
|
||||
<form id="payments-form">
|
||||
<div class="form-group-inline">
|
||||
<input type="text" name="paymentname" id="paymentname" placeholder="<?= translate('payment_method_name', $i18n) ?>" onchange="setSearchButtonStatus()" onkeypress="this.onchange();" onpaste="this.onchange();" oninput="this.onchange();"/>
|
||||
<label for="paymenticon" class="icon-preview">
|
||||
<img src="" alt="<?= translate('logo_preview', $i18n) ?>" id="form-icon">
|
||||
</label>
|
||||
<div class="form-icon-search">
|
||||
<input type="file" id="paymenticon" name="paymenticon" accept="image/jpeg, image/png" onchange="handleFileSelect(event)" class="hidden-input">
|
||||
<input type="hidden" id="icon-url" name="icon-url">
|
||||
<div id="icon-search-button" class="image-button medium disabled" title="<?= translate('search_logo', $i18n) ?>" onClick="searchPaymentIcon()">
|
||||
<img src="images/siteicons/websearch.png">
|
||||
</div>
|
||||
<div id="icon-search-results" class="icon-search">
|
||||
<header>
|
||||
<span class="fa-solid fa-xmark close-icon-search" onClick="closeIconSearch()"></span>
|
||||
</header>
|
||||
<div id="icon-search-images"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<input type="button" class="button thin" id="add-payment-button" value="+" title="<?= translate('add', $i18n) ?>" id="addPayment" onClick="addPaymentMethod()"/>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="account-section">
|
||||
|
||||
@ -107,4 +107,8 @@ input[type="button"].secondary-button:hover {
|
||||
|
||||
.payment-name {
|
||||
color: #FFF;
|
||||
}
|
||||
}
|
||||
|
||||
.payments-list .payments-payment .delete-payment-method {
|
||||
color: #FFF;
|
||||
}
|
||||
@ -168,7 +168,7 @@ main > .contain {
|
||||
color: #fff;
|
||||
border: 1px solid #007bff;
|
||||
background-color: #007bff;
|
||||
padding: 12px 30px;
|
||||
padding: 14px 30px;
|
||||
font-size: 1rem;
|
||||
border-radius: 8px;
|
||||
transition: color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;
|
||||
@ -180,6 +180,10 @@ main > .contain {
|
||||
border-color: #0056b3;
|
||||
}
|
||||
|
||||
.button.thin {
|
||||
padding: 14px 20px;
|
||||
}
|
||||
|
||||
.subscriptions {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@ -385,6 +389,10 @@ main > .contain {
|
||||
margin-bottom: 34px;
|
||||
}
|
||||
|
||||
.account-section header h2.second-header {
|
||||
margin-top:34px;
|
||||
}
|
||||
|
||||
.account-section + .account-section {
|
||||
margin-top: 34px;
|
||||
}
|
||||
@ -585,6 +593,12 @@ main > .contain {
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.payments-list .payments-payment .delete-payment-method {
|
||||
padding: 5px;
|
||||
font-weight: bold;
|
||||
color: #202020;
|
||||
}
|
||||
|
||||
.credits-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@ -780,7 +794,12 @@ input[type="checkbox"] {
|
||||
}
|
||||
}
|
||||
|
||||
.logo-search {
|
||||
.form-icon-search {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.logo-search,
|
||||
.icon-search {
|
||||
position: absolute;
|
||||
width: 165px;
|
||||
height: 298px;
|
||||
@ -797,11 +816,20 @@ input[type="checkbox"] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.logo-search.is-open {
|
||||
.icon-search {
|
||||
width: 100px;
|
||||
height: 224px;
|
||||
top: 50px;
|
||||
right: 0px;
|
||||
}
|
||||
|
||||
.logo-search.is-open,
|
||||
.icon-search.is-open {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.logo-search > header {
|
||||
.logo-search > header,
|
||||
.icon-search > header {
|
||||
padding: 0px 5px 5px;
|
||||
border-bottom: 1px solid #CCC;
|
||||
display: flex;
|
||||
@ -810,18 +838,31 @@ input[type="checkbox"] {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.logo-search .close-logo-search {
|
||||
.icon-search > header > span {
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.logo-search .close-logo-search,
|
||||
.icon-search .close-icon-search {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.logo-search img {
|
||||
.logo-search img,
|
||||
.icon-search img {
|
||||
max-width: 100%;
|
||||
cursor: pointer;
|
||||
border-bottom: 1px solid #ccc;
|
||||
padding: 10px 0px;
|
||||
}
|
||||
|
||||
.logo-search img:last-of-type {
|
||||
.icon-search img {
|
||||
padding: 8px 0px;
|
||||
aspect-ratio: 16 / 5;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.logo-search img:last-of-type,
|
||||
.icon-search img:last-of-type {
|
||||
border-bottom: none;
|
||||
padding-bottom: 0px;
|
||||
}
|
||||
@ -914,6 +955,7 @@ input[type="checkbox"] {
|
||||
height: 100%;
|
||||
color: #0056b3;
|
||||
font-size: 16px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.logo-preview img {
|
||||
@ -923,6 +965,34 @@ input[type="checkbox"] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.icon-preview {
|
||||
padding: 2px 0px;
|
||||
height: 49px;
|
||||
box-sizing: border-box;
|
||||
aspect-ratio: 3/2;
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.icon-preview:after {
|
||||
content: "Upload Icon";
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
color: #0056b3;
|
||||
font-size: 16px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.icon-preview img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: contain;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.hidden-input {
|
||||
display: none;
|
||||
}
|
||||
@ -951,7 +1021,7 @@ input[type="checkbox"] {
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
|
||||
box-sizing: border-box;
|
||||
top: 48px;
|
||||
top: 52px;
|
||||
right: 0px;
|
||||
display: none;
|
||||
width: 144px;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user