feat: Add admin console UI with outreach and onboarding updates#96
Conversation
Add an admin area, reached from the avatar menu when the signed-in user is an administrator. It has its own left-rail shell with an overview dashboard (KPIs, charts and rankings), demographics, a searchable user table whose rows open a detailed profile, and outreach: a history of sent emails plus a composer with a formatted (markdown) body, a header image, attachments, audience or specific-user targeting, and a live preview of the rendered email. Refresh the marketing surfaces to match the assistant-first direction: the login slides now lead with the assistant and bank integrations, the onboarding flow gets a brand-washed background and illustrated steps with a country step, and the emoji and stripe cards in onboarding and the learning modal are replaced with vector icons and clean surfaces.
Code Review SummaryThis PR introduces a comprehensive Admin Console and refreshes the onboarding/marketing UI. It includes new metrics dashboards, user management, and an outreach campaign tool with markdown support. It also fixes several login-related crashes. 🚀 Key Improvements
💡 Minor Suggestions
|
| } | ||
| }; | ||
|
|
||
| const normalizeUrl = (url: string): string => (/^https?:\/\//i.test(url) ? url : `https://${url}`); |
There was a problem hiding this comment.
The regex ^https?:\/\/ only validates the protocol but not the rest of the URL structure. A user could enter https:// and it would pass.
| const normalizeUrl = (url: string): string => (/^https?:\/\//i.test(url) ? url : `https://${url}`); | |
| const normalizeUrl = (url: string): string => { | |
| if (!url) return ''; | |
| const trimmed = url.trim(); | |
| return /^https?:\/\//i.test(trimmed) ? trimmed : `https://${trimmed}`; | |
| }; |
| <div class="preview__frame"> | ||
| <iframe | ||
| v-if="previewHtml" | ||
| :srcdoc="previewHtml" |
There was a problem hiding this comment.
When using srcdoc in an iframe, it is safer to use the sandbox attribute without allow-scripts unless strictly necessary to prevent XSS from the rendered markdown.
| :srcdoc="previewHtml" | |
| :srcdoc="previewHtml" | |
| class="preview__iframe" | |
| sandbox="allow-same-origin" |
| @@ -0,0 +1,15 @@ | |||
| export default defineNuxtRouteMiddleware(async () => { | |||
There was a problem hiding this comment.
The middleware relies on isAuthenticated which is usually a client-side reactive state. In a SSR context (Nuxt), ensure useAuth handles the initialization properly or wrap this in a client-side check if the API isn't ready.
| export default defineNuxtRouteMiddleware(async () => { | |
| export default defineNuxtRouteMiddleware(async () => { | |
| const { user, isAuthenticated, fetchUser } = useAuth(); | |
| if (process.server) return; | |
| if (!isAuthenticated.value) { | |
| return navigateTo('/login'); | |
| } | |
| if (user.value && typeof user.value.is_admin === 'undefined') { | |
| await fetchUser(); | |
| } | |
| if (!user.value?.is_admin) { | |
| return navigateTo('/dashboard'); | |
| } | |
| }); |
| if (cache) return cache; | ||
| let display: Intl.DisplayNames | null = null; | ||
| try { | ||
| display = new Intl.DisplayNames(['en'], { type: 'region' }); |
There was a problem hiding this comment.
The locale is hardcoded to 'en'. For a localized app, it should use the user's current language preference.
| display = new Intl.DisplayNames(['en'], { type: 'region' }); | |
| const { locale } = useI18n ? useI18n() : { locale: { value: 'en' } }; | |
| display = new Intl.DisplayNames([locale.value], { type: 'region' }); |
Deploying trakli-dev with
|
| Latest commit: |
a6820c7
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://03d5473f.trakli-dev.pages.dev |
| Branch Preview URL: | https://feat-admin-engagement-metric.trakli-dev.pages.dev |
Adds the admin console UI plus marketing and onboarding refreshes.
Admin (avatar menu, admins only) has its own left-rail shell:
Marketing / design, aligned to the assistant-first direction:
Fixes: the country list (a
.splitprecedence bug) and aconfigs-out-of-scope crash on login.Tests: 405 passing; build green.