Skip to content

Commit

Permalink
Merge pull request #235 from 1Hive/stepper
Browse files Browse the repository at this point in the history
Stepper
  • Loading branch information
Corantin committed Apr 20, 2022
2 parents 54b3c36 + f77b05e commit ee48b59
Show file tree
Hide file tree
Showing 22 changed files with 691 additions and 468 deletions.
163 changes: 94 additions & 69 deletions packages/react-app/src/components/claim-list.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Accordion } from '@1hive/1hive-ui';
import { Accordion, Box } from '@1hive/1hive-ui';
import { ClaimModel } from 'src/models/claim.model';
import { useWallet } from 'src/contexts/wallet.context';
import styled from 'styled-components';
Expand All @@ -8,6 +8,7 @@ import { TokenAmountModel } from 'src/models/token-amount.model';
import { QuestModel } from 'src/models/quest.model';
import { useEffect, useState } from 'react';
import { Logger } from 'src/utils/logger';
import { getObjectFromIpfsSafe } from 'src/services/ipfs.service';
import ChallengeModal from './modals/challenge-modal';
import ResolveChallengeModal from './modals/resolve-challenge-modal';
import { ChildSpacer, Outset } from './utils/spacer-util';
Expand Down Expand Up @@ -39,6 +40,11 @@ const HeaderStyled = styled.h1`
margin-left: ${GUpx()};
`;

const BoxStyled = styled(Box)`
display: flex;
justify-content: space-around;
`;

// #endregion

type Props = {
Expand All @@ -55,7 +61,9 @@ export default function ClaimList({
questTotalBounty,
}: Props) {
const { walletAddress } = useWallet();
const [claims, setClaims] = useState<ClaimModel[]>();
const [claims, setClaims] = useState<ClaimModel[]>([
{ state: ENUM_CLAIM_STATE.None } as ClaimModel,
]);

useEffect(() => {
fetchClaims();
Expand All @@ -71,7 +79,17 @@ export default function ClaimList({

const fetchClaims = async () => {
const result = await QuestService.fetchQuestClaims(questData);
setClaims(result);
setClaims(result); // Fetch visible data
setClaims(
await Promise.all(
result.map(async (claim) => ({
...claim,
evidence: claim.evidenceIpfsHash
? await getObjectFromIpfsSafe(claim.evidenceIpfsHash)
: 'No evidence',
})),
),
); // Fetch evidence wich is currently hidden in accordion
return result;
};

Expand All @@ -89,75 +107,82 @@ export default function ClaimList({

return (
<WrapperStyled>
{!!claims?.length && (
<>
<ClaimHeaderStyled>
<HeaderStyled>Claims</HeaderStyled>
<HelpTooltip tooltip="A claim includes the proof of the quest's completion." />
</ClaimHeaderStyled>
<Accordion
items={claims.map((claim: ClaimModel) => {
let actionButton;
if (claim.state === ENUM_CLAIM_STATE.Scheduled) {
if (walletAddress === claim.playerAddress)
actionButton = (
<ExecuteClaimModal
claim={claim}
questTotalBounty={questTotalBounty}
onClose={fetchNewClaimChanges}
/>
);
else
actionButton = (
<ChallengeModal
claim={claim}
challengeDeposit={challengeDeposit}
onClose={fetchNewClaimChanges}
/>
);
} else if (claim.state === ENUM_CLAIM_STATE.Challenged) {
<ClaimHeaderStyled>
<HeaderStyled>Claims</HeaderStyled>
<HelpTooltip tooltip="A claim includes the proof of the quest's completion." />
</ClaimHeaderStyled>
{claims?.length ? (
<Accordion
items={claims.map((claim: ClaimModel) => {
let actionButton;
if (claim.state === ENUM_CLAIM_STATE.Scheduled) {
if (walletAddress === claim.playerAddress)
actionButton = (
<ResolveChallengeModal claim={claim} onClose={fetchNewClaimChanges} />
<ExecuteClaimModal
claim={claim}
questTotalBounty={questTotalBounty}
onClose={fetchNewClaimChanges}
/>
);
} else if (!claim.state) Logger.error(`Claim doesn't have state`, { claim });
return [
<div className="wide">
<Outset>
<ChildSpacer size={16} justify="start" align="center" buttonEnd>
<FieldInput label="Status">
<StateTag state={claim.state ?? ''} className="pl-0" />
</FieldInput>
<AddressFieldInput
id="playerAddress"
value={claim.playerAddress}
label={walletAddress === claim.playerAddress ? 'You' : 'Claiming player'}
/>
{claim.claimedAmount.parsedAmount ? (
<AmountFieldInput
id="amount"
label="Claimed amount"
value={claim.claimedAmount}
/>
) : (
<FieldInput label="Claimed amount">All available</FieldInput>
)}
{walletAddress && actionButton}
</ChildSpacer>
</Outset>
</div>,
<Outset gu8>
<TextFieldInput
id="evidence"
value={claim.evidence}
isMarkDown
wide
label="Evidence of completion"
else
actionButton = (
<ChallengeModal
claim={claim}
challengeDeposit={challengeDeposit}
onClose={fetchNewClaimChanges}
/>
</Outset>,
];
})}
/>
</>
);
} else if (claim.state === ENUM_CLAIM_STATE.Challenged) {
actionButton = <ResolveChallengeModal claim={claim} onClose={fetchNewClaimChanges} />;
} else if (!claim.state) Logger.error(`Claim doesn't have state`, { claim });
return [
<div className="wide">
<Outset>
<ChildSpacer size={16} justify="start" align="center" buttonEnd>
<FieldInput label="Status" isLoading={claim.state === ENUM_CLAIM_STATE.None}>
<StateTag state={claim.state ?? ''} className="pl-0" />
</FieldInput>
<AddressFieldInput
id="playerAddress"
value={claim.playerAddress}
label={walletAddress === claim.playerAddress ? 'You' : 'Claiming player'}
isLoading={!claim.playerAddress}
/>
{claim.claimedAmount?.parsedAmount ? (
<AmountFieldInput
id="amount"
label="Claimed amount"
value={claim.claimedAmount}
/>
) : (
<FieldInput
label="Claimed amount"
isLoading={claim.state === ENUM_CLAIM_STATE.None}
>
All available
</FieldInput>
)}
{walletAddress && actionButton}
</ChildSpacer>
</Outset>
</div>,
<Outset gu8>
<TextFieldInput
id="evidence"
value={claim.evidence}
isMarkDown
wide
label="Evidence of completion"
isLoading={!claim.evidence}
/>
</Outset>,
];
})}
/>
) : (
<BoxStyled>
<i>No claims</i>
</BoxStyled>
)}
</WrapperStyled>
);
Expand Down
11 changes: 8 additions & 3 deletions packages/react-app/src/components/dashboard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ const BoxStyled = styled.div`
const TextStyled = styled.span`
color: ${({ theme }: any) => theme.positive};
font-weight: bold !important;
${textStyle('title3')};
${textStyle('title2')};
`;

const SpacerStyled = styled.div`
Expand Down Expand Up @@ -62,14 +62,19 @@ export default function Dashboard() {
tooltip="Total of the quest bounties converted into USD"
isLoading={!dashboardModel}
>
<TextStyled theme={theme}>$ {dashboardModel?.totalFunds}</TextStyled>
<TextStyled theme={theme}>
{dashboardModel?.totalFunds?.toLocaleString('en-US', {
style: 'currency',
currency: 'USD',
})}
</TextStyled>
</FieldInput>
<FieldInput
label={<LabelStyled>Open Quests</LabelStyled>}
tooltip="All the quests that are currently not expired or closed"
isLoading={!dashboardModel}
>
<TextStyled theme={theme}>{dashboardModel?.questCount}</TextStyled>
<TextStyled theme={theme}>{dashboardModel?.questCount.toLocaleString()}</TextStyled>
</FieldInput>
<SpacerStyled>
{walletAddress && <QuestModal questMode={ENUM_QUEST_VIEW_MODE.Create} />}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ import { FieldInput } from './field-input';
// #region Styled

const TextInputStyled = styled(TextInput)`
border-radius: 8px;
border-radius: 12px;
padding-right: 42px;
`;

const EthIdenticonStyled = styled(EthIdenticon)`
border-radius: 0 8px 8px 0;
border-radius: 0 12px 12px 0;
padding: 0;
`;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import { connect, FormikContextType } from 'formik';
import { noop } from 'lodash-es';
import React, { ReactNode, useEffect, useState, useRef, Fragment } from 'react';
import { NETWORK_TOKENS } from 'src/constants';
import { useWallet } from 'src/contexts/wallet.context';
import { TokenAmountModel } from 'src/models/token-amount.model';
import { TokenModel } from 'src/models/token.model';
import { getNetwork } from 'src/networks';
Expand Down Expand Up @@ -128,7 +127,6 @@ function AmountFieldInput({
const [token, setToken] = useState<TokenModel | undefined>(value?.token);
const [availableTokens, setAvailableTokens] = useState<TokenModel[]>([]);
const [_hasFocused, _setHasFocused] = useState<boolean>();
const { walletAddress } = useWallet();
const tokenInputId = tokenEditable ? id : `token-${id}`; // Handle label for
const amountInputId = !tokenEditable ? id : `amount-${id}`; // Handle label for

Expand All @@ -138,30 +136,28 @@ function AmountFieldInput({
hasFocusedRef.current = data;
_setHasFocused(data);
};

const autoCompleteRef: React.Ref<any> = useRef(null);

useEffect(() => {
fetchAvailableTokens();
}, []);

const handleFocusIn = (e: FocusEvent) => {
if (
document.activeElement === autoCompleteRef.current &&
walletAddress &&
isEdit &&
tokenEditable
) {
if (document.activeElement === autoCompleteRef.current && isEdit && tokenEditable) {
setHasFocused(true);
fetchAvailableTokens();
} else if (document.activeElement !== autoCompleteRef.current && hasFocusedRef.current) {
formik?.setFieldTouched(id, true);
formik?.handleBlur(e);
formik?.handleBlur({ ...e, target: { id, name: id } });
setHasFocused(false);
}
};

useEffect(() => {
if (!token) document.addEventListener('focusin', handleFocusIn);
return () => document.removeEventListener('focusin', handleFocusIn);
}, [walletAddress, isEdit, tokenEditable, token]);
}, [isEdit, tokenEditable, token]);

useEffect(() => {
if (availableTokens.length) {
if (availableTokens.length && _hasFocused) {
if (searchTerm && isAddress(searchTerm)) {
setTokens([]);
getTokenInfo(searchTerm)
Expand All @@ -178,7 +174,7 @@ function AmountFieldInput({
);
}
}
}, [searchTerm, availableTokens]);
}, [searchTerm, availableTokens, _hasFocused]);

useEffect(() => {
if (!isEdit) {
Expand All @@ -203,7 +199,7 @@ function AmountFieldInput({
const onAmountChange = (e: any) => {
const newAmount = e.target.value;
setAmount(newAmount);
if (token && e.target.value !== '') {
if (token && newAmount !== '') {
applyChanges({
token: {
...token,
Expand Down Expand Up @@ -232,7 +228,6 @@ function AmountFieldInput({
if (formik) formik.setFieldValue(id, nextValue);
else onChange(nextValue);
};

const amountField = (
<FieldInput key={`amountField${amountLabel}`} label={amountLabel} wide={wide} compact={compact}>
<AmountTokenWrapperStyled isEdit={isEdit} wide={wide}>
Expand All @@ -244,6 +239,9 @@ function AmountFieldInput({
onChange={onAmountChange}
placeHolder={placeHolder}
onBlur={(e: React.FocusEvent) => {
const el = e.target as HTMLInputElement;
if (el.value === '') el.value = '0';
onAmountChange(e);
formik?.setFieldTouched(id, true);
formik?.handleBlur(e);
}}
Expand Down Expand Up @@ -277,7 +275,7 @@ function AmountFieldInput({
onSelect={onTokenChange}
ref={autoCompleteRef}
onBlur={(e: FocusEvent) => formik?.handleBlur(e)}
placeholder="Search name or paste address"
placeholder={availableTokens.length ? 'Search name or paste address' : 'Loading tokens'}
wide={wide}
renderSelected={(i: number) => (
<Fragment key={tokens[i].token}>{tokens[i].name}</Fragment>
Expand Down Expand Up @@ -312,6 +310,7 @@ function AmountFieldInput({
compact
direction={!!amountLabel || !!tokenLabel ? 'column' : 'row'}
error={error}
className={!isEdit ? 'fit-content' : 'dd'}
>
{reversed ? [tokenField, amountField] : [amountField, tokenField]}
</FieldInput>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useTheme } from '@1hive/1hive-ui';
import { noop } from 'lodash-es';
import { ReactNode } from 'react';
import { FocusEventHandler, ReactNode } from 'react';
import { GUpx } from 'src/utils/style.util';
import styled from 'styled-components';
import { FieldInput } from './field-input';
Expand Down Expand Up @@ -99,6 +99,7 @@ type Props = {
isLoading?: boolean;
label?: string;
onChange?: Function;
handleBlur?: FocusEventHandler<HTMLInputElement>;
value?: boolean;
tooltip?: ReactNode;
compact?: boolean;
Expand All @@ -115,6 +116,7 @@ export default function CheckboxFieldInput({
compact = false,
onChange = noop,
disabled = false,
handleBlur = noop,
}: Props) {
const theme = useTheme();
return (
Expand All @@ -126,6 +128,7 @@ export default function CheckboxFieldInput({
name={id}
value={id}
checked={value}
onBlur={handleBlur}
disabled={disabled || !isEdit}
onChange={(e) => onChange(e)}
/>
Expand Down

1 comment on commit ee48b59

@vercel
Copy link

@vercel vercel bot commented on ee48b59 Apr 20, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

quests – ./

quests-git-main-1hive.vercel.app
quests-1hive.vercel.app
quests.vercel.app

Please sign in to comment.