FE: user profile arbitrations tab
This commit is contained in:
parent
2b78a17973
commit
048cda8216
|
@ -65,13 +65,15 @@ def get_me():
|
||||||
parameter("withProposals", type=bool, required=False),
|
parameter("withProposals", type=bool, required=False),
|
||||||
parameter("withComments", type=bool, required=False),
|
parameter("withComments", type=bool, required=False),
|
||||||
parameter("withFunded", type=bool, required=False),
|
parameter("withFunded", type=bool, required=False),
|
||||||
parameter("withPending", type=bool, required=False)
|
parameter("withPending", type=bool, required=False),
|
||||||
|
parameter("withArbitrated", type=bool, required=False)
|
||||||
)
|
)
|
||||||
def get_user(user_id, with_proposals, with_comments, with_funded, with_pending):
|
def get_user(user_id, with_proposals, with_comments, with_funded, with_pending, with_arbitrated):
|
||||||
user = User.get_by_id(user_id)
|
user = User.get_by_id(user_id)
|
||||||
if user:
|
if user:
|
||||||
result = user_schema.dump(user)
|
result = user_schema.dump(user)
|
||||||
authed_user = get_authed_user()
|
authed_user = get_authed_user()
|
||||||
|
is_self = authed_user and authed_user.id == user.id
|
||||||
if with_proposals:
|
if with_proposals:
|
||||||
proposals = Proposal.get_by_user(user)
|
proposals = Proposal.get_by_user(user)
|
||||||
proposals_dump = user_proposals_schema.dump(proposals)
|
proposals_dump = user_proposals_schema.dump(proposals)
|
||||||
|
@ -86,7 +88,7 @@ def get_user(user_id, with_proposals, with_comments, with_funded, with_pending):
|
||||||
comments = Comment.get_by_user(user)
|
comments = Comment.get_by_user(user)
|
||||||
comments_dump = user_comments_schema.dump(comments)
|
comments_dump = user_comments_schema.dump(comments)
|
||||||
result["comments"] = comments_dump
|
result["comments"] = comments_dump
|
||||||
if with_pending and authed_user and authed_user.id == user.id:
|
if with_pending and is_self:
|
||||||
pending = Proposal.get_by_user(user, [
|
pending = Proposal.get_by_user(user, [
|
||||||
ProposalStatus.STAKING,
|
ProposalStatus.STAKING,
|
||||||
ProposalStatus.PENDING,
|
ProposalStatus.PENDING,
|
||||||
|
@ -95,6 +97,8 @@ def get_user(user_id, with_proposals, with_comments, with_funded, with_pending):
|
||||||
])
|
])
|
||||||
pending_dump = user_proposals_schema.dump(pending)
|
pending_dump = user_proposals_schema.dump(pending)
|
||||||
result["pendingProposals"] = pending_dump
|
result["pendingProposals"] = pending_dump
|
||||||
|
if with_arbitrated and is_self:
|
||||||
|
result["arbitrated"] = user_proposals_schema.dump(user.arbitrated_proposals)
|
||||||
return result
|
return result
|
||||||
else:
|
else:
|
||||||
message = "User with id matching {} not found".format(user_id)
|
message = "User with id matching {} not found".format(user_id)
|
||||||
|
|
|
@ -68,6 +68,7 @@ export function getUser(address: string): Promise<{ data: User }> {
|
||||||
withComments: true,
|
withComments: true,
|
||||||
withFunded: true,
|
withFunded: true,
|
||||||
withPending: true,
|
withPending: true,
|
||||||
|
withArbitrated: true,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.then(res => {
|
.then(res => {
|
||||||
|
|
|
@ -0,0 +1,71 @@
|
||||||
|
@import '~styles/variables.less';
|
||||||
|
@small-query: ~'(max-width: 640px)';
|
||||||
|
|
||||||
|
.ProfileArbitrated {
|
||||||
|
display: flex;
|
||||||
|
padding-bottom: 1.2rem;
|
||||||
|
border-bottom: 1px solid rgba(0, 0, 0, 0.05);
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
border-bottom: none;
|
||||||
|
padding-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media @small-query {
|
||||||
|
flex-direction: column;
|
||||||
|
padding-bottom: 0.6rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-title {
|
||||||
|
font-size: 1.2rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: inherit;
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 0.1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-block {
|
||||||
|
flex: 1 0 0%;
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
margin-left: 1.2rem;
|
||||||
|
flex: 0 0 0%;
|
||||||
|
min-width: 15rem;
|
||||||
|
|
||||||
|
@media @small-query {
|
||||||
|
margin-left: 0;
|
||||||
|
margin-top: 0.6rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.is-actions {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
& button + button,
|
||||||
|
a + button {
|
||||||
|
margin-left: 0.5rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-tag {
|
||||||
|
vertical-align: text-top;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-status {
|
||||||
|
margin-bottom: 0.6rem;
|
||||||
|
|
||||||
|
& q {
|
||||||
|
display: block;
|
||||||
|
margin: 0.5rem;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
& small {
|
||||||
|
opacity: 0.6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
import React from 'react';
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
|
import { UserProposal } from 'types';
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import { AppState } from 'store/reducers';
|
||||||
|
import './ProfileArbitrated.less';
|
||||||
|
|
||||||
|
interface OwnProps {
|
||||||
|
proposal: UserProposal;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface StateProps {
|
||||||
|
user: AppState['auth']['user'];
|
||||||
|
}
|
||||||
|
|
||||||
|
type Props = OwnProps & StateProps;
|
||||||
|
|
||||||
|
class ProfileArbitrated extends React.Component<Props, {}> {
|
||||||
|
render() {
|
||||||
|
const { title, proposalId } = this.props.proposal;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="ProfileArbitrated">
|
||||||
|
<div className="ProfileArbitrated-block">
|
||||||
|
<Link to={`/proposals/${proposalId}`} className="ProfileArbitrated-title">
|
||||||
|
{title}
|
||||||
|
</Link>
|
||||||
|
<div className={`ProfileArbitrated-info`}>
|
||||||
|
You are the arbiter for this proposal. You are responsible for reviewing
|
||||||
|
milestone payout requests.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="ProfileArbitrated-block is-actions">
|
||||||
|
{/* TODO - review milestone button & etc. */}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default connect<StateProps, {}, OwnProps, AppState>(state => ({
|
||||||
|
user: state.auth.user,
|
||||||
|
}))(ProfileArbitrated);
|
|
@ -26,6 +26,7 @@ import ContributionModal from 'components/ContributionModal';
|
||||||
import LinkableTabs from 'components/LinkableTabs';
|
import LinkableTabs from 'components/LinkableTabs';
|
||||||
import './style.less';
|
import './style.less';
|
||||||
import { UserContribution } from 'types';
|
import { UserContribution } from 'types';
|
||||||
|
import ProfileArbitrated from './ProfileArbitrated';
|
||||||
|
|
||||||
interface StateProps {
|
interface StateProps {
|
||||||
usersMap: AppState['users']['map'];
|
usersMap: AppState['users']['map'];
|
||||||
|
@ -86,11 +87,19 @@ class Profile extends React.Component<Props, State> {
|
||||||
return <ExceptionPage code="404" desc="No user could be found" />;
|
return <ExceptionPage code="404" desc="No user could be found" />;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { proposals, pendingProposals, contributions, comments, invites } = user;
|
const {
|
||||||
|
proposals,
|
||||||
|
pendingProposals,
|
||||||
|
contributions,
|
||||||
|
comments,
|
||||||
|
invites,
|
||||||
|
arbitrated,
|
||||||
|
} = user;
|
||||||
const nonePending = pendingProposals.length === 0;
|
const nonePending = pendingProposals.length === 0;
|
||||||
const noneCreated = proposals.length === 0;
|
const noneCreated = proposals.length === 0;
|
||||||
const noneFunded = contributions.length === 0;
|
const noneFunded = contributions.length === 0;
|
||||||
const noneCommented = comments.length === 0;
|
const noneCommented = comments.length === 0;
|
||||||
|
const noneArbitrated = arbitrated.length === 0;
|
||||||
const noneInvites = user.hasFetchedInvites && invites.length === 0;
|
const noneInvites = user.hasFetchedInvites && invites.length === 0;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -185,6 +194,22 @@ class Profile extends React.Component<Props, State> {
|
||||||
</div>
|
</div>
|
||||||
</Tabs.TabPane>
|
</Tabs.TabPane>
|
||||||
)}
|
)}
|
||||||
|
{isAuthedUser && (
|
||||||
|
<Tabs.TabPane
|
||||||
|
tab={TabTitle('Arbitrations', arbitrated.length)}
|
||||||
|
key="arbitrations"
|
||||||
|
>
|
||||||
|
{noneArbitrated && (
|
||||||
|
<Placeholder
|
||||||
|
title="No arbitrations"
|
||||||
|
subtitle="You are not an arbiter of any proposals"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{arbitrated.map(arb => (
|
||||||
|
<ProfileArbitrated key={arb.proposalId} proposal={arb} />
|
||||||
|
))}
|
||||||
|
</Tabs.TabPane>
|
||||||
|
)}
|
||||||
</LinkableTabs>
|
</LinkableTabs>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,7 @@ export interface UserState extends User {
|
||||||
isUpdating: boolean;
|
isUpdating: boolean;
|
||||||
updateError: string | null;
|
updateError: string | null;
|
||||||
pendingProposals: UserProposal[];
|
pendingProposals: UserProposal[];
|
||||||
|
arbitrated: UserProposal[];
|
||||||
proposals: UserProposal[];
|
proposals: UserProposal[];
|
||||||
contributions: UserContribution[];
|
contributions: UserContribution[];
|
||||||
comments: UserComment[];
|
comments: UserComment[];
|
||||||
|
@ -51,6 +52,7 @@ export const INITIAL_USER_STATE: UserState = {
|
||||||
isUpdating: false,
|
isUpdating: false,
|
||||||
updateError: null,
|
updateError: null,
|
||||||
pendingProposals: [],
|
pendingProposals: [],
|
||||||
|
arbitrated: [],
|
||||||
proposals: [],
|
proposals: [],
|
||||||
contributions: [],
|
contributions: [],
|
||||||
comments: [],
|
comments: [],
|
||||||
|
|
|
@ -29,6 +29,9 @@ export function formatUserFromGet(user: UserState) {
|
||||||
if (user.pendingProposals) {
|
if (user.pendingProposals) {
|
||||||
user.pendingProposals = user.pendingProposals.map(bnUserProp);
|
user.pendingProposals = user.pendingProposals.map(bnUserProp);
|
||||||
}
|
}
|
||||||
|
if (user.arbitrated) {
|
||||||
|
user.arbitrated = user.arbitrated.map(bnUserProp);
|
||||||
|
}
|
||||||
user.proposals = user.proposals.map(bnUserProp);
|
user.proposals = user.proposals.map(bnUserProp);
|
||||||
user.contributions = user.contributions.map(c => {
|
user.contributions = user.contributions.map(c => {
|
||||||
c.amount = toZat((c.amount as any) as string);
|
c.amount = toZat((c.amount as any) as string);
|
||||||
|
|
Loading…
Reference in New Issue