Dashboard Assistant is a small chat widget built as part of a candidate challenge. It behaves like an assistant embedded in a dashboard: you can open/close the chat, load a mocked history, send messages, and receive a polymorphic assistant response (text or an interactive Reward Card).
The project intentionally runs without a backend. All responses are simulated on the client side to keep the scope focused on UI, state management, and clean architecture.
- Floating button to open/close the assistant
- Chat window with header, scrollable message list, and input footer
- Mocked history loaded on open (simulated network delay)
- Send message via button or Enter key
- Assistant “typing/loading” state
- Polymorphic assistant responses:
- Plain text messages
- Reward Card widget (hardcoded, interactive)
- Vue 3 (Composition API)
- TypeScript
- Vite
- Clone the repository:
git clone https://github.com/alanortiz-dev/dashboard-assistant- Go to the project folder:
cd dashboard-assistant- Install the dependencies and run in development mode:
npm install
npm run dev- No external API is required to run this project. Everything runs locally.
The code is organized around three goals:
- Keep UI components small and focused
- Keep state + actions in a single place
- Enforce polymorphism through TypeScript types
src/
├── components/
│ └── chat/
│ ├── ChatFabButton.vue # Floating open/close button
│ ├── ChatWindow.vue # Popup container (header/body/footer)
│ ├── MessageList.vue # Scrollable list wrapper
│ ├── MessageItem.vue # Polymorphic renderer (text vs reward)
│ ├── MessageBubble.vue # Text message bubble (user/assistant)
│ └── RewardCard.vue # Widget message (interactive card)
├── composables/
│ └── useChat.ts # Single source of truth for state + actions
└── types/
└── chat.ts # Discriminated unions for message types
This project is intentionally small and focused. The goal is to show clean component boundaries, predictable state, and type-safe polymorphic rendering rather than visual polish.
All chat state and actions live in src/composables/useChat.ts (history loading, sending messages, typing/loading flags).
This keeps components easier to read and prevents duplicated logic.
Messages are defined as discriminated unions in src/types/chat.ts.
Each message has a type, so the UI can reliably render either a text bubble or a Reward Card without guesswork.
ChatWindowhandles layout and user inputMessageListrenders the listMessageItemdecides what to render based on messagetypeMessageBubblerenders text messagesRewardCardrenders the widget message
The assistant behavior is simulated with setTimeout to match the challenge scope (no backend) while still showing real UI states like history loading and typing.
You can try the app here: Dashboard Assistant on Vercel
If you enjoyed this project, feel free to connect with me:
📧 alan.omar.ortz@gmail.com
🌐 LinkedIn
Built with care by Alan Ortiz (alanortizdev).