Add possible typings and runtime type checks for FlexView

This commit is contained in:
Maximilian Harz 2025-02-03 20:21:41 +01:00
parent 89b780eee2
commit 7102ae72cb
4 changed files with 82 additions and 46 deletions

View File

@ -4,24 +4,22 @@ import type { Item } from '#types/Item'
export const ProfileTextView = ({
item,
dataField,
text,
heading,
hideWhenEmpty,
}: {
item: Item
dataField: string
text: string
heading: string
hideWhenEmpty: boolean
}) => {
return (
<div className='tw-my-10 tw-mt-2 tw-px-6'>
{/* eslint-disable-next-line security/detect-object-injection */}
{!(item[dataField] === '' && hideWhenEmpty) && (
{!(text === '' && hideWhenEmpty) && (
<h2 className='tw-text-lg tw-font-semibold'>{heading}</h2>
)}
<div className='tw-mt-2 tw-text-sm'>
{/* eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, security/detect-object-injection */}
<TextView itemId={item.id} rawText={dataField ? item[dataField] : item.text} />
<TextView itemId={item.id} rawText={text} />
</div>
</div>
)

View File

@ -1,18 +1,51 @@
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
import { ContactInfoView } from '#components/Profile/Subcomponents/ContactInfoView'
import { GroupSubHeaderView } from '#components/Profile/Subcomponents/GroupSubHeaderView'
import { ProfileStartEndView } from '#components/Profile/Subcomponents/ProfileStartEndView'
import { ProfileTextView } from '#components/Profile/Subcomponents/ProfileTextView'
import type { Item } from '#types/Item'
import type { Key } from 'react'
import type {
ContactInfoParameters,
GroupSubHeaderParameters,
Parameters,
TextParameters,
} from '#types/ItemType'
const componentMap = {
groupSubheaders: GroupSubHeaderView,
texts: ProfileTextView,
contactInfos: ContactInfoView,
startEnd: ProfileStartEndView,
const componentMap: Record<
string,
((item: Item, parameters: Parameters) => JSX.Element) | undefined
> = {
groupSubheaders: (item: Item, parameters: GroupSubHeaderParameters) => (
<GroupSubHeaderView
item={item}
shareBaseUrl={parameters.shareBaseUrl}
platforms={parameters.platforms}
/>
),
texts: (item: Item, parameters: TextParameters) => {
if (!(parameters.dataField in item)) {
throw new Error(`Item does not have property ${parameters.dataField}`)
}
const text = item[parameters.dataField]
if (typeof text !== 'string') {
throw new Error(`Property ${parameters.dataField} is not a string`)
}
return (
<ProfileTextView
item={item}
heading={parameters.heading}
text={text}
hideWhenEmpty={parameters.hideWhenEmpty}
/>
)
},
contactInfos: (item: Item, parameters: ContactInfoParameters) => (
<ContactInfoView item={item} heading={parameters.heading} />
),
startEnd: (item: Item) => <ProfileStartEndView item={item} />,
// weitere Komponenten hier
}
@ -21,17 +54,14 @@ export const FlexView = ({ item }: { item: Item }) => {
console.log(item)
return (
<div className='tw-h-full tw-overflow-y-auto fade'>
{item.layer?.itemType.profileTemplate.map(
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(templateItem: { collection: string | number; id: Key | null | undefined; item: any }) => {
const TemplateComponent = componentMap[templateItem.collection]
return TemplateComponent ? (
<TemplateComponent key={templateItem.id} item={item} {...templateItem.item} />
) : (
<div key={templateItem.id}>Component not found</div>
)
},
)}
{item.layer?.itemType.profileTemplate.map((templateItem) => {
const TemplateComponent = componentMap[templateItem.collection]
return TemplateComponent ? (
TemplateComponent(item, templateItem.item)
) : (
<div key={templateItem.id}>Component not found</div>
)
})}
</div>
)
}

22
types/Item.d.ts vendored
View File

@ -7,7 +7,7 @@ import type { Point } from 'geojson'
type TagIds = { tags_id: string }[]
export interface Item {
interface BaseItem {
id: string
name: string
text: string
@ -40,22 +40,6 @@ export interface Item {
telephone?: string
next_appointment?: string
type?: ItemType
// {
// coordinates: [number, number]
/* constructor(
id: string,
name: string,
text: string,
position: Geometry,
layer?: LayerProps,
api?: ItemsApi<any>,
) {
this.id = id
this.name = name
this.text = text
this.position = position
this.layer = layer
this.api = api
} */
}
export type Item = BaseItem & Record<string, unknown>

28
types/ItemType.d.ts vendored
View File

@ -1,11 +1,35 @@
import type { Key } from 'react'
interface TextParameters {
dataField: string
heading: string
hideWhenEmpty: boolean
}
interface GroupSubHeaderParameters {
shareBaseUrl: string
platforms: string[]
}
interface ContactInfoParameters {
heading: string
}
interface StartEndParemeters {
heading: string
}
export type Parameters =
| TextParameters
| GroupSubHeaderParameters
| ContactInfoParameters
| StartEndParemeters
export interface ItemType {
name: string
show_start_end: boolean
show_text: boolean
// eslint-disable-next-line @typescript-eslint/no-explicit-any
profileTemplate: { collection: string | number; id: Key | null | undefined; item: any }[]
profileTemplate: { collection: string | number; id: Key | null | undefined; item: Parameters }[]
offers_and_needs: boolean
icon_as_labels: unknown
relations: boolean