Skip to content
This repository was archived by the owner on Sep 30, 2024. It is now read-only.

[WIP] feat: add generalized redirect AuthAction #2

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/AuthAction.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ const AuthAction = {
RETURN_NULL: 'returnNull',
REDIRECT_TO_LOGIN: 'redirectToLogin',
REDIRECT_TO_APP: 'redirectToApp',
REDIRECT: 'redirect',
}

export default AuthAction
1 change: 1 addition & 0 deletions src/__tests__/AuthAction.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ describe('index.js: AuthAction', () => {
RETURN_NULL: 'returnNull',
REDIRECT_TO_LOGIN: 'redirectToLogin',
REDIRECT_TO_APP: 'redirectToApp',
REDIRECT: 'redirect',
})
})
})
1 change: 1 addition & 0 deletions src/__tests__/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,7 @@ describe('index.js: AuthAction', () => {
RETURN_NULL: 'returnNull',
REDIRECT_TO_LOGIN: 'redirectToLogin',
REDIRECT_TO_APP: 'redirectToApp',
REDIRECT: 'redirect',
})
})
})
10 changes: 10 additions & 0 deletions src/testHelpers/createMockConfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,16 @@ const createMockConfig = ({ clientSide } = {}) => {
databaseURL: 'https://my-example-app.firebaseio.com',
projectId: 'my-example-app-id',
},
onRedirect: {
whenAuthed: {
destination: '/',
permanent: false,
},
whenUnauthed: {
destination: '/login',
permanent: false,
},
},
cookies: {
name: 'someExample',
keys: useClientSideConfig ? [] : ['abc', 'def'],
Expand Down
41 changes: 41 additions & 0 deletions src/withAuthUser.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ const withAuthUser =
appPageURL = null,
authPageURL = null,
LoaderComponent = null,
onRedirect = null,
} = {}) =>
(ChildComponent) => {
const WithAuthUserHOC = (props) => {
Expand Down Expand Up @@ -117,6 +118,12 @@ const withAuthUser =
? authRequestCompleted
: true)

const shouldUseCustomRedirect = [
whenAuthed,
whenUnauthedBeforeInit,
whenUnauthedAfterInit,
].includes(AuthAction.REDIRECT)

const router = useRouter()
const redirectToApp = useCallback(() => {
logDebug('Redirecting to app.')
Expand Down Expand Up @@ -160,6 +167,36 @@ const withAuthUser =
}
router.replace(destination)
}, [router, AuthUser])
const redirectToCustom = useCallback(() => {
logDebug('Redirecting to user-specified endpoint')
const redirectConfig = onRedirect || getConfig().onRedirect
if (!redirectConfig) {
throw new Error(
'The "onRedirect" config setting must be set when using `REDIRECT`.'
)
}

const authStateConfig = isAuthed
? onRedirect.whenAuthed
: onRedirect.whenUnauthed

if (!authStateConfig || !authStateConfig.destination) {
Copy link

@prescottprue prescottprue Dec 10, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (!authStateConfig || !authStateConfig.destination) {
if (!authStateConfig?.destination) {

Although that implies and - was the OR intentional before? Or were you intending to do:

if (authStateConfig && !authStateConfig.destination)

So that it is defined, but missing the destination. Thats what the error message seemed to imply anyway

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or maybe I'm misunderstanding since that seems to be what you do below?

throw new Error(
`The "destination" in the "onRedirect.whenAuthed" and "onRedirect.whenUnauthed" redirect configs must resolve to a non-empty string`

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: We could technically make this only call out the offender here instead of both (with a conditional like you did above)

)
}

if (
authStateConfig &&
(!authStateConfig.destination ||
typeof authStateConfig.destination !== 'string')
) {
throw new Error(
'The "destination" must be set to a non-empty string or resolve to a non-empty string'
)
}
router.replace(authStateConfig.destination)
}, [router, isAuthed])

useEffect(() => {
// Only redirect on the client side. To redirect server-side,
Expand All @@ -171,12 +208,16 @@ const withAuthUser =
redirectToApp()
} else if (shouldRedirectToLogin) {
redirectToLogin()
} else if (shouldUseCustomRedirect) {
redirectToCustom()
}
}, [
shouldRedirectToApp,
shouldRedirectToLogin,
shouldUseCustomRedirect,
redirectToApp,
redirectToLogin,
redirectToCustom,
])

// Decide what to render.
Expand Down
34 changes: 34 additions & 0 deletions src/withAuthUserTokenSSR.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ const withAuthUserTokenSSR =
whenUnauthed = AuthAction.RENDER,
appPageURL = null,
authPageURL = null,
onRedirect = null,
} = {},
{ useToken = true } = {}
) =>
Expand Down Expand Up @@ -144,6 +145,39 @@ const withAuthUserTokenSSR =
}
}

if ([whenAuthed, whenUnauthed].includes(AuthAction.REDIRECT)) {
const redirectConfig = onRedirect || getConfig().onRedirect

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice - I like the overridable with local config with fallback to global

if (!redirectConfig) {
throw new Error(
`When "whenAuthed" or "whenUnauthed" are set to AuthAction.REDIRECT, "onRedirect" must be set.`
)
}

const authStateConfig = AuthUser.id
? onRedirect.whenAuthed
: onRedirect.whenUnauthed

if (!authStateConfig || !authStateConfig.destination) {
throw new Error(
`The "destination" in the "onRedirect.whenAuthed" and "onRedirect.whenUnauthed" redirect configs must resolve to a non-empty string`
)
}

if (
authStateConfig &&
(!authStateConfig.destination ||
typeof authStateConfig.destination !== 'string')
) {
throw new Error(
'The "destination" must be set to a non-empty string or resolve to a non-empty string'
)
}

return {
redirect: authStateConfig,
}
}

// Prepare return data
let returnData = { props: { AuthUserSerialized } }

Expand Down