Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Revamping landingpage #74

Merged
merged 5 commits into from
Dec 1, 2024
Merged

Revamping landingpage #74

merged 5 commits into from
Dec 1, 2024

Conversation

SkidGod4444
Copy link
Owner

@SkidGod4444 SkidGod4444 commented Nov 28, 2024

Summary by CodeRabbit

Release Notes

  • New Features

    • Introduced a react-scan script for easier tool execution in multiple applications.
    • Added PricingSwitch component allowing users to toggle between yearly and monthly billing options.
    • Implemented AnimatedNumber and TextMorph components for enhanced pricing display animations.
  • Improvements

    • Enhanced PricingCards component to dynamically display pricing based on selected billing cycle.
    • Updated pricing configuration to include detailed monthly and yearly pricing structures.
  • Bug Fixes

    • Improved formatting and readability in various components without affecting functionality.

Copy link

vercel bot commented Nov 28, 2024

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

Name Status Preview Comments Updated (UTC)
plura-api ✅ Ready (Inspect) Visit Preview 💬 Add feedback Dec 1, 2024 10:32am
plura-app ✅ Ready (Inspect) Visit Preview 💬 Add feedback Dec 1, 2024 10:32am
plura-status ✅ Ready (Inspect) Visit Preview 💬 Add feedback Dec 1, 2024 10:32am
plura-web ✅ Ready (Inspect) Visit Preview 💬 Add feedback Dec 1, 2024 10:32am

Copy link

coderabbitai bot commented Nov 28, 2024

Walkthrough

The pull request introduces several changes across multiple package.json files, adding a new script for react-scan in each application and updating the version of the next dependency to 15.0.3. Additionally, new dependencies are added to the plura-www project. The turbo.json file gains a new task for type checking, and the workflow configuration is updated to enhance formatting processes. Various components, particularly those related to pricing, are refactored or newly created, improving functionality and user interaction.

Changes

File Path Change Summary
apps/app/package.json - Added script: "react-scan": "pnpm dlx react-scan@latest http://localhost:3002"
- Updated next from 15.0.2 to 15.0.3
apps/status/package.json - Added script: "react-scan": "pnpm dlx react-scan@latest http://localhost:3004"
apps/www/package.json - Added script: "react-scan": "pnpm dlx react-scan@latest http://localhost:3003"
- Updated next from 15.0.2 to 15.0.3
- Added dependencies: @radix-ui/react-radio-group, @radix-ui/react-switch
turbo.json - Added task: "typecheck": { "cache": false, "outputs": [] }"
.github/workflows/format-and-push.yml - Updated trigger conditions and job steps for formatting, integrating turbo for formatting tasks
apps/api/package.json - Added dependency: "@repo/cache": "workspace:*"
- Updated next from 15.0.2 to 15.0.3
apps/www/app/(routes)/pricing/page.tsx - Added imports and state management for pricing options; updated JSX structure to include PricingSwitch
apps/www/components/custom/anim-numb.tsx - Added new component: AnimatedNumber for animating numeric values
apps/www/components/custom/pricing/pricing.cards.tsx - Restructured PricingCards component to include new props and dynamic pricing display
apps/www/components/custom/pricing/pricing.switch.tsx - Added new component: PricingSwitch for toggling billing options
apps/www/components/custom/text-morph.tsx - Added new component: TextMorph for animated text transitions
apps/www/components/ui/switch.tsx - Added new component: Switch for customizable switch UI
apps/www/config/pricing.config.ts - Restructured pricingCardConfig for pricing tiers
apps/api/app/api/[[...route]]/auth.ts - Stylistic change in CORS middleware configuration
apps/api/app/api/[[...route]]/user.ts - Reformatting of import statements and JSON response formatting
apps/www/app/(routes)/contact/page.tsx - Refactored Contact component for improved readability
apps/www/app/(routes)/features/page.tsx - Simplified return statement in Features component
apps/www/app/(routes)/integrations/page.tsx - Removed a blank line at the end of the file
apps/www/app/(routes)/methods/page.tsx - Simplified return statement in Methods component
apps/www/components/custom/navbar/navbar.tsx - Adjusted rel attribute formatting for the "Status" link
apps/www/components/custom/site/header.tsx - Minor structural change in SiteHeader for button placement
apps/www/config/site.config.ts - Added trailing comma in siteConfig object for consistency

Possibly related PRs

  • feat/(usage_page) #21: Adds a similar react-scan script in another package.json, indicating related functionality enhancements.
  • add mail service #23: Modifies the workflow file, relevant due to interactions with the package.json scripts.
  • Feature/auth page #24: Changes to .gitignore and configurations, indirectly related to project management.
  • Feature/pricing #25: Introduces a new pricing page, potentially relevant if react-scan interacts with pricing components.
  • feature/auth #33: Modifications to API route handling, possibly connecting with the new react-scan script.
  • auth #34: Similar to feature/auth #33, focuses on API routes that may relate to the new script.
  • fix workflows #68: Workflow fixes that may connect with changes in the package.json and build processes.

🐰 "In the code, new scripts now play,
React-scan leads the way!
Pricing cards dance with delight,
As components shine so bright.
With each change, we hop and cheer,
A better app is finally here!" 🎉


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 60529ac and a6af327.

📒 Files selected for processing (1)
  • apps/www/app/(routes)/pricing/page.tsx (1 hunks)
🔇 Additional comments (5)
apps/www/app/(routes)/pricing/page.tsx (5)

10-11: LGTM: New imports are properly structured

The imports are correctly organized and support the new pricing toggle functionality.


14-14: LGTM: State management follows React best practices

The state implementation is well-typed and initialized with a sensible default value.


38-44: LGTM: Well-structured component hierarchy

The component structure is clean and organized:

  • Proper animation delays with BlurFade
  • Clear separation of pricing switch and cards
  • Correct prop passing for yearly/monthly toggle

39-42: Verify PricingSwitch and PricingCards implementation

Please ensure that:

  1. PricingSwitch properly handles the toggle state
  2. PricingCards correctly displays different prices based on isYearly prop
✅ Verification successful

Let me try a different search pattern to locate these components.


Both components are properly implemented and working as expected

The verification confirms that:

  1. PricingSwitch correctly:

    • Manages yearly/monthly toggle state
    • Properly propagates state changes via onYearlyBillingChange callback
    • Has appropriate UI feedback with labels and transitions
  2. PricingCards correctly:

    • Receives and uses isYearly prop
    • Shows different prices based on billing period
    • Uses AnimatedNumber for smooth price transitions
    • Properly integrates with pricing configuration
    • Displays appropriate billing period text
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check implementation of related components
echo "Checking PricingSwitch implementation:"
ast-grep --pattern 'export $_ function PricingSwitch({ $_ }: { $_ }) { $$ }'

echo "Checking PricingCards implementation:"
ast-grep --pattern 'export $_ function PricingCards({ isYearly }: { $_ }) { $$ }'

Length of output: 334


Script:

#!/bin/bash
# Search for PricingSwitch and PricingCards files
echo "Searching for pricing-related component files:"
fd -e tsx -e ts pricing -i

# Check content of found files
echo -e "\nChecking implementations:"
for file in $(fd -e tsx -e ts pricing -i); do
  echo -e "\n=== Content of $file ==="
  cat "$file"
done

Length of output: 14852


34-37: Verify impact of section ID change

The section ID has changed from "pricing" to "pricingCards". Please ensure this doesn't break any existing:

  • Anchor links pointing to "#pricing"
  • Analytics tracking
  • End-to-end tests
✅ Verification successful

Section ID change appears safe to proceed

