Skip to content

Commit 98a3dc8

Browse files
BA: withUser HOC creation (#85)
1 parent 9863c57 commit 98a3dc8

File tree

6 files changed

+102
-1
lines changed

6 files changed

+102
-1
lines changed

packages/authentication/CHANGELOG.md

+6
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# @baseapp-frontend/authentication
22

3+
## 2.0.1
4+
5+
### Patch Changes
6+
7+
- Creates `withUser` HOC and `ComponentWithUser` type. `withUser`'s JSDoc contains a more detailed information about its usage.
8+
39
## 2.0.0
410

511
### Major Changes
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
11
export { default as getUser } from './getUser'
22
export { default as useSimpleTokenUser } from './useSimpleTokenUser'
33
export { default as useUser } from './useUser'
4+
5+
export { default as withUser } from './withUser'
6+
export type * from './withUser/types'
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import { FC } from 'react'
2+
3+
import { render } from '@baseapp-frontend/test'
4+
import { IJWTContent } from '@baseapp-frontend/utils'
5+
6+
import withUser from '..'
7+
import { IUser } from '../../../../types/user'
8+
import getUser from '../../getUser'
9+
import { ComponentWithUser } from '../types'
10+
11+
jest.mock('../../getUser', () => jest.fn())
12+
13+
type User = IUser & IJWTContent
14+
15+
const MockComponent: FC<ComponentWithUser<User>> = ({ user }) => (
16+
<div>{user ? `Hello, ${user.firstName}` : 'No user'}</div>
17+
)
18+
19+
describe('withUser HOC', () => {
20+
const getUserMock = getUser as jest.Mock
21+
22+
it('passes the user object to the wrapped component', async () => {
23+
const userMock = { firstName: 'John', lastName: 'Doe' }
24+
getUserMock.mockResolvedValue(userMock)
25+
26+
const WithUserComponent = withUser<User>(MockComponent)
27+
const { findByText } = render(await WithUserComponent({}))
28+
29+
const userElement = await findByText(`Hello, ${userMock.firstName}`)
30+
expect(userElement).toBeInTheDocument()
31+
})
32+
33+
it('handles the case when there is no user', async () => {
34+
getUserMock.mockResolvedValue(null)
35+
36+
const WithUserComponent = withUser<User>(MockComponent)
37+
const { findByText } = render(await WithUserComponent({}))
38+
39+
const userElement = await findByText('No user')
40+
expect(userElement).toBeInTheDocument()
41+
})
42+
})
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import { FC } from 'react'
2+
3+
import { IJWTContent } from '@baseapp-frontend/utils'
4+
5+
import getUser from '../getUser'
6+
import { ComponentWithUser } from './types'
7+
8+
/**
9+
* HOC to provide the `user` object to the component.
10+
*
11+
* It's useful when the component that needs to call `getUser` and can't be async (e.g. Client Components).
12+
*
13+
* Consider rendering the Component using the `ComponentWithUser` interface to inherit the `user` type.
14+
* You may need to import the component using dynamic imports with `next/dynamic`.
15+
*
16+
* @example Defining and exporting a component with `withUser`:
17+
* ```tsx
18+
* import { FC } from 'react'
19+
*
20+
* import {ComponentWithUser, withUser} from '@baseapp/authentication'
21+
*
22+
* const MyComponent: FC<ComponentWithUser<MyUser>> = ({user}) => <div>Hi {user.firstName}</div>
23+
*
24+
* export default withUser<MyUser>(MyComponent)
25+
* ```
26+
* @example Importing a component with `withUser` using `next/dynamic`:
27+
* ```tsx
28+
* import dynamic from 'next/dynamic'
29+
*
30+
* const MyComponent = dynamic(() => import('./MyComponent'), { ssr: false })
31+
*
32+
* (...)
33+
* ```
34+
*/
35+
const withUser =
36+
<TUser extends IJWTContent, Props extends object = {}>(
37+
Component: FC<Props & ComponentWithUser<TUser>>,
38+
) =>
39+
async (props: Props) => {
40+
const user = await getUser<TUser>()
41+
42+
return <Component {...props} user={user} />
43+
}
44+
45+
export default withUser
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { IJWTContent } from '@baseapp-frontend/utils'
2+
3+
export interface ComponentWithUser<TUser extends IJWTContent> {
4+
user: TUser | null
5+
}

packages/authentication/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "@baseapp-frontend/authentication",
33
"description": "Authentication modules.",
4-
"version": "2.0.0",
4+
"version": "2.0.1",
55
"main": "./dist/index.ts",
66
"module": "./dist/index.mjs",
77
"scripts": {

0 commit comments

Comments
 (0)