diff --git a/docs/Redux/redux.md b/docs/Redux/redux.md index 979a612..3a95d21 100644 --- a/docs/Redux/redux.md +++ b/docs/Redux/redux.md @@ -82,3 +82,7 @@ How to name constants How to name action types How to name action creators + +## Forms + +[React & Redux #15. Authentication: Login Form](https://www.youtube.com/watch?v=tIajENrOJ0o) diff --git a/src/store/features/app-navigation/actions.ts b/src/store/features/app-navigation/actions.ts index ff11ea0..bdc39e6 100644 --- a/src/store/features/app-navigation/actions.ts +++ b/src/store/features/app-navigation/actions.ts @@ -61,8 +61,11 @@ export const fetchModuleFailure = (error: Error): AppNavigationActionTypes => ({ }, }) -const loaded = (): AppNavigationActionTypes => ({ +const loaded = (appid: string): AppNavigationActionTypes => ({ type: AppNavigationTypes.LOADED, + payload: { + appid, + }, }) const listModulesRequest = (id: string): AppNavigationActionTypes => ({ diff --git a/src/store/features/app-navigation/sagas.ts b/src/store/features/app-navigation/sagas.ts index ce0aac7..f7067b2 100644 --- a/src/store/features/app-navigation/sagas.ts +++ b/src/store/features/app-navigation/sagas.ts @@ -3,18 +3,13 @@ import { AppNavigationTypes } from './constants' import { ModxActions } from './actions' import { websocketSend } from '../websocket' -function* workerSaga() { - // console.log('Worker hit', action) +function* workerSaga(action) { + const { id } = action.payload.appid + console.log('Worker hit', action.payload.appid) // yield put({ ...action, type: `REMOTE_${action.type}` }) // TODO: No no! - yield delay(1000) - yield put( - websocketSend('APP_NAVIGATION__LIST_MODULES_REQUEST', { - payload: { - id: '54789c07-bb43-4db4-8b2d-1a8e1f8c67f1', - }, - }) - ) + // yield delay(1000) + yield put(websocketSend('APP_NAVIGATION__LIST_MODULES_REQUEST', { id: action.payload.appid })) } function* watcherSaga() { diff --git a/src/store/features/app-navigation/selectors.ts b/src/store/features/app-navigation/selectors.ts index 08cc110..77ede3d 100644 --- a/src/store/features/app-navigation/selectors.ts +++ b/src/store/features/app-navigation/selectors.ts @@ -3,6 +3,7 @@ import { RootState } from '../../reducer' // INPUT/BASE SELECTORS const getState = (state: RootState) => state.appModules +const getApplicationState = (state: RootState) => state.applications // MEMOIZED SELECTORS export const selectFetchState = createSelector([getState], state => state.fetching) @@ -23,7 +24,10 @@ export const selectModuleById = createSelector([selectAllModules, selectSelected export const selectModuleName = createSelector([selectModuleById], application => application.title) +const selectCurrentApplicationId = createSelector([getApplicationState], state => state.currentApplication) + export const AppNavigationSelectors = { selectFetchState, selectAllModulesArray, + selectCurrentApplicationId, } diff --git a/src/store/features/app-navigation/types.ts b/src/store/features/app-navigation/types.ts index 2bf606e..0c51018 100644 --- a/src/store/features/app-navigation/types.ts +++ b/src/store/features/app-navigation/types.ts @@ -68,6 +68,9 @@ interface FetchModuleFailure { interface Loaded { readonly type: AppNavigationTypes.LOADED + readonly payload: { + appid: string + } } interface ListModulesRequest { diff --git a/src/store/features/applications/actions.ts b/src/store/features/applications/actions.ts index ceaefc6..e332cc9 100644 --- a/src/store/features/applications/actions.ts +++ b/src/store/features/applications/actions.ts @@ -48,7 +48,9 @@ export const fetchApplicationFailure = (id: string, error: Error): ApplicationAc export const startApplication = (id: string): ApplicationActionTypes => ({ type: ApplicationTypes.START, - id, + payload: { + id, + }, }) export const getApplications = (): ApplicationActionTypes => ({ diff --git a/src/store/features/applications/reducer.ts b/src/store/features/applications/reducer.ts index ee9fb82..cd11b9a 100644 --- a/src/store/features/applications/reducer.ts +++ b/src/store/features/applications/reducer.ts @@ -7,15 +7,24 @@ const initialState: ApplicationsState = { entities: { 1: { id: '1', - title: 'Test', + title: 'Dispatch', component: 'my-component', permalink: '/dispatch', modules: [], defaultModule: '', lastModule: '', }, + 2: { + id: '2', + title: 'Sales', + component: 'my-component', + permalink: '/sales', + modules: [], + defaultModule: '', + lastModule: '', + }, }, - ids: ['1'], + ids: ['1', '2'], fetching: false, selected: { id: '', @@ -74,10 +83,7 @@ export default (state: ApplicationsState = initialState, action: ApplicationActi case ApplicationTypes.START: return { ...state, - selected: { - ...state.selected, - id: action.id, - }, + currentApplication: action.payload.id, } case ApplicationTypes.GET: diff --git a/src/store/features/applications/types.ts b/src/store/features/applications/types.ts index c7152fe..f83623d 100644 --- a/src/store/features/applications/types.ts +++ b/src/store/features/applications/types.ts @@ -63,7 +63,9 @@ interface FetchFailure { interface StartApplication { readonly type: ApplicationTypes.START - readonly id: string + readonly payload: { + id: string + } } interface StartingApplication { readonly type: ApplicationTypes.STARTING diff --git a/src/store/features/system/actions.ts b/src/store/features/system/actions.ts index 9b97ebe..2da513f 100644 --- a/src/store/features/system/actions.ts +++ b/src/store/features/system/actions.ts @@ -1,6 +1,6 @@ -import { createAction, ActionsUnion } from '../../actions' +// import { createAction, ActionsUnion } from '../../actions' import { SystemTypes, SystemActionTypes } from './types' -import { SystemState } from './models' +// import { SystemState } from './models' // ACTION CREATORS const select = (id: string): SystemActionTypes => ({ @@ -10,9 +10,11 @@ const select = (id: string): SystemActionTypes => ({ }, }) +const loaded = (): SystemActionTypes => ({ + type: SystemTypes.LOADED, +}) + export const SystemActions = { - select: (id: string) => createAction(SystemTypes.SELECT, { id }), - loaded: () => createAction(SystemTypes.LOADED, null), + select, + loaded, } - -export type SystemActions = ActionsUnion diff --git a/src/store/features/websocket/middleware.ts b/src/store/features/websocket/middleware.ts index 75bb1e3..de43190 100644 --- a/src/store/features/websocket/middleware.ts +++ b/src/store/features/websocket/middleware.ts @@ -21,8 +21,9 @@ const websocketMiddleware = ({ dispatch }) => next => { case WebsocketTypes.SEND: { const message = { type: action.payload.type, - payload: action.payload.payload ? action.payload.payload : undefined, + payload: action.payload.payload, } + console.log('WSS Message: ', message) websocket.send(JSON.stringify(message)) break } diff --git a/src/store/features/websocket/models.ts b/src/store/features/websocket/models.ts index cd2c316..d3750d7 100644 --- a/src/store/features/websocket/models.ts +++ b/src/store/features/websocket/models.ts @@ -2,4 +2,5 @@ import { WebsocketTypes } from './types' export interface WebsocketState { readonly state: WebsocketTypes + readonly connected: boolean } diff --git a/src/store/features/websocket/reducer.ts b/src/store/features/websocket/reducer.ts index 30f3f02..3e8b996 100644 --- a/src/store/features/websocket/reducer.ts +++ b/src/store/features/websocket/reducer.ts @@ -5,6 +5,7 @@ export { WebsocketState } export const websocketState: WebsocketState = { state: WebsocketTypes.DISCONNECTED, + connected: false, } export default (state: WebsocketState = websocketState, action: WebsocketActionTypes): WebsocketState => { @@ -14,13 +15,13 @@ export default (state: WebsocketState = websocketState, action: WebsocketActionT case WebsocketTypes.CONNECTING: return { ...state, state: action.type } case WebsocketTypes.CONNECTED: - return { ...state, state: action.type } + return { ...state, state: action.type, connected: true } case WebsocketTypes.SEND: return { ...state, state: action.type } case WebsocketTypes.DISCONNECT: return { ...state, state: action.type } case WebsocketTypes.DISCONNECTED: - return { ...state, state: action.type } + return { ...state, state: action.type, connected: false } default: return state diff --git a/src/store/features/websocket/selectors.ts b/src/store/features/websocket/selectors.ts index 4ad5634..df0c6d4 100644 --- a/src/store/features/websocket/selectors.ts +++ b/src/store/features/websocket/selectors.ts @@ -7,4 +7,5 @@ const getState = (state: RootState) => state.websocket //eslint-disable-next-line @typescript-eslint/no-namespace export namespace WebsocketSelectors { export const state = createSelector([getState], state => state.state) + export const selectConnectedState = createSelector([getState], state => state.connected) } diff --git a/src/ui/containers/app-navigation-connected/component.ts b/src/ui/containers/app-navigation-connected/component.ts index d84f60c..ba4980e 100644 --- a/src/ui/containers/app-navigation-connected/component.ts +++ b/src/ui/containers/app-navigation-connected/component.ts @@ -15,7 +15,8 @@ import { export class AppNavigationConnectedElement extends connect(store, AppNavigationElement) { connectedCallback() { super.connectedCallback() - store.dispatch(AppNavigationActions.loaded()) + console.log(this.appid) + store.dispatch(AppNavigationActions.loaded(this.appid)) } // Map state to props (Connect lib) @@ -24,6 +25,7 @@ export class AppNavigationConnectedElement extends connect(store, AppNavigationE pathname: RoutingSelectors.pathname(state), isApplicationsFetching: ApplicationSelectors.selectFetchState(state), isModulesFetching: ModuleSelectors.selectFetchState(state), + appid: AppNavigationSelectors.selectCurrentApplicationId(state), modules: AppNavigationSelectors.selectAllModulesArray(state), } } diff --git a/src/ui/containers/system-router/index.ts b/src/ui/containers/system-router/index.ts index 3f26923..65a4f11 100644 --- a/src/ui/containers/system-router/index.ts +++ b/src/ui/containers/system-router/index.ts @@ -6,8 +6,10 @@ import { connect } from '../../../utils/connect' import { store, RootState, RoutingSelectors } from '../../../store' // import '../app-shell' import '../../views/view-dispatch' +import '../../containers/view-dispatch-connected' import '../../views/view-dispatch-consignments' import '../../views/view-sales' +import '../../containers/view-sales-connected' import '../../views/view-signin' import '../../views/view-signup' import '../../views/view-error' diff --git a/src/ui/containers/system-shell/component.ts b/src/ui/containers/system-shell/component.ts index 7b10d58..7826ed0 100644 --- a/src/ui/containers/system-shell/component.ts +++ b/src/ui/containers/system-shell/component.ts @@ -17,13 +17,13 @@ import style from './style' @customElement('system-shell') export class SystemShellElement extends connect(store, LitElement) { - @property({ type: String }) websocketState: string = WebsocketSelectors.state.toString() + @property({ type: Boolean }) websocketState: boolean = false @property({ type: Boolean }) isLauncherVisible: boolean = false @property({ type: Object }) theme: object = {} mapState(state: RootState) { return { - websocketState: WebsocketSelectors.state(state), + websocketState: WebsocketSelectors.selectConnectedState(state), isLauncherVisible: UiSelectors.getLauncherVisibility(state), theme: ThemeSelectors.getTheme(state), } diff --git a/src/ui/containers/system-shell/template.ts b/src/ui/containers/system-shell/template.ts index 18d82d7..14959e3 100644 --- a/src/ui/containers/system-shell/template.ts +++ b/src/ui/containers/system-shell/template.ts @@ -5,11 +5,17 @@ import '../system-router' export default function template(this: SystemShellElement): TemplateResult { return html` - ${this.isLauncherVisible + ${this.websocketState ? html` - + ${this.isLauncherVisible + ? html` + + ` + : ``} + ` - : ``} - + : html` +

