lumin-next

1.0.3-beta104 • Public • Published

Lumin Next

Luminskin.com prototype rewritten in NextJS

Getting started

Installing dependencies

yarn

Setting up local ENV variables

cp .env.local-sample .env.local

Running locally

yarn dev

Building for prod locally

yarn build
yarn start

Lumin Style Guide

Style Guide

TODO:

  • [ ] Automate deployment of storybook

Components to make

  • [ ] Link
  • [ ] Tag
  • [ ] Radio button
  • [ ] Toggle
  • [x] Select
  • [ ] Checkbox
  • [ ] Popovers

Frameworks Used

Directory Structure

Whenever a top level directory is added, please add an entry here denoting what should go in it.

src/design

Design system components go here, these components should be agnostic to this codebase and should able to be used as a "3rd party library". No files in here should import anything from src/

src/modules/<Module Name>/

This is where code domain specific code related to pangaea/lumin should go. It should be organized by domain (ex: checkout, cart, gifting).

  • <Module Name>/components This is where the react components specific to a module in the codebase go.

    • For generic components there should be a shared module.
    • If you are making components as a way to break up a larger page please put them in <Module Name>/components/<PAGE NAME>/*. Keep in mind that it's preferable to create re-usable components instead of components specific to a single page.
  • <Module Name>/actionTypes.ts This is where typescript types for redux actions (both the action and the action's type constant). This file should also export a variable <ModuleName>ActionTypes which is a union of all action types

export const CHECKOUT_LOAD_ORDER = 'CHECKOUT_LOAD_ORDER'

export interface CheckoutLoadOrderAction {
  type: typeof CHECKOUT_LOAD_ORDER
  data: Order
}

export type CheckoutActionTypes = CheckoutLoadOrderAction
  • <Module Name>/actions.ts This is where redux actions go as well as any function that does a fetch. Redux action types should be defined here as enum

  • <Module Name>/constants.ts Constants specific to this domain.

  • <Module Name>/functions.ts This is where pure functions go (no side-effects)

  • <Module Name>/reducer.ts If a module needs to declare a redux reducer, it goes here.

  • <Module Name>/routes.ts This file should export an object similar to the following.

  • <Module Name>/selectors.ts Selectors should be exported here as named constants, starting with select (ex: selectCurrentOrder

import buildRoutes, { routeFromUrl } from '../shared/buildRoutes'

// Example for the products module
// The first parameter is the base value and reflects the grouping of this
// module's pages. It will be prefixed to all routes.
const productRoutes = buildRoutes('products', {
  // Items represent a single page in the application.
  list: 'list', // Points to '/products/list'
  // If the value starts with a `/`, no prefix will take place.
  alternate: '/products2' // Points to /products2
  // For dynamic routes there's a helper function generator `routeFromUrl`.
  detail: routeFromUrl<{ slug: string }>('detail/[slug]') // Will generate:
  // detail() -> /products/detail/[slug]
  // detail({slug: 'recovery-oil'}) -> /products/detail/recovery-oil
})

export default productRoutes

src/redux

Defining redux store and root reducer should go here.

src/pages

This directory follows the NextJS routing structure.

src/utils

This is where basic helpers and utilities go, these should be generic and not overly specific to lumin (lodash or underscore like functions go in here).

Things that dont belong in src/utils/*.ts

  • Constants - put them in src/modules/<name>/constants.ts and group with their specific module
  • Ajax/fetch functions - put them in src/modules/<name>/actions.ts and group with their specific module

src/publicApi.js

This is where we expose values and functions to the window. No source code should ever import this file, it's purely for exposing to window.

File naming conventions

File names should be camelCase. If the file exports a React component or a class the filename should be TitleCase matching the name of the default export.

Code style conventions

We use prettier and eslint:recommended as a starting point. Everyone is free to make suggestions regarding which of the rules to change if they feel strongly about it but keep in mind that if the team as a whole cannot reach a decision, the existing rules will prevail.

The current configurations are:

Storybook

To view examples and documentation of our design system run yarn storybook.

Adding documentation

All new components in src/design/components/ should have a file ComponentName.stories.mdx created which will automatically add documentation for that component to storybook.

Recipes

Follow the following techniques and examples.

Making AJAX requests

Use fetch(), we use the isomorphic-unfetch package, which acts as a polyfill for both nodejs and incompatible browsers.

import fetch from 'isomorphic-unfetch'

const req = await fetch('https://doit.com')
const resp = await req.json()

Linking to other NextJS pages

For linking to other pages in the codebase, import the relevant module's routes and use that with NextJS' <Link /> component.

import Link from 'next/link'
import routes from '../routes'

const Component = () => (
  <p>
    {/* NextJS uses `href` to crawl at build time and `as` to route at runtime. */}
    Go to a product: <Link href={ routes.detail() } as="{ routes.detail('recovery-oil') }"><a>Recovery Oil</a></Link>
    Go to the list: <Link href="{ routes.list() }"><a>Recovery Oil</a></Link>
  </p>
)

Linking to non NextJS pages

TODO

Storing configuration values for different environments

TODO See the docs on env variables

Adding a configuration value locally

NextJS utilizes ENV variables. For frontend variables prefix them with NEXT_PUBLIC to be exposed to the FE bundle

All config values are centralized in ./src/core/config/config.ts, and new values should be added in here via ENV variables.

Accessing config values is through the config function

import config from '../../core/config'

const BASE_URL = config('API_BASEURL')

Adding a redux reducer / actions

Reducer's should be added to modules src/modules/<ModuleName>/reducer.ts. They should export a named reducer function <ModuleName>Reducer.ts

All reducers are combined to the root reducer in ./src/redux/rootReducer.js. Make sure to update the RootState type which is the composite of all the reducer's state types.

Actions should also be unioned on the type AppActionTypes in ./src/redux/rootReducer.js

Using Type Dispatch and Selectors

There are convenience hooks for using application typed selectors and dispatch

import { useTypedSelector, useTypedDispatch } from '../../redux/store'

// in your reac compoonent
const currentOrder = useTypedSelector(selectCheckoutCurrentOrder)
const dispatch = useTypedDispatch()

Typing Redux Actions

There are convenience types for creating actions and thunk actions inside the app.

import { ThunkAppActionCreator, AppActionCreator } from '../../redux/store'

export const loadOrder: AppActionCreator = (order: Order) => {
  return {
    type: CHECKOUT_LOAD_ORDER,
    payload: order,
  }
}

export const fetchOrder: ThunkAppActionCreator<Promise<Order>> = (
  orderId: string
) => async (dispatch) => {
  const order = await fetchOrder()
  dispatch({
    type: CHECKOUT_LOAD_ORDER,
    payload: order,
  })
}

Error Handler + Boundaries

Right now all of our custom defined error live in ./src/core/errors.ts. These error should remain generic and represent things that should break out of the User Experience (show an error page or boundry).

The our handling logic lives in ./src/pages/_ErrorBoundary.tsx this page handles forwarding error to our error reporting service and also displaying errors to the user.

Throwing errors in async functions

For our ErrorBoundary to properly catch an error it must be throw in the context of a React life cycle event.

Using const [, setError] = useState() is an easy way to ensure this.

const [, setError] = useState()
useEffect(() => {
  dispatch(fetchOrder(orderId)).catch(() =>
    setError(() => {
      throw new NotFoundError('Your order was not found')
    })
  )
}, [dispatch, orderId])

Readme

Keywords

none

Package Sidebar

Install

npm i lumin-next

Weekly Downloads

1

Version

1.0.3-beta104

License

MIT

Unpacked Size

40.4 MB

Total Files

786

Last publish

Collaborators

  • fernandomens