Skip to content

CodeLanka/e-Pola

Repository files navigation

GiveMe.lk (alias e-pola)

GiveMe.lk is a tool for connecting people with essential requirements during the social distancing peroid because the SARS-CoV-2 virus started to spread worldwide.

There are two main aspects of this tool

  • Let people in isolation request items they need
  • Let suppliers who are working to supply essentials see requirement quantity geographically

Build Status Code Coverage Code Climate ![License][license-image] Code Style

Table of Contents

  1. Requirements
  2. Getting Started
  3. Application Structure
  4. Development
    1. Routing
  5. Testing
  6. Configuration
  7. Production
  8. Deployment

Requirements

  • node ^10.15.0
  • npm ^6.0.0

Getting Started

  1. Install app and functions dependencies: yarn

  2. Create src/config.js file that looks like so if it does not already exist:

    const firebase = {
      // Config from Firebase console
      // go to console.firebase.google.com
      //  select your project
      //     go to settings > General
      //     under your apps, select the web app
      //     if there is no app, create one.
    };
    
    // Overrides for for react-redux-firebase/redux-firestore config
    export const reduxFirebase = {};
    
    export const segmentId = "<- Segment ID ->";
    
    export const publicVapidKey = "<- publicVapidKey from Firebase console ->";
    
    export const sentryDsn = "<- DSN From Sentry.io ->";
    
    export default {
      env,
      firebase,
      reduxFirebase,
      sentryDsn,
      publicVapidKey,
      segmentId,
    };
  3. Start Development server: yarn start

Config Files

There are multiple configuration files:

  • Firebase Project Configuration (including settings for how src/config.js is built on CI) - .firebaserc
  • Project Configuration used within source (can change based on environment variables on CI) - src/config.js
  • Cloud Functions Local Configuration - functions/.runtimeconfig.json

More details in the Application Structure Section

Application Structure

The application structure presented in this boilerplate is fractal, where functionality is grouped primarily by feature rather than file type. Please note, however, that this structure is only meant to serve as a guide, it is by no means prescriptive. That said, it aims to represent generally accepted guidelines and patterns for building scalable applications.

├── public                   # All build-related configuration
│   ├── index.html           # Main HTML page container for app
│   ├── scripts              # Scripts used within the building process
│   │  └── compile.js        # Custom Compiler that calls Webpack compiler
│   │  └── start.js          # Starts the custom compiler
├── src                      # Application source code
│   ├── config.js            # Environment specific config file with settings from Firebase (created by CI)
│   ├── components           # Global Reusable Presentational Components
│   ├── constants            # Project constants such as firebase paths and form names
│   │  ├── formNames.js      # Names of redux forms
│   │  └── paths.js          # Paths for application routes
│   ├── containers           # Global Reusable Container Components (connected to redux state)
│   ├── layouts              # Components that dictate major page structure
│   │   └── CoreLayout       # Global application layout in which to render routes
│   ├── routes               # Main route definitions and async split points
│   │   ├── index.js         # Bootstrap main application routes
│   │   └── Home             # Fractal route
│   │       ├── index.js     # Route definitions and async split points
│   │       ├── assets       # Assets required to render components
│   │       ├── components   # Presentational React Components (state connect and handler logic in enhancers)
│   │       ├── modules      # Collections of reducers/constants/actions
│   │       └── routes/**    # Fractal sub-routes (** optional)
│   ├── static               # Static assets
│   ├── store                # Redux-specific pieces
│   │   ├── createStore.js   # Create and instrument redux store
│   │   └── reducers.js      # Reducer registry and injection
│   ├── styles               # Application-wide styles (generally settings)
│   └── utils                # General Utilities (used throughout application)
│   │   ├── components.js    # Utilities for building/implementing react components (often used in enhancers)
│   │   ├── form.js          # For forms (often used in enhancers that use redux-form)
│   │   └── router.js        # Utilities for routing such as those that redirect back to home if not logged in
├── tests                    # Unit tests
├── .env.local               # Environment settings for when running locally
├── .eslintignore            # ESLint ignore file
├── .eslintrc.js             # ESLint configuration
├── .firebaserc              # Firebase Project configuration settings (including ci settings)
├── database.rules.json      # Rules for Firebase Real Time Database
├── firebase.json            # Firebase Service settings (Hosting, Functions, etc)
├── firestore.indexes.json   # Indexs for Cloud Firestore
├── firestore.rules          # Rules for Cloud Firestore
└── storage.rules            # Rules for Cloud Storage For Firebase

Routing

We use react-router-dom route matching (<route>/index.js) to define units of logic within our application. The application routes are defined within src/routes/index.js, which loads route settings which live in each route's index.js. The component with the suffix Page is the top level component of each route (i.e. HomePage is the top level component for Home route).

There are two types of routes definitions:

Sync Routes

The most simple way to define a route is a simple object with path and component:

src/routes/Home/index.js

import HomePage from "./components/HomePage";

// Sync route definition
export default {
  path: "/",
  component: HomePage,
};

Async Routes

Routes can also be seperated into their own bundles which are only loaded when visiting that route, which helps decrease the size of your main application bundle. Routes that are loaded asynchronously are defined using loadable function which uses React.lazy and React.Suspense:

src/routes/NotFound/index.js

import loadable from "utils/components";

// Async route definition
export default {
  component: loadable(() =>
    import(/* webpackChunkName: 'NotFound' */ "./components/NotFoundPage")
  ),
};

With this setting, the name of the file (called a "chunk") is defined as part of the code as well as a loading spinner showing while the bundle file is loading.

More about how routing works is available in the react-router-dom docs.

Testing

Component Tests

To add a unit test, create a .spec.js or .test.js file anywhere inside of src. Jest will automatically find these files and generate snapshots to the __snapshots folder.

UI Tests

Cypress is used to write and run UI tests which live in the cypress folder. The following npm scripts can be used to run tests:

  • Run using Cypress run: npm run test:ui
  • Open Test Runner UI (cypress open): npm run test:ui:open

To run tests against emulators:

  1. Start database emulators: npm run emulate
  2. Start React app pointed at emulators: npm run start:emulate
  3. Open Cypress test runner with test utils pointed at emulators: npm run test:ui:emulate

To Run tests in CI add the following environment variables within your CI provider:

  • SERVICE_ACCOUNT - Used to create custom auth tokens for test user login
  • FIREBASE_APP_NAME - name of Firebase app (used to load SDK config)
  • TEST_UID - UID of the user used for testing

Deployment

Build code before deployment by running npm run build. There are multiple options below for types of deployment, if you are unsure, checkout the Firebase section.

Before starting make sure to install Firebase Command Line Tool: npm i -g firebase-tools

CI Deploy (recommended)

Note: Config for this is located within firebase-ci has been added to simplify the CI deployment process. All that is required is providing authentication with Firebase:

  1. Login: firebase login:ci to generate an authentication token (will be used to give CI rights to deploy on your behalf)
  2. Set FIREBASE_TOKEN environment variable within CI environment
  3. Run a build on CI

If you would like to deploy to different Firebase instances for different branches (i.e. prod), change ci settings within .firebaserc.

For more options on CI settings checkout the firebase-ci docs

Manual deploy

  1. Run firebase:login
  2. Initialize project with firebase init then answer:
    • What file should be used for Database Rules? -> database.rules.json
    • What do you want to use as your public directory? -> build
    • Configure as a single-page app (rewrite all urls to /index.html)? -> Yes
    • What Firebase project do you want to associate as default? -> your Firebase project name
  3. Build Project: npm run build
  4. Confirm Firebase config by running locally: firebase serve
  5. Deploy to Firebase (everything including Hosting and Functions): firebase deploy

NOTE: You can use firebase serve to test how your application will work when deployed to Firebase, but make sure you run npm run build first.

FAQ

  1. Why node 10 instead of a newer version?

Cloud Functions runtime runs on 10, which is why that is what is used for the CI build version.

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages