Skip to content

updated create-pool and implemented bulk addMember#318

Open
iYukay wants to merge 3 commits intoGoodDollar:masterfrom
iYukay:create-pool-flow
Open

updated create-pool and implemented bulk addMember#318
iYukay wants to merge 3 commits intoGoodDollar:masterfrom
iYukay:create-pool-flow

Conversation

@iYukay
Copy link

@iYukay iYukay commented Mar 11, 2026

Title: Create‑pool copy refresh + bulk add members

Summary:

  • Updated create‑pool screens with Figma copy.
  • Added initial members input and bulk add via SDK in create‑pool flow
  • Terms of Use is now clickable

Testing:

  • yarn workspace @gooddollar/goodcollective-contracts compile
  • yarn workspace @gooddollar/goodcollective-sdk build

Summary by Sourcery

Refresh the create-pool flow copy and add support for specifying and bulk-adding initial pool members.

New Features:

  • Allow pool creators to optionally input initial member wallet addresses when configuring a pool.
  • Bulk-add initial pool members to the newly created pool via the GoodCollective SDK.
  • Make the Terms of Use in the welcome screen clickable, including a direct link to the terms URL.

Enhancements:

  • Update welcome and pool type selection copy to match current product messaging and clarify available pool types.
  • Add validation for initial member wallet addresses, including format checks and maximum member count constraints.
  • Adjust pool configuration logic so closed pools are treated as members-only when creating UBI settings.

Copy link

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Hey - I've found 2 issues, and left some high level feedback:

  • In Welcome.tsx, the terms of use are rendered as two separate clickable Text elements with identical onPress handlers; consider consolidating this into a single clearly-labeled touch target to reduce duplication and improve accessibility/UX.
  • The projectId generation in CreatePoolProvider uses replace(' ', '/'), which only replaces the first space; if multiple spaces are expected, consider using a global regex or split/join to normalize the name consistently.
  • In usePoolConfigurationValidation, the comparison members.length > maximumMembers will silently do nothing when maximumMembers is undefined; if this check should only run when a max is explicitly set, consider guarding it with an explicit maximumMembers != null to make the intent clearer.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `Welcome.tsx`, the terms of use are rendered as two separate clickable `Text` elements with identical `onPress` handlers; consider consolidating this into a single clearly-labeled touch target to reduce duplication and improve accessibility/UX.
- The `projectId` generation in `CreatePoolProvider` uses `replace(' ', '/')`, which only replaces the first space; if multiple spaces are expected, consider using a global regex or `split/join` to normalize the name consistently.
- In `usePoolConfigurationValidation`, the comparison `members.length > maximumMembers` will silently do nothing when `maximumMembers` is undefined; if this check should only run when a max is explicitly set, consider guarding it with an explicit `maximumMembers != null` to make the intent clearer.

## Individual Comments

### Comment 1
<location path="packages/app/src/hooks/useCreatePool/CreatePoolContext.tsx" line_range="105-113" />
<code_context>
       return false;
     }

+    const rawRecipients = form.poolRecipients?.trim() ?? '';
+    const memberAddresses = rawRecipients ? parseMemberAddresses(rawRecipients) : [];
+    if (rawRecipients) {
+      const memberError = validateMemberAddresses(memberAddresses);
+      if (memberError) {
+        console.error(memberError);
+        return false;
+      }
+      if (form.maximumMembers && memberAddresses.length > form.maximumMembers) {
+        console.error(`Members count (${memberAddresses.length}) exceeds maximum (${form.maximumMembers}).`);
+        return false;
</code_context>
<issue_to_address>
**suggestion:** Recipient validation logic is duplicated here and in `usePoolConfigurationValidation`, which risks drift.

Parsing and validating recipient addresses (including the `maximumMembers` length check) now happens both in this context and in `usePoolConfigurationValidation`. This duplication makes it easy for rules (regex, formatting, limits) to diverge. Consider centralizing this in a shared utility—building on `parseMemberAddresses`/`validateMemberAddresses`—and having both the hook and context call the same higher-level validator.

Suggested implementation:

```typescript
    const sdk = new GoodCollectiveSDK(chainIdString, signer.provider as ethers.providers.Provider, { network });

    const validatePoolRecipients = (
      rawRecipients: string | undefined,
      maximumMembers?: number,
    ): {
      isValid: boolean;
      memberAddresses: string[];
      error?: string;
    } => {
      const trimmedRecipients = rawRecipients?.trim() ?? '';

      if (!trimmedRecipients) {
        return { isValid: true, memberAddresses: [] };
      }

      const memberAddresses = parseMemberAddresses(trimmedRecipients);
      const memberError = validateMemberAddresses(memberAddresses);

      if (memberError) {
        return { isValid: false, memberAddresses, error: memberError };
      }

      if (maximumMembers && memberAddresses.length > maximumMembers) {
        return {
          isValid: false,
          memberAddresses,
          error: `Members count (${memberAddresses.length}) exceeds maximum (${maximumMembers}).`,
        };
      }

      return { isValid: true, memberAddresses };
    };

    // Final form validation

```

```typescript
    const recipientsValidation = validatePoolRecipients(form.poolRecipients, form.maximumMembers);

    if (!recipientsValidation.isValid) {
      if (recipientsValidation.error) {
        console.error(recipientsValidation.error);
      }
      return false;
    }

    const { memberAddresses } = recipientsValidation;

```

To fully address the duplication with `usePoolConfigurationValidation`, you should:
1. Move `validatePoolRecipients` into a shared utility module (for example, `packages/app/src/utils/poolRecipients.ts`) so it is not tied to this context.
2. Update this file to import `validatePoolRecipients` from that shared module instead of defining it inline.
3. Update `usePoolConfigurationValidation` to call the shared `validatePoolRecipients` helper (and remove its local recipient parsing/validation logic), ensuring both the hook and this context share the same rules and error messages.
</issue_to_address>

### Comment 2
<location path="packages/app/src/hooks/useCreatePool/CreatePoolContext.tsx" line_range="150-156" />
<code_context>
     // Calculate cycle length based on claim frequency
     const cycleLengthDays = form.claimFrequency && form.claimFrequency <= 7 ? 7 : form.claimFrequency || 1;

+    const onlyMembers = form.joinStatus === 'closed';
     const ubiSettings: UBISettings = {
       claimPeriodDays: ethers.BigNumber.from(form.claimFrequency || 1),
       minActiveUsers: ethers.BigNumber.from(1),
       maxClaimAmount: ethers.utils.parseEther(String(form.claimAmountPerWeek || 0)),
       maxMembers: form.maximumMembers || form.expectedMembers || 100,
-      onlyMembers: form.poolRecipients ? form.canNewMembersJoin ?? false : false,
+      onlyMembers,
       cycleLengthDays: ethers.BigNumber.from(cycleLengthDays),
       claimForEnabled: false,
</code_context>
<issue_to_address>
**question:** Revisiting the `onlyMembers` logic now that it’s based solely on `joinStatus`.

Previously, `onlyMembers` also depended on `form.poolRecipients` being set, but now it’s purely `joinStatus === 'closed'`. With this change, a pool that is `closed` and has no initial members will still have `onlyMembers = true`, which may prevent anyone from ever joining. If that’s not the intended behavior, consider conditioning `onlyMembers` on both `joinStatus` and the presence of initial members, or clearly define and enforce the expected behavior for empty-member pools.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@iYukay
Copy link
Author

iYukay commented Mar 11, 2026

Hi @L03TJ3 , I just made a video walkthrough showing the functional fixes
Video Demo

@iYukay iYukay deployed to external March 11, 2026 21:48 — with GitHub Actions Active
@L03TJ3 L03TJ3 linked an issue Mar 13, 2026 that may be closed by this pull request
3 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Update: Create a UBI Pool

1 participant