2018-10-30 09:35:47 -07:00
|
|
|
import { store } from 'react-easy-state';
|
|
|
|
import axios, { AxiosError } from 'axios';
|
2019-01-09 10:23:08 -08:00
|
|
|
import { User, Proposal, PROPOSAL_STATUS } from './types';
|
2018-10-30 09:35:47 -07:00
|
|
|
|
|
|
|
// API
|
|
|
|
const api = axios.create({
|
|
|
|
baseURL: process.env.BACKEND_URL + '/api/v1',
|
|
|
|
withCredentials: true,
|
|
|
|
});
|
|
|
|
|
|
|
|
async function login(username: string, password: string) {
|
|
|
|
const { data } = await api.post('/admin/login', {
|
|
|
|
username,
|
|
|
|
password,
|
|
|
|
});
|
|
|
|
return data.isLoggedIn;
|
|
|
|
}
|
|
|
|
|
|
|
|
async function logout() {
|
|
|
|
const { data } = await api.get('/admin/logout');
|
|
|
|
return data.isLoggedIn;
|
|
|
|
}
|
|
|
|
|
|
|
|
async function checkLogin() {
|
|
|
|
const { data } = await api.get('/admin/checklogin');
|
|
|
|
return data.isLoggedIn;
|
|
|
|
}
|
|
|
|
|
|
|
|
async function fetchStats() {
|
|
|
|
const { data } = await api.get('/admin/stats');
|
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
|
|
|
async function fetchUsers() {
|
|
|
|
const { data } = await api.get('/admin/users');
|
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
2019-01-09 10:23:08 -08:00
|
|
|
async function deleteUser(id: number | string) {
|
2018-10-30 09:35:47 -07:00
|
|
|
const { data } = await api.delete('/admin/users/' + id);
|
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
2019-01-09 10:23:08 -08:00
|
|
|
async function fetchProposals(statusFilters?: PROPOSAL_STATUS[]) {
|
|
|
|
const { data } = await api.get('/admin/proposals', {
|
|
|
|
params: { statusFilters },
|
|
|
|
});
|
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
|
|
|
async function fetchProposalDetail(id: number) {
|
|
|
|
const { data } = await api.get(`/admin/proposals/${id}`);
|
2018-10-30 09:35:47 -07:00
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
2018-11-09 10:48:55 -08:00
|
|
|
async function deleteProposal(id: number) {
|
2018-10-30 09:35:47 -07:00
|
|
|
const { data } = await api.delete('/admin/proposals/' + id);
|
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
2019-01-09 10:23:08 -08:00
|
|
|
async function approveProposal(id: number, isApprove: boolean, rejectReason?: string) {
|
|
|
|
const { data } = await api.put(`/admin/proposals/${id}/approve`, {
|
|
|
|
isApprove,
|
|
|
|
rejectReason,
|
|
|
|
});
|
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
2018-10-30 09:35:47 -07:00
|
|
|
// STORE
|
|
|
|
const app = store({
|
|
|
|
hasCheckedLogin: false,
|
|
|
|
isLoggedIn: false,
|
|
|
|
loginError: '',
|
|
|
|
generalError: [] as string[],
|
2019-01-09 10:23:08 -08:00
|
|
|
statsFetched: false,
|
|
|
|
statsFetching: false,
|
2018-10-30 09:35:47 -07:00
|
|
|
stats: {
|
2019-01-09 10:23:08 -08:00
|
|
|
userCount: 0,
|
|
|
|
proposalCount: 0,
|
|
|
|
proposalPendingCount: 0,
|
2018-10-30 09:35:47 -07:00
|
|
|
},
|
|
|
|
usersFetched: false,
|
|
|
|
users: [] as User[],
|
2019-01-09 10:23:08 -08:00
|
|
|
proposalsFetching: false,
|
2018-10-30 09:35:47 -07:00
|
|
|
proposalsFetched: false,
|
|
|
|
proposals: [] as Proposal[],
|
2019-01-09 10:23:08 -08:00
|
|
|
proposalDetailFetching: false,
|
|
|
|
proposalDetail: null as null | Proposal,
|
|
|
|
proposalDetailApproving: false,
|
2018-10-30 09:35:47 -07:00
|
|
|
|
|
|
|
removeGeneralError(i: number) {
|
|
|
|
app.generalError.splice(i, 1);
|
|
|
|
},
|
|
|
|
|
2019-01-09 10:23:08 -08:00
|
|
|
updateProposalInStore(p: Proposal) {
|
|
|
|
const index = app.proposals.findIndex(x => x.proposalId === p.proposalId);
|
|
|
|
if (index > -1) {
|
|
|
|
app.proposals[index] = p;
|
|
|
|
}
|
|
|
|
if (app.proposalDetail && app.proposalDetail.proposalId === p.proposalId) {
|
|
|
|
app.proposalDetail = p;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2018-10-30 09:35:47 -07:00
|
|
|
async checkLogin() {
|
|
|
|
app.isLoggedIn = await checkLogin();
|
|
|
|
app.hasCheckedLogin = true;
|
|
|
|
},
|
|
|
|
|
|
|
|
async login(username: string, password: string) {
|
|
|
|
try {
|
|
|
|
app.isLoggedIn = await login(username, password);
|
|
|
|
} catch (e) {
|
|
|
|
app.loginError = e.response.data.message;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
async logout() {
|
|
|
|
try {
|
|
|
|
app.isLoggedIn = await logout();
|
|
|
|
} catch (e) {
|
|
|
|
app.generalError.push(e.toString());
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
async fetchStats() {
|
2019-01-09 10:23:08 -08:00
|
|
|
app.statsFetching = true;
|
2018-10-30 09:35:47 -07:00
|
|
|
try {
|
|
|
|
app.stats = await fetchStats();
|
2019-01-09 10:23:08 -08:00
|
|
|
app.statsFetched = true;
|
2018-10-30 09:35:47 -07:00
|
|
|
} catch (e) {
|
|
|
|
handleApiError(e);
|
|
|
|
}
|
2019-01-09 10:23:08 -08:00
|
|
|
app.statsFetching = false;
|
2018-10-30 09:35:47 -07:00
|
|
|
},
|
|
|
|
|
|
|
|
async fetchUsers() {
|
|
|
|
try {
|
|
|
|
app.users = await fetchUsers();
|
|
|
|
app.usersFetched = true;
|
|
|
|
} catch (e) {
|
|
|
|
handleApiError(e);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2019-01-09 10:23:08 -08:00
|
|
|
async deleteUser(id: string | number) {
|
2018-10-30 09:35:47 -07:00
|
|
|
try {
|
|
|
|
await deleteUser(id);
|
2019-01-09 10:23:08 -08:00
|
|
|
app.users = app.users.filter(u => u.userid !== id && u.emailAddress !== id);
|
2018-10-30 09:35:47 -07:00
|
|
|
} catch (e) {
|
|
|
|
handleApiError(e);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2019-01-09 10:23:08 -08:00
|
|
|
async fetchProposals(statusFilters?: PROPOSAL_STATUS[]) {
|
|
|
|
app.proposalsFetching = true;
|
2018-10-30 09:35:47 -07:00
|
|
|
try {
|
2019-01-09 10:23:08 -08:00
|
|
|
app.proposals = await fetchProposals(statusFilters);
|
2018-10-30 09:35:47 -07:00
|
|
|
app.proposalsFetched = true;
|
|
|
|
} catch (e) {
|
|
|
|
handleApiError(e);
|
|
|
|
}
|
2019-01-09 10:23:08 -08:00
|
|
|
app.proposalsFetching = false;
|
|
|
|
},
|
|
|
|
|
|
|
|
async fetchProposalDetail(id: number) {
|
|
|
|
app.proposalDetailFetching = true;
|
|
|
|
try {
|
|
|
|
app.proposalDetail = await fetchProposalDetail(id);
|
|
|
|
} catch (e) {
|
|
|
|
handleApiError(e);
|
|
|
|
}
|
|
|
|
app.proposalDetailFetching = false;
|
2018-10-30 09:35:47 -07:00
|
|
|
},
|
|
|
|
|
2018-11-09 10:48:55 -08:00
|
|
|
async deleteProposal(id: number) {
|
2018-10-30 09:35:47 -07:00
|
|
|
try {
|
|
|
|
await deleteProposal(id);
|
|
|
|
app.proposals = app.proposals.filter(p => p.proposalId === id);
|
|
|
|
} catch (e) {
|
|
|
|
handleApiError(e);
|
|
|
|
}
|
|
|
|
},
|
2019-01-09 10:23:08 -08:00
|
|
|
|
|
|
|
async approveProposal(isApprove: boolean, rejectReason?: string) {
|
|
|
|
if (!app.proposalDetail) {
|
|
|
|
(x => {
|
|
|
|
app.generalError.push(x);
|
|
|
|
console.error(x);
|
|
|
|
})('store.approveProposal(): Expected proposalDetail to be populated!');
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
app.proposalDetailApproving = true;
|
|
|
|
try {
|
|
|
|
const { proposalId } = app.proposalDetail;
|
|
|
|
const res = await approveProposal(proposalId, isApprove, rejectReason);
|
|
|
|
app.updateProposalInStore(res);
|
|
|
|
} catch (e) {
|
|
|
|
handleApiError(e);
|
|
|
|
}
|
|
|
|
app.proposalDetailApproving = false;
|
|
|
|
},
|
2018-10-30 09:35:47 -07:00
|
|
|
});
|
|
|
|
|
|
|
|
function handleApiError(e: AxiosError) {
|
|
|
|
if (e.response && e.response.data!.message) {
|
|
|
|
app.generalError.push(e.response!.data.message);
|
|
|
|
} else if (e.response && e.response.data!.data!) {
|
|
|
|
app.generalError.push(e.response!.data.data);
|
|
|
|
} else {
|
|
|
|
app.generalError.push(e.toString());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
(window as any).appStore = app;
|
|
|
|
|
|
|
|
// check login status periodically
|
|
|
|
app.checkLogin();
|
|
|
|
window.setInterval(app.checkLogin, 10000);
|
|
|
|
|
|
|
|
export type TApp = typeof app;
|
|
|
|
export default app;
|