The search results show that all references to "pricing" in the codebase are route/path related (/pricing) and not anchor links (#pricing). The ID change from "pricing" to "pricingCards" doesn't impact any existing:

  • Navigation links (they use route paths, not anchor links)
  • Component references
  • Test files (no relevant references found)
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for references to the old pricing section ID
rg -l "pricing\"" --type=tsx --type=ts --type=jsx --type=js

Length of output: 88


Script:

#!/bin/bash
# Search for references to the old pricing section ID using ripgrep
# Note: Using simpler file extensions and including the '#' anchor symbol
rg -l "#pricing" .

# Also search for potential references without the hash
rg -l "pricing\"" .

# Search for potential test files that might reference the section
fd -e test.ts -e test.tsx -e spec.ts -e spec.tsx -e cy.ts

Length of output: 258


Script:

#!/bin/bash
# Check the actual references to pricing in the identified files
rg -C 2 "pricing" ./apps/www/app/\(routes\)/page.tsx
rg -C 2 "pricing" ./apps/www/components/custom/site/footer.tsx
rg -C 2 "pricing" ./apps/www/components/custom/navbar/navbar.tsx

Length of output: 736


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ 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.
    • Generate unit testing code for this file.
    • 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 generate unit testing code for this file.
    • @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 generate unit testing code.
    • @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.

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 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: 2

🧹 Outside diff range and nitpick comments (3)
turbo.json (1)

28-31: Consider adding task dependencies.

The typecheck task might benefit from being integrated into the dependency chain. Consider:

  1. Making it depend on upstream type definitions: "dependsOn": ["^typecheck"]
  2. Making the build task depend on it: Update build's dependsOn to include "typecheck"

This ensures type checking runs in the correct order and prevents builds with type errors.

     "typecheck": {
       "cache": false,
-      "outputs": []
+      "outputs": [],
+      "dependsOn": ["^typecheck"]
     },
     // ... later in the file ...
     "build": {
-      "dependsOn": ["^build", "^db:generate"],
+      "dependsOn": ["^build", "^db:generate", "typecheck"],
       "env": [".env*"],
       "inputs": ["$TURBO_DEFAULT$", ".env*"],
       "outputs": [".next/**", "!.next/cache/**"]
     },
apps/www/package.json (1)

Line range hint 39-40: Warning: Using React Release Candidate in Production

The project is using a Release Candidate version of React (19.0.0-rc-02c0e824-20241028). RC versions are not recommended for production use as they may contain breaking changes and unstable features.

Consider downgrading to the latest stable version:

-    "react": "19.0.0-rc-02c0e824-20241028",
-    "react-dom": "19.0.0-rc-02c0e824-20241028",
+    "react": "^18.2.0",
+    "react-dom": "^18.2.0",
apps/app/package.json (1)

15-15: Consider integrating react-scan into the Turbo pipeline

The react-scan script could benefit from being integrated into your Turbo pipeline for better orchestration with other tasks.

Consider adding it to your turbo.json configuration:

{
  "pipeline": {
    "react-scan": {
      "outputs": [],
      "cache": false
    }
  }
}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between dc3e5b5 and 8693135.

📒 Files selected for processing (4)
  • apps/app/package.json (1 hunks)
  • apps/status/package.json (1 hunks)
  • apps/www/package.json (1 hunks)
  • turbo.json (1 hunks)
🔇 Additional comments (6)
turbo.json (1)

28-31: LGTM! Task configuration looks good.

The configuration for the new "typecheck" task follows the established pattern for verification tasks, with appropriate cache and outputs settings.

apps/status/package.json (3)

9-10: Verify script execution order

The new react-scan script is added after lint. Consider if there's a specific order in which these scripts should be run, and if react-scan should be integrated into the existing lint process.

Let's check if other packages in the monorepo have a consistent script order:

✅ Verification successful

Script order is consistent with other packages

Looking at the script ordering across the monorepo packages, we can see that react-scan is consistently placed after lint in all packages that include both scripts (apps/app, apps/www, and apps/status). This indicates the current ordering in apps/status/package.json follows the established pattern in the codebase.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check script ordering in other package.json files
fd --type f "package.json" apps/ --exec sh -c 'echo "=== $1 ==="; jq -r ".scripts | keys[]" "$1"' sh {}

Length of output: 568


10-10: 🛠️ Refactor suggestion

Consider pinning react-scan to a specific version

Using @latest tag can lead to unexpected behavior if breaking changes are introduced in newer versions. Consider pinning to a specific version for better reproducibility and stability.

-    "react-scan": "pnpm dlx react-scan@latest http://localhost:3004"
+    "react-scan": "pnpm dlx react-scan@1.0.0 http://localhost:3004"

Let's check the available versions and recent changes:

✅ Verification successful

Pin react-scan to version 0.0.34 for stability

The package is still in early development (0.x.x versions). To ensure stability and reproducibility, pin it to the current latest version:

-    "react-scan": "pnpm dlx react-scan@latest http://localhost:3004"
+    "react-scan": "pnpm dlx react-scan@0.0.34 http://localhost:3004"
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check react-scan package information
curl -s https://registry.npmjs.org/react-scan | jq '{
  "latest_version": .["dist-tags"].latest,
  "versions": [.versions | keys[] | select(test("^[0-9]+\\.[0-9]+\\.[0-9]+$"))]
}'

Length of output: 701


Line range hint 22-23: Review the use of React RC version

The project is using a release candidate version of React (19.0.0-rc-66855b96-20241106). This could lead to stability issues and unexpected behavior. Consider using the latest stable version unless there's a specific need for RC features.

Let's check the latest stable version:

apps/www/package.json (1)

14-15: Verify react-scan configuration across apps

The react-scan script is configured to scan localhost:3003, which matches the dev server port. Let's verify this configuration across all apps.

✅ Verification successful

React-scan configuration is correctly aligned with dev server ports

The verification shows that each app's react-scan configuration correctly matches its corresponding dev server port:

  • apps/app: dev port 3002 → react-scan localhost:3002
  • apps/status: dev port 3004 → react-scan localhost:3004
  • apps/www: dev port 3003 → react-scan localhost:3003
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check react-scan configuration consistency across apps
# Expected: Each app should use its corresponding dev server port

echo "Checking react-scan configuration in all package.json files:"
fd --type f package.json apps/ --exec grep -l "react-scan" {} | while read -r file; do
    echo "\nFile: $file"
    grep "\"dev\":" "$file"
    grep "\"react-scan\":" "$file"
done

Length of output: 1058

apps/app/package.json (1)

15-15: Verify port alignment with dev server configuration

The react-scan URL (port 3002) should match your dev server configuration. Let's verify this alignment across the codebase.

✅ Verification successful

Port 3002 correctly aligns with app dev server configuration

The port 3002 in the react-scan URL matches the dev server configuration for the app package, as confirmed by the search results showing apps/app/package.json uses port 3002 for its Next.js dev server.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify port configuration consistency
# Check for any other port 3002 references and potential conflicts

# Search for port 3002 references
echo "Checking port 3002 references:"
rg -n "3002" --type json --type typescript --type javascript

# Check for other next dev port configurations
echo -e "\nChecking Next.js dev port configurations:"
rg -n "next dev -p" --type json

Length of output: 570

@@ -11,7 +11,8 @@
"lint:fix": "next lint --fix",
"typecheck": "tsc --noEmit",
"format:write": "prettier --write \"**/*.{ts,tsx,mdx}\" --cache",
"format:check": "prettier --check \"**/*.{ts,tsx,mdx}\" --cache"
"format:check": "prettier --check \"**/*.{ts,tsx,mdx}\" --cache",
"react-scan": "pnpm dlx react-scan@latest http://localhost:3003"
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Security: Avoid using @latest tag with react-scan

Using @latest tag with pnpm dlx can be risky as it may download and execute unexpected versions. Consider pinning to a specific version for better security and reproducibility.

Apply this change:

-    "react-scan": "pnpm dlx react-scan@latest http://localhost:3003"
+    "react-scan": "pnpm dlx react-scan@1.0.0 http://localhost:3003"

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

@@ -11,7 +11,8 @@
"lint:fix": "next lint --fix",
"typecheck": "tsc --noEmit",
"format:write": "prettier --write \"**/*.{ts,tsx,mdx}\" --cache",
"format:check": "prettier --check \"**/*.{ts,tsx,mdx}\" --cache"
"format:check": "prettier --check \"**/*.{ts,tsx,mdx}\" --cache",
"react-scan": "pnpm dlx react-scan@latest http://localhost:3002"
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Consider pinning the react-scan version for stability

Using @latest tag can lead to unexpected behavior if the tool introduces breaking changes. Consider pinning to a specific version for consistency across builds.

-    "react-scan": "pnpm dlx react-scan@latest http://localhost:3002"
+    "react-scan": "pnpm dlx react-scan@1.0.0 http://localhost:3002"

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

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: 8

🧹 Outside diff range and nitpick comments (15)
apps/www/components/custom/anim-numb.tsx (2)

6-10: Add JSDoc documentation for the type definition.

Consider adding JSDoc comments to document the purpose and usage of each prop in the AnimatedNumber type.

