<repo_name>vollmerr/spo-react<file_sep>/src/webparts/demo/constants/status.ts
export enum STATUS {
  ERROR,
  READY,
  LOADING,
  SUBMITTING,
}
<file_sep>/src/webparts/demo/actions/listActions.ts
import { actionTypes, Action } from './actionTypes';
import { SPHttpClient, ISPHttpClientOptions, SPHttpClientResponse } from '@microsoft/sp-http';
import { IODataList } from '@microsoft/sp-odata-types';


const addListRequest = (): Action => ({
  type: actionTypes.ADD_LIST_REQUEST
});
const addListSuccess = (list: string): Action => ({
  type: actionTypes.ADD_LIST_SUCCESS,
  payload: list
});
const addListError = (error: Error): Action => ({
  type: actionTypes.ADD_LIST_FAILURE,
  payload: error.message
});


const getListsRequest = (): Action => ({
  type: actionTypes.GET_LISTS_REQUEST
});
const getListsSuccess = (title: string, lists: IListItems[]): Action => ({
  type: actionTypes.GET_LISTS_SUCCESS,
  payload: { title, lists }
});
const getListsError = (error: Error): Action => ({
  type: actionTypes.GET_LISTS_FAILURE,
  payload: error.message
});


export function addList(spHttpClient: SPHttpClient, currentWebUrl: string, title: string) {
  return async (dispatch: any) => {

    //Fire the 'request' action if you want to update the state to specify that an ajax request is being made.
    //This can be used to show a loading screen or a spinner.
    dispatch(addListRequest());

    const spOpts: ISPHttpClientOptions = {
      body: `{ Title: '${title}', BaseTemplate: 100 }`
    };

    try {
      const response: SPHttpClientResponse = await spHttpClient.post(`${currentWebUrl}/_api/web/lists`, SPHttpClient.configurations.v1, spOpts);
      const list: IODataList = await response.json();

      //Fire the 'success' action when you want to update the state based on a successfull request.
      dispatch(addListSuccess(list.Title));

    } catch (error) {
      //Fire the 'error' action when you want to update the state based on an error request.
      dispatch(addListError(error));
    }
  };

}


export function getLists(spHttpClient: SPHttpClient, currentWebUrl: string, listTitle: string, title: string) {
  return (dispatch) => {
    dispatch(getListsRequest());
    // return spHttpClient.get(`${currentWebUrl}/_api/web/lists/getbytitle(${listTitle})/items(1)`, SPHttpClient.configurations.v1)
    //   .then(response => response.json())
    //   .then(json => console.log("NUMERO UNO: ", json))
    // .then(
    //   () => {

     return spHttpClient.get(`${currentWebUrl}/_api/web/lists/getByTitle('${listTitle}')/items`, SPHttpClient.configurations.v1)
      .then(response => response.json())
      .then(json => json.value)
      .then(lists => dispatch(getListsSuccess(title, lists)))
      .catch(error => dispatch(getListsError(error)));
      // }
    //  );

  };
}
<file_sep>/src/webparts/demo/IDemoWebPartProps.ts
export interface IDemoWebPartProps {
  id: number;
}
<file_sep>/src/webparts/demo/reducers/loadingReducer.ts
import { Action } from '../actions/actionTypes';
import { Reducer } from 'redux';
import { LoadingState } from '../state/LoadingState';

export const actionTypeEndsInRequest = type => type.substring(type.length - 8) === '_REQUEST';
export const actionTypeEndsInSuccess = type => type.substring(type.length - 8) === '_SUCCESS';
export const actionTypeEndsInFailure = type => type.substring(type.length - 8) === '_FAILURE';

const initState = new LoadingState();

// Reducer determines how the state should change after every action.
const loadingReducer: Reducer<LoadingState> = (state: LoadingState = initState, action: Action): LoadingState => {
  if (actionTypeEndsInRequest(action.type)) {
    return state.increaseLoading();
  } else if (actionTypeEndsInSuccess(action.type)) {
    return state.decreaseLoading();
  } else if (actionTypeEndsInFailure(action.type)) {
    return state.decreaseLoading();
  }

  return state;
};

export default loadingReducer;
<file_sep>/src/webparts/demo/store/configureStore.ts
import { createStore, applyMiddleware, compose } from 'redux';
import thunkMiddleware from 'redux-thunk';
import { createLogger } from 'redux-logger';
import { RootState } from '../state';
import rootReducer from '../reducers';

const loggerMiddleware = createLogger();
const composeEnhancers = window['__REDUX_DEVTOOLS_EXTENSION_COMPOSE__'] || compose;

export default function configureStore(initialState?) {

  const middleWares = [
    thunkMiddleware,
    // loggerMiddleware,
  ];

  const enhancer = composeEnhancers(applyMiddleware(...middleWares));

  return createStore<RootState>(rootReducer, initialState, enhancer);
}
<file_sep>/src/webparts/demo/reducers/index.ts
import { Reducer, combineReducers } from 'redux';
import { reducer as form } from 'redux-form';
import lists from './listsReducer';
import loading from './loadingReducer';
import error from './errorReducer';

import { RootState } from '../state';

// ALL reducers must got through this reducer
const rootReducer = combineReducers<RootState>({
  form,
  lists,
  error,
  loading,
});

export default rootReducer;
<file_sep>/src/webparts/demo/state/index.ts
import { ListState } from './ListState';
import { LoadingState } from './LoadingState';
import { ErrorState } from './ErrorState';

export interface RootState {
  form: any;
  lists: ListState;
  error: ErrorState;
  loading: LoadingState;
}
<file_sep>/src/webparts/demo/state/ListState.ts
import * as Immutable from 'immutable';

export interface IListState {
  agencyCodes: any[];
  stage1: any[];
}

export const initialState: IListState = {
  agencyCodes: [],
  stage1: [],
};

// Immutable State.
export class ListState extends Immutable.Record(initialState) implements IListState {

  // Getters
  public readonly agencyCodes: IListItems[];
  public readonly stage1: IListItems[];

  // Setters
  public addList(payload): ListState {
    const { title, item } = payload;

    return this.update(title, (lists: any[]) => {
      return lists.concat(item);
    }) as ListState;
  }

  public setLists(payload): ListState {
    const { title, lists } = payload;
    return this.set(title, lists) as ListState;
  }
}
<file_sep>/src/webparts/demo/state/ErrorState.ts
import * as Immutable from 'immutable';

export interface IErrorState {
  error: string | null;
}

export const initialState: IErrorState = {
  error: null,
};

// Immutable State.
export class ErrorState extends Immutable.Record(initialState) implements IErrorState {

  // Getters
  public readonly error: string | null;

  public setError(error) {
    return this.set('error', error) as ErrorState;
  }

  public clearError() {
    return this.set('error', null) as ErrorState;
  }
}
<file_sep>/src/webparts/demo/loc/mystrings.d.ts
declare interface IDemoStrings {
  PropertyPaneDescription: string;
  BasicGroupName: string;
  DescriptionFieldLabel: string;
}

declare module 'demoStrings' {
  const strings: IDemoStrings;
  export = strings;
}

declare interface IListItems {
  Id?: number;
  Title?: string;
  firstName?: string;
  lastName?: string;
  phoneNumber?: string;
  testRequired?: string;
}
<file_sep>/src/webparts/demo/reducers/errorReducer.ts
import { Action } from '../actions/actionTypes';
import { Reducer } from 'redux';
import { ErrorState } from '../state/ErrorState';

export const actionTypeEndsInRequest = type => type.substring(type.length - 8) === '_REQUEST';
export const actionTypeEndsInSuccess = type => type.substring(type.length - 8) === '_SUCCESS';
export const actionTypeEndsInFailure = type => type.substring(type.length - 8) === '_FAILURE';

const initState = new ErrorState();

// Reducer determines how the state should change after every action.
const errorReducer: Reducer<ErrorState> = (state: ErrorState = initState, action: Action): ErrorState => {
  if (actionTypeEndsInRequest(action.type)) {
    return state.clearError();
  } else if (actionTypeEndsInFailure(action.type)) {
    return state.setError(action.payload);
  }

  return state;
};

export default errorReducer;
<file_sep>/src/webparts/demo/state/LoadingState.ts
import * as Immutable from 'immutable';

export interface ILoadingState {
  loading: number;
}

export const initialState: ILoadingState = {
  loading: 0,
};

// Immutable State.
export class LoadingState extends Immutable.Record(initialState) implements ILoadingState {

  // Getters
  public readonly loading: number;

  public increaseLoading() {
    return this.set('loading', this.loading + 1) as LoadingState;
  }

  public decreaseLoading() {
    return this.set('loading', this.loading - 1) as LoadingState;
  }
}
<file_sep>/src/webparts/demo/actions/actionTypes.ts
export const actionTypes = {
  ADD_LIST_REQUEST: 'ADD_LIST_REQUEST',
  ADD_LIST_SUCCESS: 'ADD_LIST_SUCCESS',
  ADD_LIST_FAILURE: 'ADD_LIST_FAILURE',
  GET_LISTS_REQUEST: 'GET_LISTS_REQUEST',
  GET_LISTS_SUCCESS: 'GET_LISTS_SUCCESS',
  GET_LISTS_FAILURE: 'GET_LISTS_FAILURE',
};

export type Action = { type: string, payload?: any };
