consistently format prices everywhere
Django CI/CD / test (push) Successful in 1m7s Details
Django CI/CD / build-and-push (push) Successful in 2m10s Details

This commit is contained in:
Lukáš Kucharczyk 2024-11-15 18:03:08 +01:00
parent 8acc4f9c5b
commit fc0d8db8e8
Signed by: lukas
SSH Key Fingerprint: SHA256:vMuSwvwAvcT6htVAioMP7rzzwMQNi3roESyhv+nAxeg
6 changed files with 28 additions and 11 deletions

View File

@ -3,6 +3,7 @@ from string import ascii_lowercase
from typing import Any, Callable from typing import Any, Callable
from django.template import TemplateDoesNotExist from django.template import TemplateDoesNotExist
from django.template.defaultfilters import floatformat
from django.template.loader import render_to_string from django.template.loader import render_to_string
from django.urls import NoReverseMatch, reverse from django.urls import NoReverseMatch, reverse
from django.utils.safestring import SafeText, mark_safe from django.utils.safestring import SafeText, mark_safe
@ -50,6 +51,7 @@ def randomid(seed: str = "", length: int = 10) -> str:
def Popover( def Popover(
popover_content: str, popover_content: str,
wrapped_content: str = "", wrapped_content: str = "",
wrapped_classes: str = "",
children: list[HTMLTag] = [], children: list[HTMLTag] = [],
attributes: list[HTMLAttribute] = [], attributes: list[HTMLAttribute] = [],
) -> str: ) -> str:
@ -62,6 +64,7 @@ def Popover(
("id", id), ("id", id),
("wrapped_content", wrapped_content), ("wrapped_content", wrapped_content),
("popover_content", popover_content), ("popover_content", popover_content),
("wrapped_classes", wrapped_classes),
], ],
children=children, children=children,
template="cotton/popover.html", template="cotton/popover.html",
@ -193,3 +196,11 @@ def NameWithPlatformIcon(name: str, platform: str) -> SafeText:
) )
return mark_safe(content) return mark_safe(content)
def PurchasePrice(purchase) -> str:
return Popover(
popover_content=f"{floatformat(purchase.price)} {purchase.price_currency}",
wrapped_content=f"{floatformat(purchase.converted_price)} {purchase.converted_currency}",
wrapped_classes="underline decoration-dotted",
)

View File

@ -2192,6 +2192,10 @@ input:checked + .toggle-bg {
text-decoration-color: #64748b; text-decoration-color: #64748b;
} }
.decoration-dotted {
text-decoration-style: dotted;
}
.opacity-0 { .opacity-0 {
opacity: 0; opacity: 0;
} }

View File

@ -1,8 +1,10 @@
<span data-popover-target={{ id }} class="{{ class }}">{{ wrapped_content|default:slot }}</span> <span data-popover-target={{ id }} class="{{ wrapped_classes }}">{{ wrapped_content|default:slot }}</span>
<div data-popover <div data-popover
id="{{ id }}" id="{{ id }}"
role="tooltip" role="tooltip"
class="absolute z-10 invisible inline-block text-sm text-white transition-opacity duration-300 bg-white border border-purple-200 rounded-lg shadow-sm opacity-0 dark:text-white dark:border-purple-600 dark:bg-purple-800"> class="absolute z-10 invisible inline-block text-sm text-white transition-opacity duration-300 bg-white border border-purple-200 rounded-lg shadow-sm opacity-0 dark:text-white dark:border-purple-600 dark:bg-purple-800">
<div class="px-3 py-2">{{ popover_content }}</div> <div class="px-3 py-2">{{ popover_content }}</div>
<div data-popper-arrow></div> <div data-popper-arrow></div>
<!-- for Tailwind CSS to generate decoration-dotted CSS from Python component -->
<span class="hidden decoration-dotted"></span>
</div> </div>

View File

