Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

@TWilson023
Copy link
Collaborator

@TWilson023 TWilson023 commented Sep 2, 2025

Summary by CodeRabbit

  • New Features
    • Added PartnerStack as a supported import source during program setup.
    • Connect PartnerStack using Public Key and Secret Key; the secret key is stored and shown in masked form.
    • Credentials auto-populate in the form after a successful connection.
    • Import validation now accepts PartnerStack alongside Rewardful and Tolt.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 2, 2025

Walkthrough

Adds PartnerStack support to the new program flow: schema gains an optional partnerstack object; action now returns masked credentials; import form accepts watch/setValue to persist returned keys into the parent form; overview validation now treats partnerstack as a valid import source alongside rewardful and tolt.

Changes

Cohort / File(s) Summary
Rewards UI integration
apps/web/app/(ee)/app.dub.co/(new-program)/[slug]/program/new/rewards/form.tsx, apps/web/app/(ee)/app.dub.co/(new-program)/[slug]/program/new/rewards/import-partnerstack-form.tsx
Passes watch/setValue from parent form to ImportPartnerStackForm; form now watches partnerstack and sets it on successful token action; input bindings use returned publicKey/maskedSecretKey.
Backend + schema support for PartnerStack
apps/web/lib/actions/partners/set-partnerstack-token.ts, apps/web/lib/zod/schemas/program-onboarding.ts
Action returns { publicKey, maskedSecretKey } after persisting; schema adds optional partnerstack object with publicKey and maskedSecretKey fields.
Overview page validation
apps/web/app/(ee)/app.dub.co/(new-program)/[slug]/program/new/overview/page-client.tsx
Destructuring includes partnerstack; import-source validity updated to accept rewardful, tolt, or partnerstack for programType === "import".

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor User
  participant RewardsForm as Rewards Form
  participant PSForm as ImportPartnerStackForm
  participant Action as setPartnerStackTokenAction

  User->>PSForm: Enter Public/Secret Keys
  PSForm->>Action: setCredentials(publicKey, secretKey)
  Action-->>PSForm: { publicKey, maskedSecretKey }
  PSForm->>RewardsForm: setValue("partnerstack", { ... })
  PSForm->>RewardsForm: onSuccess()
  note over RewardsForm: Parent form now holds partnerstack data via watch/setValue

  rect rgba(230,245,255,0.6)
  note over RewardsForm: Overview validates import when any of rewardful/tolt/partnerstack present
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Suggested reviewers

  • steven-tey

Poem

A twitch of whiskers, keys now stack,
I bound through forms and never lack—
Masked secrets snug, a gentle hop,
The schema’s pouch a perfect stop.
With import paths now three abreast,
I thump approval: PartnerStack’s blessed. 🥕🐇

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch program-onboarding-partnerstack

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore or @coderabbit ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

placeholder="Secret key"
className="mt-2 max-w-full"
value={secretKey}
value={secretKey || partnerStack?.maskedSecretKey || ""}
Copy link
Contributor

Choose a reason for hiding this comment

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

The secret key input field will display a masked value (like "sk_***") when credentials are already saved, making it confusing for users who expect to see their actual input or a blank field.

View Details
📝 Patch Details
diff --git a/apps/web/app/(ee)/app.dub.co/(new-program)/[slug]/program/new/rewards/import-partnerstack-form.tsx b/apps/web/app/(ee)/app.dub.co/(new-program)/[slug]/program/new/rewards/import-partnerstack-form.tsx
index b38199581..7f534644c 100644
--- a/apps/web/app/(ee)/app.dub.co/(new-program)/[slug]/program/new/rewards/import-partnerstack-form.tsx
+++ b/apps/web/app/(ee)/app.dub.co/(new-program)/[slug]/program/new/rewards/import-partnerstack-form.tsx
@@ -67,7 +67,7 @@ export const ImportPartnerStackForm = ({
           type="password"
           placeholder="Public key"
           className="mt-2 max-w-full"
-          value={publicKey || partnerStack?.publicKey || ""}
+          value={publicKey || ""}
           onChange={(e) => setPublicKey(e.target.value)}
         />
         <div className="mt-2 text-xs font-normal leading-[1.1] text-neutral-600">
@@ -91,7 +91,7 @@ export const ImportPartnerStackForm = ({
           type="password"
           placeholder="Secret key"
           className="mt-2 max-w-full"
-          value={secretKey || partnerStack?.maskedSecretKey || ""}
+          value={secretKey || ""}
           onChange={(e) => setSecretKey(e.target.value)}
         />
       </div>

Analysis

The secret key input field on line 94 uses value={secretKey || partnerStack?.maskedSecretKey || ""}. This means that when PartnerStack credentials have been previously saved, the input will display the masked secret key (e.g., "sk_***") instead of being empty or showing the user's current input.

This creates a poor user experience because:

  1. Users will see asterisks in the input field, which looks like they're seeing the actual secret but is actually just a masked representation
  2. If users try to edit the field, they'll be typing over the masked value rather than entering a fresh secret
  3. The masked value is not useful for editing - users need to enter their actual secret key

The input should either be empty when showing previously saved credentials, or should not show the masked value at all. A better pattern would be:

  • value={secretKey || ""} to only show the current user input
  • Or add conditional logic to show a different UI state when credentials are already saved

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/web/app/(ee)/app.dub.co/(new-program)/[slug]/program/new/rewards/form.tsx (1)

88-97: Clear PartnerStack state when switching to “New program”.
Avoid stale PartnerStack credentials lingering when toggling programType.

   useEffect(() => {
     if (programType === "new") {
       setValue("rewardful", null);
       setValue("tolt", null);
+      setValue("partnerstack", null);
     } else if (programType === "import") {
       setValue("type", null);
       setValue("amount", null);
       setValue("maxDuration", null);
     }
   }, [programType]);
🧹 Nitpick comments (3)
apps/web/app/(ee)/app.dub.co/(new-program)/[slug]/program/new/rewards/form.tsx (1)

226-238: Prevent conflicting state when changing import source.
When the user selects a different import source, clear other provider objects to avoid ambiguity downstream.

                 setSelectedItem={(item: ImportSource) => {
                   if (item) {
                     setValue("importSource", item.id, {
                       shouldDirty: true,
                     });
+                    // Clear previously entered credentials from other sources
+                    setValue("rewardful", null);
+                    setValue("tolt", null);
+                    setValue("partnerstack", null);
                   }
                 }}
apps/web/app/(ee)/app.dub.co/(new-program)/[slug]/program/new/rewards/import-partnerstack-form.tsx (2)

47-58: Allow proceeding with already-saved credentials (better UX).
If partnerstack is already saved in form state, let users continue without re-entering keys.

@@
-  const onSubmit = async () => {
-    if (!workspaceId || !publicKey || !secretKey) {
-      toast.error("Please fill in all required fields.");
-      return;
-    }
-
-    await executeAsync({
-      workspaceId,
-      publicKey,
-      secretKey,
-    });
-  };
+  const hasSavedCredentials = Boolean(
+    partnerStack?.publicKey && partnerStack?.maskedSecretKey,
+  );
+
+  const onSubmit = async () => {
+    if (!workspaceId) {
+      toast.error("Workspace not found.");
+      return;
+    }
+    // If nothing entered but creds already saved, proceed.
+    if (!publicKey && !secretKey && hasSavedCredentials) {
+      onSuccess();
+      return;
+    }
+    if (!publicKey || !secretKey) {
+      toast.error("Please fill in all required fields.");
+      return;
+    }
+    await executeAsync({ workspaceId, publicKey, secretKey });
+  };
@@
-      <Button
+      <Button
         text="Continue"
         className="w-full"
-        disabled={!publicKey || !secretKey}
+        disabled={(!publicKey || !secretKey) && !hasSavedCredentials}
         loading={isSettingPartnerStackToken || isPending}
         onClick={onSubmit}
       />

Also applies to: 99-105


70-71: Avoid pre-filling password fields with masked values.
Pre-populating password inputs with masked secrets is confusing and may cause accidental submission without edits. Prefer placeholders or a “Saved” badge.

Example:

-          value={publicKey || partnerStack?.publicKey || ""}
+          value={publicKey}
@@
-          value={secretKey || partnerStack?.maskedSecretKey || ""}
+          value={secretKey}

Then show a small “Credentials saved” hint when partnerStack exists.

Also applies to: 94-95

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 9d0cf9a and 3d68eab.

📒 Files selected for processing (5)
  • apps/web/app/(ee)/app.dub.co/(new-program)/[slug]/program/new/overview/page-client.tsx (2 hunks)
  • apps/web/app/(ee)/app.dub.co/(new-program)/[slug]/program/new/rewards/form.tsx (1 hunks)
  • apps/web/app/(ee)/app.dub.co/(new-program)/[slug]/program/new/rewards/import-partnerstack-form.tsx (3 hunks)
  • apps/web/lib/actions/partners/set-partnerstack-token.ts (1 hunks)
  • apps/web/lib/zod/schemas/program-onboarding.ts (1 hunks)
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-07-30T15:25:13.936Z
Learnt from: TWilson023
PR: dubinc/dub#2673
File: apps/web/ui/partners/rewards/add-edit-reward-sheet.tsx:56-66
Timestamp: 2025-07-30T15:25:13.936Z
Learning: In apps/web/ui/partners/rewards/add-edit-reward-sheet.tsx, the form schema uses partial condition objects to allow users to add empty/unconfigured condition fields without type errors, while submission validation uses strict schemas to ensure data integrity. This two-stage validation pattern improves UX by allowing progressive completion of complex forms.

Applied to files:

  • apps/web/lib/zod/schemas/program-onboarding.ts
  • apps/web/app/(ee)/app.dub.co/(new-program)/[slug]/program/new/overview/page-client.tsx
📚 Learning: 2025-07-30T15:29:54.131Z
Learnt from: TWilson023
PR: dubinc/dub#2673
File: apps/web/ui/partners/rewards/rewards-logic.tsx:268-275
Timestamp: 2025-07-30T15:29:54.131Z
Learning: In apps/web/ui/partners/rewards/rewards-logic.tsx, when setting the entity field in a reward condition, dependent fields (attribute, operator, value) should be reset rather than preserved because different entities (customer vs sale) have different available attributes. Maintaining existing fields when the entity changes would create invalid state combinations and confusing UX.

Applied to files:

  • apps/web/app/(ee)/app.dub.co/(new-program)/[slug]/program/new/overview/page-client.tsx
🧬 Code graph analysis (1)
apps/web/app/(ee)/app.dub.co/(new-program)/[slug]/program/new/rewards/import-partnerstack-form.tsx (2)
apps/web/lib/types.ts (1)
  • ProgramData (495-495)
apps/web/lib/actions/partners/set-partnerstack-token.ts (1)
  • setPartnerStackTokenAction (13-35)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Vade Review
  • GitHub Check: build
🔇 Additional comments (4)
apps/web/app/(ee)/app.dub.co/(new-program)/[slug]/program/new/overview/page-client.tsx (1)

52-55: PartnerStack included in destructuring and validity scope — good addition.
No issues with adding partnerstack to the form data read.

apps/web/app/(ee)/app.dub.co/(new-program)/[slug]/program/new/rewards/form.tsx (1)

155-157: Prop plumbing to ImportPartnerStackForm looks correct.
Passing watch and setValue aligns with the new form-state behavior.

apps/web/lib/zod/schemas/program-onboarding.ts (1)

38-43: Schema extension for partnerstack is consistent with progressive form UX.
Optional fields align with the two-stage validation pattern you use elsewhere.

apps/web/app/(ee)/app.dub.co/(new-program)/[slug]/program/new/rewards/import-partnerstack-form.tsx (1)

14-21: watch/setValue props integration — solid.
Enables the parent form to own state while this child reflects and updates it.

@vercel
Copy link
Contributor

vercel bot commented Sep 2, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Updated (UTC)
dub Ready Ready Preview Sep 2, 2025 4:23pm

@steven-tey
Copy link
Collaborator

/vercel run

@steven-tey steven-tey merged commit bade1e6 into main Sep 2, 2025
8 checks passed
@steven-tey steven-tey deleted the program-onboarding-partnerstack branch September 2, 2025 16:27
@coderabbitai coderabbitai bot mentioned this pull request Dec 9, 2025
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.

3 participants