Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
127 changes: 127 additions & 0 deletions web/default/src/components/dialog.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
/*
Copyright (C) 2023-2026 QuantumNous

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.

For commercial licensing, please contact support@quantumnous.com
*/
import * as React from 'react'
import { cn } from '@/lib/utils'
import {
Dialog as DialogRoot,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
} from '@/components/ui/dialog'

type DialogProps = React.ComponentProps<typeof DialogRoot> & {
title: React.ReactNode
description?: React.ReactNode
children: React.ReactNode
trigger?: React.ReactElement
footer?: React.ReactNode
contentHeight?: React.CSSProperties['height']
contentClassName?: string
headerClassName?: string
titleClassName?: string
descriptionClassName?: string
bodyClassName?: string
footerClassName?: string
initialFocus?: boolean
showCloseButton?: boolean
}

const dialogContentMotionClassName =
'data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95 duration-100'

export function Dialog({
title,
description,
children,
trigger,
footer,
contentHeight = 'auto',
contentClassName,
headerClassName,
titleClassName,
descriptionClassName,
bodyClassName,
footerClassName,
initialFocus,
showCloseButton,
...dialogProps
Comment on lines +51 to +66

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win

Refactor to avoid props destructuring.

The coding guidelines require using props.xxx directly instead of destructuring component props for clarity. As per coding guidelines, "Do not destructure component props; use props.xxx directly instead for clarity".

♻️ Refactor to use props directly
-export function Dialog({
-  title,
-  description,
-  children,
-  trigger,
-  footer,
-  contentHeight = 'auto',
-  contentClassName,
-  headerClassName,
-  titleClassName,
-  descriptionClassName,
-  bodyClassName,
-  footerClassName,
-  initialFocus,
-  showCloseButton,
-  ...dialogProps
-}: DialogProps) {
+export function Dialog(props: DialogProps) {
+  const {
+    title,
+    description,
+    children,
+    trigger,
+    footer,
+    contentHeight = 'auto',
+    contentClassName,
+    headerClassName,
+    titleClassName,
+    descriptionClassName,
+    bodyClassName,
+    footerClassName,
+    initialFocus,
+    showCloseButton,
+    ...dialogProps
+  } = props
+
   return (
-    <DialogRoot {...dialogProps}>
-      {trigger ? <DialogTrigger render={trigger} /> : null}
+    <DialogRoot {...dialogProps}>
+      {props.trigger ? <DialogTrigger render={props.trigger} /> : null}
       <DialogContent
         className={cn(
           'flex max-h-[calc(100vh-2rem)] w-full flex-col gap-4 overflow-hidden p-4 sm:max-w-2xl sm:p-6',
-          contentClassName,
+          props.contentClassName,
           dialogContentMotionClassName
         )}
-        initialFocus={initialFocus}
-        showCloseButton={showCloseButton}
+        initialFocus={props.initialFocus}
+        showCloseButton={props.showCloseButton}
         style={
           {
-            '--dialog-content-height': contentHeight,
+            '--dialog-content-height': props.contentHeight ?? 'auto',
           } as React.CSSProperties
         }
       >
         <DialogHeader
-          className={cn('flex-shrink-0 text-start', headerClassName)}
+          className={cn('flex-shrink-0 text-start', props.headerClassName)}
         >
-          <DialogTitle className={titleClassName}>{title}</DialogTitle>
-          {description ? (
-            <DialogDescription className={descriptionClassName}>
-              {description}
+          <DialogTitle className={props.titleClassName}>{props.title}</DialogTitle>
+          {props.description ? (
+            <DialogDescription className={props.descriptionClassName}>
+              {props.description}
             </DialogDescription>
           ) : null}
         </DialogHeader>
 
         <div
           className={cn(
             '-mx-1 min-h-0 overflow-x-hidden overflow-y-auto overscroll-contain',
             'h-[var(--dialog-content-height)] max-h-[calc(100vh-14rem)]'
           )}
         >
           <div
             className={cn(
               'min-w-0 px-1 py-1',
               '[&_form]:overflow-x-visible',
               '[&_[data-slot=scroll-area-viewport]]:px-1 [&_[data-slot=scroll-area-viewport]]:py-1',
-              bodyClassName
+              props.bodyClassName
             )}
           >
-            {children}
+            {props.children}
           </div>
         </div>
 
-        {footer ? (
+        {props.footer ? (
           <DialogFooter
             className={cn(
               'flex-shrink-0 gap-2 sm:-mx-6 sm:-mb-6 sm:justify-end sm:p-6',
-              footerClassName
+              props.footerClassName
             )}
           >
-            {footer}
+            {props.footer}
           </DialogFooter>
         ) : null}
       </DialogContent>
     </DialogRoot>
   )
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@web/default/src/components/dialog.tsx` around lines 51 - 66, The Dialog
component currently destructures its props in the function signature (symbols:
Dialog, title, description, children, trigger, footer, contentHeight,
contentClassName, headerClassName, titleClassName, descriptionClassName,
bodyClassName, footerClassName, initialFocus, showCloseButton, dialogProps);
refactor it to accept a single props parameter and replace all uses of the
destructured names with props.xxx (e.g., props.title, props.description,
props.initialFocus, etc.), keeping default values (like contentHeight = 'auto')
applied inside the function body (e.g., const contentHeight =
props.contentHeight ?? 'auto') and leaving the rest of the implementation and
exported name unchanged.

Source: Coding guidelines

}: DialogProps) {
return (
<DialogRoot {...dialogProps}>
{trigger ? <DialogTrigger render={trigger} /> : null}
<DialogContent
className={cn(
'flex max-h-[calc(100vh-2rem)] w-full flex-col gap-4 overflow-hidden p-4 sm:max-w-2xl sm:p-6',
contentClassName,
dialogContentMotionClassName
)}
initialFocus={initialFocus}
showCloseButton={showCloseButton}
style={
{
'--dialog-content-height': contentHeight,
} as React.CSSProperties
}
>
<DialogHeader
className={cn('flex-shrink-0 text-start', headerClassName)}
>
<DialogTitle className={titleClassName}>{title}</DialogTitle>
{description ? (
<DialogDescription className={descriptionClassName}>
{description}
</DialogDescription>
) : null}
</DialogHeader>

<div
className={cn(
'-mx-1 min-h-0 overflow-x-hidden overflow-y-auto overscroll-contain',
'h-[var(--dialog-content-height)] max-h-[calc(100vh-14rem)]'
)}
>
<div
className={cn(
'min-w-0 px-1 py-1',
'[&_form]:overflow-x-visible',
'[&_[data-slot=scroll-area-viewport]]:px-1 [&_[data-slot=scroll-area-viewport]]:py-1',
bodyClassName
)}
>
{children}
</div>
</div>

{footer ? (
<DialogFooter
className={cn(
'flex-shrink-0 gap-2 sm:-mx-6 sm:-mb-6 sm:justify-end sm:p-6',
footerClassName
)}
>
{footer}
</DialogFooter>
) : null}
</DialogContent>
</DialogRoot>
)
}
43 changes: 17 additions & 26 deletions web/default/src/components/layout/components/public-header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,8 @@ import { useNotifications } from '@/hooks/use-notifications'
import { useSystemConfig } from '@/hooks/use-system-config'
import { useTopNavLinks } from '@/hooks/use-top-nav-links'
import { Button } from '@/components/ui/button'
import {
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
} from '@/components/ui/dialog'
import { Skeleton } from '@/components/ui/skeleton'
import { Dialog } from '@/components/dialog'
import { LanguageSwitcher } from '@/components/language-switcher'
import { NotificationPopover } from '@/components/notification-popover'
import { ProfileDropdown } from '@/components/profile-dropdown'
Expand Down Expand Up @@ -427,28 +420,26 @@ export function PublicHeader(props: PublicHeaderProps) {
closeAuthPrompt()
}
}}
>
<DialogContent className='sm:max-w-md'>
<DialogHeader>
<DialogTitle>{t('Sign in required')}</DialogTitle>
<DialogDescription>
{t('Please sign in to view {{module}}.', {
module: authPromptTarget?.title || '',
})}
</DialogDescription>
</DialogHeader>
<div className='bg-muted/40 text-muted-foreground rounded-lg px-3 py-2 text-sm'>
{t('Redirecting to sign in in {{seconds}} seconds.', {
seconds: authPromptSecondsLeft,
})}
</div>
<DialogFooter>
title={t('Sign in required')}
description={t('Please sign in to view {{module}}.', {
module: authPromptTarget?.title || '',
})}
contentClassName='sm:max-w-md'
contentHeight='auto'
footer={
<>
<Button variant='outline' onClick={closeAuthPrompt}>
{t('Cancel')}
</Button>
<Button onClick={navigateToSignIn}>{t('Sign in now')}</Button>
</DialogFooter>
</DialogContent>
</>
}
>
<div className='bg-muted/40 text-muted-foreground rounded-lg px-3 py-2 text-sm'>
{t('Redirecting to sign in in {{seconds}} seconds.', {
seconds: authPromptSecondsLeft,
})}
</div>
</Dialog>
</>
)
Expand Down
Loading