@next-k8s/client 1.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.dockerignore +2 -0
- package/.eslintrc.json +3 -0
- package/CHANGELOG.md +72 -0
- package/Dockerfile +8 -0
- package/README.md +34 -0
- package/api/client.ts +25 -0
- package/components/Header/Header.tsx +42 -0
- package/context/root.ts +12 -0
- package/hooks/use-request.ts +45 -0
- package/next-env.d.ts +5 -0
- package/next.config.js +24 -0
- package/package.json +31 -0
- package/pages/_app.tsx +50 -0
- package/pages/index.tsx +22 -0
- package/pages/users/signin.tsx +67 -0
- package/pages/users/signout.tsx +31 -0
- package/pages/users/signup.tsx +67 -0
- package/pnpm-lock.yaml +2023 -0
- package/public/favicon.ico +0 -0
- package/styles/_variables.scss +0 -0
- package/styles/globals.scss +18 -0
- package/tsconfig.json +20 -0
- package/types/user.ts +4 -0
package/.dockerignore
ADDED
package/.eslintrc.json
ADDED
package/CHANGELOG.md
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
# Change Log
|
2
|
+
|
3
|
+
All notable changes to this project will be documented in this file.
|
4
|
+
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
5
|
+
|
6
|
+
## [1.0.9](https://github.com/mathiscode/next-k8s-boilerplate/compare/@next-k8s/client@1.0.8...@next-k8s/client@1.0.9) (2022-07-06)
|
7
|
+
|
8
|
+
**Note:** Version bump only for package @next-k8s/client
|
9
|
+
|
10
|
+
|
11
|
+
|
12
|
+
|
13
|
+
|
14
|
+
## 1.0.8 (2022-07-06)
|
15
|
+
|
16
|
+
**Note:** Version bump only for package @next-k8s/client
|
17
|
+
|
18
|
+
|
19
|
+
|
20
|
+
|
21
|
+
|
22
|
+
## 1.0.7 (2022-07-06)
|
23
|
+
|
24
|
+
**Note:** Version bump only for package @next-k8s/client
|
25
|
+
|
26
|
+
|
27
|
+
|
28
|
+
|
29
|
+
|
30
|
+
## 1.0.6 (2022-07-06)
|
31
|
+
|
32
|
+
**Note:** Version bump only for package @next-k8s/client
|
33
|
+
|
34
|
+
|
35
|
+
|
36
|
+
|
37
|
+
|
38
|
+
## 1.0.5 (2022-07-05)
|
39
|
+
|
40
|
+
**Note:** Version bump only for package @next-k8s/client
|
41
|
+
|
42
|
+
|
43
|
+
|
44
|
+
|
45
|
+
|
46
|
+
## 1.0.4 (2022-07-05)
|
47
|
+
|
48
|
+
**Note:** Version bump only for package @next-k8s/client
|
49
|
+
|
50
|
+
|
51
|
+
|
52
|
+
|
53
|
+
|
54
|
+
## 1.0.3 (2022-07-05)
|
55
|
+
|
56
|
+
**Note:** Version bump only for package @next-k8s/client
|
57
|
+
|
58
|
+
|
59
|
+
|
60
|
+
|
61
|
+
|
62
|
+
## 1.0.2 (2022-07-05)
|
63
|
+
|
64
|
+
**Note:** Version bump only for package @next-k8s/client
|
65
|
+
|
66
|
+
|
67
|
+
|
68
|
+
|
69
|
+
|
70
|
+
## 1.0.1 (2022-07-05)
|
71
|
+
|
72
|
+
**Note:** Version bump only for package @next-k8s/client
|
package/Dockerfile
ADDED
package/README.md
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).
|
2
|
+
|
3
|
+
## Getting Started
|
4
|
+
|
5
|
+
First, run the development server:
|
6
|
+
|
7
|
+
```bash
|
8
|
+
npm run dev
|
9
|
+
# or
|
10
|
+
yarn dev
|
11
|
+
```
|
12
|
+
|
13
|
+
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
|
14
|
+
|
15
|
+
You can start editing the page by modifying `pages/index.tsx`. The page auto-updates as you edit the file.
|
16
|
+
|
17
|
+
[API routes](https://nextjs.org/docs/api-routes/introduction) can be accessed on [http://localhost:3000/api/hello](http://localhost:3000/api/hello). This endpoint can be edited in `pages/api/hello.ts`.
|
18
|
+
|
19
|
+
The `pages/api` directory is mapped to `/api/*`. Files in this directory are treated as [API routes](https://nextjs.org/docs/api-routes/introduction) instead of React pages.
|
20
|
+
|
21
|
+
## Learn More
|
22
|
+
|
23
|
+
To learn more about Next.js, take a look at the following resources:
|
24
|
+
|
25
|
+
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
|
26
|
+
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
|
27
|
+
|
28
|
+
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!
|
29
|
+
|
30
|
+
## Deploy on Vercel
|
31
|
+
|
32
|
+
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
|
33
|
+
|
34
|
+
Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.
|
package/api/client.ts
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
import type { IncomingMessage } from 'http'
|
2
|
+
|
3
|
+
interface APIClient {
|
4
|
+
baseURL: String;
|
5
|
+
options: Object;
|
6
|
+
}
|
7
|
+
|
8
|
+
class APIClient {
|
9
|
+
constructor ({ req, ingress }: { req?: IncomingMessage, ingress?: String }) {
|
10
|
+
const isServer = typeof window === 'undefined'
|
11
|
+
const baseURL = isServer ? ingress || 'http://ingress-nginx-controller.ingress-nginx.svc.cluster.local' : ''
|
12
|
+
const headers = isServer && req ? req.headers as any : {}
|
13
|
+
const options = isServer ? { headers } : {}
|
14
|
+
|
15
|
+
this.baseURL = baseURL || ''
|
16
|
+
this.options = options || {}
|
17
|
+
}
|
18
|
+
|
19
|
+
async request (path: String) {
|
20
|
+
const response = await fetch(`${this.baseURL}/api${path}`, this.options)
|
21
|
+
return await response.json()
|
22
|
+
}
|
23
|
+
}
|
24
|
+
|
25
|
+
export default APIClient
|
@@ -0,0 +1,42 @@
|
|
1
|
+
import Link from 'next/link'
|
2
|
+
import { useContext } from 'react'
|
3
|
+
|
4
|
+
import Container from 'react-bootstrap/Container'
|
5
|
+
import Nav from 'react-bootstrap/Nav'
|
6
|
+
import Navbar from 'react-bootstrap/Navbar'
|
7
|
+
|
8
|
+
import RootContext from '../../context/root'
|
9
|
+
|
10
|
+
const Header = () => {
|
11
|
+
const { user } = useContext(RootContext)
|
12
|
+
|
13
|
+
return (
|
14
|
+
<Navbar sticky='top' bg='dark' variant='dark' expand='lg'>
|
15
|
+
<Container fluid>
|
16
|
+
<Link href='/' passHref><Navbar.Brand>Next.K8S Boilerplate</Navbar.Brand></Link>
|
17
|
+
|
18
|
+
<Navbar.Toggle aria-controls='top-nav' />
|
19
|
+
<Navbar.Collapse id='top-nav'>
|
20
|
+
<Nav fill className='ms-auto'>
|
21
|
+
{
|
22
|
+
!user &&
|
23
|
+
<>
|
24
|
+
<Link href='/users/signin' passHref><Nav.Link>Sign In</Nav.Link></Link>
|
25
|
+
<Link href='/users/signup' passHref><Nav.Link>Sign Up</Nav.Link></Link>
|
26
|
+
</>
|
27
|
+
}
|
28
|
+
|
29
|
+
{
|
30
|
+
user &&
|
31
|
+
<>
|
32
|
+
<Link href='/users/signout' passHref><Nav.Link>Sign Out</Nav.Link></Link>
|
33
|
+
</>
|
34
|
+
}
|
35
|
+
</Nav>
|
36
|
+
</Navbar.Collapse>
|
37
|
+
</Container>
|
38
|
+
</Navbar>
|
39
|
+
)
|
40
|
+
}
|
41
|
+
|
42
|
+
export default Header
|
package/context/root.ts
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
import { useState } from 'react'
|
2
|
+
|
3
|
+
export interface UseRequestHook {
|
4
|
+
doRequest: Function;
|
5
|
+
errors: Array<Object>;
|
6
|
+
}
|
7
|
+
|
8
|
+
export interface RequestError {
|
9
|
+
code: Number,
|
10
|
+
message: String
|
11
|
+
}
|
12
|
+
|
13
|
+
export interface RequestOptions {
|
14
|
+
url: RequestInfo | URL,
|
15
|
+
method?: String,
|
16
|
+
body?: Object,
|
17
|
+
customHeaders?: Object,
|
18
|
+
onSuccess?: Function
|
19
|
+
}
|
20
|
+
|
21
|
+
const defaultHeaders = { 'Content-Type': 'application/json' }
|
22
|
+
|
23
|
+
const useRequest = ({ url, method, body, customHeaders, onSuccess }: RequestOptions) => {
|
24
|
+
const [errors, setErrors] = useState<Array<RequestError>>([])
|
25
|
+
|
26
|
+
const doRequest = async () => {
|
27
|
+
const headers = customHeaders ? { ...defaultHeaders, ...customHeaders } : defaultHeaders
|
28
|
+
const options: any = { headers, method: method?.toUpperCase() || 'GET' }
|
29
|
+
if (body) options.body = JSON.stringify(body)
|
30
|
+
|
31
|
+
const response = await fetch(url, options)
|
32
|
+
const data = await response.json()
|
33
|
+
|
34
|
+
let errorsData: Array<RequestError> = []
|
35
|
+
if (data.error) errorsData = data.error?.data?.map?.((err: any) => ({ code: response.status, message: err.msg })) || [{ code: response.status, message: data.error.message }]
|
36
|
+
setErrors(errorsData)
|
37
|
+
|
38
|
+
if (errorsData.length === 0 && onSuccess) onSuccess(data)
|
39
|
+
return data
|
40
|
+
}
|
41
|
+
|
42
|
+
return { doRequest, errors }
|
43
|
+
}
|
44
|
+
|
45
|
+
export default useRequest
|
package/next-env.d.ts
ADDED
package/next.config.js
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
/** @type {import('next').NextConfig} */
|
2
|
+
const nextConfig = {
|
3
|
+
reactStrictMode: true,
|
4
|
+
|
5
|
+
sassOptions: {
|
6
|
+
additionalData: `@import "styles/_variables.scss";`
|
7
|
+
},
|
8
|
+
|
9
|
+
webpackDevMiddleware: config => {
|
10
|
+
config.watchOptions.poll = 300
|
11
|
+
return config
|
12
|
+
},
|
13
|
+
|
14
|
+
// async rewrites () {
|
15
|
+
// return [
|
16
|
+
// {
|
17
|
+
// source: '/api/:path*',
|
18
|
+
// destination: 'http://skaffold.local/:path*'
|
19
|
+
// }
|
20
|
+
// ]
|
21
|
+
// }
|
22
|
+
}
|
23
|
+
|
24
|
+
module.exports = nextConfig
|
package/package.json
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
{
|
2
|
+
"name": "@next-k8s/client",
|
3
|
+
"version": "1.0.9",
|
4
|
+
"scripts": {
|
5
|
+
"dev": "next dev",
|
6
|
+
"build": "next build",
|
7
|
+
"start": "next start",
|
8
|
+
"lint": "next lint"
|
9
|
+
},
|
10
|
+
"publishConfig": {
|
11
|
+
"access": "public"
|
12
|
+
},
|
13
|
+
"dependencies": {
|
14
|
+
"bootstrap": "^5.1.3",
|
15
|
+
"next": "12.1.6",
|
16
|
+
"react": "18.1.0",
|
17
|
+
"react-bootstrap": "^2.4.0",
|
18
|
+
"react-dom": "18.1.0"
|
19
|
+
},
|
20
|
+
"devDependencies": {
|
21
|
+
"@types/node": "17.0.42",
|
22
|
+
"@types/react": "18.0.12",
|
23
|
+
"@types/react-dom": "18.0.5",
|
24
|
+
"bootswatch": "^5.1.3",
|
25
|
+
"eslint": "8.17.0",
|
26
|
+
"eslint-config-next": "12.1.6",
|
27
|
+
"sass": "^1.52.3",
|
28
|
+
"typescript": "4.7.3"
|
29
|
+
},
|
30
|
+
"gitHead": "e28ae26195b5a105e974ff366741832500b17b31"
|
31
|
+
}
|
package/pages/_app.tsx
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
import type { NextComponentType, NextPageContext } from 'next'
|
2
|
+
import type { AppProps } from 'next/app'
|
3
|
+
import type { User } from '../types/user'
|
4
|
+
|
5
|
+
import Head from 'next/head'
|
6
|
+
import { useState } from 'react'
|
7
|
+
|
8
|
+
import '../styles/globals.scss'
|
9
|
+
import RootContext from '../context/root'
|
10
|
+
import ApiClient from '../api/client'
|
11
|
+
import Header from '../components/Header/Header'
|
12
|
+
|
13
|
+
interface AppComponentProps extends AppProps {
|
14
|
+
user: User;
|
15
|
+
}
|
16
|
+
|
17
|
+
interface AppContext {
|
18
|
+
Component: NextComponentType;
|
19
|
+
ctx: NextPageContext;
|
20
|
+
}
|
21
|
+
|
22
|
+
function AppComponent({ Component, pageProps, user }: AppComponentProps) {
|
23
|
+
const [context, setContext] = useState({ user })
|
24
|
+
|
25
|
+
return (
|
26
|
+
<RootContext.Provider value={{ ...context, setContext }}>
|
27
|
+
<Head>
|
28
|
+
<title>Next.K8S Boilerplate</title>
|
29
|
+
<meta name='description' content='Kubernetes + NextJS Boilerplate Application' />
|
30
|
+
<link rel='icon' href='/favicon.ico' />
|
31
|
+
</Head>
|
32
|
+
|
33
|
+
<Header />
|
34
|
+
<Component {...pageProps} />
|
35
|
+
</RootContext.Provider>
|
36
|
+
)
|
37
|
+
}
|
38
|
+
|
39
|
+
AppComponent.getInitialProps = async ({ Component, ctx }: AppContext) => {
|
40
|
+
const pageProps = Component.getInitialProps?.(ctx) || {}
|
41
|
+
const api = new ApiClient({ req: ctx.req })
|
42
|
+
try {
|
43
|
+
const { user } = await api.request('/users/current')
|
44
|
+
return { pageProps, user }
|
45
|
+
} catch {
|
46
|
+
return { pageProps }
|
47
|
+
}
|
48
|
+
}
|
49
|
+
|
50
|
+
export default AppComponent
|
package/pages/index.tsx
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
import type { NextPage } from 'next'
|
2
|
+
|
3
|
+
import { useContext } from 'react'
|
4
|
+
|
5
|
+
import Container from 'react-bootstrap/Container'
|
6
|
+
|
7
|
+
import RootContext from '../context/root'
|
8
|
+
|
9
|
+
const Home: NextPage = () => {
|
10
|
+
const { user } = useContext(RootContext)
|
11
|
+
|
12
|
+
return (
|
13
|
+
<Container>
|
14
|
+
<main>
|
15
|
+
<h1>K8S Ticketing</h1>
|
16
|
+
<pre>{JSON.stringify(user, null, 2)}</pre>
|
17
|
+
</main>
|
18
|
+
</Container>
|
19
|
+
)
|
20
|
+
}
|
21
|
+
|
22
|
+
export default Home
|
@@ -0,0 +1,67 @@
|
|
1
|
+
import type { NextPage } from 'next'
|
2
|
+
import type { ChangeEvent, MouseEvent } from 'react'
|
3
|
+
import type { User } from '../../types/user'
|
4
|
+
|
5
|
+
import { useContext, useEffect, useState } from 'react'
|
6
|
+
import Router from 'next/router'
|
7
|
+
|
8
|
+
import Alert from 'react-bootstrap/Alert'
|
9
|
+
import Button from 'react-bootstrap/Button'
|
10
|
+
import Container from 'react-bootstrap/Container'
|
11
|
+
import Form from 'react-bootstrap/Form'
|
12
|
+
|
13
|
+
import RootContext from '../../context/root'
|
14
|
+
import useRequest, { UseRequestHook } from '../../hooks/use-request'
|
15
|
+
|
16
|
+
const AuthSignin: NextPage = () => {
|
17
|
+
const { user, setContext } = useContext(RootContext)
|
18
|
+
|
19
|
+
const [email, setEmail] = useState('')
|
20
|
+
const [password, setPassword] = useState('')
|
21
|
+
const [loading, setLoading] = useState(false)
|
22
|
+
|
23
|
+
const { doRequest, errors }: UseRequestHook = useRequest({
|
24
|
+
url: '/api/users/signin',
|
25
|
+
method: 'POST',
|
26
|
+
body: { email, password },
|
27
|
+
onSuccess: ({ user }: { user: User }) => {
|
28
|
+
setContext((ctx: RootContext) => ({ ...ctx, user }))
|
29
|
+
Router.push('/')
|
30
|
+
}
|
31
|
+
})
|
32
|
+
|
33
|
+
const signup = async (e: MouseEvent) => {
|
34
|
+
e.preventDefault()
|
35
|
+
if (email === '' || password === '') return
|
36
|
+
setLoading(true)
|
37
|
+
await doRequest()
|
38
|
+
setLoading(false)
|
39
|
+
}
|
40
|
+
|
41
|
+
useEffect(() => {
|
42
|
+
if (user) Router.push('/')
|
43
|
+
}, [user])
|
44
|
+
|
45
|
+
return (
|
46
|
+
<Container>
|
47
|
+
<h1>Signin</h1>
|
48
|
+
<Form>
|
49
|
+
<Form.Group className='mb-3' controlId='email'>
|
50
|
+
<Form.Label>Email Address</Form.Label>
|
51
|
+
<Form.Control type='email' value={email} onChange={(e: ChangeEvent<HTMLInputElement>) => setEmail(e.target.value)} placeholder='Enter your email address' />
|
52
|
+
</Form.Group>
|
53
|
+
|
54
|
+
<Form.Group className='mb-3' controlId='password'>
|
55
|
+
<Form.Label>Password</Form.Label>
|
56
|
+
<Form.Control type='password' value={password} onChange={(e: ChangeEvent<HTMLInputElement>) => setPassword(e.target.value)} placeholder='Enter your password' />
|
57
|
+
</Form.Group>
|
58
|
+
|
59
|
+
{errors.map((err: any, index: number) => <Alert key={index} variant='danger'>{err.message}</Alert>)}
|
60
|
+
|
61
|
+
<Button variant='primary' disabled={loading} onClick={e => signup(e)}>Signin</Button>
|
62
|
+
</Form>
|
63
|
+
</Container>
|
64
|
+
)
|
65
|
+
}
|
66
|
+
|
67
|
+
export default AuthSignin
|
@@ -0,0 +1,31 @@
|
|
1
|
+
import type { NextPage } from 'next'
|
2
|
+
|
3
|
+
import Router from 'next/router'
|
4
|
+
import { useContext, useEffect } from 'react'
|
5
|
+
|
6
|
+
import Container from 'react-bootstrap/Container'
|
7
|
+
|
8
|
+
import RootContext from '../../context/root'
|
9
|
+
import useRequest, { UseRequestHook } from '../../hooks/use-request'
|
10
|
+
|
11
|
+
const AuthSignout: NextPage = () => {
|
12
|
+
const { setContext } = useContext(RootContext)
|
13
|
+
|
14
|
+
const { doRequest }: UseRequestHook = useRequest({
|
15
|
+
url: '/api/users/signout',
|
16
|
+
onSuccess: () => {
|
17
|
+
setContext((ctx: RootContext) => ({ ...ctx, user: null }))
|
18
|
+
Router.push('/')
|
19
|
+
}
|
20
|
+
})
|
21
|
+
|
22
|
+
useEffect(() => { doRequest() }, []) // eslint-disable-line
|
23
|
+
|
24
|
+
return (
|
25
|
+
<Container>
|
26
|
+
<h1>Signing you out, one moment...</h1>
|
27
|
+
</Container>
|
28
|
+
)
|
29
|
+
}
|
30
|
+
|
31
|
+
export default AuthSignout
|
@@ -0,0 +1,67 @@
|
|
1
|
+
import type { NextPage } from 'next'
|
2
|
+
import type { ChangeEvent, MouseEvent } from 'react'
|
3
|
+
import type { User } from '../../types/user'
|
4
|
+
|
5
|
+
import { useContext, useEffect, useState } from 'react'
|
6
|
+
import Router from 'next/router'
|
7
|
+
|
8
|
+
import Alert from 'react-bootstrap/Alert'
|
9
|
+
import Button from 'react-bootstrap/Button'
|
10
|
+
import Container from 'react-bootstrap/Container'
|
11
|
+
import Form from 'react-bootstrap/Form'
|
12
|
+
|
13
|
+
import RootContext from '../../context/root'
|
14
|
+
import useRequest, { UseRequestHook } from '../../hooks/use-request'
|
15
|
+
|
16
|
+
const AuthSignup: NextPage = () => {
|
17
|
+
const { user, setContext } = useContext(RootContext)
|
18
|
+
|
19
|
+
const [email, setEmail] = useState('')
|
20
|
+
const [password, setPassword] = useState('')
|
21
|
+
const [loading, setLoading] = useState(false)
|
22
|
+
|
23
|
+
const { doRequest, errors }: UseRequestHook = useRequest({
|
24
|
+
url: '/api/users/signup',
|
25
|
+
method: 'POST',
|
26
|
+
body: { email, password },
|
27
|
+
onSuccess: ({ user }: { user: User }) => {
|
28
|
+
setContext((ctx: RootContext) => ({ ...ctx, user }))
|
29
|
+
Router.push('/')
|
30
|
+
}
|
31
|
+
})
|
32
|
+
|
33
|
+
const signup = async (e: MouseEvent) => {
|
34
|
+
e.preventDefault()
|
35
|
+
if (email === '' || password === '') return
|
36
|
+
setLoading(true)
|
37
|
+
await doRequest()
|
38
|
+
setLoading(false)
|
39
|
+
}
|
40
|
+
|
41
|
+
useEffect(() => {
|
42
|
+
if (user) Router.push('/')
|
43
|
+
}, [user])
|
44
|
+
|
45
|
+
return (
|
46
|
+
<Container>
|
47
|
+
<h1>Signup</h1>
|
48
|
+
<Form>
|
49
|
+
<Form.Group className='mb-3' controlId='email'>
|
50
|
+
<Form.Label>Email Address</Form.Label>
|
51
|
+
<Form.Control type='email' value={email} onChange={(e: ChangeEvent<HTMLInputElement>) => setEmail(e.target.value)} placeholder='Enter your email address' />
|
52
|
+
</Form.Group>
|
53
|
+
|
54
|
+
<Form.Group className='mb-3' controlId='password'>
|
55
|
+
<Form.Label>Password</Form.Label>
|
56
|
+
<Form.Control type='password' value={password} onChange={(e: ChangeEvent<HTMLInputElement>) => setPassword(e.target.value)} placeholder='Enter your password' />
|
57
|
+
</Form.Group>
|
58
|
+
|
59
|
+
{errors.map((err: any, index: number) => <Alert key={index} variant='danger'>{err.message}</Alert>)}
|
60
|
+
|
61
|
+
<Button variant='primary' disabled={loading} onClick={e => signup(e)}>Signup</Button>
|
62
|
+
</Form>
|
63
|
+
</Container>
|
64
|
+
)
|
65
|
+
}
|
66
|
+
|
67
|
+
export default AuthSignup
|