Petites améliorations de formulation et d'UI

This commit is contained in:
Colin Maudry
2026-07-01 10:17:25 +02:00
parent 502d3b390a
commit 63a7ff3d89
9 changed files with 87 additions and 33 deletions
+1
View File
@@ -22,3 +22,4 @@ users.sqlite
# LLM plugins
.superpowers/
.codegraph/
.claude
+3 -2
View File
@@ -312,8 +312,9 @@ def toggle_navbar_collapse(n, is_open):
)
def _auth_nav(_):
if current_user.is_authenticated:
email = current_user.email
display = email if len(email) <= 30 else email[:27] + "..."
# email = current_user.email
# display = email if len(email) <= 30 else email[:27] + "..."
display = "★★★"
return dbc.NavItem(dbc.NavLink(display, href="/compte/admin"))
return dbc.NavItem(dbc.NavLink("Connexion", href="/connexion"))
+5 -1
View File
@@ -132,10 +132,14 @@ def get_sources_tables(source_path) -> html.Div:
+ pl.lit('">')
+ pl.col("nom")
+ pl.lit("</a>")
).alias("nom")
).alias("nom"),
)
dff = dff.drop("url", "unique")
dff = dff.sort(by=["nb_marchés"], descending=True)
dff = dff.with_columns(
pl.col("nb_marchés").map_elements(format_number, return_dtype=pl.String),
pl.col("nb_acheteurs").map_elements(format_number, return_dtype=pl.String),
)
columns = {
"nom": "Nom de la source",
+8 -14
View File
@@ -4,20 +4,8 @@ from dash import Input, Output, State, callback, html
SECTIONS = [
{"key": "presentation", "label": "Présentation", "href": "/a-propos/presentation"},
{"key": "explorer", "label": "Explorer le projet", "href": "/a-propos/explorer"},
{"key": "sources", "label": "Sources de données", "href": "/a-propos/sources"},
{"key": "qualite", "label": "Qualité des données", "href": "/a-propos/qualite"},
{
"key": "donnees-brutes",
"label": "Données brutes",
"href": "/a-propos/donnees-brutes",
},
{"key": "contribuer", "label": "Contribuer", "href": "/a-propos/contribuer"},
{"key": "contact", "label": "Contact", "href": "/a-propos/contact"},
{
"key": "mentions-legales",
"label": "Mentions légales",
"href": "/a-propos/mentions-legales",
},
{"key": "donnees", "label": "Données", "href": "/a-propos/donnees"},
# {"key": "contribuer", "label": "Contribuer", "href": "/a-propos/contribuer"},
{
"key": "abonnement",
"label": "Abonnement",
@@ -28,6 +16,12 @@ SECTIONS = [
"label": "Roadmap",
"href": "/a-propos/roadmap",
},
{"key": "contact", "label": "Contact", "href": "/a-propos/contact"},
{
"key": "mentions-legales",
"label": "Mentions légales",
"href": "/a-propos/mentions-legales",
},
]
+22 -12
View File
@@ -11,6 +11,11 @@ register_page(
image_url=META_CONTENT["image_url"],
)
abonnement_features = dcc.Markdown("""
- sauvegarde de vues dans la page Tableau
- vote pour les fonctionnalités à développer en priorité (une fois la période d'essai terminée)
""")
def layout(**_):
contenu = html.Div(
@@ -18,42 +23,46 @@ def layout(**_):
html.H2("Abonnement"),
dcc.Markdown(
"""
L'accès aux fonctionnalités de base de colibre est gratuit et sans inscription.
Un abonnement payant donne accès à des fonctionnalités supplémentaires qui nécessitent la création d'un compte.
L'accès aux fonctionnalités de base de colibre est gratuit et sans inscription. Il est également possible de créer un compte gratuitement via le menu [Connexion](/connexion). Une fois le compte créé,
il est possible de souscrire à un abonnement mensuel qui donne accès à des fonctionnalités supplémentaires. Cet abonnement s'adresse tant aux professionnel·les qu'aux particuliers.
"""
),
html.H4("Fonctionnalités incluses"),
dcc.Markdown(
"""
Les fonctionnalités accessibles aux abonnés évoluent au fil du développement du service.
La liste à jour est visible depuis la [page d'abonnement](/compte/abonnement).
Les fonctionnalités accessibles aux abonné·es évoluent au fil du développement du service.
Fonctionnalités réservées aux abonné·es :
"""
),
abonnement_features,
dcc.Markdown("""
Les fonctionnalités en cours de développement et soumises au vote sont visibles dans la section [Roadmap](/a-propos/roadmap)."""),
html.H4("Tarifs"),
dcc.Markdown(
"""
Deux formules sont proposées :
- **Abonnement** — 20 € HT / mois (soit 24 € TTC)
- **Abonnement de soutien** — 50 € HT / mois (soit 60 € TTC) — mêmes fonctionnalités, contribution renforcée au projet
- **Abonnement de soutien** — 50 € HT / mois (soit 60 € TTC) — mêmes fonctionnalités, contribution renforcée au projet
La TVA applicable est de 20 %. Les prix TTC sont affichés lors de la souscription.
La TVA applicable en France est de 20 %.
"""
),
html.H4("Période d'essai"),
dcc.Markdown(
"""
Une période d'essai gratuite peut être proposée lors de la souscription.
Une période d'essai gratuite est proposée lors de la souscription.
Sa durée est indiquée avant validation. Aucun prélèvement n'est effectué pendant cette période.
À son terme, l'abonnement est activé et facturé automatiquement.
La période d'essai est accordée une seule fois par utilisateur.
La période d'essai est accordée une seule fois par compte.
"""
),
html.H4("Facturation et paiement"),
dcc.Markdown(
"""
L'abonnement est facturé mensuellement, à la date anniversaire de la souscription.
L'abonnement est facturé mensuellement, à la date anniversaire de la souscription, et donne lieu à l'émission d'une facture visible sur le compte de l'abonné·e.
Le paiement est traité par [Frisbii](https://www.frisbii.com), prestataire européen de paiement en ligne.
Les coordonnées bancaires sont conservées exclusivement par Frisbii et ne sont pas transmises à colibre.
"""
@@ -65,15 +74,16 @@ L'abonnement peut être résilié à tout moment depuis l'espace [Mon compte](/c
La résiliation prend effet à la fin de la période mensuelle en cours : l'accès aux fonctionnalités payantes est maintenu jusqu'à cette date, sans remboursement au prorata.
"""
),
html.H4("Données personnelles"),
html.H4("Données recueillies"),
dcc.Markdown(
"""
La gestion de l'abonnement implique le traitement de données personnelles, réparties entre colibre et Frisbii (prestataire de paiement).
La gestion de l'abonnement implique le traitement de données, réparties entre colibre et Frisbii (prestataire de paiement). Conformément au RGPD, colibre ne receuille que les données strictement nécessaire
au bon fonctionnement du site et de la facturation.
**Données stockées par colibre :**
- Adresse e-mail (identification du compte)
- Numéro SIRET (si renseigné, conservé pour pré-remplir les futures souscriptions)
- Numéro SIRET (optionnel, si renseigné, conservé pour pré-remplir les futures souscriptions)
**Données stockées par Frisbii :**
+5 -3
View File
@@ -4,6 +4,7 @@ from flask_login import current_user
from src.pages._compte_shell import account_guard, account_shell
from src.subscriptions import db, plans
from src.utils.frontend import format_date_french
register_page(
__name__,
@@ -129,7 +130,7 @@ def _explainer():
def _active_view(row):
meta = plans.plan_meta(row["plan"]) or {"label": row["plan"]}
end = row["current_period_end"]
end = format_date_french(row["current_period_end"])
blocks = [html.H3(meta["label"], className="mb-3")]
if row["status"] == "pending":
@@ -167,7 +168,7 @@ def _active_view(row):
dbc.Alert(f"Abonnement résilié, actif jusqu'au {end}.", color="warning")
)
else:
blocks.append(html.P(f"Prochain renouvellement : {end}"))
blocks.append(html.P(f"Prochaine facturation : {end}"))
if row["status"] in ("pending", "trial", "active"):
blocks.append(
@@ -182,7 +183,8 @@ def _active_view(row):
return html.Div(blocks)
def _resiliation_modal(end):
def _resiliation_modal(end_raw):
end = format_date_french(end_raw) if end_raw else None
if end:
body_text = (
f"Êtes-vous sûr de vouloir mettre fin à votre abonnement ? "
+5
View File
@@ -121,6 +121,11 @@ def roadmap_content(
body.append(dbc.ListGroup(_en_cours_items(issues["en_cours"]), className="mb-4"))
can_vote = editable and balance is not None and balance > 0
body.append(html.H3("Au vote"))
body.append(
html.P(
"Les abonné·es votent pour les fonctionnalités à développer en priorité."
)
)
body.append(
html.Div(
dbc.ListGroup(
+37
View File
@@ -1,6 +1,43 @@
from datetime import datetime
from src.utils.data import DATA_SCHEMA
def format_date_french(date_input) -> str:
"""Format a date as 'jour mois' (e.g., '1er janvier', '15 décembre')."""
if isinstance(date_input, str):
try:
date_obj = datetime.fromisoformat(date_input)
except (ValueError, TypeError):
return str(date_input)
elif isinstance(date_input, datetime):
date_obj = date_input
else:
return str(date_input)
day = date_obj.day
month_names = [
"janvier",
"février",
"mars",
"avril",
"mai",
"juin",
"juillet",
"août",
"septembre",
"octobre",
"novembre",
"décembre",
]
month = month_names[date_obj.month - 1]
if day == 1:
return f"1er {month}"
else:
return f"{day} {month}"
def get_button_properties(height):
if height > 65000:
download_disabled = True
Generated
+1 -1
View File
@@ -582,7 +582,7 @@ wheels = [
[[package]]
name = "colibre"
version = "2.8.1"
version = "3.0.0"
source = { virtual = "." }
dependencies = [
{ name = "authlib" },