@ -142,7 +142,9 @@
</tr> </tr>
<tr> <tr>
<td class="px-2 sm:px-4 md:px-6 md:py-2">Spendings ({{ total_spent_currency }})</td> <td class="px-2 sm:px-4 md:px-6 md:py-2">Spendings ({{ total_spent_currency }})</td>
<td class="px-2 sm:px-4 md:px-6 md:py-2 font-mono">{{ total_spent }} ({{ spent_per_game }}/game)</td> <td class="px-2 sm:px-4 md:px-6 md:py-2 font-mono">
{{ total_spent | floatformat }} ({{ spent_per_game | floatformat }}/game)
</td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
@ -253,7 +255,7 @@
{% for purchase in purchased_unfinished %} {% for purchase in purchased_unfinished %}
<tr> <tr>
<td class="px-2 sm:px-4 md:px-6 md:py-2 font-mono">{% partial purchase-name %}</td> <td class="px-2 sm:px-4 md:px-6 md:py-2 font-mono">{% partial purchase-name %}</td>
<td class="px-2 sm:px-4 md:px-6 md:py-2 font-mono">{{ purchase.converted_price }}</td> <td class="px-2 sm:px-4 md:px-6 md:py-2 font-mono">{{ purchase.converted_price | floatformat }}</td>
<td class="px-2 sm:px-4 md:px-6 md:py-2 font-mono">{{ purchase.date_purchased | date:"d/m/Y" }}</td> <td class="px-2 sm:px-4 md:px-6 md:py-2 font-mono">{{ purchase.date_purchased | date:"d/m/Y" }}</td>
</tr> </tr>
{% endfor %} {% endfor %}
@ -274,7 +276,7 @@
{% for purchase in all_purchased_this_year %} {% for purchase in all_purchased_this_year %}
<tr> <tr>
<td class="px-2 sm:px-4 md:px-6 md:py-2 font-mono">{% partial purchase-name %}</td> <td class="px-2 sm:px-4 md:px-6 md:py-2 font-mono">{% partial purchase-name %}</td>
<td class="px-2 sm:px-4 md:px-6 md:py-2 font-mono">{{ purchase.converted_price }}</td> <td class="px-2 sm:px-4 md:px-6 md:py-2 font-mono">{{ purchase.converted_price | floatformat }}</td>
<td class="px-2 sm:px-4 md:px-6 md:py-2 font-mono">{{ purchase.date_purchased | date:"d/m/Y" }}</td> <td class="px-2 sm:px-4 md:px-6 md:py-2 font-mono">{{ purchase.date_purchased | date:"d/m/Y" }}</td>
</tr> </tr>
{% endfor %} {% endfor %}

View File

@ -16,6 +16,7 @@ from common.components import (
NameWithPlatformIcon, NameWithPlatformIcon,
Popover, Popover,
PopoverTruncated, PopoverTruncated,
PurchasePrice,
) )
from common.time import ( from common.time import (
dateformat, dateformat,
@ -25,7 +26,7 @@ from common.time import (
local_strftime, local_strftime,
timeformat, timeformat,
) )
from common.utils import format_float_or_int, safe_division, truncate from common.utils import safe_division, truncate
from games.forms import GameForm from games.forms import GameForm
from games.models import Edition, Game, Purchase, Session from games.models import Edition, Game, Purchase, Session
from games.views.general import use_custom_redirect from games.views.general import use_custom_redirect
@ -247,7 +248,7 @@ def view_game(request: HttpRequest, game_id: int) -> HttpResponse:
), ),
purchase.get_type_display(), purchase.get_type_display(),
purchase.date_purchased.strftime(dateformat), purchase.date_purchased.strftime(dateformat),
f"{format_float_or_int(purchase.price)} {purchase.price_currency}", PurchasePrice(purchase),
render_to_string( render_to_string(
"cotton/button_group.html", "cotton/button_group.html",
{ {

View File

@ -13,9 +13,8 @@ from django.template.loader import render_to_string
from django.urls import reverse from django.urls import reverse
from django.utils import timezone from django.utils import timezone
from common.components import A, Button, Icon, LinkedNameWithPlatformIcon from common.components import A, Button, Icon, LinkedNameWithPlatformIcon, PurchasePrice
from common.time import dateformat from common.time import dateformat
from common.utils import format_float_or_int
from games.forms import PurchaseForm from games.forms import PurchaseForm
from games.models import Edition, Purchase from games.models import Edition, Purchase
from games.views.general import use_custom_redirect from games.views.general import use_custom_redirect
@ -49,7 +48,6 @@ def list_purchases(request: HttpRequest) -> HttpResponse:
"Name", "Name",
"Type", "Type",
"Price", "Price",
"Currency",
"Infinite", "Infinite",
"Purchased", "Purchased",
"Refunded", "Refunded",
@ -66,8 +64,7 @@ def list_purchases(request: HttpRequest) -> HttpResponse:
platform=purchase.platform, platform=purchase.platform,
), ),
purchase.get_type_display(), purchase.get_type_display(),
format_float_or_int(purchase.price), PurchasePrice(purchase),
purchase.price_currency,
purchase.infinite, purchase.infinite,
purchase.date_purchased.strftime(dateformat), purchase.date_purchased.strftime(dateformat),
( (