Skip to content

Discord Social Auth & Settings Base#19

Merged
mezotv merged 21 commits intomainfrom
woofer21/wy-152
Mar 29, 2025
Merged

Discord Social Auth & Settings Base#19
mezotv merged 21 commits intomainfrom
woofer21/wy-152

Conversation

@Woofer21
Copy link
Member

@Woofer21 Woofer21 commented Mar 28, 2025

Implements the discord social auth and the settings page base.

Logged Out User
image

Logged In User & Dropdown
image

Language & Settings Sub-menus
image
image

Profile Settings Base & Privacy Settings Base
image
image

Summary by CodeRabbit

  • New Features

    • Introduced a permanent redirect from the settings page to the profile page, streamlining navigation.
    • Added dedicated Profile and Privacy pages with an improved settings layout and intuitive sidebar.
    • Enhanced the Discord login experience with a dynamic dropdown that offers account management, language options, and subscription controls.
  • UI Enhancements

    • Upgraded interactive menus and dropdowns with refined styling and responsive visual feedback.
    • Expanded translation labels for clearer navigation and a more accessible user interface.

@linear
Copy link

linear bot commented Mar 28, 2025

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 28, 2025

Walkthrough

This pull request introduces several new features and updates across the project. A new redirect rule is added in the Next.js configuration, and additional dependencies are included via package.json. Multiple new components and pages for settings (layout, privacy, profile) are implemented, along with a redesigned sidebar and updated Discord login functionality. Enhancements include the integration of a ReactScan component into the provider, improvements to context menus, dropdowns, and skeleton loaders. The authentication configuration is augmented with plugins and additional user fields, the Prisma schema is updated along with a migration script, and environment variable configurations are extended. Legacy components are removed.

Changes

Files Change Summary
next.config.ts Added a new redirect rule: /settings/settings/profile (permanent)
package.json Added dependencies: @radix-ui/react-context-menu@^2.2.6 and react-scan@^0.3.3
src/app/(app)/settings/{layout.tsx,privacy/page.tsx,profile/page.tsx} Introduced new settings page components: a SettingsLayout with sidebar, PrivacyPage, and ProfilePage
src/app/(marketing)/page.tsx Updated API call: switched to env.UPSTASH_API_KEY/env.UPSTASH_URL with refined error handling
src/app/providers.tsx
src/components/react-scan.tsx
Integrated ReactScan: added as standalone component and rendered within Providers
src/components/(app)/settings/sidebar.tsx Added new SettingsSidebar component with conditional rendering for sidebar items
src/components/(marketing)/discord-login.tsx
src/components/i18n/locale-switcher.tsx
Removed legacy DiscordLoginButton and LocaleSwitcher components
src/components/discord-login.tsx
src/components/navbar.tsx
Added a new DiscordLoginButton (with dropdown and session management) and updated its import path in the navbar
src/components/ui/{context-menu.tsx,dropdown-menu.tsx,skeleton.tsx} Introduced new context menu components, updated dropdown menu (icon changes, new alwaysLeft prop), and implemented a Skeleton loader
src/env.ts
.env.example
.github/workflows/build-code.yml
Extended environment variables: added UPSTASH_URL, BETTER_AUTH_SECRET, BETTER_AUTH_URL, and DATABASE_URL; updated CI configuration
src/lib/{auth-client.ts,auth.ts} Enhanced auth configuration: added plugins to authClient and updated user management (deleteUser enabled, additional locale and emailVerified fields)
prisma/migrations/.../migration.sql
prisma/schema.prisma
Updated database schema: dropped language column and added/renamed to non-nullable locale with default 'en'
src/i18n/translations/en.json Expanded translations to include new nested structures for navigation and settings (profile, sidebar items)

Sequence Diagram(s)

sequenceDiagram
    participant U as User
    participant DLB as DiscordLoginButton
    participant AC as authClient
    participant DP as Discord Provider

    U->>DLB: Click login button
    alt No session exists
        DLB->>AC: Call signIn.social("discord")
        AC->>DP: Request authentication
        DP-->>AC: Return auth response
        AC-->>DLB: Provide session data
    else Session pending or active
        DLB-->>U: Display dropdown menu with account options
    end
Loading

Poem

Oh, I hopped through lines of code,
Adding routes and pages on the go.
New menus and loaders in a stylish parade,
Auth flows refined, environment variables made.
With a twitch of my whiskers and a joyful bound,
I celebrate these changes – solutions profound!
Hop along, code friends, let’s keep the rhythm sound! 🐇✨


📜 Recent review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 6549e40 and 45acf55.

