Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

[Web] Refactor/sidebar #3361

Merged
merged 4 commits into from
Nov 21, 2024
Merged

[Web] Refactor/sidebar #3361

merged 4 commits into from
Nov 21, 2024

Conversation

NdekoCode
Copy link
Contributor

@NdekoCode NdekoCode commented Nov 21, 2024

[Web] Refactor/sidebar

Please include a summary of the changes and the related issue.

Type of Change

  • Bug fix
  • New feature
  • Breaking change
  • Documentation update

Checklist

  • My code follows the style guidelines of this project
  • I have performed a self-review of my code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings

Previous screenshots

Screen.Recording.2024-11-21.at.22.57.47.mov

Current screenshots

Screen.Recording.2024-11-21.at.22.54.31.mov

Summary by CodeRabbit

Release Notes

  • New Features

    • Introduced Mailchimp integration for user subscriptions.
    • Added a new SidebarOptInForm component for newsletter sign-ups.
    • New UI components for card layouts and form handling.
  • Improvements

    • Enhanced sidebar functionality with workspace management.
    • Refined layout and styling for various components, improving user experience.
    • Updated global styles for better text rendering and utility classes.
  • Bug Fixes

    • Adjusted z-index values for improved stacking context in navigation components.
  • Dependencies

    • Added new dependencies for form handling and validation.
    • Updated existing dependencies for improved functionality.

Copy link
Contributor

coderabbitai bot commented Nov 21, 2024

Walkthrough

The pull request introduces multiple changes across various files, primarily focusing on enhancing user interface components, adding new environment variables for Mailchimp integration, and updating the spell-checking dictionary. Key modifications include the addition of new words to the .cspell.json file, the introduction of Mailchimp-related environment variables in .env and .env.sample, and structural updates to several UI components for better usability and layout. Additionally, new components for form handling and UI cards are introduced, alongside adjustments to existing configurations and styles.

Changes

File Path Change Summary
.cspell.json Added words: "hookform", "apikey", "DATACENTER", "mailchimp", "timesheet-viewMode", "Waitlist"; reinstated "timesheet-viewMode".
apps/web/.env Added variables: MAILCHIMP_API_KEY=, MAILCHIMP_LIST_ID=.
apps/web/.env.sample Added variables: MAILCHIMP_API_KEY=, MAILCHIMP_LIST_ID=.
apps/web/app/[locale]/layout.tsx Changed import path for global styles from relative to absolute: import '@/styles/globals.css';.
apps/web/app/[locale]/page-component.tsx Removed sticky class from header; updated margin class from mt-7 to my-3.
apps/web/app/api/subscribe/route.ts Introduced a new POST handler for subscribing users to a newsletter via Mailchimp.
apps/web/components/app-sidebar.tsx Removed SidebarMenu and related components; added SidebarFooter and restructured data handling.
apps/web/components/nav-main.tsx Added SidebarGroupLabel and updated styling for sidebar menu items.
apps/web/components/nav-projects.tsx Renamed TeamSwitcher to WorkspacesSwitcher; updated logic to handle workspaces instead of teams.
apps/web/components/ui/card.tsx Introduced new card UI components: Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter.
apps/web/components/ui/form.tsx Introduced components and hooks for form handling using react-hook-form.
apps/web/components/ui/label.tsx Introduced new Label component utilizing LabelPrimitive.
apps/web/components/ui/sidebar.tsx Updated sidebar dimensions and restructured sidebar context components.
apps/web/lib/layout/main-layout.tsx Moved AppSidebar import for clarity; no functional changes to MainLayout.
apps/web/next.config.js Added transpilePackages property with ['geist']; updated Sentry and ESLint configurations.
apps/web/package.json Added dependencies: @hookform/resolvers, geist, zod; updated react-hook-form.
apps/web/styles/globals.css Modified body styling and added new utility classes.
apps/web/tailwind.config.js Restructured Tailwind CSS configuration without changing values.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant MailchimpAPI
    participant App
    User->>App: Subscribe to newsletter
    App->>User: Request email and captcha
    User->>App: Provide email and captcha
    App->>MailchimpAPI: Send subscription request
    MailchimpAPI-->>App: Response (success/error)
    App->>User: Notify subscription status
Loading

Possibly related PRs

Suggested labels

WEB, UI/UX, Ever Teams, Bug fix

Suggested reviewers

  • evereq
  • Cedric921
  • EverTechDevOps

Poem

🐰 In the meadow, changes bloom,
Words added, dispelling gloom.
Mailchimp whispers, "Join the fun!"
With new cards, our work is done.
A sidebar fresh, a layout bright,
Hoppy days are now in sight! 🌼

Warning

There were issues while running some tools. Please review the errors and either fix the tool’s configuration or disable the tool if it’s a critical failure.

🔧 eslint (1.23.1)

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

apps/web/app/[locale]/layout.tsx

