Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions templates/chat-x402/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Chat x402 Template</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
32 changes: 32 additions & 0 deletions templates/chat-x402/package.json
Original file line number Diff line number Diff line change
@@ -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"
}
}
6 changes: 6 additions & 0 deletions templates/chat-x402/postcss.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import tailwindcss from 'tailwindcss';
import autoprefixer from 'autoprefixer';

export default {
plugins: [tailwindcss, autoprefixer],
};
21 changes: 21 additions & 0 deletions templates/chat-x402/src/App.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<PaymentMethodProvider>
<div className="min-h-screen bg-gray-50 flex flex-col items-center justify-center p-4">
<h1 className="text-3xl font-bold text-gray-900 mb-6 text-center">Chat with X402 Payment Options</h1>
<div className="w-full max-w-2xl bg-white shadow-xl rounded-xl p-6">
<AuthSwitcher />
<ChatUI />
</div>
</div>
</PaymentMethodProvider>
);
};

export default App;
33 changes: 33 additions & 0 deletions templates/chat-x402/src/components/AuthSwitcher.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import React from 'react';
import { PaymentMethod, usePaymentMethod } from '../context/PaymentMethodContext';

const AuthSwitcher: React.FC = () => {
const { selectedMethod, setMethod } = usePaymentMethod();

return (
<div className="p-4 bg-gray-50 shadow-md rounded-lg mb-4 flex flex-col sm:flex-row justify-center space-y-2 sm:space-y-0 sm:space-x-4">
<button
className={`px-6 py-2 rounded-lg text-sm font-medium transition-colors ${
selectedMethod === PaymentMethod.ECHO_CREDITS
? 'bg-blue-600 text-white shadow hover:bg-blue-700'
: 'bg-gray-200 text-gray-800 hover:bg-gray-300'
}`}
onClick={() => setMethod(PaymentMethod.ECHO_CREDITS)}
>
Pay with Echo Credits
</button>
<button
className={`px-6 py-2 rounded-lg text-sm font-medium transition-colors ${
selectedMethod === PaymentMethod.X402_USDC
? 'bg-green-600 text-white shadow hover:bg-green-700'
: 'bg-gray-200 text-gray-800 hover:bg-gray-300'
}`}
onClick={() => setMethod(PaymentMethod.X402_USDC)}
>
Pay with USDC (x402)
</button>
</div>
);
};

export default AuthSwitcher;
77 changes: 77 additions & 0 deletions templates/chat-x402/src/components/ChatUI.tsx
Original file line number Diff line number Diff line change
@@ -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<Message[]>([
{ 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 (
<div className="flex flex-col h-[70vh] bg-gray-100 rounded-lg shadow-inner overflow-hidden border border-gray-200">
<div className="p-3 bg-blue-700 text-white text-center text-sm font-medium flex items-center justify-center">
Current Payment Method: <span className="font-bold ml-2">{selectedMethod.replace('_', ' ')}</span>
</div>
<div className="flex-grow overflow-y-auto p-4 space-y-4 custom-scrollbar">
{messages.map((msg) => (
<div
key={msg.id}
className={`flex ${msg.sender === 'user' ? 'justify-end' : 'justify-start'}`}
>
<div
className={`max-w-xs p-3 rounded-lg ${
msg.sender === 'user' ? 'bg-blue-500 text-white' : 'bg-gray-300 text-gray-800'
}`}
>
{msg.text}
</div>
</div>
))}
</div>
<div className="flex p-4 border-t bg-white">
<input
type="text"
className="flex-grow p-2 border border-gray-300 rounded-l-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
placeholder="Type your message..."
value={input}
onChange={(e) => setInput(e.target.value)}
onKeyPress={(e) => e.key === 'Enter' && handleSendMessage()}
/>
<button
className="bg-blue-600 text-white px-4 py-2 rounded-r-lg hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500"
onClick={handleSendMessage}
>
Send
</button>
</div>
</div>
);
};

export default ChatUI;
31 changes: 31 additions & 0 deletions templates/chat-x402/src/context/PaymentMethodContext.tsx
Original file line number Diff line number Diff line change
@@ -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<PaymentMethodContextType | undefined>(undefined);

export const PaymentMethodProvider = ({ children }: { children: ReactNode }) => {
const [selectedMethod, setMethod] = useState<PaymentMethod>(PaymentMethod.ECHO_CREDITS);

return (
<PaymentMethodContext.Provider value={{ selectedMethod, setMethod }}>
{children}
</PaymentMethodContext.Provider>
);
};

export const usePaymentMethod = () => {
const context = useContext(PaymentMethodContext);
if (context === undefined) {
throw new Error('usePaymentMethod must be used within a PaymentMethodProvider');
}
return context;
};
22 changes: 22 additions & 0 deletions templates/chat-x402/src/index.css
Original file line number Diff line number Diff line change
@@ -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;
}
10 changes: 10 additions & 0 deletions templates/chat-x402/src/main.tsx
Original file line number Diff line number Diff line change
@@ -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(
<React.StrictMode>
<App />
</React.StrictMode>,
);
1 change: 1 addition & 0 deletions templates/chat-x402/src/vite-env.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/// <reference types="vite/client" />
8 changes: 8 additions & 0 deletions templates/chat-x402/tailwind.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/** @type {import('tailwindcss').Config} */
export default {
content: ['./index.html', './src/**/*.{js,ts,jsx,tsx}'],
theme: {
extend: {},
},
plugins: [],
};
25 changes: 25 additions & 0 deletions templates/chat-x402/tsconfig.json
Original file line number Diff line number Diff line change
@@ -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" }]
}
12 changes: 12 additions & 0 deletions templates/chat-x402/tsconfig.node.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"compilerOptions": {
"composite": true,
"esModuleInterop": true,
"module": "ESNext",
"moduleResolution": "bundler",
"allowSyntheticDefaultImports": true,
"skipLibCheck": true,
"strict": true
},
"include": ["vite.config.ts"]
}
7 changes: 7 additions & 0 deletions templates/chat-x402/vite.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';

// https://vitejs.dev/config/
export default defineConfig({
plugins: [react()],
});