├── react-cars-app ├── .env ├── src │ ├── react-app-env.d.ts │ ├── typings │ │ ├── react-burger-menu.d.ts │ │ ├── react-carousel.d.ts │ │ ├── index.ts │ │ └── car.ts │ ├── assets │ │ └── images │ │ │ ├── jeep.png │ │ │ ├── porche.png │ │ │ ├── car-logo.png │ │ │ ├── car-logo-dark.png │ │ │ ├── mclaren-orange.png │ │ │ ├── homepage_design.png │ │ │ ├── mclaren-orange-big.png │ │ │ └── blob.svg │ ├── app │ │ ├── containers │ │ │ └── HomePage │ │ │ │ ├── type.ts │ │ │ │ ├── selectors.ts │ │ │ │ ├── slice.ts │ │ │ │ ├── index.tsx │ │ │ │ ├── aboutUs.tsx │ │ │ │ ├── bookingSteps.tsx │ │ │ │ ├── topSection.tsx │ │ │ │ └── topCars.tsx │ │ ├── graphql.ts │ │ ├── services │ │ │ └── carService │ │ │ │ ├── queries.ts │ │ │ │ ├── index.ts │ │ │ │ └── __generated__ │ │ │ │ └── GetCars.ts │ │ ├── hooks.ts │ │ ├── components │ │ │ ├── responsive │ │ │ │ └── index.ts │ │ │ ├── navbar │ │ │ │ ├── index.tsx │ │ │ │ ├── menuStyles.ts │ │ │ │ └── navItems.tsx │ │ │ ├── marginer │ │ │ │ └── index.tsx │ │ │ ├── logo │ │ │ │ └── index.tsx │ │ │ ├── button │ │ │ │ └── index.tsx │ │ │ ├── car │ │ │ │ └── index.tsx │ │ │ ├── bookCard │ │ │ │ └── index.tsx │ │ │ └── footer │ │ │ │ └── index.tsx │ │ ├── store.ts │ │ └── graphql-schema.json │ ├── setupTests.ts │ ├── App.test.tsx │ ├── App.tsx │ ├── index.css │ ├── App.css │ ├── index.tsx │ ├── logo.svg │ └── serviceWorker.ts ├── public │ ├── robots.txt │ ├── favicon.ico │ ├── logo192.png │ ├── logo512.png │ ├── manifest.json │ └── index.html ├── HomePage_Demo.png ├── craco.config.js ├── Dockerfile ├── .gitignore ├── server.js ├── __generated__ │ └── globalTypes.ts ├── tsconfig.json ├── tailwind.config.js ├── README.md └── package.json ├── nestjs-cars-app ├── .env ├── .prettierrc ├── nest-cli.json ├── tsconfig.build.json ├── src │ ├── app.service.ts │ ├── components │ │ ├── components.module.ts │ │ └── cars │ │ │ ├── cars.module.ts │ │ │ ├── dto │ │ │ └── new-car.input.ts │ │ │ ├── entities │ │ │ └── car.ts │ │ │ ├── cars.resolver.ts │ │ │ └── cars.service.ts │ ├── app.controller.ts │ ├── main.ts │ ├── migrations │ │ └── 1622304168366-CreateDatabase.ts │ ├── database │ │ └── database.module.ts │ ├── app.controller.spec.ts │ └── app.module.ts ├── test │ ├── jest-e2e.json │ └── app.e2e-spec.ts ├── tsconfig.json ├── Dockerfile ├── .gitignore ├── .eslintrc.js ├── ormconfig.json ├── package.json ├── README.md └── bin │ └── wait-for ├── .infragenie └── infrastructure_model.png ├── nginx └── nginx.conf ├── README.md └── docker-compose.yml /react-cars-app/.env: -------------------------------------------------------------------------------- 1 | PORT=3000 2 | REACT_APP_API_URL=http://localhost:9000 -------------------------------------------------------------------------------- /nestjs-cars-app/.env: -------------------------------------------------------------------------------- 1 | PORT=9000 2 | DB_NAME=yourcar 3 | DB_USER=root 4 | DB_PASS=pass -------------------------------------------------------------------------------- /react-cars-app/src/react-app-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /nestjs-cars-app/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "trailingComma": "all" 4 | } -------------------------------------------------------------------------------- /react-cars-app/src/typings/react-burger-menu.d.ts: -------------------------------------------------------------------------------- 1 | declare module "react-burger-menu"; 2 | -------------------------------------------------------------------------------- /react-cars-app/src/typings/react-carousel.d.ts: -------------------------------------------------------------------------------- 1 | declare module "@brainhubeu/react-carousel"; 2 | -------------------------------------------------------------------------------- /nestjs-cars-app/nest-cli.json: -------------------------------------------------------------------------------- 1 | { 2 | "collection": "@nestjs/schematics", 3 | "sourceRoot": "src" 4 | } 5 | -------------------------------------------------------------------------------- /react-cars-app/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /react-cars-app/HomePage_Demo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ipenywis/react-nestjs-full-web-app/HEAD/react-cars-app/HomePage_Demo.png -------------------------------------------------------------------------------- /react-cars-app/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ipenywis/react-nestjs-full-web-app/HEAD/react-cars-app/public/favicon.ico -------------------------------------------------------------------------------- /react-cars-app/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ipenywis/react-nestjs-full-web-app/HEAD/react-cars-app/public/logo192.png -------------------------------------------------------------------------------- /react-cars-app/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ipenywis/react-nestjs-full-web-app/HEAD/react-cars-app/public/logo512.png -------------------------------------------------------------------------------- /.infragenie/infrastructure_model.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ipenywis/react-nestjs-full-web-app/HEAD/.infragenie/infrastructure_model.png -------------------------------------------------------------------------------- /nestjs-cars-app/tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "exclude": ["node_modules", "test", "dist", "**/*spec.ts"] 4 | } 5 | -------------------------------------------------------------------------------- /react-cars-app/src/assets/images/jeep.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ipenywis/react-nestjs-full-web-app/HEAD/react-cars-app/src/assets/images/jeep.png -------------------------------------------------------------------------------- /react-cars-app/src/assets/images/porche.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ipenywis/react-nestjs-full-web-app/HEAD/react-cars-app/src/assets/images/porche.png -------------------------------------------------------------------------------- /react-cars-app/src/assets/images/car-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ipenywis/react-nestjs-full-web-app/HEAD/react-cars-app/src/assets/images/car-logo.png -------------------------------------------------------------------------------- /react-cars-app/src/assets/images/car-logo-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ipenywis/react-nestjs-full-web-app/HEAD/react-cars-app/src/assets/images/car-logo-dark.png -------------------------------------------------------------------------------- /react-cars-app/src/assets/images/mclaren-orange.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ipenywis/react-nestjs-full-web-app/HEAD/react-cars-app/src/assets/images/mclaren-orange.png -------------------------------------------------------------------------------- /react-cars-app/src/assets/images/homepage_design.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ipenywis/react-nestjs-full-web-app/HEAD/react-cars-app/src/assets/images/homepage_design.png -------------------------------------------------------------------------------- /react-cars-app/src/assets/images/mclaren-orange-big.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ipenywis/react-nestjs-full-web-app/HEAD/react-cars-app/src/assets/images/mclaren-orange-big.png -------------------------------------------------------------------------------- /react-cars-app/src/typings/index.ts: -------------------------------------------------------------------------------- 1 | import { IHomePageState } from "../app/containers/HomePage/type"; 2 | 3 | export interface IRootAppState { 4 | homePage: IHomePageState; 5 | } 6 | -------------------------------------------------------------------------------- /nestjs-cars-app/src/app.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@nestjs/common'; 2 | 3 | @Injectable() 4 | export class AppService { 5 | getHello(): string { 6 | return 'Hello World!'; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /react-cars-app/craco.config.js: -------------------------------------------------------------------------------- 1 | // craco.config.js 2 | module.exports = { 3 | style: { 4 | postcss: { 5 | plugins: [require("tailwindcss"), require("autoprefixer")], 6 | }, 7 | }, 8 | }; 9 | -------------------------------------------------------------------------------- /react-cars-app/src/app/containers/HomePage/type.ts: -------------------------------------------------------------------------------- 1 | import { GetCars_cars } from "../../services/carService/__generated__/GetCars"; 2 | 3 | export interface IHomePageState { 4 | topCars: GetCars_cars[]; 5 | } 6 | -------------------------------------------------------------------------------- /nestjs-cars-app/src/components/components.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { CarsModule } from './cars/cars.module'; 3 | 4 | @Module({ 5 | imports: [CarsModule], 6 | }) 7 | export class ComponentsModule {} 8 | -------------------------------------------------------------------------------- /react-cars-app/src/typings/car.ts: -------------------------------------------------------------------------------- 1 | export interface ICar { 2 | thumbnailSrc: string; 3 | name: string; 4 | mileage: string; 5 | gearType: string; 6 | dailyPrice: number; 7 | monthlyPrice: number; 8 | gas: string; 9 | } 10 | -------------------------------------------------------------------------------- /nestjs-cars-app/test/jest-e2e.json: -------------------------------------------------------------------------------- 1 | { 2 | "moduleFileExtensions": ["js", "json", "ts"], 3 | "rootDir": ".", 4 | "testEnvironment": "node", 5 | "testRegex": ".e2e-spec.ts$", 6 | "transform": { 7 | "^.+\\.(t|j)s$": "ts-jest" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /react-cars-app/src/app/graphql.ts: -------------------------------------------------------------------------------- 1 | import { ApolloClient, InMemoryCache } from "@apollo/client"; 2 | 3 | export const apolloClient = new ApolloClient({ 4 | uri: `${process.env.REACT_APP_API_URL}/graphql` as any, 5 | cache: new InMemoryCache(), 6 | }); 7 | -------------------------------------------------------------------------------- /react-cars-app/src/setupTests.ts: -------------------------------------------------------------------------------- 1 | // jest-dom adds custom jest matchers for asserting on DOM nodes. 2 | // allows you to do things like: 3 | // expect(element).toHaveTextContent(/react/i) 4 | // learn more: https://github.com/testing-library/jest-dom 5 | import '@testing-library/jest-dom/extend-expect'; 6 | -------------------------------------------------------------------------------- /react-cars-app/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:14 as production 2 | 3 | ARG NODE_ENV=production 4 | ENV NODE_ENV=${NODE_ENV} 5 | 6 | WORKDIR /usr/src/app 7 | 8 | COPY package.json . 9 | COPY yarn.lock . 10 | 11 | RUN yarn install --production=false 12 | 13 | COPY . . 14 | 15 | RUN yarn build 16 | 17 | CMD ["node", "server.js"] -------------------------------------------------------------------------------- /react-cars-app/src/app/services/carService/queries.ts: -------------------------------------------------------------------------------- 1 | import gql from "graphql-tag"; 2 | 3 | export const GET_ALL_CARS = gql` 4 | query GetCars { 5 | cars { 6 | id 7 | name 8 | mileage 9 | gearType 10 | gas 11 | thumbnailUrl 12 | dailyPrice 13 | monthlyPrice 14 | } 15 | } 16 | `; 17 | -------------------------------------------------------------------------------- /react-cars-app/src/app/containers/HomePage/selectors.ts: -------------------------------------------------------------------------------- 1 | import { createSelector } from "reselect"; 2 | import { IRootAppState } from "../../../typings"; 3 | 4 | const selectHomePage = (state: IRootAppState) => state.homePage; 5 | 6 | export const makeSelectTopCars = createSelector( 7 | selectHomePage, 8 | (homePage) => homePage.topCars 9 | ); 10 | -------------------------------------------------------------------------------- /nestjs-cars-app/src/app.controller.ts: -------------------------------------------------------------------------------- 1 | import { Controller, Get } from '@nestjs/common'; 2 | import { AppService } from './app.service'; 3 | 4 | @Controller() 5 | export class AppController { 6 | constructor(private readonly appService: AppService) {} 7 | 8 | @Get() 9 | getHello(): string { 10 | return this.appService.getHello(); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /react-cars-app/src/app/hooks.ts: -------------------------------------------------------------------------------- 1 | import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux'; 2 | import type { RootState, AppDispatch } from './store'; 3 | 4 | // Use throughout your app instead of plain `useDispatch` and `useSelector` 5 | export const useAppDispatch = () => useDispatch(); 6 | export const useAppSelector: TypedUseSelectorHook = useSelector; 7 | -------------------------------------------------------------------------------- /nestjs-cars-app/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "declaration": true, 5 | "removeComments": true, 6 | "emitDecoratorMetadata": true, 7 | "experimentalDecorators": true, 8 | "allowSyntheticDefaultImports": true, 9 | "target": "es2017", 10 | "sourceMap": true, 11 | "outDir": "./dist", 12 | "baseUrl": "./", 13 | "incremental": true 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /react-cars-app/.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 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | -------------------------------------------------------------------------------- /react-cars-app/server.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | 3 | const path = require("path"); 4 | const app = express(); 5 | 6 | const PORT = 3000; 7 | 8 | app.use(express.static(path.join(__dirname, "build"))); 9 | 10 | app.get("/", function (req, res) { 11 | res.sendFile(path.join(__dirname, "build", "index.html")); 12 | }); 13 | 14 | app.listen(PORT); 15 | 16 | console.log("React Server is Running on PORT: ", PORT); 17 | -------------------------------------------------------------------------------- /nestjs-cars-app/src/main.ts: -------------------------------------------------------------------------------- 1 | import { ValidationPipe } from '@nestjs/common'; 2 | import { BaseExceptionFilter, NestFactory } from '@nestjs/core'; 3 | import { AppModule } from './app.module'; 4 | 5 | async function bootstrap() { 6 | const app = await NestFactory.create(AppModule); 7 | app.useGlobalPipes(new ValidationPipe()); 8 | 9 | app.enableCors(); 10 | 11 | await app.listen(process.env.PORT || 9000); 12 | } 13 | bootstrap(); 14 | -------------------------------------------------------------------------------- /react-cars-app/src/app/components/responsive/index.ts: -------------------------------------------------------------------------------- 1 | export const SCREENS = { 2 | sm: "640px", 3 | // => @media (min-width: 640px) { ... } 4 | 5 | md: "768px", 6 | // => @media (min-width: 768px) { ... } 7 | 8 | lg: "1024px", 9 | // => @media (min-width: 1024px) { ... } 10 | 11 | xl: "1280px", 12 | // => @media (min-width: 1280px) { ... } 13 | 14 | "2xl": "1536px", 15 | // => @media (min-width: 1536px) { ... } 16 | }; 17 | -------------------------------------------------------------------------------- /nestjs-cars-app/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:14 AS production 2 | 3 | ARG NODE_ENV=production 4 | ENV NODE_ENV=${NODE_ENV} 5 | 6 | WORKDIR /usr/src/api 7 | 8 | COPY package.json . 9 | COPY yarn.lock . 10 | 11 | RUN yarn global add @nestjs/cli 12 | RUN yarn install --production=true 13 | 14 | RUN apt-get -q update && apt-get -qy install netcat 15 | 16 | COPY . . 17 | 18 | RUN yarn build 19 | 20 | CMD ["sh", "-c", "yarn typeorm migration:run && yarn start:prod"] -------------------------------------------------------------------------------- /nestjs-cars-app/src/migrations/1622304168366-CreateDatabase.ts: -------------------------------------------------------------------------------- 1 | import { MigrationInterface, QueryRunner } from 'typeorm'; 2 | 3 | export class CreateDatabase1622304168366 implements MigrationInterface { 4 | public async up(queryRunner: QueryRunner): Promise { 5 | queryRunner.createDatabase('yourcar', true); 6 | } 7 | 8 | public async down(queryRunner: QueryRunner): Promise { 9 | queryRunner.dropDatabase('yourcar', true); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /react-cars-app/src/App.test.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { render } from '@testing-library/react'; 3 | import { Provider } from 'react-redux'; 4 | import { store } from './app/store'; 5 | import App from './App'; 6 | 7 | test('renders learn react link', () => { 8 | const { getByText } = render( 9 | 10 | 11 | 12 | ); 13 | 14 | expect(getByText(/learn/i)).toBeInTheDocument(); 15 | }); 16 | -------------------------------------------------------------------------------- /react-cars-app/src/assets/images/blob.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /nestjs-cars-app/src/components/cars/cars.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { TypeOrmModule } from '@nestjs/typeorm'; 3 | import { CarsResolver } from './cars.resolver'; 4 | import { CarsService } from './cars.service'; 5 | import { Car } from './entities/car'; 6 | 7 | @Module({ 8 | imports: [TypeOrmModule.forFeature([Car])], 9 | providers: [CarsService, CarsResolver], 10 | exports: [CarsService], 11 | }) 12 | export class CarsModule {} 13 | -------------------------------------------------------------------------------- /react-cars-app/src/App.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import styled from "styled-components"; 3 | import tw from "twin.macro"; 4 | import "./App.css"; 5 | import { HomePage } from "./app/containers/HomePage"; 6 | 7 | const AppContainer = styled.div` 8 | ${tw` 9 | w-full 10 | h-full 11 | flex 12 | flex-col 13 | `}; 14 | `; 15 | 16 | function App() { 17 | return ( 18 | 19 | 20 | 21 | ); 22 | } 23 | 24 | export default App; 25 | -------------------------------------------------------------------------------- /react-cars-app/__generated__/globalTypes.ts: -------------------------------------------------------------------------------- 1 | /* tslint:disable */ 2 | /* eslint-disable */ 3 | // @generated 4 | // This file was automatically generated and should not be edited. 5 | 6 | //============================================================== 7 | // START Enums and Input Objects 8 | //============================================================== 9 | 10 | //============================================================== 11 | // END Enums and Input Objects 12 | //============================================================== 13 | -------------------------------------------------------------------------------- /nestjs-cars-app/.gitignore: -------------------------------------------------------------------------------- 1 | # compiled output 2 | /dist 3 | /node_modules 4 | 5 | # Logs 6 | logs 7 | *.log 8 | npm-debug.log* 9 | yarn-debug.log* 10 | yarn-error.log* 11 | lerna-debug.log* 12 | 13 | # OS 14 | .DS_Store 15 | 16 | # Tests 17 | /coverage 18 | /.nyc_output 19 | 20 | # IDEs and editors 21 | /.idea 22 | .project 23 | .classpath 24 | .c9/ 25 | *.launch 26 | .settings/ 27 | *.sublime-workspace 28 | 29 | # IDE - VSCode 30 | .vscode/* 31 | !.vscode/settings.json 32 | !.vscode/tasks.json 33 | !.vscode/launch.json 34 | !.vscode/extensions.json -------------------------------------------------------------------------------- /react-cars-app/src/app/containers/HomePage/slice.ts: -------------------------------------------------------------------------------- 1 | import { Action, createSlice } from "@reduxjs/toolkit"; 2 | import { IHomePageState } from "./type"; 3 | 4 | const initialState: IHomePageState = { 5 | topCars: [], 6 | }; 7 | 8 | const homePageSlice = createSlice({ 9 | name: "homePage", 10 | initialState, 11 | reducers: { 12 | setTopCars: (state, action) => { 13 | state.topCars = action.payload; 14 | }, 15 | }, 16 | }); 17 | 18 | export const { setTopCars } = homePageSlice.actions; 19 | export default homePageSlice.reducer; 20 | -------------------------------------------------------------------------------- /nginx/nginx.conf: -------------------------------------------------------------------------------- 1 | events {} 2 | http { 3 | server { 4 | listen 80; 5 | 6 | location / { 7 | proxy_http_version 1.1; 8 | proxy_cache_bypass $http_upgrade; 9 | 10 | proxy_set_header Upgrade $http_upgrade; 11 | proxy_set_header Connection 'upgrade'; 12 | proxy_set_header Host $host; 13 | proxy_set_header X-Real-IP $remote_addr; 14 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 15 | proxy_set_header X-Forwarded-Proto $scheme; 16 | 17 | proxy_pass http://app-prod:3000; 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /react-cars-app/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /react-cars-app/src/app/services/carService/index.ts: -------------------------------------------------------------------------------- 1 | import { apolloClient } from "../../graphql"; 2 | import { GET_ALL_CARS } from "./queries"; 3 | import { GetCars_cars } from "./__generated__/GetCars"; 4 | 5 | class CarService { 6 | public async getCars(): Promise { 7 | const response = await apolloClient 8 | .query({ query: GET_ALL_CARS }) 9 | .catch((err) => { 10 | throw err; 11 | }); 12 | 13 | if (response && response.data && response.data.cars) 14 | return response.data.cars as GetCars_cars[]; 15 | 16 | return []; 17 | } 18 | } 19 | 20 | export default new CarService(); 21 | -------------------------------------------------------------------------------- /nestjs-cars-app/src/components/cars/dto/new-car.input.ts: -------------------------------------------------------------------------------- 1 | import { Field, InputType, Int } from '@nestjs/graphql'; 2 | import { Max, Min } from 'class-validator'; 3 | 4 | @InputType() 5 | export class NewCarInput { 6 | @Field() 7 | name: string; 8 | 9 | @Field((type) => Int) 10 | @Max(20000) 11 | @Min(1500) 12 | monthlyPrice: number; 13 | 14 | @Field((type) => Int) 15 | @Max(1000) 16 | @Min(10, { message: "Daily price can't be that low!" }) 17 | dailyPrice: number; 18 | 19 | @Field() 20 | mileage: string; 21 | 22 | @Field() 23 | gas: string; 24 | 25 | @Field() 26 | gearType: string; 27 | 28 | @Field() 29 | thumbnailUrl: string; 30 | } 31 | -------------------------------------------------------------------------------- /react-cars-app/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": [ 5 | "dom", 6 | "dom.iterable", 7 | "esnext" 8 | ], 9 | "allowJs": true, 10 | "skipLibCheck": true, 11 | "esModuleInterop": true, 12 | "allowSyntheticDefaultImports": true, 13 | "strict": true, 14 | "forceConsistentCasingInFileNames": true, 15 | "noFallthroughCasesInSwitch": true, 16 | "module": "esnext", 17 | "moduleResolution": "node", 18 | "resolveJsonModule": true, 19 | "isolatedModules": true, 20 | "noEmit": true, 21 | "jsx": "react-jsx" 22 | }, 23 | "include": [ 24 | "src" 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /react-cars-app/src/app/store.ts: -------------------------------------------------------------------------------- 1 | import { configureStore, ThunkAction, Action } from "@reduxjs/toolkit"; 2 | import homePageReducer from "./containers/HomePage/slice"; 3 | import reduxLogger from "redux-logger"; 4 | 5 | export const store = configureStore({ 6 | middleware: (getDefaultMiddleware) => 7 | getDefaultMiddleware().concat(reduxLogger), 8 | reducer: { 9 | homePage: homePageReducer, 10 | }, 11 | }); 12 | 13 | export type AppDispatch = typeof store.dispatch; 14 | export type RootState = ReturnType; 15 | export type AppThunk = ThunkAction< 16 | ReturnType, 17 | RootState, 18 | unknown, 19 | Action 20 | >; 21 | -------------------------------------------------------------------------------- /react-cars-app/src/app/services/carService/__generated__/GetCars.ts: -------------------------------------------------------------------------------- 1 | /* tslint:disable */ 2 | /* eslint-disable */ 3 | // @generated 4 | // This file was automatically generated and should not be edited. 5 | 6 | // ==================================================== 7 | // GraphQL query operation: GetCars 8 | // ==================================================== 9 | 10 | export interface GetCars_cars { 11 | __typename: "Car"; 12 | id: string; 13 | name: string; 14 | mileage: string; 15 | gearType: string; 16 | gas: string; 17 | thumbnailUrl: string; 18 | dailyPrice: number; 19 | monthlyPrice: number; 20 | } 21 | 22 | export interface GetCars { 23 | cars: GetCars_cars[]; 24 | } 25 | -------------------------------------------------------------------------------- /nestjs-cars-app/src/database/database.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { Connection, getConnectionOptions } from 'typeorm'; 3 | import { TypeOrmModule } from '@nestjs/typeorm'; 4 | 5 | @Module({ 6 | imports: [ 7 | TypeOrmModule.forRootAsync({ 8 | useFactory: async () => 9 | Object.assign( 10 | await getConnectionOptions( 11 | process.env.NODE_ENV === 'production' ? 'prod' : 'dev', 12 | ), 13 | ), 14 | }), 15 | ], 16 | exports: [TypeOrmModule], 17 | }) 18 | export class DatabaseModule { 19 | constructor(connection: Connection) { 20 | if (connection.isConnected) console.log('DB Connected Successfully!'); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /react-cars-app/tailwind.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | purge: ["./src/**/*.{js,jsx,ts,tsx}", "./public/index.html"], 3 | darkMode: false, // or 'media' or 'class' 4 | theme: { 5 | extend: {}, 6 | screens: { 7 | sm: "640px", 8 | // => @media (min-width: 640px) { ... } 9 | 10 | md: "768px", 11 | // => @media (min-width: 768px) { ... } 12 | 13 | lg: "1024px", 14 | // => @media (min-width: 1024px) { ... } 15 | 16 | xl: "1280px", 17 | // => @media (min-width: 1280px) { ... } 18 | 19 | "2xl": "1536px", 20 | // => @media (min-width: 1536px) { ... } 21 | }, 22 | }, 23 | variants: { 24 | extend: {}, 25 | }, 26 | plugins: [], 27 | }; 28 | -------------------------------------------------------------------------------- /react-cars-app/src/index.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | @import url("https://fonts.googleapis.com/css2?family=Poppins:wght@500;700;800;900&display=swap"); 6 | 7 | html, 8 | body, 9 | #root { 10 | width: 100%; 11 | height: 100%; 12 | } 13 | 14 | body { 15 | margin: 0; 16 | font-family: "Poppins", -apple-system, BlinkMacSystemFont, "Segoe UI", 17 | "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", 18 | "Helvetica Neue", sans-serif; 19 | -webkit-font-smoothing: antialiased; 20 | -moz-osx-font-smoothing: grayscale; 21 | } 22 | 23 | code { 24 | font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", 25 | monospace; 26 | } 27 | -------------------------------------------------------------------------------- /nestjs-cars-app/src/app.controller.spec.ts: -------------------------------------------------------------------------------- 1 | import { Test, TestingModule } from '@nestjs/testing'; 2 | import { AppController } from './app.controller'; 3 | import { AppService } from './app.service'; 4 | 5 | describe('AppController', () => { 6 | let appController: AppController; 7 | 8 | beforeEach(async () => { 9 | const app: TestingModule = await Test.createTestingModule({ 10 | controllers: [AppController], 11 | providers: [AppService], 12 | }).compile(); 13 | 14 | appController = app.get(AppController); 15 | }); 16 | 17 | describe('root', () => { 18 | it('should return "Hello World!"', () => { 19 | expect(appController.getHello()).toBe('Hello World!'); 20 | }); 21 | }); 22 | }); 23 | -------------------------------------------------------------------------------- /react-cars-app/src/app/components/navbar/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import styled from "styled-components"; 3 | import tw from "twin.macro"; 4 | import { Logo } from "../logo"; 5 | import { NavItems } from "./navItems"; 6 | 7 | const NavbarContainer = styled.div` 8 | min-height: 68px; 9 | ${tw` 10 | w-full 11 | max-w-screen-2xl 12 | flex 13 | flex-row 14 | items-center 15 | lg:pl-12 16 | lg:pr-12 17 | justify-between 18 | `}; 19 | `; 20 | 21 | const LogoContainer = styled.div``; 22 | 23 | export function Navbar() { 24 | return ( 25 | 26 | 27 | 28 | 29 | 30 | 31 | ); 32 | } 33 | -------------------------------------------------------------------------------- /nestjs-cars-app/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | parser: '@typescript-eslint/parser', 3 | parserOptions: { 4 | project: 'tsconfig.json', 5 | sourceType: 'module', 6 | }, 7 | plugins: ['@typescript-eslint/eslint-plugin'], 8 | extends: [ 9 | 'plugin:@typescript-eslint/recommended', 10 | 'plugin:prettier/recommended', 11 | ], 12 | root: true, 13 | env: { 14 | node: true, 15 | jest: true, 16 | }, 17 | ignorePatterns: ['.eslintrc.js'], 18 | rules: { 19 | '@typescript-eslint/interface-name-prefix': 'off', 20 | '@typescript-eslint/explicit-function-return-type': 'off', 21 | '@typescript-eslint/explicit-module-boundary-types': 'off', 22 | '@typescript-eslint/no-explicit-any': 'off', 23 | }, 24 | }; 25 | -------------------------------------------------------------------------------- /nestjs-cars-app/test/app.e2e-spec.ts: -------------------------------------------------------------------------------- 1 | import { Test, TestingModule } from '@nestjs/testing'; 2 | import { INestApplication } from '@nestjs/common'; 3 | import * as request from 'supertest'; 4 | import { AppModule } from './../src/app.module'; 5 | 6 | describe('AppController (e2e)', () => { 7 | let app: INestApplication; 8 | 9 | beforeEach(async () => { 10 | const moduleFixture: TestingModule = await Test.createTestingModule({ 11 | imports: [AppModule], 12 | }).compile(); 13 | 14 | app = moduleFixture.createNestApplication(); 15 | await app.init(); 16 | }); 17 | 18 | it('/ (GET)', () => { 19 | return request(app.getHttpServer()) 20 | .get('/') 21 | .expect(200) 22 | .expect('Hello World!'); 23 | }); 24 | }); 25 | -------------------------------------------------------------------------------- /nestjs-cars-app/src/components/cars/entities/car.ts: -------------------------------------------------------------------------------- 1 | import { Field, ObjectType } from '@nestjs/graphql'; 2 | import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm'; 3 | 4 | @Entity({ name: 'cars' }) 5 | @ObjectType() 6 | export class Car { 7 | @PrimaryGeneratedColumn('uuid') 8 | @Field() 9 | id: string; 10 | 11 | @Column() 12 | @Field() 13 | name: string; 14 | 15 | @Column() 16 | @Field() 17 | dailyPrice: number; 18 | 19 | @Column() 20 | @Field() 21 | monthlyPrice: number; 22 | 23 | @Column() 24 | @Field() 25 | mileage: string; 26 | 27 | @Column() 28 | @Field() 29 | gas: string; 30 | 31 | @Column() 32 | @Field() 33 | gearType: string; 34 | 35 | @Column() 36 | @Field() 37 | thumbnailUrl: string; 38 | } 39 | -------------------------------------------------------------------------------- /nestjs-cars-app/src/app.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { AppController } from './app.controller'; 3 | import { AppService } from './app.service'; 4 | import { ConfigModule } from '@nestjs/config'; 5 | import { DatabaseModule } from './database/database.module'; 6 | import { GraphQLModule } from '@nestjs/graphql'; 7 | import { ComponentsModule } from './components/components.module'; 8 | 9 | @Module({ 10 | imports: [ 11 | ConfigModule.forRoot(), 12 | DatabaseModule, 13 | GraphQLModule.forRoot({ 14 | playground: true, 15 | debug: true, 16 | autoSchemaFile: true, 17 | }), 18 | ComponentsModule, 19 | ], 20 | controllers: [AppController], 21 | providers: [AppService], 22 | }) 23 | export class AppModule {} 24 | -------------------------------------------------------------------------------- /react-cars-app/src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | text-align: center; 3 | } 4 | 5 | .App-logo { 6 | height: 40vmin; 7 | pointer-events: none; 8 | } 9 | 10 | @media (prefers-reduced-motion: no-preference) { 11 | .App-logo { 12 | animation: App-logo-float infinite 3s ease-in-out; 13 | } 14 | } 15 | 16 | .App-header { 17 | min-height: 100vh; 18 | display: flex; 19 | flex-direction: column; 20 | align-items: center; 21 | justify-content: center; 22 | font-size: calc(10px + 2vmin); 23 | } 24 | 25 | .App-link { 26 | color: rgb(112, 76, 182); 27 | } 28 | 29 | @keyframes App-logo-float { 30 | 0% { 31 | transform: translateY(0); 32 | } 33 | 50% { 34 | transform: translateY(10px); 35 | } 36 | 100% { 37 | transform: translateY(0px); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /nestjs-cars-app/src/components/cars/cars.resolver.ts: -------------------------------------------------------------------------------- 1 | import { Args, Mutation, Query, Resolver } from '@nestjs/graphql'; 2 | import { CarsService } from './cars.service'; 3 | import { NewCarInput } from './dto/new-car.input'; 4 | import { Car } from './entities/car'; 5 | 6 | @Resolver() 7 | export class CarsResolver { 8 | constructor(private carsService: CarsService) {} 9 | 10 | @Query((returns) => [Car]) 11 | public async cars(): Promise { 12 | return await this.carsService.getAllCars().catch((err) => { 13 | throw err; 14 | }); 15 | } 16 | 17 | @Mutation((returns) => Car) 18 | public async addNewCar( 19 | @Args('newCarData') newCarData: NewCarInput, 20 | ): Promise { 21 | return await this.carsService.addCar(newCarData).catch((err) => { 22 | throw err; 23 | }); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /nestjs-cars-app/ormconfig.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "dev", 4 | "type": "mysql", 5 | "host": "localhost", 6 | "port": 3306, 7 | "username": "root", 8 | "password": "", 9 | "database": "yourcar", 10 | "entities": ["dist/**/entities/*{.ts,.js}"], 11 | "synchronize": true, 12 | "migrations": ["dist/migrations/*{.ts,.js}"], 13 | "cli": { 14 | "migrationsDir": "src/migrations" 15 | } 16 | }, 17 | { 18 | "name": "prod", 19 | "type": "mysql", 20 | "host": "mysqldb", 21 | "port": 3306, 22 | "username": "root", 23 | "password": "pass123", 24 | "database": "yourcar", 25 | "entities": ["dist/**/entities/*{.ts,.js}"], 26 | "synchronize": true, 27 | "migrations": ["dist/migrations/*{.ts,.js}"], 28 | "cli": { 29 | "migrationsDir": "src/migrations" 30 | } 31 | } 32 | ] 33 | -------------------------------------------------------------------------------- /react-cars-app/src/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom"; 3 | import "./index.css"; 4 | import App from "./App"; 5 | import { store } from "./app/store"; 6 | import { Provider } from "react-redux"; 7 | import * as serviceWorker from "./serviceWorker"; 8 | import { ApolloProvider } from "@apollo/client"; 9 | import { apolloClient } from "./app/graphql"; 10 | 11 | ReactDOM.render( 12 | 13 | 14 | 15 | 16 | 17 | 18 | , 19 | document.getElementById("root") 20 | ); 21 | 22 | // If you want your app to work offline and load faster, you can change 23 | // unregister() to register() below. Note this comes with some pitfalls. 24 | // Learn more about service workers: https://bit.ly/CRA-PWA 25 | serviceWorker.unregister(); 26 | -------------------------------------------------------------------------------- /nestjs-cars-app/src/components/cars/cars.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable, InternalServerErrorException } from '@nestjs/common'; 2 | import { InjectRepository } from '@nestjs/typeorm'; 3 | import { Repository } from 'typeorm'; 4 | import { NewCarInput } from './dto/new-car.input'; 5 | import { Car } from './entities/car'; 6 | 7 | @Injectable() 8 | export class CarsService { 9 | constructor(@InjectRepository(Car) private carRepository: Repository) {} 10 | 11 | public async getAllCars(): Promise { 12 | return await this.carRepository.find({}).catch((err) => { 13 | throw new InternalServerErrorException(); 14 | }); 15 | } 16 | 17 | public async addCar(newCarData: NewCarInput): Promise { 18 | const newCar = this.carRepository.create(newCarData); 19 | await this.carRepository.save(newCar).catch((err) => { 20 | new InternalServerErrorException(); 21 | }); 22 | 23 | return newCar; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /react-cars-app/src/app/components/marginer/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import styled from "styled-components"; 3 | 4 | export interface IMarginerProps { 5 | margin: number | string; 6 | direction?: "horizontal" | "vertical"; 7 | } 8 | 9 | const HorizontalMargin = styled.span` 10 | display: flex; 11 | min-width: ${({ margin }) => 12 | typeof margin === "string" ? margin : `${margin}px`}; 13 | `; 14 | 15 | const VerticalMargin = styled.span` 16 | display: flex; 17 | min-height: ${({ margin }) => 18 | typeof margin === "string" ? margin : `${margin}px`}; 19 | `; 20 | 21 | function Marginer(props: IMarginerProps) { 22 | const { direction } = props; 23 | 24 | if (direction === "horizontal") return ; 25 | else { 26 | return ; 27 | } 28 | } 29 | 30 | Marginer.defaultProps = { 31 | direction: "horizontal", 32 | }; 33 | 34 | export { Marginer }; 35 | -------------------------------------------------------------------------------- /react-cars-app/src/app/components/navbar/menuStyles.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | bmBurgerButton: { 3 | position: "absolute", 4 | width: "20px", 5 | height: "20px", 6 | right: "20px", 7 | top: "20px", 8 | }, 9 | bmBurgerBars: { 10 | background: "#373a47", 11 | }, 12 | bmBurgerBarsHover: { 13 | background: "#a90000", 14 | }, 15 | bmCrossButton: { 16 | height: "24px", 17 | width: "24px", 18 | }, 19 | bmCross: { 20 | background: "#bdc3c7", 21 | }, 22 | bmMenuWrap: { 23 | position: "fixed", 24 | width: "60%", 25 | height: "100%", 26 | top: "0px", 27 | }, 28 | bmMenu: { 29 | background: "#373a47", 30 | padding: "2.5em 1.5em 0", 31 | fontSize: "1.15em", 32 | }, 33 | bmMorphShape: { 34 | fill: "#373a47", 35 | }, 36 | bmItemList: { 37 | color: "#b8b7ad", 38 | padding: "0.8em", 39 | }, 40 | bmItem: { 41 | display: "inline-block", 42 | }, 43 | bmOverlay: { 44 | background: "rgba(0, 0, 0, 0.3)", 45 | }, 46 | }; 47 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Full Web App React Nodejs w/ GraphQL Tailwind and Docker From Zero To Deployment | Master MERN STACK 2 | 3 | ## Full Video Course on CoderOne channel 4 | https://youtu.be/4ELH8CT4J0A 5 | 6 | ## About the Video and What you'll Learn 7 | This is a Full Video Course going from Zero to Hero on creating an amazingly looking Reactjs website with Tailwind CSS, styled-components, and Apollo GraphQL alongside its Node.js/Express.js Server Side app or putting together a full dedicated Car Models GraphQL API built on top of Nest.js Framework. The final steps are Dockerizing the whole Stack with MySQL Docker image and using the Nginx Rever proxy to serve the running Nodejs applications on the server. We will take the whole dockerized MERN stack application and Deploy it on a Dedicated VPS from Hostinger and this is all in one video for you to master Web Development with React.js, Apollo GraphQL, Typescript, Tailwind, Responsive Design, Node.js, Express.js, Nest.js, TypeORM, Docker, Docker Compose and VPS. 8 | 9 | 10 | ### Infrastructure model 11 | 12 | ![Insfrastructure model](.infragenie/infrastructure_model.png) -------------------------------------------------------------------------------- /react-cars-app/src/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /react-cars-app/src/app/containers/HomePage/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import styled from "styled-components"; 3 | import tw from "twin.macro"; 4 | import { BookCard } from "../../components/bookCard"; 5 | import { Footer } from "../../components/footer"; 6 | import { Marginer } from "../../components/marginer"; 7 | import { Navbar } from "../../components/navbar"; 8 | import { AboutUs } from "./aboutUs"; 9 | import { BookingSteps } from "./bookingSteps"; 10 | import { TopCars } from "./topCars"; 11 | import { TopSection } from "./topSection"; 12 | 13 | const PageContainer = styled.div` 14 | ${tw` 15 | flex 16 | flex-col 17 | w-full 18 | h-full 19 | items-center 20 | overflow-x-hidden 21 | `} 22 | `; 23 | 24 | export function HomePage() { 25 | return ( 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 |