diff --git a/templates/chat-x402/index.html b/templates/chat-x402/index.html
new file mode 100644
index 000000000..f4808ff19
--- /dev/null
+++ b/templates/chat-x402/index.html
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+ Chat x402 Template
+
+
+
+
+
+
diff --git a/templates/chat-x402/package.json b/templates/chat-x402/package.json
new file mode 100644
index 000000000..458c56348
--- /dev/null
+++ b/templates/chat-x402/package.json
@@ -0,0 +1,32 @@
+{
+ "name": "chat-x402",
+ "private": true,
+ "version": "0.0.0",
+ "type": "module",
+ "description": "A simple chat template with an auth switcher for Echo Credits or USDC via x402.",
+ "scripts": {
+ "dev": "vite",
+ "build": "tsc && vite build",
+ "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
+ "preview": "vite preview"
+ },
+ "dependencies": {
+ "react": "^18.2.0",
+ "react-dom": "^18.2.0"
+ },
+ "devDependencies": {
+ "@types/react": "^18.2.15",
+ "@types/react-dom": "^18.2.7",
+ "@typescript-eslint/eslint-plugin": "^6.0.0",
+ "@typescript-eslint/parser": "^6.0.0",
+ "@vitejs/plugin-react": "^4.0.3",
+ "autoprefixer": "^10.4.16",
+ "eslint": "^8.45.0",
+ "eslint-plugin-react-hooks": "^4.6.0",
+ "eslint-plugin-react-refresh": "^0.4.3",
+ "postcss": "^8.4.31",
+ "tailwindcss": "^3.3.5",
+ "typescript": "^5.0.2",
+ "vite": "^4.4.5"
+ }
+}
diff --git a/templates/chat-x402/postcss.config.js b/templates/chat-x402/postcss.config.js
new file mode 100644
index 000000000..b8b93b1b6
--- /dev/null
+++ b/templates/chat-x402/postcss.config.js
@@ -0,0 +1,6 @@
+import tailwindcss from 'tailwindcss';
+import autoprefixer from 'autoprefixer';
+
+export default {
+ plugins: [tailwindcss, autoprefixer],
+};
diff --git a/templates/chat-x402/src/App.tsx b/templates/chat-x402/src/App.tsx
new file mode 100644
index 000000000..479806ec7
--- /dev/null
+++ b/templates/chat-x402/src/App.tsx
@@ -0,0 +1,21 @@
+import React from 'react';
+import ChatUI from './components/ChatUI';
+import AuthSwitcher from './components/AuthSwitcher';
+import { PaymentMethodProvider } from './context/PaymentMethodContext';
+import './index.css'; // Ensure tailwind CSS is imported
+
+const App: React.FC = () => {
+ return (
+
+
+
Chat with X402 Payment Options
+
+
+
+ );
+};
+
+export default App;
diff --git a/templates/chat-x402/src/components/AuthSwitcher.tsx b/templates/chat-x402/src/components/AuthSwitcher.tsx
new file mode 100644
index 000000000..920c945f6
--- /dev/null
+++ b/templates/chat-x402/src/components/AuthSwitcher.tsx
@@ -0,0 +1,33 @@
+import React from 'react';
+import { PaymentMethod, usePaymentMethod } from '../context/PaymentMethodContext';
+
+const AuthSwitcher: React.FC = () => {
+ const { selectedMethod, setMethod } = usePaymentMethod();
+
+ return (
+
+
+
+
+ );
+};
+
+export default AuthSwitcher;
diff --git a/templates/chat-x402/src/components/ChatUI.tsx b/templates/chat-x402/src/components/ChatUI.tsx
new file mode 100644
index 000000000..619fbba82
--- /dev/null
+++ b/templates/chat-x402/src/components/ChatUI.tsx
@@ -0,0 +1,77 @@
+import React, { useState } from 'react';
+import { PaymentMethod, usePaymentMethod } from '../context/PaymentMethodContext';
+
+type Message = {
+ id: number;
+ text: string;
+ sender: 'user' | 'bot';
+};
+
+const ChatUI: React.FC = () => {
+ const { selectedMethod } = usePaymentMethod();
+ const [messages, setMessages] = useState([
+ { id: 1, text: `Welcome! Currently, your chat interactions would utilize ${selectedMethod.replace('_', ' ')}.`, sender: 'bot' },
+ ]);
+ const [input, setInput] = useState('');
+
+ const handleSendMessage = () => {
+ if (input.trim()) {
+ const newUserMessage: Message = { id: messages.length + 1, text: input, sender: 'user' };
+ setMessages((prevMessages) => [...prevMessages, newUserMessage]);
+ setInput('');
+
+ // Simulate bot response and payment method usage
+ setTimeout(() => {
+ const botResponseText = `You sent "${input}". This message is hypothetically processed using ${selectedMethod.replace('_', ' ')}.`;
+ const botResponse: Message = {
+ id: messages.length + 2,
+ text: botResponseText,
+ sender: 'bot',
+ };
+ setMessages((prevMessages) => [...prevMessages, botResponse]);
+ }, 500);
+ }
+ };
+
+ return (
+
+
+ Current Payment Method: {selectedMethod.replace('_', ' ')}
+
+
+ {messages.map((msg) => (
+
+ ))}
+
+
+ setInput(e.target.value)}
+ onKeyPress={(e) => e.key === 'Enter' && handleSendMessage()}
+ />
+
+
+
+ );
+};
+
+export default ChatUI;
diff --git a/templates/chat-x402/src/context/PaymentMethodContext.tsx b/templates/chat-x402/src/context/PaymentMethodContext.tsx
new file mode 100644
index 000000000..4439037ed
--- /dev/null
+++ b/templates/chat-x402/src/context/PaymentMethodContext.tsx
@@ -0,0 +1,31 @@
+import React, { createContext, useContext, useState, ReactNode } from 'react';
+
+export enum PaymentMethod {
+ ECHO_CREDITS = 'ECHO_CREDITS',
+ X402_USDC = 'X402_USDC',
+}
+
+interface PaymentMethodContextType {
+ selectedMethod: PaymentMethod;
+ setMethod: (method: PaymentMethod) => void;
+}
+
+const PaymentMethodContext = createContext(undefined);
+
+export const PaymentMethodProvider = ({ children }: { children: ReactNode }) => {
+ const [selectedMethod, setMethod] = useState(PaymentMethod.ECHO_CREDITS);
+
+ return (
+
+ {children}
+
+ );
+};
+
+export const usePaymentMethod = () => {
+ const context = useContext(PaymentMethodContext);
+ if (context === undefined) {
+ throw new Error('usePaymentMethod must be used within a PaymentMethodProvider');
+ }
+ return context;
+};
diff --git a/templates/chat-x402/src/index.css b/templates/chat-x402/src/index.css
new file mode 100644
index 000000000..b549bc308
--- /dev/null
+++ b/templates/chat-x402/src/index.css
@@ -0,0 +1,22 @@
+@tailwind base;
+@tailwind components;
+@tailwind utilities;
+
+/* Custom scrollbar for chat messages */
+.custom-scrollbar::-webkit-scrollbar {
+ width: 8px;
+}
+
+.custom-scrollbar::-webkit-scrollbar-track {
+ background: #f1f1f1;
+ border-radius: 10px;
+}
+
+.custom-scrollbar::-webkit-scrollbar-thumb {
+ background: #888;
+ border-radius: 10px;
+}
+
+.custom-scrollbar::-webkit-scrollbar-thumb:hover {
+ background: #555;
+}
diff --git a/templates/chat-x402/src/main.tsx b/templates/chat-x402/src/main.tsx
new file mode 100644
index 000000000..9bb419d3d
--- /dev/null
+++ b/templates/chat-x402/src/main.tsx
@@ -0,0 +1,10 @@
+import React from 'react';
+import ReactDOM from 'react-dom/client';
+import App from './App.tsx';
+import './index.css';
+
+ReactDOM.createRoot(document.getElementById('root')!).render(
+
+
+ ,
+);
diff --git a/templates/chat-x402/src/vite-env.d.ts b/templates/chat-x402/src/vite-env.d.ts
new file mode 100644
index 000000000..11f02fe2a
--- /dev/null
+++ b/templates/chat-x402/src/vite-env.d.ts
@@ -0,0 +1 @@
+///
diff --git a/templates/chat-x402/tailwind.config.js b/templates/chat-x402/tailwind.config.js
new file mode 100644
index 000000000..d21f1cdae
--- /dev/null
+++ b/templates/chat-x402/tailwind.config.js
@@ -0,0 +1,8 @@
+/** @type {import('tailwindcss').Config} */
+export default {
+ content: ['./index.html', './src/**/*.{js,ts,jsx,tsx}'],
+ theme: {
+ extend: {},
+ },
+ plugins: [],
+};
diff --git a/templates/chat-x402/tsconfig.json b/templates/chat-x402/tsconfig.json
new file mode 100644
index 000000000..a7fc6fbf2
--- /dev/null
+++ b/templates/chat-x402/tsconfig.json
@@ -0,0 +1,25 @@
+{
+ "compilerOptions": {
+ "target": "ES2020",
+ "useDefineForClassFields": true,
+ "lib": ["ES2020", "DOM", "DOM.Iterable"],
+ "module": "ESNext",
+ "skipLibCheck": true,
+
+ /* Bundler mode */
+ "moduleResolution": "bundler",
+ "allowImportingTsExtensions": true,
+ "resolveJsonModule": true,
+ "isolatedModules": true,
+ "noEmit": true,
+ "jsx": "react-jsx",
+
+ /* Linting */
+ "strict": true,
+ "noUnusedLocals": true,
+ "noUnusedParameters": true,
+ "noFallthroughCasesInSwitch": true
+ },
+ "include": ["src"],
+ "references": [{ "path": "./tsconfig.node.json" }]
+}
diff --git a/templates/chat-x402/tsconfig.node.json b/templates/chat-x402/tsconfig.node.json
new file mode 100644
index 000000000..11eb27d89
--- /dev/null
+++ b/templates/chat-x402/tsconfig.node.json
@@ -0,0 +1,12 @@
+{
+ "compilerOptions": {
+ "composite": true,
+ "esModuleInterop": true,
+ "module": "ESNext",
+ "moduleResolution": "bundler",
+ "allowSyntheticDefaultImports": true,
+ "skipLibCheck": true,
+ "strict": true
+ },
+ "include": ["vite.config.ts"]
+}
diff --git a/templates/chat-x402/vite.config.ts b/templates/chat-x402/vite.config.ts
new file mode 100644
index 000000000..627a31962
--- /dev/null
+++ b/templates/chat-x402/vite.config.ts
@@ -0,0 +1,7 @@
+import { defineConfig } from 'vite';
+import react from '@vitejs/plugin-react';
+
+// https://vitejs.dev/config/
+export default defineConfig({
+ plugins: [react()],
+});