Skip to content

Commit 8ff7435

Browse files
committed
feat: add edit to payment builder action
fixes after rebase fix: translations, table borders Fix: Editing expenditure to not change slot IDs or override recipients Chore: Add comments with guidance on edit expenditure implementation Update ingestor image hash fix: table styles fix: remove unused prop CR fixes fixes after rebase fix: edit changes
1 parent 5b6e61a commit 8ff7435

File tree

41 files changed

+2370
-375
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+2370
-375
lines changed

src/components/v5/common/ActionSidebar/ActionSidebar.tsx

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ const ActionSidebar: FC<PropsWithChildren<ActionSidebarProps>> = ({
6363
} = useGetActionData(transactionId);
6464

6565
const {
66+
isEditMode,
6667
actionSidebarToggle: [
6768
isActionSidebarOpen,
6869
{ toggle: toggleActionSidebarOff, registerContainerRef },
@@ -210,7 +211,7 @@ const ActionSidebar: FC<PropsWithChildren<ActionSidebarProps>> = ({
210211
ref={registerContainerRef}
211212
>
212213
<div className="relative">
213-
<div className="flex w-full items-center justify-between border-b border-gray-200 px-6 py-4">
214+
<div className="flex w-full items-center justify-between px-6 py-4">
214215
<div className="flex items-center gap-2">
215216
<button
216217
type="button"
@@ -251,6 +252,7 @@ const ActionSidebar: FC<PropsWithChildren<ActionSidebarProps>> = ({
251252
!isMotion &&
252253
!isMultiSig &&
253254
!expenditure &&
255+
!isEditMode &&
254256
!loadingExpenditure && (
255257
<PillsBase
256258
className="bg-success-100 text-success-400"
@@ -265,13 +267,28 @@ const ActionSidebar: FC<PropsWithChildren<ActionSidebarProps>> = ({
265267
withAdditionalStatuses
266268
/>
267269
)}
268-
{(!!(
269-
isMotion && action?.motionData?.motionStateHistory.endedAt
270-
) ||
271-
!!isMultiSig) &&
272-
motionState && (
273-
<MotionOutcomeBadge motionState={motionState} />
274-
)}
270+
{(!!isMotion || !!isMultiSig) && motionState && (
271+
<MotionOutcomeBadge motionState={motionState} />
272+
)}
273+
{!!expenditure && isEditMode && (
274+
<Tooltip
275+
tooltipContent={
276+
<span className="font-medium">
277+
{formatText({
278+
id: 'expenditure.edit.tooltip',
279+
})}
280+
</span>
281+
}
282+
placement="bottom-start"
283+
>
284+
<PillsBase
285+
className="bg-warning-100 text-warning-400"
286+
isCapitalized={false}
287+
>
288+
{formatText({ id: 'badge.edit' })}
289+
</PillsBase>
290+
</Tooltip>
291+
)}
275292
</div>
276293
)}
277294
{isMobile && getShareButton()}

src/components/v5/common/ActionSidebar/partials/Motions/Motions.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -342,7 +342,7 @@ const Motions: FC<MotionsProps> = ({ transactionId }) => {
342342
>
343343
<Stepper<Steps>
344344
activeStepKey={activeStepKey}
345-
setActiveStepKey={setActiveStepKey}
345+
setActiveStepKey={(key: Steps) => setActiveStepKey(key)}
346346
items={items}
347347
/>
348348
</MotionProvider>

src/components/v5/common/ActionSidebar/partials/MultiSigSidebar/partials/MultiSigWidget/MultiSigWidget.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ const MultiSigWidget: FC<MultiSigWidgetProps> = ({
155155
<Stepper<MultiSigState>
156156
items={items}
157157
activeStepKey={activeStepKey}
158-
setActiveStepKey={setActiveStepKey}
158+
setActiveStepKey={(key: MultiSigState) => setActiveStepKey(key)}
159159
/>
160160
);
161161
}

src/components/v5/common/ActionSidebar/partials/forms/PaymentBuilderForm/hooks.ts

Lines changed: 114 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,117 @@ import {
2828
getPaymentBuilderPayload,
2929
} from './utils.ts';
3030

31+
export const useGetPaymentsValidationSchema = () => {
32+
const { colony } = useColonyContext();
33+
const tokenLockStatesMap = useTokenLockStates();
34+
35+
return useMemo(
36+
() =>
37+
array()
38+
.of(
39+
object()
40+
.shape({
41+
recipient: string()
42+
.required(({ path }) => {
43+
const index = getLastIndexFromPath(path);
44+
if (index === undefined) {
45+
return formatText({ id: 'errors.recipient.required' });
46+
}
47+
return formatText(
48+
{ id: 'errors.recipient.requiredIn' },
49+
{ paymentIndex: index + 1 },
50+
);
51+
})
52+
.address(),
53+
slotId: number(),
54+
amount: string()
55+
.required(formatText({ id: 'errors.amount' }))
56+
.test(
57+
'more-than-zero',
58+
({ path }) => {
59+
const index = getLastIndexFromPath(path);
60+
if (index === undefined) {
61+
return formatText({
62+
id: 'errors.amount.greaterThanZero',
63+
});
64+
}
65+
return formatText(
66+
{ id: 'errors.amount.greaterThanZeroIn' },
67+
{ paymentIndex: index + 1 },
68+
);
69+
},
70+
(value, context) =>
71+
amountGreaterThanZeroValidation({
72+
value,
73+
context,
74+
colony,
75+
}),
76+
)
77+
.test('tokens-sum-exceeded', '', (value, context) =>
78+
allTokensAmountValidation({
79+
value,
80+
context,
81+
colony,
82+
}),
83+
),
84+
tokenAddress: string()
85+
.required()
86+
.test(
87+
'token-unlocked',
88+
formatText({ id: 'errors.amount.tokenIsLocked' }) || '',
89+
(value) =>
90+
!shouldPreventPaymentsWithTokenInColony(
91+
value || '',
92+
colony,
93+
tokenLockStatesMap,
94+
),
95+
),
96+
delay: string()
97+
.test(
98+
'is-bigger-than-max',
99+
({ path }) => {
100+
const index = getLastIndexFromPath(path);
101+
102+
return formatText(
103+
{ id: 'errors.delay.max' },
104+
{
105+
paymentIndex: index === undefined ? 1 : index + 1,
106+
max: CLAIM_DELAY_MAX_VALUE,
107+
},
108+
);
109+
},
110+
(value) => {
111+
if (!value) {
112+
return true;
113+
}
114+
115+
const unformattedValue = unformatNumeral(value);
116+
117+
return BigNumber.from(moveDecimal(unformattedValue, 4)).lte(
118+
moveDecimal(CLAIM_DELAY_MAX_VALUE, 4),
119+
);
120+
},
121+
)
122+
.required(({ path }) => {
123+
const index = getLastIndexFromPath(path);
124+
if (index === undefined) {
125+
return formatText({ id: 'errors.delay.empty' });
126+
}
127+
return formatText(
128+
{ id: 'errors.delay.emptyIndex' },
129+
{ paymentIndex: index + 1 },
130+
);
131+
}),
132+
})
133+
.defined()
134+
.required(),
135+
)
136+
.defined()
137+
.required(),
138+
[colony, tokenLockStatesMap],
139+
);
140+
};
141+
31142
export const useValidationSchema = () => {
32143
const { colony } = useColonyContext();
33144
const colonyTokens = useMemo(
@@ -37,7 +148,7 @@ export const useValidationSchema = () => {
37148
.map((colonyToken) => colonyToken.token) || [],
38149
[colony.tokens?.items],
39150
);
40-
const tokenLockStatesMap = useTokenLockStates();
151+
const paymentsValidation = useGetPaymentsValidationSchema();
41152

42153
return useMemo(
43154
() =>
@@ -53,106 +164,7 @@ export const useValidationSchema = () => {
53164
),
54165
decisionMethod: string().defined(),
55166
createdIn: number().defined(),
56-
payments: array()
57-
.of(
58-
object()
59-
.shape({
60-
recipient: string()
61-
.required(({ path }) => {
62-
const index = getLastIndexFromPath(path);
63-
if (index === undefined) {
64-
return formatText({ id: 'errors.recipient.required' });
65-
}
66-
return formatText(
67-
{ id: 'errors.recipient.requiredIn' },
68-
{ paymentIndex: index + 1 },
69-
);
70-
})
71-
.address(),
72-
amount: string()
73-
.required(formatText({ id: 'errors.amount' }))
74-
.test(
75-
'more-than-zero',
76-
({ path }) => {
77-
const index = getLastIndexFromPath(path);
78-
if (index === undefined) {
79-
return formatText({
80-
id: 'errors.amount.greaterThanZero',
81-
});
82-
}
83-
return formatText(
84-
{ id: 'errors.amount.greaterThanZeroIn' },
85-
{ paymentIndex: index + 1 },
86-
);
87-
},
88-
(value, context) =>
89-
amountGreaterThanZeroValidation({
90-
value,
91-
context,
92-
colony,
93-
}),
94-
)
95-
.test('tokens-sum-exceeded', '', (value, context) =>
96-
allTokensAmountValidation({
97-
value,
98-
context,
99-
colony,
100-
}),
101-
),
102-
tokenAddress: string()
103-
.required()
104-
.test(
105-
'token-unlocked',
106-
formatText({ id: 'errors.amount.tokenIsLocked' }) || '',
107-
(value) =>
108-
!shouldPreventPaymentsWithTokenInColony(
109-
value || '',
110-
colony,
111-
tokenLockStatesMap,
112-
),
113-
),
114-
delay: string()
115-
.test(
116-
'is-bigger-than-max',
117-
({ path }) => {
118-
const index = getLastIndexFromPath(path);
119-
120-
return formatText(
121-
{ id: 'errors.delay.max' },
122-
{
123-
paymentIndex: index === undefined ? 1 : index + 1,
124-
max: CLAIM_DELAY_MAX_VALUE,
125-
},
126-
);
127-
},
128-
(value) => {
129-
if (!value) {
130-
return true;
131-
}
132-
133-
const unformattedValue = unformatNumeral(value);
134-
135-
return BigNumber.from(
136-
moveDecimal(unformattedValue, 4),
137-
).lte(moveDecimal(CLAIM_DELAY_MAX_VALUE, 4));
138-
},
139-
)
140-
.required(({ path }) => {
141-
const index = getLastIndexFromPath(path);
142-
if (index === undefined) {
143-
return formatText({ id: 'errors.delay.empty' });
144-
}
145-
return formatText(
146-
{ id: 'errors.delay.emptyIndex' },
147-
{ paymentIndex: index + 1 },
148-
);
149-
}),
150-
})
151-
.defined()
152-
.required(),
153-
)
154-
.defined()
155-
.required(),
167+
payments: paymentsValidation,
156168
})
157169
.test(
158170
'is-in-colony',
@@ -174,7 +186,7 @@ export const useValidationSchema = () => {
174186
)
175187
.defined()
176188
.concat(ACTION_BASE_VALIDATION_SCHEMA),
177-
[colony, colonyTokens, tokenLockStatesMap],
189+
[colonyTokens, paymentsValidation],
178190
);
179191
};
180192

src/components/v5/common/ActionSidebar/partials/forms/PaymentBuilderForm/partials/PaymentBuilderRecipientsField/PaymentBuilderRecipientsField.tsx

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,8 @@ const PaymentBuilderRecipientsField: FC<PaymentBuilderRecipientsFieldProps> = ({
8484
const isMobile = useMobile();
8585
const getMenuProps = ({ index }) => ({
8686
cardClassName: 'sm:min-w-[9.625rem]',
87+
contentWrapperClassName:
88+
'!left-6 right-6 !z-[65] sm:!left-auto sm:!right-0',
8789
items: [
8890
{
8991
key: 'add-token',
@@ -140,6 +142,12 @@ const PaymentBuilderRecipientsField: FC<PaymentBuilderRecipientsFieldProps> = ({
140142
item.tokenAddress === nativeToken?.tokenAddress,
141143
);
142144

145+
const latestSlotId = value.sort((a, b) => {
146+
if (!a.slotId || !b.slotId) return 0;
147+
148+
return b.slotId - a.slotId;
149+
})[0]?.slotId;
150+
143151
return (
144152
<div data-testid="payment-builder-recipients-field">
145153
<h5 className="mb-3 mt-6 text-2">
@@ -160,13 +168,6 @@ const PaymentBuilderRecipientsField: FC<PaymentBuilderRecipientsFieldProps> = ({
160168
columns={columns}
161169
data={data}
162170
layout={isTablet ? 'vertical' : 'horizontal'}
163-
rows={
164-
data.length > 10
165-
? {
166-
virtualizedRowHeight: isTablet ? 46 : 54,
167-
}
168-
: undefined
169-
}
170171
borders={{
171172
visible: true,
172173
type: 'unset',
@@ -204,6 +205,7 @@ const PaymentBuilderRecipientsField: FC<PaymentBuilderRecipientsFieldProps> = ({
204205
amount: '',
205206
tokenAddress: nativeToken?.tokenAddress || '',
206207
delay: '',
208+
slotId: latestSlotId ? latestSlotId + 1 : undefined,
207209
});
208210
}}
209211
disabled={hasNoDecisionMethods || data.length === 400}

src/components/v5/common/ActionSidebar/partials/forms/PaymentBuilderForm/partials/PaymentBuilderRecipientsField/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,5 @@ export interface PaymentBuilderRecipientsFieldModel {
1111
amount?: string;
1212
tokenAddress?: string;
1313
delay?: string;
14+
slotId?: number;
1415
}

src/components/v5/common/ActionSidebar/partials/forms/PaymentBuilderForm/utils.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ export const allTokensAmountValidation = ({
7474
const { from, _tokenSums } = formValues || {};
7575
const { tokenAddress: fieldTokenAddress } = parent || {};
7676

77-
if (!fieldTokenAddress || !from || !_tokenSums) {
77+
if (!fieldTokenAddress || !_tokenSums) {
7878
return false;
7979
}
8080

0 commit comments

Comments
 (0)