Skip to content

Instantly share code, notes, and snippets.

@joseaquino
Last active December 18, 2020 18:52
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save joseaquino/f27cf3d05f59ea44e0a4d9dd9b9122aa to your computer and use it in GitHub Desktop.
Save joseaquino/f27cf3d05f59ea44e0a4d9dd9b9122aa to your computer and use it in GitHub Desktop.
/* ==========================================================================
* Utility Types and Functions
* ========================================================================== */
export type StateAction<T extends string, P = undefined> = P extends void
? {
type: T
}
: {
type: T
payload: P
}
type GenericAction = {
type: string
payload?: any
}
export type Payload<Actions extends GenericAction, ActionType> = Extract<
Actions,
{ type: ActionType }
> extends { payload: any }
? Extract<Actions, { type: ActionType }>['payload']
: undefined
export type ReducerCollection<
Actions extends StateAction<string, any>,
TState
> = {
[ActionType in Actions['type'] | 'DEFAULT']: (
state: TState,
payload: Payload<Actions, ActionType>
) => ActionType extends 'DEFAULT' ? void | TState : TState
}
export const reducerCollection = <C extends StateAction<string, any>, TState>(
cases: ReducerCollection<C, TState>
) => {
function getCase(
state: TState,
action: C extends StateAction<string, infer A>
? StateAction<C['type'], A>
: StateAction<C['type']>
): TState | any {
if (cases.hasOwnProperty(action.type)) {
return cases[action.type as keyof typeof cases](
state,
(action as GenericAction).payload
)
} else {
return cases['DEFAULT'](state, (action as GenericAction).payload)
}
}
return getCase
}
/* ==========================================================================
* Actions Constants
* ========================================================================== */
enum CONFIG_ACTION_NAMES {
smsPaymentLoading = 'Configurations API/Loading SMS Payment',
smsPaymentUpdating = 'Configurations API/Updating SMS Payment',
smsPaymentSuccess = 'Configurations API/Commerce SMS Payment Loaded',
smsPaymentFailure = 'Configuration API/Commerce SMS Payment Failed',
}
/* ==========================================================================
* Types & Interfaces
* ========================================================================== */
export interface ConfigurationState {
smsPayment: {
value: string | null
request: BasicRequest
}
}
type SMSPaymentLoading = StateAction<CONFIG_ACTION_NAMES.smsPaymentLoading>
type SMSPaymentUpdating = StateAction<CONFIG_ACTION_NAMES.smsPaymentUpdating>
type SMSPaymentSuccess = StateAction<
CONFIG_ACTION_NAMES.smsPaymentSuccess,
{ value: string }
>
type SMSPaymentFailure = StateAction<
CONFIG_ACTION_NAMES.smsPaymentFailure,
{
errorType: RequestError
}
>
type ConfigurationActionTypes =
| SMSPaymentLoading
| SMSPaymentUpdating
| SMSPaymentSuccess
| SMSPaymentFailure
/* ==========================================================================
* State Management
* ========================================================================== */
const reducers = reducerCollection<
ConfigurationActionTypes,
ConfigurationState
>({
DEFAULT: () => {
throw new Error(
'useConfigurationsApi: An action was dispatched which has no matching reducer.'
)
},
// SMS Payment Loading reducer
[CONFIG_ACTION_NAMES.smsPaymentLoading]: (state) => ({
...state,
smsPayment: {
value: null,
request: {
status: 'LOADING',
error: null,
},
},
}),
// SMS Payment Updating reducer
[CONFIG_ACTION_NAMES.smsPaymentUpdating]: (state) => ({
...state,
smsPayment: {
value: state.smsPayment.value,
request: {
status: 'UPDATING',
error: null,
},
},
}),
// SMS Payment Success reducer
[CONFIG_ACTION_NAMES.smsPaymentSuccess]: (state, { value }) => ({
...state,
smsPayment: {
value,
request: {
status: 'IDLE',
error: null,
},
},
}),
// SMS Payment Failure reducer
[CONFIG_ACTION_NAMES.smsPaymentFailure]: (state, { errorType }) => ({
...state,
smsPayment: {
value: state.smsPayment.value,
request: {
status: 'ERROR',
error: errorType,
},
},
}),
})
const initialState: ConfigurationState = {
smsPayment: {
value: null,
request: {
status: 'IDLE',
error: null,
},
},
}
/* ==========================================================================
* Component Definition
* ========================================================================== */
const ConfigurationsComponent = () => {
const [state, dispatch] = useReducer(reducers, initialState)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment