| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250 |
- 'use client'
- import apiMethods from '@/lib/api/aura/methods'
- import { useEffect, useState } from 'react'
- import { Fence } from '../Fence'
- import Spinner from '../icons/spinner'
- import { Totem, TotemAccordion } from '../Totem'
- import ApiParameterDisplay from './apiParams'
- import ApiExampleSelector from './exampleSelector'
- import LanguageRenderer from './languageRenderer'
- import Responce from './responce'
- const ApiComponentWrapper = (args) => {
- const api = apiMethods[args.method]
- const [screenWidth, setScreenWidth] = useState(null)
- const [responce, setResponce] = useState(null)
- const [isLoading, setIsLoading] = useState(false)
- const [selectedExample, setSelectedExample] = useState(-1)
- const [activeEndpoint, setActiveEndpoint] = useState("https://api.devnet.solana.com")
- useEffect(() => {
- // Load saved endpoint from localStorage on component mount
- try {
- const savedEndpoint = localStorage.getItem('customEndPoint')
- if (savedEndpoint) {
- setActiveEndpoint(savedEndpoint)
- }
- } catch (error) {
- console.warn('Failed to load endpoint from localStorage:', error)
- }
- }, [])
- const handleSetExample = (index) => {
- if (index == -1) {
- setBody((prev) => {
- let newBody = { ...prev }
- newBody.params = {}
- return newBody
- })
- setSelectedExample(index)
- return
- }
- setBody((prev) => {
- let newBody = { ...prev }
- newBody.params = api.examples[index].body.params
- return newBody
- })
- setSelectedExample(index)
-
- // Update endpoint based on example chain if available
- if (api.examples[index].chain) {
- const chainEndpoint = api.examples[index].chain === 'devnet'
- ? 'https://api.devnet.solana.com'
- : api.examples[index].chain === 'mainnet'
- ? 'https://api.mainnet-beta.solana.com'
- : activeEndpoint
-
- setActiveEndpoint(chainEndpoint)
- try {
- localStorage.setItem('customEndPoint', chainEndpoint)
- } catch (error) {
- console.warn('Failed to save endpoint to localStorage:', error)
- }
- }
- }
- const [body, setBody] = useState({
- jsonrpc: '2.0',
- id: '1',
- method: api.method,
- params: {},
- })
- // Track screen width on resize (client-side only)
- useEffect(() => {
- const handleResize = () => {
- setScreenWidth(window.innerWidth)
- }
- // Set the initial screen width when the component mounts
- if (screenWidth === null) {
- setScreenWidth(window.innerWidth)
- }
- window.addEventListener('resize', handleResize)
- return () => window.removeEventListener('resize', handleResize)
- }, [screenWidth])
- if (screenWidth === null) {
- return null
- }
- const isLargeScreen = screenWidth >= 1536 // 2xl breakpoint
- const handleSetParam = (path, value) => {
- setBody((prev) => {
- const newBody = { ...prev }
- // Recursive function to traverse and update or clean up fields
- const updateField = (obj, path) => {
- const key = path[0]
- if (path.length === 1) {
- // If we are at the target field
- if (
- !value ||
- (Array.isArray(value) && value.every((v) => v === ''))
- ) {
- // Delete the field if value is null, undefined, or an empty key-value pair
- delete obj[key]
- } else {
- // Otherwise, set the value
- obj[key] = value
- }
- } else {
- // Ensure the parent key exists and is an object
- if (!obj[key] || typeof obj[key] !== 'object') {
- obj[key] = {}
- }
- // Recurse into the nested object
- updateField(obj[key], path.slice(1))
- // Remove the parent key if it becomes empty after the update
- if (Object.keys(obj[key]).length === 0) {
- delete obj[key]
- }
- }
- }
- updateField(newBody.params, path)
- return newBody
- })
- }
- const handleTryItOut = async () => {
- setResponce(null)
- setIsLoading(true)
- try {
- if (!activeEndpoint) {
- throw new Error('Endpoint URL is required')
- }
-
- try {
- new URL(activeEndpoint)
- } catch {
- throw new Error('Invalid endpoint URL. Please enter a valid URL starting with http:// or https://')
- }
- const res = await fetch(activeEndpoint, {
- method: 'POST',
- headers: {
- 'Content-Type': 'application/json',
- },
- body: JSON.stringify(body),
- })
- if (!res.ok) {
- throw new Error(`HTTP error! status: ${res.status}`)
- }
- const resJson = await res.json()
- setResponce(resJson)
- } catch (error) {
- setResponce({
- error: {
- message: error.message || 'Failed to fetch. Please check your endpoint URL and try again.'
- }
- })
- } finally {
- setIsLoading(false)
- }
- }
- return (
- <div>
- <div className="flex w-full flex-col-reverse gap-8 2xl:flex-row ">
- <div className="flex w-full flex-col gap-8 2xl:w-1/2">
- {api.examples && isLargeScreen && (
- <ApiExampleSelector
- examples={api.examples}
- selectedExample={selectedExample}
- handleSetExample={(index) => handleSetExample(index)}
- />
- )}
- <ApiParameterDisplay
- params={api.params}
- body={body.params}
- setParam={(path, value) => {
- handleSetParam(path, value)
- }}
- />
- <button
- className="block min-w-[150px] rounded-lg border border-gray-200 px-4 py-3 text-sm focus:border-blue-500 focus:outline-none focus:ring-2 focus:ring-blue-500/50 disabled:pointer-events-none disabled:opacity-50 dark:border-neutral-700 dark:bg-neutral-900 dark:text-neutral-300 dark:placeholder-neutral-500 2xl:hidden"
- onClick={handleTryItOut}
- >
- {isLoading ? <Spinner className="h-6 w-6" /> : 'Try it out'}
- </button>
- {responce && !isLargeScreen && <Responce responce={responce} />}
- </div>
- <div className="flex w-full flex-col items-end gap-4 2xl:w-1/2">
- {api.examples && !isLargeScreen && (
- <ApiExampleSelector
- examples={api.examples}
- selectedExample={selectedExample}
- handleSetExample={(index) => handleSetExample(index)}
- />
- )}
- <LanguageRenderer
- api={api}
- body={body}
- activeEndpoint={activeEndpoint}
- setActiveEndpoint={(endpoint) => setActiveEndpoint(endpoint)}
- noUmi={args.noUmi}
- />
- <button
- className="hidden min-w-[150px] items-center justify-center rounded-lg border border-gray-200 px-4 py-3 text-sm focus:border-blue-500 focus:outline-none focus:ring-2 focus:ring-blue-500/50 disabled:pointer-events-none disabled:opacity-50 dark:border-neutral-700 dark:bg-neutral-900 dark:text-neutral-300 dark:placeholder-neutral-500 2xl:flex"
- onClick={handleTryItOut}
- >
- {isLoading ? <Spinner className="h-6 w-6" /> : 'Try it out'}
- </button>
- {responce && isLargeScreen && <Responce responce={responce} />}
- </div>
- </div>
- {api.exampleResponse && (
- <>
- <hr className="my-8 border-gray-200 dark:border-neutral-700" />
- <Totem className="w-full">
- <TotemAccordion title="Example Response">
- <Fence className="w-full" language="python">
- {JSON.stringify(api.exampleResponse, null, 2)}
- </Fence>
- </TotemAccordion>
- </Totem>
- </>
- )}
- </div>
- )
- }
- export default ApiComponentWrapper
|