Petites améliorations de formulation et d'UI
This commit is contained in:
@@ -22,3 +22,4 @@ users.sqlite
|
|||||||
# LLM plugins
|
# LLM plugins
|
||||||
.superpowers/
|
.superpowers/
|
||||||
.codegraph/
|
.codegraph/
|
||||||
|
.claude
|
||||||
|
|||||||
+3
-2
@@ -312,8 +312,9 @@ def toggle_navbar_collapse(n, is_open):
|
|||||||
)
|
)
|
||||||
def _auth_nav(_):
|
def _auth_nav(_):
|
||||||
if current_user.is_authenticated:
|
if current_user.is_authenticated:
|
||||||
email = current_user.email
|
# email = current_user.email
|
||||||
display = email if len(email) <= 30 else email[:27] + "..."
|
# display = email if len(email) <= 30 else email[:27] + "..."
|
||||||
|
display = "★★★"
|
||||||
return dbc.NavItem(dbc.NavLink(display, href="/compte/admin"))
|
return dbc.NavItem(dbc.NavLink(display, href="/compte/admin"))
|
||||||
return dbc.NavItem(dbc.NavLink("Connexion", href="/connexion"))
|
return dbc.NavItem(dbc.NavLink("Connexion", href="/connexion"))
|
||||||
|
|
||||||
|
|||||||
+5
-1
@@ -132,10 +132,14 @@ def get_sources_tables(source_path) -> html.Div:
|
|||||||
+ pl.lit('">')
|
+ pl.lit('">')
|
||||||
+ pl.col("nom")
|
+ pl.col("nom")
|
||||||
+ pl.lit("</a>")
|
+ pl.lit("</a>")
|
||||||
).alias("nom")
|
).alias("nom"),
|
||||||
)
|
)
|
||||||
dff = dff.drop("url", "unique")
|
dff = dff.drop("url", "unique")
|
||||||
dff = dff.sort(by=["nb_marchés"], descending=True)
|
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 = {
|
columns = {
|
||||||
"nom": "Nom de la source",
|
"nom": "Nom de la source",
|
||||||
|
|||||||
@@ -4,20 +4,8 @@ from dash import Input, Output, State, callback, html
|
|||||||
SECTIONS = [
|
SECTIONS = [
|
||||||
{"key": "presentation", "label": "Présentation", "href": "/a-propos/presentation"},
|
{"key": "presentation", "label": "Présentation", "href": "/a-propos/presentation"},
|
||||||
{"key": "explorer", "label": "Explorer le projet", "href": "/a-propos/explorer"},
|
{"key": "explorer", "label": "Explorer le projet", "href": "/a-propos/explorer"},
|
||||||
{"key": "sources", "label": "Sources de données", "href": "/a-propos/sources"},
|
{"key": "donnees", "label": "Données", "href": "/a-propos/donnees"},
|
||||||
{"key": "qualite", "label": "Qualité des données", "href": "/a-propos/qualite"},
|
# {"key": "contribuer", "label": "Contribuer", "href": "/a-propos/contribuer"},
|
||||||
{
|
|
||||||
"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": "abonnement",
|
"key": "abonnement",
|
||||||
"label": "Abonnement",
|
"label": "Abonnement",
|
||||||
@@ -28,6 +16,12 @@ SECTIONS = [
|
|||||||
"label": "Roadmap",
|
"label": "Roadmap",
|
||||||
"href": "/a-propos/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",
|
||||||
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,11 @@ register_page(
|
|||||||
image_url=META_CONTENT["image_url"],
|
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(**_):
|
def layout(**_):
|
||||||
contenu = html.Div(
|
contenu = html.Div(
|
||||||
@@ -18,42 +23,46 @@ def layout(**_):
|
|||||||
html.H2("Abonnement"),
|
html.H2("Abonnement"),
|
||||||
dcc.Markdown(
|
dcc.Markdown(
|
||||||
"""
|
"""
|
||||||
L'accès aux fonctionnalités de base de colibre est gratuit et sans inscription.
|
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éé,
|
||||||
Un abonnement payant donne accès à des fonctionnalités supplémentaires qui nécessitent la création d'un compte.
|
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"),
|
html.H4("Fonctionnalités incluses"),
|
||||||
dcc.Markdown(
|
dcc.Markdown(
|
||||||
"""
|
"""
|
||||||
Les fonctionnalités accessibles aux abonnés évoluent au fil du développement du service.
|
Les fonctionnalités accessibles aux abonné·es évoluent au fil du développement du service.
|
||||||
La liste à jour est visible depuis la [page d'abonnement](/compte/abonnement).
|
|
||||||
|
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"),
|
html.H4("Tarifs"),
|
||||||
dcc.Markdown(
|
dcc.Markdown(
|
||||||
"""
|
"""
|
||||||
Deux formules sont proposées :
|
Deux formules sont proposées :
|
||||||
|
|
||||||
- **Abonnement** — 20 € HT / mois (soit 24 € TTC)
|
- **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"),
|
html.H4("Période d'essai"),
|
||||||
dcc.Markdown(
|
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.
|
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.
|
À 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"),
|
html.H4("Facturation et paiement"),
|
||||||
dcc.Markdown(
|
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.
|
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.
|
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.
|
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(
|
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 :**
|
**Données stockées par colibre :**
|
||||||
|
|
||||||
- Adresse e-mail (identification du compte)
|
- 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 :**
|
**Données stockées par Frisbii :**
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ from flask_login import current_user
|
|||||||
|
|
||||||
from src.pages._compte_shell import account_guard, account_shell
|
from src.pages._compte_shell import account_guard, account_shell
|
||||||
from src.subscriptions import db, plans
|
from src.subscriptions import db, plans
|
||||||
|
from src.utils.frontend import format_date_french
|
||||||
|
|
||||||
register_page(
|
register_page(
|
||||||
__name__,
|
__name__,
|
||||||
@@ -129,7 +130,7 @@ def _explainer():
|
|||||||
|
|
||||||
def _active_view(row):
|
def _active_view(row):
|
||||||
meta = plans.plan_meta(row["plan"]) or {"label": row["plan"]}
|
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")]
|
blocks = [html.H3(meta["label"], className="mb-3")]
|
||||||
|
|
||||||
if row["status"] == "pending":
|
if row["status"] == "pending":
|
||||||
@@ -167,7 +168,7 @@ def _active_view(row):
|
|||||||
dbc.Alert(f"Abonnement résilié, actif jusqu'au {end}.", color="warning")
|
dbc.Alert(f"Abonnement résilié, actif jusqu'au {end}.", color="warning")
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
blocks.append(html.P(f"Prochain renouvellement : {end}"))
|
blocks.append(html.P(f"Prochaine facturation : {end}"))
|
||||||
|
|
||||||
if row["status"] in ("pending", "trial", "active"):
|
if row["status"] in ("pending", "trial", "active"):
|
||||||
blocks.append(
|
blocks.append(
|
||||||
@@ -182,7 +183,8 @@ def _active_view(row):
|
|||||||
return html.Div(blocks)
|
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:
|
if end:
|
||||||
body_text = (
|
body_text = (
|
||||||
f"Êtes-vous sûr de vouloir mettre fin à votre abonnement ? "
|
f"Êtes-vous sûr de vouloir mettre fin à votre abonnement ? "
|
||||||
|
|||||||
@@ -121,6 +121,11 @@ def roadmap_content(
|
|||||||
body.append(dbc.ListGroup(_en_cours_items(issues["en_cours"]), className="mb-4"))
|
body.append(dbc.ListGroup(_en_cours_items(issues["en_cours"]), className="mb-4"))
|
||||||
can_vote = editable and balance is not None and balance > 0
|
can_vote = editable and balance is not None and balance > 0
|
||||||
body.append(html.H3("Au vote"))
|
body.append(html.H3("Au vote"))
|
||||||
|
body.append(
|
||||||
|
html.P(
|
||||||
|
"Les abonné·es votent pour les fonctionnalités à développer en priorité."
|
||||||
|
)
|
||||||
|
)
|
||||||
body.append(
|
body.append(
|
||||||
html.Div(
|
html.Div(
|
||||||
dbc.ListGroup(
|
dbc.ListGroup(
|
||||||
|
|||||||
@@ -1,6 +1,43 @@
|
|||||||
|
from datetime import datetime
|
||||||
|
|
||||||
from src.utils.data import DATA_SCHEMA
|
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):
|
def get_button_properties(height):
|
||||||
if height > 65000:
|
if height > 65000:
|
||||||
download_disabled = True
|
download_disabled = True
|
||||||
|
|||||||
Reference in New Issue
Block a user