This project has been migrated from static HTML + jQuery to a modern React + TypeScript SPA with auto-generated navigation.
- Phase 1: Foundation Setup - Vite, React, TypeScript configured
- Phase 2: Core Components - Layout, Sidebar, Navigation components
- Phase 3: Registry System - Auto-generation script created
- Phase 4 (Partial): Sample page migrated (Messaging Authentication)
- Phase 4: Migrate remaining 29 pages
- Messaging Authentication (sample)
- 8 more Messaging pages
- 4 Classic Widget pages
- 7 Proactive Messaging pages
- 2 Answer Bot & Storage pages
- 8 Embed mode pages
- Phase 5: Hono backend setup
- Phase 6: Testing & deployment
You have an npm cache permission issue. Run this command to fix it:
sudo chown -R $(whoami) ~/.npmnpm install# Run dev server with hot reload
npm run dev
# Generate page registry (run after adding new pages)
npm run generate-registry
# Build for production
npm run buildzendesk_widget/
βββ src/
β βββ main.tsx # React entry point
β βββ App.tsx # Root component with routing
β β
β βββ pages/ # Page components
β β βββ HomePage.tsx # Landing page
β β βββ messaging/
β β βββ Authentication.tsx # Sample migrated page
β β
β βββ components/
β β βββ Layout/ # Layout components
β β β βββ AppLayout.tsx
β β β βββ Sidebar.tsx
β β β βββ MobileSidebar.tsx
β β β βββ MobileHeader.tsx
β β β βββ Footer.tsx
β β β
β β βββ Navigation/
β β βββ NavigationMenu.tsx # Auto-generated nav
β β
β βββ lib/
β β βββ pageRegistry.ts # AUTO-GENERATED page registry
β β βββ navigation.ts # Navigation builder
β β
β βββ types/
β β βββ page.ts # PageMetadata interface
β β βββ navigation.ts # Navigation types
β β
β βββ styles/
β βββ globals.css # Tailwind + custom styles
β
βββ scripts/
β βββ generate-registry.ts # Registry generation script
β
βββ public/ # Static assets (copied from docs/)
β βββ fonts/ # VanillaSans fonts
β βββ img/ # Images
β
βββ index.html # HTML entry point
βββ vite.config.ts # Vite configuration
βββ tsconfig.json # TypeScript config
βββ package.json
Each page exports metadata for automatic navigation generation:
// src/pages/messaging/Authentication.tsx
import { PageMetadata } from '@/types/page'
export const metadata: PageMetadata = {
id: 'authentication',
category: 'messaging',
categoryName: 'Messaging Widget',
name: 'Authentication',
icon: 'π',
path: '/messaging/authentication',
title: 'Zendesk Messaging Authentication',
description: 'Demo page to showcase JWT Authentication'
}
export default function MessagingAuthentication() {
// Component implementation
return <div>...</div>
}Run the registry generator to scan all pages and create src/lib/pageRegistry.ts:
npm run generate-registryThis script:
- Scans all
.tsxfiles insrc/pages/ - Extracts
export const metadatafrom each file - Generates imports and a typed registry
- Creates helper functions for lookups
The navigation menu automatically builds from the registry:
- Groups pages by category
- Shows/hides based on available pages
- Highlights active page
- Handles external links
No hardcoded navigation arrays needed!
-
Create your page file in the appropriate category folder:
src/pages/[category]/[PageName].tsx
-
Export metadata and default component:
export const metadata: PageMetadata = { ... } export default function PageName() { ... }
-
Regenerate the registry:
npm run generate-registry
-
Done! The page appears in navigation automatically.
When migrating a page from HTML to React:
- Create
.tsxfile in appropriate category folder - Export
metadataobject with all required fields - Convert HTML structure to JSX
- Port jQuery logic to React hooks:
$('#element').click()βonClick={handler}$.ajax()βfetch()or custom hooks$('#element').val()βuseState()+ controlled inputs
- Implement Zendesk widget loading with
useEffect - Convert inline
<script>tags to component logic - Test authentication flows if applicable
- Verify responsive layout
- Test all interactive features
- Tailwind CSS v4 with custom theme
- Custom colors:
matcha,licorice,cactus,lime - Custom font: Vanilla Sans
- All existing Tailwind config preserved
To rebuild Tailwind (if needed for docs/):
npx tailwindcss -i ./tailwind/input.css -o ./docs/css/style.css --watchCHECK OUT THE FULL DEMO AND SETUP AT INTERNALNOTE.COM
The project uses Cloudflare Pages Functions (serverless) to generate JWTs for:
- Zendesk Messaging SDK β
/api/messaging - Zendesk Guide/Classic Widget β
/api/guide - Zendesk Chat β
/api/chat - Zendesk SDK β
/api/sdk
Located in: functions/api/
Set these in Cloudflare Pages Dashboard (Settings β Environment Variables):
Production & Preview:
MESSAGING_APP_ID=your_messaging_app_id
MESSAGING_SECRET=your_messaging_secret_key
GUIDE_SECRET=your_guide_secret_key
CHAT_SECRET=your_chat_secret_key
SDK_SECRET=your_sdk_secret_key
ANSWERBOT_DOMAIN=your_zendesk_subdomain
ANSWERBOT_ADMIN_EMAIL=admin@example.com
ANSWERBOT_API_TOKEN=your_api_token
Local Development:
- Copy
.dev.vars.exampleto.dev.vars - Fill in your credentials
- Run
npm run dev(Vite will proxy/api/*requests)
URL: /api/messaging or https://jwtauth.internalnote.com/messaging
For: Zendesk Messaging SDK authentication
Request:
curl -X POST https://demo.internalnote.com/api/messaging \
-H "Content-Type: application/json" \
-d '{
"external_id": "123456",
"email": "john@example.com",
"name": "John Appleseed"
}'Response: JWT token (plain text)
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
URL: /api/guide or https://jwtauth.internalnote.com/guide
For: Zendesk Classic Widget / Guide authentication
Request:
curl -X POST https://demo.internalnote.com/api/guide \
-H "Content-Type: application/json" \
-d '{
"external_id": "123456",
"user_email": "john@example.com",
"user_name": "John Appleseed"
}'Response: JWT token (plain text)
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
URL: /api/chat
For: Zendesk Chat authentication
Request:
curl -X POST https://demo.internalnote.com/api/chat \
-H "Content-Type: application/json" \
-d '{
"name": "John Appleseed",
"email": "john@example.com",
"external_id": "123456"
}'Response: JSON with JWT
{
"jwt": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}URL: /api/sdk
For: Zendesk SDK authentication
Request:
curl -X POST https://demo.internalnote.com/api/sdk \
-H "Content-Type: application/json" \
-d '{
"user_token": "john@example.com"
}'Response: JSON with JWT
{
"jwt": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}Base URL: /api/answerbot/*
For: Zendesk Answer Bot article recommendations, resolutions, and rejections
URL: /api/answerbot/recommendations
Request:
curl -X POST https://demo.internalnote.com/api/answerbot/recommendations \
-H "Content-Type: application/json" \
-d '{
"enquiry": "How to reset my password?",
"locale": "en-us",
"reference": "demo"
}'Response: JSON with articles and interaction token
{
"articles": [
{
"article_id": "123456",
"title": "How to reset your password",
"snippet": "To reset your password...",
"html_url": "https://support.example.com/..."
}
],
"interaction_access_token": "abc123..."
}URL: /api/answerbot/resolve
Request:
curl -X POST https://demo.internalnote.com/api/answerbot/resolve \
-H "Content-Type: application/json" \
-d '{
"article_id": "123456",
"interaction_access_token": "abc123..."
}'Response: JSON with status code
URL: /api/answerbot/reject
Request:
curl -X POST https://demo.internalnote.com/api/answerbot/reject \
-H "Content-Type: application/json" \
-d '{
"article_id": "123456",
"interaction_access_token": "abc123...",
"reason_id": 2
}'Response: JSON with status code
Header:
{
"alg": "HS256",
"typ": "JWT",
"kid": "your_app_id"
}Payload:
{
"scope": "user",
"name": "John Appleseed",
"email": "john@example.com",
"external_id": "123456",
"exp": 1234567890,
"email_verified": true
}To set up the custom domain in Cloudflare Pages:
- Go to your Pages project β Custom domains
- Add
jwtauth.internalnote.comas a custom domain - Update your DNS to point to Cloudflare Pages:
- CNAME
jwtauthβyour-project.pages.dev
- CNAME
- The functions will be available at:
https://jwtauth.internalnote.com/messaginghttps://jwtauth.internalnote.com/guide
Will deploy via Hono on Cloudflare Workers:
npm run deployDeployment uses GitHub Action for Wrangler
- Add page: Create file with metadata β automatic nav entry
- Remove page: Delete file β automatic nav removal
- Update page: Edit metadata β automatic nav update
- TypeScript enforces metadata structure
- Compile-time errors for missing fields
- IDE autocomplete for page properties
- Single-file page definition (component + metadata)
- Hot module replacement in development
- Clear folder organization by category
sudo chown -R $(whoami) ~/.npm
npm cache clean --force
npm installnpm run generate-registry- Check browser console for errors
- Verify Zendesk snippet key
- Ensure
useEffectcleanup is working
- Original navigation:
docs/js/view.js(lines 119-264) - Original homepage:
docs/index.html - Sample migrated page:
docs/messaging.html - JWT Workers:
messaging-worker/src/worker.js,classic-worker/index.js
- Fix npm permissions (see above)
β οΈ - Run
npm install - Test dev server:
npm run dev - Continue migrating pages (see migration checklist)
- Set up Hono backend (Phase 5)
- Deploy to Cloudflare Workers (Phase 6)
Built with β€οΈ by Internal Note
