├── .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 |
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 | 4 | 5 | 12 | 13 | 14 | 15 | 17 | 19 | 22 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 36 | 37 | 38 | 40 | 41 | 43 | 45 | 46 | 49 | 51 | 52 | 53 | 54 | 55 | 56 | 58 | 61 | 62 | 64 | 66 | 67 | 68 | 69 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 80 | 81 | 83 | 84 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 101 | 103 | 105 | 107 | 109 | 110 | 112 | 113 | 114 | 115 | 116 | 117 | 119 | 120 | 122 | 124 | 126 | 127 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 138 | 139 | 141 | 143 | 144 | 145 | 147 | 149 | 151 | 152 | 153 | 156 | 158 | 161 | 163 | 164 | 165 | 166 | 169 | 170 | 172 | 173 | 174 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 184 | 185 | 186 | 188 | 190 | 192 | 193 | 194 | 195 | 197 | 199 | 201 | 202 | 204 | 205 | 206 | 207 | 209 | 210 | 211 | 212 | 214 | 216 | 218 | 220 | 222 | 224 | 227 | 230 | 231 | 233 | 234 | 235 | 236 | 238 | 239 | 240 | 242 | 244 | 246 | 248 | 251 | 254 | 257 | 260 | 262 | 264 | 266 | 268 | 271 | 272 | 273 | 274 | 276 | 278 | 280 | 282 | 284 | 286 | 289 | 292 | 293 | 295 | 296 | 297 | 298 | 300 | 301 | 303 | 305 | 306 | 307 | 308 | 309 | 310 | 312 | 314 | 316 | 317 | 318 | 319 | 320 | 321 | 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 | 4 | 5 | 12 | 13 | 14 | 15 | 17 | 20 | 23 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 36 | 37 | 38 | 40 | 41 | 43 | 45 | 46 | 49 | 51 | 52 | 53 | 54 | 55 | 56 | 58 | 61 | 62 | 64 | 66 | 67 | 68 | 69 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 80 | 81 | 83 | 84 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 101 | 103 | 105 | 107 | 109 | 110 | 112 | 113 | 114 | 115 | 116 | 117 | 119 | 120 | 122 | 124 | 126 | 127 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 138 | 139 | 141 | 143 | 144 | 145 | 147 | 149 | 151 | 152 | 153 | 156 | 158 | 161 | 163 | 164 | 165 | 166 | 169 | 170 | 172 | 173 | 174 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 184 | 185 | 186 | 188 | 190 | 192 | 193 | 194 | 195 | 197 | 199 | 201 | 202 | 204 | 205 | 206 | 207 | 209 | 210 | 211 | 212 | 214 | 216 | 218 | 220 | 222 | 224 | 227 | 230 | 231 | 233 | 234 | 235 | 237 | 239 | 240 | 241 | 243 | 245 | 247 | 249 | 252 | 255 | 258 | 261 | 263 | 265 | 267 | 269 | 272 | 273 | 274 | 275 | 277 | 279 | 281 | 283 | 285 | 287 | 290 | 293 | 294 | 296 | 297 | 298 | 299 | 301 | 302 | 304 | 306 | 307 | 308 | 309 | 310 | 311 | 313 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 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 | 4 | 5 | 12 | 13 | 14 | 15 | 17 | 19 | 22 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 35 | 36 | 37 | 39 | 40 | 42 | 44 | 45 | 48 | 50 | 51 | 52 | 53 | 54 | 55 | 57 | 60 | 61 | 63 | 65 | 66 | 67 | 68 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 79 | 80 | 82 | 83 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 100 | 102 | 104 | 106 | 108 | 109 | 111 | 112 | 113 | 114 | 115 | 116 | 118 | 119 | 121 | 123 | 125 | 126 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 137 | 138 | 141 | 143 | 144 | 145 | 147 | 149 | 151 | 152 | 153 | 156 | 158 | 161 | 163 | 164 | 165 | 166 | 169 | 170 | 172 | 173 | 174 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 184 | 185 | 186 | 188 | 190 | 192 | 193 | 194 | 195 | 197 | 199 | 201 | 202 | 204 | 205 | 206 | 207 | 209 | 210 | 211 | 212 | 214 | 216 | 218 | 220 | 222 | 224 | 227 | 230 | 231 | 233 | 234 | 235 | 237 | 239 | 240 | 241 | 243 | 245 | 247 | 249 | 252 | 255 | 258 | 261 | 263 | 265 | 267 | 269 | 272 | 273 | 274 | 275 | 277 | 279 | 281 | 283 | 285 | 287 | 290 | 293 | 294 | 296 | 297 | 298 | 299 | 301 | 302 | 304 | 306 | 307 | 308 | 309 | 310 | 311 | 313 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 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 |
6 |

Im here to stay (Footer)

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