reworked astro collections
This commit is contained in:
@@ -1,87 +0,0 @@
|
||||
import { defineCollection, z } from "astro:content";
|
||||
import qs from "qs";
|
||||
|
||||
// Define a custom content collection that loads data from Strapi
|
||||
const strapiPoleElementsLoader = defineCollection({
|
||||
// Async loader function that fetches data from Strapi API
|
||||
loader: async () => {
|
||||
// Get Strapi URL from environment variables or fallback to localhost
|
||||
const BASE_URL = import.meta.env.STRAPI_URL || "http://localhost:1337";
|
||||
const path = "/api/elements";
|
||||
const url = new URL(path, BASE_URL);
|
||||
|
||||
// Build query parameters using qs to populate cover image data
|
||||
url.search = qs.stringify({
|
||||
populate: {
|
||||
mainImage: {
|
||||
fields: ["url", "alternativeText"],
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
try {
|
||||
// Fetch articles from Strapi
|
||||
const poleElementsData = await fetch(url.href);
|
||||
|
||||
if (!poleElementsData.ok) {
|
||||
throw new Error(`Failed to fetch data from Strapi: ${poleElementsData.status} ${poleElementsData.statusText}`);
|
||||
}
|
||||
|
||||
const response = await poleElementsData.json();
|
||||
const { data } = response;
|
||||
|
||||
// Check if data is null or undefined
|
||||
if (!data) {
|
||||
throw new Error("No data received from Strapi API - the response was null or undefined");
|
||||
}
|
||||
|
||||
// Ensure data is an array
|
||||
const dataArray = Array.isArray(data) ? data : [data];
|
||||
|
||||
// Transform the API response into the desired data structure
|
||||
return dataArray
|
||||
.filter(item => item !== null && item !== undefined) // Filter out null/undefined items
|
||||
.map((item) => ({
|
||||
id: item.id?.toString() || "",
|
||||
name: item.name || "",
|
||||
title: item.name || "",
|
||||
description: item.description || "",
|
||||
createdAt: item.createdAt || "",
|
||||
updatedAt: item.updatedAt || "",
|
||||
publishedAt: item.publishedAt || "",
|
||||
mainImage: item.mainImage ? {
|
||||
id: Number(item.mainImage.id) || 0,
|
||||
documentId: item.mainImage.documentId || "",
|
||||
url: item.mainImage.url || "",
|
||||
alternativeText: item.mainImage.alternativeText || "",
|
||||
} : {
|
||||
id: 0,
|
||||
documentId: "",
|
||||
url: "",
|
||||
alternativeText: "",
|
||||
}
|
||||
}));
|
||||
} catch (error) {
|
||||
console.error("Error loading pole elements from Strapi:", error);
|
||||
return [];
|
||||
}
|
||||
},
|
||||
// Define the schema for type validation using Zod
|
||||
schema: z.object({
|
||||
id: z.string(),
|
||||
name: z.string(),
|
||||
title: z.string(),
|
||||
description: z.string(),
|
||||
createdAt: z.string(),
|
||||
updatedAt: z.string(),
|
||||
publishedAt: z.string(),
|
||||
mainImage: z.object({
|
||||
id: z.number(),
|
||||
documentId: z.string(),
|
||||
url: z.string(),
|
||||
alternativeText: z.string(),
|
||||
}),
|
||||
}),
|
||||
});
|
||||
|
||||
export default strapiPoleElementsLoader;
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
// Import necessary components and utilities
|
||||
import MarkdownComponent from "./MardownContent.astro";
|
||||
import { getStrapiMedia } from "../utils/strapi";
|
||||
import { getStrapiMedia } from "../lib/strapi";
|
||||
import { getStrapiBaseUrl } from "../config/strapi";
|
||||
import type { HTMLAttributes } from "astro/types";
|
||||
|
||||
@@ -18,19 +18,20 @@ const BASE_URL = getStrapiBaseUrl();
|
||||
<div {...otherProps}>
|
||||
{
|
||||
elements.map((poleElement) => (
|
||||
console.log(poleElement),
|
||||
<a href={`/elements/${poleElement.id}`} class="block">
|
||||
<article class="flex items-center bg-white rounded-lg shadow-lg overflow-hidden hover:shadow-xl transition-shadow duration-200">
|
||||
<img
|
||||
src={getStrapiMedia(
|
||||
poleElement.data.mainImage.url,
|
||||
poleElement.mainImage.url,
|
||||
BASE_URL,
|
||||
)}
|
||||
alt={poleElement.data.mainImage.alternativeText}
|
||||
alt={poleElement.mainImage.alternativeText}
|
||||
class="w-24 h-24 object-cover flex-shrink-0"
|
||||
/>
|
||||
<div class="p-4">
|
||||
<h2 class="text-xl font-bold">
|
||||
{poleElement.data.name}
|
||||
{poleElement.name}
|
||||
</h2>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
import strapiPoleElementsLoader from "./collections/strapiPoleElementsLoader.mjs";
|
||||
|
||||
// Export the collection for use in Astro pages
|
||||
export const collections = {
|
||||
poleElements: strapiPoleElementsLoader,
|
||||
};
|
||||
3
client/src/env.d.ts
vendored
Normal file
3
client/src/env.d.ts
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
interface ImportMetaEnv {
|
||||
readonly STRAPI_URL: string;
|
||||
}
|
||||
15
client/src/interfaces/poleElement.ts
Normal file
15
client/src/interfaces/poleElement.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
export default interface PoleElement {
|
||||
id: string;
|
||||
name: string;
|
||||
title: string;
|
||||
description: string;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
publishedAt: string;
|
||||
mainImage: {
|
||||
id: number;
|
||||
documentId: string;
|
||||
url: string;
|
||||
alternativeText: string;
|
||||
};
|
||||
}
|
||||
68
client/src/lib/strapi.ts
Normal file
68
client/src/lib/strapi.ts
Normal file
@@ -0,0 +1,68 @@
|
||||
interface Props {
|
||||
endpoint: string;
|
||||
query?: Record<string, string>;
|
||||
wrappedByKey?: string;
|
||||
wrappedByList?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches data from the Strapi API
|
||||
* @param endpoint - The endpoint to fetch from
|
||||
* @param query - The query parameters to add to the url
|
||||
* @param wrappedByKey - The key to unwrap the response from
|
||||
* @param wrappedByList - If the response is a list, unwrap it
|
||||
* @returns
|
||||
*/
|
||||
export default async function fetchApi<T>({
|
||||
endpoint,
|
||||
query,
|
||||
wrappedByKey,
|
||||
wrappedByList,
|
||||
}: Props): Promise<T> {
|
||||
if (endpoint.startsWith('/')) {
|
||||
endpoint = endpoint.slice(1);
|
||||
}
|
||||
const strapiUrl = import.meta.env.STRAPI_URL || process.env.STRAPI_URL || "http://localhost:1337";
|
||||
console.log(strapiUrl);
|
||||
const url = new URL(`${strapiUrl}/api/${endpoint}`);
|
||||
|
||||
if (query) {
|
||||
Object.entries(query).forEach(([key, value]) => {
|
||||
url.searchParams.append(key, value);
|
||||
});
|
||||
}
|
||||
|
||||
try {
|
||||
const res = await fetch(url.toString());
|
||||
|
||||
if (!res.ok) {
|
||||
throw new Error(`HTTP error! status: ${res.status}`);
|
||||
}
|
||||
|
||||
let data = await res.json();
|
||||
|
||||
if (wrappedByKey) {
|
||||
data = data[wrappedByKey];
|
||||
}
|
||||
|
||||
if (wrappedByList) {
|
||||
data = data[0];
|
||||
}
|
||||
|
||||
return data as T;
|
||||
} catch (error) {
|
||||
console.error('Error fetching from Strapi API:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
// Helper function to handle media URLs from Strapi
|
||||
export function getStrapiMedia(url: string | null, baseUrl: string) {
|
||||
if (url == null) return null;
|
||||
// Return as-is if it's a data URL (base64)
|
||||
if (url.startsWith("data:")) return url;
|
||||
// Return as-is if it's an absolute URL
|
||||
if (url.startsWith("http") || url.startsWith("//")) return url;
|
||||
// Prepend baseUrl for relative URLs
|
||||
return `${baseUrl}${url}`;
|
||||
}
|
||||
@@ -1,14 +1,15 @@
|
||||
---
|
||||
// Import necessary components and utilities
|
||||
import Layout from "../layouts/Layout.astro";
|
||||
import { getCollection } from "astro:content";
|
||||
import PoleElementsList from "../components/PoleElementsList.astro";
|
||||
import { getStrapiBaseUrl } from "../config/strapi";
|
||||
|
||||
// Fetch all posts from Strapi using Astro's content collection
|
||||
const strapiPoleElements = await getCollection("poleElements");
|
||||
// Get Strapi URL from global config
|
||||
const BASE_URL = getStrapiBaseUrl();
|
||||
import fetchApi from '../lib/strapi';
|
||||
import type PoleElement from "../interfaces/poleElement";
|
||||
|
||||
const strapiPoleElements = await fetchApi<PoleElement[]>({
|
||||
endpoint: 'elements?populate=*', // the content type to fetch
|
||||
wrappedByKey: 'data', // the key to unwrap the response
|
||||
});
|
||||
---
|
||||
|
||||
<Layout title="Pole Elements" description="Pole Elements">
|
||||
|
||||
@@ -1,20 +1,30 @@
|
||||
---
|
||||
import { getCollection } from 'astro:content';
|
||||
import MardownContent from '../../components/MardownContent.astro';
|
||||
import Layout from '../../layouts/Layout.astro';
|
||||
|
||||
// 1. Genera una nueva ruta para cada entrada de colección
|
||||
export async function getStaticPaths() {
|
||||
const poleElements = await getCollection('poleElements');
|
||||
return poleElements.map(entry => ({
|
||||
params: { id: entry.id }, props: { entry },
|
||||
}));
|
||||
}
|
||||
// 2. Para tu plantilla, puedes obtener la entrada directamente de la prop
|
||||
const { entry } = Astro.props;
|
||||
---
|
||||
import fetchApi from '../../lib/strapi';
|
||||
import type PoleElement from '../../interfaces/poleElement';
|
||||
|
||||
<Layout title={entry.data.title} description={entry.data.description}>
|
||||
<h1>{entry.data.title}</h1>
|
||||
<MardownContent content={entry.data.description} />
|
||||
const { id } = Astro.params;
|
||||
|
||||
let poleElement: PoleElement;
|
||||
|
||||
try {
|
||||
poleElement = await fetchApi<PoleElement>({
|
||||
endpoint: 'elements',
|
||||
wrappedByKey: 'data',
|
||||
wrappedByList: true,
|
||||
query: {
|
||||
'populate': '*',
|
||||
'filters[id][$eq]': id || '',
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
return Astro.redirect('/404');
|
||||
}
|
||||
|
||||
---
|
||||
<Layout title={poleElement.name} description={poleElement.description}>
|
||||
<h1>{poleElement.name}</h1>
|
||||
{poleElement.description && <MardownContent content={poleElement.description} />}
|
||||
</Layout>
|
||||
@@ -1,10 +0,0 @@
|
||||
// Helper function to handle media URLs from Strapi
|
||||
export function getStrapiMedia(url: string | null, baseUrl: string) {
|
||||
if (url == null) return null;
|
||||
// Return as-is if it's a data URL (base64)
|
||||
if (url.startsWith("data:")) return url;
|
||||
// Return as-is if it's an absolute URL
|
||||
if (url.startsWith("http") || url.startsWith("//")) return url;
|
||||
// Prepend baseUrl for relative URLs
|
||||
return `${baseUrl}${url}`;
|
||||
}
|
||||
Reference in New Issue
Block a user