2019-02-06 10:38:07 -08:00
|
|
|
import { debounce } from 'lodash';
|
|
|
|
import React from 'react';
|
|
|
|
import { view } from 'react-easy-state';
|
|
|
|
import { Button, Modal, Input, Icon, List, Avatar, message } from 'antd';
|
|
|
|
import store from 'src/store';
|
2019-02-09 19:00:49 -08:00
|
|
|
import { Proposal, User, PROPOSAL_ARBITER_STATUS } from 'src/types';
|
2019-02-06 10:38:07 -08:00
|
|
|
import Search from 'antd/lib/input/Search';
|
|
|
|
import { ButtonProps } from 'antd/lib/button';
|
|
|
|
import './index.less';
|
|
|
|
|
|
|
|
interface OwnProps {
|
|
|
|
buttonProps?: ButtonProps;
|
|
|
|
}
|
|
|
|
|
|
|
|
type Props = OwnProps & Proposal;
|
|
|
|
|
|
|
|
const STATE = {
|
|
|
|
showSearch: false,
|
|
|
|
searching: false,
|
|
|
|
};
|
|
|
|
type State = typeof STATE;
|
|
|
|
|
|
|
|
class ArbiterControlNaked extends React.Component<Props, State> {
|
|
|
|
state = STATE;
|
|
|
|
searchInput: null | Search = null;
|
|
|
|
|
|
|
|
private searchArbiter = debounce(async search => {
|
|
|
|
await store.searchArbiters(search);
|
|
|
|
this.setState({ searching: false });
|
|
|
|
}, 1000);
|
|
|
|
|
|
|
|
render() {
|
2019-10-16 20:43:20 -07:00
|
|
|
const { arbiter, isVersionTwo, acceptedWithFunding } = this.props;
|
2019-02-06 10:38:07 -08:00
|
|
|
const { showSearch, searching } = this.state;
|
|
|
|
const { results, search, error } = store.arbitersSearch;
|
|
|
|
const showEmpty = !results.length && !searching;
|
ZF Grants 2.1 (#496)
* fix ccr pagination defaults
* add ccr admin tests
* add ccr user tests
* checkpoint
* fix tslint
* request changes discussion flow mvp
* admin - add discussion status
* backend - add live drafts
* admin - add live drafts
* frontend - add live drafts
* frontend - add edit discussion proposal
* fix tsc
* include DISCUSSION status in propsal listview
* do not make live draft on admin request changes
* hide live drafts from user proposal draft list
* fix backend tests
* add admin tests
* add user tests
* fix: liking, viewing discussion proposals, admin menu
* admin - update hints for live drafts
* fe - add better messaging when updating a proposal
* be - fix like test
* remove TODO comments
* add new email types
* fix storybook
* add revision tab story
* backend - implement proposal revisions
* frontend - implement proposal revisions
* update revision tab story
* fix lint
* remove set detection
* email proposal followers on revision
* restrict banner to team members only
* misc bug fixes
* update, add backend tests
* add milestone title change to revision history story
* fix milestones display in preview
* allow archived proposals to be queried
* implement archived proposal page
* fix tsc
* implement archived proposal get route
* move styling into less
* remove proposal archive parent id
* handle archived proposal status
* cleanup
* remove contributions, switch to USD, implement quarters
* use Qs to preserve formatting
* handle edit only kyc
* prevent ARCHIVED proposals from being sent to admin
* display latest revision first
* admin - proposal & ccr reject permanently
* backend - proposal & ccr reject permanently
* frontend - proposal & ccr reject permanently
* fix tsc
* use $ in milestone payout email
* introduce custom filters to proposal listview
* hide archive link on first revision
* upgrade packages
* add bech32 implementation
* add z address validation with tests
* fix tslint
* use local address validation
* fix tests, remove blockchain mock gets
* add additional bad addresses
* update briefs to include page break message
* remove contributions routes, menu entry
* disable countribution count admin stats
* remove matching and pretty print in finance
* fix tslint
* separate out rejected permanently proposals
* make removing proposals generic
* allow linked tabs to be ignored
* remove rejected permanently, bugfix
* update preview link to point to rejected tab
* implement rejected permanently tab, add tab message
* refactor variable
* fix tslint
* fix tslint
* send ccr reject permanently email on rejection
* fix preview message
* wire up proposal arbiter and rejected emails
* disable tip jar in proposal and profile
* sync ccr/proposal drafts on create form init
* check invites on submit modal open
* update team invite language
* update team text when edit
* fix ccr rejected permanently tag
* text changes, email preview fix
* display changes requested tag when in discussion with changes requested
* enable social share on open for discussion proposals, update language
* place sort below filter
* derive filter from query string
* use better filter names in query params
* fix tslint
* create snapshot of original proposal on first revision
* clear invites between edits, account for additional changes not tracked in revisions
* update tests
* fix test
* remove print
* SameSite Fixes (#150)
* QA Fixes 2 (#151)
* set filters as query strings on change
* remove rejected permanently tags
* add dollar sign in financials legend
* fix tsc
* Copy Touchups (#152)
* Email Fixes (#155)
* fix ZEC in milestone payout emails
* fix links in rejected permanently CCR/proposal emails
* Poll for Team and Invite Changes in Create Flow (#153)
* poll for team and invite changes in create flow
* fix tslint
Co-authored-by: Daniel Ternyak <dternyak@gmail.com>
* pretty print payouts by quarter (#156)
Co-authored-by: Daniel Ternyak <dternyak@gmail.com>
* Remove Blockchain Module (#154)
* remove blockchain route from backend, remove calls to node
* revert blockchain_get removal
* Add Tags to Proposal Cards (#157)
* add tag to proposals and dynamically set v1 card height
* listen on window resize
* make card height props optional
* set tag in bottom right, remove dynamic card resize, add dynamic tag resize
* cleanup
* cleanup
Co-authored-by: Daniel Ternyak <dternyak@gmail.com>
* Improve Frontend Address Validation (#158)
Co-authored-by: Daniel Ternyak <dternyak@gmail.com>
* Remove blockchain module (#162)
* remove blockchain route from backend, remove calls to node
* revert blockchain_get removal
* Remove Blockchain App (#160)
* remove blockchain app
* remove blockchain app from travis
Co-authored-by: Danny Skubak <skubakdj@gmail.com>
* Proposal Edit Fixes (#161)
* fe - display error if edit creation fails
* be - restrict live draft publish
Co-authored-by: Daniel Ternyak <dternyak@gmail.com>
* Restrict Arbiter Assignment (#159)
Co-authored-by: Daniel Ternyak <dternyak@gmail.com>
* Email Copy updates
* Remove Admin Financials Card
* Hookup 'proposal_approved_without_funding' to admin email example
* bump various package versions
* Update yarn.lock files
* Attach 'proposal_approved_without_funding' to backend example email
* bump package versions
Co-authored-by: Danny Skubak <skubakdj@gmail.com>
2020-04-07 19:56:32 -07:00
|
|
|
const buttonDisabled = isVersionTwo && !acceptedWithFunding;
|
2019-02-09 19:00:49 -08:00
|
|
|
|
|
|
|
const disp = {
|
|
|
|
[PROPOSAL_ARBITER_STATUS.MISSING]: 'Nominate arbiter',
|
|
|
|
[PROPOSAL_ARBITER_STATUS.NOMINATED]: 'Change nomination',
|
|
|
|
[PROPOSAL_ARBITER_STATUS.ACCEPTED]: 'Change arbiter',
|
|
|
|
};
|
|
|
|
|
2019-02-06 10:38:07 -08:00
|
|
|
return (
|
|
|
|
<>
|
|
|
|
{/* CONTROL */}
|
|
|
|
<Button
|
|
|
|
className="ArbiterControl-control"
|
2019-02-15 19:35:25 -08:00
|
|
|
loading={store.arbiterSaving}
|
2019-02-06 10:38:07 -08:00
|
|
|
icon="crown"
|
|
|
|
type="primary"
|
|
|
|
onClick={this.handleShowSearch}
|
|
|
|
{...this.props.buttonProps}
|
2019-10-16 20:43:20 -07:00
|
|
|
disabled={buttonDisabled}
|
2019-02-06 10:38:07 -08:00
|
|
|
>
|
2019-02-09 19:00:49 -08:00
|
|
|
{disp[arbiter.status]}
|
2019-02-06 10:38:07 -08:00
|
|
|
</Button>
|
|
|
|
{/* SEARCH MODAL */}
|
|
|
|
{showSearch && (
|
|
|
|
<Modal
|
|
|
|
title={
|
|
|
|
<>
|
2019-02-09 19:00:49 -08:00
|
|
|
<Icon type="crown" /> Nominate an arbiter
|
2019-02-06 10:38:07 -08:00
|
|
|
</>
|
|
|
|
}
|
|
|
|
visible={true}
|
|
|
|
footer={null}
|
|
|
|
onCancel={this.handleCloseSearch}
|
|
|
|
>
|
|
|
|
<>
|
|
|
|
<Input.Search
|
|
|
|
ref={x => (this.searchInput = x)}
|
|
|
|
placeholder="name or email"
|
|
|
|
onChange={this.handleSearchInputChange}
|
|
|
|
/>
|
|
|
|
{/* EMPTY RESULTS */}
|
|
|
|
{showEmpty && (
|
|
|
|
<div className={`ArbiterControl-results no-results`}>
|
|
|
|
{(!error && (
|
|
|
|
<>
|
|
|
|
no arbiters found {search && ` for "${search}"`}, please type search
|
|
|
|
query
|
|
|
|
</>
|
|
|
|
)) || (
|
|
|
|
<>
|
|
|
|
<Icon type="exclamation-circle" /> {error}
|
|
|
|
</>
|
|
|
|
)}
|
|
|
|
</div>
|
|
|
|
)}
|
|
|
|
{/* RESULTS */}
|
|
|
|
{!showEmpty && (
|
|
|
|
<div className="ArbiterControl-results">
|
|
|
|
<List
|
|
|
|
size="small"
|
|
|
|
loading={searching}
|
|
|
|
bordered
|
|
|
|
dataSource={results}
|
|
|
|
renderItem={(u: User) => (
|
|
|
|
<List.Item
|
|
|
|
actions={[
|
|
|
|
<Button
|
|
|
|
type="primary"
|
|
|
|
key="select"
|
|
|
|
onClick={() => this.handleSelect(u)}
|
|
|
|
>
|
2019-02-09 19:00:49 -08:00
|
|
|
Nominate
|
2019-02-06 10:38:07 -08:00
|
|
|
</Button>,
|
|
|
|
]}
|
|
|
|
>
|
|
|
|
<List.Item.Meta
|
|
|
|
avatar={
|
|
|
|
<Avatar
|
|
|
|
icon="user"
|
|
|
|
src={(u.avatar && u.avatar.imageUrl) || undefined}
|
|
|
|
/>
|
|
|
|
}
|
|
|
|
title={u.displayName}
|
|
|
|
description={u.emailAddress}
|
|
|
|
/>
|
|
|
|
</List.Item>
|
|
|
|
)}
|
|
|
|
/>
|
|
|
|
</div>
|
|
|
|
)}
|
|
|
|
</>
|
|
|
|
</Modal>
|
|
|
|
)}
|
|
|
|
</>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
private handleShowSearch = () => {
|
|
|
|
this.setState({ showSearch: true });
|
|
|
|
// hacky way of waiting for modal to render in before focus
|
|
|
|
setTimeout(() => {
|
|
|
|
if (this.searchInput) this.searchInput.focus();
|
|
|
|
}, 200);
|
|
|
|
};
|
|
|
|
|
|
|
|
private handleSearchInputChange = (ev: React.ChangeEvent<HTMLInputElement>) => {
|
|
|
|
this.setState({ searching: true });
|
|
|
|
const search = ev.currentTarget.value;
|
|
|
|
this.searchArbiter(search);
|
|
|
|
};
|
|
|
|
|
|
|
|
private handleSelect = async (user: User) => {
|
|
|
|
this.setState({ showSearch: false });
|
|
|
|
store.searchArbitersClear();
|
2019-02-15 19:35:25 -08:00
|
|
|
await store.setArbiter(this.props.proposalId, user.userid);
|
|
|
|
if (store.arbiterSaved) {
|
2019-02-06 10:38:07 -08:00
|
|
|
message.success(
|
|
|
|
<>
|
2019-02-15 19:35:25 -08:00
|
|
|
<b>{user.displayName}</b> nominated as arbiter of <b>{this.props.title}</b>
|
2019-02-06 10:38:07 -08:00
|
|
|
</>,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
private handleCloseSearch = () => {
|
|
|
|
this.setState({ showSearch: false });
|
|
|
|
store.searchArbitersClear();
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
const ArbiterControl = view(ArbiterControlNaked);
|
|
|
|
export default ArbiterControl;
|