📒 Files selected for processing (4)
  • .env.example (1 hunks)
  • .github/workflows/build-code.yml (1 hunks)
  • src/app/(marketing)/page.tsx (2 hunks)
  • src/env.ts (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • .env.example
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/app/(marketing)/page.tsx
🔇 Additional comments (2)
src/env.ts (1)

8-12: Environment variables added for authentication and database support.

These new environment variables align with the PR objective of implementing Discord social authentication and setting up the necessary infrastructure. The URL validation for UPSTASH_URL and BETTER_AUTH_URL is a good practice to ensure proper formatting.

Additional safety notes:

  • Ensure these environment variables are properly set in all deployment environments
  • Verify that the .env.example file includes these new variables to guide other developers
.github/workflows/build-code.yml (1)

48-48: Added UPSTASH_URL environment variable to the build workflow.

This addition properly corresponds to the new environment variable defined in src/env.ts, ensuring the build process has access to all required configuration values.

✨ Finishing Touches
  • 📝 Generate Docstrings

🪧 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 generate docstrings to generate docstrings for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai plan to trigger planning for file edits and PR creation.
  • @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.

@Woofer21 Woofer21 marked this pull request as ready for review March 28, 2025 23:49
@Woofer21 Woofer21 requested review from dpaulos6 and taqh as code owners March 28, 2025 23:49
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 8

🧹 Nitpick comments (8)
src/app/(app)/settings/profile/page.tsx (1)

1-7: Basic skeleton established for the Profile settings page

This component establishes the foundation for the profile settings page, aligning with the PR objective of creating a settings base. While currently minimal, it serves as a good starting point.

Consider adding more structure or at least TODO comments to indicate what functionality will be implemented in future PRs. This would help other developers understand the intended features for this page.

src/app/(app)/settings/privacy/page.tsx (1)

1-7: Basic skeleton established for the Privacy settings page

This component establishes the foundation for the privacy settings page, consistent with the profile page structure and the overall settings base objective of the PR.

Consider adding more structure or at least TODO comments to indicate what privacy settings will be implemented here. This would provide clarity on the planned functionality and help with future development.

src/components/(app)/settings/sidebar.tsx (1)

36-58: Consider making sidebar items more dynamic.

The sidebar item implementation is clean and reusable. For future scalability, consider extracting the navigation items into a configuration array that can be mapped over, making it easier to add more settings pages later.

export default function SettingsSidebar() {
	const pathname = usePathname();

+	const navItems = [
+		{
+			href: "/settings/profile",
+			icon: <User className="size-4" />,
+			label: "Profile"
+		},
+		{
+			href: "/settings/privacy",
+			icon: <ShieldUser className="size-4" />,
+			label: "Privacy"
+		}
+	];

	return (
		<div className="w-full rounded-xl border border-border bg-card px-4 py-4">
			<p className="mb-2 px-4 text-muted-foreground">Account Settings</p>
			<ul className="flex flex-col gap-1">
-				<SettingsSidebarItem
-					href={"/settings/profile"}
-					selected={pathname === "/settings/profile"}
-				>
-					<User className="size-4" />
-					Profile
-				</SettingsSidebarItem>
-				<SettingsSidebarItem
-					href={"/settings/privacy"}
-					selected={pathname === "/settings/privacy"}
-				>
-					<ShieldUser className="size-4" />
-					Privacy
-				</SettingsSidebarItem>
+				{navItems.map((item) => (
+					<SettingsSidebarItem
+						key={item.href}
+						href={item.href}
+						selected={pathname === item.href}
+					>
+						{item.icon}
+						{item.label}
+					</SettingsSidebarItem>
+				))}
			</ul>
		</div>
	);
}
src/components/ui/dropdown-menu.tsx (1)

217-223: New alwaysLeft prop enhances menu flexibility.

The alwaysLeft prop with conditional chevron rendering is a good addition for supporting different menu orientations. Consider adding a brief comment explaining its purpose for better maintainability.

interface DropdownMenuSubTriggerProps extends ComponentProps<typeof DropdownMenuPrimitive.SubTrigger> {
  inset?: boolean;
+ // Controls chevron direction - useful for RTL layouts or left-opening submenus
  alwaysLeft?: boolean;
}

Also applies to: 234-236

src/components/discord-login.tsx (3)

78-81: Navigation missing for Profile menu item

The Profile menu item at lines 78-81 doesn't have any navigation or click handler, unlike other menu items that use Link components.

Add a Link component to navigate to the user profile page:

-<DropdownMenuItem>
-  <User className="size-4" />
-  Profile
-</DropdownMenuItem>
+<Link href="/profile">
+  <DropdownMenuItem>
+    <User className="size-4" />
+    Profile
+  </DropdownMenuItem>
+</Link>

159-162: Missing navigation for Subscription management

The "Manage Subscription" menu item doesn't have a navigation link or click handler.

Add a Link component or click handler for subscription management:

-<DropdownMenuItem>
-  <CreditCard className="size-4" />
-  Manage Subscription
-</DropdownMenuItem>
+<Link href="/settings/subscription">
+  <DropdownMenuItem>
+    <CreditCard className="size-4" />
+    Manage Subscription
+  </DropdownMenuItem>
+</Link>

131-139: Nested navigation pattern may be confusing

The Settings link is wrapped in a dropdown submenu trigger, which is unconventional. Typically, clicking on "Settings" would navigate directly to the settings page rather than opening a submenu.

Consider separating the navigation and submenu functionality:

-<DropdownMenuSubTrigger>
-  <Link
-    href={"/settings"}
-    className="flex w-full items-center gap-2"
-  >
-    <Settings className="size-4 text-muted-foreground" />
-    Settings
-  </Link>
-</DropdownMenuSubTrigger>
+<DropdownMenuItem asChild>
+  <Link
+    href={"/settings"}
+    className="flex w-full items-center gap-2"
+  >
+    <Settings className="size-4 text-muted-foreground" />
+    Settings
+  </Link>
+</DropdownMenuItem>
+<DropdownMenuSub>
+  <DropdownMenuSubTrigger>
+    <Settings className="size-4 text-muted-foreground" />
+    Settings Options
+  </DropdownMenuSubTrigger>
src/components/ui/context-menu.tsx (1)

88-90: Consider breaking long className strings into multiple lines

The className strings are very long and difficult to read, which makes maintenance harder.

Break up long className strings for better readability:

-className={cn(
-  "focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground flex cursor-default items-center rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
-  className
-)}
+className={cn(
+  [
+    "cursor-default flex items-center outline-hidden px-2 py-1.5 rounded-sm select-none text-sm",
+    "focus:bg-accent focus:text-accent-foreground",
+    "data-[state=open]:bg-accent data-[state=open]:text-accent-foreground",
+    "data-[inset]:pl-8",
+    "[&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4"
+  ],
+  className
+)}
🧰 Tools
🪛 GitHub Actions: Format & Lint Code

[error] 88-88: lint/nursery/useSortedClasses: These CSS classes should be sorted.

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 5f97b25 and 6130d2f.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (21)
  • next.config.ts (1 hunks)
  • package.json (2 hunks)
  • prisma/migrations/20250327233403_changed_language_to_locale/migration.sql (1 hunks)
  • prisma/migrations/20250327234009_revert/migration.sql (1 hunks)
  • src/app/(app)/settings/layout.tsx (1 hunks)
  • src/app/(app)/settings/privacy/page.tsx (1 hunks)
  • src/app/(app)/settings/profile/page.tsx (1 hunks)
  • src/app/(marketing)/page.tsx (2 hunks)
  • src/app/providers.tsx (2 hunks)
  • src/components/(app)/settings/sidebar.tsx (1 hunks)
  • src/components/(marketing)/discord-login.tsx (0 hunks)
  • src/components/discord-login.tsx (1 hunks)
  • src/components/i18n/locale-switcher.tsx (0 hunks)
  • src/components/navbar.tsx (1 hunks)
  • src/components/react-scan.tsx (1 hunks)
  • src/components/ui/context-menu.tsx (1 hunks)
  • src/components/ui/dropdown-menu.tsx (5 hunks)
  • src/components/ui/skeleton.tsx (1 hunks)
  • src/env.ts (1 hunks)
  • src/lib/auth-client.ts (1 hunks)
  • src/lib/auth.ts (2 hunks)
💤 Files with no reviewable changes (2)
  • src/components/i18n/locale-switcher.tsx
  • src/components/(marketing)/discord-login.tsx
🧰 Additional context used
🧬 Code Definitions (6)
src/app/(app)/settings/layout.tsx (1)
src/components/(app)/settings/sidebar.tsx (1)
  • SettingsSidebar (10-34)
src/app/(marketing)/page.tsx (1)
src/env.ts (1)
  • env (4-19)
src/lib/auth-client.ts (2)
src/env.ts (1)
  • env (4-19)
src/lib/auth.ts (1)
  • auth (6-43)
src/app/providers.tsx (1)
src/components/react-scan.tsx (1)
  • ReactScan (7-15)
src/components/discord-login.tsx (3)
src/lib/auth-client.ts (1)
  • authClient (6-9)
src/components/ui/dropdown-menu.tsx (12)
  • DropdownMenu (258-258)
  • DropdownMenuTrigger (260-260)
  • DropdownMenuContent (261-261)
  • DropdownMenuGroup (262-262)
  • DropdownMenuLabel (263-263)
  • DropdownMenuSeparator (268-268)
  • DropdownMenuItem (264-264)
  • DropdownMenuSub (270-270)
  • DropdownMenuSubTrigger (271-271)
  • DropdownMenuSubContent (272-272)
  • DropdownMenuRadioGroup (266-266)
  • DropdownMenuRadioItem (267-267)
src/components/ui/skeleton.tsx (1)
  • Skeleton (14-14)
src/components/ui/dropdown-menu.tsx (1)
src/lib/utils.ts (1)
  • cn (4-6)
🪛 GitHub Actions: Format & Lint Code
src/components/ui/context-menu.tsx

[error] 88-88: lint/nursery/useSortedClasses: These CSS classes should be sorted.


[error] 107-107: lint/nursery/useSortedClasses: These CSS classes should be sorted.


[error] 124-124: lint/nursery/useSortedClasses: These CSS classes should be sorted.


[error] 148-148: lint/nursery/useSortedClasses: These CSS classes should be sorted.


[error] 166-166: lint/nursery/useSortedClasses: These CSS classes should be sorted.


[error] 191-191: lint/nursery/useSortedClasses: These CSS classes should be sorted.


[error] 218-218: lint/nursery/useSortedClasses: These CSS classes should be sorted.


[error] 233-233: lint/nursery/useSortedClasses: These CSS classes should be sorted.


[error] 247-247: lint/nursery/useSortedClasses: These CSS classes should be sorted.


[error] 3-3: lint/style/useImportType: All these imports are only used as types. Use import type.

🔇 Additional comments (22)
package.json (2)

18-18: Added Radix UI context menu dependency

The addition of the @radix-ui/react-context-menu dependency is appropriate for implementing UI context menus, which aligns with enhancing the user interface for settings pages.


36-36:

Details

✅ Verification successful

Added react-scan dependency

The react-scan package has been added as a dependency, likely to support new functionality in the application.


🌐 Web query:

What is react-scan npm package used for?

💡 Result:

The react-scan npm package is a performance optimization tool for React applications that automatically detects and visualizes unnecessary re-renders and component inefficiencies. It helps developers identify performance bottlenecks without requiring code changes, offering real-time insights through a visual interface.

Key Features

  • Zero-configuration integration: Add via script tag, npm, CLI, or browser extension[1][5]
  • Visual render tracking: Highlights components with unnecessary re-renders using colored outlines (gray for unnecessary, yellow/purple for expensive renders)[1][4]
  • Multi-framework support: Works with Next.js, Vite, Remix, React Router, Astro, and React Native[1][5]
  • Production monitoring: Offers paid monitoring solution for performance tracking in live environments[1][5]

Common Use Cases

  1. Debugging render waterfalls
    Visualizes component update sequences to identify cascading re-render patterns[4][5]

  2. Optimizing memoization
    Helps determine where to apply React.memo, useMemo, or useCallback by showing prop stability issues[1][4]

  3. Performance audits
    Generates reports showing:

    • Component render frequency
    • DOM mutation costs
    • Unnecessary render chains[1][5]

Usage Example

// Basic setup
import { scan } from 'react-scan'

scan({
  enabled: process.env.NODE_ENV === 'development',
  trackUnnecessaryRenders: true,
  animationSpeed: 'fast'
})

The package differentiates itself from similar tools by:

Feature React-Scan React DevTools Why Did You Render?
Setup Complexity Zero config Manual setup Code modifications
Visual Feedback Real-time outlines Performance metrics Console logs only
Production Monitoring Available Not available Not applicable

A 2025 case study showed teams reducing render counts by 40-65% using React-Scan's insights[4]. The tool is actively maintained with weekly updates[1] and integrates with Million.js' optimization suite for comprehensive performance tuning[5].

Citations:


ACTION: Confirming the new react-scan dependency

The addition of "react-scan": "^0.3.3" in the package.json is appropriate. React-scan is a performance optimization tool that automatically identifies and visualizes unnecessary re-renders and other component inefficiencies, offering real-time feedback to help debug performance issues. This dependency appears to be correctly integrated to support enhanced performance monitoring and does not require further changes.

next.config.ts (1)

107-112: LGTM: Settings redirect is appropriately structured

The permanent redirect from /settings to /settings/profile is well-implemented and aligns with the PR objectives of establishing a foundational settings page structure. The permanent flag (HTTP 308) is appropriate if you're confident that /settings/profile will always be the default landing page for settings.

As shown in the relevant code snippet for the sidebar component, this redirect ensures users correctly land on the profile settings page, which appears to be the intended primary settings view.

prisma/migrations/20250327234009_revert/migration.sql (1)

1-9:

Details

❓ Verification inconclusive

Potential data loss when switching from locale to language

This migration drops the locale column and creates a new language column, which will result in the loss of all user language preferences previously stored. All users will default back to 'en' regardless of their previous setting.

Consider using a column rename operation instead to preserve user preferences:

-- AlterTable
- ALTER TABLE "users" DROP COLUMN "locale",
- ADD COLUMN     "language" TEXT NOT NULL DEFAULT 'en';
+ ALTER TABLE "users" RENAME COLUMN "locale" TO "language";

If there's a specific reason to reset all language preferences to 'en', please document this decision.


🏁 Script executed:

#!/bin/bash
# Check if the migration has been applied to production
# and if there's significant user data that would be lost

# Count number of users with non-default locale settings that would be lost
echo "Checking for users with custom locale settings that would be lost:"
psql -c "SELECT COUNT(*) FROM users WHERE locale != 'en';" || echo "Cannot connect to database, verify manually"

Length of output: 401


Action Required: Validate Data Preservation for Language Settings
The migration currently drops the locale column and creates a new language column with a default of 'en', which risks losing any custom user locale settings. Our test script couldn’t connect to the database (psql command not found), so we couldn't verify whether any non-default locale data exists in production.

  • File: prisma/migrations/20250327234009_revert/migration.sql (Lines: 1-9)
  • Concern: Dropping locale may cause data loss if users had custom settings different from 'en'.
  • Suggestion: Consider using a column rename operation such as:
    -- AlterTable
    - ALTER TABLE "users" DROP COLUMN "locale",
    - ADD COLUMN     "language" TEXT NOT NULL DEFAULT 'en';
    + ALTER TABLE "users" RENAME COLUMN "locale" TO "language";
  • Action: If resetting to 'en' was intentional, please document this decision. Otherwise, verify manually in production whether any user records contain custom locale settings before applying this migration.
src/app/(app)/settings/layout.tsx (1)

1-13: LGTM: Well-structured settings layout

The settings layout is well-implemented with a responsive grid system, appropriately separating the sidebar navigation from the main content area. The component follows React best practices with proper typing and Readonly props.

The layout works well with the SettingsSidebar component shown in the relevant code snippets, providing a consistent user interface for the settings pages.

src/lib/auth-client.ts (2)

2-4: Well-structured imports for authentication enhancements

The addition of these imports properly sets up the integration with the authentication system. The type import for auth ensures type safety when using it with the inferAdditionalFields plugin.


7-8: Good implementation of authentication plugins

The changes enhance the authentication client by:

  1. Properly configuring the base URL from environment variables
  2. Adding the inferAdditionalFields plugin with proper type safety

This integration will correctly enable access to custom user fields (like "language") defined in the auth configuration.

src/components/ui/skeleton.tsx (3)

1-3: Clean imports for the Skeleton component

The imports are appropriately defined with the utility function for class name management and proper type imports.


4-12: Well-implemented Skeleton component

The Skeleton component follows best practices:

  1. Proper TypeScript typing with ComponentProps
  2. Effective use of className composition with the cn utility
  3. Spreading remaining props to the div element
  4. Good semantic structure with data-slot attribute

This implementation will work well for loading states throughout the application.


14-14: Proper component export

The named export follows the convention used in other UI components.

src/app/(marketing)/page.tsx (2)

2-2: Improved environment variable management

Good addition of the structured env import, which provides better type safety and validation compared to directly accessing process.env.


14-23: Enhanced API call structure and error handling

The refactored API call improves the code by:

  1. Better formatting for readability
  2. Using the typed env object for the API key
  3. Adding proper error handling with a fallback value

This makes the code more robust against potential API failures.

src/app/providers.tsx (2)

1-1: Added ReactScan component import

The import is correctly defined to bring in the scanning functionality.


17-20: Properly integrated ReactScan into provider hierarchy

The ReactScan component is appropriately placed within the NextIntlClientProvider, ensuring it has access to the internationalization context if needed, while still rendering the children components.

src/env.ts (1)

8-11: Environment variables configuration looks good.

The addition of authentication and database environment variables aligns well with implementing Discord social authentication and settings functionality. The validation of BETTER_AUTH_URL as a URL is a good practice.

src/components/navbar.tsx (1)

10-10: Import path update is correct.

The simplified import path for DiscordLoginButton reflects the component restructuring to support the new authentication flow.

src/components/(app)/settings/sidebar.tsx (1)

10-34: Well-structured settings sidebar component.

The sidebar implementation provides a clean navigation interface for the settings pages, with proper highlighting of the current selection using pathname comparison.

src/components/ui/dropdown-menu.tsx (3)

4-4: Icon import update for dropdown menu direction control.

Replacing CircleIcon with ChevronLeftIcon supports the new bi-directional menu navigation feature.


88-88: Improved interaction feedback with cursor-pointer.

Changing from cursor-default to cursor-pointer across dropdown menu items provides better visual feedback that these elements are interactive, improving usability.

Also applies to: 142-142, 229-229


169-170: Enhanced visual hierarchy with muted text.

Adding text-muted-foreground to dropdown menu labels improves the visual distinction between labels and actionable items.

src/lib/auth.ts (2)

30-30: Hardcoded email instead of using profile email

The email is hardcoded to "internal@wouldyoubot.gg" rather than using the user's actual email from their Discord profile.

Is this an intentional design decision? If users need to receive emails related to their account, this approach might prevent that functionality.


10-20:

Details

❌ Incorrect review comment

Inconsistency between database and code field naming

The field is defined as language here, but according to the summary, database migrations were changing between language and locale columns. This inconsistency could lead to data persistence issues.

Verify if the database schema matches the code by running:


🏁 Script executed:

#!/bin/bash
# Check the current database schema for the users table
# to see if it's using 'language' or 'locale' column

# Find the latest migration file
LATEST_MIGRATION=$(find prisma/migrations -type f -name "*.sql" | sort -r | head -1)
echo "Latest migration file: $LATEST_MIGRATION"

# Display the content of the migration file
if [ -n "$LATEST_MIGRATION" ]; then
  cat "$LATEST_MIGRATION"
else
  echo "No migration files found"
fi

# Check Prisma schema
echo "Checking Prisma schema..."
cat prisma/schema.prisma | grep -E 'language|locale'

Length of output: 854


Database schema and code naming are aligned—no inconsistency found.

The migration file clearly shows that the locale column is dropped and replaced with a language column, which is confirmed by the Prisma schema. The code snippet using language in src/lib/auth.ts is therefore consistent with the current database schema. Please disregard the original naming concern.

Likely an incorrect or invalid review comment.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/lib/auth.ts (1)

37-38: Consider user language preferences

You're setting language: "en" explicitly in the return object, which doesn't allow for user language preferences. Since the PR mentions settings and language sub-menus, you might want to use the user's preferred language from their Discord profile if available.

Consider using Discord's locale information if available:

- language: "en"
+ language: profile.locale || "en"
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 6130d2f and 63ccc72.

📒 Files selected for processing (2)
  • src/components/ui/context-menu.tsx (1 hunks)
  • src/lib/auth.ts (2 hunks)
🔇 Additional comments (14)
src/components/ui/context-menu.tsx (12)

3-7: React imports are correctly typed but consider component reorganization.

The import statements are well-organized with correct usage of import type for type-only imports. This fixes the previously flagged linter error.


87-90: CSS classes need to be sorted alphabetically.

The CSS classes in the className property should be sorted alphabetically to fix the linter error.

- "flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-hidden focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[inset]:pl-8 data-[state=open]:text-accent-foreground [&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0"
+ "cursor-default data-[inset]:pl-8 data-[state=open]:bg-accent data-[state=open]:text-accent-foreground flex focus:bg-accent focus:text-accent-foreground items-center outline-hidden px-2 py-1.5 rounded-sm select-none text-sm [&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0"

107-109: Fix CSS property syntax errors and sort classes alphabetically.

The origin CSS property has incorrect syntax and the classes need alphabetical sorting.

- "data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 min-w-[8rem] origin-(--radix-context-menu-content-transform-origin) overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg data-[state=closed]:animate-out data-[state=open]:animate-in"
+ "bg-popover border data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 min-w-[8rem] origin-[var(--radix-context-menu-content-transform-origin)] overflow-hidden p-1 rounded-md shadow-lg text-popover-foreground z-50"

124-126: Fix max-height and origin CSS property syntax errors.

Both properties have incorrect syntax and the CSS classes need to be sorted alphabetically.

- "data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 max-h-(--radix-context-menu-content-available-height) min-w-[8rem] origin-(--radix-context-menu-content-transform-origin) overflow-y-auto overflow-x-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md data-[state=closed]:animate-out data-[state=open]:animate-in"
+ "bg-popover border data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 max-h-[var(--radix-context-menu-content-available-height)] min-w-[8rem] origin-[var(--radix-context-menu-content-transform-origin)] overflow-x-hidden overflow-y-auto p-1 rounded-md shadow-md text-popover-foreground z-50"

147-150: Sort CSS classes alphabetically.

Alphabetical sorting of CSS classes is required per linter rules.


165-168: Sort CSS classes alphabetically.

Alphabetical sorting of CSS classes is required per linter rules.


190-193: Sort CSS classes alphabetically.

Alphabetical sorting of CSS classes is required per linter rules.


217-220: Sort CSS classes alphabetically.

Alphabetical sorting of CSS classes is required per linter rules.


233-234: Sort CSS classes alphabetically.

Alphabetical sorting of CSS classes is required per linter rules.

- "-mx-1 my-1 h-px bg-border"
+ "-mx-1 bg-border h-px my-1"

246-249: Sort CSS classes alphabetically.

Alphabetical sorting of CSS classes is required per linter rules.

- "ml-auto text-muted-foreground text-xs tracking-widest"
+ "ml-auto text-muted-foreground text-xs tracking-widest"

9-253: Well-implemented context menu components with proper accessibility attributes.

The implementation of these context menu components is thorough and follows best practices:

  • Each component correctly wraps its corresponding Radix UI primitive
  • Proper data attributes for accessibility and styling
  • Components are organized in a consistent pattern with clean prop passing

This will provide a solid foundation for context menus throughout the application.


255-271: Exports are comprehensive and well-organized.

All components are properly exported, making them easily accessible for use elsewhere in the application.

src/lib/auth.ts (2)

30-30: Review the hardcoded email assignment

The email is hardcoded to "internal@wouldyoubot.gg" rather than using the user's actual email from Discord. While this might be intentional for your use case, verify that this is the desired behavior as it means all users will have the same email address in your system.

Confirm that this is the intended approach for handling user emails. If you need to collect actual user emails, you would need to add "email" to the scope array and use profile.email instead.


31-36: Improved URL construction for avatars and banners

The URL construction for Discord avatars and banners now properly handles cases where the avatar or banner doesn't exist using conditional checks.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (8)
src/components/(app)/settings/sidebar.tsx (1)

38-60: Well-implemented sidebar item component with good props handling

The SettingsSidebarItem component is well-designed:

  • Properly extends Link component props with TypeScript
  • Uses composition pattern effectively
  • Implements conditional styling based on selected state
  • Uses proper accessibility patterns

One optimization suggestion would be to destructure the href prop directly in the function parameters for clarity.

function SettingsSidebarItem({
	selected,
	children,
+	href,
	...props
}: ComponentProps<typeof Link> & {
	selected: boolean;
	children: ReactNode;
}) {
	return (
-		<Link href={props.href}>
+		<Link href={href} {...props}>
src/i18n/translations/en.json (1)

207-214: Consistent settings sidebar translations

The translations for the settings sidebar perfectly align with the implementation in the SettingsSidebar component, ensuring a consistent user experience. The structure matches the component hierarchy and includes all the necessary labels.

Consider adding more sections to the sidebar as the settings area expands (like "Security", "Notifications", etc.) to accommodate future functionality.

src/components/discord-login.tsx (4)

84-131: Consider adding support for RTL languages

The language selection dropdown is well-implemented with flag icons and localized names. However, there's no support for RTL (Right-to-Left) languages like Arabic or Hebrew.

Consider adding RTL language support and addressing any UI adjustments needed for these languages. For example:

// Add additional language options
<DropdownMenuRadioItem value="ar">
  <Flag
    code="sa"
    className="size-4"
  />
  العربية
</DropdownMenuRadioItem>

You would also need to ensure your layout handles RTL text direction properly using the dir attribute or CSS.


116-121: Incorrect Spanish language name

The name for the Spanish language is incorrectly written as "Española" which refers to a Spanish woman or the island. The correct term for the Spanish language is "Español".

-     Española
+     Español

122-128: Incorrect Italian language name

Similarly, "Italiana" is incorrect for the Italian language. The correct term is "Italiano".

-     Italiana
+     Italiano

147-152: Link wrapping DropdownMenuItem may cause propagation issues

The current structure wraps DropdownMenuItem with Link, which might cause click event propagation issues or unexpected behavior with keyboard navigation.

Consider using the onClick handler of DropdownMenuItem for navigation instead:

- <Link href={"/settings/profile"}>
-   <DropdownMenuItem>
-     <User className="size-4" />
-     {t("nav.profile.dropdown.account.settings.sub.profile")}
-   </DropdownMenuItem>
- </Link>

+ <DropdownMenuItem onSelect={() => window.location.href = "/settings/profile"}>
+   <User className="size-4" />
+   {t("nav.profile.dropdown.account.settings.sub.profile")}
+ </DropdownMenuItem>

Or use a custom component that handles both dropdown item behavior and navigation properly.

Also applies to: 153-158

src/lib/auth.ts (2)

30-30: Consider making email configurable or using profile email

The hardcoded email "internal@wouldyoubot.gg" might not be optimal as it doesn't reflect the user's actual email from Discord.

Consider either:

  1. Using the email from the profile if available: email: profile.email || "internal@wouldyoubot.gg"
  2. Making this configurable via environment variables
  3. Adding a comment explaining why a standard email is used instead of the user's Discord email
- email: "internal@wouldyoubot.gg",
+ // Using internal email as Discord requires additional scope for user email
+ email: profile.email || "internal@wouldyoubot.gg",

Note that you would need to request the "email" scope from Discord if you want to access the user's actual email.


38-38: Consider using the user's Discord locale instead of hardcoded "en"

The locale is hardcoded to "en" rather than using the user's preferred locale from their Discord profile.

- locale: "en"
+ locale: profile.locale || "en"

This would provide a better user experience by respecting their language preference from Discord rather than defaulting everyone to English.

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 63ccc72 and bc38d3d.

📒 Files selected for processing (6)
  • prisma/migrations/20250329000636_back_to_locale/migration.sql (1 hunks)
  • prisma/schema.prisma (1 hunks)
  • src/components/(app)/settings/sidebar.tsx (1 hunks)
  • src/components/discord-login.tsx (1 hunks)
  • src/i18n/translations/en.json (2 hunks)
  • src/lib/auth.ts (2 hunks)
🧰 Additional context used
🧬 Code Definitions (1)
src/components/discord-login.tsx (3)
src/lib/auth-client.ts (1)
  • authClient (6-9)
src/components/ui/dropdown-menu.tsx (12)
  • DropdownMenu (258-258)
  • DropdownMenuTrigger (260-260)
  • DropdownMenuContent (261-261)
  • DropdownMenuGroup (262-262)
  • DropdownMenuLabel (263-263)
  • DropdownMenuSeparator (268-268)
  • DropdownMenuItem (264-264)
  • DropdownMenuSub (270-270)
  • DropdownMenuSubTrigger (271-271)
  • DropdownMenuSubContent (272-272)
  • DropdownMenuRadioGroup (266-266)
  • DropdownMenuRadioItem (267-267)
src/components/ui/skeleton.tsx (1)
  • Skeleton (14-14)
🔇 Additional comments (13)
src/components/(app)/settings/sidebar.tsx (1)

1-36: Well-structured settings sidebar component with proper navigation handling

The SettingsSidebar component is well-implemented with:

  • Clear client-side directive for use with navigation hooks
  • Proper internationalization using useTranslations
  • Clean pathname detection for highlighting the active section
  • Good semantic HTML structure with appropriate ARIA considerations

The component correctly determines the selected state based on the current pathname, which ensures users can understand which section they're currently viewing.

prisma/migrations/20250329000636_back_to_locale/migration.sql (1)

1-9:

Details

❓ Verification inconclusive

Verify data migration strategy for language to locale transition

This migration script changes the database schema by dropping the language column and creating a new locale column. While the structure is correct, this approach will result in data loss as warned in the comment.

Consider whether a data migration strategy is needed to preserve user language preferences during this transition. In production environments, you might want to first copy data from language to locale before dropping the original column.


🏁 Script executed:

#!/bin/bash
# Check if there's another migration that handles data migration
grep -r "language.*locale" --include="*.sql" prisma/migrations/

Length of output: 65


Action Required: Verify Data Migration Strategy Before Dropping the Old Column

The migration in prisma/migrations/20250329000636_back_to_locale/migration.sql (lines 1–9) drops the language column and adds a new locale column with a default value ('en'). However, no evidence was found of an accompanying step to migrate existing data from language to locale.

  • The absence of any SQL statement that copies or transforms the data suggests that—if preserving users’ language preferences is desired—a dedicated data migration step is missing.
  • In production, you might need to introduce a migration that first updates locale using the current values from language before dropping the language column.

Please verify whether the data loss is acceptable or if a proper data migration is needed to preserve user settings.

prisma/schema.prisma (1)

55-55: Field name change from 'language' to 'locale' is consistent with migration

The change from language to locale in the User model aligns with best practices for internationalization. This field name better represents the concept of locale (which includes both language and region), which is more precise than just "language".

This change is consistent with the corresponding migration script that updates the database schema.

src/i18n/translations/en.json (1)

148-169: Well-structured user profile dropdown menu translations

The translation structure for the profile dropdown menu is well-organized with a logical hierarchy. It includes all the necessary UI elements for user account management, including profile access, language settings, and logout functionality.

The nested structure with dedicated sections for sub-menus (like settings.sub) provides good organization for maintainability.

src/components/discord-login.tsx (7)

1-32: Well-organized imports and dependencies

The import section is comprehensive and properly organized, covering UI components, icons, authentication utilities, and internationalization features needed for the Discord login functionality.


34-36: Appropriate component interface design

The DiscordLoginButtonProps interface provides good flexibility with an optional className property, allowing for custom styling when the component is used in different contexts.

Also applies to: 38-40


41-50: Well-implemented authentication flow

The session management and login handling are properly implemented using the auth client. The login function correctly sets up Discord authentication with the current pathname as the callback URL.


52-57: Locale change handler matches database field name

The handler correctly updates both the UI locale and the user record with the same field name (locale), which aligns with the database schema changes mentioned in past reviews.


59-83: Nicely implemented user profile dropdown

The dropdown menu for logged-in users is well-structured with appropriate avatar display and fallback, proper positioning, and clear labeling.


181-183: Good loading state implementation

The skeleton loader is appropriately sized and positioned, providing a good visual indication while the session is loading.


185-200: Well-implemented responsive login button

The login button is well-designed with responsive text that changes based on screen size, appropriate styling, and clear visual indication of its purpose with the Discord icon.

src/lib/auth.ts (2)

10-20: Good user configuration with GDPR compliance

The user configuration with deleteUser enabled is a good addition that supports GDPR compliance by allowing users to delete their accounts. The additional fields section properly defines the locale field with a sensible default.


30-39: Improved profile mapping with better URL handling

The profile mapping function has been improved with proper conditional handling for avatar and banner URLs, along with the addition of email verification status and locale settings.

Copy link
Member

@mezotv mezotv left a comment

Choose a reason for hiding this comment

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

Do you think we could display the users displayname next to the profile picture?

mezotv
mezotv previously approved these changes Mar 29, 2025
@mezotv mezotv enabled auto-merge (squash) March 29, 2025 17:06
Copy link
Collaborator

@taqh taqh left a comment

Choose a reason for hiding this comment

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

LGTM

@mezotv mezotv merged commit bde4997 into main Mar 29, 2025
4 checks passed
@mezotv mezotv deleted the woofer21/wy-152 branch March 29, 2025 18:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants