Skip to content

verschoren/zendesk_widget

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

200 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Zendesk Widget Demo - React + TypeScript Migration

This project has been migrated from static HTML + jQuery to a modern React + TypeScript SPA with auto-generated navigation.

Zendesk Widget Demo

πŸš€ Migration Status

βœ… Completed

  • 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)

🚧 In Progress

  • 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

πŸ› οΈ Setup Instructions

Fix NPM Permissions (Required First)

You have an npm cache permission issue. Run this command to fix it:

sudo chown -R $(whoami) ~/.npm

Install Dependencies

npm install

Development

# 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 build

πŸ“ Project Structure

zendesk_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

🎯 How Auto-Generated Navigation Works

1. Create a Page

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>
}

2. Generate Registry

Run the registry generator to scan all pages and create src/lib/pageRegistry.ts:

npm run generate-registry

This script:

  • Scans all .tsx files in src/pages/
  • Extracts export const metadata from each file
  • Generates imports and a typed registry
  • Creates helper functions for lookups

3. Navigation Auto-Updates

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!

πŸ“ Adding a New Page

  1. Create your page file in the appropriate category folder:

    src/pages/[category]/[PageName].tsx
  2. Export metadata and default component:

    export const metadata: PageMetadata = { ... }
    export default function PageName() { ... }
  3. Regenerate the registry:

    npm run generate-registry
  4. Done! The page appears in navigation automatically.

πŸ”„ Migration Checklist Per Page

When migrating a page from HTML to React:

  • Create .tsx file in appropriate category folder
  • Export metadata object 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

🎨 Styling

  • 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 --watch

πŸ” JWT Authentication

CHECK OUT THE FULL DEMO AND SETUP AT INTERNALNOTE.COM

Current Setup (Cloudflare Pages Functions)

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/

Environment Variables

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:

  1. Copy .dev.vars.example to .dev.vars
  2. Fill in your credentials
  3. Run npm run dev (Vite will proxy /api/* requests)

API Endpoints

Messaging JWT Endpoint

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...

Guide JWT Endpoint

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...

Chat JWT Endpoint

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..."
}

SDK JWT Endpoint

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..."
}

Answer Bot API Endpoints

Base URL: /api/answerbot/*

For: Zendesk Answer Bot article recommendations, resolutions, and rejections

Get Recommendations

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..."
}
Mark Article as Resolved

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

Mark Article as Rejected

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

JWT Structure

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
}

Custom Domain Setup (jwtauth.internalnote.com)

To set up the custom domain in Cloudflare Pages:

  1. Go to your Pages project β†’ Custom domains
  2. Add jwtauth.internalnote.com as a custom domain
  3. Update your DNS to point to Cloudflare Pages:
    • CNAME jwtauth β†’ your-project.pages.dev
  4. The functions will be available at:
    • https://jwtauth.internalnote.com/messaging
    • https://jwtauth.internalnote.com/guide

πŸš€ Deployment (Coming Soon)

Will deploy via Hono on Cloudflare Workers:

npm run deploy

Deployment uses GitHub Action for Wrangler

πŸ“š Key Benefits

Zero Hardcoded Navigation

  • Add page: Create file with metadata β†’ automatic nav entry
  • Remove page: Delete file β†’ automatic nav removal
  • Update page: Edit metadata β†’ automatic nav update

Type Safety

  • TypeScript enforces metadata structure
  • Compile-time errors for missing fields
  • IDE autocomplete for page properties

Developer Experience

  • Single-file page definition (component + metadata)
  • Hot module replacement in development
  • Clear folder organization by category

πŸ› Troubleshooting

npm permission errors

sudo chown -R $(whoami) ~/.npm
npm cache clean --force
npm install

TypeScript errors

npm run generate-registry

Widget not loading

  • Check browser console for errors
  • Verify Zendesk snippet key
  • Ensure useEffect cleanup is working

πŸ“– Reference Files

  • 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

🎯 Next Steps

  1. Fix npm permissions (see above) ⚠️
  2. Run npm install
  3. Test dev server: npm run dev
  4. Continue migrating pages (see migration checklist)
  5. Set up Hono backend (Phase 5)
  6. Deploy to Cloudflare Workers (Phase 6)

πŸ“š References


Built with ❀️ by Internal Note

About

Demo Pages for Internal Note showcasing Zendesk features.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors