-
-
Notifications
You must be signed in to change notification settings - Fork 11
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
Conversation
The latest updates on your projects. Learn more about Vercel for Git ↗︎
|
WalkthroughThe pull request introduces several changes across multiple Changes
Possibly related PRs
📜 Recent review detailsConfiguration used: CodeRabbit UI 📒 Files selected for processing (1)
🔇 Additional comments (5)apps/www/app/(routes)/pricing/page.tsx (5)
The imports are correctly organized and support the new pricing toggle functionality.
The state implementation is well-typed and initialized with a sensible default value.
The component structure is clean and organized:
Please ensure that:
✅ Verification successfulLet me try a different search pattern to locate these components. Both components are properly implemented and working as expected The verification confirms that:
🏁 Scripts executedThe 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
The section ID has changed from "pricing" to "pricingCards". Please ensure this doesn't break any existing:
✅ Verification successfulSection ID change appears safe to proceed The search results show that all references to "pricing" in the codebase are route/path related (
🏁 Scripts executedThe 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? 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
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)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this 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:
- Making it depend on upstream type definitions:
"dependsOn": ["^typecheck"]
- 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 ProductionThe 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 pipelineThe 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
📒 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:3002apps/status
: dev port 3004 → react-scan localhost:3004apps/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" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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" |
There was a problem hiding this comment.
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.
There was a problem hiding this 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.
- Make the initial state configurable via props
- 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.
- The transition duration and colors should be extracted to constants/design tokens
- 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 improvementsSeveral architectural improvements could enhance the workflow:
- Limit write permissions scope:
permissions: contents: write pull-requests: read
- 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
- 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 valuesThe 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 improvementsThe 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 optimizationsSince this is a client component with multiple animated sections, consider:
- Lazy loading the PricingTable component as it might not be immediately visible
- 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 configurationTo 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:
- Discount percentages are between 0-100%
- Yearly prices reflect annual calculations
- Pricing tiers maintain logical progression
- Currency consistency across tiers
apps/www/components/custom/pricing/pricing.cards.tsx (2)
106-110
: Refactor RepeatedspringOptions
into a ConstantThe
springOptions
object is repeated multiple times with the same values in theAnimatedNumber
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 ComponentThere 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
⛔ 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 proponYearlyBillingChange
- The state is correctly propagated to
PricingCards
component which uses theisYearly
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
andioredis
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:
- Add character length limit or pagination for very long strings
- Implement virtualization for large text
- 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", |
There was a problem hiding this comment.
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" |
There was a problem hiding this comment.
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:
- Using "style" type for formatting changes
- 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.
git commit -m "format: make the code prettier" | |
git commit -m "style: format code with prettier" |
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]); |
There was a problem hiding this comment.
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:
- Add validation for empty strings
- Handle special characters and emojis properly
- 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.
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]); |
tier: "Free Forever", | ||
discount: "100", | ||
beforePrice: "19", | ||
currency: "$", | ||
priceMonthly: 0, | ||
priceYearly: 0, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
tier: "Free Forever", | |
discount: "100", | |
beforePrice: "19", | |
currency: "$", | |
priceMonthly: 0, | |
priceYearly: 0, | |
tier: "Free Forever", | |
currency: "$", | |
priceMonthly: 0, | |
priceYearly: 0, |
apps/www/config/pricing.config.ts
Outdated
discountMonthly: 42.3, | ||
discountYearly: 60.60, | ||
beforePriceMonthly: 69, | ||
beforePriceYearly: 69, | ||
currency: "$", | ||
price: 29, | ||
priceMonthly: 29, | ||
priceYearly: 279, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix Plus tier yearly pricing calculation
The yearly pricing structure has several issues:
- The
beforePriceYearly
($69) is incorrectly set to the same value asbeforePriceMonthly
- 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.
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, |
discountMonthly: 423.03, | ||
discountYearly: 334.03, | ||
beforePriceMonthly: 629, | ||
beforePriceYearly: 659, | ||
currency: "$", | ||
price: 249, | ||
priceMonthly: 249, | ||
priceYearly: 679, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix critical pricing calculation errors in Pro tier
There are several critical issues with the Pro tier pricing:
- The discount percentages (423.03% and 334.03%) are mathematically impossible as they exceed 100%
- The
beforePriceYearly
($659) is less thanbeforePriceMonthly
($629) - 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.
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, |
<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> |
There was a problem hiding this comment.
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 useAnimatedNumber
and toggle between yearly/monthly prices like the other cardsapps/www/config/pricing.config.ts
: BothpriceMonthly
andpriceYearly
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
There was a problem hiding this 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 queryThe 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 handlingWhile 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 featuresTwo structural issues need attention:
- All tiers currently have identical feature lists, which doesn't justify the price differences
- Features mention "1 year access" but the pricing is structured as monthly/yearly subscriptions, which is contradictory
Consider:
- Differentiating features across tiers to justify price differences
- 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
📒 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
definesformat:write
script that uses Turbo to run the command across the workspace - Multiple apps (
api
,app
,www
) have theformat: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
:
Fix critical Pro tier pricing errors
Several critical issues found in the Pro tier pricing structure:
- The monthly discount of 423.03% is mathematically impossible (actual savings is 60.4%)
- The yearly pricing structure is problematic:
beforePriceYearly
($659) is less thanbeforePriceMonthly
($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
:
Fix Plus tier yearly pricing calculations
There are inconsistencies in the yearly pricing structure:
- The
beforePriceYearly
($69) is incorrectly set to the monthly value instead of the annual total ($828 = $69 * 12) - 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
:
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:
- Missing yearly/monthly price toggle based on isYearly prop
- 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>
with: | ||
ref: ${{ github.head_ref }} # Checkout the PR branch |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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 }} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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="); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Codebase verification
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:
-
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
-
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
- With cursor-based pagination,
-
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:
- Redirecting on missing cursor parameter is unusual for a REST API
- Hardcoded
skip: 1
seems arbitrary and could cause issues - 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
<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> |
There was a problem hiding this comment.
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>
More than 10,000 Linear users share questions and best | ||
practices in our Slack community. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Summary by CodeRabbit
Release Notes
New Features
react-scan
script for easier tool execution in multiple applications.PricingSwitch
component allowing users to toggle between yearly and monthly billing options.AnimatedNumber
andTextMorph
components for enhanced pricing display animations.Improvements
PricingCards
component to dynamically display pricing based on selected billing cycle.Bug Fixes