@next-k8s/client 1.0.9
Sign up to get free protection for your applications and to get access to all the features.
- 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
|