Skip to content

Commit

Permalink
Site Data Refactor to make similar to CustomerData and InventoryData (#…
Browse files Browse the repository at this point in the history
…83)

SiteData now uses entity adapters similar to customerData and inventoryData
  • Loading branch information
julianrkung authored Apr 10, 2021
1 parent fdc58c9 commit 17e87c1
Show file tree
Hide file tree
Showing 17 changed files with 155 additions and 114 deletions.
6 changes: 3 additions & 3 deletions src/lib/airtable/interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,9 @@ export interface SiteRecord {
name: string;
customerIds: string[];
financialSummaryIds: string[];
financialSummaries: FinancialSummaryRecord[];
tariffPlans: TariffPlanRecord[];
// These are extracted to other slices and deleted from SiteRecord
// These are extracted to other slices or entities and deleted from SiteRecord
financialSummaries?: FinancialSummaryRecord[];
tariffPlans?: TariffPlanRecord[];
inventoryIds?: string[];
products?: ProductRecord[];
inventory?: InventoryRecord[];
Expand Down
6 changes: 3 additions & 3 deletions src/lib/redux/customerData.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { CustomerRecord, MeterReadingRecord, PaymentRecord, SiteRecord } from '../airtable/interface';
import { addCustomer, setCurrentCustomerId, editCustomer, selectCustomerById, saveCustomerData, selectAllMeterReadingsArray, selectAllCustomersArray, selectAllPaymentsArray, selectAllCustomers } from './customerDataSlice';
import { isBeforeCurrentPeriod } from '../moment/momentUtils';
import { getCurrentSiteId } from './siteData';
import { selectCurrentSiteId } from './siteData';
import { RootState, store } from './store';
import { createSelector } from '@reduxjs/toolkit';

Expand All @@ -20,14 +20,14 @@ export const refreshCustomerData = (site: SiteRecord): void => {
};

export const addCustomerToRedux = (customer: CustomerRecord): void => {
const siteId = getCurrentSiteId();
const siteId = selectCurrentSiteId(store.getState());
store.dispatch(addCustomer({ siteId, customer }));
};

export const editCustomerInRedux = (customer: Partial<CustomerRecord>): void => {
const customerUpdates = {
...customer,
siteId: getCurrentSiteId()
siteId: selectCurrentSiteId(store.getState())
}
store.dispatch(editCustomer(customerUpdates));
};
Expand Down
10 changes: 5 additions & 5 deletions src/lib/redux/customerDataSlice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
/* eslint-disable no-param-reassign */
import { createEntityAdapter, createSlice, EntityState } from '@reduxjs/toolkit';
import { CustomerRecord, MeterReadingRecord, PaymentRecord, SiteId } from '../airtable/interface';
import { setCurrSite } from './siteDataSlice';
import { setCurrentSiteId } from './siteDataSlice';
import { RootState } from './store';
import moment from 'moment';

Expand All @@ -23,23 +23,23 @@ export const {
selectById: selectCustomerById,
selectIds: selectCustomerIds
} = customersAdapter.getSelectors(
(state: RootState) => state.customerData.sitesCustomers[state.siteData.currentSite.id].customers);
(state: RootState) => state.customerData.sitesCustomers[state.siteData.currentSiteId].customers);

export const {
selectEntities: selectAllPayments,
selectAll: selectAllPaymentsArray,
selectById: selectPaymentById,
selectIds: selectPaymentIds
} = paymentsAdapter.getSelectors(
(state: RootState) => state.customerData.sitesCustomers[state.siteData.currentSite.id].payments);
(state: RootState) => state.customerData.sitesCustomers[state.siteData.currentSiteId].payments);

export const {
selectEntities: selectAllMeterReadings,
selectAll: selectAllMeterReadingsArray,
selectById: selectMeterReadingById,
selectIds: selectMeterReadingIds
} = meterReadingsAdapter.getSelectors(
(state: RootState) => state.customerData.sitesCustomers[state.siteData.currentSite.id].meterReadings);
(state: RootState) => state.customerData.sitesCustomers[state.siteData.currentSiteId].meterReadings);