Oops! Something went wrong! :(

ESLint: 8.46.0

ESLint couldn't find the config "next/core-web-vitals" to extend from. Please check that the name of the config is correct.

The config "next/core-web-vitals" was referenced from the config file in "/apps/web/.eslintrc.json".

If you still have problems, please stop by https://eslint.org/chat/help to chat with the team.


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

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

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

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

CodeRabbit Commands (Invoked using PR comments)

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

Other keywords and placeholders

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

CodeRabbit Configuration File (.coderabbit.yaml)

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

Documentation and Community

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

Copy link
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: 23

🧹 Outside diff range and nitpick comments (34)
apps/web/components/ui/label.tsx (1)

9-9: Consider adding size and appearance variants for better flexibility.

While the base styling is good, the component could be more reusable with additional variants. Consider adding size variants (sm, md, lg) and appearance variants (default, error) to support different use cases.

-const labelVariants = cva('text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70');
+const labelVariants = cva(
+  'font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70',
+  {
+    variants: {
+      size: {
+        sm: 'text-xs',
+        md: 'text-sm',
+        lg: 'text-base'
+      },
+      variant: {
+        default: 'text-gray-900',
+        error: 'text-red-500'
+      }
+    },
+    defaultVariants: {
+      size: 'md',
+      variant: 'default'
+    }
+  }
+);
apps/web/components/ui/card.tsx (3)

5-8: Consider using semantic HTML for better accessibility.

While the implementation is solid, consider using <article> or <section> instead of <div> for better semantic meaning, especially if the card represents a self-contained composition.

-const Card = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(({ className, ...props }, ref) => (
-	<div ref={ref} className={cn('rounded-lg border bg-card text-card-foreground shadow-sm', className)} {...props} />
+const Card = React.forwardRef<HTMLElement, React.HTMLAttributes<HTMLElement>>(({ className, ...props }, ref) => (
+	<article ref={ref} className={cn('rounded-lg border bg-card text-card-foreground shadow-sm', className)} {...props} />
));

10-41: Consider enhancing type safety and component organization.

The implementation is solid, but could benefit from the following improvements:

  1. Define specific prop interfaces for each component
  2. Consider composing components using the Compound Component pattern

Example implementation:

interface CardProps extends React.HTMLAttributes<HTMLElement> {
  variant?: 'default' | 'bordered';
}

interface CardHeaderProps extends React.HTMLAttributes<HTMLDivElement> {
  // Add specific props if needed
}

// Similar interfaces for other components

const Card = React.forwardRef<HTMLElement, CardProps>(({ variant = 'default', className, ...props }, ref) => {
  // Implementation
}) as CardComponent;

type CardComponent = React.ForwardRefExoticComponent<CardProps> & {
  Header: typeof CardHeader;
  Title: typeof CardTitle;
  // ... other components
};

// Attach subcomponents
Card.Header = CardHeader;
Card.Title = CardTitle;
// ... other attachments

This would enable a more intuitive usage:

<Card>
  <Card.Header>
    <Card.Title>Title</Card.Title>
  </Card.Header>
</Card>

1-43: Consider adding component documentation and examples.

Since this is a new reusable UI component, it would be valuable to:

  1. Add JSDoc comments describing each component's purpose and props
  2. Create Storybook stories or examples showcasing different use cases
  3. Consider adding aria-* attributes for better accessibility

Example JSDoc:

/**
 * Card component that serves as a container for related content.
 * 
 * @example
 * <Card>
 *   <CardHeader>
 *     <CardTitle>Title</CardTitle>
 *     <CardDescription>Description</CardDescription>
 *   </CardHeader>
 *   <CardContent>Content</CardContent>
 * </Card>
 */
apps/web/.env.sample (2)

90-93: Consider grouping Mailchimp configuration with other external services.

The Mailchimp configuration would be better organized if placed with other third-party service integrations (like OAuth, SMTP) rather than at the end of the file.

 MEET_JWT_APP_SECRET=
+
+# Mailchimp
+MAILCHIMP_API_KEY=
+MAILCHIMP_LIST_ID=
 
 # Warning: IF TRUE This allows production builds to successfully complete even if
 # your project has ESLint errors.
 NEXT_IGNORE_ESLINT_ERROR_ON_BUILD=true
-
-# Mailchimp
-MAILCHIMP_API_KEY=
-MAILCHIMP_LIST_ID=

91-93: Add documentation for Mailchimp credentials format and security.

The Mailchimp configuration lacks important documentation about:

  1. The expected format of the API key
  2. Where to obtain these credentials
  3. Security implications of these sensitive values
 # Mailchimp
-MAILCHIMP_API_KEY=
-MAILCHIMP_LIST_ID=
+# Get these from your Mailchimp account settings
+# API Key format: <dc>-us<number>
+MAILCHIMP_API_KEY= # Keep this secure and never commit the actual value
+MAILCHIMP_LIST_ID= # Also known as Audience ID in Mailchimp dashboard
apps/web/components/pages/task/description-block/editor-components/LinkElement.tsx (2)

Line range hint 38-73: Enhance accessibility for the popup menu.

The popup menu lacks proper ARIA attributes and keyboard navigation support.

Consider the following improvements:

  1. Add ARIA attributes to the popup
  2. Implement keyboard navigation
  3. Add a visible focus state
 <div
   className="absolute left-0 flex items-center max-w-xs bg-white dark:bg-dark--theme-light p-2 gap-1 rounded-md border border-gray-300 dark:border-[#7B8089] z-10 "
   contentEditable="false"
+  role="menu"
+  aria-label="Link options"
 >
   <div className="flex items-center pr-2 text-xs border-r dark:bg-dark--theme-light border-gray-300">
     <ExternalLinkIcon className="h-[18px]  w-[18px] mr-1" />
     <a
       href={href}
       rel="noreferrer"
       target="_blank"
       className="text-[#5000B9] dark:text-primary-light truncate max-w-[230px] overflow-hidden whitespace-nowrap mr-0"
       style={{ textOverflow: 'ellipsis' }}
+      role="menuitem"
     >
       {element.href}
     </a>
   </div>
   <button
     onClick={() => removeLink(editor)}
     className="border-none bg-transparent hover:cursor-pointer ml-0 "
+    role="menuitem"
+    aria-label="Remove link"
   >
     <UnlinkRoundIcon className="h-4 w-4 text-black dark:text-white" />
   </button>
 </div>

Line range hint 33-35: Consider sanitizing URLs before display and navigation.

The URL manipulation could be improved to handle malicious inputs more safely.

-const href = `https://${element?.href?.replace('https://', '')}`;
+const sanitizeUrl = (url: string): string => {
+  try {
+    const urlObj = new URL(url.startsWith('http') ? url : `https://${url}`);
+    return urlObj.toString();
+  } catch {
+    return '#';
+  }
+};
+const href = sanitizeUrl(element?.href || '');
apps/web/components/pages/main/header-tabs.tsx (6)

11-11: Consider improving prop names and adding documentation.

The prop names could be more descriptive:

  • linkAll doesn't clearly indicate its purpose
  • kanban could be renamed to something more specific like isKanbanView
-const HeaderTabs = ({ linkAll, kanban = false }: { linkAll: boolean; kanban?: boolean }) => {
+interface HeaderTabsProps {
+  /** Whether to enable routing for all tab views */
+  enableRouting: boolean;
+  /** Whether the component is being used in Kanban view */
+  isKanbanView?: boolean;
+}
+
+const HeaderTabs = ({ enableRouting, isKanbanView = false }: HeaderTabsProps) => {

13-18: Move options array outside component.

The options array is static and should be defined outside the component to prevent unnecessary recreation on each render.

+const VIEW_OPTIONS = [
+  { label: 'CARDS', icon: QueueListIcon, view: IssuesView.CARDS },
+  { label: 'TABLE', icon: TableCellsIcon, view: IssuesView.TABLE },
+  { label: 'BLOCKS', icon: Squares2X2Icon, view: IssuesView.BLOCKS },
+  { label: 'KANBAN', icon: KanbanIcon, view: IssuesView.KANBAN }
+] as const;
+
 const HeaderTabs = ({ linkAll, kanban = false }) => {
   const t = useTranslations();
-  const options = [...]

19-19: Improve links array clarity and maintainability.

The links array uses magic strings and its relationship with the options array isn't immediately clear.

-const links = linkAll ? ['/', '/', '/', '/kanban'] : [undefined, undefined, undefined, '/kanban'];
+const ROUTE_PATHS = {
+  DEFAULT: '/',
+  KANBAN: '/kanban'
+} as const;
+
+const links = VIEW_OPTIONS.map(option => 
+  linkAll 
+    ? option.view === IssuesView.KANBAN ? ROUTE_PATHS.KANBAN : ROUTE_PATHS.DEFAULT
+    : option.view === IssuesView.KANBAN ? ROUTE_PATHS.KANBAN : undefined
+);

29-29: Document the purpose of z-20 class.

The z-index value seems arbitrary. Consider documenting why this specific z-index is needed and if it follows your application's z-index system.

Add a comment explaining the z-index choice:

 className="z-20" // Ensures tooltip appears above other UI elements in the header

38-42: Simplify click handler logic.

The click handler condition can be simplified and made more explicit.

-onClick={() => {
-  if (links[index] !== '/kanban') {
-    setView(optionView);
-  }
-}}
+onClick={() => {
+  const isKanbanView = optionView === IssuesView.KANBAN;
+  if (!isKanbanView) {
+    setView(optionView);
+  }
+}}

33-37: Consider using a more maintainable approach for conditional classes.

The conditional classes could be more readable using a dedicated styling object or CSS modules.

+const getTabStyles = (isActive: boolean) => ({
+  button: clsxm(
+    'rounded-md p-2 text-gray-700 dark:text-gray-300',
+    isActive && 'bg-gray-100 text-gray-900 dark:bg-gray-800 dark:text-gray-100'
+  ),
+  icon: clsxm(
+    'w-5 h-5 inline text-gray-600 dark:text-gray-400',
+    isActive && 'dark:text-white text-gray-800'
+  )
+});

-className={clsxm(
-  'rounded-md p-2 text-gray-700 dark:text-gray-300',
-  activeView === optionView &&
-    'bg-gray-100 text-gray-900 dark:bg-gray-800 dark:text-gray-100'
-)}
+className={getTabStyles(activeView === optionView).button}

-className={clsxm(
-  'w-5 h-5 inline text-gray-600 dark:text-gray-400',
-  activeView === optionView && 'dark:text-white text-gray-800'
-)}
+className={getTabStyles(activeView === optionView).icon}

Also applies to: 45-48

apps/web/components/workspace-switcher.tsx (2)

16-25: LGTM! Consider enhancing type safety.

The component declaration and props structure look good. The use of Readonly for props is a good practice for immutability.

Consider extracting the workspace type to a separate interface for better reusability:

interface Workspace {
  name: string;
  logo: React.ElementType;
  plan: string;
}

export function WorkspacesSwitcher({
  workspaces
}: Readonly<{
  workspaces: Workspace[];
}>)

Line range hint 67-73: Add proper handling for workspace creation.

The "Add team" button appears to be non-functional and still references teams instead of workspaces.

Consider implementing proper workspace creation handling:

-<DropdownMenuItem className="gap-2 p-2">
+<DropdownMenuItem 
+  className="gap-2 p-2"
+  onClick={() => handleAddWorkspace()}
+  role="menuitem"
+  aria-label="Create new workspace"
+>
   <div className="flex items-center justify-center border rounded-md size-6 bg-background">
     <Plus className="size-4" />
   </div>
-  <div className="font-medium text-muted-foreground">Add team</div>
+  <div className="font-medium text-muted-foreground">Add workspace</div>
 </DropdownMenuItem>

Would you like me to help implement the handleAddWorkspace function?

apps/web/components/nav-projects.tsx (3)

27-41: Consider keeping the Readonly type wrapper for better type safety.

While removing Readonly simplifies the type, keeping it helps prevent accidental mutations of the props object, which is a React best practice.

-}: {
+}: Readonly<{
	projects: {
		name: string;
		url: string;
		icon: LucideIcon;
	}[];
-}) {
+}>) {

46-46: Use optional chaining for better null safety.

The condition can be simplified using optional chaining.

-{projects && projects.length ? (
+{projects?.length ? (
🧰 Tools
🪛 Biome (1.9.4)

[error] 46-46: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


96-96: Extract hardcoded styles to a CSS class.

The button styles contain hardcoded values which should be moved to a CSS class for better maintainability.

-className="w-full text-xs mt-3 dark:text-white rounded-xl border-[0.0938rem] w-full max-w-[230px]"
+className="create-project-button"

Add to your CSS:

.create-project-button {
  @apply w-full text-xs mt-3 dark:text-white rounded-xl border max-w-[230px];
  border-width: 0.0938rem;
}
apps/web/components/sidebar-opt-in-form.tsx (1)

16-20: Consider enhancing email validation rules.

The current email validation is basic. Consider adding more specific validation rules for better user experience.

 const subscribeFormSchema = z
   .object({
-    email: z.string().email()
+    email: z.string()
+      .email('Please enter a valid email address')
+      .min(5, 'Email must be at least 5 characters')
+      .max(255, 'Email must not exceed 255 characters')
+      .refine((email) => !email.endsWith('.test'), {
+        message: 'Test email domains are not allowed'
+      })
   })
   .required();
apps/web/app/[locale]/page-component.tsx (2)

Line range hint 42-57: Consider optimizing localStorage effect

The useEffect for fullWidth mode could be optimized to avoid multiple localStorage reads and unnecessary re-renders.

Consider this improvement:

  React.useEffect(() => {
-   window && window?.localStorage.getItem('conf-fullWidth-mode');
-   setFullWidth(JSON.parse(window?.localStorage.getItem('conf-fullWidth-mode') || 'true'));
+   const storedValue = window?.localStorage.getItem('conf-fullWidth-mode');
+   if (storedValue !== null) {
+     setFullWidth(JSON.parse(storedValue));
+   }
  }, [setFullWidth]);

Line range hint 108-127: Simplify mobile responsiveness in TaskTimerSection

The current implementation uses multiple conditional classes and a separate mobile toggle, which could be simplified for better maintainability.

Consider using a more declarative approach:

- <AuthUserTaskInput
-   className={clsxm(
-     'w-full lg:basis-3/4 grow',
-     !showInput && '!hidden md:!flex',
-     !isTrackingEnabled && 'md:w-full'
-   )}
- />
- <div
-   onClick={() => setShowInput((p) => !p)}
-   className="border dark:border-[#26272C] w-full rounded p-2 md:hidden flex justify-center mt-2"
- >
-   <ChevronDown className={clsxm('h-12  transition-all', showInput && 'rotate-180')}>
-     {showInput ? 'hide the issue input' : 'show the issue input'}
-   </ChevronDown>
- </div>
+ <div className="w-full">
+   <AuthUserTaskInput
+     className={clsxm(
+       'w-full transition-all duration-200',
+       'lg:basis-3/4 grow',
+       'md:flex',
+       !isTrackingEnabled && 'md:w-full',
+       {
+         'max-h-0 md:max-h-full overflow-hidden': !showInput,
+         'max-h-[200px]': showInput
+       }
+     )}
+   />
+   <button
+     onClick={() => setShowInput((p) => !p)}
+     className="w-full flex justify-center items-center p-2 md:hidden border dark:border-[#26272C] rounded mt-2"
+     aria-label={showInput ? 'Hide issue input' : 'Show issue input'}
+   >
+     <ChevronDown className={clsxm('h-12 transition-transform duration-200', showInput && 'rotate-180')} />
+   </button>
+ </div>

This approach:

  • Uses CSS transitions for smoother animations
  • Improves accessibility with proper button semantics
  • Simplifies the class structure
  • Uses height transitions instead of display properties
apps/web/package.json (1)

91-91: Consider pinning the geist version

While using ^1.3.1 allows for minor version updates, considering this is a UI framework being used in a sidebar refactor, it might be safer to pin to an exact version to prevent unexpected visual changes.

-    "geist": "^1.3.1",
+    "geist": "1.3.1",
apps/web/components/nav-main.tsx (2)

68-68: Consider i18n for the Platform label

The hardcoded "Platform" text should be internationalized for better maintainability and multi-language support.

- <SidebarGroupLabel>Platform</SidebarGroupLabel>
+ <SidebarGroupLabel>{t('common.platform')}</SidebarGroupLabel>

Line range hint 149-174: Consolidate styling and improve accessibility

The sub-menu styling has some good improvements but needs attention in a few areas:

  1. The ChevronRight icon should have a more descriptive aria-label
  2. The width constraint is duplicated from the parent component

Consider these improvements:

- <ChevronRight />
- <span className="sr-only">Toggle</span>
+ <ChevronRight aria-label={`Toggle ${item.title} sub-menu`} />

- <SidebarMenuSubItem className="w-full max-w-[230px]" key={key}>
+ <SidebarMenuSubItem className="w-full" key={key}>
apps/web/styles/globals.css (2)

Line range hint 279-281: Consider using Tailwind's built-in tracking utilities.

The .details-label class uses a custom tracking value (-0.02em). Consider using Tailwind's built-in tracking utilities (tracking-tighter, tracking-tight, etc.) for better maintainability and consistency.

-.details-label {
-  @apply not-italic font-medium text-[0.625rem] leading-[140%] tracking-[-0.02em] text-[#A5A2B2] 2xl:text-xs;
-}
+.details-label {
+  @apply not-italic font-medium text-[0.625rem] leading-[140%] tracking-tight text-[#A5A2B2] 2xl:text-xs;
+}

Line range hint 285-299: Improve search input styling maintainability.

Several issues with the search input styling could be improved:

  1. Fixed heights might cause layout issues with different font sizes
  2. Use of !important in placeholder styles
  3. Commented code should be removed

Consider this more maintainable approach:

 .search-border {
-  height: 33px;
+  @apply h-[33px];
 }
 .search-border .input-border {
-  border-width: 0px !important;
-  height: 40px;
+  @apply border-0 h-10;
 }
 .search-border .input-border input {
-  height: 40px;
+  @apply h-10;
 }
 .search-border .input-border input::placeholder {
-  color: #7e7991;
-  font-size: 15px !important;
-  /* font-weight: 500; */
-  letter-spacing: 0.8px;
+  @apply text-[#7e7991] text-[15px] tracking-[0.8px];
 }
apps/web/components/ui/sidebar.tsx (3)

Line range hint 67-76: Enhance cookie security settings.

The cookie implementation should include additional security flags.

-document.cookie = `${SIDEBAR_COOKIE_NAME}=${nextOpen}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`;
+document.cookie = `${SIDEBAR_COOKIE_NAME}=${nextOpen}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}; SameSite=Lax; Secure`;

Line range hint 84-94: Improve keyboard shortcut accessibility.

The keyboard shortcut implementation should include ARIA labels and consider users who might not be able to use modifier keys.

 const handleKeyDown = (event: KeyboardEvent) => {
   if (event.key === SIDEBAR_KEYBOARD_SHORTCUT && (event.metaKey || event.ctrlKey)) {
     event.preventDefault();
     toggleSidebar();
+    // Announce state change for screen readers
+    const message = state === 'expanded' ? 'Sidebar collapsed' : 'Sidebar expanded';
+    document.getElementById('a11y-status')?.setAttribute('aria-label', message);
   }
 };

Consider adding this element to your main layout:

<div id="a11y-status" role="status" aria-live="polite" className="sr-only" />

Line range hint 183-183: Improve z-index management.

Using z-[9999] is an anti-pattern that can lead to layering issues. Consider implementing a z-index scale system.

Create a new constants file for z-index management:

// constants/z-index.ts
export const ZINDEX = {
  sidebar: 50,
  modal: 100,
  tooltip: 150,
  // ... other values
} as const;

Then update the z-index values:

-className="w-[--sidebar-width] bg-sidebar p-0 text-sidebar-foreground [&>button]:hidden z-[9999]"
+className="w-[--sidebar-width] bg-sidebar p-0 text-sidebar-foreground [&>button]:hidden z-[var(--z-sidebar)]"

Also applies to: 249-249

apps/web/components/app-sidebar.tsx (4)

8-11: Avoid potential naming conflicts with X import

Importing X directly might cause conflicts if there's an existing component or variable named X in your codebase. Consider aliasing it to a more descriptive name to prevent potential naming collisions.

Apply this diff to alias the X import:

 import {
     MonitorSmartphone,
     LayoutDashboard,
     Heart,
     SquareActivity,
     Files,
-    X,
+    X as CloseIcon,
     Command,
     AudioWaveform,
     GalleryVerticalEnd
 } from 'lucide-react';

And update its usage accordingly:

-<X
+<CloseIcon
    className="w-5 h-5 cursor-pointer"
    onClick={() => toggleFavorite(task)}
/>

45-95: Replace hardcoded sample data with dynamic data

The workspaces array currently contains hardcoded sample data. For production, consider fetching workspace data dynamically from an API or using state management to ensure the sidebar displays actual user data.


48-77: Extract inline SVG logo into a separate component

The inline SVG for the 'Ever Teams' logo increases code complexity and reduces readability. Consider extracting it into a separate component or importing it from an external file to improve maintainability.


Line range hint 121-174: Use unique identifiers for keys in list rendering instead of index

Using the array index index as the key prop in list rendering can lead to issues when the list changes. It's better to use a unique and stable identifier like task.id.

Apply this diff to use task.id as the key:

 .map((task, index) => ({
     title: task?.title,
     url: '#',
     component: (
         <SidebarMenuSubButton
-            key={index}
+            key={task.id}
             className={cn(
                 'hover:bg-[#eaeef4] first:mt-1 last:mb-1 flex items-center text-[#1F2937] dark:text-gray-50 data-[active=true]:bg-[#eaeef4] min-h-10 h-10 dark:hover:bg-sidebar-accent transition-colors duration-300'
             )}
             asChild
         >
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 681714b and e9584e7.

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (28)
  • .cspell.json (6 hunks)
  • apps/web/.env (1 hunks)
  • apps/web/.env.sample (1 hunks)
  • apps/web/app/[locale]/layout.tsx (1 hunks)
  • apps/web/app/[locale]/page-component.tsx (1 hunks)
  • apps/web/app/api/subscribe/route.ts (1 hunks)
  • apps/web/components/app-sidebar.tsx (4 hunks)
  • apps/web/components/nav-main.tsx (8 hunks)
  • apps/web/components/nav-projects.tsx (2 hunks)
  • apps/web/components/nav-secondary.tsx (1 hunks)
  • apps/web/components/pages/all-teams/header-tabs.tsx (1 hunks)
  • apps/web/components/pages/main/header-tabs.tsx (1 hunks)
  • apps/web/components/pages/task/description-block/editor-components/LinkElement.tsx (1 hunks)
  • apps/web/components/sidebar-opt-in-form.tsx (1 hunks)
  • apps/web/components/ui/card.tsx (1 hunks)
  • apps/web/components/ui/form.tsx (1 hunks)
  • apps/web/components/ui/label.tsx (1 hunks)
  • apps/web/components/ui/sidebar.tsx (1 hunks)
  • apps/web/components/workspace-switcher.tsx (4 hunks)
  • apps/web/lib/features/task/daily-plan/views-header-tabs.tsx (1 hunks)
  • apps/web/lib/features/task/task-input-kanban.tsx (2 hunks)
  • apps/web/lib/features/task/task-input.tsx (6 hunks)
  • apps/web/lib/features/user-nav-menu.tsx (2 hunks)
  • apps/web/lib/layout/main-layout.tsx (1 hunks)
  • apps/web/next.config.js (1 hunks)
  • apps/web/package.json (5 hunks)
  • apps/web/styles/globals.css (1 hunks)
  • apps/web/tailwind.config.js (1 hunks)
✅ Files skipped from review due to trivial changes (6)
  • apps/web/app/[locale]/layout.tsx
  • apps/web/components/pages/all-teams/header-tabs.tsx
  • apps/web/lib/features/task/daily-plan/views-header-tabs.tsx
  • apps/web/lib/features/user-nav-menu.tsx
  • apps/web/lib/layout/main-layout.tsx
  • apps/web/tailwind.config.js
🧰 Additional context used
🪛 Biome (1.9.4)
apps/web/components/nav-projects.tsx

[error] 46-46: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

apps/web/lib/features/task/task-input-kanban.tsx

[error] 83-83: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


[error] 138-138: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


[error] 157-158: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


[error] 170-170: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


[error] 195-195: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


[error] 259-259: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

apps/web/lib/features/task/task-input.tsx

[error] 117-117: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


[error] 122-122: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


[error] 173-173: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


[error] 204-204: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


[error] 224-225: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


[error] 260-260: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


[error] 329-329: Unnecessary use of boolean literals in conditional expression.

Simplify your code by directly assigning the result without using a ternary operator.
If your goal is negation, you may use the logical NOT (!) or double NOT (!!) operator for clearer and concise code.
Check for more details about NOT operator.
Unsafe fix: Remove the conditional expression with

(lint/complexity/noUselessTernary)


[error] 347-347: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


[error] 376-376: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


[error] 400-400: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


[error] 633-633: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


[error] 647-647: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

🔇 Additional comments (23)
apps/web/components/ui/label.tsx (3)

1-8: LGTM! Well-structured imports with proper client directive.

The imports are well-organized and the 'use client' directive is correctly placed. Using Radix UI primitives is a good choice for building accessible form components.


19-19: LGTM! Clean named export.

The named export is appropriate for this component and follows React best practices.


1-19: Verify integration with FormLabel component.

The AI summary mentions integration with a FormLabel component. Let's verify this integration to ensure proper form handling capabilities.

✅ Verification successful

Let's examine the form integration by checking the content of these files, particularly form.tsx which likely contains the FormLabel component.


Let's check the actual usage of FormLabel in the task-row component to complete our verification.


Label component is properly integrated with form handling

The verification shows that:

  • The Label component is correctly imported and used in the form system
  • FormLabel is implemented as a wrapper around the Label component in form.tsx
  • It properly handles form context, error states, and accessibility attributes (htmlFor, aria-describedby)
  • The integration provides proper form handling capabilities including error states and accessibility features
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for FormLabel component and its usage of this Label component
rg -l "FormLabel|import.*Label.*from.*label" apps/web/components/

Length of output: 203


Script:

#!/bin/bash
# Check the content of form.tsx to understand the Label integration
rg -A 10 "FormLabel|import.*Label.*from.*label" apps/web/components/ui/form.tsx

Length of output: 1448


Script:

#!/bin/bash
# Check how FormLabel is used in the task-row component
rg -A 5 "FormLabel|import.*Label.*from.*label" apps/web/components/pages/task/details-section/components/task-row.tsx

Length of output: 252

apps/web/components/nav-secondary.tsx (2)

30-31: LGTM! Width constraints improve layout consistency

The addition of w-full max-w-[230px] to both the MenuItem and MenuButton ensures:

  • Consistent width across all menu items
  • Proper button sizing within the sidebar
  • Prevention of unwanted stretching

28-28: Verify the reduced gap spacing visually

The vertical gap between menu items has been reduced from gap-y-3 (0.75rem) to gap-y-1 (0.25rem). While this change helps with space efficiency, please ensure it maintains good visual hierarchy and readability.

✅ Verification successful

The gap-y-1 spacing is consistent with other sidebar components

The reduced gap spacing from gap-y-3 to gap-y-1 aligns with the spacing used in other sidebar components:

  • nav-main.tsx uses gap-y-1 for its main menu items
  • nav-secondary.tsx (the file in review) uses gap-y-1
  • Other sidebar components like nav-projects.tsx use consistent width constraints

This change maintains visual consistency across the application's navigation components, making it a valid improvement.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for other instances of gap-y-1 or gap-y-3 in sidebar components
# to verify consistency across the application
rg --type tsx "gap-y-[13]" "apps/web/components"

Length of output: 76


Script:

#!/bin/bash
# Search for gap-y patterns in all files under components directory
rg "gap-y-[13]" apps/web/components/

Length of output: 641


Script:

#!/bin/bash
# Search for SidebarMenu component usage to check spacing patterns
rg "SidebarMenu" apps/web/components/

Length of output: 7159


Script:

#!/bin/bash
# Find all tsx/jsx files in components directory that might contain sidebar-related code
fd -e tsx -e jsx . apps/web/components/ --exec grep -l "sidebar"

Length of output: 578

apps/web/components/ui/card.tsx (2)

1-4: LGTM! Clean and minimal imports.

The imports are well-organized and include only the necessary dependencies.


43-43: LGTM! Clean exports.

The named exports approach is perfect for tree-shaking and explicit imports.

apps/web/.env.sample (2)

91-93: Verify Mailchimp configuration completeness.

Please confirm if additional Mailchimp configuration variables are needed for:

  1. Server Region/Data Center
  2. Audience/List Name (for logging/debugging)
  3. Default subscription status
✅ Verification successful

The Mailchimp configuration is complete and well-implemented

The current implementation already handles all necessary Mailchimp configuration aspects:

  • Server Region/Data Center is automatically extracted from the API key format (<key>-us3)
  • Default subscription status is hardcoded as 'subscribed'
  • Default tag 'Ever Teams' is set if no tags provided
  • Error handling and validation are properly implemented

No additional environment variables are needed as the implementation follows Mailchimp's best practices.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check if any Mailchimp-related code references additional environment variables
rg -i "process\.env\.MAILCHIMP" --type ts

Length of output: 250


Script:

#!/bin/bash
# Check the implementation details of the Mailchimp subscription route
cat apps/web/app/api/subscribe/route.ts

Length of output: 2123


92-93: Verify no actual credentials are committed.

Ensure that these empty values don't contain any actual Mailchimp credentials, even in the commit history.

✅ Verification successful

No Mailchimp credentials exposed in environment files

The environment files have been checked and contain no exposed Mailchimp credentials. The .env.sample file correctly shows empty placeholder values, and no Mailchimp-related credentials were found in other environment files or related utilities. The only API-like string found was an Expo project ID, which is not a security concern.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check for potential API keys in the commit history
rg -i "mailchimp.*[a-f0-9]{32}" 
rg -i "list-id.*[a-f0-9]{10}" 

Length of output: 65


Script:

#!/bin/bash
# Let's check the .env.sample file directly and also look for any Mailchimp-related patterns
cat apps/web/.env.sample | grep -i mailchimp
# Also check for any potential API key patterns in the file
rg -i "[a-f0-9-]{32,}" apps/web/.env.sample
# Let's also check other env files that might exist
fd -t f ".env" 

Length of output: 229


Script:

#!/bin/bash
# Let's check the other env files for any potential Mailchimp credentials
cat apps/mobile/.env.template | grep -i mailchimp
# Let's also check the content of the check-provider-env-vars file for any hardcoded values
cat apps/web/app/utils/check-provider-env-vars.ts | grep -i mailchimp
# Additional check for any potential API key patterns in these files
rg -i "[a-f0-9-]{32,}" apps/mobile/.env.template apps/web/app/utils/check-provider-env-vars.ts

Length of output: 299

apps/web/components/pages/task/description-block/editor-components/LinkElement.tsx (1)

56-56: LGTM on the max-width adjustment.

The reduction in max-width from 240px to 230px appears reasonable for maintaining consistent layout within the sidebar context.

apps/web/components/workspace-switcher.tsx (1)

Line range hint 16-77: Verify workspace switching integration.

Since this is a significant refactor from teams to workspaces, we should verify the integration points.

✅ Verification successful

Workspace switching integration looks correct

The verification shows that:

  • The WorkspacesSwitcher component is properly integrated in app-sidebar.tsx and receives the required workspaces prop from data.workspaces
  • No legacy TeamSwitcher references remain in the codebase
  • The component is correctly placed within the SidebarHeader section of the sidebar layout

The refactoring from teams to workspaces appears to be consistent in this component's integration points.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for any remaining team references and verify workspace integration

# Check for any remaining team references in the codebase
echo "Checking for remaining team references..."
rg -l "TeamSwitcher" apps/

# Check for workspace switcher usage
echo "Checking workspace switcher usage..."
rg -l "WorkspacesSwitcher" apps/

# Check for potential breaking changes in parent components
echo "Checking sidebar integration..."
rg -l "SidebarMenu.*WorkspacesSwitcher" apps/

Length of output: 435


Script:

#!/bin/bash
# Let's examine the integration in app-sidebar.tsx and check the props being passed
echo "Checking WorkspacesSwitcher usage in app-sidebar.tsx..."
rg -A 10 "WorkspacesSwitcher" apps/web/components/app-sidebar.tsx

# Let's also check for any team-related props or state management
echo "Checking for team/workspace state management..."
rg -l "useTeam|useWorkspace" apps/web/components/

# Check for any workspace-related types
echo "Checking workspace types..."
ast-grep --pattern 'type $_ = {
  $$$
  workspace$_: $_
  $$$
}'

Length of output: 2482

apps/web/.env (1)

141-143: LGTM! Mailchimp configuration variables added correctly.

The new environment variables for Mailchimp integration follow the established pattern in the file, with clear section header and empty default values.

apps/web/components/nav-projects.tsx (1)

Line range hint 1-25: LGTM! Imports and setup are well-organized.

The imports are properly structured and all dependencies are necessary for the component's functionality.

🧰 Tools
🪛 Biome (1.9.4)

[error] 46-46: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

apps/web/components/sidebar-opt-in-form.tsx (1)

1-11: LGTM! Imports are well-organized and necessary.

All required dependencies are properly imported for form handling, validation, and UI components.

apps/web/app/[locale]/page-component.tsx (1)

69-71: Verify header behavior during scrolling

The removal of the sticky behavior from the header might affect the user experience during scrolling, especially on longer pages. Consider if this was intentional as part of the sidebar refactoring.

Let's check if there are any other sticky headers in the codebase that might conflict:

If the header should remain visible while scrolling, consider one of these approaches:

  1. Restore the sticky behavior with proper z-index management
  2. Implement a collapsible header that shows/hides based on scroll direction
✅ Verification successful

Header sticky behavior removal is intentional

The codebase search reveals that sticky headers are used selectively in specific components like calendar setup, dropdowns, and team views, but not in the main page layout. This suggests the removal of sticky behavior from the header in page-component.tsx is intentional, aligning with the sidebar refactoring changes.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for sticky header implementations
rg -g '*.{tsx,jsx,css,scss}' -i '(position:\s*sticky|sticky\s+top|className=.*sticky)'

Length of output: 588

apps/web/package.json (2)

40-40: Form handling dependencies look well-structured

The combination of react-hook-form, @hookform/resolvers, and zod is a robust choice for form handling and validation in the sidebar component. This setup provides:

  • Type-safe form validation with Zod schemas
  • Efficient form state management with react-hook-form
  • Integration between the two via @hookform/resolvers

Let's verify these dependencies are being used together correctly:

Also applies to: 121-121, 137-137

✅ Verification successful

Form validation setup is correctly implemented in the sidebar component

The codebase shows proper integration of the form handling dependencies in sidebar-opt-in-form.tsx:

  • Uses zodResolver from @hookform/resolvers/zod for schema validation
  • Implements useForm with the resolver configuration
  • Includes proper schema validation with Zod
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for form validation setup patterns
rg -A 5 "useForm|zodResolver|z\.object" 

Length of output: 20238


40-40: Verify peer dependency compatibility

Please ensure these new dependencies have compatible peer dependencies with the existing packages in the project.

Also applies to: 91-91, 121-121, 137-137

✅ Verification successful

Peer dependencies are compatible

The package @hookform/resolvers is being used with react-hook-form@^7.53.2 which is the correct version range for compatibility. No peer dependency conflicts were found.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check for potential peer dependency conflicts
yarn why @hookform/resolvers
yarn why geist
yarn why zod

Length of output: 2306


Script:

#!/bin/bash
# Let's try a different approach to check package dependencies
cat apps/web/package.json | jq '.dependencies + .devDependencies'

# Also check if there are any peer dependency warnings in package-lock.json or yarn.lock
fd -t f "package-lock.json|yarn.lock" -x cat {}

Length of output: 135722


Script:

#!/bin/bash
# Let's check the package.json for peer dependencies of @hookform/resolvers
cat apps/web/package.json | jq '.peerDependencies'

# Also check if react-hook-form is installed since it's commonly a peer dependency
cat apps/web/package.json | jq '.dependencies["react-hook-form"]'

Length of output: 133

apps/web/components/nav-main.tsx (2)

8-8: LGTM: Clean import addition

The SidebarGroupLabel import is properly integrated with other sidebar-related imports.


Line range hint 1-195: Verify collapsed state behavior and keyboard navigation

Please ensure:

  1. The collapsed state properly maintains accessibility
  2. Keyboard navigation works correctly through the menu hierarchy
  3. Screen readers can properly announce the menu structure
✅ Verification successful

Keyboard navigation and accessibility features are properly implemented

The implementation has robust accessibility features:

  1. The sidebar uses Radix UI's primitives (Collapsible, Tooltip) which provide built-in accessibility
  2. Proper ARIA attributes and roles through Radix UI components
  3. Keyboard shortcut (Ctrl/Cmd + B) for toggling sidebar
  4. Screen reader support with proper labeling (e.g., "Toggle Sidebar" in sr-only spans)
  5. Focus management through outline and ring styling
  6. Proper tab navigation structure through semantic HTML (nav, button, link elements)
  7. Tooltip support for collapsed state to show labels
  8. Proper state management for expanded/collapsed views

The collapsed state maintains accessibility through:

  • Visible icons with tooltips
  • Keyboard shortcut support
  • Screen reader announcements
  • Focus indicators
  • Semantic HTML structure
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check for other accessibility-related components and keyboard handlers
rg -l "useKeyboard|aria-|role=" --type tsx

# Look for related test files
fd -e test.tsx -e spec.tsx nav-main

Length of output: 110


Script:

#!/bin/bash
# Check for accessibility attributes and keyboard handlers with proper file extension
rg -l "useKeyboard|aria-|role=" --type ts --type tsx --type jsx --type js

# Look for test files with various extensions
fd "nav-main" -e test.tsx -e test.ts -e test.jsx -e test.js -e spec.tsx -e spec.ts -e spec.jsx -e spec.js

# Check for keyboard event handlers in the nav component
rg "onKeyDown|onKeyPress|onKeyUp" apps/web/components/nav-main.tsx

# Check for aria attributes in the nav component
rg "aria-|role=" apps/web/components/nav-main.tsx

Length of output: 330


Script:

#!/bin/bash
# Let's check the sidebar component since it's imported and used extensively
cat apps/web/components/ui/sidebar.tsx

# Check the collapsible component for accessibility features
cat apps/web/components/ui/collapsible.tsx

# Look for any accessibility tests in the components directory
find apps/web/components -type f -name "*test*" -o -name "*spec*"

Length of output: 23306

.cspell.json (1)

9-9: LGTM! Verify word usage in codebase.

The new dictionary entries align well with the PR's objectives of sidebar refactoring and Mailchimp integration. The words follow proper naming conventions.

Let's verify that these new words are actually used in the codebase:

Also applies to: 28-28, 97-97, 246-246, 373-373, 407-407

✅ Verification successful

All new dictionary words are actively used in the codebase

All the newly added words to .cspell.json are verified to be in use:

  • "hookform": Used in imports from "@hookform/resolvers"
  • "apikey": Used in API route files for authentication
  • "DATACENTER": Used in Mailchimp API integration
  • "mailchimp": Used extensively in subscribe route implementation
  • "timesheet-viewMode": Used in timesheet page component
  • "Waitlist": Used in sidebar opt-in form component
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify that the newly added words are used in the codebase
# Note: Using case-insensitive search as specified in the config

echo "Checking usage of new dictionary words..."

# Search for each word
for word in hookform apikey DATACENTER mailchimp "timesheet-viewMode" Waitlist; do
  echo "Searching for: $word"
  rg -i "$word" --type-not json
done

Length of output: 2976

apps/web/styles/globals.css (1)

152-152: Verify text readability across different viewport sizes.

The addition of text-sm utility class to the body element will ensure consistent text sizing across the application.

Let's check if this change affects any existing responsive text utilities:

✅ Verification successful

The text-sm utility is safely applied and doesn't conflict with other text size utilities

The text size utilities in the codebase are properly scoped:

  • Body text uses text-sm as a default size
  • Tooltip uses text-xs specifically for its content
  • Details label has its own responsive sizing (text-[0.625rem] to text-xs)
  • Nivo calendar text is specifically scoped with text-sm
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for responsive text size utilities that might conflict with text-sm
rg -l 'text-(xs|sm|base|lg|xl)' --type css

Length of output: 156


Script:

#!/bin/bash
# Check the context of text size utilities in globals.css to understand potential conflicts
rg 'text-(xs|sm|base|lg|xl)' apps/web/styles/globals.css -B 2 -A 2

Length of output: 545

apps/web/components/ui/sidebar.tsx (2)

Line range hint 391-673: LGTM! Well-structured component hierarchy.

The supporting components (SidebarMenu*, SidebarGroup*, etc.) demonstrate:

  • Good use of TypeScript
  • Proper composition patterns
  • Consistent prop interfaces
  • Clear separation of concerns

16-18: Verify the impact of sidebar width changes on existing layouts.

The sidebar widths have been reduced:

  • Full width: 17rem → 16rem
  • Icon width: 5rem → 3rem

These changes could affect existing layouts and content alignment.

✅ Verification successful

Based on the search results, I can now provide a final response:

The sidebar width changes appear safe to implement

The width changes (17rem → 16rem and 5rem → 3rem) are localized to the sidebar component and properly handled through CSS variables that are consistently used throughout the codebase. The search results show:

  1. The sidebar widths are defined as CSS variables (--sidebar-width, --sidebar-width-icon) and referenced appropriately in all dependent components
  2. No hardcoded references to the old width values (17rem or 5rem) were found in layouts or other components
  3. The responsive layout system properly handles width transitions through CSS variables

The changes reduce the sidebar width slightly while maintaining the existing responsive behavior and layout structure.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Search for any hardcoded width values in the codebase that might need adjustment

# Look for any CSS/style references to the old widths
rg -t css -t tsx -t ts "17rem|5rem" 

# Look for potential layout dependencies
rg -t tsx -t ts "sidebar.*width|width.*sidebar"

Length of output: 143


Script:

#!/bin/bash
# Search for any references to the old widths using ripgrep without file type filters
rg "17rem|5rem"

# Look for potential layout dependencies
rg "sidebar.*width|width.*sidebar"

# Search for any style-related files that might contain width references
fd "\.(css|scss|tsx|ts|js|jsx)$" --exec rg -l "rem"

Length of output: 59143

Comment on lines +11 to +17
const Label = React.forwardRef<
React.ElementRef<typeof LabelPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root> & VariantProps<typeof labelVariants>
>(({ className, ...props }, ref) => (
<LabelPrimitive.Root ref={ref} className={cn(labelVariants(), className)} {...props} />
));
Label.displayName = LabelPrimitive.Root.displayName;
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Consider adding required prop validation for accessibility.

While the implementation is solid, consider adding validation for the htmlFor prop to ensure proper label-input association, which is crucial for accessibility.

 const Label = React.forwardRef<
   React.ElementRef<typeof LabelPrimitive.Root>,
   React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root> & VariantProps<typeof labelVariants>
->(({ className, ...props }, ref) => (
+>(({ className, htmlFor, ...props }, ref) => {
+  if (process.env.NODE_ENV !== 'production' && !htmlFor) {
+    console.warn(
+      'Label component: Missing htmlFor prop. This may cause accessibility issues.'
+    );
+  }
+  return (
   <LabelPrimitive.Root ref={ref} className={cn(labelVariants(), className)} {...props} />
-));
+  );
+});
📝 Committable suggestion

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

Suggested change
const Label = React.forwardRef<
React.ElementRef<typeof LabelPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root> & VariantProps<typeof labelVariants>
>(({ className, ...props }, ref) => (
<LabelPrimitive.Root ref={ref} className={cn(labelVariants(), className)} {...props} />
));
Label.displayName = LabelPrimitive.Root.displayName;
const Label = React.forwardRef<
React.ElementRef<typeof LabelPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root> & VariantProps<typeof labelVariants>
>(({ className, htmlFor, ...props }, ref) => {
if (process.env.NODE_ENV !== 'production' && !htmlFor) {
console.warn(
'Label component: Missing htmlFor prop. This may cause accessibility issues.'
);
}
return (
<LabelPrimitive.Root ref={ref} className={cn(labelVariants(), className)} {...props} />
);
});
Label.displayName = LabelPrimitive.Root.displayName;

Comment on lines +56 to 59
className=" text-[#5000B9] dark:text-primary-light truncate max-w-[230px] overflow-hidden whitespace-nowrap mr-0"
style={{ textOverflow: 'ellipsis' }}
>
{element.href}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Consider enhancing security for external links.

The link element could benefit from additional security attributes when opening external URLs.

 <a
   href={href}
   rel="noreferrer"
   target="_blank"
   className=" text-[#5000B9] dark:text-primary-light truncate max-w-[230px] overflow-hidden whitespace-nowrap mr-0"
+  rel="noopener noreferrer"
   style={{ textOverflow: 'ellipsis' }}
 >

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

Comment on lines +3 to +20
export const POST = async (req: NextRequest) => {
// 1. Destructure the email address from the request body.
const reqData = (await req.json()) as {
email_address: string;
tags: string[];
captcha?: string;
};

if (!reqData.email_address) {
// 2. Throw an error if an email wasn't provided.
return NextResponse.json({ error: 'Email is required' }, { status: 400 });
}

if (!reqData.captcha) {
// 2. Display an error if the captcha code wasn't provided.
console.error('ERROR: Please provide required fields', 'STATUS: 400');
}

Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Strengthen input validation and security measures

The current input validation has several security concerns:

  1. Email validation is too permissive
  2. Captcha validation is ineffective (logs but doesn't block)
  3. Missing rate limiting could enable API abuse

Consider implementing these improvements:

 export const POST = async (req: NextRequest) => {
+  // Rate limiting
+  const ip = req.headers.get('x-forwarded-for') || 'unknown';
+  const rateLimiter = await getRateLimiter(ip);
+  if (!rateLimiter.isAllowed) {
+    return NextResponse.json(
+      { error: 'Too many requests' },
+      { status: 429 }
+    );
+  }
+
   const reqData = (await req.json()) as {
     email_address: string;
     tags: string[];
     captcha?: string;
   };
 
-  if (!reqData.email_address) {
+  const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
+  if (!reqData.email_address || !emailRegex.test(reqData.email_address)) {
     return NextResponse.json({ error: 'Email is required' }, { status: 400 });
   }
 
   if (!reqData.captcha) {
-    console.error('ERROR: Please provide required fields', 'STATUS: 400');
+    return NextResponse.json(
+      { error: 'Captcha verification failed' },
+      { status: 400 }
+    );
   }
+
+  // Verify captcha
+  const isCaptchaValid = await verifyCaptcha(reqData.captcha);
+  if (!isCaptchaValid) {
+    return NextResponse.json(
+      { error: 'Invalid captcha' },
+      { status: 400 }
+    );
+  }

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

Comment on lines +21 to +29
try {
// 3. Fetch the environment variables.
const LIST_ID = process.env.MAILCHIMP_LIST_ID;
const API_KEY = process.env.MAILCHIMP_API_KEY ? process.env.MAILCHIMP_API_KEY : '';
if (!LIST_ID || !API_KEY) {
throw new Error('Missing Mailchimp environment variables');
}
// 4. API keys are in the form <key>-us3.
const DATACENTER = API_KEY.split('-')[1];
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Improve API key validation and error handling

The current API key handling is fragile and could fail silently with malformed keys.

Apply this improvement:

   try {
     const LIST_ID = process.env.MAILCHIMP_LIST_ID;
-    const API_KEY = process.env.MAILCHIMP_API_KEY ? process.env.MAILCHIMP_API_KEY : '';
+    const API_KEY = process.env.MAILCHIMP_API_KEY?.trim() || '';
+    
     if (!LIST_ID || !API_KEY) {
       throw new Error('Missing Mailchimp environment variables');
     }
-    const DATACENTER = API_KEY.split('-')[1];
+    
+    // Validate API key format
+    const API_KEY_REGEX = /^[a-f0-9]{32}-([a-z]{2}\d{1,2})$/;
+    const match = API_KEY.match(API_KEY_REGEX);
+    if (!match) {
+      throw new Error('Invalid Mailchimp API key format');
+    }
+    const DATACENTER = match[1];
📝 Committable suggestion

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

Suggested change
try {
// 3. Fetch the environment variables.
const LIST_ID = process.env.MAILCHIMP_LIST_ID;
const API_KEY = process.env.MAILCHIMP_API_KEY ? process.env.MAILCHIMP_API_KEY : '';
if (!LIST_ID || !API_KEY) {
throw new Error('Missing Mailchimp environment variables');
}
// 4. API keys are in the form <key>-us3.
const DATACENTER = API_KEY.split('-')[1];
try {
// 3. Fetch the environment variables.
const LIST_ID = process.env.MAILCHIMP_LIST_ID;
const API_KEY = process.env.MAILCHIMP_API_KEY?.trim() || '';
if (!LIST_ID || !API_KEY) {
throw new Error('Missing Mailchimp environment variables');
}
// Validate API key format
const API_KEY_REGEX = /^[a-f0-9]{32}-([a-z]{2}\d{1,2})$/;
const match = API_KEY.match(API_KEY_REGEX);
if (!match) {
throw new Error('Invalid Mailchimp API key format');
}
const DATACENTER = match[1];

Comment on lines +30 to +34
const mailchimpData = {
email_address: reqData.email_address,
status: 'subscribed',
tags: reqData.tags ? [...reqData.tags] : ['Ever Teams']
};
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Enhance data preparation and configuration flexibility

The current implementation has hardcoded values and lacks validation for tags.

Consider these improvements:

+    const DEFAULT_TAG = process.env.MAILCHIMP_DEFAULT_TAG || 'Ever Teams';
+    
+    // Validate tags
+    const validateTags = (tags: string[]) => {
+      return tags.every(tag => 
+        typeof tag === 'string' && 
+        tag.length <= 100 &&
+        /^[\w\s-]+$/.test(tag)
+      );
+    };
+
     const mailchimpData = {
       email_address: reqData.email_address,
       status: 'subscribed',
-      tags: reqData.tags ? [...reqData.tags] : ['Ever Teams']
+      tags: reqData.tags && validateTags(reqData.tags) 
+        ? [...reqData.tags] 
+        : [DEFAULT_TAG]
     };
📝 Committable suggestion

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

Suggested change
const mailchimpData = {
email_address: reqData.email_address,
status: 'subscribed',
tags: reqData.tags ? [...reqData.tags] : ['Ever Teams']
};
const DEFAULT_TAG = process.env.MAILCHIMP_DEFAULT_TAG || 'Ever Teams';
// Validate tags
const validateTags = (tags: string[]) => {
return tags.every(tag =>
typeof tag === 'string' &&
tag.length <= 100 &&
/^[\w\s-]+$/.test(tag)
);
};
const mailchimpData = {
email_address: reqData.email_address,
status: 'subscribed',
tags: reqData.tags && validateTags(reqData.tags)
? [...reqData.tags]
: [DEFAULT_TAG]
};

Comment on lines +71 to +110
return state == 'expanded' ? (
<Form {...form}>
<Card className="p-1 mt-auto shadow-none">
<form onSubmit={form.handleSubmit(onSubmit)}>
<CardHeader className="flex flex-col gap-1 p-4 pb-0">
<CardTitle className="text-sm font-medium">Subscribe to our newsletter</CardTitle>
<CardDescription className="text-xs">
Opt-in to receive updates and news about Ever Teams.
</CardDescription>
</CardHeader>
<CardContent className="grid gap-2.5 p-4">
<FormField
control={form.control}
name="email"
render={({ field }) => (
<FormItem>
<FormControl>
<SidebarInput
type="email"
placeholder="Email"
className="placeholder:text-xs"
{...field}
/>
</FormControl>
<FormMessage className="text-xs" />
</FormItem>
)}
/>
<Button
type="submit"
className="w-full shadow-none bg-sidebar-primary text-sidebar-primary-foreground"
size="sm"
>
{isLoading ? 'Subscribing...' : 'Subscribe'}
</Button>
</CardContent>
</form>
</Card>
</Form>
) : null;
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Enhance accessibility and user experience.

The form could benefit from improved accessibility and user feedback during loading states.

 <Card className="p-1 mt-auto shadow-none">
-  <form onSubmit={form.handleSubmit(onSubmit)}>
+  <form 
+    onSubmit={form.handleSubmit(onSubmit)}
+    aria-label="Newsletter subscription form"
+  >
     <CardHeader className="flex flex-col gap-1 p-4 pb-0">
       <CardTitle className="text-sm font-medium">Subscribe to our newsletter</CardTitle>
       <CardDescription className="text-xs">
         Opt-in to receive updates and news about Ever Teams.
       </CardDescription>
     </CardHeader>
     <CardContent className="grid gap-2.5 p-4">
       <FormField
         control={form.control}
         name="email"
         render={({ field }) => (
           <FormItem>
             <FormControl>
               <SidebarInput
                 type="email"
                 placeholder="Email"
                 className="placeholder:text-xs"
+                aria-label="Email address"
+                disabled={isLoading}
+                autoComplete="email"
                 {...field}
               />
             </FormControl>
             <FormMessage className="text-xs" />
           </FormItem>
         )}
       />
       <Button
         type="submit"
         className="w-full shadow-none bg-sidebar-primary text-sidebar-primary-foreground"
         size="sm"
+        disabled={isLoading}
+        aria-busy={isLoading}
       >
         {isLoading ? 'Subscribing...' : 'Subscribe'}
       </Button>
     </CardContent>
   </form>
 </Card>
📝 Committable suggestion

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

Suggested change
return state == 'expanded' ? (
<Form {...form}>
<Card className="p-1 mt-auto shadow-none">
<form onSubmit={form.handleSubmit(onSubmit)}>
<CardHeader className="flex flex-col gap-1 p-4 pb-0">
<CardTitle className="text-sm font-medium">Subscribe to our newsletter</CardTitle>
<CardDescription className="text-xs">
Opt-in to receive updates and news about Ever Teams.
</CardDescription>
</CardHeader>
<CardContent className="grid gap-2.5 p-4">
<FormField
control={form.control}
name="email"
render={({ field }) => (
<FormItem>
<FormControl>
<SidebarInput
type="email"
placeholder="Email"
className="placeholder:text-xs"
{...field}
/>
</FormControl>
<FormMessage className="text-xs" />
</FormItem>
)}
/>
<Button
type="submit"
className="w-full shadow-none bg-sidebar-primary text-sidebar-primary-foreground"
size="sm"
>
{isLoading ? 'Subscribing...' : 'Subscribe'}
</Button>
</CardContent>
</form>
</Card>
</Form>
) : null;
return state == 'expanded' ? (
<Form {...form}>
<Card className="p-1 mt-auto shadow-none">
<form
onSubmit={form.handleSubmit(onSubmit)}
aria-label="Newsletter subscription form"
>
<CardHeader className="flex flex-col gap-1 p-4 pb-0">
<CardTitle className="text-sm font-medium">Subscribe to our newsletter</CardTitle>
<CardDescription className="text-xs">
Opt-in to receive updates and news about Ever Teams.
</CardDescription>
</CardHeader>
<CardContent className="grid gap-2.5 p-4">
<FormField
control={form.control}
name="email"
render={({ field }) => (
<FormItem>
<FormControl>
<SidebarInput
type="email"
placeholder="Email"
className="placeholder:text-xs"
aria-label="Email address"
disabled={isLoading}
autoComplete="email"
{...field}
/>
</FormControl>
<FormMessage className="text-xs" />
</FormItem>
)}
/>
<Button
type="submit"
className="w-full shadow-none bg-sidebar-primary text-sidebar-primary-foreground"
size="sm"
disabled={isLoading}
aria-busy={isLoading}
>
{isLoading ? 'Subscribing...' : 'Subscribe'}
</Button>
</CardContent>
</form>
</Card>
</Form>
) : null;

Comment on lines +85 to +89
'hover:bg-[#eaeef4] text-[#1F2937] items-center dark:text-gray-50 data-[active=true]:bg-[#eaeef4] min-h-10 h-10 dark:hover:bg-sidebar-accent px-3 py-2 transition-colors duration-300 !text-sm',
state === 'collapsed' ? ' justify-center' : '',
index === activeMenuIndex
? 'font-medium bg-[#eaeef4] dark:text-gray-50 dark:bg-sidebar-accent'
: '!font-normal' // Style for active menu
? 'font-normal bg-[#eaeef4] dark:text-gray-50 dark:bg-sidebar-accent'
: '!font-light' // Style for active menu
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Refactor repeated styling patterns and use theme variables

Several styling issues need attention:

  1. Duplicate styling logic between menu and sub-menu buttons
  2. Hardcoded color values (#eaeef4, #1F2937)
  3. Overuse of !important flags for font weights

Consider creating a shared style utility:

const getMenuButtonStyles = (isCollapsed: boolean, isActive: boolean) => cn(
  'hover:bg-accent text-foreground items-center dark:text-gray-50',
  'data-[active=true]:bg-accent min-h-10 h-10',
  'dark:hover:bg-sidebar-accent px-3 py-2',
  'transition-colors duration-300 text-sm',
  isCollapsed && 'justify-center',
  isActive ? 'font-normal bg-accent dark:bg-sidebar-accent' : 'font-light'
);

Also applies to: 117-121

Comment on lines +69 to +71
<SidebarMenu
className={cn('w-full max-w-[230px]', state === 'collapsed' ? 'items-center gap-y-2' : '', 'gap-y-1')}
>
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Consider consolidating width constraints and gap handling

  1. The max-width constraint (230px) is duplicated in child components (see line 157)
  2. There are potentially conflicting gap classes: gap-y-1 and gap-y-2 for collapsed state

Consider moving the width constraint to a CSS variable and using a single gap strategy:

- className={cn('w-full max-w-[230px]', state === 'collapsed' ? 'items-center gap-y-2' : '', 'gap-y-1')}
+ className={cn('w-full var(--sidebar-width)', state === 'collapsed' ? 'items-center' : '', 'gap-y-2')}

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

@@ -44,6 +44,7 @@ const eslintBuildConfig = process.env.NEXT_IGNORE_ESLINT_ERROR_ON_BUILD
const nextConfig = {
output: ['standalone', 'export'].includes(BUILD_OUTPUT_MODE) ? BUILD_OUTPUT_MODE : undefined,
reactStrictMode: false,
transpilePackages: ['geist'],
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Codebase verification

Geist package setup needs attention

The verification reveals potential issues with the geist package setup:

  1. While geist v1.3.1 is correctly listed in package.json dependencies and properly configured in next.config.js for transpilation, there are no direct imports or usage of geist components found in the codebase.
  2. The codebase appears to use custom components (Button, Input, Card, Modal) instead of geist components, suggesting the geist dependency might be unnecessary.

Recommendations:

  • Remove the unused geist dependency and its transpilation configuration if it's not being utilized
  • Or, if geist UI components are intended to be used, update the components to properly import and use them
🔗 Analysis chain

LGTM! Verify geist package setup

The addition of geist to transpilePackages is correct and follows Next.js best practices for handling external UI libraries.

Let's verify the geist package setup:

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify geist package installation and configuration

# Check if geist is listed in package.json with the correct version
echo "Checking package.json for geist dependency..."
cat package.json | jq '.dependencies.geist, .devDependencies.geist'

# Look for geist imports in the codebase
echo "Checking geist usage in the codebase..."
rg "from ['|\"]geist" --type ts --type tsx

Length of output: 344


Script:

#!/bin/bash
# Let's try a different approach to verify geist setup

# Check package.json files in all directories
echo "Checking all package.json files for geist..."
fd package.json --type f --exec cat {} \; | jq -c 'select(.dependencies.geist != null or .devDependencies.geist != null)'

# Look for geist imports with broader pattern and file types
echo "Checking geist usage in the codebase..."
rg "geist" --type js --type jsx --type ts

# Check if there are any .tsx files
echo "Checking for .tsx files..."
fd -e tsx

# Check the content of next.config.js to understand the context better
echo "Content of next.config.js:"
cat apps/web/next.config.js

Length of output: 50049


Script:

#!/bin/bash
# Let's verify if geist is properly installed and used in the project

# Check all package.json files in the workspace for geist dependency
echo "Checking workspace package.json files for geist..."
fd package.json --type f --exec grep -l "geist"

# Look for geist imports with a more comprehensive pattern
echo "Checking for geist usage in the codebase..."
rg "from ['\"]geist" --type=js,jsx,ts,tsx || true
rg "import.*geist" --type=js,jsx,ts,tsx || true

# Check if there are any UI components from geist being used
echo "Checking for geist UI components usage..."
rg "Geist|<(Button|Input|Card|Modal)" --type=js,jsx,ts,tsx || true

Length of output: 656


Script:

#!/bin/bash
# Let's try one final verification with corrected file type flags

# Check the content of web/package.json to see geist version
echo "Checking web/package.json content..."
cat apps/web/package.json | jq '.dependencies.geist, .devDependencies.geist'

# Look for geist imports with individual file type flags
echo "Checking for geist usage..."
rg "from ['\"]geist" -t ts || true
rg "from ['\"]geist" -t tsx || true
rg "import.*geist" -t ts || true
rg "import.*geist" -t tsx || true

# Check for UI components with individual file type flags
echo "Checking for geist UI components..."
rg "Geist|<(Button|Input|Card|Modal)" -t ts || true
rg "Geist|<(Button|Input|Card|Modal)" -t tsx || true

Length of output: 53172

Comment on lines +38 to +40
if (!fieldContext) {
throw new Error('useFormField should be used within <FormField>');
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Add error handling for itemContext in useFormField.

In the useFormField hook, the itemContext obtained from React.useContext(FormItemContext) might be undefined if useFormField is used outside of a FormItem component. This could lead to a runtime error when destructuring { id } from itemContext.

Apply this diff to ensure itemContext is not undefined:

  const fieldContext = React.useContext(FormFieldContext);
  const itemContext = React.useContext(FormItemContext);
  const { getFieldState, formState } = useFormContext();

  if (!fieldContext) {
    throw new Error('useFormField should be used within <FormField>');
  }
+ if (!itemContext) {
+   throw new Error('useFormField should be used within <FormItem>');
+ }

  const fieldState = getFieldState(fieldContext.name, formState);

  const { id } = itemContext;
📝 Committable suggestion

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

Suggested change
if (!fieldContext) {
throw new Error('useFormField should be used within <FormField>');
}
if (!fieldContext) {
throw new Error('useFormField should be used within <FormField>');
}
if (!itemContext) {
throw new Error('useFormField should be used within <FormItem>');
}

@evereq evereq merged commit 74bdec5 into develop Nov 21, 2024
14 checks passed
@evereq evereq deleted the refactor/sidebar branch November 21, 2024 22:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request Ever Teams Improvement Improvement UI/UX WEB Web app
Projects
None yet
2 participants