// EXPERIMENTAL: This is a work in progress and may not work as expected. import { useMatch, useParams } from 'react-router-dom'; import Timeline from '../components/timeline'; import useTitle from '../utils/useTitle'; const LIMIT = 20; let nextUrl = null; function Public() { const isLocal = !!useMatch('/p/l/:instance'); const params = useParams(); const { instance = '' } = params; const title = `${instance} (${isLocal ? 'local' : 'federated'})`; useTitle(title, `/p/${instance}`); async function fetchPublic(firstLoad) { const url = firstLoad ? `https://${instance}/api/v1/timelines/public?limit=${LIMIT}&local=${isLocal}` : nextUrl; if (!url) return { values: [], done: true }; const response = await fetch(url); let value = await response.json(); if (value) { value = camelCaseKeys(value); } const done = !response.headers.has('link'); nextUrl = done ? null : response.headers.get('link').match(/<(.+?)>; rel="next"/)?.[1]; console.debug({ url, value, done, nextUrl, }); return { value, done }; } return ( ); } function camelCaseKeys(obj) { if (Array.isArray(obj)) { return obj.map((item) => camelCaseKeys(item)); } return new Proxy(obj, { get(target, prop) { let value = undefined; if (prop in target) { value = target[prop]; } if (!value) { const snakeCaseProp = prop.replace( /([A-Z])/g, (g) => `_${g.toLowerCase()}`, ); if (snakeCaseProp in target) { value = target[snakeCaseProp]; } } if (value && typeof value === 'object') { return camelCaseKeys(value); } return value; }, }); } export default Public;