Skip to content

Commit

Permalink
using the new data loader from minreact
Browse files Browse the repository at this point in the history
  • Loading branch information
robertfmurdock committed Jul 10, 2023
1 parent 382d518 commit 69293a5
Show file tree
Hide file tree
Showing 9 changed files with 111 additions and 77 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package com.zegreatrob.coupling.client.components

import com.zegreatrob.minreact.create
import com.zegreatrob.minreact.ReactFunc
import com.zegreatrob.minreact.nfc
import com.zegreatrob.react.dataloader.DataLoadState
import com.zegreatrob.react.dataloader.DataLoader
import com.zegreatrob.react.dataloader.EmptyState
import com.zegreatrob.react.dataloader.PendingState
Expand All @@ -9,23 +11,40 @@ import kotlinx.coroutines.delay
import kotlinx.coroutines.withTimeout
import react.ChildrenBuilder
import react.ElementType
import react.Fragment
import react.Props
import react.ReactNode
import react.create
import react.dom.html.ReactHTML.div

fun <T : Props> ChildrenBuilder.waitForAsyncReactComponent(
getComponent: () -> ElementType<T>?,
useComponent: ChildrenBuilder.(ElementType<T>) -> Unit,
useComponent: (ElementType<T>) -> ReactNode,
) {
+DataLoader({ waitForComponent(getComponent) }, { null }) { state ->
when (state) {
is EmptyState -> div { +"Preparing component" }
is PendingState -> div { +"Pending component" }
is ResolvedState ->
state.result
?.let { useComponent(it) }
?: div { +"Error finding component." }
DataLoader({ waitForComponent(getComponent) }, { null }, child = { state ->
Fragment.create {
AsyncReactComponent(state, useComponent)
}
}.create()
})
}

external interface AsyncReactComponentProps<T : Props> : Props {
var state: DataLoadState<ElementType<T>?>
var useComponent: (ElementType<T>) -> ReactNode
}

@ReactFunc
val AsyncReactComponent by nfc<AsyncReactComponentProps<Props>> { props ->
val state = props.state
val useComponent = props.useComponent
when (state) {
is EmptyState -> div { +"Preparing component" }
is PendingState -> div { +"Pending component" }
is ResolvedState ->
state.result
?.let { Fragment { child(useComponent(it)) } }
?: div { +"Error finding component." }
}
}

private suspend fun <T : Props> waitForComponent(getComponent: () -> ElementType<T>?): ElementType<T>? =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import kotlinx.coroutines.async
import kotlinx.coroutines.await
import react.ElementType
import react.FC
import react.create
import kotlin.js.Json
import kotlin.js.Promise
import kotlin.js.json
Expand All @@ -22,7 +23,7 @@ val DndProvider: ElementType<DnDProvideProps> = FC { props ->
+props.children
} else {
waitForAsyncReactComponent({ runCatching { reactDnd.getCompleted().dndProvider }.getOrNull() }) { component ->
component { +props }
component.create { +props }
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@ import org.w3c.dom.get
import react.ElementType
import react.FC
import react.Props
import react.create

val Markdown: ElementType<Props> = FC { props ->
waitForAsyncReactComponent({ window["ReactMarkdown"].unsafeCast<ElementType<Props>?>() }) { component ->
component { +props }
component.create { +props }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import com.zegreatrob.coupling.action.pairassignmentdocument.DeletePairAssignmen
import com.zegreatrob.coupling.client.components.Controls
import com.zegreatrob.coupling.client.components.ServerMessage
import com.zegreatrob.coupling.client.components.external.reactdnd.DndProvider
import com.zegreatrob.coupling.client.components.external.reactdndhtml5backend.ReactDndHtml5BackendModule
import com.zegreatrob.coupling.client.components.external.reactdndhtml5backend.html5BackendDeferred
import com.zegreatrob.coupling.client.components.party.PartyBrowser
import com.zegreatrob.coupling.client.components.player.PlayerRoster
Expand All @@ -14,8 +15,8 @@ import com.zegreatrob.coupling.model.pairassignmentdocument.players
import com.zegreatrob.coupling.model.party.PartyDetails
import com.zegreatrob.coupling.model.player.Player
import com.zegreatrob.minreact.ReactFunc
import com.zegreatrob.minreact.add
import com.zegreatrob.minreact.nfc
import com.zegreatrob.react.dataloader.DataLoadState
import com.zegreatrob.react.dataloader.DataLoader
import com.zegreatrob.react.dataloader.EmptyState
import com.zegreatrob.react.dataloader.PendingState
Expand All @@ -24,6 +25,7 @@ import csstype.PropertiesBuilder
import emotion.css.ClassName
import react.Props
import react.PropsWithChildren
import react.PropsWithValue
import react.dom.html.ReactHTML.div
import web.cssom.Color
import web.cssom.Display
Expand Down Expand Up @@ -66,22 +68,31 @@ val PairAssignments by nfc<PairAssignmentsProps> { props ->
}

val Html5DndProvider by nfc<PropsWithChildren> { props ->
add(
DataLoader({ html5BackendDeferred.await() }, { null }) { state ->
when (state) {
is EmptyState -> div { +"Preparing component" }
is PendingState -> div { +"Pending component" }
is ResolvedState -> state.result?.let {
DndProvider {
backend = it.html5Backend
+props.children
}
}
}
},
DataLoader(
getDataAsync = { html5BackendDeferred.await() },
errorData = { null },
child = { state -> DndProviderLoading.create(value = state, children = { +props.children }) },
)
}

external interface DndProviderLoadingProps :
PropsWithValue<DataLoadState<ReactDndHtml5BackendModule?>>,
PropsWithChildren

@ReactFunc
val DndProviderLoading by nfc<DndProviderLoadingProps> { props ->
when (val state = props.value) {
is EmptyState -> div { +"Preparing component" }
is PendingState -> div { +"Pending component" }
is ResolvedState -> state.result?.let {
DndProvider {
backend = it.html5Backend
+props.children
}
}
}
}

private fun PropertiesBuilder.pairAssignmentStyles() {
display = Display.inlineBlock
minHeight = 100.vh
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package com.zegreatrob.coupling.client.graphql
import com.zegreatrob.coupling.client.components.external.auth0.react.useAuth0Data
import com.zegreatrob.coupling.client.components.external.w3c.WindowFunctions
import com.zegreatrob.coupling.client.routing.PageProps
import com.zegreatrob.minreact.add
import com.zegreatrob.minreact.nfc
import com.zegreatrob.react.dataloader.DataLoadState
import com.zegreatrob.react.dataloader.DataLoader
Expand All @@ -13,6 +12,8 @@ import com.zegreatrob.react.dataloader.ResolvedState
import emotion.react.css
import kotlinx.browser.window
import org.w3c.dom.get
import react.PropsWithValue
import react.create
import react.dom.html.ReactHTML.div
import web.cssom.TextAlign
import web.cssom.vh
Expand All @@ -26,17 +27,21 @@ val GraphIQLPage by nfc<PageProps> {
textAlign = TextAlign.left
height = 100.vh
}
add(
DataLoader({ auth0Data.getAccessTokenSilently() }, { "" }) { state: DataLoadState<String> ->
when (state) {
is EmptyState -> div()
is PendingState -> +"Loading authorization..."
is ResolvedState -> GraphiQL {
this.editorTheme = "dracula"
this.fetcher = createGraphiQLFetcher(graphQlUrl, state.result)
}
}
},
DataLoader(
getDataAsync = { auth0Data.getAccessTokenSilently() },
errorData = { "" },
child = GraphIQLPageLoader::create,
)
}
}

val GraphIQLPageLoader by nfc<PropsWithValue<DataLoadState<String>>> { props ->
when (val state = props.value) {
is EmptyState -> div()
is PendingState -> +"Loading authorization..."
is ResolvedState -> GraphiQL {
this.editorTheme = "dracula"
this.fetcher = createGraphiQLFetcher(graphQlUrl, state.result)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,13 @@ import org.w3c.dom.get
import react.ElementType
import react.FC
import react.Props
import react.create
import kotlin.js.Json
import kotlin.js.Promise

val GraphiQL: ElementType<GraphiQLProps> = FC { props ->
waitForAsyncReactComponent({ window["GraphiQL"].unsafeCast<ElementType<Props>?>() }) { component ->
component { +props }
component.create { +props }
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import com.zegreatrob.coupling.client.CommandDispatcher
import com.zegreatrob.coupling.client.DecoratedDispatchFunc
import com.zegreatrob.coupling.client.components.DispatchFunc
import com.zegreatrob.minreact.ReactFunc
import com.zegreatrob.minreact.add
import com.zegreatrob.minreact.nfc
import com.zegreatrob.react.dataloader.DataLoadState
import com.zegreatrob.react.dataloader.DataLoader
Expand All @@ -13,9 +12,10 @@ import com.zegreatrob.react.dataloader.ReloadFunc
import com.zegreatrob.react.dataloader.ResolvedState
import com.zegreatrob.testmints.action.async.SuspendAction
import com.zegreatrob.testmints.action.async.execute
import react.ChildrenBuilder
import react.Props
import react.PropsWithValue
import react.ReactNode
import react.create
import react.useCallback

external interface CouplingQueryProps<R> : Props {
Expand All @@ -36,24 +36,18 @@ val CouplingQuery by nfc<CouplingQueryProps<Any>> { props ->
toNode(tools.reloadData, dispatchFunc, value)
}
}
add(
DataLoader(getDataAsync, { null }) { state: DataLoadState<ReactNode?> ->
animationFrame(state)
},
)
DataLoader(getDataAsync, { null }, child = CouplingQueryLoadState::create)
}

private fun ChildrenBuilder.animationFrame(state: DataLoadState<ReactNode?>) =
val CouplingQueryLoadState by nfc<PropsWithValue<DataLoadState<ReactNode?>>> { props ->
val state = props.value
animationFrame {
this.state = state
if (state is ResolvedState) {
resolvedComponent(state)
when (val result = state.result) {
null -> notFoundContent()
else -> +result
}
}
}

private fun ChildrenBuilder.resolvedComponent(state: ResolvedState<ReactNode?>) {
when (val result = state.result) {
null -> notFoundContent()
else -> +result
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,15 @@ import com.zegreatrob.coupling.client.components.external.reactmarkdown.Markdown
import com.zegreatrob.coupling.client.components.loadMarkdownString
import com.zegreatrob.coupling.client.components.slack.ReturnToCouplingButton
import com.zegreatrob.coupling.client.routing.PageProps
import com.zegreatrob.minreact.add
import com.zegreatrob.minreact.nfc
import com.zegreatrob.react.dataloader.DataLoadState
import com.zegreatrob.react.dataloader.DataLoader
import com.zegreatrob.react.dataloader.EmptyState
import com.zegreatrob.react.dataloader.PendingState
import com.zegreatrob.react.dataloader.ResolvedState
import react.Props
import react.PropsWithValue
import react.create
import react.router.dom.useSearchParams

val SlackCallbackPage by nfc<PageProps> { props ->
Expand All @@ -24,31 +26,31 @@ val SlackCallbackPage by nfc<PageProps> { props ->
if (code == null || state == null) {
+"code and state missing"
} else {
add(
DataLoader(
getDataAsync = {
props.commander.tracingDispatcher().sdk.perform(
GrantSlackAccessCommand(code, state),
)
},
errorData = { VoidResult.Rejected },
children = {
when (it) {
is EmptyState -> +"Empty"
is PendingState -> +"Pending"
is ResolvedState -> when (it.result) {
VoidResult.Accepted -> SlackInstallSuccess {}
VoidResult.Rejected -> +"Rejected"
CommandResult.Unauthorized -> +"Unauthorized"
}
}
},
),
DataLoader(
getDataAsync = {
props.commander.tracingDispatcher().sdk.perform(
GrantSlackAccessCommand(code, state),
)
},
errorData = { VoidResult.Rejected },
child = SlackCallbackLoadContent::create,
)
}
}
}

val SlackCallbackLoadContent by nfc<PropsWithValue<DataLoadState<VoidResult>>> { props ->
when (val data = props.value) {
is EmptyState -> +"Empty"
is PendingState -> +"Pending"
is ResolvedState -> when (data.result) {
VoidResult.Accepted -> SlackInstallSuccess {}
VoidResult.Rejected -> +"Rejected"
CommandResult.Unauthorized -> +"Unauthorized"
}
}
}

val SlackInstallSuccess by nfc<Props> {
Markdown { +loadMarkdownString("InstallSuccess") }
ReturnToCouplingButton {
Expand Down
2 changes: 1 addition & 1 deletion gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ com-benasher44-uuid = "com.benasher44:uuid:0.7.1"
com-fasterxml-jackson-core-jackson-databind = "com.fasterxml.jackson.core:jackson-databind:2.15.2"
com-github-ajalt-clikt-clikt = "com.github.ajalt.clikt:clikt:4.0.0"
com-soywiz-korlibs-klock = "com.soywiz.korlibs.klock:klock:4.0.8"
com-zegreatrob-jsmints-jsmints-bom = "com.zegreatrob.jsmints:jsmints-bom:4.2.1"
com-zegreatrob-jsmints-jsmints-bom = "com.zegreatrob.jsmints:jsmints-bom:4.3.0"
com-zegreatrob-testmints-testmints-bom = "com.zegreatrob.testmints:testmints-bom:10.0.1"
io-github-microutils-kotlin-logging = "io.github.microutils:kotlin-logging:3.0.5"
io-ktor-ktor-bom = "io.ktor:ktor-bom:2.3.2"
Expand Down

0 comments on commit 69293a5

Please sign in to comment.