interface SiteCustomerData {
customers: EntityState<CustomerRecord>;
Expand Down Expand Up @@ -137,7 +137,7 @@ const customerDataSlice = createSlice({
extraReducers: {
// When current site is changed, current customer id needs to be reset
// because it's no longer valid in the new site context.
[setCurrSite.type]: (state, action) => {
[setCurrentSiteId.type]: (state, action) => {
state.currentCustomerId = initialState.currentCustomerId;
}
}
Expand Down
10 changes: 5 additions & 5 deletions src/lib/redux/inventoryData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import {
updateInventoryQuantity,
updatePurchaseRequest
} from './inventoryDataSlice';
import { getCurrentSiteId } from './siteData';
import { selectCurrentSiteId } from './siteData';
import { RootState, store } from './store';


Expand Down Expand Up @@ -82,23 +82,23 @@ export const addInventoryToRedux = (inventory: InventoryRecord): void => {
export const addPurchaseRequestToRedux = (purchaseRequest: PurchaseRequestRecord): void => {
const purchaseRequestData = {
...purchaseRequest,
siteId: getCurrentSiteId(),
siteId: selectCurrentSiteId(store.getState()),
};
store.dispatch(addPurchaseRequest(purchaseRequestData));
};

export const updatePurchaseRequestInRedux = (purchaseRequest: Partial<PurchaseRequestRecord>): void => {
const purchaseRequestUpdates = {
...purchaseRequest,
siteId: getCurrentSiteId(),
siteId: selectCurrentSiteId(store.getState()),
};
store.dispatch(updatePurchaseRequest(purchaseRequestUpdates));
};

export const addInventoryUpdateToRedux = (inventoryUpdate: InventoryUpdateRecord): void => {
const inventoryUpdateData = {
...inventoryUpdate,
siteId: getCurrentSiteId(),
siteId: selectCurrentSiteId(store.getState()),
};
store.dispatch(addInventoryUpdate(inventoryUpdateData));
};
Expand All @@ -107,7 +107,7 @@ export const updateInventoryQuantityInRedux = (inventoryId: string, newQuantity:
const updateData = {
inventoryId,
newQuantity,
siteId: getCurrentSiteId(),
siteId: selectCurrentSiteId(store.getState()),
};
store.dispatch(updateInventoryQuantity(updateData));
};
Expand Down
10 changes: 5 additions & 5 deletions src/lib/redux/inventoryDataSlice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import { createEntityAdapter, createSlice, EntityState } from '@reduxjs/toolkit';
import moment from 'moment';
import { InventoryRecord, InventoryUpdateRecord, ProductRecord, PurchaseRequestRecord } from '../airtable/interface';
import { setCurrSite } from './siteDataSlice';
import { setCurrentSiteId } from './siteDataSlice';
import { RootState } from './store';

const inventoryUpdatesAdapter = createEntityAdapter<InventoryUpdateRecord>({
Expand All @@ -24,7 +24,7 @@ export const {
selectById: selectInventoryUpdateById,
selectIds: selectInventoryUpdateIds,
} = inventoryUpdatesAdapter.getSelectors(
(state: RootState) => state.inventoryData.sitesInventory[state.siteData.currentSite.id].inventoryUpdates,
(state: RootState) => state.inventoryData.sitesInventory[state.siteData.currentSiteId].inventoryUpdates,
);

// Customized selectors for products
Expand All @@ -42,7 +42,7 @@ export const {
selectById: selectCurrentSiteInventoryById,
selectIds: selectCurrentSiteInventoryIds,
} = siteInventoryAdapter.getSelectors(
(state: RootState) => state.inventoryData.sitesInventory[state.siteData.currentSite.id].siteInventory,
(state: RootState) => state.inventoryData.sitesInventory[state.siteData.currentSiteId].siteInventory,
);

// Customized selectors for purchase requests
Expand All @@ -52,7 +52,7 @@ export const {
selectById: selectCurrentSitePurchaseRequestById,
selectIds: selectCurrentSitePurchaseRequestsIds,
} = purchaseRequestsAdapter.getSelectors(
(state: RootState) => state.inventoryData.sitesInventory[state.siteData.currentSite.id].purchaseRequests,
(state: RootState) => state.inventoryData.sitesInventory[state.siteData.currentSiteId].purchaseRequests,
);

export interface SiteInventoryData {
Expand Down Expand Up @@ -187,7 +187,7 @@ const inventoryDataSlice = createSlice({
},
extraReducers: {
// If the site changes, reset currentInventoryId
[setCurrSite.type]: (state, action) => {
[setCurrentSiteId.type]: (state, action) => {
state.currentInventoryId = initialState.currentInventoryId;
},
},
Expand Down
1 change: 0 additions & 1 deletion src/lib/redux/refreshData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import { store } from './store';
import { getAllSites } from '../airtable/request';
import { SiteRecord } from '../airtable/interface';
import { saveSiteData, setLoadingForSiteData } from './siteDataSlice';
import { MeterReadingRecord } from '../airtable/interface';
import { refreshInventoryData } from './inventoryData'
import { refreshCustomerData } from './customerData';

Expand Down
22 changes: 14 additions & 8 deletions src/lib/redux/siteData.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
import { setCurrSite } from './siteDataSlice';
import { store } from './store';
import { createSelector } from '@reduxjs/toolkit';
import { SiteRecord } from '../airtable/interface';
import { setCurrentSiteId } from './siteDataSlice';
import { store, RootState } from './store';

const setCurrentSite = (newSite: any): void => {
store.dispatch(setCurrSite(newSite));
export const setCurrentSite = (newSite: any): void => {
store.dispatch(setCurrentSiteId(newSite.id))
};

const getCurrentSiteId = (): string => {
return store.getState().siteData.currentSite.id;
}
export const selectCurrentSiteId = (state: RootState) => state.siteData.currentSiteId;

export { setCurrentSite, getCurrentSiteId };
export const selectCurrentSiteInformation = createSelector(
selectCurrentSiteId,
store.getState,
(siteId, state) => state.siteData.sites[siteId].siteInformation)

// Returns all SiteRecord[] information
export const selectAllSitesInformation = (state: RootState): SiteRecord[] => Object.values(state.siteData.sites).map(site => site.siteInformation);
78 changes: 66 additions & 12 deletions src/lib/redux/siteDataSlice.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,47 @@
/* eslint-disable no-unused-vars */
/* eslint-disable no-param-reassign */
import { createSlice } from '@reduxjs/toolkit';
import { SiteRecord, CustomerRecord, FinancialSummaryRecord } from '../airtable/interface';
import { createEntityAdapter, createSlice, EntityState } from '@reduxjs/toolkit';
import { RootState } from './store';
import { SiteRecord, FinancialSummaryRecord, TariffPlanRecord, SiteId } from '../airtable/interface';

const tariffPlanAdapter = createEntityAdapter<TariffPlanRecord>();
const financialSummaryAdapter = createEntityAdapter<FinancialSummaryRecord>();

// Returns tariff plans in the context of the current site
export const {
selectEntities: selectAllTariffPlans,
selectAll: selectAllTariffPlansArray,
selectById: selectTariffPlanById,
selectIds: selectTariffPlanIds
} = tariffPlanAdapter.getSelectors(
(state: RootState) => state.siteData.sites[state.siteData.currentSiteId].tariffPlans);

// Returns financial summaries in the context of the current site
export const {
selectEntities: selectAllFinancialSummaries,
selectAll: selectAllFinancialSummariesArray,
selectById: selectFinancialSummaryById,
selectIds: selectFinancialSummaryIds
} = financialSummaryAdapter.getSelectors(
(state: RootState) => state.siteData.sites[state.siteData.currentSiteId].financialSummaries);

interface SiteData {
siteInformation: SiteRecord;
tariffPlans: EntityState<TariffPlanRecord>;
financialSummaries: EntityState<FinancialSummaryRecord>;
}


interface siteDataSliceState {
isLoading: boolean;
currentSite: any; //TODO: Set as SiteRecord | null and resolve errors
sites: any[];
currentSiteId: string;
sites: Record<SiteId, SiteData>;
}

//TODO @julianrkung: Change sites to siteIdsToSites and change currentSite to currentSiteId
const initialState: siteDataSliceState = {
isLoading: false,
currentSite: null,
sites: [],
currentSiteId: '',
sites: {},
};

export const EMPTY_SITE: SiteRecord = {
Expand Down Expand Up @@ -43,6 +71,12 @@ export const EMPTY_FINANCIAL_SUMMARY: FinancialSummaryRecord = {
issubmitted: false,
}

const EMPTY_SITE_DATA: SiteData = {
siteInformation: EMPTY_SITE,
tariffPlans: tariffPlanAdapter.getInitialState(),
financialSummaries: financialSummaryAdapter.getInitialState()
}

const siteDataSlice = createSlice({
name: 'siteData',
initialState,
Expand All @@ -52,15 +86,35 @@ const siteDataSlice = createSlice({
},
saveSiteData(state, action) {
const { sites, currentSite } = action.payload;
state.sites = sites;
state.currentSite = currentSite;

sites.forEach((site: SiteRecord) => {
const siteId = site.id;
const siteTariffPlans = site.tariffPlans;
const siteFinancialSummaries = site.financialSummaries;

state.sites[siteId] = JSON.parse(JSON.stringify(EMPTY_SITE_DATA));

const tariffPlanEntities =
tariffPlanAdapter.addMany(state.sites[siteId].tariffPlans, siteTariffPlans as TariffPlanRecord[]);
state.sites[siteId].tariffPlans = tariffPlanEntities;

const financialSummaryEntities =
financialSummaryAdapter.addMany(state.sites[siteId].financialSummaries, siteFinancialSummaries as FinancialSummaryRecord[]);
state.sites[siteId].financialSummaries = financialSummaryEntities;

delete site.tariffPlans;
delete site.financialSummaries
state.sites[siteId].siteInformation = site;
})

state.currentSiteId = currentSite.id;
state.isLoading = false;
},
setCurrSite(state, action) {
state.currentSite = action.payload;
setCurrentSiteId(state, action) {
state.currentSiteId = action.payload;
},
},
});

export const { setLoadingForSiteData, saveSiteData, setCurrSite } = siteDataSlice.actions;
export const { setLoadingForSiteData, saveSiteData, setCurrentSiteId } = siteDataSlice.actions;
export default siteDataSlice.reducer;
6 changes: 3 additions & 3 deletions src/lib/utils/customerUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import { CustomerRecord, MeterReadingRecord, SiteRecord, TariffPlanRecord } from '../../lib/airtable/interface';
import { isBeforeCurrentPeriod } from '../../lib/moment/momentUtils';
import { selectMeterReadingsByCustomerId } from '../../lib/redux/customerData';
import { selectTariffPlanById } from '../../lib/redux/siteDataSlice';
import { store } from '../redux/store';

// Returns the last reading in the period or undefined if no reading has been made in the current period
Expand Down Expand Up @@ -36,9 +37,8 @@ export const getAmountBilled = (currReading: MeterReadingRecord) => {
};

// TODO: add better error handling
export const getTariffPlan = (customer: CustomerRecord, currentSite: SiteRecord): TariffPlanRecord | undefined => {
const tariffPlanId = customer.tariffPlanId;
return currentSite.tariffPlans.find((plan: TariffPlanRecord) => plan.id === tariffPlanId);
export const getTariffPlanByCustomer = (customer: CustomerRecord): TariffPlanRecord | undefined => {
return selectTariffPlanById(store.getState(), customer.tariffPlanId);
}

export const getLatestReadingDate = (customer: CustomerRecord): string => {
Expand Down
Loading

0 comments on commit 17e87c1

Please sign in to comment.