Skip to content

Upgrade staging#212

Merged
elliotBraem merged 19 commits intomainfrom
staging
Jul 9, 2025
Merged

Upgrade staging#212
elliotBraem merged 19 commits intomainfrom
staging

Conversation

@elliotBraem
Copy link
Collaborator

@elliotBraem elliotBraem commented Jul 9, 2025

Summary by CodeRabbit

  • New Features

    • Distributor badges now display consistent names and, when available, are clickable links that open in a new tab.
    • Added support for generating and displaying distributor-specific URLs and user-friendly names.
  • Enhancements

    • Feed creation now automatically manages and updates RSS distributor configurations to ensure synchronization of feed details.
  • Refactor

    • The /create/feed route structure was reorganized to introduce a nested _tabs layer, affecting the URLs for feed creation, review, and settings pages.

elliotBraem and others added 17 commits June 25, 2025 17:40
* feat: update my feeds tab on profile page

* feat: update tabs to be routes

* fix: double scrollbar

* comment unused files in overview tab

* fix: revert rsbuild

* fmt

* fix: add routegen to prettier ignore

* clean up, server side

---------

Co-authored-by: Elliot Braem <elliot@ejlbraem.com>
* feat: add name and tag validation to create

* feat: add no activity data in activity tab

* add coming soon sections for profile page

* feat: clicking on leaderboard feed hashtag will redirect to that feed

* fix: keeps name on start when disable feed names collapse

* fix: rsbuild

* fix: add routegen to prettier ignore

* fix: add ability to navigate to collapsed feeds in leaderboard

* add ability to expand or collapse all

* fix: rsbuild

* adjustments

* nitpicks

---------

Co-authored-by: Elliot Braem <elliot@ejlbraem.com>
* feat: update the feed editor

* feat: improve performance, and fix bugs

* feat: revert local development change

* add routegen to pretttier ignore

* fix: resolve code rabbit comments

* fix some nitpick comments

* fix prettier and build config

* formats

* merge

---------

Co-authored-by: Elliot Braem <elliot@ejlbraem.com>
* Feat: add recent feeds

* feat: add recent content to the main feed page

* fmt

* Update apps/app/src/hooks/use-rss-feed.ts

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* nitpicks

---------

Co-authored-by: Elliot Braem <elliot@everything.dev>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: Elliot Braem <elliot@ejlbraem.com>
@vercel
Copy link

vercel bot commented Jul 9, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
curatedotfun-app ✅ Ready (Inspect) Visit Preview 💬 Add feedback Jul 9, 2025 0:12am
curatedotfun-app (staging) ✅ Ready (Inspect) Visit Preview 💬 Add feedback Jul 9, 2025 0:12am

@coderabbitai
Copy link

coderabbitai bot commented Jul 9, 2025

"""

Walkthrough

This update restructures the /create/feed route subtree by introducing an intermediate _tabs route, moves its child routes under this new layer, and updates all related imports and type declarations. Additionally, it enhances the DistributorBadges component to use structured distributor configs, introduces utility functions for distributor display names and URLs, and automatically manages RSS distributor setup in the feed creation store.

Changes

File(s) Change Summary
apps/app/src/components/DistributorBadges.tsx Updated to accept DistributorConfig[], use new utilities for display names/URLs, and render clickable badges.
apps/app/src/lib/distributor-urls.ts New module: defines DistributorConfig, utilities for distributor URLs, display names, and URL presence checks.
apps/app/src/store/feed-creation-store.ts Enhanced setValues to auto-manage RSS distributor config and object-transform mappings in feed creation logic.
apps/app/src/routeTree.gen.ts Restructured /create/feed route: added _tabs layer, updated all related route/type declarations and imports.
apps/app/src/routes/_layout/create/feed/_tabs.tsx Changed route path from /create/feed to /create/feed/_tabs.
apps/app/src/routes/_layout/create/feed/_tabs/index.tsx Changed route path from /create/feed/ to /create/feed/_tabs/.
apps/app/src/routes/_layout/create/feed/_tabs/review.tsx Changed route path from /create/feed/review to /create/feed/_tabs/review.
apps/app/src/routes/_layout/create/feed/_tabs/settings.tsx Changed route path from /create/feed/settings to /create/feed/_tabs/settings.

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant DistributorBadges
  participant distributor-urls.ts

  User->>DistributorBadges: Render with distribute: DistributorConfig[]
  DistributorBadges->>distributor-urls.ts: getDistributorDisplayName(distributor)
  DistributorBadges->>distributor-urls.ts: getDistributorUrl(distributor)
  alt URL exists
    DistributorBadges->>User: Render clickable badge (anchor)
  else No URL
    DistributorBadges->>User: Render static badge (span)
  end
Loading
sequenceDiagram
  participant FeedCreationStore
  participant setValues
  participant RSS Distributor

  FeedCreationStore->>setValues: setValues({ id, ... })
  setValues->>RSS Distributor: Check if RSS distributor exists
  alt Not found
    setValues->>RSS Distributor: Create default RSS distributor config
  end
  setValues->>RSS Distributor: Update feedConfig title, description, serviceUrl
  setValues->>RSS Distributor: Ensure feed id in categories mapping
Loading

Possibly related PRs

  • PotLock/curatedotfun#182: Refactored and enhanced the initial DistributorBadges component, upon which this PR builds.
  • PotLock/curatedotfun#210: Also modifies DistributorBadges to use DistributorConfig and new utility functions, indicating overlapping code changes.
  • PotLock/curatedotfun#68: Upgraded RSS feed and object-transform plugins, related to this PR's enhancements to RSS distributor setup in the feed creation store.

Poem

A bunny hopped through routes anew,
With tabs and badges shining through.
URLs for every friend,
RSS feeds that auto-blend.
In fields of config, carrots grow—
Hooray for code that helps us flow!
🥕✨
"""


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1ec8989 and c36fa5a.

📒 Files selected for processing (1)
  • apps/app/src/store/feed-creation-store.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/app/src/store/feed-creation-store.ts
✨ Finishing Touches
  • 📝 Generate Docstrings

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.
    • Explain this complex logic.
    • 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. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • 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 src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

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

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai 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

Documentation and Community

  • 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.

Copy link

@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: 3

🔭 Outside diff range comments (6)
apps/app/src/routes/_layout/create/feed/_tabs.tsx (1)

12-16: Update step navigation paths to match new route structure.

The step navigation still references the old route paths without the _tabs layer. This could cause navigation issues.

  const steps = [
-    { id: "/_layout/create/feed/", title: "Basic Information" },
-    { id: "/_layout/create/feed/settings", title: "Curation Settings" },
-    { id: "/_layout/create/feed/review", title: "Feed Review" },
+    { id: "/_layout/create/feed/_tabs/", title: "Basic Information" },
+    { id: "/_layout/create/feed/_tabs/settings", title: "Curation Settings" },
+    { id: "/_layout/create/feed/_tabs/review", title: "Feed Review" },
  ];
apps/app/src/routes/_layout/create/feed/_tabs/review.tsx (1)

148-148: Update navigation path to match new route structure.

The navigation to the settings page still uses the old route path without the _tabs layer.

-          onClick={() => navigate({ to: "/create/feed/settings" })}
+          onClick={() => navigate({ to: "/create/feed/_tabs/settings" })}
apps/app/src/routes/_layout/create/feed/_tabs/index.tsx (1)

63-63: Update navigation path to match new route structure.

The navigation to the settings page still uses the old route path without the _tabs layer.

-      to: "/create/feed/settings",
+      to: "/create/feed/_tabs/settings",
apps/app/src/routes/_layout/create/feed/_tabs/settings.tsx (2)

68-68: Update navigation path to match new route structure.

The navigation to the review page still uses the old route path without the _tabs layer.

-      navigate({ to: "/create/feed/review" });
+      navigate({ to: "/create/feed/_tabs/review" });

89-91: Update navigation path to match new route structure.

The navigation to the feed creation page still uses the old route path without the _tabs layer.

              navigate({
-                to: "/create/feed",
+                to: "/create/feed/_tabs",
              })
apps/app/src/store/feed-creation-store.ts (1)

1-200: Fix Prettier formatting issues

The pipeline indicates formatting issues. Run prettier --write apps/app/src/store/feed-creation-store.ts to fix the code style.

🧹 Nitpick comments (3)
apps/app/src/lib/distributor-urls.ts (1)

16-18: Consider more robust template variable detection.

The current implementation only checks for {{ which might miss other template formats or cause false positives with legitimate URLs containing these characters.

Consider a more specific regex pattern:

function isTemplateVariable(value: unknown): boolean {
-  return typeof value === "string" && value.includes("{{");
+  return typeof value === "string" && /\{\{[^}]+\}\}/.test(value);
}
apps/app/src/store/feed-creation-store.ts (1)

95-152: Consider making RSS distributor creation explicit rather than automatic

The current implementation automatically creates and manages an RSS distributor whenever setValues is called with an id. This side effect might be unexpected for consumers of this store. Consider:

  1. Making RSS distributor creation an explicit action
  2. Adding a configuration option to control this behavior
  3. At minimum, documenting this automatic behavior clearly
apps/app/src/components/DistributorBadges.tsx (1)

19-47: Consider extracting Badge component to reduce duplication

The badge styling and content are duplicated between the linked and non-linked versions. Consider extracting a reusable component.

+const DistributorBadge = ({ displayName, className }: { displayName: string; className?: string }) => (
+  <Badge 
+    className={`text-black border border-stone-500 rounded-md bg-stone-50 shadow-none px-2 py-0.5 text-xs whitespace-nowrap flex-shrink-0 ${className || ''}`}
+  >
+    {displayName}
+  </Badge>
+);

 export function DistributorBadges({
   distribute,
 }: {
   distribute: DistributorConfig[];
 }) {
   return (
     <div className="flex flex-wrap gap-1 max-w-full overflow-hidden">
       {distribute.map((distributor, index) => {
         const displayName = getDistributorDisplayName(distributor);
         const url = getDistributorUrl(distributor);
+        const key = `${distributor.plugin}-${index}`;

-        const badgeContent = (
-          <Badge className="text-black border border-stone-500 rounded-md bg-stone-50 shadow-none px-2 py-0.5 text-xs whitespace-nowrap flex-shrink-0 cursor-pointer hover:bg-stone-100 transition-colors">
-            {displayName}
-          </Badge>
-        );
-
-        // If we have a URL, wrap in a link, otherwise just render the badge
         if (url) {
           return (
             <a
-              key={`${distributor.plugin}-${index}`}
+              key={key}
               href={url}
               target="_blank"
               rel="noopener noreferrer"
               className="inline-block"
             >
-              {badgeContent}
+              <DistributorBadge 
+                displayName={displayName} 
+                className="cursor-pointer hover:bg-stone-100 transition-colors"
+              />
             </a>
           );
         }

-        return (
-          <Badge
-            key={`${distributor.plugin}-${index}`}
-            className="text-black border border-stone-500 rounded-md bg-stone-50 shadow-none px-2 py-0.5 text-xs whitespace-nowrap flex-shrink-0"
-          >
-            {displayName}
-          </Badge>
-        );
+        return <DistributorBadge key={key} displayName={displayName} />;
       })}
     </div>
   );
 }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9c0deeb and 1ec8989.

📒 Files selected for processing (8)
  • apps/app/src/components/DistributorBadges.tsx (1 hunks)
  • apps/app/src/lib/distributor-urls.ts (1 hunks)
  • apps/app/src/routeTree.gen.ts (21 hunks)
  • apps/app/src/routes/_layout/create/feed/_tabs.tsx (1 hunks)
  • apps/app/src/routes/_layout/create/feed/_tabs/index.tsx (1 hunks)
  • apps/app/src/routes/_layout/create/feed/_tabs/review.tsx (1 hunks)
  • apps/app/src/routes/_layout/create/feed/_tabs/settings.tsx (1 hunks)
  • apps/app/src/store/feed-creation-store.ts (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (5)
apps/app/src/routes/_layout/create/feed/_tabs.tsx (3)
apps/app/src/routes/_layout/create/feed/_tabs/index.tsx (1)
  • Route (37-40)
apps/app/src/routes/_layout/create/feed/_tabs/review.tsx (1)
  • Route (9-11)
apps/app/src/routes/_layout/create/feed/_tabs/settings.tsx (1)
  • Route (54-56)
apps/app/src/routes/_layout/create/feed/_tabs/review.tsx (3)
apps/app/src/routes/_layout/create/feed/_tabs.tsx (1)
  • Route (5-7)
apps/app/src/routes/_layout/create/feed/_tabs/index.tsx (1)
  • Route (37-40)
apps/app/src/routes/_layout/create/feed/_tabs/settings.tsx (1)
  • Route (54-56)
apps/app/src/routes/_layout/create/feed/_tabs/index.tsx (3)
apps/app/src/routes/_layout/create/feed/_tabs.tsx (1)
  • Route (5-7)
apps/app/src/routes/_layout/create/feed/_tabs/review.tsx (1)
  • Route (9-11)
apps/app/src/routes/_layout/create/feed/_tabs/settings.tsx (1)
  • Route (54-56)
apps/app/src/routes/_layout/create/feed/_tabs/settings.tsx (3)
apps/app/src/routes/_layout/create/feed/_tabs.tsx (1)
  • Route (5-7)
apps/app/src/routes/_layout/create/feed/_tabs/index.tsx (1)
  • Route (37-40)
apps/app/src/routes/_layout/create/feed/_tabs/review.tsx (1)
  • Route (9-11)
apps/app/src/components/DistributorBadges.tsx (2)
apps/app/src/lib/distributor-urls.ts (3)
  • DistributorConfig (8-11)
  • getDistributorDisplayName (195-211)
  • getDistributorUrl (148-190)
packages/types/src/config.ts (1)
  • DistributorConfig (101-101)
🪛 GitHub Actions: CI
apps/app/src/store/feed-creation-store.ts

[error] 1-1: Prettier formatting check failed. Run 'prettier --write' to fix code style issues.

🔇 Additional comments (9)
apps/app/src/lib/distributor-urls.ts (3)

148-190: LGTM! Well-structured distributor URL routing.

The main URL generation function handles multiple distributor types with appropriate fallbacks. The switch statement is comprehensive and the plugin name normalization is well-implemented.


195-211: LGTM! Consistent display name formatting.

The display name function properly handles special cases like "NEAR Social" and "RSS" while providing sensible defaults with proper capitalization.


216-261: LGTM! Comprehensive specific URL validation.

The hasSpecificUrl function correctly checks for meaningful configuration values across all supported distributors, enabling proper conditional rendering logic.

apps/app/src/routes/_layout/create/feed/_tabs.tsx (1)

5-7: LGTM! Route path updated correctly.

The route path has been properly updated to include the new _tabs intermediate layer, consistent with the route restructuring.

apps/app/src/routes/_layout/create/feed/_tabs/review.tsx (1)

9-11: LGTM! Route path updated correctly.

The route path has been properly updated to include the new _tabs intermediate layer.

apps/app/src/routes/_layout/create/feed/_tabs/index.tsx (1)

37-40: LGTM! Route path updated correctly.

The route path has been properly updated to include the new _tabs intermediate layer.

apps/app/src/routes/_layout/create/feed/_tabs/settings.tsx (1)

54-56: LGTM! Route path updated correctly.

The route path has been properly updated to include the new _tabs intermediate layer.

apps/app/src/components/DistributorBadges.tsx (1)

1-51: Good refactoring to use centralized utility functions

The refactoring to use getDistributorDisplayName and getDistributorUrl utilities improves consistency and maintainability across the application.

apps/app/src/routeTree.gen.ts (1)

1-908: Auto-generated file - no manual changes needed

This file is automatically generated by TanStack Router and reflects the route restructuring changes. The new _tabs intermediate layer is correctly represented in the route tree.

Comment on lines +129 to +133
const match = url.match(/https:\/\/([^.]+)\.supabase\.co/);
if (match) {
const projectRef = match[1];
return `https://supabase.com/dashboard/project/${projectRef}`;
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Strengthen URL validation for Supabase project extraction.

The regex pattern for extracting Supabase project references could be more robust and should handle edge cases.

-    const match = url.match(/https:\/\/([^.]+)\.supabase\.co/);
+    const match = url.match(/^https:\/\/([a-zA-Z0-9-]+)\.supabase\.co(?:\/|$)/);

This ensures:

  • URL starts with https://
  • Project ref contains only valid characters
  • Properly handles trailing slashes
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const match = url.match(/https:\/\/([^.]+)\.supabase\.co/);
if (match) {
const projectRef = match[1];
return `https://supabase.com/dashboard/project/${projectRef}`;
}
const match = url.match(/^https:\/\/([a-zA-Z0-9-]+)\.supabase\.co(?:\/|$)/);
if (match) {
const projectRef = match[1];
return `https://supabase.com/dashboard/project/${projectRef}`;
}
🤖 Prompt for AI Agents
In apps/app/src/lib/distributor-urls.ts around lines 129 to 133, the current
regex for extracting the Supabase project reference is too loose and may match
invalid URLs. Update the regex to ensure the URL starts with https://, the
project reference contains only valid characters (e.g., alphanumeric and
hyphens), and it properly handles optional trailing slashes. This will make the
URL validation more robust and prevent incorrect matches.

if (channelId) {
// Discord channel URLs format: https://discord.com/channels/serverId/channelId
// Since we don't have serverId, we use @me which works for direct channel links
return `https://discord.com/channels/@me/${channelId}`;
Copy link

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Verify Discord channel URL format compatibility.

The Discord URL format using @me may not work for all channel types. Server channels typically require the actual server ID.

Please verify that Discord channel URLs with @me work correctly for your use case:


🌐 Web query:

Does Discord support channel URLs in the format https://discord.com/channels/@me/channelId for all channel types?

💡 Result:

Yes, Discord supports channel URLs in the format https://discord.com/channels/@me/channelId for direct message (DM) channels. This URL structure allows users to access their private conversations directly. For other channel types, such as text or voice channels within a server (guild), the URL format is https://discord.com/channels/guildId/channelId. This distinction ensures that users can navigate to both server-based and direct message channels using appropriate URLs.


Ensure correct Discord channel URL generation for DMs and guild channels

We verified that https://discord.com/channels/@me/<channelId> only works for direct‐message channels, whereas server (guild) channels require the guild ID in the URL. If this utility may be used for guild channels, update it to accept an optional guildId and generate the URL accordingly.

• apps/app/src/lib/distributor-urls.ts: adjust return value
• Introduce an optional guildId parameter (or pull it from context)

Suggested diff:

-   return `https://discord.com/channels/@me/${channelId}`;
+   if (guildId) {
+     return `https://discord.com/channels/${guildId}/${channelId}`;
+   }
+   return `https://discord.com/channels/@me/${channelId}`;

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In apps/app/src/lib/distributor-urls.ts at line 104, the function currently
returns a URL formatted only for direct-message channels using
`https://discord.com/channels/@me/${channelId}`. To support both DM and guild
channels, modify the function to accept an optional `guildId` parameter. If
`guildId` is provided, return the URL as
`https://discord.com/channels/${guildId}/${channelId}`, otherwise keep the
existing DM URL format. Update the function signature and the return statement
accordingly to handle both cases.

Comment on lines +95 to +152
if (values.id && state.feedConfig.outputs?.stream?.distribute) {
let rssDistributor = state.feedConfig.outputs.stream.distribute.find(
(d) => d.plugin === "@curatedotfun/rss",
);
if (!rssDistributor) {
rssDistributor = {
plugin: "@curatedotfun/rss",
config: {
apiSecret: "{{RSS_SERVICE_API_SECRET}}",
feedConfig: {
title: "",
description: "",
},
serviceUrl: "",
},
transform: [
{
plugin: "@curatedotfun/object-transform",
config: {
mappings: {
link: "{{source}}",
title: "{{title}}",
author: {
link: "https://x.com/{{author}}",
name: "{{username}}",
},
source: {
url: "{{source}}",
title: "twitter",
},
content: "<h2>{{title}}</h2><p>{{summary}}</p>",
categories: ["{{tags}}"],
description: "{{summary}}",
publishedAt: "{{createdAt}}",
},
},
},
],
};
state.feedConfig.outputs.stream.distribute.push(rssDistributor);
}
rssDistributor.config.feedConfig.title = values.name ?? "";
rssDistributor.config.feedConfig.description =
values.description ?? "";
rssDistributor.config.serviceUrl = `https://rss.curate.fun/${values.id}/rss.xml`;
const objectTransform = rssDistributor.transform?.find(
(t) => t.plugin === "@curatedotfun/object-transform",
);
if (
objectTransform &&
Array.isArray(objectTransform.config.mappings.categories)
) {
const categories = objectTransform.config.mappings.categories;
if (!categories.includes(values.id)) {
categories.push(values.id);
}
}
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Extract RSS distributor management logic into a helper function

The RSS distributor setup logic is complex and deeply nested within setValues. This reduces readability and makes the code harder to test and maintain.

Consider extracting this logic into a dedicated helper function:

+const createOrUpdateRssDistributor = (
+  feedId: string,
+  name: string,
+  description: string,
+  existingDistributors: DistributorConfig[] = []
+): DistributorConfig[] => {
+  const distributors = [...existingDistributors];
+  let rssDistributor = distributors.find(d => d.plugin === "@curatedotfun/rss");
+  
+  if (!rssDistributor) {
+    rssDistributor = {
+      plugin: "@curatedotfun/rss",
+      config: {
+        apiSecret: "{{RSS_SERVICE_API_SECRET}}",
+        feedConfig: { title: "", description: "" },
+        serviceUrl: "",
+      },
+      transform: [
+        {
+          plugin: "@curatedotfun/object-transform",
+          config: {
+            mappings: {
+              link: "{{source}}",
+              title: "{{title}}",
+              author: {
+                link: "https://x.com/{{author}}",
+                name: "{{username}}",
+              },
+              source: {
+                url: "{{source}}",
+                title: "twitter",
+              },
+              content: "<h2>{{title}}</h2><p>{{summary}}</p>",
+              categories: ["{{tags}}"],
+              description: "{{summary}}",
+              publishedAt: "{{createdAt}}",
+            },
+          },
+        },
+      ],
+    };
+    distributors.push(rssDistributor);
+  }
+  
+  // Update RSS distributor configuration
+  rssDistributor.config.feedConfig.title = name;
+  rssDistributor.config.feedConfig.description = description;
+  rssDistributor.config.serviceUrl = `https://rss.curate.fun/${feedId}/rss.xml`;
+  
+  // Update categories
+  const objectTransform = rssDistributor.transform?.find(
+    t => t.plugin === "@curatedotfun/object-transform"
+  );
+  if (objectTransform && Array.isArray(objectTransform.config.mappings.categories)) {
+    const categories = objectTransform.config.mappings.categories;
+    if (!categories.includes(feedId)) {
+      categories.push(feedId);
+    }
+  }
+  
+  return distributors;
+};

 setValues: (values) => {
   setState((state) => {
     state.feedConfig = { ...state.feedConfig, ...values };
-    if (values.id && state.feedConfig.outputs?.stream?.distribute) {
-      let rssDistributor = state.feedConfig.outputs.stream.distribute.find(
-        (d) => d.plugin === "@curatedotfun/rss",
-      );
-      // ... rest of the RSS logic
+    if (values.id && state.feedConfig.outputs?.stream) {
+      state.feedConfig.outputs.stream.distribute = createOrUpdateRssDistributor(
+        values.id,
+        values.name ?? "",
+        values.description ?? "",
+        state.feedConfig.outputs.stream.distribute
+      );
     }
   });
 },
🤖 Prompt for AI Agents
In apps/app/src/store/feed-creation-store.ts around lines 95 to 152, the RSS
distributor setup logic is deeply nested inside the setValues function, making
it hard to read and maintain. Extract this entire block that manages the
rssDistributor creation, configuration, and updating into a separate helper
function that accepts necessary parameters like state and values. Then call this
helper from setValues to keep the main function cleaner and improve testability.

@elliotBraem elliotBraem merged commit 793cbab into main Jul 9, 2025
8 checks passed
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.

2 participants