diff options
Diffstat (limited to 'src/App.tsx')
| -rw-r--r-- | src/App.tsx | 107 |
1 files changed, 82 insertions, 25 deletions
diff --git a/src/App.tsx b/src/App.tsx index aaeba0a..3472fd0 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,34 +1,91 @@ -import { useState } from 'react' -import reactLogo from './assets/react.svg' -import viteLogo from '/vite.svg' +import { useEffect, useState } from 'react' +import { fetchDrupalResource } from './lib/drupalClient' import './App.css' +type DrupalArticle = { + id: string + attributes?: { + title?: string + status?: boolean + created?: string + } +} + +type DrupalCollectionResponse<T> = { + data: T[] +} + +type DrupalJsonApiEntryPoint = { + links: Record<string, { href: string }> +} + function App() { - const [count, setCount] = useState(0) + const [articles, setArticles] = useState<DrupalArticle[]>([]) + const [resourcePath, setResourcePath] = useState<string | null>(null) + const [isLoading, setIsLoading] = useState(true) + const [error, setError] = useState<string | null>(null) + + useEffect(() => { + const loadArticles = async () => { + try { + setIsLoading(true) + setError(null) + + const entryPoint = await fetchDrupalResource<DrupalJsonApiEntryPoint>('') + const nodeResources = Object.keys(entryPoint.links).filter((key) => key.startsWith('node--')) + + if (nodeResources.length === 0) { + throw new Error('No node resources found in JSON:API. Create a content type (for example Article) and ensure JSON:API is enabled.') + } + + const selectedNodeResource = nodeResources.includes('node--article') ? 'node--article' : nodeResources[0] + const selectedPath = `/${selectedNodeResource.replace('--', '/')}` + + setResourcePath(selectedPath) + + const response = await fetchDrupalResource<DrupalCollectionResponse<DrupalArticle>>(selectedPath) + setArticles(response.data) + } catch (loadError) { + const message = loadError instanceof Error ? loadError.message : 'Failed to load articles from Drupal.' + setError(message) + } finally { + setIsLoading(false) + } + } + + void loadArticles() + }, []) return ( - <> - <div className="flex gap-8 justify-center mb-8"> - <a href="https://vite.dev" target="_blank" rel="noreferrer" className="hover:drop-shadow-lg transition-all"> - <img src={viteLogo} className="h-24 w-24" alt="Vite logo" /> - </a> - <a href="https://react.dev" target="_blank" rel="noreferrer" className="hover:drop-shadow-lg transition-all"> - <img src={reactLogo} className="h-24 w-24" alt="React logo" /> - </a> - </div> - <h1>Vite + React</h1> - <div className="card"> - <button onClick={() => setCount((count) => count + 1)}> - count is {count} - </button> - <p> - Edit <code>src/App.tsx</code> and save to test HMR + <main> + <h1 className="mb-4 text-2xl font-bold">Articles</h1> + {!isLoading && !error && resourcePath && <p>Using resource: {resourcePath}</p>} + + {isLoading && <p>Loading articles…</p>} + + {error && ( + <p role="alert" className="text-red-600"> + Could not fetch articles: {error} </p> - </div> - <p className="read-the-docs"> - Click on the Vite and React logos to learn more - </p> - </> + )} + + {!isLoading && !error && articles.length === 0 && ( + <p>Connected to Drupal, but no articles were returned.</p> + )} + + {!isLoading && !error && articles.length > 0 && ( + <ul style={{ textAlign: 'left' }}> + {articles.map((article) => ( + <li key={article.id}> + <strong>{article.attributes?.title ?? '(Untitled)'}</strong> + <div>ID: {article.id}</div> + <div>Status: {article.attributes?.status ? 'Published' : 'Unpublished'}</div> + {article.attributes?.created && <div>Created: {new Date(article.attributes.created).toLocaleString()}</div>} + </li> + ))} + </ul> + )} + </main> ) } |
