feat: allow sorting of categories in settings
feat: add filters to statistics page feat: allow renaming / translation of payment methods feat: allow deletion of the default payment methods
This commit is contained in:
parent
d7e050b868
commit
83234ab8cd
34
endpoints/categories/sort.php
Normal file
34
endpoints/categories/sort.php
Normal file
@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
require_once '../../includes/connect_endpoint.php';
|
||||
|
||||
session_start();
|
||||
|
||||
if (isset($_SESSION['loggedin']) && $_SESSION['loggedin'] === true) {
|
||||
$categories = $_POST['categoryIds'];
|
||||
$order = 2;
|
||||
|
||||
foreach ($categories as $categoryId) {
|
||||
$sql = "UPDATE categories SET `order` = :order WHERE id = :categoryId";
|
||||
$stmt = $db->prepare($sql);
|
||||
$stmt->bindParam(':order', $order, SQLITE3_INTEGER);
|
||||
$stmt->bindParam(':categoryId', $categoryId, SQLITE3_INTEGER);
|
||||
$result = $stmt->execute();
|
||||
$order++;
|
||||
}
|
||||
|
||||
$response = [
|
||||
"success" => true,
|
||||
"message" => translate("sort_order_saved", $i18n)
|
||||
];
|
||||
echo json_encode($response);
|
||||
} else {
|
||||
$response = [
|
||||
"success" => false,
|
||||
"errorMessage" => translate("session_expired", $i18n)
|
||||
];
|
||||
echo json_encode($response);
|
||||
die();
|
||||
}
|
||||
|
||||
?>
|
||||
@ -39,7 +39,7 @@ if (isset($_SESSION['loggedin']) && $_SESSION['loggedin'] === true) {
|
||||
<?= $payment['name'] ?>
|
||||
</span>
|
||||
<?php
|
||||
if ($payment['id'] > 31 && !$inUse) {
|
||||
if (!$inUse) {
|
||||
?>
|
||||
<div class="delete-payment-method" title="<?= translate('delete', $i18n) ?>" data-paymentid="<?= $payment['id'] ?>" onclick="deletePaymentMethod(<?= $payment['id'] ?>)">
|
||||
x
|
||||
|
||||
41
endpoints/payments/rename.php
Normal file
41
endpoints/payments/rename.php
Normal file
@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
require_once '../../includes/connect_endpoint.php';
|
||||
session_start();
|
||||
|
||||
if (!isset($_SESSION['loggedin']) || $_SESSION['loggedin'] !== true) {
|
||||
die(json_encode([
|
||||
"success" => false,
|
||||
"message" => translate('session_expired', $i18n)
|
||||
]));
|
||||
}
|
||||
|
||||
if (!isset($_POST['paymentId']) || !isset($_POST['name']) || $_POST['paymentId'] === '' || $_POST['name'] === '') {
|
||||
die(json_encode([
|
||||
"success" => false,
|
||||
"message" => translate('fields_missing', $i18n)
|
||||
]));
|
||||
}
|
||||
|
||||
$paymentId = $_POST['paymentId'];
|
||||
$name = $_POST['name'];
|
||||
|
||||
$sql = "UPDATE payment_methods SET name = :name WHERE id = :paymentId";
|
||||
$stmt = $db->prepare($sql);
|
||||
$stmt->bindParam(':name', $name, SQLITE3_TEXT);
|
||||
$stmt->bindParam(':paymentId', $paymentId, SQLITE3_INTEGER);
|
||||
$result = $stmt->execute();
|
||||
|
||||
if ($result) {
|
||||
echo json_encode([
|
||||
"success" => true,
|
||||
"message" => translate('payment_renamed', $i18n)
|
||||
]);
|
||||
} else {
|
||||
echo json_encode([
|
||||
"success" => false,
|
||||
"message" => translate('payment_not_renamed', $i18n)
|
||||
]);
|
||||
}
|
||||
|
||||
?>
|
||||
BIN
images/siteicons/draggable.png
Normal file
BIN
images/siteicons/draggable.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 987 B |
@ -26,7 +26,7 @@
|
||||
}
|
||||
|
||||
$categories = array();
|
||||
$query = "SELECT * FROM categories";
|
||||
$query = "SELECT * FROM categories ORDER BY `order` ASC";
|
||||
$result = $db->query($query);
|
||||
while ($row = $result->fetchArray(SQLITE3_ASSOC)) {
|
||||
$categoryId = $row['id'];
|
||||
|
||||
@ -136,17 +136,24 @@ $i18n = [
|
||||
"experimental_info" => "Experimentelle Einstellungen funktionieren möglicherweise nicht perfekt.",
|
||||
"payment_methods" => "Zahlungsmethoden",
|
||||
"payment_methods_info" => "Zahlungsmethode zum (de-)aktivieren anklicken.",
|
||||
"rename_payment_methods_info" => "Klicken Sie auf den Namen einer Zahlungsmethode, um sie umzubenennen",
|
||||
"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",
|
||||
"rename_payment_method" => "Zahlungsmethode umbenennen",
|
||||
"payment_renamed" => "Zahlungsmethode umbenannt",
|
||||
"payment_not_renamed" => "Zahlungsmethode konnte nicht umbenannt werden",
|
||||
"test" => "Test",
|
||||
"add" => "Hinzufügen",
|
||||
"save" => "Speichern",
|
||||
"export_subscriptions" => "Abonnements exportieren",
|
||||
"export_to_json" => "Nach JSON exportieren",
|
||||
// Filters menu
|
||||
"filter" => "Filter",
|
||||
"clear" => "Leeren",
|
||||
// Toast
|
||||
"success" => "Erfolgreich",
|
||||
// Endpoint responses
|
||||
@ -162,6 +169,7 @@ $i18n = [
|
||||
"failed_remove_category" => "Kategorie konnte nicht gelöscht werden",
|
||||
"category_saved" => "Kategorie gespeichert",
|
||||
"category_removed" => "Kategorie gelöscht",
|
||||
"sort_order_saved" => "Sortierung gespeichert",
|
||||
// Currency
|
||||
"currency_saved" => "wurde gespeichert.",
|
||||
"error_adding_currency" => "Fehler beim hinzufügen der Währung.",
|
||||
|
||||
@ -136,17 +136,24 @@ $i18n = [
|
||||
"experimental_info" => "Οι πειραματικές ρυθμίσεις πιθανότατα δεν θα λειτουργούν τέλεια.",
|
||||
"payment_methods" => "Τρόποι πληρωμής",
|
||||
"payment_methods_info" => "Κάνε κλικ σε μια μέθοδο πληρωμής για να την απενεργοποιήσεις/ενεργοποιήσεις.",
|
||||
"rename_payment_methods_info" => "Κάντε κλικ στο όνομα μιας μεθόδου πληρωμής για να τη μετονομάσετε.",
|
||||
"cant_delete_payment_method_in_use" => "Δεν είναι εφικτό να απενεργοποιηθεί η χρησιμοποιούμενη μέθοδο πληρωμής",
|
||||
"add_custom_payment" => "Προσθήκη προσαρμοσμένης μεθόδου πληρωμής",
|
||||
"payment_method_name" => "Όνομα μεθόδου πληρωμής",
|
||||
"payment_method_added_successfuly" => "Η μέθοδος πληρωμής προστέθηκε με επιτυχία",
|
||||
"disable" => "Ανενεργό",
|
||||
"enable" => "Ενεργό",
|
||||
"rename_payment_method" => "Μετονομασία μεθόδου πληρωμής",
|
||||
"payment_renamed" => "Η μέθοδος πληρωμής μετονομάστηκε",
|
||||
"payment_not_renamed" => "Η μέθοδος πληρωμής δεν μετονομάστηκε",
|
||||
"test" => "Δοκιμή",
|
||||
"add" => "Προσθήκη",
|
||||
"save" => "Αποθήκευση",
|
||||
"export_subscriptions" => "Εξαγωγή συνδρομών",
|
||||
"export_to_json" => "Εξαγωγή σε JSON",
|
||||
// Filters menu
|
||||
"filter" => "Φίλτρο",
|
||||
"clear" => "Καθαρισμός",
|
||||
// Toast
|
||||
"success" => "Επιτυχία",
|
||||
// Endpoint responses
|
||||
@ -162,6 +169,7 @@ $i18n = [
|
||||
"failed_remove_category" => "Απέτυχε η διαγραφή κατηγορίας",
|
||||
"category_saved" => "Αποθήκευση κατηγορίας",
|
||||
"category_removed" => "Διαγραφή κατηγορίας",
|
||||
"sort_order_saved" => "Η ταξινόμηση αποθηκεύτηκε",
|
||||
// Currency
|
||||
"currency_saved" => "αποθηκεύτηκε.",
|
||||
"error_adding_currency" => "Error adding currency entry.",
|
||||
|
||||
@ -136,17 +136,24 @@ $i18n = [
|
||||
"experimental_info" => "Experimental settings will probably not work perfectly.",
|
||||
"payment_methods" => "Payment Methods",
|
||||
"payment_methods_info" => "Click a payment method to disable / enable it.",
|
||||
"rename_payment_methods_info" => "Click the name on a payment method to rename 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",
|
||||
"rename_payment_method" => "Rename Payment Method",
|
||||
"payment_renamed" => "Payment method renamed",
|
||||
"payment_not_renamed" => "Payment method not renamed",
|
||||
"test" => "Test",
|
||||
"add" => "Add",
|
||||
"save" => "Save",
|
||||
"export_subscriptions" => "Export Subscriptions",
|
||||
"export_to_json" => "Export to JSON",
|
||||
// Filters menu
|
||||
"filter" => "Filter",
|
||||
"clear" => "Clear",
|
||||
// Toast
|
||||
"success" => "Success",
|
||||
// Endpoint responses
|
||||
@ -162,6 +169,7 @@ $i18n = [
|
||||
"failed_remove_category" => "Failed to remove category",
|
||||
"category_saved" => "Category saved",
|
||||
"category_removed" => "Category removed",
|
||||
"sort_order_saved" => "Sort order saved",
|
||||
// Currency
|
||||
"currency_saved" => "was saved.",
|
||||
"error_adding_currency" => "Error adding currency entry.",
|
||||
|
||||
@ -136,17 +136,24 @@ $i18n = [
|
||||
"experimental_info" => "Las configuraciones experimentales probablemente no funcionarán perfectamente.",
|
||||
"payment_methods" => "Métodos de Pago",
|
||||
"payment_methods_info" => "Haz clic en un método de pago para deshabilitarlo/habilitarlo.",
|
||||
"rename_payment_methods_info" => "Haz clic en el nombre de un método de pago para cambiarle el nombre.",
|
||||
"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",
|
||||
"rename_payment_method" => "Renombrar método de pago",
|
||||
"payment_renamed" => "Método de pago renombrado",
|
||||
"payment_not_renamed" => "Error al renombrar el método de pago",
|
||||
"test" => "Probar",
|
||||
"add" => "Agregar",
|
||||
"save" => "Guardar",
|
||||
"export_subscriptions" => "Exportar suscripciones",
|
||||
"export_to_json" => "Exportar a JSON",
|
||||
// Filters menu
|
||||
"filter" => "Filtrar",
|
||||
"clear" => "Limpiar",
|
||||
// Toast
|
||||
"success" => "Éxito",
|
||||
// Endpoint responses
|
||||
@ -162,6 +169,7 @@ $i18n = [
|
||||
"failed_remove_category" => "Error al eliminar la categoría",
|
||||
"category_saved" => "Categoría guardada",
|
||||
"category_removed" => "Categoría eliminada",
|
||||
"sort_order_saved" => "Orden de clasificación guardado",
|
||||
// Currency
|
||||
"currency_saved" => "fue guardada.",
|
||||
"error_adding_currency" => "Error al añadir la entrada de la moneda.",
|
||||
|
||||
@ -136,17 +136,24 @@ $i18n = [
|
||||
"experimental_info" => "Les paramètres expérimentaux ne fonctionneront probablement pas parfaitement.",
|
||||
"payment_methods" => "Méthodes de paiement",
|
||||
"payment_methods_info" => "Cliquez sur une méthode de paiement pour la désactiver / l'activer.",
|
||||
"rename_payment_methods_info" => "Cliquez sur le nom d'un mode de paiement pour le renommer.",
|
||||
"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",
|
||||
"rename_payment_method" => "Renommer la méthode de paiement",
|
||||
"payment_renamed" => "Méthode de paiement renommée",
|
||||
"payment_not_renamed" => "La méthode de paiement n'a pas été renommée",
|
||||
"test" => "Test",
|
||||
"add" => "Ajouter",
|
||||
"save" => "Enregistrer",
|
||||
"export_subscriptions" => "Exporter les abonnements",
|
||||
"export_to_json" => "Exporter en JSON",
|
||||
// Menu des filtes
|
||||
"filter" => "Filtre",
|
||||
"clear" => "Effacer",
|
||||
// Toast
|
||||
"success" => "Succès",
|
||||
// Réponses de l'API
|
||||
@ -162,6 +169,7 @@ $i18n = [
|
||||
"failed_remove_category" => "Échec de la suppression de la catégorie",
|
||||
"category_saved" => "Catégorie enregistrée",
|
||||
"category_removed" => "Catégorie supprimée",
|
||||
"sort_order_saved" => "L'ordre de tri a été enregistré",
|
||||
// Devise
|
||||
"currency_saved" => "a été enregistrée.",
|
||||
"error_adding_currency" => "Erreur lors de l'ajout de l'entrée de devise.",
|
||||
|
||||
@ -136,17 +136,24 @@ $i18n = [
|
||||
"experimental_info" => "実験的な設定は、おそらく完全には機能しません。",
|
||||
"payment_methods" => "支払い方法",
|
||||
"payment_methods_info" => "支払い方法をクリックして無効/有効を切り替えます。",
|
||||
"rename_payment_methods_info" => "支払い方法の名前をクリックして、名前を変更します。",
|
||||
"cant_delete_payment_method_in_use" => "支払い方法が使用中のため無効にできません。",
|
||||
"add_custom_payment" => "カスタム支払い方法を追加",
|
||||
"payment_method_name" => "支払い方法名",
|
||||
"payment_method_added_successfuly" => "支払い方法が追加されました",
|
||||
"disable" => "無効",
|
||||
"enable" => "有効",
|
||||
"rename_payment_method" => "支払い方法の名前を変更",
|
||||
"payment_renamed" => "支払い方法が変更されました",
|
||||
"payment_not_renamed" => "支払い方法が変更されませんでした",
|
||||
"test" => "テスト",
|
||||
"add" => "追加",
|
||||
"save" => "保存",
|
||||
"export_subscriptions" => "購読をエクスポート",
|
||||
"export_to_json" => "JSONにエクスポート",
|
||||
// Filters menu
|
||||
"filter" => "フィルタ",
|
||||
"clear" => "クリア",
|
||||
// Toast
|
||||
"success" => "成功",
|
||||
// Endpoint responses
|
||||
@ -162,6 +169,7 @@ $i18n = [
|
||||
"failed_remove_category" => "カテゴリの削除に失敗",
|
||||
"category_saved" => "カテゴリの保存",
|
||||
"category_removed" => "カテゴリの削除",
|
||||
"sort_order_saved" => "並べ替え順が保存されました",
|
||||
// Currency
|
||||
"currency_saved" => "通貨を保存",
|
||||
"error_adding_currency" => "通貨エントリの追加エラー.",
|
||||
|
||||
@ -136,17 +136,24 @@ $i18n = [
|
||||
"experimental_info" => "Definições experimentais provavelmente não funcionarão correctamente.",
|
||||
"payment_methods" => "Métodos de Pagamento",
|
||||
"payment_methods_info" => "Clique num método de pagamento para o activar / desactivar.",
|
||||
"rename_payment_methods_info" => "Clique no nome do método de pagamento para o renomear.",
|
||||
"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",
|
||||
"rename_payment_method" => "Renomear método de pagamento",
|
||||
"payment_renamed" => "Método de pagamento renomeado",
|
||||
"payment_not_renamed" => "Método de pagamento não renomeado",
|
||||
"test" => "Testar",
|
||||
"add" => "Adicionar",
|
||||
"save" => "Guardar",
|
||||
"export_subscriptions" => "Exportar Subscrições",
|
||||
"export_to_json" => "Exportar para JSON",
|
||||
// Filters menu
|
||||
"filter" => "Filtro",
|
||||
"clear" => "Limpar",
|
||||
// Toast
|
||||
"success" => "Sucesso",
|
||||
// Endpoint responses
|
||||
@ -162,6 +169,7 @@ $i18n = [
|
||||
"failed_remove_category" => "Erro ao remover categoria",
|
||||
"category_saved" => "Categoria guardada",
|
||||
"category_removed" => "Categoria removida",
|
||||
"sort_order_saved" => "Ordenação guardada",
|
||||
// Currency
|
||||
"currency_saved" => "guardada.",
|
||||
"error_adding_currency" => "Erro ao adicionar moeda.",
|
||||
|
||||
@ -136,17 +136,24 @@ $i18n = [
|
||||
"experimental_info" => "Deneysel ayarlar muhtemelen mükemmel çalışmayacak.",
|
||||
"payment_methods" => "Ödeme Yöntemleri",
|
||||
"payment_methods_info" => "Bir ödeme yöntemini devre dışı bırakmak / etkinleştirmek için tıklayın.",
|
||||
"rename_payment_methods_info" => "Yeniden adlandırmak için bir ödeme yönteminin adına 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",
|
||||
"rename_payment_method" => "Ödeme yöntemi adını değiştir",
|
||||
"payment_renamed" => "Ödeme yöntemi adı değiştirildi",
|
||||
"payment_not_renamed" => "Ödeme yöntemi adı değiştirilemedi",
|
||||
"test" => "Test Et",
|
||||
"add" => "Ekle",
|
||||
"save" => "Kaydet",
|
||||
"export_subscriptions" => "Abonelikleri Dışa Aktar",
|
||||
"export_to_json" => "JSON'a dışa aktar",
|
||||
// Filters menu
|
||||
"filter" => "Filtre",
|
||||
"clear" => "Temizle",
|
||||
// Toast
|
||||
"success" => "Başarılı",
|
||||
// Endpoint responses
|
||||
@ -162,6 +169,7 @@ $i18n = [
|
||||
"failed_remove_category" => "Kategori kaldırılamadı",
|
||||
"category_saved" => "Kategori kaydedildi",
|
||||
"category_removed" => "Kategori kaldırıldı",
|
||||
"sort_order_saved" => "Sıralama düzeni kaydedildi",
|
||||
// Currency
|
||||
"currency_saved" => "kaydedildi.",
|
||||
"error_adding_currency" => "Para birimi girişi eklenirken hata oluştu.",
|
||||
|
||||
@ -143,17 +143,25 @@ $i18n = [
|
||||
"experimental_info" => "实验性设置,可能存在问题。",
|
||||
"payment_methods" => "支付方式",
|
||||
"payment_methods_info" => "点击支付方式以禁用/启用。",
|
||||
"rename_payment_methods_info" => "点击付款方式名称,重新命名该付款方式。"
|
||||
"cant_delete_payment_method_in_use" => "不能禁用正在使用的支付方式",
|
||||
"add_custom_payment" => "添加自定义支付方式",
|
||||
"payment_method_name" => "支付方式名称",
|
||||
"payment_method_added_successfuly" => "支付方式已成功添加",
|
||||
"disable" => "禁用",
|
||||
"enable" => "启用",
|
||||
"rename_payment_method" => "重命名支付方式",
|
||||
"payment_renamed" => "支付方式已重命名",
|
||||
"payment_not_renamed" => "支付方式未重命名",
|
||||
"test" => "测试",
|
||||
"add" => "添加",
|
||||
"save" => "保存",
|
||||
"export_subscriptions" => "导出订阅",
|
||||
"export_to_json" => "导出为 JSON",
|
||||
|
||||
// Filters menu
|
||||
"filter" => "筛选",
|
||||
"clear" => "清除",
|
||||
|
||||
// Toast
|
||||
"success" => "成功",
|
||||
@ -172,6 +180,7 @@ $i18n = [
|
||||
"failed_remove_category" => "移除分类失败",
|
||||
"category_saved" => "分类已保存",
|
||||
"category_removed" => "分类已移除",
|
||||
"sort_order_saved" => "排序顺序已保存",
|
||||
|
||||
// Currency
|
||||
"currency_saved" => "货币已保存。",
|
||||
|
||||
@ -136,17 +136,24 @@ $i18n = [
|
||||
"experimental_info" => "實驗性設定,可能存在問題。",
|
||||
"payment_methods" => "付款方式",
|
||||
"payment_methods_info" => "點選付款方式以停用/啟用。",
|
||||
"rename_payment_methods_info" => "點選付款方式的名稱可對其進行重新命名。",
|
||||
"cant_delete_payment_method_in_use" => "無法停用正在使用的付款方式",
|
||||
"add_custom_payment" => "新增自訂付款方式",
|
||||
"payment_method_name" => "付款方式名稱",
|
||||
"payment_method_added_successfuly" => "付款方式已成功新增",
|
||||
"disable" => "停用",
|
||||
"enable" => "啟用",
|
||||
"rename_payment_method" => "更改付款方式名稱",
|
||||
"payment_renamed" => "付款方式名稱已更改",
|
||||
"payment_not_renamed" => "付款方式名稱未更改",
|
||||
"test" => "測試",
|
||||
"add" => "新增",
|
||||
"save" => "儲存",
|
||||
"export_subscriptions" => "匯出訂閱",
|
||||
"export_to_json" => "匯出為 JSON 檔案",
|
||||
// Filters menu
|
||||
"filter" => "篩選",
|
||||
"clear" => "清除",
|
||||
// Toast
|
||||
"success" => "成功",
|
||||
// Endpoint responses
|
||||
@ -162,6 +169,7 @@ $i18n = [
|
||||
"failed_remove_category" => "移除分類失敗",
|
||||
"category_saved" => "分類已儲存",
|
||||
"category_removed" => "分類已移除",
|
||||
"sort_order_saved" => "排序順序已儲存",
|
||||
// Currency
|
||||
"currency_saved" => "已儲存。",
|
||||
"error_adding_currency" => "新增貨幣時發生錯誤。",
|
||||
|
||||
@ -1,3 +1,3 @@
|
||||
<?php
|
||||
$version = "v1.11.3";
|
||||
$version = "v1.12.0";
|
||||
?>
|
||||
14
migrations/000010.php
Normal file
14
migrations/000010.php
Normal file
@ -0,0 +1,14 @@
|
||||
<?php
|
||||
// This migration adds a "order" column to the categories table so that they can be sorted and initializes all values to their id.
|
||||
|
||||
/** @noinspection PhpUndefinedVariableInspection */
|
||||
$columnQuery = $db->query("SELECT * FROM pragma_table_info('categories') WHERE name='order'");
|
||||
$columnRequired = $columnQuery->fetchArray(SQLITE3_ASSOC) === false;
|
||||
|
||||
if ($columnRequired) {
|
||||
$db->exec('ALTER TABLE categories ADD COLUMN `order` INTEGER DEFAULT 0');
|
||||
$db->exec('UPDATE categories SET `order` = id');
|
||||
}
|
||||
|
||||
|
||||
?>
|
||||
2
scripts/libs/sortable.min.js
vendored
Normal file
2
scripts/libs/sortable.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
@ -165,9 +165,12 @@ function addCategoryButton(categoryId) {
|
||||
if(responseData.success) {
|
||||
const newCategoryId = responseData.categoryId;;
|
||||
let container = document.getElementById("categories");
|
||||
let div = document.createElement("div");
|
||||
div.className = "form-group-inline";
|
||||
div.dataset.categoryid = newCategoryId;
|
||||
let row = document.createElement("li");
|
||||
row.className = "form-group-inline";
|
||||
row.dataset.categoryid = newCategoryId;
|
||||
|
||||
let dragIcon = document.createElement("div");
|
||||
dragIcon.className = "drag-icon";
|
||||
|
||||
let input = document.createElement("input");
|
||||
input.type = "text";
|
||||
@ -201,11 +204,12 @@ function addCategoryButton(categoryId) {
|
||||
|
||||
deleteLink.appendChild(deleteImage);
|
||||
|
||||
div.appendChild(input);
|
||||
div.appendChild(editLink);
|
||||
div.appendChild(deleteLink);
|
||||
row.appendChild(dragIcon);
|
||||
row.appendChild(input);
|
||||
row.appendChild(editLink);
|
||||
row.appendChild(deleteLink);
|
||||
|
||||
container.appendChild(div);
|
||||
container.appendChild(row);
|
||||
} else {
|
||||
showErrorMessage(responseData.errorMessage);
|
||||
}
|
||||
@ -246,6 +250,7 @@ function removeCategory(categoryId) {
|
||||
function editCategory(categoryId) {
|
||||
var saveButton = document.querySelector(`div[data-categoryid="${categoryId}"] button[name="save"]`);
|
||||
var inputElement = document.querySelector(`div[data-categoryid="${categoryId}"] input[name="category"]`);
|
||||
console.log(saveButton);
|
||||
saveButton.classList.add("disabled");
|
||||
saveButton.disabled = true;
|
||||
if (inputElement) {
|
||||
@ -424,7 +429,7 @@ function togglePayment(paymentId) {
|
||||
const element = document.querySelector(`div[data-paymentid="${paymentId}"]`);
|
||||
|
||||
if (element.dataset.inUse === 'yes') {
|
||||
return showErrorMessage(translate(cant_disable_payment_in_use));
|
||||
return showErrorMessage(translate('cant_disable_payment_in_use'));
|
||||
}
|
||||
|
||||
const newEnabledState = element.dataset.enabled === '1' ? '0' : '1';
|
||||
@ -449,6 +454,69 @@ function togglePayment(paymentId) {
|
||||
});
|
||||
}
|
||||
|
||||
document.body.addEventListener('click', function(e) {
|
||||
let targetElement = e.target;
|
||||
do {
|
||||
if (targetElement.classList && targetElement.classList.contains('payments-payment')) {
|
||||
let targetChild = e.target;
|
||||
do {
|
||||
if (targetChild.classList && targetChild.classList.contains('payment-name')) {
|
||||
return;
|
||||
}
|
||||
targetChild = targetChild.parentNode;
|
||||
} while (targetChild && targetChild !== targetElement);
|
||||
|
||||
const paymentId = targetElement.dataset.paymentid;
|
||||
togglePayment(paymentId);
|
||||
return;
|
||||
}
|
||||
targetElement = targetElement.parentNode;
|
||||
} while (targetElement);
|
||||
});
|
||||
|
||||
document.body.addEventListener('blur', function(e) {
|
||||
let targetElement = e.target;
|
||||
if (targetElement.classList && targetElement.classList.contains('payment-name')) {
|
||||
const paymentId = targetElement.closest('.payments-payment').dataset.paymentid;
|
||||
const newName = targetElement.textContent;
|
||||
renamePayment(paymentId, newName);
|
||||
}
|
||||
}, true);
|
||||
|
||||
function renamePayment(paymentId, newName) {
|
||||
const name = newName.trim();
|
||||
const formData = new FormData();
|
||||
formData.append('paymentId', paymentId);
|
||||
formData.append('name', name);
|
||||
fetch('endpoints/payments/rename.php', {
|
||||
method: 'POST',
|
||||
body: formData
|
||||
}).then(response => {
|
||||
if (!response.ok) {
|
||||
throw new Error(translate('network_response_error'));
|
||||
}
|
||||
return response.json();
|
||||
}).then(data => {
|
||||
if (data.success) {
|
||||
showSuccessMessage(`${newName} ${data.message}`);
|
||||
} else {
|
||||
showErrorMessage(data.message);
|
||||
}
|
||||
}).catch(error => {
|
||||
showErrorMessage(translate('unknown_error'));
|
||||
});
|
||||
}
|
||||
|
||||
document.body.addEventListener('keypress', function(e) {
|
||||
let targetElement = e.target;
|
||||
if (targetElement.classList && targetElement.classList.contains('payment-name')) {
|
||||
if (e.key === 'Enter') {
|
||||
e.preventDefault();
|
||||
targetElement.blur();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function handleFileSelect(event) {
|
||||
const fileInput = event.target;
|
||||
const iconPreview = document.querySelector('.icon-preview');
|
||||
@ -843,3 +911,41 @@ function setRemoveBackground() {
|
||||
function exportToJson() {
|
||||
window.location.href = "endpoints/subscriptions/export.php";
|
||||
}
|
||||
|
||||
function saveCategorySorting() {
|
||||
const categories = document.getElementById('categories');
|
||||
const categoryIds = Array.from(categories.children).map(category => category.dataset.categoryid);
|
||||
|
||||
const formData = new FormData();
|
||||
categoryIds.forEach(categoryId => {
|
||||
formData.append('categoryIds[]', categoryId);
|
||||
});
|
||||
|
||||
fetch('endpoints/categories/sort.php', {
|
||||
method: 'POST',
|
||||
body: formData
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
showSuccessMessage(data.message);
|
||||
} else {
|
||||
showErrorMessage(data.errorMessage);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
showErrorMessage(translate('unknown_error'));
|
||||
});
|
||||
}
|
||||
|
||||
var el = document.getElementById('categories');
|
||||
var sortable = Sortable.create(el, {
|
||||
handle: '.drag-icon',
|
||||
ghostClass: 'sortable-ghost',
|
||||
delay: 500,
|
||||
delayOnTouchOnly: true,
|
||||
touchStartThreshold: 5,
|
||||
onEnd: function (evt) {
|
||||
saveCategorySorting();
|
||||
},
|
||||
});
|
||||
@ -25,3 +25,91 @@ function loadGraph(container, dataPoints, currency, run) {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function closeSubMenus() {
|
||||
var subMenus = document.querySelectorAll('.filtermenu-submenu-content');
|
||||
subMenus.forEach(subMenu => {
|
||||
subMenu.classList.remove('is-open');
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
var filtermenu = document.querySelector('#filtermenu-button');
|
||||
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);
|
||||
|
||||
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();
|
||||
} else {
|
||||
closeSubMenus();
|
||||
subMenu.classList.add("is-open");
|
||||
}
|
||||
}
|
||||
|
||||
document.querySelectorAll('.filter-item').forEach(function(item) {
|
||||
item.addEventListener('click', function(e) {
|
||||
if (this.hasAttribute('data-categoryid')) {
|
||||
const categoryId = this.getAttribute('data-categoryid');
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
let newUrl = 'stats.php?';
|
||||
|
||||
if (urlParams.get('category') === categoryId) {
|
||||
urlParams.delete('category');
|
||||
} else {
|
||||
urlParams.set('category', categoryId);
|
||||
}
|
||||
|
||||
newUrl += urlParams.toString();
|
||||
window.location.href = newUrl;
|
||||
} else if (this.hasAttribute('data-memberid')) {
|
||||
const memberId = this.getAttribute('data-memberid');
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
let newUrl = 'stats.php?';
|
||||
|
||||
if (urlParams.get('member') === memberId) {
|
||||
urlParams.delete('member');
|
||||
} else {
|
||||
urlParams.set('member', memberId);
|
||||
}
|
||||
|
||||
newUrl += urlParams.toString();
|
||||
window.location.href = newUrl;
|
||||
} else if (this.hasAttribute('data-paymentid')) {
|
||||
const paymentId = this.getAttribute('data-paymentid');
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
let newUrl = 'stats.php?';
|
||||
|
||||
if (urlParams.get('payment') === paymentId) {
|
||||
urlParams.delete('payment');
|
||||
} else {
|
||||
urlParams.set('payment', paymentId);
|
||||
}
|
||||
|
||||
newUrl += urlParams.toString();
|
||||
window.location.href = newUrl;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
function clearFilters() {
|
||||
window.location.href = 'stats.php';
|
||||
}
|
||||
@ -33,6 +33,7 @@ self.addEventListener('install', function(event) {
|
||||
'scripts/i18n/zh_tw.js',
|
||||
'scripts/i18n/getlang.js',
|
||||
'scripts/libs/chart.js',
|
||||
'scripts/libs/sortable.min.js',
|
||||
'images/icon/favicon.ico',
|
||||
'images/wallossolid.png',
|
||||
'images/wallossolidwhite.png',
|
||||
|
||||
19
settings.php
19
settings.php
@ -2,6 +2,7 @@
|
||||
require_once 'includes/header.php';
|
||||
?>
|
||||
|
||||
<script src="scripts/libs/sortable.min.js"></script>
|
||||
<style>
|
||||
.logo-preview:after {
|
||||
content: '<?= translate('upload_logo', $i18n) ?>';
|
||||
@ -238,7 +239,7 @@
|
||||
</section>
|
||||
|
||||
<?php
|
||||
$sql = "SELECT * FROM categories";
|
||||
$sql = "SELECT * FROM categories ORDER BY `order` ASC";
|
||||
$result = $db->query($sql);
|
||||
|
||||
if ($result) {
|
||||
@ -254,7 +255,7 @@
|
||||
<h2><?= translate('categories', $i18n) ?></h2>
|
||||
</header>
|
||||
<div class="account-categories">
|
||||
<div id="categories">
|
||||
<div id="categories" class="sortable-list">
|
||||
<?php
|
||||
foreach ($categories as $category) {
|
||||
if ($category['id'] != 1) {
|
||||
@ -272,6 +273,7 @@
|
||||
}
|
||||
?>
|
||||
<div class="form-group-inline" data-categoryid="<?= $category['id'] ?>">
|
||||
<div class="drag-icon"></div>
|
||||
<input type="text" name="category" value="<?= $category['name'] ?>" placeholder="Category">
|
||||
<button class="image-button medium" onClick="editCategory(<?= $category['id'] ?>)" name="save">
|
||||
<img src="images/siteicons/save.png" title="<?= translate('save_category', $i18n) ?>">
|
||||
@ -497,14 +499,11 @@
|
||||
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'] ?>)">
|
||||
title="<?= $inUse ? translate('cant_delete_payment_method_in_use', $i18n) : ($payment['enabled'] ? translate('disable', $i18n) : translate('enable', $i18n)) ?>">
|
||||
<img src="<?= $paymentIconFolder.$payment['icon'] ?>" alt="Logo" />
|
||||
<span class="payment-name">
|
||||
<?= $payment['name'] ?>
|
||||
</span>
|
||||
<span class="payment-name" contenteditable="true" title="<?= translate("rename_payment_method", $i18n) ?>"><?= $payment['name'] ?></span>
|
||||
<?php
|
||||
if ($payment['id'] > 31 && !$inUse) {
|
||||
if (!$inUse) {
|
||||
?>
|
||||
<div class="delete-payment-method" title="<?= translate('delete', $i18n) ?>" data-paymentid="<?= $payment['id'] ?>">x</div>
|
||||
<?php
|
||||
@ -520,6 +519,10 @@
|
||||
<i class="fa-solid fa-circle-info"></i>
|
||||
<?= translate('payment_methods_info', $i18n) ?>
|
||||
</p>
|
||||
<p>
|
||||
<i class="fa-solid fa-circle-info"></i>
|
||||
<?= translate('rename_payment_methods_info', $i18n) ?>
|
||||
</p>
|
||||
</div>
|
||||
<header>
|
||||
<h2 class="second-header"><?= translate("add_custom_payment", $i18n) ?></h2>
|
||||
|
||||
281
stats.php
281
stats.php
@ -51,7 +51,7 @@ while ($row = $result->fetchArray(SQLITE3_ASSOC)) {
|
||||
|
||||
// Get categories
|
||||
$categories = array();
|
||||
$query = "SELECT * FROM categories";
|
||||
$query = "SELECT * FROM categories ORDER BY 'order' ASC";
|
||||
$result = $db->query($query);
|
||||
while ($row = $result->fetchArray(SQLITE3_ASSOC)) {
|
||||
$categoryId = $row['id'];
|
||||
@ -61,7 +61,7 @@ while ($row = $result->fetchArray(SQLITE3_ASSOC)) {
|
||||
}
|
||||
|
||||
// Get payment methods
|
||||
$categories = array();
|
||||
$paymentMethodCount = array();
|
||||
$query = "SELECT * FROM payment_methods WHERE enabled = 1";
|
||||
$result = $db->query($query);
|
||||
while ($row = $result->fetchArray(SQLITE3_ASSOC)) {
|
||||
@ -89,8 +89,41 @@ $amountDueThisMonth = 0;
|
||||
$totalCostPerMonth = 0;
|
||||
$totalSavingsPerMonth = 0;
|
||||
|
||||
$statsSubtitleParts = [];
|
||||
$query = "SELECT name, price, frequency, cycle, currency_id, next_payment, payer_user_id, category_id, payment_method_id, inactive FROM subscriptions";
|
||||
$result = $db->query($query);
|
||||
$conditions = [];
|
||||
$params = [];
|
||||
|
||||
if (isset($_GET['member'])) {
|
||||
$conditions[] = "payer_user_id = :member";
|
||||
$params[':member'] = $_GET['member'];
|
||||
$statsSubtitleParts[] = $members[$_GET['member']]['name'];
|
||||
}
|
||||
|
||||
if (isset($_GET['category'])) {
|
||||
$conditions[] = "category_id = :category";
|
||||
$params[':category'] = $_GET['category'];
|
||||
$statsSubtitleParts[] = $categories[$_GET['category']]['name'];
|
||||
}
|
||||
|
||||
if (isset($_GET['payment'])) {
|
||||
$conditions[] = "payment_method_id = :payment";
|
||||
$params[':payment'] = $_GET['payment'];
|
||||
$statsSubtitleParts[] = $paymentMethodCount[$_GET['payment']]['name'];
|
||||
}
|
||||
|
||||
if (!empty($conditions)) {
|
||||
$query .= " WHERE " . implode(' AND ', $conditions);
|
||||
}
|
||||
|
||||
$stmt = $db->prepare($query);
|
||||
$statsSubtitle = !empty($statsSubtitleParts) ? '(' . implode(', ', $statsSubtitleParts) . ')' : "";
|
||||
|
||||
foreach ($params as $key => $value) {
|
||||
$stmt->bindValue($key, $value, SQLITE3_INTEGER);
|
||||
}
|
||||
|
||||
$result = $stmt->execute();
|
||||
if ($result) {
|
||||
while ($row = $result->fetchArray(SQLITE3_ASSOC)) {
|
||||
$subscriptions[] = $row;
|
||||
@ -160,7 +193,97 @@ if ($result) {
|
||||
$numberOfElements = 6;
|
||||
?>
|
||||
<section class="contain">
|
||||
<h2><?= translate('general_statistics', $i18n) ?></h2>
|
||||
<div class="split-header">
|
||||
<h2>
|
||||
<?= translate('general_statistics', $i18n) ?> <span class="header-subtitle"><?= $statsSubtitle ?></span>
|
||||
</h2>
|
||||
<div class="filtermenu">
|
||||
<button class="button" id="filtermenu-button">
|
||||
<i class="fa-solid fa-filter"></i>
|
||||
<?= translate("filter", $i18n) ?>
|
||||
</button>
|
||||
<div class="filtermenu-content">
|
||||
<?php
|
||||
if (count($members) > 1) {
|
||||
?>
|
||||
<div class="filtermenu-submenu">
|
||||
<div class="filter-title" onClick="toggleSubMenu('member')"><?= translate("member", $i18n) ?></div>
|
||||
<div class="filtermenu-submenu-content" id="filter-member">
|
||||
<?php
|
||||
foreach ($members as $member) {
|
||||
$selectedClass = '';
|
||||
if (isset($_GET['member']) && $_GET['member'] == $member['id']) {
|
||||
$selectedClass = 'selected';
|
||||
}
|
||||
?>
|
||||
<div class="filter-item <?= $selectedClass ?>" data-memberid="<?= $member['id'] ?>"><?= $member['name'] ?></div>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
<?php
|
||||
if (count($categories) > 1) {
|
||||
?>
|
||||
<div class="filtermenu-submenu">
|
||||
<div class="filter-title" onClick="toggleSubMenu('category')"><?= translate("category", $i18n) ?></div>
|
||||
<div class="filtermenu-submenu-content" id="filter-category">
|
||||
<?php
|
||||
foreach ($categories as $category) {
|
||||
$selectedClass = '';
|
||||
if (isset($_GET['category']) && $_GET['category'] == $category['id']) {
|
||||
$selectedClass = 'selected';
|
||||
}
|
||||
?>
|
||||
<div class="filter-item <?= $selectedClass ?>" data-categoryid="<?= $category['id'] ?>"><?= $category['name'] ?></div>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
<?php
|
||||
if (count($paymentMethodCount) > 1) {
|
||||
?>
|
||||
<div class="filtermenu-submenu">
|
||||
<div class="filter-title" onClick="toggleSubMenu('payment')"><?= translate("payment_method", $i18n) ?></div>
|
||||
<div class="filtermenu-submenu-content" id="filter-payment">
|
||||
<?php
|
||||
foreach ($paymentMethodCount as $payment) {
|
||||
$selectedClass = '';
|
||||
if (isset($_GET['payment']) && $_GET['payment'] == $payment['id']) {
|
||||
$selectedClass = 'selected';
|
||||
}
|
||||
?>
|
||||
<div class="filter-item <?= $selectedClass ?>" data-paymentid="<?= $payment['id'] ?>"><?= $payment['name'] ?></div>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
<?php
|
||||
if (isset($_GET['member']) || isset($_GET['category']) || isset($_GET['payment'])) {
|
||||
?>
|
||||
<div class="filtermenu-submenu">
|
||||
<div class="filter-title filter-clear" onClick="clearFilters()">
|
||||
<i class="fa-solid fa-times-circle"></i> <?= translate("clear", $i18n) ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="statistics">
|
||||
<div class="statistic">
|
||||
<span><?= $activeSubscriptions ?></span>
|
||||
@ -208,86 +331,92 @@ $numberOfElements = 6;
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
<h2><?= translate('split_views', $i18n) ?></h2>
|
||||
<div class="graphs">
|
||||
<?php
|
||||
$categoryDataPoints = [];
|
||||
foreach ($categoryCost as $category) {
|
||||
if ($category['cost'] != 0) {
|
||||
$categoryDataPoints[] = [
|
||||
"label" => $category['name'],
|
||||
"y" => $category["cost"],
|
||||
];
|
||||
}
|
||||
}
|
||||
<?php
|
||||
$categoryDataPoints = [];
|
||||
foreach ($categoryCost as $category) {
|
||||
if ($category['cost'] != 0) {
|
||||
$categoryDataPoints[] = [
|
||||
"label" => $category['name'],
|
||||
"y" => $category["cost"],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
$showCategoryCostGraph = count($categoryDataPoints) > 1;
|
||||
$showCategoryCostGraph = count($categoryDataPoints) > 1;
|
||||
|
||||
$memberDataPoints = [];
|
||||
foreach ($memberCost as $member) {
|
||||
if ($member['cost'] != 0) {
|
||||
$memberDataPoints[] = [
|
||||
"label" => $member['name'],
|
||||
"y" => $member["cost"],
|
||||
];
|
||||
|
||||
}
|
||||
}
|
||||
$memberDataPoints = [];
|
||||
foreach ($memberCost as $member) {
|
||||
if ($member['cost'] != 0) {
|
||||
$memberDataPoints[] = [
|
||||
"label" => $member['name'],
|
||||
"y" => $member["cost"],
|
||||
];
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
$showMemberCostGraph = count($memberDataPoints) > 1;
|
||||
$showMemberCostGraph = count($memberDataPoints) > 1;
|
||||
|
||||
$paymentMethodDataPoints = [];
|
||||
foreach ($paymentMethodCount as $paymentMethod) {
|
||||
if ($paymentMethod['count'] != 0) {
|
||||
$paymentMethodDataPoints[] = [
|
||||
"label" => $paymentMethod['name'],
|
||||
"y" => $paymentMethod["count"],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
$showPaymentMethodCountGraph = count($paymentMethodDataPoints) > 1;
|
||||
|
||||
if ($showMemberCostGraph) {
|
||||
?>
|
||||
<section class="graph">
|
||||
<header>
|
||||
<?= translate('household_split', $i18n) ?>
|
||||
<div class="sub-header">(<?= translate('monthly_cost', $i18n) ?>)</div>
|
||||
</header>
|
||||
<canvas id="memberSplitChart"></canvas>
|
||||
</section>
|
||||
<?php
|
||||
}
|
||||
|
||||
if ($showCategoryCostGraph) {
|
||||
?>
|
||||
<section class="graph">
|
||||
<header>
|
||||
<?= translate('category_split', $i18n) ?>
|
||||
<div class="sub-header">(<?= translate('monthly_cost', $i18n) ?>)</div>
|
||||
</header>
|
||||
<canvas id="categorySplitChart" style="height: 370px; width: 100%;"></canvas>
|
||||
</section>
|
||||
<?php
|
||||
}
|
||||
|
||||
if ($showPaymentMethodCountGraph) {
|
||||
?>
|
||||
<section class="graph">
|
||||
<header>
|
||||
<?= translate('payment_method_split', $i18n) ?>
|
||||
</header>
|
||||
<canvas id="paymentMethidSplitChart" style="height: 370px; width: 100%;"></canvas>
|
||||
</section>
|
||||
<?php
|
||||
}
|
||||
$paymentMethodDataPoints = [];
|
||||
foreach ($paymentMethodCount as $paymentMethod) {
|
||||
if ($paymentMethod['count'] != 0) {
|
||||
$paymentMethodDataPoints[] = [
|
||||
"label" => $paymentMethod['name'],
|
||||
"y" => $paymentMethod["count"],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
$showPaymentMethodCountGraph = count($paymentMethodDataPoints) > 1;
|
||||
if ($showCategoryCostGraph || $showMemberCostGraph || $showPaymentMethodCountGraph) {
|
||||
?>
|
||||
</div>
|
||||
<h2><?= translate('split_views', $i18n) ?></h2>
|
||||
<div class="graphs">
|
||||
<?php
|
||||
if ($showMemberCostGraph) {
|
||||
?>
|
||||
<section class="graph">
|
||||
<header>
|
||||
<?= translate('household_split', $i18n) ?>
|
||||
<div class="sub-header">(<?= translate('monthly_cost', $i18n) ?>)</div>
|
||||
</header>
|
||||
<canvas id="memberSplitChart"></canvas>
|
||||
</section>
|
||||
<?php
|
||||
}
|
||||
|
||||
if ($showCategoryCostGraph) {
|
||||
?>
|
||||
<section class="graph">
|
||||
<header>
|
||||
<?= translate('category_split', $i18n) ?>
|
||||
<div class="sub-header">(<?= translate('monthly_cost', $i18n) ?>)</div>
|
||||
</header>
|
||||
<canvas id="categorySplitChart" style="height: 370px; width: 100%;"></canvas>
|
||||
</section>
|
||||
<?php
|
||||
}
|
||||
|
||||
if ($showPaymentMethodCountGraph) {
|
||||
?>
|
||||
<section class="graph">
|
||||
<header>
|
||||
<?= translate('payment_method_split', $i18n) ?>
|
||||
</header>
|
||||
<canvas id="paymentMethidSplitChart" style="height: 370px; width: 100%;"></canvas>
|
||||
</section>
|
||||
<?php
|
||||
}
|
||||
|
||||
?>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
|
||||
</section>
|
||||
<?php
|
||||
if ($showCategoryCostGraph || $showMemberCostGraph) {
|
||||
if ($showCategoryCostGraph || $showMemberCostGraph || $showPaymentMethodCountGraph) {
|
||||
?>
|
||||
<script src="scripts/libs/chart.js"></script>
|
||||
<script type="text/javascript">
|
||||
|
||||
@ -11,15 +11,21 @@ header .logo .logo-image {
|
||||
background-image: url("../images/wallossolidwhite.png");
|
||||
}
|
||||
|
||||
.split-header > h2 .header-subtitle {
|
||||
color: #A9A9A9;
|
||||
}
|
||||
|
||||
.subscription,
|
||||
.subscription-form,
|
||||
.account-section,
|
||||
.avatar-select,
|
||||
.logo-search,
|
||||
.icon-search,
|
||||
.dropdown-content,
|
||||
.sort-options,
|
||||
.statistic,
|
||||
.graph {
|
||||
.graph,
|
||||
.filtermenu-content {
|
||||
background-color: #222;
|
||||
border: 1px solid #333;
|
||||
box-shadow: 0 2px 5px rgba(120, 120, 120, 0.1);
|
||||
@ -37,6 +43,11 @@ header .logo .logo-image {
|
||||
background-color: #333333;
|
||||
}
|
||||
|
||||
.filtermenu-content .filter-item:hover,
|
||||
.filtermenu-content .filter-title:hover {
|
||||
background-color: #333333;
|
||||
}
|
||||
|
||||
.subscription-form h3 {
|
||||
color: #FFF;
|
||||
border-bottom: 1px solid #EEE;
|
||||
|
||||
@ -21,10 +21,34 @@ h2, h3 {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.split-header {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.split-header h2 {
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
.split-header > h2 .header-subtitle {
|
||||
font-size: 22px;
|
||||
font-weight: 400;
|
||||
color: #666666;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.contain.settings {
|
||||
padding: 20px 0px;
|
||||
}
|
||||
|
||||
.split-header > h2 .header-subtitle {
|
||||
margin-left: 0px;
|
||||
font-size: 18px;
|
||||
}
|
||||
}
|
||||
|
||||
body > header {
|
||||
@ -96,7 +120,7 @@ header .logo .logo-image {
|
||||
|
||||
.dropdown-content a {
|
||||
color: black;
|
||||
padding: 12px 16px;
|
||||
padding: 14px 18px;
|
||||
text-decoration: none;
|
||||
display: block;
|
||||
}
|
||||
@ -593,6 +617,10 @@ main > .contain {
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.payments-list .payments-payment > .payment-name {
|
||||
cursor: text;
|
||||
}
|
||||
|
||||
.payments-list .payments-payment .delete-payment-method {
|
||||
padding: 5px;
|
||||
font-weight: bold;
|
||||
@ -817,7 +845,7 @@ input[type="checkbox"] {
|
||||
}
|
||||
|
||||
.icon-search {
|
||||
width: 100px;
|
||||
width: 112px;
|
||||
height: 224px;
|
||||
top: 50px;
|
||||
right: 0px;
|
||||
@ -1047,7 +1075,7 @@ input[type="checkbox"] {
|
||||
|
||||
.sort-options > ul > li {
|
||||
list-style: none;
|
||||
padding: 10px 35px 10px 10px;
|
||||
padding: 14px 35px 14px 18px;
|
||||
border-bottom: 1px solid #DDD;
|
||||
cursor: pointer;
|
||||
}
|
||||
@ -1283,4 +1311,122 @@ input[type="checkbox"] {
|
||||
flex-basis: 100%;
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
/* Settings sort category */
|
||||
|
||||
.sortable-list {
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
-webkit-touch-callout: none;
|
||||
-webkit-user-select: none;
|
||||
-khtml-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.drag-icon {
|
||||
width: 28px;
|
||||
height: 50px;
|
||||
cursor: grab;
|
||||
background-image: url(../images/siteicons/draggable.png);
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
background-size: 14px auto;
|
||||
}
|
||||
|
||||
.sortable-list .sortable-ghost {
|
||||
border-radius: 16px;
|
||||
background-color: #c1d9f7;
|
||||
border: 1px solid #8FBFFA;
|
||||
}
|
||||
|
||||
/* Fitler dropdown */
|
||||
|
||||
.filtermenu {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.filtermenu-content {
|
||||
display: none;
|
||||
position: absolute;
|
||||
background-color: #f9f9f9;
|
||||
left: auto;
|
||||
right: 0;
|
||||
width: 220px;
|
||||
background-color: #fff;
|
||||
border: 1px solid #eee;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
|
||||
z-index: 3;
|
||||
overflow: hidden;
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.filtermenu-content.is-open {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.filtermenu-content .filter-title {
|
||||
padding: 14px 18px;
|
||||
text-decoration: none;
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
font-weight: 500;
|
||||
border-bottom: 1px solid #DDD;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.filtermenu-content .filtermenu-submenu:last-of-type .filter-title {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.filtermenu-content .filtermenu-submenu:last-of-type .filter-item:first-of-type {
|
||||
border-top: 1px solid #DDD;
|
||||
}
|
||||
|
||||
.filtermenu-content .filtermenu-submenu:last-of-type .filter-item:last-of-type {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.filtermenu-content .filter-item {
|
||||
padding: 14px 24px;
|
||||
text-decoration: none;
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
border-bottom: 1px solid #DDD;
|
||||
user-select: none;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.filtermenu-content .filter-item.selected {
|
||||
background-image: url(../images/siteicons/check.png);
|
||||
background-size: 16px;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center right 10px;
|
||||
}
|
||||
|
||||
.filtermenu-content .filter-title.filter-clear {
|
||||
color: #0056b3;
|
||||
font-weight: normal;
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.filtermenu-content .filter-title.filter-clear > i {
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.filtermenu-content .filter-item:hover,
|
||||
.filtermenu-content .filter-title:hover {
|
||||
background-color: #f1f1f1;
|
||||
}
|
||||
|
||||
.filtermenu-submenu-content {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.filtermenu-submenu-content.is-open {
|
||||
display: block;
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user