Anton Tranelis f53c02ead9
Update lib/src/Components/Profile/Subcomponents/TabsContainerForm.tsx
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-12-16 21:12:38 +01:00

130 lines
4.4 KiB
TypeScript

import { useCallback, useEffect, useState } from 'react'
import { useLocation, useNavigate } from 'react-router-dom'
import { ContactInfoForm } from '#components/Profile/Subcomponents/ContactInfoForm'
import { CrowdfundingForm } from '#components/Profile/Subcomponents/CrowdfundingForm'
import { GalleryForm } from '#components/Profile/Subcomponents/GalleryForm'
import { GroupSubheaderForm } from '#components/Profile/Subcomponents/GroupSubheaderForm'
import { ProfileStartEndForm } from '#components/Profile/Subcomponents/ProfileStartEndForm'
import { ProfileTagsForm } from '#components/Profile/Subcomponents/ProfileTagsForm'
import { ProfileTextForm } from '#components/Profile/Subcomponents/ProfileTextForm'
import type { FormState } from '#types/FormState'
import type { Item } from '#types/Item'
import type { Key } from 'react'
// eslint-disable-next-line @typescript-eslint/no-explicit-any
type ComponentMap = Record<string, React.ComponentType<any>>
const componentMap: ComponentMap = {
groupSubheaders: GroupSubheaderForm,
texts: ProfileTextForm,
contactInfos: ContactInfoForm,
startEnd: ProfileStartEndForm,
crowdfundings: CrowdfundingForm,
gallery: GalleryForm,
inviteLinks: () => null,
relations: () => null, // Relations are not editable in form
tags_component: ProfileTagsForm,
attestations_component: () => null, // Attestations are view-only
}
interface TabItem {
id: string
title: string
icon?: string
// eslint-disable-next-line @typescript-eslint/no-explicit-any
items: { collection: string; id: Key | null | undefined; item: any }[]
}
interface Props {
item: Item
state: FormState
setState: React.Dispatch<React.SetStateAction<FormState>>
tabs: TabItem[]
iconAsLabels?: boolean
}
export const TabsContainerForm = ({ item, state, setState, tabs, iconAsLabels = false }: Props) => {
const location = useLocation()
const navigate = useNavigate()
const [activeTab, setActiveTab] = useState<number>(0)
const tabsLength = tabs.length
useEffect(() => {
if (tabs.length === 0) return
const params = new URLSearchParams(location.search)
const urlTab = params.get('tab')
if (urlTab !== null && !isNaN(Number(urlTab))) {
const index = Number(urlTab)
if (index >= 0 && index < tabs.length) {
setActiveTab(index)
}
}
}, [tabs, tabsLength, location.search])
const updateActiveTab = useCallback(
(index: number) => {
setActiveTab(index)
const params = new URLSearchParams(location.search)
params.set('tab', `${index}`)
const newUrl = location.pathname + '?' + params.toString()
navigate(newUrl)
},
[location.pathname, location.search, navigate],
)
if (tabs.length === 0) {
return null
}
return (
<div className='tw:flex tw:flex-col tw:flex-1 tw:min-h-0'>
{/* Tabs */}
<div className='tw:flex tw:bg-base-200 tw:rounded-lg tw:p-1 tw:mb-4 tw:flex-none'>
{tabs.map((tab, index) => (
<button
type='button'
key={tab.id}
className={`tw:flex-1 tw:flex tw:items-center tw:justify-center tw:gap-2 tw:py-2 tw:px-4 tw:rounded-md tw:transition-colors tw:cursor-pointer ${activeTab === index ? 'tw:bg-primary tw:text-primary-content' : 'hover:tw:bg-base-300'}`}
onClick={() => updateActiveTab(index)}
onKeyDown={(e) => {
if (e.key === 'Enter') {
e.preventDefault()
updateActiveTab(index)
}
}}
>
{tab.icon && <span>{tab.icon}</span>}
{!(iconAsLabels && activeTab !== index) && <span>{tab.title}</span>}
</button>
))}
</div>
{/* Tab Content */}
<div className='tw:flex-1 tw:flex tw:flex-col tw:min-h-0'>
{/* eslint-disable-next-line security/detect-object-injection */}
{tabs[activeTab].items.map((templateItem) => {
const TemplateComponent = componentMap[templateItem.collection]
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
return TemplateComponent ? (
<TemplateComponent
key={templateItem.id}
item={item}
state={state}
setState={setState}
{...templateItem.item}
/>
) : (
<div className='tw:mt-2 tw:flex-none' key={templateItem.id}>
{templateItem.collection} form not found
</div>
)
})}
</div>
</div>
)
}