Merge pull request #153

feat(monthly): add quick-search field
This commit is contained in:
Herculino Trotta
2025-02-09 17:14:44 -03:00
committed by GitHub
3 changed files with 184 additions and 162 deletions

View File

@@ -1,172 +1,174 @@
{% load markdown %} {% load markdown %}
{% load i18n %} {% load i18n %}
<div class="transaction d-flex my-1 {% if transaction.type == "EX" %}expense{% else %}income{% endif %}"> <div class="transaction">
{% if not disable_selection %} <div class="d-flex my-1 {% if transaction.type == "EX" %}expense{% else %}income{% endif %}">
<label class="px-3 d-flex align-items-center justify-content-center"> {% if not disable_selection %}
<input class="form-check-input" type="checkbox" name="transactions" value="{{ transaction.id }}" <label class="px-3 d-flex align-items-center justify-content-center">
id="check-{{ transaction.id }}" aria-label="{% translate 'Select' %}" hx-preserve> <input class="form-check-input" type="checkbox" name="transactions" value="{{ transaction.id }}"
</label> id="check-{{ transaction.id }}" aria-label="{% translate 'Select' %}" hx-preserve>
{% endif %} </label>
<div class="tw-border-s-6 tw-border-e-0 tw-border-t-0 tw-border-b-0 border-bottom {% endif %}
<div class="tw-border-s-6 tw-border-e-0 tw-border-t-0 tw-border-b-0 border-bottom
hover:tw-bg-zinc-900 p-2 {% if transaction.account.is_asset %}tw-border-dashed{% else %}tw-border-solid{% endif %} hover:tw-bg-zinc-900 p-2 {% if transaction.account.is_asset %}tw-border-dashed{% else %}tw-border-solid{% endif %}
{% if transaction.type == "EX" %}tw-border-red-500{% else %}tw-border-green-500{% endif %} tw-relative {% if transaction.type == "EX" %}tw-border-red-500{% else %}tw-border-green-500{% endif %} tw-relative
w-100 transaction-item" w-100 transaction-item"
_="on mouseover remove .tw-invisible from the first .transaction-actions in me end _="on mouseover remove .tw-invisible from the first .transaction-actions in me end
on mouseout add .tw-invisible to the first .transaction-actions in me end"> on mouseout add .tw-invisible to the first .transaction-actions in me end">
<div class="row font-monospace tw-text-sm align-items-center"> <div class="row font-monospace tw-text-sm align-items-center">
<div class="col-lg-1 col-12 d-flex align-items-center tw-text-2xl lg:tw-text-xl text-lg-center text-center"> <div class="col-lg-1 col-12 d-flex align-items-center tw-text-2xl lg:tw-text-xl text-lg-center text-center">
{% if not transaction.deleted %} {% if not transaction.deleted %}
<a class="text-decoration-none my-lg-3 mx-lg-3 mx-2 my-2 tw-text-gray-500" <a class="text-decoration-none my-lg-3 mx-lg-3 mx-2 my-2 tw-text-gray-500"
title="{% if transaction.is_paid %}{% trans 'Paid' %}{% else %}{% trans 'Projected' %}{% endif %}" title="{% if transaction.is_paid %}{% trans 'Paid' %}{% else %}{% trans 'Projected' %}{% endif %}"
role="button" role="button"
hx-get="{% url 'transaction_pay' transaction_id=transaction.id %}" hx-get="{% url 'transaction_pay' transaction_id=transaction.id %}"
hx-target="closest .transaction" hx-target="closest .transaction"
hx-swap="outerHTML"> hx-swap="outerHTML">
{% if transaction.is_paid %}<i class="fa-regular fa-circle-check"></i>{% else %}<i {% if transaction.is_paid %}<i class="fa-regular fa-circle-check"></i>{% else %}<i
class="fa-regular fa-circle"></i>{% endif %} class="fa-regular fa-circle"></i>{% endif %}
</a> </a>
{% else %} {% else %}
<div class="text-decoration-none my-lg-3 mx-lg-3 mx-2 my-2 tw-text-gray-500" <div class="text-decoration-none my-lg-3 mx-lg-3 mx-2 my-2 tw-text-gray-500"
title="{% if transaction.is_paid %}{% trans 'Paid' %}{% else %}{% trans 'Projected' %}{% endif %}"> title="{% if transaction.is_paid %}{% trans 'Paid' %}{% else %}{% trans 'Projected' %}{% endif %}">
{% if transaction.is_paid %}<i class="fa-regular fa-circle-check"></i>{% else %}<i {% if transaction.is_paid %}<i class="fa-regular fa-circle-check"></i>{% else %}<i
class="fa-regular fa-circle"></i>{% endif %} class="fa-regular fa-circle"></i>{% endif %}
</div>
{% endif %}
</div>
<div class="col-lg-8 col-12">
{# Date#}
<div class="row mb-2 mb-lg-1 tw-text-gray-400">
<div class="col-auto pe-1"><i class="fa-solid fa-calendar fa-fw me-1 fa-xs"></i></div>
<div
class="col ps-0">{{ transaction.date|date:"SHORT_DATE_FORMAT" }} • {{ transaction.reference_date|date:"b/Y" }}</div>
</div> </div>
{% endif %} {# Description#}
</div> <div class="mb-2 mb-lg-1 text-white tw-text-base">
<div class="col-lg-8 col-12"> {% spaceless %}
{# Date#} <span>{{ transaction.description }}</span>
<div class="row mb-2 mb-lg-1 tw-text-gray-400"> {% if transaction.installment_plan and transaction.installment_id %}
<div class="col-auto pe-1"><i class="fa-solid fa-calendar fa-fw me-1 fa-xs"></i></div> <span
<div class="badge text-bg-secondary ms-2">{{ transaction.installment_id }}/{{ transaction.installment_plan.installment_total_number }}</span>
class="col ps-0">{{ transaction.date|date:"SHORT_DATE_FORMAT" }} • {{ transaction.reference_date|date:"b/Y" }}</div> {% endif %}
</div> {% if transaction.recurring_transaction %}
{# Description#} <span class="text-primary tw-text-xs ms-2"><i class="fa-solid fa-arrows-rotate fa-fw"></i></span>
<div class="mb-2 mb-lg-1 text-white tw-text-base"> {% endif %}
{% spaceless %} {% endspaceless %}
<span>{{ transaction.description }}</span> </div>
{% if transaction.installment_plan and transaction.installment_id %} <div class="tw-text-gray-400 tw-text-sm">
<span {# Entities #}
class="badge text-bg-secondary ms-2">{{ transaction.installment_id }}/{{ transaction.installment_plan.installment_total_number }}</span> {% with transaction.entities.all as entities %}
{% endif %} {% if entities %}
{% if transaction.recurring_transaction %} <div class="row mb-2 mb-lg-1 tw-text-gray-400">
<span class="text-primary tw-text-xs ms-2"><i class="fa-solid fa-arrows-rotate fa-fw"></i></span> <div class="col-auto pe-1"><i class="fa-solid fa-user-group fa-fw me-1 fa-xs"></i></div>
{% endif %} <div class="col ps-0">{{ entities|join:", " }}</div>
{% endspaceless %} </div>
</div> {% endif %}
<div class="tw-text-gray-400 tw-text-sm"> {% endwith %}
{# Entities #} {# Notes#}
{% with transaction.entities.all as entities %} {% if transaction.notes %}
{% if entities %}
<div class="row mb-2 mb-lg-1 tw-text-gray-400"> <div class="row mb-2 mb-lg-1 tw-text-gray-400">
<div class="col-auto pe-1"><i class="fa-solid fa-user-group fa-fw me-1 fa-xs"></i></div> <div class="col-auto pe-1"><i class="fa-solid fa-align-left fa-fw me-1 fa-xs"></i></div>
<div class="col ps-0">{{ entities|join:", " }}</div> <div class="col ps-0">{{ transaction.notes | limited_markdown | linebreaksbr }}</div>
</div> </div>
{% endif %} {% endif %}
{% endwith %} {# Category#}
{# Notes#} {% if transaction.category %}
{% if transaction.notes %} <div class="row mb-2 mb-lg-1 tw-text-gray-400">
<div class="row mb-2 mb-lg-1 tw-text-gray-400"> <div class="col-auto pe-1"><i class="fa-solid fa-icons fa-fw me-1 fa-xs"></i></div>
<div class="col-auto pe-1"><i class="fa-solid fa-align-left fa-fw me-1 fa-xs"></i></div> <div class="col ps-0">{{ transaction.category.name }}</div>
<div class="col ps-0">{{ transaction.notes | limited_markdown | linebreaksbr }}</div> </div>
</div> {% endif %}
{% endif %} {# Tags#}
{# Category#} {% with transaction.tags.all as tags %}
{% if transaction.category %} {% if tags %}
<div class="row mb-2 mb-lg-1 tw-text-gray-400"> <div class="row mb-2 mb-lg-1 tw-text-gray-400">
<div class="col-auto pe-1"><i class="fa-solid fa-icons fa-fw me-1 fa-xs"></i></div> <div class="col-auto pe-1"><i class="fa-solid fa-hashtag fa-fw me-1 fa-xs"></i></div>
<div class="col ps-0">{{ transaction.category.name }}</div> <div class="col ps-0">{{ tags|join:", " }}</div>
</div> </div>
{% endif %} {% endif %}
{# Tags#} {% endwith %}
{% with transaction.tags.all as tags %} </div>
{% if tags %} </div>
<div class="row mb-2 mb-lg-1 tw-text-gray-400"> <div class="col-lg-3 col-12 text-lg-end align-self-end">
<div class="col-auto pe-1"><i class="fa-solid fa-hashtag fa-fw me-1 fa-xs"></i></div> <div class="main-amount mb-2 mb-lg-0">
<div class="col ps-0">{{ tags|join:", " }}</div> <c-amount.display
:amount="transaction.amount"
:prefix="transaction.account.currency.prefix"
:suffix="transaction.account.currency.suffix"
:decimal_places="transaction.account.currency.decimal_places"
color="{% if transaction.type == "EX" %}red{% else %}green{% endif %}"></c-amount.display>
</div>
{# Exchange Rate#}
{% with exchanged=transaction.exchanged_amount %}
{% if exchanged %}
<div class="exchanged-amount mb-2 mb-lg-0">
<c-amount.display
:amount="exchanged.amount"
:prefix="exchanged.prefix"
:suffix="exchanged.suffix"
:decimal_places="exchanged.decimal_places"
color="grey"></c-amount.display>
</div> </div>
{% endif %} {% endif %}
{% endwith %} {% endwith %}
<div>
{% if transaction.account.group %}{{ transaction.account.group.name }} • {% endif %}{{ transaction.account.name }}
</div>
</div> </div>
</div>
<div class="col-lg-3 col-12 text-lg-end align-self-end">
<div class="main-amount mb-2 mb-lg-0">
<c-amount.display
:amount="transaction.amount"
:prefix="transaction.account.currency.prefix"
:suffix="transaction.account.currency.suffix"
:decimal_places="transaction.account.currency.decimal_places"
color="{% if transaction.type == "EX" %}red{% else %}green{% endif %}"></c-amount.display>
</div>
{# Exchange Rate#}
{% with exchanged=transaction.exchanged_amount %}
{% if exchanged %}
<div class="exchanged-amount mb-2 mb-lg-0">
<c-amount.display
:amount="exchanged.amount"
:prefix="exchanged.prefix"
:suffix="exchanged.suffix"
:decimal_places="exchanged.decimal_places"
color="grey"></c-amount.display>
</div>
{% endif %}
{% endwith %}
<div> <div>
{% if transaction.account.group %}{{ transaction.account.group.name }} • {% endif %}{{ transaction.account.name }} {# Item actions#}
</div> <div
</div> class="transaction-actions !tw-absolute tw-left-1/2 tw-top-0 tw--translate-x-1/2 tw--translate-y-1/2 tw-invisible d-flex flex-row card">
<div> <div class="card-body p-1 shadow-lg">
{# Item actions#} {% if not transaction.deleted %}
<div <a class="btn btn-secondary btn-sm transaction-action"
class="transaction-actions !tw-absolute tw-left-1/2 tw-top-0 tw--translate-x-1/2 tw--translate-y-1/2 tw-invisible d-flex flex-row card"> role="button"
<div class="card-body p-1 shadow-lg"> data-bs-toggle="tooltip"
{% if not transaction.deleted %} data-bs-title="{% translate "Edit" %}"
<a class="btn btn-secondary btn-sm transaction-action" hx-get="{% url 'transaction_edit' transaction_id=transaction.id %}"
role="button" hx-target="#generic-offcanvas" hx-swap="innerHTML">
data-bs-toggle="tooltip" <i class="fa-solid fa-pencil fa-fw"></i></a>
data-bs-title="{% translate "Edit" %}" <a class="btn btn-secondary btn-sm transaction-action"
hx-get="{% url 'transaction_edit' transaction_id=transaction.id %}" role="button"
hx-target="#generic-offcanvas" hx-swap="innerHTML"> data-bs-toggle="tooltip"
<i class="fa-solid fa-pencil fa-fw"></i></a> data-bs-title="{% translate "Duplicate" %}"
<a class="btn btn-secondary btn-sm transaction-action" hx-get="{% url 'transaction_clone' transaction_id=transaction.id %}"
role="button" _="on click if event.ctrlKey set @hx-get to `{% url 'transaction_clone' transaction_id=transaction.id %}?edit=true` then call htmx.process(me) end then trigger ready"
data-bs-toggle="tooltip" hx-trigger="ready">
data-bs-title="{% translate "Duplicate" %}" <i class="fa-solid fa-clone fa-fw"></i></a>
hx-get="{% url 'transaction_clone' transaction_id=transaction.id %}" <a class="btn btn-secondary btn-sm transaction-action"
_="on click if event.ctrlKey set @hx-get to `{% url 'transaction_clone' transaction_id=transaction.id %}?edit=true` then call htmx.process(me) end then trigger ready" role="button"
hx-trigger="ready"> data-bs-toggle="tooltip"
<i class="fa-solid fa-clone fa-fw"></i></a> data-bs-title="{% translate "Delete" %}"
<a class="btn btn-secondary btn-sm transaction-action" hx-delete="{% url 'transaction_delete' transaction_id=transaction.id %}"
role="button" hx-trigger='confirmed'
data-bs-toggle="tooltip" data-bypass-on-ctrl="true"
data-bs-title="{% translate "Delete" %}" data-title="{% translate "Are you sure?" %}"
hx-delete="{% url 'transaction_delete' transaction_id=transaction.id %}" data-text="{% translate "You won't be able to revert this!" %}"
hx-trigger='confirmed' data-confirm-text="{% translate "Yes, delete it!" %}"
data-bypass-on-ctrl="true" _="install prompt_swal"><i class="fa-solid fa-trash fa-fw text-danger"></i>
data-title="{% translate "Are you sure?" %}" </a>
data-text="{% translate "You won't be able to revert this!" %}" {% else %}
data-confirm-text="{% translate "Yes, delete it!" %}" <a class="btn btn-secondary btn-sm transaction-action"
_="install prompt_swal"><i class="fa-solid fa-trash fa-fw text-danger"></i> role="button"
</a> data-bs-toggle="tooltip"
{% else %} data-bs-title="{% translate "Restore" %}"
<a class="btn btn-secondary btn-sm transaction-action" hx-get="{% url 'transaction_undelete' transaction_id=transaction.id %}"><i
role="button" class="fa-solid fa-trash-arrow-up"></i></a>
data-bs-toggle="tooltip" <a class="btn btn-secondary btn-sm transaction-action"
data-bs-title="{% translate "Restore" %}" role="button"
hx-get="{% url 'transaction_undelete' transaction_id=transaction.id %}"><i data-bs-toggle="tooltip"
class="fa-solid fa-trash-arrow-up"></i></a> data-bs-title="{% translate "Delete" %}"
<a class="btn btn-secondary btn-sm transaction-action" hx-delete="{% url 'transaction_delete' transaction_id=transaction.id %}"
role="button" hx-trigger='confirmed'
data-bs-toggle="tooltip" data-bypass-on-ctrl="true"
data-bs-title="{% translate "Delete" %}" data-title="{% translate "Are you sure?" %}"
hx-delete="{% url 'transaction_delete' transaction_id=transaction.id %}" data-text="{% translate "You won't be able to revert this!" %}"
hx-trigger='confirmed' data-confirm-text="{% translate "Yes, delete it!" %}"
data-bypass-on-ctrl="true" _="install prompt_swal"><i class="fa-solid fa-trash fa-fw text-danger"></i>
data-title="{% translate "Are you sure?" %}" </a>
data-text="{% translate "You won't be able to revert this!" %}" {% endif %}
data-confirm-text="{% translate "Yes, delete it!" %}" </div>
_="install prompt_swal"><i class="fa-solid fa-trash fa-fw text-danger"></i>
</a>
{% endif %}
</div> </div>
</div> </div>
</div> </div>

View File

@@ -4,9 +4,9 @@
<div id="transactions-list"> <div id="transactions-list">
{% for x in transactions_by_date %} {% for x in transactions_by_date %}
<div id="{{ x.grouper|slugify }}" <div id="{{ x.grouper|slugify }}" class="transactions-divider"
_="on htmx:afterSettle from #transactions if sessionStorage.getItem(my id) is null then sessionStorage.setItem(my id, 'true')"> _="on htmx:afterSwap from #transactions if sessionStorage.getItem(my id) is null then sessionStorage.setItem(my id, 'true')">
<div class="mt-3 mb-1 w-100 tw-text-base border-bottom bg-body"> <div class="mt-3 mb-1 w-100 tw-text-base border-bottom bg-body transactions-divider-title">
<a class="text-decoration-none d-inline-block w-100" <a class="text-decoration-none d-inline-block w-100"
role="button" role="button"
data-bs-toggle="collapse" data-bs-toggle="collapse"
@@ -17,15 +17,21 @@
{{ x.grouper }} {{ x.grouper }}
</a> </a>
</div> </div>
<div class="collapse" id="c-{{ x.grouper|slugify }}-collapse" <div class="collapse transactions-divider-collapse" id="c-{{ x.grouper|slugify }}-collapse"
_="on shown.bs.collapse sessionStorage.setItem(the closest parent @id, 'true') _="on shown.bs.collapse sessionStorage.setItem(the closest parent @id, 'true')
on hidden.bs.collapse sessionStorage.setItem(the closest parent @id, 'false') on hidden.bs.collapse sessionStorage.setItem(the closest parent @id, 'false')
on htmx:afterSettle from #transactions on htmx:afterSettle from #transactions or toggle
set state to sessionStorage.getItem(the closest parent @id) set state to sessionStorage.getItem(the closest parent @id)
if state is 'true' or state is null if state is 'true' or state is null
add .show to me add .show to me
set @aria-expanded of #c-{{ x.grouper|slugify }}-collapsible to true set @aria-expanded of #c-{{ x.grouper|slugify }}-collapsible to true
end"> else
remove .show from me
set @aria-expanded of #c-{{ x.grouper|slugify }}-collapsible to false
end
on show
add .show to me
set @aria-expanded of #c-{{ x.grouper|slugify }}-collapsible to true">
<div class="d-flex flex-column"> <div class="d-flex flex-column">
{% for transaction in x.list %} {% for transaction in x.list %}
<c-transaction.item <c-transaction.item

View File

@@ -172,6 +172,20 @@
_="on click call #filter.reset() then trigger change on #filter">{% translate 'Clear' %}</button> _="on click call #filter.reset() then trigger change on #filter">{% translate 'Clear' %}</button>
</div> </div>
</div> </div>
<div id="search" class="my-3">
<label class="w-100">
<input type="search" class="form-control" placeholder="Buscar" hx-preserve id="quick-search"
_="on input or search or htmx:afterSwap from window
if my value is empty
trigger toggle on <.transactions-divider-collapse/>
else
trigger show on <.transactions-divider-collapse/>
end
show <.transactions-divider-title/> when my value is empty
show <.transaction/> in <#transactions-list/>
when its textContent.toLowerCase() contains my value.toLowerCase()">
</label>
</div>
{# Transactions list#} {# Transactions list#}
<div id="transactions" <div id="transactions"
class="show-loading" class="show-loading"