magic: added a way for running async functions in the top level jsx code
This commit is contained in:
+11
-5
@@ -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
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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`)}`))
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user