Skip to content

Commit

Permalink
Add useGoConfig hook for client configuration
Browse files Browse the repository at this point in the history
Since we cannot use async in client components we have tor introduce a
hook for retrieving goConfig client side.

A test is added for proving how it functions.
  • Loading branch information
spaceo committed Nov 25, 2024
1 parent 22a840d commit 6067b7a
Show file tree
Hide file tree
Showing 6 changed files with 71 additions and 2 deletions.
1 change: 1 addition & 0 deletions .env.test
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ UNILOGIN_CLIENT_SECRET=XXX
UNILOGIN_SESSION_SECRET=XXX

NEXT_PUBLIC_APP_URL=https://hellboy.the-movie.com
UNILOGIN_WELLKNOWN_URL=https://hi-i-am-well-known-url.com
14 changes: 14 additions & 0 deletions __tests__/config.test.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { renderHook, waitFor } from "@testing-library/react"
import { describe } from "node:test"
import { expect, test } from "vitest"

import MissingConfigurationError from "@/lib/config/errors/MissingConfigurationError"
import goConfig from "@/lib/config/goConfig"
import useGoConfig from "@/lib/config/useGoConfig"

describe("Config test suite", () => {
test("That an error is thrown if we ask for unknown config", async () => {
Expand All @@ -14,4 +16,16 @@ describe("Config test suite", () => {
const appUrl = goConfig("app.url")
expect(appUrl).toBe("https://hellboy.the-movie.com")
})

test("That the client hook returns configuration as expected", async () => {
const { result } = renderHook(() =>
useGoConfig(["service.unilogin.wellknown.url", "search.item.limit"])
)

await waitFor(() => {})
expect(result.current).toEqual({
"search.item.limit": 12,
"service.unilogin.wellknown.url": "https://hi-i-am-well-known-url.com",
})
})
})
51 changes: 51 additions & 0 deletions lib/config/useGoConfig.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { useEffect, useState } from "react"

import goConfig from "./goConfig"
import { TConfigKey, resolvers } from "./resolvers"

const createPromisesFromConfig = (keys: TConfigKey[]) => {
// Get configuration resolvers.
// Turn all configuration resolvers into promises.
// So we can run them all together via Promise.all
return keys.map(key => {
return resolvers[key] instanceof Promise
? goConfig(key as TConfigKey)
: Promise.resolve(goConfig(key as TConfigKey))
})
}

// This functionality (useGoConfig) is used to retrieve configuration values from the client side.
// Only non sensitive configuration values should retrieved from the client side.

const useGoConfig = <K extends TConfigKey>(keys: K[]) => {
type GoConfigReturnType<K extends TConfigKey> = {
[key in K]: ReturnType<typeof goConfig>
}
const [values, setValues] = useState<GoConfigReturnType<K> | null>(null)

useEffect(() => {
if (values) return
const promises = createPromisesFromConfig(keys)

async function retrieveData() {
// Resolve all client configuration resolver promises
// And create an object with the configuration values keyed by the requested keys.
const confData = await Promise.all(promises)
return confData.reduce(
(acc: GoConfigReturnType<K>, value: ReturnType<typeof goConfig>, index: number) => {
return { ...acc, [keys[index]]: value }
},
{} as GoConfigReturnType<K>
)
}

retrieveData().then(data => {
if (!data) return
setValues(data)
})
}, [keys, values])

return values
}

export default useGoConfig
1 change: 1 addition & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"extends": "@tsconfig/create-react-app/tsconfig.json",
"compilerOptions": {
"types": ["vitest/globals"],
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
Expand Down
2 changes: 2 additions & 0 deletions vitest.config.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/// reference types=”vitest” />
import env from "@next/env"
import react from "@vitejs/plugin-react"
import tsconfigPaths from "vite-tsconfig-paths"
Expand All @@ -10,6 +11,7 @@ loadEnvConfig(process.cwd())
export default defineConfig({
plugins: [react(), tsconfigPaths()],
test: {
globals: true,
environment: "jsdom",
alias: {
"@/": new URL("./", import.meta.url).pathname,
Expand Down
4 changes: 2 additions & 2 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4227,7 +4227,7 @@

"@testing-library/react@^16.0.1":
version "16.0.1"
resolved "https://registry.npmjs.org/@testing-library/react/-/react-16.0.1.tgz"
resolved "https://registry.yarnpkg.com/@testing-library/react/-/react-16.0.1.tgz#29c0ee878d672703f5e7579f239005e4e0faa875"
integrity sha512-dSmwJVtJXmku+iocRhWOUFbrERC76TX2Mnf0ATODz8brzAZrMBbzLwQixlBSanZxR6LddK3eiwpSFZgDET1URg==
dependencies:
"@babel/runtime" "^7.12.5"
Expand Down Expand Up @@ -9338,7 +9338,7 @@ jsdoc-type-pratt-parser@^4.0.0:

jsdom@^25.0.1:
version "25.0.1"
resolved "https://registry.npmjs.org/jsdom/-/jsdom-25.0.1.tgz"
resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-25.0.1.tgz#536ec685c288fc8a5773a65f82d8b44badcc73ef"
integrity sha512-8i7LzZj7BF8uplX+ZyOlIz86V6TAsSs+np6m1kpW9u0JWi4z/1t+FzcK1aek+ybTnAC4KhBL4uXCNT0wcUIeCw==
dependencies:
cssstyle "^4.1.0"
Expand Down

0 comments on commit 6067b7a

Please sign in to comment.