zcash-grant-system/admin/src/components/ArbiterControl/index.tsx

169 lines
5.0 KiB
TypeScript
Raw Normal View History

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() {
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"
loading={store.arbiterSaving}
2019-02-06 10:38:07 -08:00
icon="crown"
type="primary"
onClick={this.handleShowSearch}
{...this.props.buttonProps}
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();
await store.setArbiter(this.props.proposalId, user.userid);
if (store.arbiterSaved) {
2019-02-06 10:38:07 -08:00
message.success(
<>
<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;