Path: blob/master/gate-controller/components/ApiInstructionsModal.tsx
1082 views
'use client';12import { useState, useEffect } from 'react';3import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription } from '@/components/ui/dialog';4import { Button } from '@/components/ui/button';5import { toast } from 'sonner';6import { ClipboardCopy } from 'lucide-react';7import { invoke } from '@tauri-apps/api/core';89interface Relay {10id: string;11type: 'ch340' | 'hw348' | 'cp210x';12channels?: number;13}1415interface ApiInstructionsModalProps {16relay: Relay;17isOpen: boolean;18onClose: () => void;19}2021const CodeBlock = ({ payload }: { payload: object }) => {22const payloadString = JSON.stringify(payload, null, 2);2324const handleCopy = () => {25navigator.clipboard.writeText(payloadString);26toast.success('Payload copied to clipboard!');27};2829return (30<div className="relative bg-gray-900 text-white rounded-md p-4 font-mono text-sm my-2">31<Button variant="ghost" size="icon" className="absolute top-2 right-2 h-8 w-8" onClick={handleCopy}>32<ClipboardCopy className="h-4 w-4" />33</Button>34<pre><code>{payloadString}</code></pre>35</div>36);37};3839export function ApiInstructionsModal({ relay, isOpen, onClose }: ApiInstructionsModalProps) {40const [webhookUrl, setWebhookUrl] = useState('');41const isMultiChannel = relay.type === 'ch340' || relay.type === 'hw348' || relay.type === 'cp210x';4243useEffect(() => {44async function getToken() {45try {46const token = await invoke('get_webhook_token');47// Assuming the server runs on localhost:484848// This could be made configurable in the future49setWebhookUrl(`http://localhost:4848/webhook/${token}`);50} catch (error) {51console.error("Failed to get webhook token:", error);52setWebhookUrl('Could not retrieve webhook URL.');53}54}55if (isOpen) {56getToken();57}58}, [isOpen]);5960return (61<Dialog open={isOpen} onOpenChange={onClose}>62<DialogContent className="max-w-lg">63<DialogHeader>64<DialogTitle className="text-lg">API Instructions for {relay.id}</DialogTitle>65</DialogHeader>66<div className="grid grid-cols-1 md:grid-cols-2 gap-2 mt-2">67<div className="md:col-span-2">68<h3 className="font-semibold text-sm">Payloads</h3>69<p className="text-xs text-gray-500 mb-1">The body of your POST request must be a JSON object with one of the following structures.</p>7071<h4 className="font-medium text-sm">Standard Actions</h4>72<div className="grid grid-cols-1 md:grid-cols-2 gap-1">73<CodeBlock payload={{ id: relay.id, action: 'on', ...(isMultiChannel && { channel: 1 }) }} />74<CodeBlock payload={{ id: relay.id, action: 'off', ...(isMultiChannel && { channel: 1 }) }} />75</div>7677<h4 className="font-medium text-sm mt-2">Toggle Actions</h4>78<p className="text-xs text-gray-500 mb-1">79The <code>toggle</code> parameter inverts the action after a <code>period</code> (in milliseconds).80</p>81<div className="grid grid-cols-1 md:grid-cols-2 gap-1">82<CodeBlock payload={{ id: relay.id, action: 'on', toggle: true, period: 5000, ...(isMultiChannel && { channel: 1 }) }} />83<CodeBlock payload={{ id: relay.id, action: 'off', toggle: true, period: 5000, ...(isMultiChannel && { channel: 1 }) }} />84</div>8586{isMultiChannel && relay.channels && relay.channels > 1 && (87<p className="text-xs text-gray-500 mt-1">For this relay, you can change the <code>channel</code> value from 1 to {relay.channels}.</p>88)}89</div>90</div>91</DialogContent>92</Dialog>93);94}959697