Connecting

+ `} ` } diff --git a/src/ui/containers/view-dispatch-connected/component.ts b/src/ui/containers/view-dispatch-connected/component.ts new file mode 100644 index 0000000..83ad0a6 --- /dev/null +++ b/src/ui/containers/view-dispatch-connected/component.ts @@ -0,0 +1,21 @@ +import { ViewDispatchElement } from '../../views/view-dispatch' +import { connect } from '../../../utils/connect' +import { store, RootState, startApplication } from '../../../store' + +export class ViewDispatchConnectedElement extends connect(store, ViewDispatchElement) { + connectedCallback() { + super.connectedCallback() + store.dispatch(startApplication(this.appid)) + // store.dispatch(getApplications()) + // store.dispatch(getModules()) + } + + // Map state to props (Connect lib) + // mapState(state: RootState) { + // return { + + // } + // } +} + +customElements.define(ViewDispatchElement.is, ViewDispatchConnectedElement) diff --git a/src/ui/containers/view-dispatch-connected/index.ts b/src/ui/containers/view-dispatch-connected/index.ts new file mode 100644 index 0000000..452e5c2 --- /dev/null +++ b/src/ui/containers/view-dispatch-connected/index.ts @@ -0,0 +1 @@ +export * from './component' diff --git a/src/ui/containers/view-sales-connected/component.ts b/src/ui/containers/view-sales-connected/component.ts new file mode 100644 index 0000000..6e0f10f --- /dev/null +++ b/src/ui/containers/view-sales-connected/component.ts @@ -0,0 +1,21 @@ +import { ViewSalesElement } from '../../views/view-sales' +import { connect } from '../../../utils/connect' +import { store, RootState, startApplication } from '../../../store' + +export class ViewSalesConnectedElement extends connect(store, ViewSalesElement) { + connectedCallback() { + super.connectedCallback() + store.dispatch(startApplication(this.appid)) + // store.dispatch(getApplications()) + // store.dispatch(getModules()) + } + + // Map state to props (Connect lib) + // mapState(state: RootState) { + // return { + + // } + // } +} + +customElements.define(ViewSalesElement.is, ViewSalesConnectedElement) diff --git a/src/ui/containers/view-sales-connected/index.ts b/src/ui/containers/view-sales-connected/index.ts new file mode 100644 index 0000000..452e5c2 --- /dev/null +++ b/src/ui/containers/view-sales-connected/index.ts @@ -0,0 +1 @@ +export * from './component' diff --git a/src/ui/views/view-dispatch/component.ts b/src/ui/views/view-dispatch/component.ts index 9053ed4..4d86c75 100644 --- a/src/ui/views/view-dispatch/component.ts +++ b/src/ui/views/view-dispatch/component.ts @@ -1,20 +1,12 @@ -import { customElement, TemplateResult, CSSResultArray, property } from 'lit-element' -import { ViewBaseElement } from '../view-base' -import { connect } from '../../../utils/connect' -import { store, RootState, ModuleSelectors, getApplications, getModules, startApplication } from '../../../store' +import { TemplateResult, CSSResultArray, property, LitElement } from 'lit-element' import template from './template' import style from './style' -@customElement('view-dispatch') -export class ViewDispatchElement extends connect(store, ViewBaseElement) { - @property({ type: String }) appid: string = '54789c07-bb43-4db4-8b2d-1a8e1f8c67f1' - - connectedCallback(): void { - super.connectedCallback() - // store.dispatch(startApplication(this.appid)) - // store.dispatch(getApplications()) - // store.dispatch(getModules()) +export class ViewDispatchElement extends LitElement { + static get is() { + return 'view-dispatch' } + @property({ type: String }) appid: string = '54789c07-bb43-4db4-8b2d-1a8e1f8c67f1' protected render(): TemplateResult { return template.call(this) @@ -23,6 +15,10 @@ export class ViewDispatchElement extends connect(store, ViewBaseElement) { public static get styles(): CSSResultArray { return [style] } + + protected createRenderRoot(): Element | ShadowRoot { + return this.hasAttribute('noshadow') ? this : super.createRenderRoot() + } } declare global { diff --git a/src/ui/views/view-sales/component.ts b/src/ui/views/view-sales/component.ts index b950c57..5f1a6e8 100644 --- a/src/ui/views/view-sales/component.ts +++ b/src/ui/views/view-sales/component.ts @@ -1,30 +1,22 @@ -import { LitElement, customElement, property, TemplateResult, CSSResultArray } from 'lit-element' -import { ViewBaseElement } from '../view-base' -import { connect } from '../../../utils/connect' -import { store, RootState, ModuleSelectors, getApplications, getModules, startApplication } from '../../../store' +import { LitElement, property, TemplateResult, CSSResultArray } from 'lit-element' import template from './template' import style from './style' -@customElement('view-sales') -export class ViewSalesElement extends connect(store, ViewBaseElement) { - @property({ type: String }) appid: string = '178025e-a209-4c50-8c34-36d35f36494c' - - connectedCallback(): void { - super.connectedCallback() - store.dispatch(startApplication(this.appid)) - store.dispatch(getApplications()) - store.dispatch(getModules()) +export class ViewSalesElement extends LitElement { + static get is() { + return 'view-sales' } + @property({ type: String }) appid: string = 'c178025e-a209-4c50-8c34-36d35f36494c' protected render(): TemplateResult { return template.call(this) } - static get styles(): CSSResultArray { + public static get styles(): CSSResultArray { return [style] } - createRenderRoot(): Element | ShadowRoot { + protected createRenderRoot(): Element | ShadowRoot { return this.hasAttribute('noshadow') ? this : super.createRenderRoot() } }