├── examples ├── lwc │ ├── songConstant │ │ ├── songConstant.js │ │ └── songConstant.js-meta.xml │ ├── .eslintrc.json │ ├── todoApp │ │ ├── todoApp.css │ │ ├── todoApp.js-meta.xml │ │ ├── todoApp.html │ │ └── todoApp.js │ ├── songList │ │ ├── songList.css │ │ ├── songList.js-meta.xml │ │ ├── songList.js │ │ └── songList.html │ ├── todoAppReducer │ │ ├── todoAppReducer.js │ │ ├── todoAppReducer.js-meta.xml │ │ ├── filter.js │ │ └── todo.js │ ├── todoAppActions │ │ ├── todoAppActions.js │ │ ├── filter.js │ │ ├── todoAppActions.js-meta.xml │ │ └── todo.js │ ├── songContainer │ │ ├── songContainer.html │ │ ├── songContainer.js-meta.xml │ │ └── songContainer.js │ ├── counterConstant │ │ ├── counterConstant.js │ │ └── counterConstant.js-meta.xml │ ├── counterContainer │ │ ├── counterContainer.html │ │ ├── counterContainer.js-meta.xml │ │ └── counterContainer.js │ ├── todoAppContainer │ │ ├── todoAppContainer.html │ │ ├── todoAppContainer.js-meta.xml │ │ └── todoAppContainer.js │ ├── stopWatchContainer │ │ ├── stopWatchContainer.html │ │ ├── stopWatchContainer.js-meta.xml │ │ └── stopWatchContainer.js │ ├── counter │ │ ├── counter.css │ │ ├── counter.js-meta.xml │ │ ├── counter.js │ │ └── counter.html │ ├── todo │ │ ├── todo.css │ │ ├── todo.js-meta.xml │ │ ├── todo.js │ │ └── todo.html │ ├── stopWatch │ │ ├── stopWatch.css │ │ ├── stopWatch.js-meta.xml │ │ ├── stopWatch.js │ │ └── stopWatch.html │ ├── songActions │ │ ├── songActions.js │ │ └── songActions.js-meta.xml │ ├── lapCard │ │ ├── lapCard.html │ │ ├── lapCard.js-meta.xml │ │ └── lapCard.js │ ├── laps │ │ ├── laps.js-meta.xml │ │ ├── laps.js │ │ └── laps.html │ ├── stopWatchConstant │ │ ├── stopWatchConstant.js │ │ └── stopWatchConstant.js-meta.xml │ ├── addTodo │ │ ├── addTodo.js-meta.xml │ │ ├── addTodo.html │ │ └── addTodo.js │ ├── songCard │ │ ├── songCard.js-meta.xml │ │ ├── songCard.html │ │ ├── songCard.css │ │ └── songCard.js │ ├── todoList │ │ ├── todoList.js-meta.xml │ │ ├── todoList.html │ │ └── todoList.js │ ├── todoFilter │ │ ├── todoFilter.js-meta.xml │ │ ├── todoFilter.js │ │ └── todoFilter.html │ ├── counterActions │ │ ├── counterActions.js-meta.xml │ │ └── counterActions.js │ ├── songReducers │ │ ├── songReducers.js-meta.xml │ │ └── songReducers.js │ ├── counterReducers │ │ ├── counterReducers.js-meta.xml │ │ └── counterReducers.js │ ├── stopWatchAction │ │ ├── stopWatchAction.js-meta.xml │ │ └── stopWatchAction.js │ ├── todoAppConstant │ │ ├── todoAppConstant.js-meta.xml │ │ └── todoAppConstant.js │ └── stopWatchReducers │ │ ├── stopWatchReducers.js-meta.xml │ │ └── stopWatchReducers.js └── classes │ ├── TodoCC.cls-meta.xml │ ├── TodoWrapper.cls-meta.xml │ ├── TodoWrapper.cls │ └── TodoCC.cls ├── force-app └── main │ └── default │ ├── lwc │ ├── .eslintrc.json │ ├── provider │ │ ├── provider.html │ │ ├── provider.js-meta.xml │ │ └── provider.js │ └── lwcRedux │ │ ├── lwcRedux.js-meta.xml │ │ ├── reduxHandler.js │ │ ├── lwcRedux.js │ │ └── reduxElement.js │ └── staticresources │ ├── redux.resource-meta.xml │ ├── reduxLogger.resource-meta.xml │ ├── reduxThunk.resource-meta.xml │ ├── reduxThunk.js │ ├── redux.js │ └── reduxLogger.js ├── config └── project-scratch-def.json ├── .prettierignore ├── scripts ├── soql │ └── account.soql └── apex │ └── hello.apex ├── .prettierrc ├── .forceignore ├── orgs ├── beta.json ├── release.json ├── dev.json └── feature.json ├── cumulusci.yml ├── .gitignore ├── sfdx-project.json ├── LICENSE └── README.md /examples/lwc/songConstant/songConstant.js: -------------------------------------------------------------------------------- 1 | export const SELECT_SONG_ACTION = 'SELECT_SONG'; 2 | -------------------------------------------------------------------------------- /examples/lwc/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@salesforce/eslint-config-lwc/recommended" 3 | } 4 | -------------------------------------------------------------------------------- /force-app/main/default/lwc/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["@salesforce/eslint-config-lwc/recommended"] 3 | } 4 | -------------------------------------------------------------------------------- /config/project-scratch-def.json: -------------------------------------------------------------------------------- 1 | { 2 | "orgName": "LWC-redux", 3 | "edition": "Developer", 4 | "features": [] 5 | } 6 | -------------------------------------------------------------------------------- /examples/lwc/todoApp/todoApp.css: -------------------------------------------------------------------------------- 1 | .container{ 2 | margin: 0 1rem; 3 | border-top: 1px solid #e8e5e5; 4 | padding: .5rem 0; 5 | } -------------------------------------------------------------------------------- /examples/lwc/songList/songList.css: -------------------------------------------------------------------------------- 1 | .list-container{ 2 | margin: 0 1rem; 3 | border-top: 1px solid #e8e5e5; 4 | padding: .5rem 0; 5 | } 6 | -------------------------------------------------------------------------------- /examples/lwc/todoAppReducer/todoAppReducer.js: -------------------------------------------------------------------------------- 1 | import todo from "./todo"; 2 | import filter from "./filter"; 3 | 4 | export default { 5 | todo, 6 | filter 7 | } -------------------------------------------------------------------------------- /force-app/main/default/lwc/provider/provider.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/lwc/todoAppActions/todoAppActions.js: -------------------------------------------------------------------------------- 1 | import * as todo from "./todo" 2 | import * as filter from "./filter" 3 | 4 | export default { 5 | todo, 6 | filter 7 | } -------------------------------------------------------------------------------- /examples/lwc/songContainer/songContainer.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | # List files or directories below to ignore them when running prettier 2 | # More information: https://prettier.io/docs/en/ignore.html 3 | # 4 | 5 | .sfdx 6 | .localdevserver -------------------------------------------------------------------------------- /examples/lwc/counterConstant/counterConstant.js: -------------------------------------------------------------------------------- 1 | export const INCREMENT_ACTION = 'INCREMENT'; 2 | export const DECREMENT_ACTION = 'DECREMENT'; 3 | export const RESET_ACTION = 'RESET'; 4 | 5 | -------------------------------------------------------------------------------- /examples/lwc/counterContainer/counterContainer.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/lwc/todoAppContainer/todoAppContainer.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/lwc/stopWatchContainer/stopWatchContainer.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/lwc/todoAppActions/filter.js: -------------------------------------------------------------------------------- 1 | import {SET_FILTER} from 'c/todoAppConstant'; 2 | 3 | export const setFilter = filter => ({ 4 | type: SET_FILTER, 5 | payload: { filter } 6 | }); 7 | -------------------------------------------------------------------------------- /examples/lwc/counter/counter.css: -------------------------------------------------------------------------------- 1 | .container{ 2 | margin: 0 1rem; 3 | border-top: 1px solid #e8e5e5; 4 | padding: .5rem 0; 5 | text-align: center; 6 | font-size: 4rem; 7 | font-weight: bold; 8 | } -------------------------------------------------------------------------------- /examples/lwc/todo/todo.css: -------------------------------------------------------------------------------- 1 | .inprogress{ 2 | border-left: .5rem solid #ffc800; 3 | } 4 | .incomplete{ 5 | border-left: .5rem solid #d0cfcd; 6 | } 7 | .completed{ 8 | border-left: .5rem solid #89e08c; 9 | } -------------------------------------------------------------------------------- /examples/lwc/stopWatch/stopWatch.css: -------------------------------------------------------------------------------- 1 | .container{ 2 | margin: 0 1rem; 3 | border-top: 1px solid #e8e5e5; 4 | padding: .5rem 0; 5 | text-align: center; 6 | font-size: 3rem; 7 | font-weight: bold; 8 | } -------------------------------------------------------------------------------- /examples/lwc/songActions/songActions.js: -------------------------------------------------------------------------------- 1 | import {SELECT_SONG_ACTION} from 'c/songConstant'; 2 | export const selectSong = (song) =>{ 3 | return { 4 | type: SELECT_SONG_ACTION, 5 | payload: song 6 | } 7 | } -------------------------------------------------------------------------------- /examples/classes/TodoCC.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 50.0 4 | Active 5 | 6 | -------------------------------------------------------------------------------- /examples/classes/TodoWrapper.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 50.0 4 | Active 5 | 6 | -------------------------------------------------------------------------------- /examples/lwc/lapCard/lapCard.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/lwc/laps/laps.js-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 47.0 4 | false 5 | -------------------------------------------------------------------------------- /examples/lwc/stopWatchConstant/stopWatchConstant.js: -------------------------------------------------------------------------------- 1 | export const START_ACTION = 'START'; 2 | export const STOP_ACTION = 'STOP'; 3 | export const RESET_ACTION = 'RESET'; 4 | export const TICK_ACTION = 'TICK'; 5 | export const CREATE_LAP_ACTION = 'CREATE_LEP'; -------------------------------------------------------------------------------- /examples/lwc/todo/todo.js-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 47.0 4 | false 5 | -------------------------------------------------------------------------------- /examples/lwc/laps/laps.js: -------------------------------------------------------------------------------- 1 | import { LightningElement} from 'lwc'; 2 | import { Redux } from 'c/lwcRedux'; 3 | 4 | export default class Laps extends Redux(LightningElement) { 5 | mapStateToProps(state){ 6 | return {laps : state.laps}; 7 | } 8 | } -------------------------------------------------------------------------------- /examples/lwc/addTodo/addTodo.js-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 47.0 4 | false 5 | -------------------------------------------------------------------------------- /examples/lwc/counter/counter.js-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 47.0 4 | false 5 | -------------------------------------------------------------------------------- /examples/lwc/lapCard/lapCard.js-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 47.0 4 | false 5 | -------------------------------------------------------------------------------- /examples/lwc/songCard/songCard.js-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 47.0 4 | false 5 | -------------------------------------------------------------------------------- /examples/lwc/songList/songList.js-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 47.0 4 | false 5 | -------------------------------------------------------------------------------- /examples/lwc/stopWatch/stopWatch.js-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 47.0 4 | false 5 | -------------------------------------------------------------------------------- /examples/lwc/todoApp/todoApp.js-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 47.0 4 | false 5 | -------------------------------------------------------------------------------- /examples/lwc/todoList/todoList.js-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 47.0 4 | false 5 | -------------------------------------------------------------------------------- /examples/lwc/songActions/songActions.js-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 47.0 4 | false 5 | -------------------------------------------------------------------------------- /examples/lwc/songList/songList.js: -------------------------------------------------------------------------------- 1 | import { LightningElement} from 'lwc'; 2 | import { Redux } from 'c/lwcRedux'; 3 | 4 | export default class SongList extends Redux(LightningElement) { 5 | mapStateToProps(state){ 6 | return {songs: state.songs}; 7 | } 8 | } -------------------------------------------------------------------------------- /examples/lwc/todoFilter/todoFilter.js-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 47.0 4 | false 5 | -------------------------------------------------------------------------------- /examples/lwc/counterActions/counterActions.js-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 47.0 4 | false 5 | -------------------------------------------------------------------------------- /examples/lwc/songConstant/songConstant.js-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 47.0 4 | false 5 | -------------------------------------------------------------------------------- /examples/lwc/songReducers/songReducers.js-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 47.0 4 | false 5 | -------------------------------------------------------------------------------- /examples/lwc/todoAppActions/todoAppActions.js-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 47.0 4 | false 5 | -------------------------------------------------------------------------------- /examples/lwc/todoAppReducer/todoAppReducer.js-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 47.0 4 | false 5 | -------------------------------------------------------------------------------- /scripts/soql/account.soql: -------------------------------------------------------------------------------- 1 | // Use .soql files to store SOQL queries. 2 | // You can execute queries in VS Code by selecting the 3 | // query text and running the command: 4 | // SFDX: Execute SOQL Query with Currently Selected Text 5 | 6 | SELECT Id, Name FROM Account; -------------------------------------------------------------------------------- /examples/lwc/counterConstant/counterConstant.js-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 47.0 4 | false 5 | -------------------------------------------------------------------------------- /examples/lwc/counterReducers/counterReducers.js-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 47.0 4 | false 5 | -------------------------------------------------------------------------------- /examples/lwc/stopWatchAction/stopWatchAction.js-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 47.0 4 | false 5 | -------------------------------------------------------------------------------- /examples/lwc/todoAppConstant/todoAppConstant.js-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 47.0 4 | false 5 | -------------------------------------------------------------------------------- /force-app/main/default/lwc/lwcRedux/lwcRedux.js-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 47.0 4 | false 5 | -------------------------------------------------------------------------------- /force-app/main/default/lwc/provider/provider.js-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 47.0 4 | false 5 | -------------------------------------------------------------------------------- /examples/lwc/stopWatchConstant/stopWatchConstant.js-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 47.0 4 | false 5 | -------------------------------------------------------------------------------- /examples/lwc/stopWatchReducers/stopWatchReducers.js-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 47.0 4 | false 5 | -------------------------------------------------------------------------------- /force-app/main/default/staticresources/redux.resource-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Private 4 | application/javascript 5 | 6 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "trailingComma": "none", 3 | "overrides": [ 4 | { 5 | "files": "**/lwc/**/*.html", 6 | "options": { "parser": "lwc" } 7 | }, 8 | { 9 | "files": "*.{cmp,page,component}", 10 | "options": { "parser": "html" } 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /force-app/main/default/staticresources/reduxLogger.resource-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Private 4 | application/javascript 5 | 6 | -------------------------------------------------------------------------------- /force-app/main/default/staticresources/reduxThunk.resource-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Private 4 | application/javascript 5 | 6 | -------------------------------------------------------------------------------- /examples/lwc/laps/laps.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/lwc/todoApp/todoApp.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/lwc/songCard/songCard.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/lwc/songList/songList.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/lwc/songCard/songCard.css: -------------------------------------------------------------------------------- 1 | .song-card{ 2 | padding: .8rem; 3 | border: 1px solid #e8e5e5; 4 | margin-bottom: .5rem; 5 | border-radius: .3rem; 6 | } 7 | lightning-button{ 8 | float: right; 9 | margin-top: -4px; 10 | } 11 | .song-name{ 12 | font-size: medium; 13 | display: inline-block; 14 | } 15 | .selected{ 16 | background: #7794fd; 17 | } -------------------------------------------------------------------------------- /examples/lwc/todoAppReducer/filter.js: -------------------------------------------------------------------------------- 1 | import {SET_FILTER, VISIBILITY_FILTER} from 'c/todoAppConstant'; 2 | 3 | const initialState = VISIBILITY_FILTER.ALL; 4 | 5 | const filter = (state = initialState, action) => { 6 | switch (action.type) { 7 | case SET_FILTER: return action.payload.filter; 8 | default: return state; 9 | } 10 | } 11 | 12 | export default filter; -------------------------------------------------------------------------------- /examples/lwc/todoList/todoList.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.forceignore: -------------------------------------------------------------------------------- 1 | # List files or directories below to ignore them when running force:source:push, force:source:pull, and force:source:status 2 | # More information: https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/sfdx_dev_exclude_source.htm 3 | # 4 | 5 | package.xml 6 | 7 | # LWC configuration files 8 | **/jsconfig.json 9 | **/.eslintrc.json 10 | 11 | # LWC Jest 12 | **/__tests__/** -------------------------------------------------------------------------------- /examples/lwc/counterActions/counterActions.js: -------------------------------------------------------------------------------- 1 | import {INCREMENT_ACTION, DECREMENT_ACTION, RESET_ACTION} from 'c/counterConstant'; 2 | export const increment = ()=> { 3 | return { 4 | type: INCREMENT_ACTION 5 | } 6 | } 7 | export const decrement = () => { 8 | return { 9 | type: DECREMENT_ACTION 10 | } 11 | } 12 | export const reset = () => { 13 | return { type: RESET_ACTION } 14 | } -------------------------------------------------------------------------------- /examples/lwc/counter/counter.js: -------------------------------------------------------------------------------- 1 | import { LightningElement } from 'lwc'; 2 | import { Redux } from 'c/lwcRedux'; 3 | import {increment, decrement, reset} from 'c/counterActions'; 4 | 5 | export default class Counter extends Redux(LightningElement) { 6 | 7 | mapStateToProps(state){ 8 | return {counter: state.counter}; 9 | } 10 | mapDispatchToProps(){ 11 | return {increment, decrement, reset}; 12 | } 13 | } -------------------------------------------------------------------------------- /examples/lwc/todoApp/todoApp.js: -------------------------------------------------------------------------------- 1 | import { LightningElement } from 'lwc'; 2 | import { Redux } from 'c/lwcRedux'; 3 | import {todo} from 'c/todoAppActions'; 4 | 5 | export default class TodoApp extends Redux(LightningElement) { 6 | connectedCallback(){ 7 | super.connectedCallback(); 8 | this.props.initialize(); 9 | } 10 | mapDispatchToProps(){ 11 | return {initialize : todo.initialize}; 12 | } 13 | } -------------------------------------------------------------------------------- /examples/lwc/songContainer/songContainer.js-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 47.0 4 | true 5 | 6 | lightning__RecordPage 7 | lightning__AppPage 8 | lightning__HomePage 9 | 10 | -------------------------------------------------------------------------------- /examples/lwc/counterContainer/counterContainer.js-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 47.0 4 | true 5 | 6 | lightning__RecordPage 7 | lightning__AppPage 8 | lightning__HomePage 9 | 10 | -------------------------------------------------------------------------------- /examples/lwc/counterReducers/counterReducers.js: -------------------------------------------------------------------------------- 1 | import {INCREMENT_ACTION, DECREMENT_ACTION, RESET_ACTION} from 'c/counterConstant'; 2 | const reducer = (counter = 0, action) => { 3 | switch (action.type) { 4 | case INCREMENT_ACTION: return counter + 1; 5 | case DECREMENT_ACTION: return counter - 1; 6 | case RESET_ACTION : return 0; 7 | default: return counter; 8 | } 9 | } 10 | export default { 11 | counter: reducer 12 | } -------------------------------------------------------------------------------- /examples/lwc/todoAppContainer/todoAppContainer.js-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 47.0 4 | true 5 | 6 | lightning__RecordPage 7 | lightning__AppPage 8 | lightning__HomePage 9 | 10 | -------------------------------------------------------------------------------- /examples/lwc/stopWatchContainer/stopWatchContainer.js-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 47.0 4 | true 5 | 6 | lightning__RecordPage 7 | lightning__AppPage 8 | lightning__HomePage 9 | 10 | -------------------------------------------------------------------------------- /scripts/apex/hello.apex: -------------------------------------------------------------------------------- 1 | // Use .apex files to store anonymous Apex. 2 | // You can execute anonymous Apex in VS Code by selecting the 3 | // apex text and running the command: 4 | // SFDX: Execute Anonymous Apex with Currently Selected Text 5 | // You can also execute the entire file by running the command: 6 | // SFDX: Execute Anonymous Apex with Editor Contents 7 | 8 | string tempvar = 'Enter_your_name_here'; 9 | System.debug('Hello World!'); 10 | System.debug('My name is ' + tempvar); -------------------------------------------------------------------------------- /examples/lwc/addTodo/addTodo.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /orgs/beta.json: -------------------------------------------------------------------------------- 1 | { 2 | "orgName": "lwc-redux - Beta Test Org", 3 | "edition": "Developer", 4 | "settings": { 5 | "lightningExperienceSettings": { 6 | "enableS1DesktopEnabled": true 7 | }, 8 | "chatterSettings": { 9 | "enableChatter": true 10 | }, 11 | "userManagementSettings": { 12 | "enableNewProfileUI": true 13 | }, 14 | "securitySettings": { 15 | "enableAdminLoginAsAnyUser": true, 16 | "sessionSettings": { 17 | "forceRelogin": false 18 | } 19 | } } 20 | } -------------------------------------------------------------------------------- /examples/lwc/todoFilter/todoFilter.js: -------------------------------------------------------------------------------- 1 | import { LightningElement} from 'lwc'; 2 | import { Redux } from 'c/lwcRedux'; 3 | import {VISIBILITY_FILTER} from 'c/todoAppConstant'; 4 | import {filter} from 'c/todoAppActions'; 5 | 6 | export default class TodoFilter extends Redux(LightningElement) { 7 | 8 | visibilityFilter = VISIBILITY_FILTER 9 | mapDispatchToProps(){ 10 | return {setFilter : filter.setFilter} 11 | } 12 | handleClick(event){ 13 | this.props.setFilter(event.target.value); 14 | } 15 | 16 | } -------------------------------------------------------------------------------- /orgs/release.json: -------------------------------------------------------------------------------- 1 | { 2 | "orgName": "lwc-redux - Release Test Org", 3 | "edition": "Enterprise", 4 | "settings": { 5 | "lightningExperienceSettings": { 6 | "enableS1DesktopEnabled": true 7 | }, 8 | "chatterSettings": { 9 | "enableChatter": true 10 | }, 11 | "userManagementSettings": { 12 | "enableNewProfileUI": true 13 | }, 14 | "securitySettings": { 15 | "enableAdminLoginAsAnyUser": true, 16 | "sessionSettings": { 17 | "forceRelogin": false 18 | } 19 | } } 20 | } -------------------------------------------------------------------------------- /examples/lwc/todoAppConstant/todoAppConstant.js: -------------------------------------------------------------------------------- 1 | export const ADD_TODO = "ADD_TODO"; 2 | export const CHANGE_TODO_STATUS = "CHANGE_TODO_STATUS"; 3 | export const SET_FILTER = "SET_FILTER"; 4 | export const ACTION_INITIALIZE_APP = "INITIALIZE_APP"; 5 | 6 | export const VISIBILITY_FILTER = { 7 | ALL: "All", 8 | COMPLETED: "Completed", 9 | INCOMPLETE: "Incomplete", 10 | INPROGRESS: "Inprogress" 11 | } 12 | export const STATUS = { 13 | COMPLETED: "Completed", 14 | INCOMPLETE: "Incomplete", 15 | INPROGRESS: "Inprogress" 16 | } -------------------------------------------------------------------------------- /examples/lwc/addTodo/addTodo.js: -------------------------------------------------------------------------------- 1 | import { LightningElement, track} from 'lwc'; 2 | import { Redux } from 'c/lwcRedux'; 3 | import {todo} from 'c/todoAppActions'; 4 | 5 | export default class AddTodo extends Redux(LightningElement) { 6 | @track todoInput = ''; 7 | mapDispatchToProps(){ 8 | return {addTodo : todo.addTodo}; 9 | } 10 | inputChange(event){ 11 | this.todoInput = event.target.value; 12 | } 13 | handleClick(event){ 14 | if(this.todoInput){ 15 | this.props.addTodo(this.todoInput); 16 | this.todoInput = ''; 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /examples/lwc/todoList/todoList.js: -------------------------------------------------------------------------------- 1 | import { LightningElement} from 'lwc'; 2 | import { Redux } from 'c/lwcRedux'; 3 | 4 | export default class TodoList extends Redux(LightningElement) { 5 | mapStateToProps(state){ 6 | const { filter, todo } = state; 7 | let allIds; 8 | if(filter != 'All'){ 9 | allIds = todo.allIds.filter(id => todo.byIds[id].status == filter) 10 | }else{ 11 | allIds = todo.allIds 12 | } 13 | return {allIds} 14 | } 15 | get hasRecord(){ 16 | return this.props.allIds && this.props.allIds.length > 0 17 | } 18 | } -------------------------------------------------------------------------------- /orgs/dev.json: -------------------------------------------------------------------------------- 1 | { 2 | "orgName": "lwc-redux - Dev Org", 3 | "edition": "Developer", 4 | "settings": { 5 | "lightningExperienceSettings": { 6 | "enableS1DesktopEnabled": true 7 | }, 8 | "chatterSettings": { 9 | "enableChatter": true 10 | }, 11 | "userManagementSettings": { 12 | "enableNewProfileUI": true 13 | }, 14 | "securitySettings": { 15 | "enableAdminLoginAsAnyUser": true, 16 | "sessionSettings": { 17 | "forceRelogin": false 18 | } 19 | }, 20 | "languageSettings": { 21 | "enableTranslationWorkbench": true 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /orgs/feature.json: -------------------------------------------------------------------------------- 1 | { 2 | "orgName": "lwc-redux - Feature Test Org", 3 | "edition": "Developer", 4 | "settings": { 5 | "lightningExperienceSettings": { 6 | "enableS1DesktopEnabled": true 7 | }, 8 | "chatterSettings": { 9 | "enableChatter": true 10 | }, 11 | "userManagementSettings": { 12 | "enableNewProfileUI": true 13 | }, 14 | "securitySettings": { 15 | "enableAdminLoginAsAnyUser": true, 16 | "sessionSettings": { 17 | "forceRelogin": false 18 | } 19 | }, 20 | "languageSettings": { 21 | "enableTranslationWorkbench": true 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /cumulusci.yml: -------------------------------------------------------------------------------- 1 | minimum_cumulusci_version: '3.21.1' 2 | project: 3 | name: lwc-redux 4 | package: 5 | name: lwc-redux 6 | api_version: '49.0' 7 | git: 8 | source_format: sfdx 9 | 10 | tasks: 11 | robot: 12 | options: 13 | suites: robot/lwc-redux/tests 14 | options: 15 | outputdir: robot/lwc-redux/results 16 | 17 | robot_testdoc: 18 | options: 19 | path: robot/lwc-redux/tests 20 | output: robot/lwc-redux/doc/lwc-redux_tests.html 21 | 22 | run_tests: 23 | options: 24 | required_org_code_coverage_percent: 75 25 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Salesforce / SFDX / CCI 2 | .cci 3 | .sfdx 4 | /src.orig 5 | /src 6 | .localdevserver 7 | .eslintcache 8 | 9 | # LWC VSCode autocomplete 10 | **/lwc/jsconfig.json 11 | 12 | # Logs 13 | logs 14 | *.log 15 | npm-debug.log* 16 | yarn-debug.log* 17 | yarn-error.log* 18 | 19 | # Dependency directories 20 | node_modules/ 21 | 22 | 23 | # Python 24 | *.pyc 25 | __pycache__ 26 | 27 | # Robot Framework results 28 | robot/lwc-redux/results/ 29 | 30 | # Editors 31 | *.sublime-project 32 | *.sublime-workspace 33 | .vscode 34 | .idea 35 | .project 36 | .settings 37 | 38 | # Misc 39 | .DS_Store 40 | 41 | # Windows system files 42 | Thumbs.db 43 | ehthumbs.db 44 | [Dd]esktop.ini 45 | $RECYCLE.BIN/ 46 | -------------------------------------------------------------------------------- /examples/lwc/counter/counter.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/lwc/songReducers/songReducers.js: -------------------------------------------------------------------------------- 1 | import {SELECT_SONG_ACTION} from 'c/songConstant'; 2 | const songReducer = (songs=null) => { 3 | if(songs == null){ 4 | songs = [ 5 | {title: 'Sorry, Blame it on Me ', duration: '4:30'}, 6 | {title: 'Lonely', duration: '5:10'}, 7 | {title: 'Smack That', duration: '1:45'} 8 | ] 9 | } 10 | return songs; 11 | } 12 | 13 | const selectedSongReducer = (selectedSong=null, action) => { 14 | if(action.type === SELECT_SONG_ACTION){ 15 | return action.payload; 16 | } 17 | return selectedSong; 18 | } 19 | 20 | export default { 21 | songs: songReducer, 22 | selectedSong: selectedSongReducer 23 | } -------------------------------------------------------------------------------- /examples/lwc/todoFilter/todoFilter.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/lwc/lapCard/lapCard.js: -------------------------------------------------------------------------------- 1 | import { LightningElement, api, track } from 'lwc'; 2 | 3 | export default class LapCard extends LightningElement { 4 | @api index; 5 | @api length 6 | @track lapToShow; 7 | _lap; 8 | @api 9 | get lap(){ 10 | return this._lap; 11 | } 12 | set lap(value){ 13 | this._lap = value; 14 | this.lapToShow = this.checkTime(value.hour) + ' : ' + this.checkTime(value.min) + ' : ' + this.checkTime(value.sec) + ' : ' + this.checkTime(value.milliSec); 15 | } 16 | checkTime(time) { 17 | if (time < 10) { 18 | time = "0" + time; 19 | } 20 | return time; 21 | } 22 | get getName(){ 23 | return ('Lap ' + (this.length-this.index)); 24 | } 25 | 26 | } -------------------------------------------------------------------------------- /examples/lwc/songCard/songCard.js: -------------------------------------------------------------------------------- 1 | import { LightningElement, api } from 'lwc'; 2 | import { Redux } from 'c/lwcRedux'; 3 | import { selectSong } from 'c/songActions'; 4 | export default class SongCard extends Redux(LightningElement) { 5 | @api song={} 6 | mapStateToProps(state){ 7 | return {selectedSong: state.selectedSong}; 8 | } 9 | mapDispatchToProps(){ 10 | return {selectSong}; 11 | } 12 | handleClick(){ 13 | this.props.selectSong(this.song); 14 | } 15 | get getCardClass(){ 16 | let strClass = 'song-card ' 17 | if(this.props.selectedSong && this.song && this.song.title === this.props.selectedSong.title){ 18 | strClass += 'selected '; 19 | } 20 | return strClass; 21 | } 22 | } -------------------------------------------------------------------------------- /examples/lwc/stopWatch/stopWatch.js: -------------------------------------------------------------------------------- 1 | import { LightningElement} from 'lwc'; 2 | import { Redux } from 'c/lwcRedux'; 3 | import {start, stop, reset, createLap} from 'c/stopWatchAction'; 4 | 5 | export default class StopWatch extends Redux(LightningElement) { 6 | mapStateToProps(state){ 7 | return { 8 | milliSec : this.checkTime(state.milliSec), 9 | sec : this.checkTime(state.sec), 10 | min: this.checkTime(state.min), 11 | hour: this.checkTime(state.hour), 12 | interval: state.interval 13 | } 14 | } 15 | mapDispatchToProps(){ 16 | return {start, stop, reset, createLap} 17 | } 18 | checkTime(time) { 19 | if (time < 10) { 20 | time = "0" + time; 21 | } 22 | return time; 23 | } 24 | } -------------------------------------------------------------------------------- /examples/classes/TodoWrapper.cls: -------------------------------------------------------------------------------- 1 | public with sharing class TodoWrapper { 2 | @AuraEnabled 3 | public String id {get;set;} 4 | 5 | @AuraEnabled 6 | public String content {get;set;} 7 | 8 | @AuraEnabled 9 | public String status {get;set;} 10 | 11 | public TodoWrapper(){} 12 | 13 | public TodoWrapper(Todo__c todo){ 14 | this.id = todo.Id; 15 | this.content = todo.Content__c; 16 | this.status = todo.Status__c; 17 | } 18 | 19 | public static Todo__c getSobject(TodoWrapper wrapper, Boolean isCreate){ 20 | Todo__c todo = new Todo__c(); 21 | todo.Content__c = wrapper.content; 22 | todo.Status__c = wrapper.status; 23 | if(!isCreate){ 24 | todo.Id = wrapper.id; 25 | } 26 | return todo; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /force-app/main/default/staticresources/reduxThunk.js: -------------------------------------------------------------------------------- 1 | !function (t, e) { "object" == typeof exports && "object" == typeof module ? module.exports = e() : "function" == typeof define && define.amd ? define([], e) : "object" == typeof exports ? exports.ReduxThunk = e() : t.ReduxThunk = e() }(this, function () { return function (t) { function e(o) { if (n[o]) return n[o].exports; var r = n[o] = { exports: {}, id: o, loaded: !1 }; return t[o].call(r.exports, r, r.exports, e), r.loaded = !0, r.exports } var n = {}; return e.m = t, e.c = n, e.p = "", e(0) }([function (t, e, n) { t.exports = n(1) }, function (t, e) { "use strict"; function n(t) { return function (e) { var n = e.dispatch, o = e.getState; return function (e) { return function (r) { return "function" == typeof r ? r(n, o, t) : e(r) } } } } e.__esModule = !0; var o = n(); o.withExtraArgument = n, e.default = o }]) }); -------------------------------------------------------------------------------- /examples/lwc/stopWatchAction/stopWatchAction.js: -------------------------------------------------------------------------------- 1 | import {START_ACTION,TICK_ACTION, STOP_ACTION, RESET_ACTION, CREATE_LAP_ACTION} from 'c/stopWatchConstant'; 2 | export const start = ()=> { 3 | 4 | return dispatch => { 5 | // eslint-disable-next-line @lwc/lwc/no-async-operation 6 | const interval = setInterval(() => { 7 | dispatch({ 8 | type:TICK_ACTION 9 | }) 10 | }, 10); 11 | dispatch({ 12 | type:START_ACTION, 13 | payload: {interval} 14 | }); 15 | 16 | } 17 | } 18 | export const stop = () => { 19 | return { 20 | type: STOP_ACTION 21 | } 22 | } 23 | export const reset = () => { 24 | return { 25 | type: RESET_ACTION 26 | } 27 | } 28 | export const createLap = () => { 29 | return { 30 | type: CREATE_LAP_ACTION 31 | } 32 | } -------------------------------------------------------------------------------- /examples/lwc/todoAppContainer/todoAppContainer.js: -------------------------------------------------------------------------------- 1 | import { LightningElement, api } from 'lwc'; 2 | import {createStore, combineReducers, createLogger} from 'c/lwcRedux'; 3 | import reducers from 'c/todoAppReducer'; 4 | 5 | // Set ENABLE_LOGGING true if you wanna use the logger. 6 | // We prefer to use the Custom label because we can directly access in the LWC components. 7 | const ENABLE_LOGGING = true; 8 | 9 | export default class TodoAppContainer extends LightningElement { 10 | @api store; 11 | initialize(){ 12 | let logger; 13 | 14 | if(ENABLE_LOGGING){ 15 | logger = createLogger({ 16 | duration: true, 17 | diff: true 18 | }); 19 | } 20 | const combineReducersInstance = combineReducers(reducers); 21 | this.store = createStore(combineReducersInstance, logger); 22 | } 23 | } -------------------------------------------------------------------------------- /examples/lwc/counterContainer/counterContainer.js: -------------------------------------------------------------------------------- 1 | import { LightningElement, api } from 'lwc'; 2 | import {createStore, combineReducers, createLogger} from 'c/lwcRedux'; 3 | import reducers from 'c/counterReducers'; 4 | 5 | // Set ENABLE_LOGGING true if you wanna use the logger. 6 | // We prefer to use the Custom label because we can directly access in the LWC components. 7 | const ENABLE_LOGGING = true; 8 | 9 | export default class CounterContainer extends LightningElement { 10 | @api store; 11 | initialize(){ 12 | let logger; 13 | 14 | // Check for the Logging 15 | if(ENABLE_LOGGING){ 16 | logger = createLogger({ 17 | duration: true, 18 | diff: true 19 | }); 20 | } 21 | 22 | const combineReducersInstance = combineReducers(reducers); 23 | this.store = createStore(combineReducersInstance, logger); 24 | } 25 | } -------------------------------------------------------------------------------- /sfdx-project.json: -------------------------------------------------------------------------------- 1 | { 2 | "packageDirectories": [ 3 | { 4 | "path": "force-app", 5 | "default": true, 6 | "package": "lwc-redux", 7 | "versionName": "Version 3.0", 8 | "versionNumber": "3.0.0.NEXT" 9 | }, 10 | { 11 | "path": "examples", 12 | "default": false, 13 | "package": "lwc-redux", 14 | "versionName": "Version 2.0", 15 | "versionNumber": "2.0.0.NEXT" 16 | } 17 | ], 18 | "namespace": "", 19 | "sfdcLoginUrl": "https://login.salesforce.com", 20 | "sourceApiVersion": "47.0", 21 | "packageAliases": { 22 | "lwc-redux": "0Ho2v000000bllSCAQ", 23 | "lwc-redux@1.0.0-1": "04t2v00000799S7AAI", 24 | "lwc-redux@2.0.0-1": "04t2v0000079AtMAAU", 25 | "lwc-redux@2.0.0-2": "04t2v0000079AtRAAU", 26 | "lwc-redux@2.0.0-4": "04t2v0000079B7xAAE", 27 | "lwc-redux@3.0.0-1": "04t2v000007GTFkAAO" 28 | } 29 | } -------------------------------------------------------------------------------- /examples/lwc/stopWatchContainer/stopWatchContainer.js: -------------------------------------------------------------------------------- 1 | import { LightningElement, api } from 'lwc'; 2 | import {createStore} from 'c/lwcRedux'; 3 | import reducers from 'c/stopWatchReducers'; 4 | 5 | export default class StopWatchContainer extends LightningElement { 6 | @api store; 7 | initialize(){ 8 | //const combineReducersInstance = combineReducers(reducers); 9 | this.store = createStore(reducers, this.logger); 10 | } 11 | logger({ getState }) { 12 | return next => action => { 13 | // eslint-disable-next-line no-console 14 | console.log('will dispatch', JSON.stringify(action)) 15 | // Call the next dispatch method in the middleware chain. 16 | const returnValue = next(action) 17 | // eslint-disable-next-line no-console 18 | console.log('state after dispatch', JSON.stringify(getState())); 19 | // This will likely be the action itself, unless 20 | // a middleware further in chain changed it. 21 | return returnValue 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /examples/lwc/songContainer/songContainer.js: -------------------------------------------------------------------------------- 1 | import { LightningElement, api} from 'lwc'; 2 | import {createStore} from 'c/lwcRedux'; 3 | import reducers from 'c/songReducers'; 4 | import {combineReducers} from 'c/lwcRedux'; 5 | 6 | export default class SongContainer extends LightningElement { 7 | @api store; 8 | initialize(){ 9 | const combineReducersInstance = combineReducers(reducers); 10 | this.store = createStore(combineReducersInstance, this.logger); 11 | } 12 | logger({ getState }) { 13 | return next => action => { 14 | // eslint-disable-next-line no-console 15 | console.log('will dispatch', JSON.stringify(action)) 16 | // Call the next dispatch method in the middleware chain. 17 | const returnValue = next(action) 18 | // eslint-disable-next-line no-console 19 | console.log('state after dispatch', JSON.stringify(getState())); 20 | // This will likely be the action itself, unless 21 | // a middleware further in chain changed it. 22 | return returnValue 23 | } 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 lwc-redux 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /examples/lwc/todo/todo.js: -------------------------------------------------------------------------------- 1 | import { LightningElement, api } from 'lwc'; 2 | import { Redux } from 'c/lwcRedux'; 3 | import {STATUS} from 'c/todoAppConstant'; 4 | import {todo} from 'c/todoAppActions'; 5 | 6 | export default class Todo extends Redux(LightningElement) { 7 | @api recordId; 8 | status = STATUS; 9 | mapStateToProps(state){ 10 | return {record : state.todo.byIds[this.recordId]} 11 | } 12 | mapDispatchToProps(){ 13 | return {changeTodoStatus : todo.changeTodoStatus}; 14 | } 15 | handleStatusChange(event){ 16 | this.props.changeTodoStatus(this.recordId, event.target.value); 17 | } 18 | 19 | get bodyClass(){ 20 | let strClass = 'slds-m-top_medium slds-box slds-box_xx-small '; 21 | if(this.props.record.status == STATUS.INCOMPLETE){ 22 | strClass += 'incomplete'; 23 | }else if(this.props.record.status == STATUS.INPROGRESS){ 24 | strClass += 'inprogress'; 25 | }else if(this.props.record.status == STATUS.COMPLETED){ 26 | strClass += 'completed'; 27 | } 28 | return strClass; 29 | } 30 | get isCompleted(){ 31 | return this.props.record.status == STATUS.COMPLETED 32 | } 33 | } -------------------------------------------------------------------------------- /examples/lwc/stopWatch/stopWatch.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/lwc/todoAppReducer/todo.js: -------------------------------------------------------------------------------- 1 | import {ACTION_INITIALIZE_APP, ADD_TODO, CHANGE_TODO_STATUS, STATUS} from 'c/todoAppConstant'; 2 | 3 | const initialState = { 4 | allIds: [], 5 | byIds: {} 6 | }; 7 | 8 | const todo = (state = initialState, action) => { 9 | switch (action.type) { 10 | case ACTION_INITIALIZE_APP: { 11 | const payload = action.payload; 12 | const allIds = Object.keys(payload) || []; 13 | return { 14 | ...state, 15 | allIds: [...allIds], 16 | byIds: {...payload} 17 | }; 18 | } 19 | case ADD_TODO: { 20 | const payload = action.payload; 21 | return { 22 | ...state, 23 | allIds: [...state.allIds, payload.id], 24 | byIds: { 25 | ...state.byIds, 26 | [payload.id]: {...payload} 27 | } 28 | }; 29 | } 30 | case CHANGE_TODO_STATUS: { 31 | const { id, status } = action.payload; 32 | return { 33 | ...state, 34 | byIds: { 35 | ...state.byIds, 36 | [id]: { 37 | ...state.byIds[id], 38 | status: status 39 | } 40 | } 41 | }; 42 | } 43 | 44 | default: return state; 45 | } 46 | } 47 | 48 | export default todo; -------------------------------------------------------------------------------- /examples/classes/TodoCC.cls: -------------------------------------------------------------------------------- 1 | public with sharing class TodoCC { 2 | 3 | @AuraEnabled 4 | public static Map initialLoad(){ 5 | Map mapOfTodoById = new Map(); 6 | try { 7 | List lstTodo = [Select Id, Content__c, Status__c from Todo__c]; 8 | if(lstTodo.size() > 0){ 9 | for(Todo__c todo : lstTodo){ 10 | mapOfTodoById.put(todo.Id, new TodoWrapper(todo)); 11 | } 12 | } 13 | return mapOfTodoById; 14 | } catch (Exception e) { 15 | return mapOfTodoById; 16 | } 17 | } 18 | 19 | @AuraEnabled 20 | public static TodoWrapper addNewTodo(String content){ 21 | try { 22 | TodoWrapper wrapper = new TodoWrapper(); 23 | wrapper.content = content; 24 | wrapper.status = 'Incomplete'; 25 | Todo__c todo = TodoWrapper.getSobject(wrapper, true); 26 | insert todo; 27 | 28 | wrapper.id = todo.Id; 29 | return wrapper; 30 | } catch (Exception e) { 31 | return null; 32 | } 33 | } 34 | 35 | @AuraEnabled 36 | public static TodoWrapper changeTodoStatus(String strTodo){ 37 | try { 38 | TodoWrapper wrapper = (TodoWrapper)JSON.deserialize(strTodo, TodoWrapper.class); 39 | Todo__c todo = TodoWrapper.getSobject(wrapper, false); 40 | update todo; 41 | return wrapper; 42 | } catch (Exception e) { 43 | return null; 44 | } 45 | } 46 | } -------------------------------------------------------------------------------- /examples/lwc/todoAppActions/todo.js: -------------------------------------------------------------------------------- 1 | import { 2 | ACTION_INITIALIZE_APP, 3 | ADD_TODO, 4 | CHANGE_TODO_STATUS, 5 | STATUS 6 | } from 'c/todoAppConstant'; 7 | import initialLoad from '@salesforce/apex/TodoCC.initialLoad'; 8 | import addNewTodo from '@salesforce/apex/TodoCC.addNewTodo'; 9 | import changeStatus from '@salesforce/apex/TodoCC.changeTodoStatus'; 10 | 11 | let nextTodoId = 0; 12 | 13 | export const initialize = () => { 14 | return dispatch => { 15 | initialLoad() 16 | .then(result => { 17 | dispatch({ 18 | type:ACTION_INITIALIZE_APP, 19 | payload: JSON.parse(JSON.stringify(result)) 20 | }); 21 | }) 22 | .catch(error => { 23 | console.error(error); 24 | }); 25 | } 26 | } 27 | 28 | export const addTodo = content => { 29 | return (dispatch, getState) => { 30 | addNewTodo({content: content}) 31 | .then(result => { 32 | dispatch({ 33 | type:ADD_TODO, 34 | payload: JSON.parse(JSON.stringify(result)) 35 | }); 36 | }) 37 | .catch(error => { 38 | console.error(error); 39 | }); 40 | } 41 | } 42 | export const changeTodoStatus = (id, status )=> { 43 | return (dispatch, getState) => { 44 | const todo = getState().todo.byIds[id]; 45 | todo.status = status; 46 | changeStatus({strTodo: JSON.stringify(todo)}) 47 | .then(result => { 48 | dispatch({ 49 | type: CHANGE_TODO_STATUS, 50 | payload: { id, status } 51 | }); 52 | }) 53 | .catch(error => { 54 | console.error(error); 55 | }); 56 | } 57 | } -------------------------------------------------------------------------------- /force-app/main/default/lwc/lwcRedux/reduxHandler.js: -------------------------------------------------------------------------------- 1 | /** 2 | * This file contains the all the helper method for the LWC-redux 3 | * 4 | * @author : https://github.com/chandrakiran-dev 5 | */ 6 | 7 | const reduxEvent = []; 8 | export const registerListener = (eventName, callback, thisArg) => { 9 | if (!reduxEvent[eventName]) { 10 | reduxEvent[eventName] = []; 11 | } 12 | const duplicate = reduxEvent[eventName].find(listener => { 13 | return listener.callback === callback && listener.thisArg === thisArg; 14 | }); 15 | if (!duplicate) { 16 | reduxEvent[eventName].push({ callback, thisArg}); 17 | } 18 | }; 19 | 20 | export const unregisterListener = (eventName, callback, thisArg) => { 21 | if (reduxEvent[eventName]) { 22 | reduxEvent[eventName] = reduxEvent[eventName].filter( 23 | listener => 24 | listener.callback !== callback || listener.thisArg !== thisArg 25 | ); 26 | } 27 | }; 28 | 29 | export const unregisterAllListeners = (thisArg) => { 30 | Object.keys(reduxEvent).forEach(eventName => { 31 | reduxEvent[eventName] = reduxEvent[eventName].filter( 32 | listener => listener.thisArg !== thisArg 33 | ); 34 | }); 35 | }; 36 | 37 | export const fireEvent = (storeName,eventName) => { 38 | if (reduxEvent[eventName]) { 39 | const listeners = reduxEvent[eventName]; 40 | let listenerToReturn; 41 | listeners.forEach(listener => { 42 | if (storeName === listener.thisArg.storeName){ 43 | listenerToReturn = listener; 44 | } 45 | 46 | }); 47 | return listenerToReturn; 48 | } 49 | return undefined; 50 | }; -------------------------------------------------------------------------------- /force-app/main/default/lwc/provider/provider.js: -------------------------------------------------------------------------------- 1 | /** 2 | * THis is provider component that's load the redux library. This will be tom most component for the lwc-redux application. 3 | * 4 | * @author : https://github.com/chandrakiran-dev 5 | */ 6 | 7 | import { LightningElement, api , track} from 'lwc'; 8 | import { loadScript } from 'lightning/platformResourceLoader'; 9 | import reduxURL from '@salesforce/resourceUrl/redux'; 10 | import reduxThunkURL from '@salesforce/resourceUrl/reduxThunk'; 11 | import reduxLoggerURL from '@salesforce/resourceUrl/reduxLogger'; 12 | 13 | export default class Provider extends LightningElement { 14 | @api _store; 15 | @track loadCompleted = false; 16 | @api 17 | get store(){ 18 | return this._store; 19 | } 20 | set store(value){ 21 | if(value){ 22 | this._store = value; 23 | } 24 | } 25 | async connectedCallback(){ 26 | try{ 27 | if(!window.Redux){ 28 | await Promise.all([ 29 | loadScript(this, reduxURL), 30 | loadScript(this, reduxThunkURL), 31 | loadScript(this, reduxLoggerURL) 32 | ]); 33 | } 34 | this.template.addEventListener('lwcredux__getstore', this.handleGetStore.bind(this)); 35 | this.dispatchEvent(new CustomEvent('init')); 36 | 37 | setTimeout(() =>{ 38 | this.loadCompleted = true; 39 | }) 40 | } 41 | catch(error){ 42 | console.error(error) 43 | } 44 | } 45 | handleGetStore(event){ 46 | try{ 47 | event.stopPropagation(); 48 | let callback = event.detail 49 | callback(this._store); 50 | } 51 | catch(error){ 52 | console.error(error) 53 | } 54 | } 55 | getStore(){ 56 | return this._store; 57 | } 58 | } -------------------------------------------------------------------------------- /examples/lwc/todo/todo.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Introducing Redux with Lightning web components(LWC) 2 | 3 | [LWC-redux](http://www.lwc-redux.com/) is a [LWC](https://developer.salesforce.com/blogs/2018/12/introducing-lightning-web-components.html) binding for [Redux](https://redux.js.org/introduction/getting-started#basic-example). It will allow your Lightning Web Components to read data from a Redux store, and dispatch actions to the store to update data. 4 | 5 | LWC-redux helps you to write application that behaves consistently and provide state management to the application. It's also separate the JS business and design layers. 6 | 7 | ## Installation 8 | 9 | To install the LWC-redux, we only need to click on the below button. It will redirect you to another page where you can select production/sandbox org and proceed with 'Login to Salesforce' button. 10 | [Click here to install](http://www.lwc-redux.com/quick-start#installation) 11 | 12 | There are two types of developer processes or models supported in Salesforce Extensions for VS Code and Salesforce CLI. These models are explained below. Each model offers pros and cons and is fully supported. 13 | 14 | ## Why Use LWC Redux? 15 | 16 | Redux itself is a standalone library that can be used with any UI layer or framework, including LWC, React, Angular, Vue, Ember, and vanilla JS. Although Redux and React are commonly used together, they are independent of each other. 17 | 18 | If you are using Redux with any kind of UI framework, you will normally use a "UI binding" library to tie Redux together with your UI framework, rather than directly interacting with the store from your UI code. 19 | 20 | LWC Redux is the Redux UI binding library for LWC. If you are using Redux and LWC together, you should also use LWC Redux to bind these two libraries. 21 | 22 | ##### It is the Redux UI Bindings for LWC. 23 | 24 | ##### It Encourages Good LWC Architecture. 25 | 26 | ##### It Implements Performance Optimizations For You 27 | 28 | [Click here for more information](http://www.lwc-redux.com/why-use-lwc-redux) 29 | 30 | ## Basic Tutorial 31 | 32 | To see how to use LWC Redux in practice, we’ll show a step-by-step example by creating a todo list app. 33 | 34 | [Click here for basic tutorial](http://www.lwc-redux.com/basic-tutorial) 35 | 36 | ## Examples 37 | 38 | Go to Examples folder in the repository or [refer examples page](http://www.lwc-redux.com/examples) 39 | 40 | ## CCI Integration 41 | 42 | Add to your cumulusci.yml: 43 | 44 | ``` 45 | sources: 46 | lwc-redux: 47 | github: https://github.com/chandrakiran-dev/lwc-redux 48 | ``` 49 | 50 | Add to your cci flow: 51 | 52 | ``` 53 | task: lwc-redux:deploy 54 | options: 55 | path: force-app/main/default 56 | ``` 57 | -------------------------------------------------------------------------------- /examples/lwc/stopWatchReducers/stopWatchReducers.js: -------------------------------------------------------------------------------- 1 | import {START_ACTION, STOP_ACTION, RESET_ACTION, TICK_ACTION, CREATE_LAP_ACTION} from 'c/stopWatchConstant'; 2 | 3 | let initialLapData = { 4 | milliSec : 0, 5 | sec : 0, 6 | min : 0, 7 | hour : 0 8 | } 9 | 10 | let initialState = { 11 | milliSec : 0, 12 | sec : 0, 13 | min : 0, 14 | hour : 0, 15 | interval : undefined, 16 | laps : [], 17 | lapData : initialLapData 18 | } 19 | 20 | 21 | 22 | const reducers = (state = initialState, action) => { 23 | switch (action.type) { 24 | case START_ACTION: 25 | return { 26 | ...state, 27 | interval : action.payload.interval 28 | } 29 | case TICK_ACTION:{ 30 | let tempState = {...state}; 31 | tempState.milliSec = ++tempState.milliSec; 32 | tempState.lapData.milliSec = ++tempState.lapData.milliSec 33 | if (tempState.milliSec === 100) { 34 | tempState.milliSec = 0; 35 | tempState.sec = ++tempState.sec; 36 | } 37 | if (tempState.lapData.milliSec === 100) { 38 | tempState.lapData.milliSec = 0; 39 | tempState.lapData.sec = ++tempState.lapData.sec; 40 | } 41 | 42 | if (tempState.sec === 60) { 43 | tempState.min = ++tempState.min; 44 | tempState.sec = 0; 45 | } 46 | if (tempState.lapData.sec === 60) { 47 | tempState.lapData.min = ++tempState.lapData.min; 48 | tempState.lapData.sec = 0; 49 | } 50 | 51 | if (tempState.min === 60) { 52 | tempState.min = 0; 53 | tempState.hour = ++tempState.hour; 54 | } 55 | if (tempState.lapData.min === 60) { 56 | tempState.lapData.min = 0; 57 | tempState.lapData.hour = ++tempState.lapData.hour; 58 | } 59 | return JSON.parse(JSON.stringify(tempState)); 60 | } 61 | case STOP_ACTION: { 62 | clearInterval(state.interval) 63 | return { 64 | ...state, 65 | interval: undefined 66 | } 67 | } 68 | case RESET_ACTION : { 69 | return initialState; 70 | } 71 | case CREATE_LAP_ACTION : { 72 | let tempLap = [...state.laps] 73 | tempLap.unshift({hour: state.lapData.hour, min: state.lapData.min, sec: state.lapData.sec, milliSec: state.lapData.milliSec}); 74 | return { 75 | ...state, 76 | laps: tempLap, 77 | lapData: initialLapData 78 | } 79 | } 80 | default: return state; 81 | } 82 | } 83 | export default reducers; -------------------------------------------------------------------------------- /force-app/main/default/lwc/lwcRedux/lwcRedux.js: -------------------------------------------------------------------------------- 1 | /** 2 | * This is lwc-redux component js file. This expose all the method that can be use in other components. 3 | * 4 | * @author : https://github.com/chandrakiran-dev 5 | */ 6 | 7 | import ReduxElement from './reduxElement'; 8 | import {registerListener, unregisterAllListeners} from './reduxHandler'; 9 | export const combineReducers = reducers => { 10 | try{ 11 | return window.Redux.combineReducers(reducers); 12 | } 13 | catch(error){ 14 | console.error(error) 15 | } 16 | } 17 | 18 | export const createStore = (reducers, logger) => { 19 | try{ 20 | let middleware; 21 | if(logger){ 22 | middleware = window.Redux.applyMiddleware(window.ReduxThunk.default, logger); 23 | }else{ 24 | middleware = window.Redux.applyMiddleware(window.ReduxThunk.default); 25 | } 26 | return window.Redux.createStore(reducers, middleware); 27 | } 28 | catch(error){ 29 | console.error(error) 30 | } 31 | } 32 | 33 | export const createLogger = (logger = initialLogger) => { 34 | try{ 35 | logger = {...initialLogger, ...logger}; 36 | return window.reduxLogger.createLogger(logger); 37 | } 38 | catch(error){ 39 | console.error(error) 40 | } 41 | } 42 | 43 | export const bindActionCreators = (actions, dispatch) => { 44 | try{ 45 | return window.Redux.bindActionCreators(actions, dispatch); 46 | } 47 | catch(error){ 48 | console.error(error) 49 | } 50 | } 51 | 52 | const getStore = (thisArg, callback) =>{ 53 | try{ 54 | const eventStore = new CustomEvent('lwcredux__getstore', { bubbles: true,composed: true, detail : (store)=>{ 55 | callback(store); 56 | }}) 57 | if(eventStore){ 58 | thisArg.dispatchEvent(eventStore); 59 | } 60 | } 61 | catch(error){ 62 | console.error(error) 63 | } 64 | } 65 | 66 | export const Redux = (Superclass = Object) => { 67 | return ReduxElement 68 | } 69 | 70 | const initialLogger = { 71 | level: 'log', 72 | logger: console, 73 | logErrors: true, 74 | collapsed: undefined, 75 | predicate: undefined, 76 | duration: false, // By default, duration is false 77 | timestamp: true, 78 | stateTransformer: state => JSON.parse(JSON.stringify(state)), 79 | actionTransformer: action => JSON.parse(JSON.stringify(action)), 80 | errorTransformer: error => JSON.parse(JSON.stringify(error)), 81 | colors: { 82 | title: () => 'inherit', 83 | prevState: () => '#9E9E9E', 84 | action: () => '#03A9F4', 85 | nextState: () => '#4CAF50', 86 | error: () => '#F20404', 87 | }, 88 | diff: false, // By default, diff is false 89 | diffPredicate: undefined, 90 | }; 91 | 92 | 93 | export {ReduxElement, registerListener, unregisterAllListeners}; 94 | 95 | -------------------------------------------------------------------------------- /force-app/main/default/lwc/lwcRedux/reduxElement.js: -------------------------------------------------------------------------------- 1 | /** 2 | * This file contains the ReduxElement that extends the LightningElement. This will be the parent component for all redux component 3 | * 4 | * @author : https://github.com/chandrakiran-dev 5 | */ 6 | 7 | import { LightningElement, track } from "lwc"; 8 | import { bindActionCreators } from "./lwcRedux"; 9 | const getStore = (thisArg, callback) => { 10 | try { 11 | const eventStore = new CustomEvent("lwcredux__getstore", { 12 | bubbles: true, 13 | composed: true, 14 | detail: store => { 15 | callback(store); 16 | } 17 | }); 18 | if (eventStore) { 19 | thisArg.dispatchEvent(eventStore); 20 | } 21 | } catch (error) { 22 | console.error(error); 23 | } 24 | }; 25 | 26 | const prepareProps = (thisArg, store) => { 27 | try { 28 | if (thisArg.mapStateToProps) { 29 | const state = thisArg.mapStateToProps(store.getState()); 30 | return Object.assign({}, thisArg.props, state); 31 | } 32 | } catch (error) { 33 | console.error(error); 34 | } 35 | return thisArg.props; 36 | }; 37 | 38 | export default class ReduxElement extends LightningElement { 39 | @track props = {}; 40 | oldState; 41 | _unsubscribe; 42 | connectedCallback() { 43 | getStore(this, store => { 44 | if (store) { 45 | try { 46 | let actions = {}; 47 | if (this.mapDispatchToProps) { 48 | actions = this.mapDispatchToProps(); 49 | } 50 | this.props = prepareProps(this, store); 51 | this.props = Object.assign({}, this.props, bindActionCreators(actions, store.dispatch)); 52 | this._unsubscribe = store.subscribe(this._handleStoreChange.bind(this)); 53 | } catch (error) { 54 | console.error(error); 55 | } 56 | } 57 | }); 58 | } 59 | 60 | disconnectedCallback() { 61 | if (this._unsubscribe) { 62 | this._unsubscribe(); 63 | } 64 | } 65 | 66 | _forceUpdate() { 67 | getStore(this, store => { 68 | try { 69 | if (store) { 70 | this.props = prepareProps(this, store); 71 | } 72 | } catch (error) { 73 | console.error(error); 74 | } 75 | }); 76 | this.props = Object.assign({}, this.props); 77 | } 78 | 79 | _handleStoreChange() { 80 | this._updateOnlyOnChange(); 81 | } 82 | 83 | _updateOnlyOnChange(){ 84 | getStore(this, store => { 85 | try { 86 | if (store) { 87 | if (this.mapStateToProps) { 88 | const state = this.mapStateToProps(store.getState()); 89 | let reload = false; 90 | for(const key of Object.keys(state)){ 91 | const value = state[key]; 92 | const oldValue = this.oldState ? this.oldState[key] : undefined; 93 | if(value !== oldValue){ 94 | reload = true; 95 | break; 96 | } 97 | } 98 | this.oldState = state 99 | if(reload){ 100 | this.props = Object.assign({}, this.props, state); 101 | } 102 | 103 | } 104 | } 105 | } catch (error) { 106 | console.error(error); 107 | } 108 | }); 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /force-app/main/default/staticresources/redux.js: -------------------------------------------------------------------------------- 1 | !function (e, t) { "object" == typeof exports && "undefined" != typeof module ? t(exports) : "function" == typeof define && define.amd ? define(["exports"], t) : t(e.Redux = {}) }(this, function (e) { "use strict"; var t = function (e) { var t, r = e.Symbol; return "function" == typeof r ? r.observable ? t = r.observable : (t = r("observable"), r.observable = t) : t = "@@observable", t }("undefined" != typeof self ? self : "undefined" != typeof window ? window : "undefined" != typeof global ? global : "undefined" != typeof module ? module : Function("return this")()), r = function () { return Math.random().toString(36).substring(7).split("").join(".") }, n = { INIT: "@@redux/INIT" + r(), REPLACE: "@@redux/REPLACE" + r(), PROBE_UNKNOWN_ACTION: function () { return "@@redux/PROBE_UNKNOWN_ACTION" + r() } }; function o(e, t) { var r = t && t.type; return "Given " + (r && 'action "' + r + '"' || "an action") + ', reducer "' + e + '" returned undefined. To ignore an action, you must explicitly return the previous state. If you want this reducer to hold no value, you can return null instead of undefined.' } function i(e, t) { return function () { return t(e.apply(this, arguments)) } } function u(e, t, r) { return t in e ? Object.defineProperty(e, t, { value: r, enumerable: !0, configurable: !0, writable: !0 }) : e[t] = r, e } function a() { for (var e = arguments.length, t = Array(e), r = 0; e > r; r++)t[r] = arguments[r]; return 0 === t.length ? function (e) { return e } : 1 === t.length ? t[0] : t.reduce(function (e, t) { return function () { return e(t.apply(void 0, arguments)) } }) } e.createStore = function e(r, o, i) { var u; if ("function" == typeof o && "function" == typeof i || "function" == typeof i && "function" == typeof arguments[3]) throw Error("It looks like you are passing several store enhancers to createStore(). This is not supported. Instead, compose them together to a single function"); if ("function" == typeof o && void 0 === i && (i = o, o = void 0), void 0 !== i) { if ("function" != typeof i) throw Error("Expected the enhancer to be a function."); return i(e)(r, o) } if ("function" != typeof r) throw Error("Expected the reducer to be a function."); var a = r, c = o, f = [], s = f, d = !1; function l() { s === f && (s = f.slice()) } function p() { if (d) throw Error("You may not call store.getState() while the reducer is executing. The reducer has already received the state as an argument. Pass it down from the top reducer instead of reading it from the store."); return c } function h(e) { if ("function" != typeof e) throw Error("Expected the listener to be a function."); if (d) throw Error("You may not call store.subscribe() while the reducer is executing. If you would like to be notified after the store has been updated, subscribe from a component and invoke store.getState() in the callback to access the latest state. See https://redux.js.org/api-reference/store#subscribe(listener) for more details."); var t = !0; return l(), s.push(e), function () { if (t) { if (d) throw Error("You may not unsubscribe from a store listener while the reducer is executing. See https://redux.js.org/api-reference/store#subscribe(listener) for more details."); t = !1, l(); var r = s.indexOf(e); s.splice(r, 1) } } } function y(e) { if (!function (e) { if ("object" != typeof e || null === e) return !1; for (var t = e; null !== Object.getPrototypeOf(t);)t = Object.getPrototypeOf(t); return Object.getPrototypeOf(e) === t }(e)) throw Error("Actions must be plain objects. Use custom middleware for async actions."); if (void 0 === e.type) throw Error('Actions may not have an undefined "type" property. Have you misspelled a constant?'); if (d) throw Error("Reducers may not dispatch actions."); try { d = !0, c = a(c, e) } finally { d = !1 } for (var t = f = s, r = 0; t.length > r; r++)(0, t[r])(); return e } return y({ type: n.INIT }), (u = { dispatch: y, subscribe: h, getState: p, replaceReducer: function (e) { if ("function" != typeof e) throw Error("Expected the nextReducer to be a function."); a = e, y({ type: n.REPLACE }) } })[t] = function () { var e, r = h; return (e = { subscribe: function (e) { if ("object" != typeof e || null === e) throw new TypeError("Expected the observer to be an object."); function t() { e.next && e.next(p()) } return t(), { unsubscribe: r(t) } } })[t] = function () { return this }, e }, u }, e.combineReducers = function (e) { for (var t = Object.keys(e), r = {}, i = 0; t.length > i; i++) { var u = t[i]; "function" == typeof e[u] && (r[u] = e[u]) } var a, c = Object.keys(r); try { !function (e) { Object.keys(e).forEach(function (t) { var r = e[t]; if (void 0 === r(void 0, { type: n.INIT })) throw Error('Reducer "' + t + "\" returned undefined during initialization. If the state passed to the reducer is undefined, you must explicitly return the initial state. The initial state may not be undefined. If you don't want to set a value for this reducer, you can use null instead of undefined."); if (void 0 === r(void 0, { type: n.PROBE_UNKNOWN_ACTION() })) throw Error('Reducer "' + t + "\" returned undefined when probed with a random type. Don't try to handle " + n.INIT + ' or other actions in "redux/*" namespace. They are considered private. Instead, you must return the current state for any unknown actions, unless it is undefined, in which case you must return the initial state, regardless of the action type. The initial state may not be undefined, but can be null.') }) }(r) } catch (e) { a = e } return function (e, t) { if (void 0 === e && (e = {}), a) throw a; for (var n = !1, i = {}, u = 0; c.length > u; u++) { var f = c[u], s = e[f], d = (0, r[f])(s, t); if (void 0 === d) { var l = o(f, t); throw Error(l) } i[f] = d, n = n || d !== s } return n ? i : e } }, e.bindActionCreators = function (e, t) { if ("function" == typeof e) return i(e, t); if ("object" != typeof e || null === e) throw Error("bindActionCreators expected an object or a function, instead received " + (null === e ? "null" : typeof e) + '. Did you write "import ActionCreators from" instead of "import * as ActionCreators from"?'); for (var r = Object.keys(e), n = {}, o = 0; r.length > o; o++) { var u = r[o], a = e[u]; "function" == typeof a && (n[u] = i(a, t)) } return n }, e.applyMiddleware = function () { for (var e = arguments.length, t = Array(e), r = 0; e > r; r++)t[r] = arguments[r]; return function (e) { return function () { var r = e.apply(void 0, arguments), n = function () { throw Error("Dispatching while constructing your middleware is not allowed. Other middleware would not be applied to this dispatch.") }, o = { getState: r.getState, dispatch: function () { return n.apply(void 0, arguments) } }, i = t.map(function (e) { return e(o) }); return function (e) { for (var t = 1; arguments.length > t; t++) { var r = null != arguments[t] ? arguments[t] : {}, n = Object.keys(r); "function" == typeof Object.getOwnPropertySymbols && (n = n.concat(Object.getOwnPropertySymbols(r).filter(function (e) { return Object.getOwnPropertyDescriptor(r, e).enumerable }))), n.forEach(function (t) { u(e, t, r[t]) }) } return e }({}, r, { dispatch: n = a.apply(void 0, i)(r.dispatch) }) } } }, e.compose = a, e.__DO_NOT_USE__ActionTypes = n, Object.defineProperty(e, "__esModule", { value: !0 }) }); -------------------------------------------------------------------------------- /force-app/main/default/staticresources/reduxLogger.js: -------------------------------------------------------------------------------- 1 | !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t(e.reduxLogger=e.reduxLogger||{})}(this,function(e){"use strict";function t(e,t){return r=t-e.toString().length,new Array(1+r).join("0")+e;var r}var r,n,L=function(e){return t(e.getHours(),2)+":"+t(e.getMinutes(),2)+":"+t(e.getSeconds(),2)+"."+t(e.getMilliseconds(),3)},p="undefined"!=typeof performance&&null!==performance&&"function"==typeof performance.now?performance:Date,v="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},M=function(e){if(Array.isArray(e)){for(var t=0,r=Array(e.length);t=o.length?i(new w(c,p,new m(void 0,n[p]))):j(n[p],o[p],i,a,c,p,l);for(;p