Skip to content

Instantly share code, notes, and snippets.

View kasper573's full-sized avatar

Kasper kasper573

View GitHub Profile

State management

Use mobx in strict mode for state management and follow the flux architecture. This yields a unidirectional data flow:

state -> view -> action -> state

This creates a natural separation between view and state, which simplifies testing and makes the flow of code easier to follow.

Using state

Frontend guidelines

This document explains what practices to follow while working in the frontend codebase.

Coding

Keep it simple

Solve the problems at hand. Avoid premature optimization and architecture. Refactoring is and should be simple.

Use Typescript

/**
* Updates the RouteStore with static routes.
*/
export function setStaticRoutes ({state, apiClient}: AppContextProps) {
state.routes.setRoot(() => ({
// Require locale url prefix
path: `:locale<${localeRegexString}>`,
populate: () => state.i18n.availableLocales,
// Always render the Layout
import * as React from 'react';
const hoistNonReactStatic = require('hoist-non-react-statics');
/**
* Decorator to form a HOC that acts like a react context consumer.
* Useful when you want context to be made available in an entire component and not just in render.
*
* Example:
* type MyContextProps = {foo: string};
* const MyContext = createContext<MyContextProps>({foo: 'bar'});
import {I18nStore} from 'state/I18nStore';
import {SnackStore} from 'state/SnackStore';
import {CookieStore} from 'state/CookieStore';
import {cookieConsentBehavior} from './cookieConsentBehavior';
describe('cookieConsentBehavior', () => {
let cookieStore: CookieStore;
let snackStore: SnackStore;
let i18nStore: I18nStore;
type AProps = {foo: string, prop?: string};
type BProps = {bar: number};
class A extends React.Component<AProps> {}
class B extends React.Component<BProps> {}
class AB extends React.Component<AProps & BProps> {
render () {
const {aProps, bProps} = split(runtime AProps, runtime BProps, this.props);
return (
import {when} from 'mobx';
import {Resource} from './Resource';
describe('Resource', () => {
it('initial value is the default value when default getter is available', () => {
const defaultValue = 1;
const asyncValue = 2;
const r = new Resource('test', async () => asyncValue, () => defaultValue);
expect(r.value).toBe(defaultValue);
});
// Declare and name FormField instances containing the state of form fields.
const fields = {
name: new FormField(),
age: new FormField(),
description: new FormField()
};
// Render a Form component, which automates the presentation of these fields.
// Internally it analyzes the type of each field and chooses the proper control component to render per field.
import originalWithStyles, {
CSSProperties,
ClassNameMap,
StyleRules,
WithStylesOptions
} from '@material-ui/core/styles/withStyles'; // tslint:disable-line
import {IReactComponent} from 'mobx-react';
import {OcastTheme} from './OcastTheme';
export {CSSProperties};
function getInstances<T, C, B> (
target: T,
clazz: Class<C>,
transform: (instance: C) => B = noop
) {
const transformed: Record<keyof SubType<T, C>, B> = {} as any;
for (const key in target) {
const value = target[key];
if (value instanceof clazz) {
(transformed as any)[key] = transform(value);