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 @@
+
+
+
+
+
+
+
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..c45b118 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 @@
-
-
-
- | {{ t('Name') }} |
- {{ t('Email') }} |
- {{ t('Joined') }} |
- {{ t('Actions') }} |
-
-
-
-
- | {{ u.first_name }} {{ u.last_name }} |
- {{ u.email }} |
- {{ formatDate(u.created_at) }} |
-
-
-
-
-
- {{ t('View profile') }}
- {{ t('Reach out') }}
- {{ t('Grant discount') }}
-
- |
-
-
-
- {{ users.length ? t('No matches') : t('No users yet') }}
+
+
+ {{ u.first_name }} {{ u.last_name }}
+
+ {{ formatDate(u.created_at) }}
+
+ {{ u.last_seen_at ? formatDateTime(u.last_seen_at) : t('Never') }}
+
+
+ {{ u.last_transaction_at ? formatDateTime(u.last_transaction_at) : t('Never') }}
+
+ {{ fmt(u.tokens_used) }}
+
+
+
+
+
+
+ {{ t('View profile') }}
+ {{ t('Reach out') }}
+ {{ t('Grant discount') }}
+
+
+
+
+ {{ t('No users found') }}
+
+
+
+
+
@@ -206,24 +235,12 @@
-
-
-
- | {{ t('Subject') }} |
- {{ t('Audience') }} |
- {{ t('Sent') }} |
- {{ t('Date') }} |
-
-
-
-
- | {{ o.subject }} |
- {{ o.audience }} |
- {{ o.sent }} |
- {{ formatDate(o.created_at) }} |
-
-
-
+
+ {{ value }}
+ {{ formatDate(row.created_at) }}
+
{{ t('No outreaches yet') }}
@@ -240,23 +257,65 @@
/>
-
-
+
+
+ {{ t('Loading...') }}
+
+
+
+
+ {{ fmt(metricByKey('ai_tokens_used')?.value) }}
+ {{ t('AI tokens used') }}
+
+
+
+
+ {{ t('Token usage') }}
+
+
+
+
+
+ {{ t('Tokens by user') }}
+
+ -
+ {{ k + 1 }}
+ {{ row.label }}
+ {{ fmt(row.value) }}
+
+
+ {{ t('No token usage yet') }}
+
+
+