hensei-web/components/common/Popover/index.tsx
Justin Edmund e4b7f0c356
Fix TypeScript errors for production build (#436)
## Summary
Fixed multiple TypeScript errors that were preventing the production
build from completing on Railway.

## Changes Made

### Nullable Type Fixes
- Fixed `searchParams.toString()` calls with optional chaining (`?.`)
and fallback values
- Fixed `pathname` nullable access in UpdateToastClient
- Added fallbacks for undefined values in translation interpolations

### Type Consistency Fixes
- Fixed recency parameter handling (string from URL, converted to number
internally)
- Removed duplicate local interface definitions for Party and User types
- Fixed Party type mismatches by using global type definitions

### API Route Error Handling
- Fixed error type checking in catch blocks for login/signup routes
- Added proper type guards for axios error objects

### Component Props Fixes
- Fixed RadixSelect.Trigger by removing invalid placeholder prop
- Fixed Toast and Tooltip components by using Omit to exclude
conflicting content type
- Added missing onAdvancedFilter prop to FilterBar components
- Fixed PartyFooter props with required parameters

## Test Plan
- [x] Fixed all TypeScript compilation errors locally
- [ ] Production build should complete successfully on Railway
- [ ] All affected components should function correctly

🤖 Generated with [Claude Code](https://claude.ai/code)

---------

Co-authored-by: Claude <noreply@anthropic.com>
2025-09-04 01:47:10 -07:00

128 lines
2.7 KiB
TypeScript

import React, {
ComponentProps,
PropsWithChildren,
ReactNode,
useEffect,
useState,
} from 'react'
import classNames from 'classnames'
import * as PopoverPrimitive from '@radix-ui/react-popover'
import ChevronIcon from '~public/icons/Chevron.svg'
import styles from './index.module.scss'
interface Props extends ComponentProps<'div'> {
open: boolean
disabled?: boolean
icon?: {
src: string
alt: string
}
trigger?: {
bound?: boolean
className?: string
placeholder?: string
size?: 'small' | 'medium' | 'large'
}
triggerTabIndex?: number
value?: {
element: ReactNode
rawValue: string
}
onOpenChange?: () => void
}
const Popover = React.forwardRef<HTMLDivElement, Props>(function Popover(
{ children, ...props }: PropsWithChildren<Props>,
forwardedRef
) {
// Component state
const [open, setOpen] = useState(false)
// Element classes
const triggerClasses = classNames(
{
[styles.trigger]: true,
[styles.disabled]: props.disabled,
[styles.bound]: props.trigger ? props.trigger.bound : false,
[styles.small]: props.trigger?.size === 'small',
[styles.medium]: !props.trigger || props.trigger?.size === 'medium',
[styles.large]: props.trigger?.size === 'large',
},
props.trigger?.className?.split(' ').map((className) => styles[className])
)
const popoverClasses = classNames(
{
[styles.popover]: true,
},
props.className?.split(' ').map((className) => styles[className])
)
// Hooks
useEffect(() => {
setOpen(props.open)
}, [props.open])
// Elements
const value = props.value ? (
<span className={styles.value} data-value={props.value?.rawValue}>
{props.value?.element}
</span>
) : (
<span
className={classNames({
[styles.value]: true,
[styles.empty]: true,
})}
>
{props.trigger?.placeholder}
</span>
)
const icon = props.icon ? (
<img alt={props.icon.alt} src={props.icon.src} />
) : (
''
)
const arrow = !props.disabled ? (
<i className={styles.icon}>
<ChevronIcon />
</i>
) : (
''
)
return (
<PopoverPrimitive.Root
open={open}
onOpenChange={props.onOpenChange}
modal={true}
>
<PopoverPrimitive.Trigger
className={triggerClasses}
data-placeholder={!props.value}
tabIndex={props.triggerTabIndex}
>
{icon}
{value}
{arrow}
</PopoverPrimitive.Trigger>
<PopoverPrimitive.Content
className={popoverClasses}
sideOffset={6}
ref={forwardedRef}
>
{children}
</PopoverPrimitive.Content>
</PopoverPrimitive.Root>
)
})
Popover.defaultProps = {
disabled: false,
}
export default Popover