@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 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