Skip to content

CSR Cockpit Integration

CSR Cockpit Integration

The CSR Cockpit has two separate interfaces with different audiences and different role mappings. Both embed the same widget — configured differently.

Prerequisites

  • @teei/chat-widget installed (see Integration Guide)
  • @astrojs/react already configured in csr-cockpit/astro.config.mjs (it is)
  • RAG Worker running at https://knowledge-api.theeducationalequalityinstitute.org
  • Widget CSS imported once globally

Interface 1 — Manager Dashboard

URL pattern: /{company-slug}/ and all sub-routes Layout file: csr-cockpit/src/layouts/CockpitLayout.astro Audience: CSR managers at partner companies Role values: viewer, csr_manager, company_admin, platform_admin

Role mapping

The CSR Cockpit uses a 5-role permission system (CockpitRole). Map these to the knowledge widget’s simpler role hierarchy:

// In CockpitLayout.astro frontmatter
const KNOWLEDGE_ROLE_MAP: Record<string, string> = {
viewer: 'employee', // read-only manager — same content as employees
csr_manager: 'manager', // full CSR manager access
company_admin: 'manager', // company administrator
platform_admin: 'admin', // TEEI platform administrator
};
// managerRole comes from resolvePageContext() / page-auth.ts
const knowledgeRole = KNOWLEDGE_ROLE_MAP[managerRole] ?? 'employee';

Step-by-step installation

Step 1: Open csr-cockpit/src/layouts/CockpitLayout.astro.

Step 2: Add the import at the top of the frontmatter block, with the other React component imports:

---
// Existing imports
import { AnnotationOverlay } from "../components/annotations/AnnotationOverlay";
// Add these two lines:
import { ChatProvider, ChatWidget } from '@teei/chat-widget';
import '@teei/chat-widget/styles';
---

Step 3: Add the role mapping in the frontmatter, after managerRole is resolved:

---
// ... existing resolvePageContext() call
const KNOWLEDGE_ROLE_MAP: Record<string, string> = {
viewer: 'employee',
csr_manager: 'manager',
company_admin: 'manager',
platform_admin: 'admin',
};
const knowledgeRole = KNOWLEDGE_ROLE_MAP[managerRole] ?? 'employee';
---

Step 4: Add the widget to the layout body, immediately before </body>. Place it after <AnnotationOverlay> to avoid z-index conflicts (the annotation overlay uses z-index 9994; the chat widget uses z-index 9999):

<!-- Existing components -->
{isAnnotationsEnabled() && (
<AnnotationOverlay client:load transition:persist />
)}
<!-- TEEI Knowledge Assistant -->
<ChatProvider
client:idle
apiUrl="https://knowledge-api.theeducationalequalityinstitute.org"
platform="csr-cockpit"
userRole={knowledgeRole}
language="en"
>
<ChatWidget />
</ChatProvider>
</body>

Step 5: Verify the build:

Terminal window
cd teei-astro/csr-cockpit
npx astro check
npm run build

Step 6: Verify the widget renders:

Terminal window
curl -I http://localhost:6410/demo/
# → HTTP/2 200

Open http://localhost:6410/demo/ in a browser. You should see the TEEI chat FAB (floating blue circle) in the bottom-right corner. Click it to open the panel.


Interface 2 — Employee Portal

URL pattern: /{company-slug}/portal/ and all sub-routes Layout file: csr-cockpit/src/layouts/PortalLayout.astro (if it exists) or the portal pages directly Audience: Employees participating in volunteering programmes Role: Always employee

Employees access a simplified view of company volunteering data. They should receive volunteer-level knowledge content — how to log hours, programme overviews, mentor guides.

Step-by-step installation

Step 1: Locate the portal layout. If a shared portal layout exists:

Terminal window
find csr-cockpit/src -name "*Portal*Layout*" -o -name "*portal*layout*" 2>/dev/null

If no portal-specific layout exists, add the widget to each portal page directly (see pattern below).

Step 2: In the portal layout or portal page frontmatter:

---
import { ChatProvider, ChatWidget } from '@teei/chat-widget';
// Styles only need to be imported once — skip if already imported in a parent layout
---

Step 3: Add the widget to the portal body:

<!-- TEEI Knowledge Assistant — Employee Portal -->
<ChatProvider
client:idle
apiUrl="https://knowledge-api.theeducationalequalityinstitute.org"
platform="csr-portal"
userRole="employee"
language="en"
>
<ChatWidget
greeting="Hi! I can help you find volunteer opportunities, log hours, and navigate the portal. What do you need?"
/>
</ChatProvider>

Note platform="csr-portal" (not csr-cockpit) — this ensures the widget only retrieves content tagged for the portal context, not manager-only content.


Demo company considerations

The CSR Cockpit has a public demo at /demo/. The widget should work in demo mode. When isDemoCompany is true, the widget can still render — it simply queries with whatever role the demo session provides.

If you want to show a demo-specific greeting:

---
const widgetGreeting = isDemo
? "Hi! This is the TEEI Knowledge Assistant demo. I can answer questions about the CSR Cockpit's features. What would you like to know?"
: undefined; // undefined falls back to the default greeting
---
<ChatProvider client:idle apiUrl={...} platform="csr-cockpit" userRole={knowledgeRole}>
<ChatWidget greeting={widgetGreeting} />
</ChatProvider>

Z-index reference (CSR Cockpit)

Existing overlay z-indexes in CSR Cockpit:

Componentz-index
AnnotationOverlay FAB9994
AnnotationOverlay panel9995
CommandPalette9996
DemoExitIntent modal9997
DemoContactDrawer9998
Chat Widget FAB9999
Chat Widget panel9999

The chat widget’s z-index is set via --teei-chat-z: 9999 in the widget CSS. If you experience stacking conflicts, override this CSS variable:

/* In csr-cockpit/src/styles/cockpit-layout.css */
.teei-chat-widget {
--teei-chat-z: 9990; /* Lower than DemoExitIntent if needed */
}

Verification checklist

  • npx astro check exits 0 (no TypeScript errors)
  • npm run build exits 0
  • curl -I http://localhost:6410/demo/ returns 200
  • Chat FAB visible at bottom-right of /demo/ at 1440px
  • Chat panel opens on FAB click
  • Sending a message produces a streamed response
  • Widget does not appear on /portal/login (excluded path)
  • No console errors in browser DevTools

Gotchas

React hydration conflict with client:visible: The widget uses client:idle. Do not change this to client:visible — it is banned in CSR Cockpit’s CLAUDE.md.

jsxDEV is not a function during dev: This is a known Vite esbuild gotcha in CSR Cockpit (documented in astro.config.mjs). The fix is already in place via optimizeDeps.esbuildOptions.define. If the widget component triggers this, clear the Vite cache: rm -rf node_modules/.vite.

Dark mode: The widget reads [data-theme="dark"] from the document root. CSR Cockpit sets this attribute via its theme toggle. No extra configuration is needed — dark mode works automatically.

Annotations overlay click-intercept: The AnnotationOverlay .ann-click-overlay intercepts pointer events when active. The chat widget uses z-index: 9999 (above the annotation overlay at 9994–9995). If click interception prevents the chat FAB from receiving clicks, check that the annotation overlay is not in active intercept mode.