Skip to content

Commit

Permalink
Move rewards step above credentials (#4818)
Browse files Browse the repository at this point in the history
* Moved rewards step above credentials

* Move rewards above credentials

* Update getCurrentStep.ts

* Update getCurrentStep.ts

* fix settings ui

---------

Co-authored-by: mattcasey <mattwad@gmail.com>
  • Loading branch information
Devorein and mattcasey authored Oct 16, 2024
1 parent 6989471 commit 1c08001
Show file tree
Hide file tree
Showing 13 changed files with 119 additions and 120 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -88,18 +88,18 @@ export function IssueProposalCredentials({
!space?.useOnchainCredentials || !space.credentialsChainId || !space.credentialsWallet
? 'A space admin must set up onchain credentials to use this functionality'
: publishingCredential
? 'Issuing credentials...'
: !issuableProposalCredentials?.length
? 'No onchain credentials to issue'
: !account || !signer
? 'Unlock your wallet to issue credentials'
: !userWalletCanIssueCredentialsForSpace
? gnosisSafeForCredentials
? `You must be connected as one of the owners of the ${gnosisSafeForCredentials.address} Gnosis Safe on ${
getChainById(space?.credentialsChainId)?.chainName
}`
: `You must be connected with wallet ${space?.credentialsWallet} to issue credentials`
: undefined;
? 'Issuing credentials...'
: !issuableProposalCredentials?.length
? 'No onchain credentials to issue'
: !account || !signer
? 'Unlock your wallet to issue credentials'
: !userWalletCanIssueCredentialsForSpace
? gnosisSafeForCredentials
? `You must be connected as one of the owners of the ${gnosisSafeForCredentials.address} Gnosis Safe on ${
getChainById(space?.credentialsChainId)?.chainName
}`
: `You must be connected with wallet ${space?.credentialsWallet} to issue credentials`
: undefined;

async function _handleIssueCredentials() {
if (!space?.credentialsChainId) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,16 +119,16 @@ export function EvaluationsReview({
[proposalTemplates]
);

const isCredentialsComplete =
hasCredentialsStep && currentEvaluation?.result === 'pass' && !hasPendingOnchainCredentials;
const isCredentialsActive =
hasCredentialsStep && currentEvaluation?.result === 'pass' && (!isCredentialsComplete || !hasRewardsStep);
const isCredentialsActive = hasCredentialsStep && currentEvaluation?.result === 'pass' && isRewardsComplete;

const isCredentialsComplete = isCredentialsActive && !hasPendingOnchainCredentials;

const shareLink = getAbsolutePath(pagePath || '', currentSpace?.domain);
const shareText = `${pageTitle || 'Untitled'} from ${currentSpace?.name} is now open for feedback.\n`;
const { user } = useUser();
const isRewardsActive =
hasRewardsStep && currentEvaluation?.result === 'pass' && (!hasCredentialsStep || !!isCredentialsComplete);
hasRewardsStep && currentEvaluation?.result === 'pass' && !isCredentialsActive && !isCredentialsComplete;

// To find the previous step index. we have to calculate the position including Draft and Rewards steps
let adjustedCurrentEvaluationIndex = 0; // "draft" step
if (proposal && currentEvaluation) {
Expand Down Expand Up @@ -186,12 +186,12 @@ export function EvaluationsReview({
const disabledPublishTooltip = !proposal?.permissions.evaluate
? `Only reviewers can publish ${lowercaseRewardsTitle}`
: proposal?.archived
? `Cannot publish ${lowercaseRewardsTitle} for an archived proposal`
: !isRewardsActive
? `Proposal must be in ${lowercaseRewardsTitle} step to publish ${lowercaseRewardsTitle}`
: isRewardsComplete
? `${capitalisedRewardsTitle} step is already complete`
: null;
? `Cannot publish ${lowercaseRewardsTitle} for an archived proposal`
: !isRewardsActive
? `Proposal must be in ${lowercaseRewardsTitle} step to publish ${lowercaseRewardsTitle}`
: isRewardsComplete
? `${capitalisedRewardsTitle} step is already complete`
: null;

return (
<LoadingComponent isLoading={!proposal}>
Expand Down Expand Up @@ -315,13 +315,34 @@ export function EvaluationsReview({
</EvaluationStepRow>
);
})}
{hasRewardsStep && (
<EvaluationStepRow
expanded={expandedEvaluationId === 'rewards'}
expandedContainer={expandedContainer}
isCurrent={isRewardsActive}
onChange={(e, expand) => setExpandedEvaluationId(expand ? 'rewards' : undefined)}
index={proposal ? proposal.evaluations.length + 1 : 0}
result={isRewardsComplete ? 'pass' : null}
title={rewardsTitle}
>
<RewardReviewStep
disabledPublishTooltip={disabledPublishTooltip}
proposalId={proposal?.id}
pendingRewards={pendingRewards}
rewardIds={proposal?.rewardIds}
onSubmit={refreshProposal}
makeRewardsPublic={!!proposal?.fields?.makeRewardsPublic}
togglePublicRewards={(value) => onChangeRewardSettings?.({ makeRewardsPublic: !!value })}
/>
</EvaluationStepRow>
)}
{hasCredentialsStep && (
<EvaluationStepRow
expanded={expandedEvaluationId === 'credentials'}
expandedContainer={expandedContainer}
isCurrent={isCredentialsActive}
onChange={(e, expand) => setExpandedEvaluationId(expand ? 'credentials' : undefined)}
index={proposal ? proposal.evaluations.length + 1 : 0}
index={proposal ? proposal.evaluations.length + (hasRewardsStep ? 2 : 1) : 0}
result={isCredentialsComplete ? 'pass' : null}
title='Credentials'
actions={
Expand All @@ -338,27 +359,6 @@ export function EvaluationsReview({
/>
</EvaluationStepRow>
)}
{hasRewardsStep && (
<EvaluationStepRow
expanded={expandedEvaluationId === 'rewards'}
expandedContainer={expandedContainer}
isCurrent={isRewardsActive}
onChange={(e, expand) => setExpandedEvaluationId(expand ? 'rewards' : undefined)}
index={proposal ? proposal.evaluations.length + (hasCredentialsStep ? 2 : 1) : 0}
result={isRewardsComplete ? 'pass' : null}
title={rewardsTitle}
>
<RewardReviewStep
disabledPublishTooltip={disabledPublishTooltip}
proposalId={proposal?.id}
pendingRewards={pendingRewards}
rewardIds={proposal?.rewardIds}
onSubmit={refreshProposal}
makeRewardsPublic={!!proposal?.fields?.makeRewardsPublic}
togglePublicRewards={(value) => onChangeRewardSettings?.({ makeRewardsPublic: !!value })}
/>
</EvaluationStepRow>
)}
{pagePath && pageId && pageTitle && proposal && expandedContainer && proposal?.isPublic && (
<>
<Divider />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ export function RewardReviewStep({
const disabledTogglePublicTooltip = rewards.length
? 'Rewards are already published for this proposal'
: !isAdmin
? 'Only admins can change public reward settings'
: null;
? 'Only admins can change public reward settings'
: null;

async function createRewards() {
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -162,36 +162,36 @@ export function EvaluationsSettings({
</EvaluationStepSettingsRow>
);
})}
{showCredentials && (
<Box mb={showRewards ? 0 : 8}>
{/* reward settings */}
{showRewards && (
<Box mb={showCredentials ? 0 : 8}>
<EvaluationStepSettingsRow
key={String(expandedSidebar)}
expandedSidebar={expandedSidebar}
index={proposal ? proposal.evaluations.length + 1 : 0}
title='Credentials'
title={mappedFeatures.rewards.title}
expanded={expanded}
>
<ProposalCredentialSettings
readOnly={readOnlyCredentials}
selectedCredentialTemplates={proposal.selectedCredentialTemplates ?? []}
setSelectedCredentialTemplates={onChangeSelectedCredentialTemplates}
/>
{(proposal.fields?.enableRewards || !isStructuredProposal) && (
<RewardSettings value={proposal.fields} onChange={onChangeRewardSettings} />
)}
</EvaluationStepSettingsRow>
</Box>
)}
{/* reward settings */}
{showRewards && (
{showCredentials && (
<Box mb={8}>
<EvaluationStepSettingsRow
key={String(expandedSidebar)}
expandedSidebar={expandedSidebar}
index={proposal ? proposal.evaluations.length + (showCredentials ? 2 : 1) : 0}
title={mappedFeatures.rewards.title}
index={proposal ? proposal.evaluations.length + (showRewards ? 2 : 1) : 0}
title='Credentials'
expanded={expanded}
>
{(proposal.fields?.enableRewards || !isStructuredProposal) && (
<RewardSettings value={proposal.fields} onChange={onChangeRewardSettings} />
)}
<ProposalCredentialSettings
readOnly={readOnlyCredentials}
selectedCredentialTemplates={proposal.selectedCredentialTemplates ?? []}
setSelectedCredentialTemplates={onChangeSelectedCredentialTemplates}
/>
</EvaluationStepSettingsRow>
</Box>
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -157,8 +157,8 @@ export function EvaluationStepSettings({
{evaluation.type === 'vote'
? 'Voters'
: requiredReviews !== 1
? `Reviewers (required ${requiredReviews})`
: 'Reviewers'}
? `Reviewers (required ${requiredReviews})`
: 'Reviewers'}
</Typography>
</FormLabel>
<Typography variant='caption'>Who can evaluate the proposal during this step</Typography>
Expand Down
28 changes: 14 additions & 14 deletions components/proposals/components/ProposalStatusSelect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,8 @@ function ProposalStatusSelectBase({
currentEvaluationStep === 'rewards'
? `${rewardLabel} ${statusLabel}`
: currentEvaluationStep === 'credentials'
? `Credentials ${statusLabel}`
: statusLabel;
? `Credentials ${statusLabel}`
: statusLabel;

return {
id: status,
Expand Down Expand Up @@ -145,25 +145,25 @@ function ProposalStatusSelectBase({
proposal.archived
? 'archived'
: hasPublishedRewards
? getProposalEvaluationStatus({
result: 'pass',
step: 'rewards'
})
: proposal
? getProposalEvaluationStatus({
result: proposal.currentStep.result ?? 'in_progress',
step: proposal.currentStep.step
})
: 'in_progress'
? getProposalEvaluationStatus({
result: 'pass',
step: 'rewards'
})
: proposal
? getProposalEvaluationStatus({
result: proposal.currentStep.result ?? 'in_progress',
step: proposal.currentStep.step
})
: 'in_progress'
}
disableClearable
onChange={(status) => {
onChange(
status === 'complete' || status === 'passed' || status === 'published'
? 'pass'
: status === 'declined' || status === 'unpublished'
? 'fail'
: null
? 'fail'
: null
);
}}
/>
Expand Down
2 changes: 1 addition & 1 deletion components/proposals/hooks/useProposalCredentials.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ export function useMultiProposalCredentials({ proposalIds }: { proposalIds?: str
proposalId: ic.proposalId,
credentialTemplateId: ic.credentialTemplateId,
recipientAddress: ic.recipientAddress
} as PartialIssuableProposalCredentialContent)
}) as PartialIssuableProposalCredentialContent
),
type: 'proposal'
});
Expand Down
25 changes: 14 additions & 11 deletions lib/credentials/findIssuableProposalCredentials.ts
Original file line number Diff line number Diff line change
Expand Up @@ -268,20 +268,23 @@ export async function findSpaceIssuableProposalCredentials({
}
});

const pendingProposalsInSafe = pendingSafeTransactions.reduce((acc, pendingTx) => {
for (const proposalId of pendingTx.proposalIds) {
const pendingProposalCredentials =
(pendingTx as TypedPendingGnosisSafeTransaction<'proposal'>).credentialContent?.[proposalId] ?? [];
const pendingProposalsInSafe = pendingSafeTransactions.reduce(
(acc, pendingTx) => {
for (const proposalId of pendingTx.proposalIds) {
const pendingProposalCredentials =
(pendingTx as TypedPendingGnosisSafeTransaction<'proposal'>).credentialContent?.[proposalId] ?? [];

if (!acc[proposalId]) {
acc[proposalId] = [];
}

if (!acc[proposalId]) {
acc[proposalId] = [];
acc[proposalId].push(...pendingProposalCredentials);
}

acc[proposalId].push(...pendingProposalCredentials);
}

return acc;
}, {} as Record<string, PartialIssuableProposalCredentialContent[]>);
return acc;
},
{} as Record<string, PartialIssuableProposalCredentialContent[]>
);

return proposals
.map((p) =>
Expand Down
6 changes: 6 additions & 0 deletions lib/proposals/createRewardsForProposal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { publishProposalEventBase } from '@root/lib/webhookPublisher/publishEven
import { relay } from '@root/lib/websockets/relay';
import { uniqBy } from 'lodash';

import { issueOffchainProposalCredentialsIfNecessary } from '../credentials/issueOffchainProposalCredentialsIfNecessary';
import { permissionsApiClient } from '../permissions/api/client';

export async function createRewardsForProposal({ proposalId, userId }: { userId: string; proposalId: string }) {
Expand Down Expand Up @@ -194,5 +195,10 @@ export async function createRewardsForProposal({ proposalId, userId }: { userId:
});
}

await issueOffchainProposalCredentialsIfNecessary({
event: 'proposal_approved',
proposalId
});

return updatedProposal;
}
24 changes: 12 additions & 12 deletions lib/proposals/getCurrentStep.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,13 @@ export function getCurrentStep({

const proposalEvaluationStepsCompleted =
currentEvaluation.id === lastEvaluation?.id && lastEvaluation?.result === 'pass';

if (proposalEvaluationStepsCompleted && (hasPendingCredentials || (credentialsEnabled && !hasRewards))) {
// show Rewards step if the are pending, or if they are published and there are no credentials to publish
if (proposalEvaluationStepsCompleted && (hasPendingRewards || (hasPublishedRewards && !credentialsEnabled))) {
return {
title: 'Credentials',
step: 'credentials' as ProposalEvaluationStep,
result: !hasPendingCredentials ? ProposalEvaluationResult.pass : 'in_progress',
id: 'credentials',
title: 'Rewards',
step: 'rewards' as ProposalEvaluationStep,
result: hasPublishedRewards ? ProposalEvaluationResult.pass : 'in_progress',
id: 'rewards',
// Add 1 with total evaluations so that draft step is also included
index: evaluations.length + 1,
requiredReviews: 1,
Expand All @@ -65,14 +65,14 @@ export function getCurrentStep({
};
}

if (proposalEvaluationStepsCompleted && hasRewards) {
if (proposalEvaluationStepsCompleted && (hasPendingCredentials || credentialsEnabled)) {
return {
title: 'Rewards',
step: 'rewards' as ProposalEvaluationStep,
result: hasPublishedRewards ? ProposalEvaluationResult.pass : 'in_progress',
id: 'rewards',
title: 'Credentials',
step: 'credentials' as ProposalEvaluationStep,
result: !hasPendingCredentials ? ProposalEvaluationResult.pass : 'in_progress',
id: 'credentials',
// Add 1 with total evaluations so that draft step is also included
index: evaluations.length + (credentialsEnabled ? 2 : 1),
index: evaluations.length + (hasRewards ? 2 : 1),
requiredReviews: 1,
finalStep: null,
appealedAt: null,
Expand Down
16 changes: 8 additions & 8 deletions lib/proposals/getUserProposals.ts
Original file line number Diff line number Diff line change
Expand Up @@ -418,14 +418,14 @@ export async function getUserProposals({
currentEvaluation: !canSeeEvaluationDetails
? undefined
: currentEvaluation
? {
id: currentEvaluation.id,
type: currentEvaluation.type,
dueDate: currentEvaluation.dueDate || null,
title: currentEvaluation.title,
result: currentEvaluation.result || null
}
: undefined,
? {
id: currentEvaluation.id,
type: currentEvaluation.type,
dueDate: currentEvaluation.dueDate || null,
title: currentEvaluation.title,
result: currentEvaluation.result || null
}
: undefined,
updatedAt: proposal.page.updatedAt,
path: proposal.page.path,
status: proposal.status,
Expand Down
Loading

0 comments on commit 1c08001

Please sign in to comment.