magic: added a way for running async functions in the top level jsx code

This commit is contained in:
2023-01-11 21:38:37 +01:00
parent 71280fba5c
commit fab8398a7a
8 changed files with 91 additions and 44 deletions
+11 -5
View File
@@ -1,20 +1,26 @@
import renderToString from 'preact-render-to-string'
// import { App } from './App'
import { MetadataContext, ServerContext } from './hooks'
import { ServerAsyncCallbacksContext, DatabaseContext, MetadataContext, ServerContext } from './hooks'
import { RenderedPage } from '../shared/ssr'
import { RenderedPage, ServerAsyncCallback } from '../shared/ssr'
import { App } from './App'
import { DatabaseConnection } from '../shared/database'
export default (url: string): RenderedPage => {
export default (url: string, db: DatabaseConnection): RenderedPage => {
const metadata = {}
const asyncCallbacks: ServerAsyncCallback[] = []
const html = renderToString(
<MetadataContext.Provider value={metadata}>
<ServerContext.Provider value={true}>
<App url={url} />
<DatabaseContext.Provider value={db}>
<ServerAsyncCallbacksContext.Provider value={asyncCallbacks}>
<App url={url} />
</ServerAsyncCallbacksContext.Provider>
</DatabaseContext.Provider>
</ServerContext.Provider>
</MetadataContext.Provider>
)
return { html, metadata }
return { html, metadata, asyncCallbacks }
}
+12 -1
View File
@@ -1,7 +1,9 @@
import { StateUpdater, useEffect, useState } from 'preact/hooks'
import { StateUpdater, useContext, useEffect, useState } from 'preact/hooks'
import { createContext } from 'preact'
import { prependBaseUrl } from '../shared/utils'
import { DatabaseConnection } from '../shared/database'
import { ServerAsyncCallback } from '../shared/ssr'
type Metadata = {
title?: string
@@ -13,6 +15,8 @@ export const MetadataContext = createContext<Metadata>({})
export const ServerContext = createContext<boolean>(false)
export const ClientContext = createContext<boolean>(false)
export const DatabaseContext = createContext<DatabaseConnection | null>(null)
type RefreshFunction = () => AbortController
type HeuristicStateUpdater<S> = StateUpdater<S>
@@ -73,3 +77,10 @@ export const useListResource = <T,>(
return [list, refreshList, setItemHeuristic, setListHeuristic]
}
export const ServerAsyncCallbacksContext = createContext<ServerAsyncCallback[]>([])
export const useServerAsyncCallback = (fn: () => Promise<void>) => {
const registeredAsyncCallbacks = useContext(ServerAsyncCallbacksContext)
registeredAsyncCallbacks.push(fn)
}
+12 -4
View File
@@ -7,7 +7,7 @@ import { Header } from '../components/Header'
import { MarkdownEditor } from '../components/MarkdownEditor'
import { Problem } from '../components/Problem'
import { Solution } from '../components/Solution'
import { MetadataContext, useListResource, useResource } from '../hooks'
import { MetadataContext, useListResource, useResource, ServerContext, DatabaseContext, useServerAsyncCallback } from '../hooks'
import { useCurrentUser } from '../hooks/useCurrentUser'
type RouteProps = {
@@ -16,8 +16,16 @@ type RouteProps = {
export const ProblemPage = ({ id }: RouteProps) => {
const metadata = useContext(MetadataContext)
metadata.title = `Problem ${id}`
metadata.description = 'Bacheca di problemi del PHC'
const db = useContext(DatabaseContext)
if (db) {
useServerAsyncCallback(async () => {
const problem = await db.getProblem(id)
if (problem) {
metadata.title = `PHC Problemi | ${problem.title}`
metadata.description = problem.content
}
})
}
const [user] = useCurrentUser()
@@ -25,7 +33,7 @@ export const ProblemPage = ({ id }: RouteProps) => {
const [problem, refreshProblem] = useResource<ProblemModel | null>(`/api/problem/${id}`, null, problem => {
if (problem === null) {
route(prependBaseUrl('/'))
route(prependBaseUrl(`/error?message=${encodeURIComponent(`Il problema "${id}" non esiste`)}`))
}
})