2018-09-10 09:55:26 -07:00
|
|
|
|
import types from './types';
|
2018-09-18 15:15:01 -07:00
|
|
|
|
import { findComment } from 'utils/helpers';
|
2019-01-09 12:48:41 -08:00
|
|
|
|
import { Proposal, ProposalComments, ProposalUpdates, Comment, ProposalContributions } from 'types';
|
2018-09-10 09:55:26 -07:00
|
|
|
|
|
|
|
|
|
export interface ProposalState {
|
2018-12-21 10:47:50 -08:00
|
|
|
|
proposals: Proposal[];
|
2018-09-10 09:55:26 -07:00
|
|
|
|
proposalsError: null | string;
|
|
|
|
|
isFetchingProposals: boolean;
|
|
|
|
|
|
|
|
|
|
proposalComments: { [id: string]: ProposalComments };
|
|
|
|
|
commentsError: null | string;
|
|
|
|
|
isFetchingComments: boolean;
|
|
|
|
|
|
|
|
|
|
proposalUpdates: { [id: string]: ProposalUpdates };
|
|
|
|
|
updatesError: null | string;
|
|
|
|
|
isFetchingUpdates: boolean;
|
2018-09-18 15:15:01 -07:00
|
|
|
|
|
2019-01-09 12:48:41 -08:00
|
|
|
|
proposalContributions: { [id: string]: ProposalContributions };
|
|
|
|
|
fetchContributionsError: null | string;
|
|
|
|
|
isFetchingContributions: boolean;
|
|
|
|
|
|
2018-09-18 15:15:01 -07:00
|
|
|
|
isPostCommentPending: boolean;
|
|
|
|
|
postCommentError: null | string;
|
2018-09-10 09:55:26 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export const INITIAL_STATE: ProposalState = {
|
|
|
|
|
proposals: [],
|
|
|
|
|
proposalsError: null,
|
|
|
|
|
isFetchingProposals: false,
|
|
|
|
|
|
|
|
|
|
proposalComments: {},
|
|
|
|
|
commentsError: null,
|
|
|
|
|
isFetchingComments: false,
|
|
|
|
|
|
|
|
|
|
proposalUpdates: {},
|
|
|
|
|
updatesError: null,
|
|
|
|
|
isFetchingUpdates: false,
|
2018-09-18 15:15:01 -07:00
|
|
|
|
|
2019-01-09 12:48:41 -08:00
|
|
|
|
proposalContributions: {},
|
|
|
|
|
fetchContributionsError: null,
|
|
|
|
|
isFetchingContributions: false,
|
|
|
|
|
|
2018-09-18 15:15:01 -07:00
|
|
|
|
isPostCommentPending: false,
|
|
|
|
|
postCommentError: null,
|
2018-09-10 09:55:26 -07:00
|
|
|
|
};
|
|
|
|
|
|
2018-12-21 10:47:50 -08:00
|
|
|
|
function addProposal(state: ProposalState, payload: Proposal) {
|
2018-09-10 09:55:26 -07:00
|
|
|
|
let proposals = state.proposals;
|
|
|
|
|
|
|
|
|
|
const existingProposal = state.proposals.find(
|
2018-12-21 10:47:50 -08:00
|
|
|
|
(p: Proposal) => p.proposalId === payload.proposalId,
|
2018-09-10 09:55:26 -07:00
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if (!existingProposal) {
|
|
|
|
|
proposals = proposals.concat(payload);
|
|
|
|
|
} else {
|
|
|
|
|
proposals = [...proposals];
|
|
|
|
|
const index = proposals.indexOf(existingProposal);
|
|
|
|
|
proposals[index] = payload;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
...state,
|
|
|
|
|
...{
|
|
|
|
|
proposals,
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
2018-12-21 10:47:50 -08:00
|
|
|
|
function addProposals(state: ProposalState, payload: Proposal[]) {
|
2018-09-10 09:55:26 -07:00
|
|
|
|
return {
|
|
|
|
|
...state,
|
|
|
|
|
proposals: payload,
|
|
|
|
|
isFetchingProposals: false,
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function addComments(state: ProposalState, payload: { data: ProposalComments }) {
|
|
|
|
|
return {
|
|
|
|
|
...state,
|
|
|
|
|
proposalComments: {
|
|
|
|
|
...state.proposalComments,
|
|
|
|
|
[payload.data.proposalId]: payload.data,
|
|
|
|
|
},
|
|
|
|
|
isFetchingComments: false,
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-02 09:24:28 -07:00
|
|
|
|
function addUpdates(state: ProposalState, payload: ProposalUpdates) {
|
2018-09-10 09:55:26 -07:00
|
|
|
|
return {
|
|
|
|
|
...state,
|
|
|
|
|
proposalUpdates: {
|
|
|
|
|
...state.proposalUpdates,
|
2018-11-02 09:24:28 -07:00
|
|
|
|
[payload.proposalId]: payload,
|
2018-09-10 09:55:26 -07:00
|
|
|
|
},
|
|
|
|
|
isFetchingUpdates: false,
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-09 12:48:41 -08:00
|
|
|
|
function addContributions(state: ProposalState, payload: ProposalContributions) {
|
|
|
|
|
return {
|
|
|
|
|
...state,
|
|
|
|
|
proposalContributions: {
|
|
|
|
|
...state.proposalContributions,
|
|
|
|
|
[payload.proposalId]: payload,
|
|
|
|
|
},
|
|
|
|
|
isFetchingContributions: false,
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-18 15:15:01 -07:00
|
|
|
|
interface PostCommentPayload {
|
2018-12-21 10:47:50 -08:00
|
|
|
|
proposalId: Proposal['proposalId'];
|
2018-09-18 15:15:01 -07:00
|
|
|
|
comment: Comment;
|
2018-11-08 11:14:52 -08:00
|
|
|
|
parentCommentId?: Comment['id'];
|
2018-09-18 15:15:01 -07:00
|
|
|
|
}
|
|
|
|
|
function addPostedComment(state: ProposalState, payload: PostCommentPayload) {
|
|
|
|
|
const { proposalId, comment, parentCommentId } = payload;
|
|
|
|
|
const newComments = state.proposalComments[proposalId]
|
|
|
|
|
? {
|
|
|
|
|
...state.proposalComments[proposalId],
|
|
|
|
|
totalComments: state.proposalComments[proposalId].totalComments + 1,
|
|
|
|
|
comments: [...state.proposalComments[proposalId].comments],
|
|
|
|
|
}
|
|
|
|
|
: {
|
|
|
|
|
proposalId: payload.proposalId,
|
|
|
|
|
totalComments: 1,
|
|
|
|
|
comments: [],
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if (parentCommentId) {
|
|
|
|
|
const parentComment = findComment(parentCommentId, newComments.comments);
|
|
|
|
|
if (parentComment) {
|
|
|
|
|
// FIXME: Object mutation because I'm lazy, but this probably shouldn’t
|
|
|
|
|
// exist once API hookup is done. We'll just re-request from server.
|
|
|
|
|
parentComment.replies.unshift(comment);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
newComments.comments.unshift(comment);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
...state,
|
|
|
|
|
isPostCommentPending: false,
|
|
|
|
|
proposalComments: {
|
|
|
|
|
...state.proposalComments,
|
|
|
|
|
[payload.proposalId]: newComments,
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-10 09:55:26 -07:00
|
|
|
|
export default (state = INITIAL_STATE, action: any) => {
|
|
|
|
|
const { payload } = action;
|
|
|
|
|
switch (action.type) {
|
|
|
|
|
case types.PROPOSALS_DATA_PENDING:
|
|
|
|
|
return {
|
|
|
|
|
...state,
|
|
|
|
|
proposals: [],
|
|
|
|
|
proposalsError: null,
|
|
|
|
|
isFetchingProposals: true,
|
|
|
|
|
};
|
|
|
|
|
case types.PROPOSALS_DATA_FULFILLED:
|
|
|
|
|
return addProposals(state, payload);
|
|
|
|
|
case types.PROPOSALS_DATA_REJECTED:
|
|
|
|
|
return {
|
|
|
|
|
...state,
|
|
|
|
|
// TODO: Get action to send real error
|
|
|
|
|
proposalsError: 'Failed to fetch proposal',
|
|
|
|
|
isFetchingProposals: false,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
case types.PROPOSAL_DATA_FULFILLED:
|
|
|
|
|
return addProposal(state, payload);
|
|
|
|
|
|
|
|
|
|
case types.PROPOSAL_COMMENTS_PENDING:
|
|
|
|
|
return {
|
|
|
|
|
...state,
|
|
|
|
|
commentsError: null,
|
|
|
|
|
isFetchingComments: true,
|
|
|
|
|
};
|
|
|
|
|
case types.PROPOSAL_COMMENTS_FULFILLED:
|
|
|
|
|
return addComments(state, payload);
|
|
|
|
|
case types.PROPOSAL_COMMENTS_REJECTED:
|
|
|
|
|
return {
|
|
|
|
|
...state,
|
|
|
|
|
// TODO: Get action to send real error
|
|
|
|
|
commentsError: 'Failed to fetch comments',
|
|
|
|
|
isFetchingComments: false,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
case types.PROPOSAL_UPDATES_PENDING:
|
|
|
|
|
return {
|
|
|
|
|
...state,
|
|
|
|
|
updatesError: null,
|
|
|
|
|
isFetchingUpdates: true,
|
|
|
|
|
};
|
|
|
|
|
case types.PROPOSAL_UPDATES_FULFILLED:
|
|
|
|
|
return addUpdates(state, payload);
|
|
|
|
|
case types.PROPOSAL_UPDATES_REJECTED:
|
|
|
|
|
return {
|
|
|
|
|
...state,
|
|
|
|
|
// TODO: Get action to send real error
|
|
|
|
|
updatesError: 'Failed to fetch updates',
|
|
|
|
|
isFetchingUpdates: false,
|
|
|
|
|
};
|
|
|
|
|
|
2019-01-09 12:48:41 -08:00
|
|
|
|
case types.PROPOSAL_CONTRIBUTIONS_PENDING:
|
|
|
|
|
return {
|
|
|
|
|
...state,
|
|
|
|
|
fetchContributionsError: null,
|
|
|
|
|
isFetchingContributions: true,
|
|
|
|
|
};
|
|
|
|
|
case types.PROPOSAL_CONTRIBUTIONS_FULFILLED:
|
|
|
|
|
return addContributions(state, payload);
|
|
|
|
|
case types.PROPOSAL_CONTRIBUTIONS_REJECTED:
|
|
|
|
|
return {
|
|
|
|
|
...state,
|
|
|
|
|
// TODO: Get action to send real error
|
|
|
|
|
fetchContributionsError: 'Failed to fetch updates',
|
|
|
|
|
isFetchingContributions: false,
|
|
|
|
|
};
|
|
|
|
|
|
2018-09-18 15:15:01 -07:00
|
|
|
|
case types.POST_PROPOSAL_COMMENT_PENDING:
|
|
|
|
|
return {
|
|
|
|
|
...state,
|
|
|
|
|
isPostCommentPending: true,
|
|
|
|
|
postCommentError: null,
|
|
|
|
|
};
|
|
|
|
|
case types.POST_PROPOSAL_COMMENT_FULFILLED:
|
|
|
|
|
return addPostedComment(state, payload);
|
|
|
|
|
case types.POST_PROPOSAL_COMMENT_REJECTED:
|
|
|
|
|
return {
|
|
|
|
|
...state,
|
|
|
|
|
isPostCommentPending: false,
|
|
|
|
|
postCommentError: payload,
|
|
|
|
|
};
|
|
|
|
|
|
2018-09-10 09:55:26 -07:00
|
|
|
|
default:
|
|
|
|
|
return state;
|
|
|
|
|
}
|
|
|
|
|
};
|