+/**
+ * Props for the AnimatedNumber component
+ * @property {number} value - The number to be animated
+ * @property {string} [className] - Optional CSS classes to apply
+ * @property {SpringOptions} [springOptions] - Optional configuration for the spring animation
+ */
 type AnimatedNumber = {
   value: number;
   className?: string;
   springOptions?: SpringOptions;
 };

26-30: Consider adding ARIA attributes for better accessibility.

The animated number might benefit from ARIA attributes to improve screen reader support.

 return (
   <motion.span
+    role="text"
+    aria-label={`Value: ${value}`}
     className={cn('tabular-nums', className)}>
     {display}
   </motion.span>
 );
apps/www/components/custom/pricing/pricing.switch.tsx (4)

7-9: Add JSDoc documentation for better code maintainability.

Consider adding JSDoc documentation to describe the interface and its prop.

+/**
+ * Props for the PricingSwitch component
+ * @interface PricingSwitchProps
+ */
 interface PricingSwitchProps {
+  /** Callback fired when billing period changes */
   onYearlyBillingChange?: (isYearly: boolean) => void;
 }

11-17: Consider performance and configurability improvements.

  1. Make the initial state configurable via props
  2. Optimize the callback handling to prevent unnecessary re-renders
-export default function PricingSwitch({onYearlyBillingChange}: PricingSwitchProps) {
-  const [isYearly, setIsYearly] = useState<boolean>(true);
+interface PricingSwitchProps {
+  onYearlyBillingChange?: (isYearly: boolean) => void;
+  defaultYearly?: boolean;
+}
+
+export default function PricingSwitch({
+  onYearlyBillingChange,
+  defaultYearly = true
+}: PricingSwitchProps) {
+  const [isYearly, setIsYearly] = useState<boolean>(defaultYearly);
+
+  const handleChange = (value: boolean) => {
+    setIsYearly(value);
+    onYearlyBillingChange?.(value);
+  };

-  useEffect(() => {
-    if (onYearlyBillingChange) {
-      onYearlyBillingChange(isYearly);
-    }
-  }, [isYearly, onYearlyBillingChange]);

20-25: Extract magic values and enhance accessibility.

  1. The transition duration and colors should be extracted to constants/design tokens
  2. Add aria-label for better accessibility
+const TRANSITION_DURATION = 300;
+const BG_COLOR = '#171717';

 <div className="flex items-center space-x-2 rounded-xl bg-[#171717] shadow-lg py-2 px-3 border">
   <Switch 
     id="yearly-mode" 
     checked={isYearly}
     onCheckedChange={setIsYearly}
+    aria-label="Toggle yearly billing"
   />
-  <Label htmlFor="yearly-mode" className="transition-all duration-300">
+  <Label htmlFor="yearly-mode" className={`transition-all duration-${TRANSITION_DURATION}`}>
     Billed Yearly
   </Label>
 </div>

1-27: Consider adding error boundaries and loading states.

The component could benefit from proper error handling and loading states, especially if the billing period switch triggers any async operations.

Would you like me to provide an example implementation with error boundaries and loading states?

apps/www/components/ui/switch.tsx (1)

12-26: Consider extracting Tailwind classes for better maintainability.

While the implementation is solid and accessible, the long className string could be better organized. Consider extracting the base styles into a constant or using a variant configuration with class-variance-authority (cva).

Example refactor:

const switchVariants = {
  base: "peer inline-flex h-5 w-9 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent shadow-sm transition-colors",
  states: "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background",
  interactive: "disabled:cursor-not-allowed disabled:opacity-50",
  colors: "data-[state=checked]:bg-primary data-[state=unchecked]:bg-input"
}

// Usage
className={cn(
  switchVariants.base,
  switchVariants.states,
  switchVariants.interactive,
  switchVariants.colors,
  className
)}
.github/workflows/format-and-push.yml (1)

Line range hint 1-60: Consider workflow security and reliability improvements

Several architectural improvements could enhance the workflow:

  1. Limit write permissions scope:
permissions:
  contents: write
  pull-requests: read
  1. Add failure handling and reporting:
- name: Format code with Prettier
  id: format
  continue-on-error: true
  run: turbo format:write

- name: Report formatting errors
  if: steps.format.outcome == 'failure'
  run: |
    echo "::error::Formatting failed. Please run 'pnpm format' locally and commit changes"
    exit 1
  1. Consider adding status checks to prevent merging if formatting fails

Would you like me to create a GitHub issue to track these improvements?

apps/www/components/custom/text-morph.tsx (1)

13-18: Consider adding role prop for better accessibility.

While the component is well-structured, consider adding a role prop to enhance accessibility when using non-semantic elements.

 type TextMorphProps = {
   children: string;
   as?: React.ElementType;
   className?: string;
   style?: React.CSSProperties;
+  role?: string;
 };
apps/www/app/(routes)/pricing/page.tsx (3)

33-40: Consider extracting animation delay values

The delay calculations (0.2 * 3) could be more maintainable by using constants.

+const ANIMATION_BASE_DELAY = 0.2;
+const PRICING_CARDS_DELAY = ANIMATION_BASE_DELAY * 3;
 <section id="pricingCards" className="flex items-center justify-center px-8 mb-20">
-  <BlurFade delay={0.2 * 3} inView>
+  <BlurFade delay={PRICING_CARDS_DELAY} inView>

42-47: Consider responsive design improvements

The border and padding styles might need adjustments for different screen sizes.

-<section id="pricingTable" className="flex items-center justify-center px-8 my-20 border-t-2 border-dashed w-full">
+<section id="pricingTable" className="flex items-center justify-center px-4 sm:px-6 md:px-8 my-12 sm:my-16 md:my-20 border-t border-dashed md:border-t-2 w-full">

Line range hint 14-49: Consider performance optimizations

Since this is a client component with multiple animated sections, consider:

  1. Lazy loading the PricingTable component as it might not be immediately visible
  2. Memoizing the PricingCards component to prevent unnecessary re-renders when switching between yearly/monthly

Example implementation:

import dynamic from 'next/dynamic'
import { memo } from 'react'

const LazyPricingTable = dynamic(() => import('@/components/custom/pricing/pricing.table'), {
  loading: () => <div>Loading...</div>
})

const MemoizedPricingCards = memo(PricingCards)
apps/www/config/pricing.config.ts (1)

Line range hint 1-85: Consider adding input validation for pricing configuration

To prevent future pricing calculation errors, consider adding runtime validation for the pricing configuration object.

Would you like me to help create a validation utility that ensures:

  1. Discount percentages are between 0-100%
  2. Yearly prices reflect annual calculations
  3. Pricing tiers maintain logical progression
  4. Currency consistency across tiers
apps/www/components/custom/pricing/pricing.cards.tsx (2)

106-110: Refactor Repeated springOptions into a Constant

The springOptions object is repeated multiple times with the same values in the AnimatedNumber components. Consider defining it as a constant to improve code maintainability and reduce redundancy.

Example:

const springOptions = {
  bounce: 0,
  duration: 2000,
};

Then use it in the AnimatedNumber components:

<AnimatedNumber
  springOptions={springOptions}
  value={...}
/>

Also applies to: 118-122, 127-131, 194-198, 206-210, 215-219


Line range hint 23-84: Consider Refactoring Pricing Cards into a Reusable Component

There is significant code duplication among the 'Plura Basic', 'Plura Plus', and 'Plura Pro' cards. Consider creating a reusable PricingCard component that accepts props for the card data. This will enhance maintainability and reduce redundancy.

Also applies to: 86-176, 178-240

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 8693135 and 62d1f50.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (12)
  • .github/workflows/format-and-push.yml (1 hunks)
  • apps/api/package.json (1 hunks)
  • apps/app/package.json (2 hunks)
  • apps/www/app/(routes)/pricing/page.tsx (2 hunks)
  • apps/www/components/custom/anim-numb.tsx (1 hunks)
  • apps/www/components/custom/pricing/pricing.cards.tsx (3 hunks)
  • apps/www/components/custom/pricing/pricing.switch.tsx (1 hunks)
  • apps/www/components/custom/pricing/pricing.table.tsx (1 hunks)
  • apps/www/components/custom/text-morph.tsx (1 hunks)
  • apps/www/components/ui/switch.tsx (1 hunks)
  • apps/www/config/pricing.config.ts (3 hunks)
  • apps/www/package.json (3 hunks)
✅ Files skipped from review due to trivial changes (1)
  • apps/www/components/custom/pricing/pricing.table.tsx
🚧 Files skipped from review as they are similar to previous changes (2)
  • apps/app/package.json
  • apps/www/package.json
🔇 Additional comments (15)
apps/www/components/custom/anim-numb.tsx (2)

12-31: LGTM! Clean and efficient implementation.

The component effectively uses framer-motion for smooth animations and properly handles value updates.


1-31: Verify integration with PricingCards component.

The AI summary mentions this component is used in PricingCards. Let's verify the integration to ensure proper usage.

✅ Verification successful

Let me gather more context about the actual usage to ensure all required props are properly passed.


Integration with PricingCards component is properly implemented

The AnimatedNumber component is correctly integrated within the PricingCards component with all required props:

  • Properly imported from the correct path
  • Used consistently with appropriate springOptions (bounce: 0, duration: 2000)
  • Value prop correctly passed with dynamic pricing values based on isYearly state
  • Used for displaying prices, before prices, and discount values for different pricing tiers
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the usage of AnimatedNumber in PricingCards component
# Expected: Find usage of AnimatedNumber component with proper props

# Search for AnimatedNumber usage in pricing cards component
rg -A 3 "AnimatedNumber" "apps/www/components/custom/pricing"

Length of output: 2262


Script:

#!/bin/bash
# Get more context around the AnimatedNumber usage in PricingCards
rg -B 2 -A 5 "<AnimatedNumber" "apps/www/components/custom/pricing/pricing.cards.tsx"

Length of output: 1952

apps/www/components/custom/pricing/pricing.switch.tsx (1)

1-27: Verify component integration with pricing page.

Let's verify how this component is integrated with the pricing page and its dependencies.

✅ Verification successful

Component integration verified successfully

The PricingSwitch component is properly integrated within the pricing ecosystem:

  • It's imported and used in apps/www/app/(routes)/pricing/page.tsx with the correct prop onYearlyBillingChange
  • The state is correctly propagated to PricingCards component which uses the isYearly value to:
    • Toggle between yearly/monthly pricing displays
    • Update animated price numbers
    • Show appropriate billing period text
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check component usage and dependencies

# Find files that import PricingSwitch
echo "Files importing PricingSwitch:"
rg -l "PricingSwitch" --type tsx

# Check for pricing-related components that might interact with this
echo "\nRelated pricing components:"
fd -e tsx -e ts pricing apps/www/components/custom/pricing/

# Look for usage patterns
echo "\nUsage patterns:"
rg -A 5 "PricingSwitch" --type tsx

Length of output: 530


Script:

#!/bin/bash
# Let's try a different approach without file type restrictions

# Find files that import or use PricingSwitch
echo "Files containing PricingSwitch:"
rg "PricingSwitch"

# Look at the pricing cards implementation to see integration
echo -e "\nPricing Cards Implementation:"
cat "apps/www/components/custom/pricing/pricing.cards.tsx"

# Look at pricing table implementation
echo -e "\nPricing Table Implementation:"
cat "apps/www/components/custom/pricing/pricing.table.tsx"

Length of output: 10757

apps/api/package.json (1)

21-21: Verify the cache integration

The addition of @repo/cache workspace dependency might affect the API's caching behavior.

Let's verify the cache package usage and integration:

✅ Verification successful

Cache integration is properly implemented

The @repo/cache dependency is correctly integrated and used in the API's status endpoints to retrieve latency history from Redis. The implementation shows:

  • Proper import and usage of the cache package
  • Consistent usage across status endpoints for both DB and site latency metrics
  • Integration with Redis via @upstash/redis and ioredis dependencies
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check how the cache package is being used in the API
rg -l "@repo/cache" --type ts --type tsx

# Look for cache-related configurations
fd "cache.config" --type ts --type tsx --type json

Length of output: 289


Script:

#!/bin/bash
# Check how the cache package is being used in the API, using ripgrep without file type filters
rg -l "@repo/cache"

# Look for cache-related configurations using fd without type filters
fd "cache"

# Check if there are any TypeScript files that import from @repo/cache
rg "import.*from.*@repo/cache"

Length of output: 490


Script:

#!/bin/bash
# Check the content of status.ts to understand cache usage
cat "apps/api/app/api/[[...route]]/status.ts"

# Check if cache was previously used (git history)
git log -p -- "apps/api/app/api/[[...route]]/status.ts"

# Check the cache package's exports
cat "packages/cache/package.json"

Length of output: 987

apps/www/components/ui/switch.tsx (4)

1-7: LGTM! Imports and directives are properly configured.

The necessary imports are present and the "use client" directive is correctly placed for client-side rendering.


8-11: Excellent TypeScript implementation!

The component is well-typed using proper generic types from Radix UI primitives and correctly implements ref forwarding.


27-29: LGTM! Proper component naming and export.

The display name is correctly set from the primitive component, which aids in debugging, and the export is clean.


1-29: Verify integration with PricingSwitch component.

Since this Switch component is used in the pricing feature, let's verify its integration with the PricingSwitch component.

✅ Verification successful

Switch component is properly integrated and used in the pricing feature

The verification shows that:

  • The Switch component is correctly imported and used in pricing.switch.tsx
  • PricingSwitch is properly integrated in the pricing page (apps/www/app/(routes)/pricing/page.tsx)
  • The implementation includes proper state management and callback handling for yearly billing changes
  • The component follows the expected usage pattern of the base Switch component
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the Switch component's integration with PricingSwitch
# and check for any other usages in the codebase

# Check for PricingSwitch implementation
echo "Checking PricingSwitch implementation..."
rg -A 10 "import.*Switch.*from.*switch" "apps/www/components/custom/pricing"

# Check for other Switch component usages
echo "Checking other Switch component usages..."
rg -l "import.*Switch.*from.*switch" --type tsx

Length of output: 1317


Script:

#!/bin/bash
# Let's try a different approach to find Switch component usage

# Check for PricingSwitch implementation with more context
echo "Checking PricingSwitch implementation with more context..."
rg -A 20 "import.*Switch.*from.*switch" .

# Find all tsx files that might use the Switch component
echo "Finding tsx files..."
fd -e tsx

# Search for Switch usage patterns in tsx files
echo "Checking Switch usage patterns..."
rg "Switch" -A 5 -g "*.tsx"

Length of output: 18809

.github/workflows/format-and-push.yml (1)

47-48: Verify turbo format configuration exists

Need to ensure that the format:write command is properly configured in turbo.json and works as expected.

✅ Verification successful

Turbo format configuration is properly set up

The verification shows that:

  • The format:write task is correctly configured in turbo.json
  • All workspace packages have the necessary format:write scripts that use prettier
  • The root package.json has the correct turbo command to run formatting across all packages
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify turbo format configuration exists and is properly set up

# Check if turbo.json exists and contains format:write configuration
if [ -f "turbo.json" ]; then
  echo "Checking turbo.json for format:write configuration..."
  jq '.pipeline.["format:write"]' turbo.json
else
  echo "Error: turbo.json not found"
  exit 1
fi

# Check if the format script exists in package.json files
echo "Checking for format scripts in package.json files..."
fd package.json --type f --exec jq '.scripts | select(.format != null or .["format:write"] != null)'

Length of output: 2533


Script:

#!/bin/bash
# Let's check the turbo.json content directly to verify the pipeline configuration
cat turbo.json

Length of output: 1062

apps/www/components/custom/text-morph.tsx (3)

1-11: LGTM! Well-structured imports and type definitions.

The component follows React best practices with proper TypeScript types and necessary imports.


1-60: Overall well-implemented animation component!

The TextMorph component demonstrates good practices:

  • Efficient use of React hooks (useMemo, useId)
  • Well-structured animation implementation
  • Type-safe props interface
  • Basic accessibility considerations

While there are opportunities for improvement, the core implementation is solid.


35-59: Consider performance optimization for long text.

While the animation implementation is solid, there are potential performance implications for long text strings. Consider these improvements:

  1. Add character length limit or pagination for very long strings
  2. Implement virtualization for large text
  3. Add ARIA live region for dynamic content

Let's check if this component is used with long text anywhere:

apps/www/app/(routes)/pricing/page.tsx (2)

10-11: LGTM! Clean import structure

The new imports follow the project's conventions and are properly organized within the pricing components directory.


15-15: Verify state propagation to child components

The isYearly state is correctly typed and initialized. However, let's verify its integration with child components.

✅ Verification successful

State propagation is properly implemented

The isYearly state is correctly integrated with child components:

  • PricingSwitch receives onYearlyBillingChange callback to control the state
  • PricingCards receives isYearly prop and uses it to display correct pricing values
  • Both components have proper TypeScript interfaces defining the props
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check if PricingCards and PricingSwitch components properly handle the isYearly prop
ast-grep --pattern 'interface $interface {
  $$$
  isYearly?: boolean;
  $$$
}'

# Verify the prop usage in components
ast-grep --pattern 'function PricingCards({ isYearly }: { isYearly: boolean }) {
  $$$
}'

