Skip to content

Instantly share code, notes, and snippets.

@adnaan
Created June 23, 2020 09:53
Show Gist options
  • Save adnaan/76ce62701da0f8318e61589ebecfb145 to your computer and use it in GitHub Desktop.
Save adnaan/76ce62701da0f8318e61589ebecfb145 to your computer and use it in GitHub Desktop.
import {createSlice} from "@reduxjs/toolkit";
import {asyncThunk, rx, asyncAction} from "./thunks";
import {identity} from "./identity";
export const fetchAccount = asyncThunk(
"account",
"fetchAccount",
async (id, state) => {
return identity.currentUser().attributes();
});
export const resetAPIKey = asyncThunk(
"account",
"resetAPIKey",
async (id, state) => {
return identity.currentUser().resetAPIKey();
});
export const updateName = asyncThunk(
"account",
"updateName",
async (name, state) => {
return identity.currentUser().update({data: {name: name}});
});
export const updateEmail = asyncThunk(
"account",
"updateEmail",
async (email, state) => {
return identity.currentUser().update({email: email});
});
export const requestPasswordRecovery = asyncThunk(
"account",
"requestPasswordRecovery",
async (email, state) => {
return identity.requestPasswordRecovery(email);
});
export const confirm = asyncThunk(
"account",
"confirm",
async (data, state) => {
return identity.confirm(data, true);
});
export const confirmPasswordReset = asyncThunk(
"account",
"confirmPasswordReset",
async (data, state) => {
return identity
.recover(data.token)
.then(response => {
const user = identity.currentUser();
user.update({password: data.password})
.then()
.catch(error => {
throw error;
});
})
});
export const login = asyncThunk(
"account",
"login",
async (data, state) => {
return identity.login(data.email, data.pass, true);
});
export const signup = asyncThunk(
"account",
"signup",
async (data, state) => {
console.log("signup")
return identity.signup(data.email, data.pass, data.data);
});
export const logout = asyncThunk(
"account",
"logout",
async (data, state) => {
return identity.currentUser().logout();
});
export const subscribePlan = asyncThunk(
"account",
"subscribePlan",
async (data, state) => {
console.log(data, identity.currentUser())
return identity.currentUser().subscribePlan(data);
});
export const unsubscribePlan = asyncThunk(
"account",
"unsubscribePlan",
async (data, state) => {
return identity.currentUser().unsubscribePlan(data);
})
export const listPaymentMethods = asyncThunk(
"account",
"listPaymentMethods",
async (data, state) => {
return identity.currentUser().listPaymentMethods();
});
export const addPaymentMethod = asyncThunk(
"account",
"addPaymentMethod",
async (id, state) => {
return identity.currentUser().addPaymentMethod(id);
});
export const removePaymentMethod = asyncThunk(
"account",
"removePaymentMethod",
async (id, state) => {
return identity.currentUser().removePaymentMethod(id);
});
export const setDefaultPaymentMethod = asyncThunk(
"account",
"setDefaultPaymentMethod",
async (id, state) => {
return identity.currentUser().setDefaultPaymentMethod(id);
});
export const paymentMethodsUpdate = (state, action) => {
state.paymentMethods = action.payload.data;
state.default_payment_method_id = action.payload.default_payment_method_id;
};
export const listInvoices = asyncThunk(
"account",
"listInvoices",
async (data, state) => {
return identity.currentUser().listInvoices();
});
export const listUsage = asyncThunk(
"account",
"listUsage",
async (data, state) => {
return identity.currentUser().listUsage();
});
const fetchUserAccountAction = asyncAction(
"app",
"fetchUserAccount",
async data => identity.currentUser().getAccount(),
(state, action) => {
state.userAccount = action.payload
}
);
export const fetchUserAccount = fetchUserAccountAction.thunk;
const createOrgAction = asyncAction(
"app",
"createOrg",
async data => identity.currentUser().createOrg(data),
(state, action) => {
state.userAccount = action.payload
}
);
export const createOrg = createOrgAction.thunk;
export const userUpdate = (state, action) => {
state.user = action.payload
}
export const initialAccountState = {
loading: {},
user: identity.currentUser(),
userAccount: null,
subscription: null,
paymentMethods: [],
default_payment_method_id: null,
invoices: null,
usage: null,
error: {},
currentRequestId: {},
};
export const accountSlice = createSlice({
name: "account",
initialState: initialAccountState,
reducers: {
setUser: (state, action) => {
state.user = action.payload
}
},
extraReducers: {
...rx(login, userUpdate),
...rx(logout, (state, action) => {
state.user = null
}),
...rx(signup),
...rx(fetchAccount, (state, action) => {
state.user = action.payload
}),
...rx(resetAPIKey, userUpdate),
...rx(updateName, userUpdate),
...rx(updateEmail, userUpdate),
...rx(requestPasswordRecovery),
...rx(confirm),
...rx(confirmPasswordReset),
...rx(subscribePlan, (state, action) => {
state.subscription = action.payload
}),
...rx(unsubscribePlan, (state, action) => {
state.subscription = action.payload
}),
...rx(listPaymentMethods, paymentMethodsUpdate),
...rx(addPaymentMethod, paymentMethodsUpdate),
...rx(removePaymentMethod, paymentMethodsUpdate),
...rx(setDefaultPaymentMethod, paymentMethodsUpdate),
...rx(listInvoices, (state, action) => {
state.invoices = action.payload
}),
...rx(listUsage, (state, action) => {
state.usage = action.payload
}),
...fetchUserAccountAction.reducers,
...createOrgAction.reducers
}
});
import {createAsyncThunk} from "@reduxjs/toolkit";
const pending = (state, action) => {
const key = action.type.split('/')[1];
if (state.loading[key] === 'idle' || state.loading[key] === undefined) {
state.loading[key] = 'pending';
state.error[key] = undefined;
state.currentRequestId[key] = action.meta.requestId
}
};
const fulfilled = (update) => {
return (state, action) => {
const {requestId} = action.meta;
const key = action.type.split('/')[1];
// console.log("fulfilled => ", state.loading[key], key, state.currentRequestId[key], requestId);
if (state.loading[key] === 'pending' && state.currentRequestId[key] === requestId) {
state.loading[key] = 'idle';
state.currentRequestId[key] = undefined;
state.error[key] = undefined
if (update) {
update(state, action);
}
}
}
};
const rejected = (state, action) => {
const {requestId} = action.meta;
const key = action.type.split('/')[1];
// console.log("rejected => ", state.loading[key], key, state.currentRequestId[key], requestId);
if (state.loading[key] === 'pending' && state.currentRequestId[key] === requestId) {
console.log("rejected", key, action.error)
state.loading[key] = 'idle';
state.error[key] = action.error;
state.currentRequestId[key] = undefined
}
};
const rx = (thunk, update) => {
return {
[thunk.pending]: pending,
[thunk.fulfilled]: fulfilled(update),
[thunk.rejected]: rejected
}
};
const asyncThunk = (stateName, actionName, fetchFn) => {
return createAsyncThunk(
`${stateName}/${actionName}`,
(id, {getState}) => {
return fetchFn(id, getState())
}
)
};
const asyncAction = (stateName, actionName, fetchFn, update) => {
const thunk = createAsyncThunk(
`${stateName}/${actionName}`,
(payload, {getState}) => {
return fetchFn(payload)
}
);
const reducers = {
[thunk.pending]: pending,
[thunk.fulfilled]: fulfilled(update),
[thunk.rejected]: rejected
}
return {thunk, reducers}
};
export {
asyncAction,
asyncThunk,
rx,
rejected,
fulfilled,
pending,
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment