├── .env.example
├── .eslintignore
├── .eslintrc.json
├── .gitattributes
├── .gitignore
├── .prettierignore
├── .prettierrc
├── .stylelintrc
├── @types
├── globalTypes.d.ts
├── graphql.d.ts
└── index.d.ts
├── README.md
├── graphql
├── fragments.ts
├── mutations
│ └── user.ts
└── queries
│ └── user.ts
├── jest.config.js
├── lib
├── apolloClient.ts
└── validations.ts
├── next-env.d.ts
├── next.config.js
├── nodemon.json
├── package-lock.json
├── package.json
├── pages
├── _app.tsx
└── index.tsx
├── postcss.config.js
├── public
├── favicon.ico
└── static
│ └── fonts
│ ├── poppins-v5-latin-500.eot
│ ├── poppins-v5-latin-500.svg
│ ├── poppins-v5-latin-500.ttf
│ ├── poppins-v5-latin-500.woff
│ ├── poppins-v5-latin-500.woff2
│ ├── poppins-v5-latin-600.eot
│ ├── poppins-v5-latin-600.svg
│ ├── poppins-v5-latin-600.ttf
│ ├── poppins-v5-latin-600.woff
│ ├── poppins-v5-latin-600.woff2
│ ├── poppins-v5-latin-700.eot
│ ├── poppins-v5-latin-700.svg
│ ├── poppins-v5-latin-700.ttf
│ ├── poppins-v5-latin-700.woff
│ ├── poppins-v5-latin-700.woff2
│ ├── poppins-v5-latin-800.eot
│ ├── poppins-v5-latin-800.svg
│ ├── poppins-v5-latin-800.ttf
│ ├── poppins-v5-latin-800.woff
│ ├── poppins-v5-latin-800.woff2
│ ├── poppins-v5-latin-regular.eot
│ ├── poppins-v5-latin-regular.svg
│ ├── poppins-v5-latin-regular.ttf
│ ├── poppins-v5-latin-regular.woff
│ └── poppins-v5-latin-regular.woff2
├── server
├── common
│ ├── enums
│ │ └── UpdateOperators.ts
│ ├── models
│ │ └── Email.ts
│ └── scalars.ts
├── core
│ ├── apollo.ts
│ └── database.ts
├── index.ts
├── serverLib
│ ├── encryption.ts
│ ├── resolvers.ts
│ └── typegoose-middleware.ts
└── subgraphs
│ ├── schema.gql
│ └── user
│ ├── user.model.ts
│ ├── user.resolver.ts
│ └── user.service.ts
├── styles
├── base
│ ├── _base.scss
│ ├── _fonts.scss
│ └── _variables.scss
├── main.scss
├── pages
│ └── _index.scss
└── vendors
│ └── _normalize.scss
├── tests
├── jest.integration.config.js
├── jest.unit.config.js
└── test-setup.ts
├── tsconfig.jest.json
├── tsconfig.json
├── tsconfig.server.json
├── views
├── components
│ ├── Footer.tsx
│ ├── Nav.tsx
│ ├── footer.module.scss
│ └── nav.module.scss
└── ui
│ └── Button.tsx
└── yarn.lock
/.env.example:
--------------------------------------------------------------------------------
1 | NODE_ENV=development
2 | PORT=3000
3 | GRAPHQL_URL=http://localhost:3000/graphql
4 | MONGODB_URL=...
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | next.config.js
2 | jest.config.js
--------------------------------------------------------------------------------
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "parser": "@typescript-eslint/parser",
3 | "parserOptions": {
4 | "ecmaVersion": 2019,
5 | "sourceType": "module"
6 | },
7 | "env": {
8 | "browser": true,
9 | "node": true,
10 | "es6": true
11 | },
12 | "extends": [
13 | "next",
14 | "plugin:@typescript-eslint/recommended",
15 | "plugin:react/recommended",
16 | "plugin:prettier/recommended",
17 | "prettier"
18 | ],
19 | "plugins": ["@typescript-eslint", "react", "prettier", "graphql"],
20 | "rules": {
21 | "prettier/prettier": "error",
22 | "no-var": "warn",
23 | "no-console": "off",
24 | "react/jsx-filename-extension": [1, { "extensions": [".js", ".jsx"] }],
25 | "@typescript-eslint/explicit-function-return-type": [
26 | "error",
27 | {
28 | "allowExpressions": true,
29 | "allowTypedFunctionExpressions": true
30 | }
31 | ],
32 | "graphql/template-strings": [
33 | "error",
34 | {
35 | "env": "literal"
36 | }
37 | ],
38 | "better-styled-components/sort-declarations-alphabetically": 2
39 | },
40 | "settings": {
41 | "import/resolver": {
42 | "babel-module": {}
43 | },
44 | "react": {
45 | "version": "detect"
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | *.js linguist-language=TypeScript
2 | *.css linguist-detectable=false
3 | * -text
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # next.js
12 | /.next/
13 | /out/
14 |
15 | # production
16 | /build
17 |
18 | # misc
19 | .DS_Store
20 | .env*
21 | !.env.example
22 |
23 | # debug
24 | npm-debug.log*
25 | yarn-debug.log*
26 | yarn-error.log*
27 |
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | .cache
2 | package.json
3 | package-lock.json
4 | public
5 | styles/vendors
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "endOfLine": "lf",
3 | "semi": false,
4 | "singleQuote": true,
5 | "tabWidth": 2,
6 | "trailingComma": "es5"
7 | }
8 |
--------------------------------------------------------------------------------
/.stylelintrc:
--------------------------------------------------------------------------------
1 | {
2 | "plugins": [
3 | "stylelint-scss"
4 | ],
5 | "extends": "stylelint-config-standard",
6 | "ignoreFiles": ["./styles/vendors/**"],
7 | "rules": {
8 | "at-rule-no-unknown": null,
9 | "scss/at-rule-no-unknown": true,
10 | "block-opening-brace-space-before": null,
11 | "rule-empty-line-before": ["always", {
12 | except: ["first-nested", "after-single-line-comment"],
13 | }],
14 | "color-hex-length": "long",
15 | "no-descending-specificity": null
16 | }
17 | }
--------------------------------------------------------------------------------
/@types/globalTypes.d.ts:
--------------------------------------------------------------------------------
1 | export interface exampleType {
2 | _id?: string
3 | name: string
4 | username: string
5 | avatar?: string
6 | }
7 |
--------------------------------------------------------------------------------
/@types/graphql.d.ts:
--------------------------------------------------------------------------------
1 | declare module '*.gql' {
2 | import { DocumentNode } from 'graphql'
3 |
4 | const content: DocumentNode
5 | export default content
6 | }
7 |
8 | declare module '*.graphql' {
9 | import { DocumentNode } from 'graphql'
10 |
11 | const content: DocumentNode
12 | export default content
13 | }
14 |
15 | declare module '*.qql' {
16 | const content: any
17 | export default content
18 | }
19 |
--------------------------------------------------------------------------------
/@types/index.d.ts:
--------------------------------------------------------------------------------
1 | declare module 'express'
2 | declare module 'next'
3 | declare module 'morgan'
4 | declare module 'helmet'
5 | declare module 'compression'
6 | declare module 'node-fetch'
7 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
React + GraphQL + Next.js + Apollo + Scss + Typescript Starter
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 | ## Project boostrap built with:
13 |
14 | - React.js
15 | - Next.js
16 | - Typescript
17 | - SCSS
18 | - Apollo
19 | - GraphQl
20 | - EsLint
21 | - Prettier
22 | - Jest
23 | - Nodemon
24 | - Typegoose
25 | - Type-graphql
26 |
27 | ## How to use
28 |
29 | ```javascript
30 | npm i
31 | npm run dev
32 | ```
33 |
34 | ## Environment variables
35 |
36 | You can access your .env variables by deconstructing 'process.env' object, both on client and server.
37 | Just make sure that you reboot the server when updating .env file.
38 |
39 | ## Configuration
40 |
41 | You should configure things like eslint, tsconfig, prettier etc. with things that suit you and your project.
42 | Configuration in this project is not perfect - it's just my own preference, and I'm open to suggestions :)
43 |
44 | ## To see before coding;
45 |
46 | - [Check out this to read more about /server/graphql workings](https://github.com/Urigo/merge-graphql-schemas)
47 | - [Context management choice](https://www.youtube.com/watch?v=Q54YDGC_t3Y)
48 | - [Apollo context management](https://www.apollographql.com/docs/react/data/local-state/)
49 |
--------------------------------------------------------------------------------
/graphql/fragments.ts:
--------------------------------------------------------------------------------
1 | import gql from 'graphql-tag'
2 |
3 | export const FRAGMENT_exampleObject = gql`
4 | fragment wholeUserObject on User {
5 | _id
6 | login
7 | email
8 | avatar
9 | createdAt
10 | }
11 | `
12 |
--------------------------------------------------------------------------------
/graphql/mutations/user.ts:
--------------------------------------------------------------------------------
1 | import gql from 'graphql-tag'
2 | import { FRAGMENT_exampleObject } from '@graphql/fragments'
3 |
4 | export const UPDATE_PROFILE = gql`
5 | ${FRAGMENT_exampleObject}
6 |
7 | mutation updateUser($newName: String) {
8 | updateUser(newName: $newName) {
9 | ...wholeUserObject
10 | }
11 | }
12 | `
13 |
--------------------------------------------------------------------------------
/graphql/queries/user.ts:
--------------------------------------------------------------------------------
1 | import gql from 'graphql-tag'
2 | import { FRAGMENT_exampleObject } from '@graphql/fragments'
3 |
4 | export const PROFILE_BY_USERNAME = gql`
5 | ${FRAGMENT_exampleObject}
6 |
7 | query currentUser() {
8 | currentUser() {
9 | ...wholeUserObject
10 | }
11 | }
12 | `
13 |
--------------------------------------------------------------------------------
/jest.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | transform: {
3 | "^.+\\.(js|jsx)?$": "babel-jest",
4 | },
5 | testRegex: "(/__tests__/.*|(\\.|/)(test|spec))\\.ts?$",
6 | preset: "ts-jest",
7 | transform: {
8 | "^.+\\.(t|j)sx?$": "ts-jest",
9 | },
10 | testEnvironment: "node",
11 | globals: {
12 | jsx: "react",
13 | "ts-jest": {
14 | tsConfig: "tsconfig.jest.json",
15 | },
16 | },
17 | setupFiles: ["/tests/test-setup.ts"],
18 | moduleFileExtensions: ["ts", "tsx", "js", "jsx"],
19 | transformIgnorePatterns: ["/node_modules/"],
20 | moduleNameMapper: {
21 | "@graphql/(.*)": "/graphql/$1",
22 | "@constants/(.*)": "/constants/$1",
23 | "@views/(.*)": "/views/$1",
24 | "@views/(.*)": "/views/$1",
25 | "@viewsUi/(.*)": "/views/ui/$1",
26 | "@viewsComp/(.*)": "/views/components/$1",
27 | "@viewsLay/(.*)": "/views/layouts/$1",
28 | "@styles/(.*)": "/styles/$1",
29 | "@lib/(.*)": "/lib/$1",
30 | "@assets/(.*)": "/assets/$1",
31 | "@styles/(.*)": "/styles/$1",
32 | "@static/(.*)": "/public/static/$1",
33 | },
34 | };
35 |
36 |
--------------------------------------------------------------------------------
/lib/apolloClient.ts:
--------------------------------------------------------------------------------
1 | import fetch from 'node-fetch'
2 |
3 | import { ApolloClient, InMemoryCache, from, HttpLink } from '@apollo/client'
4 | import { onError } from '@apollo/client/link/error'
5 |
6 | const { GRAPHQL_URL } = process.env
7 | const { NODE_ENV } = process.env
8 |
9 | const httpLink = new HttpLink({
10 | uri: NODE_ENV !== 'production' ? '/graphql' : GRAPHQL_URL,
11 | fetch: fetch,
12 | credentials: 'same-origin',
13 | })
14 |
15 | const errorLink = onError(({ graphQLErrors, networkError }) => {
16 | if (graphQLErrors)
17 | graphQLErrors.map(({ message, locations, path }) =>
18 | console.log(
19 | `[GraphQL error]: Message: ${message}, Location: ${locations}, Path: ${path}`
20 | )
21 | )
22 |
23 | if (networkError) console.log(`[Network error]: ${networkError}`)
24 | })
25 |
26 | //merger all apollo links
27 | const link = from([errorLink, httpLink])
28 |
29 | const cache = new InMemoryCache()
30 |
31 | //main apollo client
32 | const apollo = new ApolloClient({
33 | defaultOptions: {
34 | watchQuery: {
35 | errorPolicy: 'all',
36 | },
37 | query: {
38 | errorPolicy: 'all',
39 | },
40 | mutate: {
41 | errorPolicy: 'all',
42 | },
43 | },
44 | ssrMode: !process.browser, // Disables forceFetch on the server (so queries are only run once)
45 | link,
46 | cache,
47 | })
48 |
49 | export default apollo
50 |
--------------------------------------------------------------------------------
/lib/validations.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * @param {string} email - string to check
3 | * @return {boolean} if string = valid email
4 | */
5 | export const isEmailValid = (data): boolean => {
6 | if (typeof data !== 'string') {
7 | return false
8 | }
9 | const re = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
10 | return re.test(data)
11 | }
12 |
13 | export const isPasswordValid = (data): boolean =>
14 | typeof data === 'string' && data.length >= 6
15 |
16 | //
17 | // utilities
18 | //
19 |
20 | export const isEmpty = (data: any): boolean => {
21 | if (typeof data === 'object') {
22 | if (JSON.stringify(data) === '{}' || JSON.stringify(data) === '[]') {
23 | return true
24 | }
25 | if (!data) {
26 | return true
27 | }
28 | return false
29 | }
30 | if (typeof data === 'string') {
31 | if (!data.trim()) {
32 | return true
33 | }
34 | return false
35 | }
36 | if (typeof data === 'undefined' || data === null) {
37 | return true
38 | }
39 | return false
40 | }
41 |
42 | export const isAlphaNumeric = (data: string): boolean => {
43 | const alphaNumRegExp = /[^A-Za-z0-9]+/g // only letters and numbers
44 | const notAllowedArr = data.match(alphaNumRegExp)
45 | return notAllowedArr == null
46 | }
47 |
--------------------------------------------------------------------------------
/next-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 | ///
3 | ///
4 |
5 | // NOTE: This file should not be edited
6 | // see https://nextjs.org/docs/basic-features/typescript for more information.
7 |
--------------------------------------------------------------------------------
/next.config.js:
--------------------------------------------------------------------------------
1 | require("dotenv").config();
2 | const path = require("path");
3 | const withImages = require("next-images");
4 |
5 | const TsconfigPathsPlugin = require("tsconfig-paths-webpack-plugin");
6 |
7 | const configureWebpack = (config, { dev }) => {
8 | config.plugins = config.plugins || [];
9 |
10 | if (config.resolve.plugins) {
11 | config.resolve.plugins.push(new TsconfigPathsPlugin());
12 | } else {
13 | config.resolve.plugins = [new TsconfigPathsPlugin()];
14 | }
15 |
16 | config.module.rules.push({
17 | test: /\.(eot|woff|woff2|ttf|svg|png|jpg|gif)$/,
18 | use: {
19 | loader: "url-loader",
20 | options: {
21 | limit: 100000,
22 | name: "[name].[ext]",
23 | },
24 | },
25 | });
26 |
27 | config.module.rules.push({
28 | test: /\.(graphql|gql)$/,
29 | exclude: /node_modules/,
30 | loader: "graphql-tag/loader",
31 | });
32 |
33 | if (dev) {
34 | config.module.rules.push({
35 | test: /\.jsx?$/,
36 | exclude: /node_modules/,
37 | loader: "eslint-loader",
38 | });
39 | config.devtool = "cheap-module-eval-source-map";
40 | }
41 |
42 | return config;
43 | };
44 |
45 | module.exports = withImages({
46 | webpack: {
47 | ...configureWebpack,
48 | sassOptions: {
49 | includePaths: [path.join(__dirname, "styles")],
50 | },
51 | }
52 | });
53 |
--------------------------------------------------------------------------------
/nodemon.json:
--------------------------------------------------------------------------------
1 | {
2 | "ignore": [".git", "node_modules/**/node_modules", "*.gql"],
3 | "watch": ["server/*"],
4 | "ext": "*",
5 | "exec": "ts-node --project tsconfig.server.json -r tsconfig-paths/register -r dotenv/config server/index.ts"
6 | }
7 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "NRG-bootstrap",
3 | "version": "0.1.0",
4 | "description": "Next.js + GraphQL + Typescript + Typegoose + Type-graphql project architecture that I play with",
5 | "author": "Seb",
6 | "license": "MIT",
7 | "url": "https://github.com/Sebastp/Next-react-graphql-apollo_Boostrap",
8 | "keywords": [
9 | "express",
10 | "graphQL",
11 | "next.js",
12 | "bootstrap",
13 | "apollo",
14 | "typescript",
15 | "typegoose",
16 | "type-graphql"
17 | ],
18 | "main": "server/index.ts",
19 | "scripts": {
20 | "dev": "nodemon",
21 | "build": "next build && tsc --project tsconfig.server.json",
22 | "start": "cross-env NODE_ENV=production ts-node --project tsconfig.server.json -r tsconfig-paths/register dist/server",
23 | "test": "jest",
24 | "test:unit": "jest --config tests/jest.unit.config.js",
25 | "test:integration": "jest --config tests/jest.integration.config.js",
26 | "test:watch": "jest --watch --no-cache",
27 | "eslint:fix": "eslint . --fix --ignore-path .gitignore",
28 | "prettify": "node_modules/.bin/prettier --config ./.prettierrc --write \"**/*.ts*\" --write \"**/*.js\" --write \"**/*.json\"",
29 | "lint": "eslint --ext .ts --ext .tsx ."
30 | },
31 | "engines": {
32 | "node": "^14.17.6",
33 | "npm": "^7.11.2"
34 | },
35 | "dependencies": {
36 | "@apollo/client": "^3.5.5",
37 | "@typegoose/auto-increment": "^1.0.0",
38 | "@typegoose/typegoose": "^9.1.0",
39 | "apollo-server": "^2.25.2",
40 | "apollo-server-express": "^3.1.2",
41 | "bcryptjs": "^2.4.3",
42 | "compression": "^1.7.4",
43 | "cors": "^2.8.5",
44 | "dotenv": "^10.0.0",
45 | "express": "^4.17.1",
46 | "graphql": "^15.5.5",
47 | "graphql-middleware": "^6.0.10",
48 | "graphql-passport": "^0.6.4",
49 | "graphql-scalars": "^1.10.1",
50 | "graphql-tag": "^2.12.4",
51 | "graphql-tools": "^8.1.0",
52 | "helmet": "^4.6.0",
53 | "merge-graphql-schemas": "^1.7.8",
54 | "moment": "^2.29.1",
55 | "mongoose": "^6.0.10",
56 | "morgan": "^1.10.0",
57 | "next": "^12.0.4",
58 | "next-images": "^1.7.0",
59 | "node-fetch": "^2.6.1",
60 | "passport": "^0.5.0",
61 | "react": "17.0.2",
62 | "react-dom": "17.0.2",
63 | "sass": "^1.38.2",
64 | "ts-node": "^9.1.1",
65 | "tsconfig-paths": "^3.9.0",
66 | "tsconfig-paths-webpack-plugin": "^3.5.1",
67 | "type-graphql": "^1.1.1",
68 | "typegoose": "^5.9.1",
69 | "typescript": "^4.5.2"
70 | },
71 | "devDependencies": {
72 | "@next/eslint-plugin-next": "^12.0.4",
73 | "@types/bcryptjs": "^2.4.2",
74 | "@types/compression": "^1.7.2",
75 | "@types/dotenv": "^8.2.0",
76 | "@types/express": "4.17.1",
77 | "@types/jest": "^26.0.23",
78 | "@types/mongoose": "^5.11.97",
79 | "@types/morgan": "^1.9.3",
80 | "@types/node": "^15.0.1",
81 | "@types/react": "^17.0.4",
82 | "@typescript-eslint/eslint-plugin": "^4.22.0",
83 | "@typescript-eslint/parser": "^4.22.0",
84 | "autoprefixer": "^10.3.3",
85 | "babel-eslint": "^10.1.0",
86 | "eslint": "^7.25.0",
87 | "eslint-config-prettier": "^8.2.0",
88 | "eslint-loader": "^4.0.2",
89 | "eslint-plugin-graphql": "^4.0.0",
90 | "eslint-plugin-import": "^2.22.1",
91 | "eslint-plugin-jsx-a11y": "^6.4.1",
92 | "eslint-plugin-prettier": "^3.4.0",
93 | "jest": "^26.6.3",
94 | "lint-staged": "^11.0.0",
95 | "nodemon": "^2.0.7",
96 | "postcss": "^8.3.6",
97 | "prettier": "^2.2.1",
98 | "stylelint": "^13.13.0",
99 | "stylelint-config-standard": "^22.0.0",
100 | "stylelint-scss": "^3.19.0",
101 | "ts-jest": "^26.5.5"
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/pages/_app.tsx:
--------------------------------------------------------------------------------
1 | import App from 'next/app'
2 | import { ApolloProvider } from '@apollo/client'
3 |
4 | import apollo from '@lib/apolloClient'
5 | import '@styles/main.scss'
6 |
7 | class MyApp extends App {
8 | render() {
9 | const { Component, pageProps } = this.props
10 |
11 | return (
12 |
13 |
14 |
15 | )
16 | }
17 | }
18 |
19 | export default MyApp
20 |
--------------------------------------------------------------------------------
/pages/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import Head from 'next/head'
3 | import Nav from '@views/components/Nav'
4 | import Footer from '@views/components/Footer'
5 |
6 | const Home = () => (
7 |
8 |
9 |
Home
10 |
11 |
12 |
13 |
14 |
15 |
16 |
Welcome to Next.js!
17 |
18 | To get started, edit pages/index.js
and save to reload.{' '}
19 |
20 | Good Luck with your project :) -Sebastian
21 |
22 |
23 |
40 |
41 |
42 |
43 |
89 |
90 | )
91 |
92 | export default Home
93 |
--------------------------------------------------------------------------------
/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: ['autoprefixer'],
3 | }
4 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Sebastp/Next-react-graphql-apollo_Boostrap/c66cb0e93b8aae0cb94fc7aaa5de8d83bca87bf3/public/favicon.ico
--------------------------------------------------------------------------------
/public/static/fonts/poppins-v5-latin-500.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Sebastp/Next-react-graphql-apollo_Boostrap/c66cb0e93b8aae0cb94fc7aaa5de8d83bca87bf3/public/static/fonts/poppins-v5-latin-500.eot
--------------------------------------------------------------------------------
/public/static/fonts/poppins-v5-latin-500.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Sebastp/Next-react-graphql-apollo_Boostrap/c66cb0e93b8aae0cb94fc7aaa5de8d83bca87bf3/public/static/fonts/poppins-v5-latin-500.ttf
--------------------------------------------------------------------------------
/public/static/fonts/poppins-v5-latin-500.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Sebastp/Next-react-graphql-apollo_Boostrap/c66cb0e93b8aae0cb94fc7aaa5de8d83bca87bf3/public/static/fonts/poppins-v5-latin-500.woff
--------------------------------------------------------------------------------
/public/static/fonts/poppins-v5-latin-500.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Sebastp/Next-react-graphql-apollo_Boostrap/c66cb0e93b8aae0cb94fc7aaa5de8d83bca87bf3/public/static/fonts/poppins-v5-latin-500.woff2
--------------------------------------------------------------------------------
/public/static/fonts/poppins-v5-latin-600.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Sebastp/Next-react-graphql-apollo_Boostrap/c66cb0e93b8aae0cb94fc7aaa5de8d83bca87bf3/public/static/fonts/poppins-v5-latin-600.eot
--------------------------------------------------------------------------------
/public/static/fonts/poppins-v5-latin-600.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
322 |
--------------------------------------------------------------------------------
/public/static/fonts/poppins-v5-latin-600.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Sebastp/Next-react-graphql-apollo_Boostrap/c66cb0e93b8aae0cb94fc7aaa5de8d83bca87bf3/public/static/fonts/poppins-v5-latin-600.ttf
--------------------------------------------------------------------------------
/public/static/fonts/poppins-v5-latin-600.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Sebastp/Next-react-graphql-apollo_Boostrap/c66cb0e93b8aae0cb94fc7aaa5de8d83bca87bf3/public/static/fonts/poppins-v5-latin-600.woff
--------------------------------------------------------------------------------
/public/static/fonts/poppins-v5-latin-600.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Sebastp/Next-react-graphql-apollo_Boostrap/c66cb0e93b8aae0cb94fc7aaa5de8d83bca87bf3/public/static/fonts/poppins-v5-latin-600.woff2
--------------------------------------------------------------------------------
/public/static/fonts/poppins-v5-latin-700.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Sebastp/Next-react-graphql-apollo_Boostrap/c66cb0e93b8aae0cb94fc7aaa5de8d83bca87bf3/public/static/fonts/poppins-v5-latin-700.eot
--------------------------------------------------------------------------------
/public/static/fonts/poppins-v5-latin-700.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
322 |
--------------------------------------------------------------------------------
/public/static/fonts/poppins-v5-latin-700.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Sebastp/Next-react-graphql-apollo_Boostrap/c66cb0e93b8aae0cb94fc7aaa5de8d83bca87bf3/public/static/fonts/poppins-v5-latin-700.ttf
--------------------------------------------------------------------------------
/public/static/fonts/poppins-v5-latin-700.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Sebastp/Next-react-graphql-apollo_Boostrap/c66cb0e93b8aae0cb94fc7aaa5de8d83bca87bf3/public/static/fonts/poppins-v5-latin-700.woff
--------------------------------------------------------------------------------
/public/static/fonts/poppins-v5-latin-700.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Sebastp/Next-react-graphql-apollo_Boostrap/c66cb0e93b8aae0cb94fc7aaa5de8d83bca87bf3/public/static/fonts/poppins-v5-latin-700.woff2
--------------------------------------------------------------------------------
/public/static/fonts/poppins-v5-latin-800.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Sebastp/Next-react-graphql-apollo_Boostrap/c66cb0e93b8aae0cb94fc7aaa5de8d83bca87bf3/public/static/fonts/poppins-v5-latin-800.eot
--------------------------------------------------------------------------------
/public/static/fonts/poppins-v5-latin-800.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
322 |
--------------------------------------------------------------------------------
/public/static/fonts/poppins-v5-latin-800.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Sebastp/Next-react-graphql-apollo_Boostrap/c66cb0e93b8aae0cb94fc7aaa5de8d83bca87bf3/public/static/fonts/poppins-v5-latin-800.ttf
--------------------------------------------------------------------------------
/public/static/fonts/poppins-v5-latin-800.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Sebastp/Next-react-graphql-apollo_Boostrap/c66cb0e93b8aae0cb94fc7aaa5de8d83bca87bf3/public/static/fonts/poppins-v5-latin-800.woff
--------------------------------------------------------------------------------
/public/static/fonts/poppins-v5-latin-800.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Sebastp/Next-react-graphql-apollo_Boostrap/c66cb0e93b8aae0cb94fc7aaa5de8d83bca87bf3/public/static/fonts/poppins-v5-latin-800.woff2
--------------------------------------------------------------------------------
/public/static/fonts/poppins-v5-latin-regular.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Sebastp/Next-react-graphql-apollo_Boostrap/c66cb0e93b8aae0cb94fc7aaa5de8d83bca87bf3/public/static/fonts/poppins-v5-latin-regular.eot
--------------------------------------------------------------------------------
/public/static/fonts/poppins-v5-latin-regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Sebastp/Next-react-graphql-apollo_Boostrap/c66cb0e93b8aae0cb94fc7aaa5de8d83bca87bf3/public/static/fonts/poppins-v5-latin-regular.ttf
--------------------------------------------------------------------------------
/public/static/fonts/poppins-v5-latin-regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Sebastp/Next-react-graphql-apollo_Boostrap/c66cb0e93b8aae0cb94fc7aaa5de8d83bca87bf3/public/static/fonts/poppins-v5-latin-regular.woff
--------------------------------------------------------------------------------
/public/static/fonts/poppins-v5-latin-regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Sebastp/Next-react-graphql-apollo_Boostrap/c66cb0e93b8aae0cb94fc7aaa5de8d83bca87bf3/public/static/fonts/poppins-v5-latin-regular.woff2
--------------------------------------------------------------------------------
/server/common/enums/UpdateOperators.ts:
--------------------------------------------------------------------------------
1 |
2 |
3 | export enum UpdateOperators {
4 | PLAIN,MAKE_DEFAULT,REMOVE
5 | }
6 |
--------------------------------------------------------------------------------
/server/common/models/Email.ts:
--------------------------------------------------------------------------------
1 | import { Field, ID, InputType, ObjectType } from 'type-graphql'
2 | import { prop as Property } from '@typegoose/typegoose/lib/prop'
3 | import { ObjectId } from 'mongoose'
4 |
5 | @ObjectType()
6 | @InputType('EmailInput')
7 | export default class Email {
8 | @Field((type) => ID, { nullable: true })
9 | readonly _id: ObjectId
10 |
11 | @Field((_type) => String, { nullable: false })
12 | @Property({ required: true })
13 | email: string
14 |
15 | @Field((_type) => Boolean, { nullable: false })
16 | @Property({ required: true, default: true })
17 | isDefault: boolean
18 |
19 | @Field((_type) => Boolean, { nullable: true })
20 | @Property({ required: true, default: true })
21 | isActive: boolean
22 | }
23 |
--------------------------------------------------------------------------------
/server/common/scalars.ts:
--------------------------------------------------------------------------------
1 | import { GraphQLScalarType, Kind } from 'graphql'
2 | import { ObjectId } from 'mongodb'
3 |
4 | export default {
5 | ObjectIdScalar: new GraphQLScalarType({
6 | name: 'ObjectId',
7 | description: 'Mongo object id scalar type',
8 | parseValue(value: string) {
9 | return new ObjectId(value) // value from the client input variables
10 | },
11 | serialize(value: ObjectId) {
12 | return value.toHexString() // value sent to the client
13 | },
14 | parseLiteral(ast) {
15 | if (ast.kind === Kind.STRING) {
16 | return new ObjectId(ast.value) // value from the client query
17 | }
18 | return null
19 | },
20 | }),
21 |
22 | IsoDate: new GraphQLScalarType({
23 | name: 'IsoDate',
24 | description: 'A date and time, represented as an ISO-8601 string',
25 | serialize: (value) => {
26 | if (value instanceof Date) {
27 | return value.toISOString()
28 | } else {
29 | return value
30 | }
31 | },
32 | parseValue: (value) => new Date(value),
33 | //@ts-ignore
34 | parseLiteral: (ast) => new Date(ast.value),
35 | }),
36 | }
37 |
--------------------------------------------------------------------------------
/server/core/apollo.ts:
--------------------------------------------------------------------------------
1 | import { ApolloServer } from 'apollo-server-express'
2 | // import { makeExecutableSchema } from '@graphql-tools/schema'
3 | // import typeDefs from '@server/subgraphs/typeDefs'
4 | // import resolvers from '@server/subgraphs/resolvers'
5 |
6 | import { buildContext } from 'graphql-passport'
7 | import UserResolver from '@server/subgraphs/user/user.resolver'
8 |
9 | //////
10 | import path from 'path'
11 | import { TypegooseMiddleware } from '@server/serverLib/typegoose-middleware'
12 | import { buildSchema } from 'type-graphql'
13 |
14 | //////
15 |
16 | // const { User } = models
17 | // const schema = makeExecutableSchema({ typeDefs, resolvers })
18 |
19 | export default async function () {
20 | const schema = await buildSchema({
21 | resolvers: [UserResolver], //[__dirname + '../subgraphs/**/*.resolver.ts'],
22 | emitSchemaFile: path.resolve(__dirname + '/../subgraphs', 'schema.gql'),
23 | // use document converting middleware
24 | globalMiddlewares: [TypegooseMiddleware],
25 | // validate: false,
26 | })
27 |
28 | const apollo = new ApolloServer({
29 | schema,
30 | context: ({ req, res }) => {
31 | return buildContext({ req, res, User: {} })
32 | },
33 | })
34 | await apollo.start()
35 | return apollo
36 | }
37 |
--------------------------------------------------------------------------------
/server/core/database.ts:
--------------------------------------------------------------------------------
1 | import mongoose from 'mongoose'
2 |
3 | const { MONGODB_URL } = process.env
4 |
5 | export const connectDB: any = async () => {
6 | return mongoose
7 | .connect(MONGODB_URL as string)
8 | .then(() => {
9 | console.log('Connected to MongoDB')
10 | })
11 | .catch((err: string) => {
12 | console.error(err)
13 | })
14 | }
15 |
--------------------------------------------------------------------------------
/server/index.ts:
--------------------------------------------------------------------------------
1 | require('dotenv').config()
2 |
3 | import express from 'express'
4 | import next from 'next'
5 | import morgan from 'morgan'
6 | import helmet from 'helmet'
7 | import compression from 'compression'
8 |
9 | import initApollo from '@server/core/apollo'
10 | import { connectDB } from '@server/core/database'
11 |
12 | const { PORT = '3000', NODE_ENV } = process.env
13 | const port = parseInt(PORT, 10) || 3000
14 | const dev = NODE_ENV !== 'production'
15 |
16 | console.log('Running env; ' + NODE_ENV)
17 |
18 | const nextApp = next({ dev })
19 | const handle = nextApp.getRequestHandler()
20 |
21 | nextApp.prepare().then(async () => {
22 | const server = express()
23 | const apollo = await initApollo()
24 | connectDB()
25 |
26 | //security
27 | server.use(
28 | helmet({
29 | contentSecurityPolicy: false,
30 | })
31 | )
32 | // Generate logs
33 | server.use(
34 | morgan(':method :url :status :res[content-length] - :response-time ms')
35 | )
36 | server.use(compression())
37 |
38 | //start apollo server
39 | apollo.applyMiddleware({ app: server })
40 |
41 | server.get('*', (req: any, res: any) => handle(req, res))
42 | // express().use(handler).listen(3000) //routes handle way
43 | //@ts-ignore
44 | server.listen(port, (err) => {
45 | if (err) throw err
46 | })
47 | })
48 |
--------------------------------------------------------------------------------
/server/serverLib/encryption.ts:
--------------------------------------------------------------------------------
1 | import bcrypt from 'bcryptjs'
2 |
3 | /**
4 | * use bcrypt to hash given string
5 | @return Promise
6 | */
7 | export const hashPassword = (stringToHash: string): Promise => {
8 | return new Promise((resolve, reject) => {
9 | bcrypt.genSalt(10, function(err, salt) {
10 | if (err) reject(err)
11 | bcrypt.hash(stringToHash, salt, function(err, hash) {
12 | if (err) reject(err)
13 | resolve(hash)
14 | })
15 | })
16 | })
17 | }
18 |
--------------------------------------------------------------------------------
/server/serverLib/resolvers.ts:
--------------------------------------------------------------------------------
1 | import path from 'path'
2 |
3 | import { fileLoader, mergeResolvers } from 'merge-graphql-schemas'
4 | import customScalars from '@server/common/scalars'
5 |
6 | //loads files automaticly so you don't have to import anything
7 | const resolversArray: any = fileLoader(
8 | path.join(__dirname, '../subgraphs/**/*.resolver.*')
9 | )
10 | export default mergeResolvers([customScalars, ...resolversArray])
11 |
--------------------------------------------------------------------------------
/server/serverLib/typegoose-middleware.ts:
--------------------------------------------------------------------------------
1 | import { Model, Document } from "mongoose";
2 | import { getClassForDocument } from "@typegoose/typegoose";
3 | import {MiddlewareFn} from "type-graphql";
4 |
5 |
6 | export const TypegooseMiddleware: MiddlewareFn = async (_, next) => {
7 | const result = await next();
8 |
9 | if (Array.isArray(result)) {
10 | return result.map(item => (item instanceof Model ? convertDocument(item) : item));
11 | }
12 |
13 | if (result instanceof Model) {
14 | return convertDocument(result);
15 | }
16 |
17 | return result;
18 | };
19 |
20 | function convertDocument(doc: Document) {
21 | const convertedDocument = doc.toObject();
22 | const DocumentClass = getClassForDocument(doc)!;
23 | Object.setPrototypeOf(convertedDocument, DocumentClass.prototype);
24 | return convertedDocument;
25 | }
--------------------------------------------------------------------------------
/server/subgraphs/schema.gql:
--------------------------------------------------------------------------------
1 | # -----------------------------------------------
2 | # !!! THIS FILE WAS GENERATED BY TYPE-GRAPHQL !!!
3 | # !!! DO NOT MODIFY THIS FILE BY YOURSELF !!!
4 | # -----------------------------------------------
5 |
6 | type Email {
7 | _id: ID
8 | email: String!
9 | isActive: Boolean
10 | isDefault: Boolean!
11 | }
12 |
13 | """Mongo object id scalar type"""
14 | scalar ObjectId
15 |
16 | type Query {
17 | candidate(candidateId: ObjectId!): User
18 | }
19 |
20 | type User {
21 | _id: ID
22 | avatar: String
23 | email: Email
24 | familyName: String
25 | firstName: String
26 | }
27 |
--------------------------------------------------------------------------------
/server/subgraphs/user/user.model.ts:
--------------------------------------------------------------------------------
1 | import { getModelForClass, prop as Property } from '@typegoose/typegoose'
2 | import { Field, ID, InputType, ObjectType } from 'type-graphql'
3 | import { ObjectId } from 'mongoose'
4 | import { TimeStamps, Base } from '@typegoose/typegoose/lib/defaultClasses'
5 |
6 | import Email from '@server/common/models/Email'
7 |
8 | @ObjectType()
9 | @InputType('UserInput')
10 | export default class User extends TimeStamps {
11 | @Field((_type) => ID, { nullable: true })
12 | readonly _id: ObjectId
13 |
14 | @Field((_type) => String, { nullable: true })
15 | @Property({ required: false })
16 | firstName: string
17 |
18 | @Field((_type) => String, { nullable: true })
19 | @Property({ required: false })
20 | familyName: string
21 |
22 | @Field((_type) => String, { nullable: true })
23 | @Property({ required: false })
24 | avatar: string
25 |
26 | @Field((_type) => Email, { nullable: true })
27 | @Property({ type: Email, required: false })
28 | email: Email
29 | }
30 |
31 | export const UserModel = getModelForClass(User)
32 |
--------------------------------------------------------------------------------
/server/subgraphs/user/user.resolver.ts:
--------------------------------------------------------------------------------
1 | import { Arg, Ctx, Mutation, Query, Resolver } from 'type-graphql'
2 | import UserService from './user.service'
3 | import User from './user.model'
4 | import { ObjectId } from 'mongoose'
5 | import scalars from '@server/common/scalars'
6 |
7 | // @Resolver((_of) => User)
8 | export default class UserResolver {
9 | @Query((returns) => User, { nullable: true })
10 | candidate(
11 | @Arg('candidateId', (type) => scalars.ObjectIdScalar)
12 | candidateId: ObjectId
13 | ) {
14 | console.log('Retrieving candidate with id ' + candidateId)
15 | return UserService.find(candidateId)
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/server/subgraphs/user/user.service.ts:
--------------------------------------------------------------------------------
1 | import User, { UserModel } from './user.model'
2 | import { ObjectId } from 'mongoose'
3 |
4 | const UserService = {
5 | async findAll() {
6 | return UserModel.find()
7 | },
8 |
9 | find(candidateId: ObjectId) {
10 | return UserModel.findById(candidateId)
11 | },
12 | }
13 |
14 | export default UserService
15 |
--------------------------------------------------------------------------------
/styles/base/_base.scss:
--------------------------------------------------------------------------------
1 | html {
2 | overflow-x: hidden;
3 | }
4 |
5 | body {
6 | color: $black;
7 | font-family: $poppins;
8 | font-size: 16px;
9 | -webkit-font-smoothing: antialiased;
10 | -webkit-text-size-adjust: 100%;
11 | /* prevent abrupt change in smoothing when animations complete (only in Safari) */
12 | -webkit-backface-visibility: hidden;
13 | cursor: default;
14 | overflow-x: hidden;
15 | overflow-y: hidden;
16 | max-width: 100vw;
17 | margin: auto;
18 | }
19 |
20 | #__next{
21 | display: block;
22 | position: relative;
23 | min-height: 100vh;
24 | margin: 0 auto;
25 | }
26 |
27 |
28 |
29 |
30 | // =====================================================
31 | // MEDIA QUERIES
32 | // =====================================================
33 |
34 | // Medium
35 | @media (min-width: 768px) {
36 | }
37 | // Large
38 | @media (max-width: 992px) {
39 | }
40 | // Extra large
41 | @media (max-width: 1225px) {
42 | }
43 |
44 | @media (max-width: 544px) {
45 | }
46 |
--------------------------------------------------------------------------------
/styles/base/_fonts.scss:
--------------------------------------------------------------------------------
1 | /* poppins-300 - latin */
2 | @font-face {
3 | font-family: 'Poppins';
4 | font-style: normal;
5 | font-weight: 300;
6 | src: url('/static/fonts/poppins/fonts/poppins-v6-latin-300.eot'); /* IE9 Compat Modes */
7 | src: local('Poppins Light'), local('Poppins-Light'),
8 | url('/static/fonts/poppins/fonts/poppins-v6-latin-300.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
9 | url('/static/fonts/poppins/fonts/poppins-v6-latin-300.woff2') format('woff2'), /* Super Modern Browsers */
10 | url('/static/fonts/poppins/fonts/poppins-v6-latin-300.woff') format('woff'), /* Modern Browsers */
11 | url('/static/fonts/poppins/fonts/poppins-v6-latin-300.ttf') format('truetype'), /* Safari, Android, iOS */
12 | url('/static/fonts/poppins/fonts/poppins-v6-latin-300.svg#Poppins') format('svg'); /* Legacy iOS */
13 | }
14 |
15 | /* poppins-regular - latin */
16 | @font-face {
17 | font-family: 'Poppins';
18 | font-style: normal;
19 | font-weight: 400;
20 | src: url('/static/fonts/poppins/fonts/poppins-v5-latin-regular.eot'); /* IE9 Compat Modes */
21 | src: local('Poppins Regular'), local('Poppins-Regular'),
22 | url('/static/fonts/poppins/fonts/poppins-v5-latin-regular.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
23 | url('/static/fonts/poppins/fonts/poppins-v5-latin-regular.woff2') format('woff2'), /* Super Modern Browsers */
24 | url('/static/fonts/poppins/fonts/poppins-v5-latin-regular.woff') format('woff'), /* Modern Browsers */
25 | url('/static/fonts/poppins/fonts/poppins-v5-latin-regular.ttf') format('truetype'), /* Safari, Android, iOS */
26 | url('/static/fonts/poppins/fonts/poppins-v5-latin-regular.svg#Poppins') format('svg'); /* Legacy iOS */
27 | }
28 | /* poppins-500 - latin */
29 | @font-face {
30 | font-family: 'Poppins';
31 | font-style: normal;
32 | font-weight: 500;
33 | src: url('/static/fonts/poppins/fonts/poppins-v5-latin-500.eot'); /* IE9 Compat Modes */
34 | src: local('Poppins Medium'), local('Poppins-Medium'),
35 | url('/static/fonts/poppins/fonts/poppins-v5-latin-500.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
36 | url('/static/fonts/poppins/fonts/poppins-v5-latin-500.woff2') format('woff2'), /* Super Modern Browsers */
37 | url('/static/fonts/poppins/fonts/poppins-v5-latin-500.woff') format('woff'), /* Modern Browsers */
38 | url('/static/fonts/poppins/fonts/poppins-v5-latin-500.ttf') format('truetype'), /* Safari, Android, iOS */
39 | url('/static/fonts/poppins/fonts/poppins-v5-latin-500.svg#Poppins') format('svg'); /* Legacy iOS */
40 | }
41 | /* poppins-600 - latin */
42 | @font-face {
43 | font-family: 'Poppins';
44 | font-style: normal;
45 | font-weight: 600;
46 | src: url('/static/fonts/poppins/fonts/poppins-v5-latin-600.eot'); /* IE9 Compat Modes */
47 | src: local('Poppins SemiBold'), local('Poppins-SemiBold'),
48 | url('/static/fonts/poppins/fonts/poppins-v5-latin-600.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
49 | url('/static/fonts/poppins/fonts/poppins-v5-latin-600.woff2') format('woff2'), /* Super Modern Browsers */
50 | url('/static/fonts/poppins/fonts/poppins-v5-latin-600.woff') format('woff'), /* Modern Browsers */
51 | url('/static/fonts/poppins/fonts/poppins-v5-latin-600.ttf') format('truetype'), /* Safari, Android, iOS */
52 | url('/static/fonts/poppins/fonts/poppins-v5-latin-600.svg#Poppins') format('svg'); /* Legacy iOS */
53 | }
54 | /* poppins-700 - latin */
55 | @font-face {
56 | font-family: 'Poppins';
57 | font-style: normal;
58 | font-weight: 700;
59 | src: url('/static/fonts/poppins/fonts/poppins-v5-latin-700.eot'); /* IE9 Compat Modes */
60 | src: local('Poppins Bold'), local('Poppins-Bold'),
61 | url('/static/fonts/poppins/fonts/poppins-v5-latin-700.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
62 | url('/static/fonts/poppins/fonts/poppins-v5-latin-700.woff2') format('woff2'), /* Super Modern Browsers */
63 | url('/static/fonts/poppins/fonts/poppins-v5-latin-700.woff') format('woff'), /* Modern Browsers */
64 | url('/static/fonts/poppins/fonts/poppins-v5-latin-700.ttf') format('truetype'), /* Safari, Android, iOS */
65 | url('/static/fonts/poppins/fonts/poppins-v5-latin-700.svg#Poppins') format('svg'); /* Legacy iOS */
66 | }
67 | /* poppins-800 - latin */
68 | @font-face {
69 | font-family: 'Poppins';
70 | font-style: normal;
71 | font-weight: 800;
72 | src: url('/static/fonts/poppins/fonts/poppins-v5-latin-800.eot'); /* IE9 Compat Modes */
73 | src: local('Poppins ExtraBold'), local('Poppins-ExtraBold'),
74 | url('/static/fonts/poppins/fonts/poppins-v5-latin-800.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
75 | url('/static/fonts/poppins/fonts/poppins-v5-latin-800.woff2') format('woff2'), /* Super Modern Browsers */
76 | url('/static/fonts/poppins/fonts/poppins-v5-latin-800.woff') format('woff'), /* Modern Browsers */
77 | url('/static/fonts/poppins/fonts/poppins-v5-latin-800.ttf') format('truetype'), /* Safari, Android, iOS */
78 | url('/static/fonts/poppins/fonts/poppins-v5-latin-800.svg#Poppins') format('svg'); /* Legacy iOS */
79 | }
80 |
81 |
82 |
--------------------------------------------------------------------------------
/styles/base/_variables.scss:
--------------------------------------------------------------------------------
1 | // =====================================================
2 | // COLORS
3 | // =====================================================
4 |
5 | $black: #000;
6 | $white: #fff;
7 |
8 |
9 |
10 | // =====================================================
11 | // Fonts
12 | // =====================================================
13 | $poppins: 'Poppins', sans-serif;
14 |
15 | // =====================================================
16 | // Fonts Weight
17 | // =====================================================
18 | $light: 300;
19 | $regular: 400;
20 | $medium: 500;
21 | $semi-bold: 600;
22 | $bold: 700;
23 |
24 | /* letter spacing
25 | 10 = 0.01em
26 | 20 = 0.02em
27 | */
28 |
--------------------------------------------------------------------------------
/styles/main.scss:
--------------------------------------------------------------------------------
1 | @charset 'UTF-8';
2 |
3 | // Base stuff
4 | @import 'base/variables', 'base/base', 'base/fonts';
5 |
6 | // Vendors
7 | @import 'vendors/normalize';
8 |
9 | // Page-specific styles
10 | @import 'pages/index';
11 |
--------------------------------------------------------------------------------
/styles/pages/_index.scss:
--------------------------------------------------------------------------------
1 | // -----------------------------------------------------------------------------
2 | // This file contains styles that are specific to the home page.
3 | // -----------------------------------------------------------------------------
4 |
--------------------------------------------------------------------------------
/styles/vendors/_normalize.scss:
--------------------------------------------------------------------------------
1 | /*! normalize.css v8.0.0 | MIT License | github.com/necolas/normalize.css */
2 |
3 | /* Document
4 | ========================================================================== */
5 |
6 | /**
7 | * 1. Correct the line height in all browsers.
8 | * 2. Prevent adjustments of font size after orientation changes in iOS.
9 | */
10 |
11 | html {
12 | line-height: 1.15; /* 1 */
13 | -webkit-text-size-adjust: 100%; /* 2 */
14 | }
15 |
16 | /* Sections
17 | ========================================================================== */
18 |
19 | /**
20 | * Remove the margin in all browsers.
21 | */
22 |
23 | body {
24 | margin: 0;
25 | }
26 |
27 | /**
28 | * Correct the font size and margin on `h1` elements within `section` and
29 | * `article` contexts in Chrome, Firefox, and Safari.
30 | */
31 |
32 | h1 {
33 | font-size: 2em;
34 | margin: 0;
35 | }
36 |
37 | h1, h2,h3,h4,h5,h6 {
38 | font-family: $poppins;
39 | font-weight: $regular;
40 | margin: 0;
41 | padding: 0;
42 |
43 | span{
44 | font-weight: inherit;
45 | }
46 | }
47 |
48 |
49 | ul{
50 | padding: 0;
51 | margin: 0;
52 | }
53 |
54 | /* Grouping content
55 | ========================================================================== */
56 |
57 | /**
58 | * 1. Add the correct box sizing in Firefox.
59 | * 2. Show the overflow in Edge and IE.
60 | */
61 |
62 | hr {
63 | box-sizing: content-box; /* 1 */
64 | height: 0; /* 1 */
65 | overflow: visible; /* 2 */
66 | }
67 |
68 | /**
69 | * 1. Correct the inheritance and scaling of font size in all browsers.
70 | * 2. Correct the odd `em` font sizing in all browsers.
71 | */
72 |
73 | pre {
74 | font-family: monospace, monospace; /* 1 */
75 | font-size: 1em; /* 2 */
76 | }
77 |
78 | /* Text-level semantics
79 | ========================================================================== */
80 |
81 | /**
82 | * Remove the gray background on active links in IE 10.
83 | */
84 |
85 | a {
86 | color: inherit;
87 | background-color: transparent;
88 | text-decoration: none;
89 |
90 | &:hover{
91 | text-decoration: none;
92 | color: inherit;
93 | }
94 | }
95 |
96 | ul{
97 | list-style: none;
98 | }
99 |
100 | /**
101 | * 1. Remove the bottom border in Chrome 57-
102 | * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.
103 | */
104 |
105 | abbr[title] {
106 | border-bottom: none; /* 1 */
107 | text-decoration: underline; /* 2 */
108 | text-decoration: underline dotted; /* 2 */
109 | }
110 |
111 | /**
112 | * Add the correct font weight in Chrome, Edge, and Safari.
113 | */
114 |
115 | b,
116 | strong {
117 | font-weight: bolder;
118 | }
119 |
120 | /**
121 | * 1. Correct the inheritance and scaling of font size in all browsers.
122 | * 2. Correct the odd `em` font sizing in all browsers.
123 | */
124 |
125 | code,
126 | kbd,
127 | samp {
128 | font-family: monospace, monospace; /* 1 */
129 | font-size: 1em; /* 2 */
130 | }
131 |
132 | /**
133 | * Add the correct font size in all browsers.
134 | */
135 |
136 | small {
137 | font-size: 80%;
138 | }
139 |
140 | /**
141 | * Prevent `sub` and `sup` elements from affecting the line height in
142 | * all browsers.
143 | */
144 |
145 | sub,
146 | sup {
147 | font-size: 75%;
148 | line-height: 0;
149 | position: relative;
150 | vertical-align: baseline;
151 | }
152 |
153 | sub {
154 | bottom: -0.25em;
155 | }
156 |
157 | sup {
158 | top: -0.5em;
159 | }
160 |
161 | /* Embedded content
162 | ========================================================================== */
163 |
164 | /**
165 | * Remove the border on images inside links in IE 10.
166 | */
167 |
168 | img {
169 | border-style: none;
170 | }
171 |
172 | /* Forms
173 | ========================================================================== */
174 |
175 | /**
176 | * 1. Change the font styles in all browsers.
177 | * 2. Remove the margin in Firefox and Safari.
178 | */
179 |
180 | button,
181 | input,
182 | optgroup,
183 | select,
184 | textarea {
185 | font-family: inherit; /* 1 */
186 | font-size: 100%; /* 1 */
187 | line-height: 1.15; /* 1 */
188 | margin: 0; /* 2 */
189 | background: none;
190 | }
191 |
192 | /**
193 | * Show the overflow in IE.
194 | * 1. Show the overflow in Edge.
195 | */
196 |
197 | button,
198 | input { /* 1 */
199 | overflow: visible;
200 | border: none;
201 |
202 | &:active{
203 | outline: none;
204 | border: none;
205 | }
206 | &:focus {outline:0;}
207 | }
208 |
209 | /**
210 | * Remove the inheritance of text transform in Edge, Firefox, and IE.
211 | * 1. Remove the inheritance of text transform in Firefox.
212 | */
213 |
214 | button,
215 | select { /* 1 */
216 | text-transform: none;
217 | }
218 |
219 | /**
220 | * Correct the inability to style clickable types in iOS and Safari.
221 | */
222 |
223 | button,
224 | [type="button"],
225 | [type="reset"],
226 | [type="submit"] {
227 | -webkit-appearance: button;
228 | }
229 |
230 | /**
231 | * Remove the inner border and padding in Firefox.
232 | */
233 |
234 | button::-moz-focus-inner,
235 | [type="button"]::-moz-focus-inner,
236 | [type="reset"]::-moz-focus-inner,
237 | [type="submit"]::-moz-focus-inner {
238 | border-style: none;
239 | padding: 0;
240 | }
241 |
242 | /**
243 | * Restore the focus styles unset by the previous rule.
244 | */
245 |
246 | button:-moz-focusring,
247 | [type="button"]:-moz-focusring,
248 | [type="reset"]:-moz-focusring,
249 | [type="submit"]:-moz-focusring {
250 | outline: 1px dotted ButtonText;
251 | }
252 |
253 |
254 | input[type=number]::-webkit-inner-spin-button,
255 | input[type=number]::-webkit-outer-spin-button {
256 | -webkit-appearance: none;
257 | }
258 |
259 | /**
260 | * Correct the padding in Firefox.
261 | */
262 |
263 | fieldset {
264 | padding: 0.35em 0.75em 0.625em;
265 | }
266 |
267 | /**
268 | * 1. Correct the text wrapping in Edge and IE.
269 | * 2. Correct the color inheritance from `fieldset` elements in IE.
270 | * 3. Remove the padding so developers are not caught out when they zero out
271 | * `fieldset` elements in all browsers.
272 | */
273 |
274 | legend {
275 | box-sizing: border-box; /* 1 */
276 | color: inherit; /* 2 */
277 | display: table; /* 1 */
278 | max-width: 100%; /* 1 */
279 | padding: 0; /* 3 */
280 | white-space: normal; /* 1 */
281 | }
282 |
283 | /**
284 | * Add the correct vertical alignment in Chrome, Firefox, and Opera.
285 | */
286 |
287 | progress {
288 | vertical-align: baseline;
289 | }
290 |
291 | /**
292 | * Remove the default vertical scrollbar in IE 10+.
293 | */
294 |
295 | textarea {
296 | overflow: auto;
297 | }
298 |
299 | /**
300 | * 1. Add the correct box sizing in IE 10.
301 | * 2. Remove the padding in IE 10.
302 | */
303 |
304 | [type="checkbox"],
305 | [type="radio"] {
306 | box-sizing: border-box; /* 1 */
307 | padding: 0; /* 2 */
308 | }
309 |
310 | /**
311 | * Correct the cursor style of increment and decrement buttons in Chrome.
312 | */
313 |
314 | [type="number"]::-webkit-inner-spin-button,
315 | [type="number"]::-webkit-outer-spin-button {
316 | height: auto;
317 | }
318 |
319 | /**
320 | * 1. Correct the odd appearance in Chrome and Safari.
321 | * 2. Correct the outline style in Safari.
322 | */
323 |
324 | [type="search"] {
325 | -webkit-appearance: textfield; /* 1 */
326 | outline-offset: -2px; /* 2 */
327 | }
328 |
329 | /**
330 | * Remove the inner padding in Chrome and Safari on macOS.
331 | */
332 |
333 | [type="search"]::-webkit-search-decoration {
334 | -webkit-appearance: none;
335 | }
336 |
337 | /**
338 | * 1. Correct the inability to style clickable types in iOS and Safari.
339 | * 2. Change font properties to `inherit` in Safari.
340 | */
341 |
342 | ::-webkit-file-upload-button {
343 | -webkit-appearance: button; /* 1 */
344 | font: inherit; /* 2 */
345 | }
346 |
347 | /* Interactive
348 | ========================================================================== */
349 |
350 | /*
351 | * Add the correct display in Edge, IE 10+, and Firefox.
352 | */
353 |
354 | details {
355 | display: block;
356 | }
357 |
358 | /*
359 | * Add the correct display in all browsers.
360 | */
361 |
362 | summary {
363 | display: list-item;
364 | }
365 |
366 | /* Misc
367 | ========================================================================== */
368 |
369 | /**
370 | * Add the correct display in IE 10+.
371 | */
372 |
373 | template {
374 | display: none;
375 | }
376 |
377 | /**
378 | * Add the correct display in IE 10.
379 | */
380 |
381 | [hidden] {
382 | display: none;
383 | }
384 |
385 |
386 | p{
387 | margin: 0;
388 | }
389 |
390 |
391 | .scrlbar-hidden{
392 | &::-webkit-scrollbar-track{
393 | background: none;
394 | display: none;
395 | }
396 |
397 | &::-webkit-scrollbar{
398 | background: none;
399 | display: none;
400 | }
401 |
402 | &::-webkit-scrollbar-thumb{
403 | background: none;
404 | display: none;
405 | }
406 | }
407 |
--------------------------------------------------------------------------------
/tests/jest.integration.config.js:
--------------------------------------------------------------------------------
1 | import * as path from 'path'
2 |
3 | module.exports = {
4 | verbose: true,
5 | // moduleFileExtensions: ['**/*.integration.js'],
6 | testRegex: 'integration.test',
7 | globalSetup: path.join(__dirname, './global-setup.js'),
8 | globalTeardown: path.join(__dirname, './global-teardown.js'),
9 | testEnvironment: 'node',
10 | }
11 |
--------------------------------------------------------------------------------
/tests/jest.unit.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | verbose: true,
3 | testEnvironment: 'node',
4 | testRegex: 'unit.test',
5 | }
6 |
--------------------------------------------------------------------------------
/tests/test-setup.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Defines the React 16 Adapter for Enzyme.
3 | *
4 | * @link http://airbnb.io/enzyme/docs/installation/#working-with-react-16
5 | * @copyright 2017 Airbnb, Inc.
6 | */
7 |
8 | import * as enzyme from 'enzyme'
9 | import Adapter from 'enzyme-adapter-react-16'
10 |
11 | enzyme.configure({ adapter: new Adapter() })
12 |
--------------------------------------------------------------------------------
/tsconfig.jest.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig.json",
3 | "exclude": ["node_modules", "jest"],
4 | "compilerOptions": {
5 | "jsx": "react"
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "esnext",
4 | "module": "esnext",
5 | "lib": ["es6", "es7", "esnext", "dom"],
6 | "allowJs": true,
7 | "skipLibCheck": true,
8 | "strict": true,
9 | "forceConsistentCasingInFileNames": true,
10 | "noEmit": true,
11 | "esModuleInterop": true,
12 | "moduleResolution": "node",
13 | "resolveJsonModule": true,
14 | "isolatedModules": true,
15 | "jsx": "preserve",
16 | "strictNullChecks": false,
17 | "allowSyntheticDefaultImports": true,
18 | "noFallthroughCasesInSwitch": true,
19 | "experimentalDecorators": true,
20 | "emitDecoratorMetadata": true,
21 | "sourceMap": true,
22 | "baseUrl": "./",
23 | "typeRoots": ["node_modules/@types", "@types"],
24 | "paths": {
25 | "@types/*": ["./@types/*"],
26 | "@constants/*": ["./constants/*"],
27 | "@graphql/*": ["./graphql/*"],
28 | "@views/*": ["./views/*"],
29 | "@viewsUi/*": ["./views/ui/*"],
30 | "@viewsComp/*": ["./views/components/*"],
31 | "@styles/*": ["./styles/*"],
32 | "@server/*": ["./server/*"],
33 | "@lib/*": ["./lib/*"],
34 | "@assets/*": ["./assets/*"],
35 | "@static/*": ["./public/static/*"]
36 | },
37 | "incremental": true
38 | },
39 | "exclude": [
40 | "node_modules",
41 | "dist",
42 | ".next",
43 | "out",
44 | "next.config.js",
45 | ".babelrc",
46 | "bundles",
47 | "coverage",
48 | "test/*"
49 | ],
50 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"]
51 | }
52 |
--------------------------------------------------------------------------------
/tsconfig.server.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig.json",
3 | "compilerOptions": {
4 | "module": "commonjs",
5 | "outDir": "dist",
6 | "target": "es2018",
7 | "isolatedModules": false,
8 | "noEmit": false
9 | },
10 | "include": ["server/**/*.ts"]
11 | }
12 |
--------------------------------------------------------------------------------
/views/components/Footer.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import styles from './footer.module.scss'
3 |
4 | const Footer = () => (
5 |
8 | )
9 |
10 | export default Footer
11 |
--------------------------------------------------------------------------------
/views/components/Nav.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import Link from 'next/link'
3 | import styles from './nav.module.scss'
4 |
5 | const Nav = () => (
6 |
42 | )
43 |
44 | export default Nav
45 |
--------------------------------------------------------------------------------
/views/components/footer.module.scss:
--------------------------------------------------------------------------------
1 | @import '@styles/base/variables';
2 |
3 | .footer {
4 | text-align: center;
5 |
6 | p {
7 | color: $black;
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/views/components/nav.module.scss:
--------------------------------------------------------------------------------
1 | @import '@styles/base/variables';
2 |
--------------------------------------------------------------------------------
/views/ui/Button.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | interface IProps {
4 | loading: boolean
5 | children: string
6 | }
7 |
8 | const Button = ({ loading = false, children, ...props }: IProps) => (
9 |
13 | )
14 |
15 | export default Button
16 |
--------------------------------------------------------------------------------