Length of output: 173


Script:

#!/bin/bash
# Search for files containing PricingCards or PricingSwitch components
fd -e tsx -e ts "Pricing(Cards|Switch)"

# Check usage of isYearly prop in these components
rg "isYearly" -A 3 -B 3

# Look for any component that accepts isYearly prop
ast-grep --pattern 'export $_ function $_($props) {
  $$$
  isYearly
  $$$
}'

Length of output: 8620

apps/www/components/custom/pricing/pricing.cards.tsx (1)

15-19: Well-defined Props Interface for PricingCards Component

The introduction of the PCards interface and the inclusion of the isYearly prop enhance the component's clarity and type safety.

"hono": "^4.6.9",
"next": "15.0.2",
"next": "15.0.3",
Copy link

Choose a reason for hiding this comment

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

💡 Codebase verification

Next.js version inconsistency detected in root package.json

The root package.json is using Next.js version 15.0.2 while all applications (apps/www, apps/status, apps/api, apps/app) are using version 15.0.3. This inconsistency should be addressed to maintain version alignment across the monorepo.

  • package.json: version 15.0.2
  • All apps: version 15.0.3
🔗 Analysis chain

Verify Next.js update compatibility

The Next.js update from 15.0.2 to 15.0.3 is part of a coordinated update across multiple applications.

Let's verify the version consistency across the monorepo:

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check Next.js versions across all package.json files
fd package.json | xargs rg '"next":' -A 1

Length of output: 519


- name: Check for changes and push if needed
run: |
if [ -n "$(git status --porcelain)" ]; then
git config --global user.name "github-actions[bot]"
git config --global user.email "github-actions[bot]@users.noreply.github.com"
git add .
git commit -m "chore: format code with Prettier"
git commit -m "format: make the code prettier"
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Use conventional commit message format

The current commit message "format: make the code prettier" is less descriptive and doesn't follow the conventional commits specification properly.

Apply this diff to improve the commit message:

- git commit -m "format: make the code prettier"
+ git commit -m "style: format code with prettier"

This follows the Conventional Commits specification better by:

  1. Using "style" type for formatting changes
  2. Being more specific about the tool used
📝 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
git commit -m "format: make the code prettier"
git commit -m "style: format code with prettier"

Comment on lines 21 to 33
const characters = useMemo(() => {
const charCounts: Record<string, number> = {};

return children.split('').map((char, index) => {
const lowerChar = char.toLowerCase();
charCounts[lowerChar] = (charCounts[lowerChar] || 0) + 1;

return {
id: `${uniqueId}-${lowerChar}${charCounts[lowerChar]}`,
label: index === 0 ? char.toUpperCase() : lowerChar,
};
});
}, [children, uniqueId]);
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add input validation and optimize memory usage.

The character processing logic could be improved in several ways:

  1. Add validation for empty strings
  2. Handle special characters and emojis properly
  3. Optimize memory usage for the charCounts object
 const characters = useMemo(() => {
+  if (!children.trim()) {
+    return [];
+  }
   const charCounts: Record<string, number> = {};
+  const result = [];
 
-  return children.split('').map((char, index) => {
+  for (let i = 0; i < children.length; i++) {
+    const char = children[i];
     const lowerChar = char.toLowerCase();
     charCounts[lowerChar] = (charCounts[lowerChar] || 0) + 1;
 
-    return {
+    result.push({
       id: `${uniqueId}-${lowerChar}${charCounts[lowerChar]}`,
-      label: index === 0 ? char.toUpperCase() : lowerChar,
-    };
-  });
+      label: i === 0 ? char.toUpperCase() : lowerChar,
+    });
+  }
+  return result;
 }, [children, uniqueId]);
📝 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 characters = useMemo(() => {
const charCounts: Record<string, number> = {};
return children.split('').map((char, index) => {
const lowerChar = char.toLowerCase();
charCounts[lowerChar] = (charCounts[lowerChar] || 0) + 1;
return {
id: `${uniqueId}-${lowerChar}${charCounts[lowerChar]}`,
label: index === 0 ? char.toUpperCase() : lowerChar,
};
});
}, [children, uniqueId]);
const characters = useMemo(() => {
if (!children.trim()) {
return [];
}
const charCounts: Record<string, number> = {};
const result = [];
for (let i = 0; i < children.length; i++) {
const char = children[i];
const lowerChar = char.toLowerCase();
charCounts[lowerChar] = (charCounts[lowerChar] || 0) + 1;
result.push({
id: `${uniqueId}-${lowerChar}${charCounts[lowerChar]}`,
label: i === 0 ? char.toUpperCase() : lowerChar,
});
}
return result;
}, [children, uniqueId]);

Comment on lines +4 to +9
tier: "Free Forever",
discount: "100",
beforePrice: "19",
currency: "$",
priceMonthly: 0,
priceYearly: 0,
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Remove unnecessary pricing fields from the Basic (free) tier

The Basic tier is marked as "Free Forever" but includes discount and beforePrice fields, which could be misleading to users. These fields suggest a discounted price when the tier is meant to be free.

Consider this simplified structure:

  basic: {
    name: "Basic",
    tier: "Free Forever",
-   discount: "100",
-   beforePrice: "19",
    currency: "$",
    priceMonthly: 0,
    priceYearly: 0,
    features: [
📝 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
tier: "Free Forever",
discount: "100",
beforePrice: "19",
currency: "$",
priceMonthly: 0,
priceYearly: 0,
tier: "Free Forever",
currency: "$",
priceMonthly: 0,
priceYearly: 0,

Comment on lines 29 to 35
discountMonthly: 42.3,
discountYearly: 60.60,
beforePriceMonthly: 69,
beforePriceYearly: 69,
currency: "$",
price: 29,
priceMonthly: 29,
priceYearly: 279,
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix Plus tier yearly pricing calculation

The yearly pricing structure has several issues:

  1. The beforePriceYearly ($69) is incorrectly set to the same value as beforePriceMonthly
  2. The yearly discount (60.60%) doesn't align with the actual price reduction from the supposed yearly total

Suggested corrections:

    discountMonthly: 42.3,
    discountYearly: 60.60,
    beforePriceMonthly: 69,
-   beforePriceYearly: 69,
+   beforePriceYearly: 828, // $69 * 12 months
    currency: "$",
    priceMonthly: 29,
    priceYearly: 279,
📝 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
discountMonthly: 42.3,
discountYearly: 60.60,
beforePriceMonthly: 69,
beforePriceYearly: 69,
currency: "$",
price: 29,
priceMonthly: 29,
priceYearly: 279,
discountMonthly: 42.3,
discountYearly: 60.60,
beforePriceMonthly: 69,
beforePriceYearly: 828, // $69 * 12 months
currency: "$",
priceMonthly: 29,
priceYearly: 279,

Comment on lines +55 to +61
discountMonthly: 423.03,
discountYearly: 334.03,
beforePriceMonthly: 629,
beforePriceYearly: 659,
currency: "$",
price: 249,
priceMonthly: 249,
priceYearly: 679,
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix critical pricing calculation errors in Pro tier

There are several critical issues with the Pro tier pricing:

  1. The discount percentages (423.03% and 334.03%) are mathematically impossible as they exceed 100%
  2. The beforePriceYearly ($659) is less than beforePriceMonthly ($629)
  3. The yearly price ($679) is higher than the monthly price ($249) * 12 months, which contradicts common SaaS pricing models that offer discounts for yearly commitments

Suggested corrections (assuming a 20% yearly discount):

    discountMonthly: 423.03,
-   discountYearly: 334.03,
+   discountYearly: 20,
    beforePriceMonthly: 629,
-   beforePriceYearly: 659,
+   beforePriceYearly: 7548, // $629 * 12
    currency: "$",
    priceMonthly: 249,
-   priceYearly: 679,
+   priceYearly: 2390, // ($249 * 12) * 0.8 (20% discount)
📝 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
discountMonthly: 423.03,
discountYearly: 334.03,
beforePriceMonthly: 629,
beforePriceYearly: 659,
currency: "$",
price: 249,
priceMonthly: 249,
priceYearly: 679,
discountMonthly: 423.03,
discountYearly: 20,
beforePriceMonthly: 629,
beforePriceYearly: 7548,
currency: "$",
priceMonthly: 249,
priceYearly: 2390,

Comment on lines +31 to +44
<span className="text-xl align-bottom">
{pricingCardConfig.basic.currency}
</span>
{pricingCardConfig.basic.priceMonthly}
</span>
{/* <div className="flex flex-col text-lg gap-2 font-semibold">
<span className="line-through">$199</span>
<Badge className='bg-background text-primary'>
35% OFF
</Badge>
</div> */}
<div className="flex flex-col text-lg gap-2 font-semibold">
<span className="line-through">
{pricingCardConfig.basic.currency}
{pricingCardConfig.basic.beforePrice}
</span>
<Badge className="bg-background hover:bg-background text-primary">
{pricingCardConfig.basic.discount}% OFF
</Badge>
</div>
Copy link

Choose a reason for hiding this comment

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

💡 Codebase verification

🛠️ Refactor suggestion

Basic Plan Already Has Yearly Price Configuration - Implementation Missing

The review comment is correct. The pricing configuration (pricing.config.ts) shows that the Basic plan does have both priceMonthly and priceYearly fields (both set to 0), but the component isn't using the isYearly prop or AnimatedNumber component like the Plus and Pro cards do. This inconsistency in implementation should be addressed for better code maintainability and user experience consistency.

  • apps/www/components/custom/pricing/pricing.cards.tsx: Update the Basic pricing card to use AnimatedNumber and toggle between yearly/monthly prices like the other cards
  • apps/www/config/pricing.config.ts: Both priceMonthly and priceYearly are defined but not fully utilized in the component
🔗 Analysis chain

Inconsistent Pricing Logic in 'Plura Basic' Card

The 'Plura Basic' card currently displays only the monthly price and does not toggle between yearly and monthly pricing based on the isYearly prop, unlike the 'Plura Plus' and 'Plura Pro' cards. For consistency and a better user experience, consider implementing the same pricing logic using AnimatedNumber and the isYearly prop in the 'Plura Basic' card.

To confirm whether yearly pricing data exists for the 'Basic' plan in pricingCardConfig, run the following script:

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify if 'priceYearly' exists for 'basic' in pricingCardConfig

# Search for 'basic' pricing configurations that include 'priceYearly'
rg 'basic.*priceYearly'

Length of output: 25


Script:

#!/bin/bash
# Let's first find the pricing configuration file
fd -e ts -e tsx -e js -e jsx pricingCard

# Then let's examine its content to understand the pricing structure
rg -A 10 "basic.*price" 

Length of output: 1148


Script:

#!/bin/bash
# Let's find and examine the pricing configuration object definition
rg -B 5 -A 15 "pricingCardConfig.*=.*{" 

# Also search for any yearly price related code in pricing cards
rg -B 2 -A 2 "isYearly|priceYearly" apps/www/components/custom/pricing/pricing.cards.tsx

Length of output: 1699


Script:

#!/bin/bash
# Let's find the pricing configuration object with a corrected regex
rg -B 5 -A 15 'pricingCardConfig\s*=' 

# Also let's check if there are any other pricing-related configuration files
fd config -e ts -e tsx -e js -e jsx | rg -i pricing

Length of output: 1183

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

🧹 Outside diff range and nitpick comments (7)
apps/api/app/api/[[...route]]/user.ts (2)

12-18: LGTM, but consider adding error handling for the database query

The formatting changes improve readability. However, the database query could fail, and it's not handled explicitly.

Consider wrapping the database query in a try-catch:

-    const user = await prisma.user.findUnique({
-      where: {
-        id: currentUser.user.id,
-      },
-    });
+    try {
+      const user = await prisma.user.findUnique({
+        where: {
+          id: currentUser.user.id,
+        },
+      });
+      return c.json({ user }, 200);
+    } catch (error) {
+      return c.json(
+        { message: "Failed to fetch user data", status: 500 },
+        500
+      );
+    }

Also applies to: 30-30


77-77: Consider adding consistent error handling

While the formatting change is good, this endpoint could benefit from the same error handling pattern suggested for the /self endpoint.

Consider applying this pattern:

-    const user = await prisma.user.findUnique({
-      where: {
-        id: userId,
-      },
-    });
+    try {
+      const user = await prisma.user.findUnique({
+        where: {
+          id: userId,
+        },
+      });
+      if (!user) {
+        return c.json(
+          { message: "User not found", status: 404 },
+          404
+        );
+      }
+      return c.json({ user }, 200);
+    } catch (error) {
+      return c.json(
+        { message: "Failed to fetch user data", status: 500 },
+        500
+      );
+    }
apps/www/app/(routes)/pricing/page.tsx (3)

35-45: Consider extracting animation delay calculations to constants.

The multiplication of 0.2 with different numbers could be made more maintainable by using named constants.

+ const ANIMATION_BASE_DELAY = 0.2;
+ const PRICING_CARDS_DELAY = ANIMATION_BASE_DELAY * 3;
- <BlurFade delay={0.2 * 3} inView>
+ <BlurFade delay={PRICING_CARDS_DELAY} inView>

47-54: Consider moving border styles to a CSS class.

The border styling in the pricingTable section could be moved to a CSS class for better maintainability and reusability.

- className="flex items-center justify-center px-8 my-20 border-t-2 border-dashed w-full"
+ className="flex items-center justify-center px-8 my-20 w-full pricing-table-section"

Add to your CSS:

.pricing-table-section {
  @apply border-t-2 border-dashed;
}

20-55: Consider extracting common padding values to a CSS utility class.

The px-8 padding is duplicated across multiple elements. Consider creating a utility class for consistent padding.

+ // In your CSS
+ .section-padding {
+   @apply px-8;
+ }

- className="px-8 md:px-12"
+ className="section-padding md:px-12"

- className="flex items-center justify-center px-8 mb-20"
+ className="flex items-center justify-center section-padding mb-20"

- className="flex items-center justify-center px-8 my-20 border-t-2 border-dashed w-full"
+ className="flex items-center justify-center section-padding my-20 border-t-2 border-dashed w-full"
apps/www/config/pricing.config.ts (1)

Line range hint 11-24: Review pricing tier structure and features

Two structural issues need attention:

  1. All tiers currently have identical feature lists, which doesn't justify the price differences
  2. Features mention "1 year access" but the pricing is structured as monthly/yearly subscriptions, which is contradictory

Consider:

  1. Differentiating features across tiers to justify price differences
  2. Removing "1 year" mentions from features to align with the subscription model

Also applies to: 37-50, 63-76

apps/www/components/custom/pricing/pricing.cards.tsx (1)

104-142: LGTM! Consider extracting repeated spring options.

The implementation is solid with proper price animations and yearly/monthly toggle. However, the springOptions configuration is repeated multiple times.

Consider extracting the spring options to a constant:

+ const PRICE_ANIMATION_CONFIG = {
+   springOptions: {
+     bounce: 0,
+     duration: 2000,
+   },
+ };

// Then use it like:
<AnimatedNumber
-  springOptions={{
-    bounce: 0,
-    duration: 2000,
-  }}
+  {...PRICE_ANIMATION_CONFIG}
   value={isYearly ? price.yearly : price.monthly}
/>
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 62d1f50 and 60529ac.

📒 Files selected for processing (18)
  • .github/workflows/format-and-push.yml (2 hunks)
  • apps/api/app/api/[[...route]]/auth.ts (1 hunks)
  • apps/api/app/api/[[...route]]/user.ts (4 hunks)
  • apps/www/app/(routes)/contact/page.tsx (1 hunks)
  • apps/www/app/(routes)/features/page.tsx (1 hunks)
  • apps/www/app/(routes)/integrations/page.tsx (0 hunks)
  • apps/www/app/(routes)/methods/page.tsx (1 hunks)
  • apps/www/app/(routes)/pricing/page.tsx (1 hunks)
  • apps/www/components/custom/anim-numb.tsx (1 hunks)
  • apps/www/components/custom/navbar/navbar.tsx (1 hunks)
  • apps/www/components/custom/pricing/pricing.cards.tsx (3 hunks)
  • apps/www/components/custom/pricing/pricing.switch.tsx (1 hunks)
  • apps/www/components/custom/pricing/pricing.table.tsx (1 hunks)
  • apps/www/components/custom/site/header.tsx (2 hunks)
  • apps/www/components/custom/text-morph.tsx (1 hunks)
  • apps/www/components/ui/switch.tsx (1 hunks)
  • apps/www/config/pricing.config.ts (3 hunks)
  • apps/www/config/site.config.ts (1 hunks)
💤 Files with no reviewable changes (1)
  • apps/www/app/(routes)/integrations/page.tsx
✅ Files skipped from review due to trivial changes (6)
  • apps/api/app/api/[[...route]]/auth.ts
  • apps/www/app/(routes)/features/page.tsx
  • apps/www/app/(routes)/methods/page.tsx
  • apps/www/components/custom/navbar/navbar.tsx
  • apps/www/components/custom/site/header.tsx
  • apps/www/config/site.config.ts
🚧 Files skipped from review as they are similar to previous changes (5)
  • apps/www/components/custom/anim-numb.tsx
  • apps/www/components/custom/pricing/pricing.switch.tsx
  • apps/www/components/custom/pricing/pricing.table.tsx
  • apps/www/components/custom/text-morph.tsx
  • apps/www/components/ui/switch.tsx
🧰 Additional context used
🪛 actionlint (1.7.4)
.github/workflows/format-and-push.yml

53-53: "github.head_ref" is potentially untrusted. avoid using it directly in inline scripts. instead, pass it through an environment variable. see https://docs.github.com/en/actions/security-guides/security-hardening-for-github-actions for more details

(expression)

🔇 Additional comments (15)
.github/workflows/format-and-push.yml (4)

Line range hint 1-14: LGTM! Branch patterns and permissions are well configured.

The workflow trigger configuration properly handles both direct pushes and pull requests, with appropriate branch patterns for feature and bugfix branches.


46-47: Previous review comment is still applicable

The current installation approach still has the issues mentioned in the previous review.


58-58: Previous review comment about commit message format is still applicable

The commit message still doesn't follow conventional commits specification.


49-50: Verify turbo configuration for format:write command

Ensure that the format:write command is properly configured in turbo.json.

✅ Verification successful

Let me verify if there are any format-related scripts defined in the package.json files.


The format:write command is properly configured in the workspace

The command is correctly set up:

  • Root package.json defines format:write script that uses Turbo to run the command across the workspace
  • Multiple apps (api, app, www) have the format:write script configured to run Prettier
  • The command will format TypeScript, TSX, and MDX files using Prettier with caching enabled
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify turbo configuration for format:write command

# Check if format:write is configured in turbo.json
if [ -f "turbo.json" ]; then
  cat turbo.json | jq '.pipeline."format:write"'
else
  echo "turbo.json not found"
  exit 1
fi

Length of output: 77


Script:

#!/bin/bash
# Search for format-related scripts in package.json files
fd package.json --exec sh -c 'echo "=== $1 ==="; cat "$1" | jq .scripts | grep -i "format"' sh {}

Length of output: 1073

apps/api/app/api/[[...route]]/user.ts (1)

3-3: LGTM!

The import and export statement changes improve readability while maintaining functionality.

Also applies to: 81-81

apps/www/app/(routes)/pricing/page.tsx (2)

10-15: LGTM! Clean implementation of imports and state management.

The new imports and state management are well-structured, with clear naming conventions and proper initialization of the yearly pricing state.


40-42: Verify accessibility of the pricing toggle.

Ensure that the PricingSwitch component implements proper ARIA attributes and keyboard navigation for accessibility compliance.

✅ Verification successful

The pricing toggle implementation meets accessibility requirements

The component is built using Radix UI's Switch primitive (@radix-ui/react-switch), which provides built-in accessibility features including:

  • Proper ARIA attributes and roles
  • Keyboard navigation support
  • Focus management
  • Screen reader compatibility

Additionally, the implementation includes:

  • Proper label association using htmlFor/id attributes
  • Focus visible styles for keyboard navigation
  • Disabled states styling
  • Clear visual feedback for state changes
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check if PricingSwitch component implements necessary accessibility attributes

# Search for ARIA attributes and keyboard event handlers in the PricingSwitch component
ast-grep --pattern 'aria-$_' components/custom/pricing/pricing.switch.tsx
ast-grep --pattern 'onKeyDown|onKeyPress|role=' components/custom/pricing/pricing.switch.tsx

Length of output: 354


Script:

#!/bin/bash
# First, let's find the correct location of the PricingSwitch component
fd -t f "pricing.*switch" --full-path

# Then search for the component definition and its accessibility attributes
rg -i "pricingswitch|pricing.*switch" -A 10

Length of output: 3362


Script:

#!/bin/bash
# Let's check the content of the PricingSwitch component to see the Switch implementation
cat apps/www/components/custom/pricing/pricing.switch.tsx

# Also check if there's a custom Switch component being used
fd -t f "switch" --full-path | grep -v "pricing.switch"

Length of output: 1086


Script:

#!/bin/bash
# Let's check the implementation of the base Switch component
cat apps/www/components/ui/switch.tsx

Length of output: 1210

apps/www/config/pricing.config.ts (3)

4-9: Remove unnecessary pricing fields from the Basic (free) tier

The Basic tier is marked as "Free Forever" but includes discount and beforePrice fields, which could be misleading to users. These fields suggest a discounted price when the tier is meant to be free.


55-61: ⚠️ Potential issue

Fix critical Pro tier pricing errors

Several critical issues found in the Pro tier pricing structure:

  1. The monthly discount of 423.03% is mathematically impossible (actual savings is 60.4%)
  2. The yearly pricing structure is problematic:
    • beforePriceYearly ($659) is less than beforePriceMonthly ($629)
    • Yearly price ($679) is higher than monthly price ($249 * 12 = $2,988)
    • 334.03% discount is mathematically impossible

Apply this diff to fix the calculations (assuming a 20% yearly discount):

-   discountMonthly: 423.03,
+   discountMonthly: 60.4,
-   discountYearly: 334.03,
+   discountYearly: 20,
    beforePriceMonthly: 629,
-   beforePriceYearly: 659,
+   beforePriceYearly: 7548,
    currency: "$",
    priceMonthly: 249,
-   priceYearly: 679,
+   priceYearly: 2390,

Likely invalid or redundant comment.


29-35: ⚠️ Potential issue

Fix Plus tier yearly pricing calculations

There are inconsistencies in the yearly pricing structure:

  1. The beforePriceYearly ($69) is incorrectly set to the monthly value instead of the annual total ($828 = $69 * 12)
  2. The yearly discount (60.60%) doesn't match the actual savings of 66.3% (($828 - $279) / $828 * 100)

Apply this diff to fix the calculations:

    discountMonthly: 42.3,
-   discountYearly: 60.6,
+   discountYearly: 66.3,
    beforePriceMonthly: 69,
-   beforePriceYearly: 69,
+   beforePriceYearly: 828,
    currency: "$",
    priceMonthly: 29,
    priceYearly: 279,

Likely invalid or redundant comment.

apps/www/app/(routes)/contact/page.tsx (1)

1-12: LGTM! Well-organized imports

The imports are properly grouped and formatted for better readability.

apps/www/components/custom/pricing/pricing.cards.tsx (4)

12-17: LGTM! Clean interface and imports.

The new imports and interface definition are well-structured and properly typed.


19-19: LGTM! Component signature properly updated.

The component now correctly accepts the isYearly prop as defined in the PCards interface.


202-240: Implementation matches Plus card pattern.

The Pro card implementation correctly follows the same pattern as the Plus card.


31-44: ⚠️ Potential issue

Basic plan pricing implementation is inconsistent with other plans.

The Basic plan's pricing display doesn't follow the same pattern as Plus and Pro plans:

  1. Missing yearly/monthly price toggle based on isYearly prop
  2. Not using AnimatedNumber for smooth price transitions

Apply this diff to maintain consistency:

- <span className="text-xl align-bottom">
-   {pricingCardConfig.basic.currency}
- </span>
- {pricingCardConfig.basic.priceMonthly}
+ <span className="text-xl align-bottom">
+   {pricingCardConfig.basic.currency}
+ </span>
+ <AnimatedNumber
+   springOptions={{
+     bounce: 0,
+     duration: 2000,
+   }}
+   value={
+     isYearly
+       ? pricingCardConfig.basic.priceYearly
+       : pricingCardConfig.basic.priceMonthly
+   }
+ />

Also add the billing period text:

- <p className="text-xs">{pricingCardConfig.basic.tier}</p>
+ <p className="text-xs inline-flex gap-1">
+   Billed
+   <TextMorph>{isYearly ? "Yearly" : "Monthly"}</TextMorph>
+ </p>

Comment on lines +23 to +24
with:
ref: ${{ github.head_ref }} # Checkout the PR branch
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Enhance security by using environment variable for branch reference

The direct use of github.head_ref in scripts can be a security risk. It's recommended to pass it through an environment variable.

Apply this diff to improve security:

- ref: ${{ github.head_ref }}  # Checkout the PR branch
+ ref: ${{ github.event.pull_request.head.ref }}

Also, add input sanitization:

- name: Validate branch name
  run: |
    BRANCH_NAME="${{ github.event.pull_request.head.ref }}"
    if [[ ! $BRANCH_NAME =~ ^(feat|bugfix)/.+ || $BRANCH_NAME == "main" ]]; then
      echo "Invalid branch name: $BRANCH_NAME"
      exit 1
    fi

git commit -m "chore: format code with Prettier"
git push
git commit -m "format: make the code prettier"
git push origin ${{ github.head_ref }}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Secure the git push command

Similar to the checkout step, using github.head_ref directly in the push command is a security risk.

Apply this diff to improve security:

- git push origin ${{ github.head_ref }}
+ git push origin "$SAFE_BRANCH_NAME"

Add this before the push command:

SAFE_BRANCH_NAME="${{ github.event.pull_request.head.ref }}"
if [[ ! $SAFE_BRANCH_NAME =~ ^(feat|bugfix)/.+ || $SAFE_BRANCH_NAME == "main" ]]; then
  echo "Invalid branch name for push: $SAFE_BRANCH_NAME"
  exit 1
fi

);
})
.get("/all", async (c) => {
const cursor = c.req.query("cursor");
const take = c.req.query("take");
if (!c.req.url.includes("?cursor=")) {
return c.redirect("?cursor=");
return c.redirect("?cursor=");
Copy link

Choose a reason for hiding this comment

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

💡 Codebase verification

⚠️ Potential issue

Pagination implementation needs revision for better reliability and standards compliance

The code inspection confirms the concerns raised in the review comment. The current implementation has several issues:

  1. The redirect on missing cursor (?cursor=) is indeed problematic as:

    • It's not RESTful - APIs should return proper status codes and error messages
    • It could cause infinite redirects if not handled properly by clients
    • It makes the cursor parameter mandatory when it should be optional for initial page fetch
  2. The skip: 1 is arbitrary and breaks cursor-based pagination:

    • With cursor-based pagination, skip shouldn't be used as the cursor itself handles the offset
    • Skipping the first record on every request will lead to missing data
  3. The take parameter lacks validation and proper defaults:

    • No bounds checking could lead to performance issues
    • Silent fallback to 10 without validation

The suggested improvements in the review comment are valid and would make the implementation more robust and standards-compliant.

🔗 Analysis chain

Review and revise the pagination implementation

Several concerns with the current implementation:

  1. Redirecting on missing cursor parameter is unusual for a REST API
  2. Hardcoded skip: 1 seems arbitrary and could cause issues
  3. The take parameter parsing lacks validation

Consider this improved implementation:

-    if (!c.req.url.includes("?cursor=")) {
-      return c.redirect("?cursor=");
-    }
+    const take = parseInt(take!) || 10;
+    if (isNaN(take) || take < 1 || take > 100) {
+      return c.json(
+        { message: "Invalid take parameter. Must be between 1 and 100", status: 400 },
+        400
+      );
+    }

     const users = await prisma.user.findMany({
-      take: parseInt(take!) || 10,
-      skip: 1,
+      take: take,
       cursor: cursor
         ? {
             id: cursor,
           }
         : undefined,
     });

Let's verify the usage of this endpoint:

Also applies to: 43-47

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for calls to this endpoint to understand pagination usage
rg -l "\/api\/.*\/user\/all" --type ts

Length of output: 127


Script:

#!/bin/bash
# Search for API calls to user/all endpoint with proper escaping
rg -l "/api/.*/user/all" --type ts

# Search for any references to this endpoint pattern
rg -l "user/all" --type ts

# Look for fetch/axios calls that might be using this endpoint
ast-grep --pattern 'fetch($$$"/user/all"$$$)'
ast-grep --pattern 'axios.$_($$$"/user/all"$$$)'

Length of output: 162


Script:

#!/bin/bash
# Let's examine the route handler file content to understand the full context
cat "apps/api/app/api/[[...route]]/user.ts"

# Look for any pagination-related patterns in the codebase
rg "findMany.*take.*skip" --type ts -A 2

# Check for other similar route handlers that might use pagination
fd "route" -e ts -x cat {} 

Length of output: 2550

Comment on lines +33 to +78
<div className="grid grid-cols-1 md:grid-cols-3 px-8 md:px-20">
<Card className="border-none">
<CardHeader>
<CardTitle className="text-xl">Join the community</CardTitle>
</CardHeader>
<CardContent className="text-sm text-muted-foreground">
<p>
More than 10,000 Linear users share questions and best
practices in our Slack community.
</p>
</CardContent>
<CardFooter>
<p>Card Footer</p>
</CardFooter>
</Card>

<Card className="border-none">
<CardHeader>
<CardTitle className="text-xl">Join the community</CardTitle>
</CardHeader>
<CardContent className="text-sm text-muted-foreground">
<p>More than 10,000 Linear users share questions and best practices in our Slack community.</p>
</CardContent>
<CardFooter>
<p>Card Footer</p>
</CardFooter>
</Card>
<Card className="border-none">
<CardHeader>
<CardTitle className="text-xl">Join the community</CardTitle>
</CardHeader>
<CardContent className="text-sm text-muted-foreground">
<p>
More than 10,000 Linear users share questions and best
practices in our Slack community.
</p>
</CardContent>
<CardFooter>
<p>Card Footer</p>
</CardFooter>
</Card>

<Card className="border-none">
<CardHeader>
<CardTitle className="text-xl">Join the community</CardTitle>
</CardHeader>
<CardContent className="text-sm text-muted-foreground">
<p>
More than 10,000 Linear users share questions and best
practices in our Slack community.
</p>
</CardContent>
<CardFooter>
<p>Card Footer</p>
</CardFooter>
</Card>
</div>
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Refactor duplicate card components

The three cards are identical in structure and content, which violates the DRY principle. Consider creating a reusable component and mapping over an array of data.

Here's a suggested refactor:

type ContactCardProps = {
  title: string;
  description: string;
  footer: string;
};

const ContactCard = ({ title, description, footer }: ContactCardProps) => (
  <Card className="border-none">
    <CardHeader>
      <CardTitle className="text-xl">{title}</CardTitle>
    </CardHeader>
    <CardContent className="text-sm text-muted-foreground">
      <p>{description}</p>
    </CardContent>
    <CardFooter>
      <p>{footer}</p>
    </CardFooter>
  </Card>
);

// Usage:
const cardData = [
  {
    title: "Join the community",
    description: "More than 10,000 Linear users share questions and best practices in our Slack community.",
    footer: "Card Footer"
  },
  // ... add data for other cards
];

<div className="grid grid-cols-1 md:grid-cols-3 px-8 md:px-20">
  {cardData.map((data, index) => (
    <ContactCard key={index} {...data} />
  ))}
</div>

Comment on lines +40 to +41
More than 10,000 Linear users share questions and best
practices in our Slack community.
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Update card content to match your product

The cards reference "Linear users", which appears to be copied content from another product. Update the content to be relevant to your product and users.

Also applies to: 55-56, 70-71

</p>
</CardContent>
<CardFooter>
<p>Card Footer</p>
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Replace footer placeholder text

All cards contain placeholder text "Card Footer". Replace with meaningful content such as action buttons, links, or relevant information.

Also applies to: 60-60, 75-75

<p>Card Footer</p>
</CardFooter>
</Card>
<Card className="w-3/6 m-10">Ok beb</Card>
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Replace placeholder card content

The card contains placeholder text "Ok beb" which should be replaced with meaningful content appropriate for a contact page.

Consider adding a contact form or relevant contact information. Example structure:

-<Card className="w-3/6 m-10">Ok beb</Card>
+<Card className="w-3/6 m-10">
+  <CardHeader>
+    <CardTitle>Get in Touch</CardTitle>
+  </CardHeader>
+  <CardContent>
+    {/* Add contact form or contact information here */}
+  </CardContent>
+</Card>

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Revamping landing page.
1 participant