@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 ADDED
@@ -0,0 +1,2 @@
1
+ node_modules
2
+ .next
package/.eslintrc.json ADDED
@@ -0,0 +1,3 @@
1
+ {
2
+ "extends": "next/core-web-vitals"
3
+ }
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
@@ -0,0 +1,8 @@
1
+ FROM node:alpine
2
+
3
+ WORKDIR /app
4
+ COPY package.json .
5
+ RUN npm install
6
+ COPY . .
7
+
8
+ CMD ["npm", "run", "dev"]
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
@@ -0,0 +1,12 @@
1
+ import { createContext } from 'react'
2
+
3
+ interface RootContext {
4
+ user?: Object;
5
+ setContext: Function;
6
+ }
7
+
8
+ const RootContext = createContext<RootContext>({
9
+ setContext: () => {}
10
+ })
11
+
12
+ export default RootContext
@@ -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
@@ -0,0 +1,5 @@
1
+ /// <reference types="next" />
2
+ /// <reference types="next/image-types/global" />
3
+
4
+ // NOTE: This file should not be edited
5
+ // see https://nextjs.org/docs/basic-features/typescript for more information.
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
@@ -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