From c9a3e959165431fac97785b6b785964fd26945a0 Mon Sep 17 00:00:00 2001 From: nfebe Date: Tue, 18 Aug 2026 21:53:05 +0100 Subject: [PATCH 1/3] refactor: Share table and pagination components Main and administrative tables now share consistent presentation and paging behavior. --- components/ContentTable.vue | 418 +++++------------------------------- components/TDataTable.vue | 150 +++++++++++++ components/TPagination.vue | 122 +++++++++++ 3 files changed, 328 insertions(+), 362 deletions(-) create mode 100644 components/TDataTable.vue create mode 100644 components/TPagination.vue diff --git a/components/ContentTable.vue b/components/ContentTable.vue index a8e8c7a..6aefd93 100644 --- a/components/ContentTable.vue +++ b/components/ContentTable.vue @@ -18,108 +18,46 @@
-
- - - - - - - - - + + + + +
{{ t('Show') }} {{ t('per page') }}
- +
@@ -137,15 +75,12 @@ diff --git a/components/TPagination.vue b/components/TPagination.vue new file mode 100644 index 0000000..c8c3282 --- /dev/null +++ b/components/TPagination.vue @@ -0,0 +1,122 @@ + + + + + From 97c7c3a3fb2e535a92423f54d5ec215bdb358693 Mon Sep 17 00:00:00 2001 From: nfebe Date: Tue, 18 Aug 2026 21:53:14 +0100 Subject: [PATCH 2/3] feat(admin): Complete user insights Administrators can inspect registration trends, user activity, and token consumption. Outreach history is available from the same paginated view. --- components/admin/OutreachComposer.vue | 2 +- components/admin/UserDetail.vue | 5 + i18n/locales/de.json | 5 + i18n/locales/en.json | 5 + i18n/locales/es.json | 5 + i18n/locales/fr.json | 5 + i18n/locales/it.json | 5 + i18n/locales/pt.json | 5 + pages/admin/index.vue | 341 ++++++++++++++++---------- services/api/adminApi.ts | 31 ++- tests/services/adminApi.test.ts | 39 +++ 11 files changed, 318 insertions(+), 130 deletions(-) create mode 100644 tests/services/adminApi.test.ts diff --git a/components/admin/OutreachComposer.vue b/components/admin/OutreachComposer.vue index 78e36d3..96dd2b3 100644 --- a/components/admin/OutreachComposer.vue +++ b/components/admin/OutreachComposer.vue @@ -214,7 +214,7 @@ const filteredUsers = computed(() => { onMounted(async () => { try { - users.value = await adminApi.users(); + users.value = (await adminApi.users({ perPage: 100 })).data; } catch { users.value = []; } diff --git a/components/admin/UserDetail.vue b/components/admin/UserDetail.vue index 252d862..e74a6b7 100644 --- a/components/admin/UserDetail.vue +++ b/components/admin/UserDetail.vue @@ -40,6 +40,10 @@
{{ t('Last transaction') }}
{{ detail.last_transaction_at ? fmtDate(detail.last_transaction_at) : '-' }}
+
+
{{ t('AI tokens used') }}
+
{{ fmtNumber(detail.user.tokens_used) }}
+
@@ -91,6 +95,7 @@ const initials = computed(() => { }); const fmtDate = (iso: string): string => (iso ? new Date(iso).toLocaleDateString() : ''); +const fmtNumber = (value: number): string => new Intl.NumberFormat().format(value ?? 0); const load = async () => { loading.value = true; diff --git a/i18n/locales/de.json b/i18n/locales/de.json index f01fc24..3199d9b 100644 --- a/i18n/locales/de.json +++ b/i18n/locales/de.json @@ -1,4 +1,9 @@ { + "Joined on {date}": "Beigetreten am {date}", + "Last seen": "Zuletzt gesehen", + "Last transaction": "Letzte Transaktion", + "Never": "Nie", + "Page {page} of {pages} · {total} users": "Seite {page} von {pages} · {total} Benutzer", "Recent imports": "Letzte Importe", "Needs review": "Zu prüfen", "Analyzing": "Wird analysiert", diff --git a/i18n/locales/en.json b/i18n/locales/en.json index f1c2468..05a02b5 100644 --- a/i18n/locales/en.json +++ b/i18n/locales/en.json @@ -1,4 +1,9 @@ { + "Joined on {date}": "Joined on {date}", + "Last seen": "Last seen", + "Last transaction": "Last transaction", + "Never": "Never", + "Page {page} of {pages} · {total} users": "Page {page} of {pages} · {total} users", "Recent imports": "Recent imports", "Needs review": "Needs review", "Analyzing": "Analyzing", diff --git a/i18n/locales/es.json b/i18n/locales/es.json index 73662a9..6d2bba9 100644 --- a/i18n/locales/es.json +++ b/i18n/locales/es.json @@ -1,4 +1,9 @@ { + "Joined on {date}": "Se unió el {date}", + "Last seen": "Última visita", + "Last transaction": "Última transacción", + "Never": "Nunca", + "Page {page} of {pages} · {total} users": "Página {page} de {pages} · {total} usuarios", "Recent imports": "Importaciones recientes", "Needs review": "Por revisar", "Analyzing": "Analizando", diff --git a/i18n/locales/fr.json b/i18n/locales/fr.json index e06a05b..246ba73 100644 --- a/i18n/locales/fr.json +++ b/i18n/locales/fr.json @@ -1,4 +1,9 @@ { + "Joined on {date}": "Inscrit le {date}", + "Last seen": "Dernière visite", + "Last transaction": "Dernière transaction", + "Never": "Jamais", + "Page {page} of {pages} · {total} users": "Page {page} sur {pages} · {total} utilisateurs", "Recent imports": "Imports récents", "Needs review": "À vérifier", "Analyzing": "Analyse en cours", diff --git a/i18n/locales/it.json b/i18n/locales/it.json index 3fd1ded..ba3ca06 100644 --- a/i18n/locales/it.json +++ b/i18n/locales/it.json @@ -1,4 +1,9 @@ { + "Joined on {date}": "Iscritto il {date}", + "Last seen": "Ultimo accesso", + "Last transaction": "Ultima transazione", + "Never": "Mai", + "Page {page} of {pages} · {total} users": "Pagina {page} di {pages} · {total} utenti", "Recent imports": "Importazioni recenti", "Needs review": "Da rivedere", "Analyzing": "Analisi in corso", diff --git a/i18n/locales/pt.json b/i18n/locales/pt.json index f8b9f5d..0ed05a0 100644 --- a/i18n/locales/pt.json +++ b/i18n/locales/pt.json @@ -1,4 +1,9 @@ { + "Joined on {date}": "Inscrito em {date}", + "Last seen": "Último acesso", + "Last transaction": "Última transação", + "Never": "Nunca", + "Page {page} of {pages} · {total} users": "Página {page} de {pages} · {total} utilizadores", "Recent imports": "Importações recentes", "Needs review": "A rever", "Analyzing": "A analisar", diff --git a/pages/admin/index.vue b/pages/admin/index.vue index 3bf207c..14ed9e1 100644 --- a/pages/admin/index.vue +++ b/pages/admin/index.vue @@ -73,6 +73,7 @@ height="220" :options="areaOptions(usersChart.categories, chartColors.primary)" :series="[{ name: t('New users'), data: usersChart.data }]" + @data-point-selection="showSignupsForPoint" /> @@ -138,47 +139,75 @@ @@ -206,24 +235,12 @@ -
- {{ t(col.label) }} - {{ t('Action') }}
- - - - - - - - - - - - - - - - -
{{ t('Subject') }}{{ t('Audience') }}{{ t('Sent') }}{{ t('Date') }}
{{ o.subject }}{{ o.audience }}{{ o.sent }}{{ formatDate(o.created_at) }}
+ + + +

{{ t('No outreaches yet') }}

@@ -240,23 +257,56 @@ /> -
- +
+
+
+

{{ t('AI usage') }}

+

+ {{ t('Assistant token consumption for the selected period.') }} +

+
+
+
{{ t('Loading...') }}
+