diff --git a/src/components/compare/CompareColumnHeader.tsx b/src/components/compare/CompareColumnHeader.tsx
index 3c1168a..a2b0427 100644
--- a/src/components/compare/CompareColumnHeader.tsx
+++ b/src/components/compare/CompareColumnHeader.tsx
@@ -1,6 +1,7 @@
import { Box, Button, Chip, IconButton, Tooltip, Typography } from '@mui/material'
import { X, AlertTriangle, BookmarkCheck, ExternalLink, Kanban } from 'lucide-react'
import { useNavigate } from 'react-router'
+import { usePipelineItems } from '../../hooks/usePipeline'
import { usePipelineStore } from '../../stores/pipelineStore'
import type { UnifiedMatchResult } from '../../domain/unifiedResult'
@@ -20,7 +21,8 @@ interface Props {
export function CompareColumnHeader({ item, onRemove }: Props) {
const navigate = useNavigate()
- const { items: pipelineItems, openSavedDialog } = usePipelineStore()
+ const { data: pipelineItems = [] } = usePipelineItems()
+ const { openSavedDialog } = usePipelineStore()
const meta = TYPE_META[item.resultType] ?? { label: item.resultType, color: '#64748b' }
const prop = item.resultType !== 'FUTURE_AVAILABILITY' ? (item as any).property : null
diff --git a/src/components/pipeline/PipelineDetailPanel.tsx b/src/components/pipeline/PipelineDetailPanel.tsx
index abc2794..21746fd 100644
--- a/src/components/pipeline/PipelineDetailPanel.tsx
+++ b/src/components/pipeline/PipelineDetailPanel.tsx
@@ -7,7 +7,7 @@ import {
AlertTriangle, ChevronRight, CheckCircle, ExternalLink, FileText,
MapPin, MessageSquare, Sparkles, StickyNote, X,
} from 'lucide-react'
-import { usePipelineStore } from '../../stores/pipelineStore'
+import { useMoveStage, useUpdateNotes, useLoseItem } from '../../hooks/usePipeline'
import type { PipelineItem } from '../../domain/pipeline'
import { STAGES, NEXT_STAGE, MOCK_DOCS } from './pipelineConstants'
import { scoreColor, detailPath, getKiInsight } from './pipelineUtils'
@@ -16,7 +16,9 @@ import { scoreColor, detailPath, getKiInsight } from './pipelineUtils'
export function DetailPanel({ item, onClose }: { item: PipelineItem; onClose: () => void }) {
const navigate = useNavigate()
- const { moveStage, updateNotes, loseItem } = usePipelineStore()
+ const { mutate: moveStage } = useMoveStage()
+ const { mutate: updateNotes } = useUpdateNotes()
+ const { mutate: loseItem } = useLoseItem()
const path = detailPath(item)
const [notes, setNotes] = useState(item.notes ?? '')
const stageConfig = STAGES.find(s => s.key === item.stage)!
@@ -128,7 +130,7 @@ export function DetailPanel({ item, onClose }: { item: PipelineItem; onClose: ()
{nextStage && (
}
- onClick={() => moveStage(item.id, nextStage.key)}
+ onClick={() => moveStage({ id: item.id, stage: nextStage.key })}
sx={{ bgcolor: stageConfig.color, '&:hover': { filter: 'brightness(0.9)' }, fontSize: '0.75rem', py: 0.5 }}
>
{nextStage.label}
@@ -157,7 +159,7 @@ export function DetailPanel({ item, onClose }: { item: PipelineItem; onClose: ()
placeholder="Notiz hinzufügen…"
value={notes}
onChange={e => setNotes(e.target.value)}
- onBlur={() => updateNotes(item.id, notes)}
+ onBlur={() => updateNotes({ id: item.id, notes })}
sx={{ '& .MuiOutlinedInput-root': { fontSize: '0.8rem', borderRadius: 1.5 } }}
/>
diff --git a/src/components/shortlist/AddToPipelineDialog.tsx b/src/components/shortlist/AddToPipelineDialog.tsx
index fb513af..2ce1de6 100644
--- a/src/components/shortlist/AddToPipelineDialog.tsx
+++ b/src/components/shortlist/AddToPipelineDialog.tsx
@@ -5,29 +5,22 @@ import {
} from '@mui/material'
import { Bookmark } from 'lucide-react'
import { usePipelineStore } from '../../stores/pipelineStore'
-import { useToastStore } from '../../stores/toastStore'
+import { useAddToPipeline } from '../../hooks/usePipeline'
export function AddToPipelineDialog() {
- const { dialogOpen, pendingItem, closeSavedDialog, confirmSaved } = usePipelineStore()
- const showToast = useToastStore((s) => s.showToast)
+ const { dialogOpen, pendingItem, closeSavedDialog } = usePipelineStore()
+ const { mutate: addToPipeline, isPending } = useAddToPipeline()
const [note, setNote] = useState('')
- const [saving, setSaving] = useState(false)
function handleClose() {
closeSavedDialog()
setNote('')
}
- async function handleConfirm() {
- setSaving(true)
- const result = confirmSaved(note.trim() || undefined)
- setSaving(false)
+ function handleConfirm() {
+ if (!pendingItem) return
+ addToPipeline({ pending: pendingItem, notes: note.trim() || undefined })
setNote('')
- if (result === 'duplicate') {
- showToast('Bereits in der Pipeline vorhanden.', 'warning')
- } else {
- showToast('Zur Pipeline (Gemerkt) hinzugefügt.')
- }
}
return (
@@ -59,12 +52,12 @@ export function AddToPipelineDialog() {
/>
-
+
: undefined}
+ disabled={isPending}
+ endIcon={isPending ? : undefined}
sx={{ bgcolor: '#1e3a5f', '&:hover': { bgcolor: '#162d4a' } }}
>
Merken
diff --git a/src/domain/pipeline.ts b/src/domain/pipeline.ts
index 97bf10d..74badcb 100644
--- a/src/domain/pipeline.ts
+++ b/src/domain/pipeline.ts
@@ -24,3 +24,17 @@ export interface PipelineItem {
notes?: string
assignedTo?: string
}
+
+export interface PendingPipelineItem {
+ resultId: string
+ resultType: PipelineItem['resultType']
+ title: string
+ location?: string
+ matchScore: number
+ propertyId?: string
+ unitId?: string
+ propertyAddress?: string
+ areaLabel?: string
+ rentLabel?: string
+ availabilityLabel?: string
+}
diff --git a/src/hooks/index.ts b/src/hooks/index.ts
index 4d9e3ef..76efa0f 100644
--- a/src/hooks/index.ts
+++ b/src/hooks/index.ts
@@ -1,3 +1,4 @@
+export { usePipelineItems, useAddToPipeline, useMoveStage, useUpdateNotes, useLoseItem, useLinkInquiry } from './usePipeline'
export { useProperties, useProperty, usePropertyDetail } from './useProperties'
export { useMatches, useMatchesByNeed, useMatchesByProperty, useApproveMatch, useMatchDetail } from './useMatches'
export { useFutureSignals, useFutureSignalsByProperty, useVerifySignal } from './useFutureSignals'
diff --git a/src/hooks/usePipeline.ts b/src/hooks/usePipeline.ts
new file mode 100644
index 0000000..161c63a
--- /dev/null
+++ b/src/hooks/usePipeline.ts
@@ -0,0 +1,91 @@
+import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
+import { pipelineService } from '../services/pipelineService'
+import { usePipelineStore } from '../stores/pipelineStore'
+import { useToastStore } from '../stores/toastStore'
+import type { PipelineStage, PendingPipelineItem } from '../domain/pipeline'
+
+export const PIPELINE_QUERY_KEY = ['pipeline', 'items'] as const
+
+export function usePipelineItems() {
+ return useQuery({
+ queryKey: PIPELINE_QUERY_KEY,
+ queryFn: () => pipelineService.getAll(),
+ select: (res) => res.data ?? [],
+ staleTime: Infinity,
+ })
+}
+
+export function useAddToPipeline() {
+ const queryClient = useQueryClient()
+ const { closeSavedDialog } = usePipelineStore()
+
+ return useMutation({
+ mutationFn: ({ pending, notes }: { pending: PendingPipelineItem; notes?: string }) =>
+ pipelineService.confirmSaved(pending, notes),
+ onSuccess: (res) => {
+ queryClient.invalidateQueries({ queryKey: PIPELINE_QUERY_KEY })
+ closeSavedDialog()
+ if (res.data === 'duplicate') {
+ useToastStore.getState().showToast('Bereits in der Pipeline vorhanden.', 'warning')
+ } else {
+ useToastStore.getState().showToast('Zur Pipeline (Gemerkt) hinzugefügt.')
+ }
+ },
+ onError: () => {
+ useToastStore.getState().showToast('Fehler beim Hinzufügen zur Pipeline.', 'error')
+ },
+ })
+}
+
+export function useMoveStage() {
+ const queryClient = useQueryClient()
+
+ return useMutation({
+ mutationFn: ({ id, stage }: { id: string; stage: PipelineStage }) =>
+ pipelineService.moveStage(id, stage),
+ onSuccess: () => {
+ queryClient.invalidateQueries({ queryKey: PIPELINE_QUERY_KEY })
+ },
+ onError: () => {
+ useToastStore.getState().showToast('Fehler beim Verschieben.', 'error')
+ },
+ })
+}
+
+export function useUpdateNotes() {
+ const queryClient = useQueryClient()
+
+ return useMutation({
+ mutationFn: ({ id, notes }: { id: string; notes: string }) =>
+ pipelineService.updateNotes(id, notes),
+ onSuccess: () => {
+ queryClient.invalidateQueries({ queryKey: PIPELINE_QUERY_KEY })
+ },
+ })
+}
+
+export function useLoseItem() {
+ const queryClient = useQueryClient()
+
+ return useMutation({
+ mutationFn: (id: string) => pipelineService.loseItem(id),
+ onSuccess: () => {
+ queryClient.invalidateQueries({ queryKey: PIPELINE_QUERY_KEY })
+ },
+ onError: () => {
+ useToastStore.getState().showToast('Fehler beim Ablehnen.', 'error')
+ },
+ })
+}
+
+export function useLinkInquiry() {
+ const queryClient = useQueryClient()
+
+ return useMutation({
+ mutationFn: ({ id, inquiryId }: { id: string; inquiryId: string }) =>
+ pipelineService.linkInquiry(id, inquiryId),
+ onSuccess: () => {
+ queryClient.invalidateQueries({ queryKey: PIPELINE_QUERY_KEY })
+ },
+ })
+}
diff --git a/src/pages/demand/Anfragen.tsx b/src/pages/demand/Anfragen.tsx
index 9dcb556..03f4d90 100644
--- a/src/pages/demand/Anfragen.tsx
+++ b/src/pages/demand/Anfragen.tsx
@@ -6,7 +6,7 @@ import {
} from '@mui/material'
import { Search, Send, Paperclip, ArrowLeft, Bot, Building2, Kanban } from 'lucide-react'
import { mockInquiries } from '../../mock-data/inquiries'
-import { usePipelineStore } from '../../stores/pipelineStore'
+import { usePipelineItems, useMoveStage } from '../../hooks/usePipeline'
import { useToastStore } from '../../stores/toastStore'
import type { InquiryMessage } from '../../domain/inquiry'
import { STAGE_ORDER, STAGE_LABELS, detectKiStage } from './anfragenKiDetection'
@@ -34,7 +34,8 @@ const FILTER_TABS = [
export default function Anfragen() {
const navigate = useNavigate()
const [searchParams] = useSearchParams()
- const { findByPropertyId, findByInquiryId, moveStage } = usePipelineStore()
+ const { data: pipelineItems = [] } = usePipelineItems()
+ const { mutate: moveStage } = useMoveStage()
const showToast = useToastStore(s => s.showToast)
const preselectedId = searchParams.get('inquiry')
@@ -65,8 +66,8 @@ export default function Anfragen() {
// Pipeline link for currently selected inquiry
const linkedPipelineItem = selected?.propertyId
- ? findByPropertyId(selected.propertyId)
- : (selected ? findByInquiryId(selected.id) : undefined)
+ ? pipelineItems.find(i => i.propertyId === selected.propertyId)
+ : (selected ? pipelineItems.find(i => i.inquiryId === selected.id) : undefined)
useEffect(() => {
if (threadRef.current) {
@@ -112,13 +113,13 @@ export default function Anfragen() {
const ki = detectKiStage(text)
if (ki && selected) {
const pipelineItem = selected.propertyId
- ? findByPropertyId(selected.propertyId)
- : findByInquiryId(selectedId)
+ ? pipelineItems.find(i => i.propertyId === selected.propertyId)
+ : pipelineItems.find(i => i.inquiryId === selectedId)
if (pipelineItem) {
const currentIdx = STAGE_ORDER.indexOf(pipelineItem.stage)
const targetIdx = STAGE_ORDER.indexOf(ki.stage)
if (targetIdx > currentIdx) {
- moveStage(pipelineItem.id, ki.stage)
+ moveStage({ id: pipelineItem.id, stage: ki.stage })
setKiAlert({ title: pipelineItem.title, stage: STAGE_LABELS[ki.stage] })
}
}
@@ -180,7 +181,7 @@ export default function Anfragen() {
key={inq.id}
inq={inq}
isSelected={inq.id === selectedId}
- hasPipeline={!!(inq.propertyId ? findByPropertyId(inq.propertyId) : findByInquiryId(inq.id))}
+ hasPipeline={!!(inq.propertyId ? pipelineItems.find(i => i.propertyId === inq.propertyId) : pipelineItems.find(i => i.inquiryId === inq.id))}
onSelect={handleSelect}
/>
))}
diff --git a/src/pages/demand/Pipeline.tsx b/src/pages/demand/Pipeline.tsx
index 20115fc..4922db5 100644
--- a/src/pages/demand/Pipeline.tsx
+++ b/src/pages/demand/Pipeline.tsx
@@ -8,7 +8,7 @@ import {
} from '@dnd-kit/core'
import type { DragEndEvent, DragStartEvent } from '@dnd-kit/core'
import { TrendingUp } from 'lucide-react'
-import { usePipelineStore } from '../../stores/pipelineStore'
+import { usePipelineItems, useMoveStage } from '../../hooks/usePipeline'
import { AddToPipelineDialog } from '../../components/shortlist'
import type { PipelineItem, PipelineStage } from '../../domain/pipeline'
import { STAGES } from '../../components/pipeline/pipelineConstants'
@@ -20,7 +20,8 @@ import { DetailPanel } from '../../components/pipeline/PipelineDetailPanel'
export default function Pipeline() {
const navigate = useNavigate()
- const { items, moveStage } = usePipelineStore()
+ const { data: items = [] } = usePipelineItems()
+ const { mutate: moveStage } = useMoveStage()
const [selectedItem, setSelectedItem] = useState(null)
const [activeId, setActiveId] = useState(null)
const [overId, setOverId] = useState(null)
@@ -53,7 +54,7 @@ export default function Pipeline() {
const targetStage = over.id as PipelineStage
const item = items.find(i => i.id === active.id)
if (item && item.stage !== targetStage) {
- moveStage(item.id, targetStage)
+ moveStage({ id: item.id, stage: targetStage })
}
}
diff --git a/src/provider/IPipelineProvider.ts b/src/provider/IPipelineProvider.ts
new file mode 100644
index 0000000..e3fda3d
--- /dev/null
+++ b/src/provider/IPipelineProvider.ts
@@ -0,0 +1,10 @@
+import type { PipelineItem, PipelineStage } from '../domain/pipeline'
+
+export interface IPipelineProvider {
+ getAll(): Promise
+ add(item: PipelineItem): Promise
+ moveStage(id: string, stage: PipelineStage): Promise
+ updateNotes(id: string, notes: string): Promise
+ loseItem(id: string): Promise
+ linkInquiry(id: string, inquiryId: string): Promise
+}
diff --git a/src/provider/MockupPipelineProvider.ts b/src/provider/MockupPipelineProvider.ts
new file mode 100644
index 0000000..4a55bb1
--- /dev/null
+++ b/src/provider/MockupPipelineProvider.ts
@@ -0,0 +1,67 @@
+import type { IPipelineProvider } from './IPipelineProvider'
+import type { PipelineItem, PipelineStage } from '../domain/pipeline'
+import { mockPipelineItems } from '../mock-data/pipelineItems'
+
+const STORAGE_KEY = 'property_match_pipeline_items'
+
+function load(): PipelineItem[] {
+ try {
+ const raw = localStorage.getItem(STORAGE_KEY)
+ if (raw) return JSON.parse(raw) as PipelineItem[]
+ } catch { /* ignore */ }
+ return [...mockPipelineItems]
+}
+
+function save(items: PipelineItem[]): void {
+ try {
+ localStorage.setItem(STORAGE_KEY, JSON.stringify(items))
+ } catch { /* ignore */ }
+}
+
+export const MockupPipelineProvider: IPipelineProvider = {
+ async getAll() {
+ return load()
+ },
+
+ async add(item) {
+ const items = load()
+ items.push(item)
+ save(items)
+ },
+
+ async moveStage(id: string, stage: PipelineStage) {
+ const items = load()
+ const idx = items.findIndex(i => i.id === id)
+ if (idx !== -1) {
+ items[idx] = { ...items[idx], stage, updatedAt: new Date().toISOString() }
+ save(items)
+ }
+ },
+
+ async updateNotes(id: string, notes: string) {
+ const items = load()
+ const idx = items.findIndex(i => i.id === id)
+ if (idx !== -1) {
+ items[idx] = { ...items[idx], notes }
+ save(items)
+ }
+ },
+
+ async loseItem(id: string) {
+ const items = load()
+ const idx = items.findIndex(i => i.id === id)
+ if (idx !== -1) {
+ items[idx] = { ...items[idx], stage: 'CLOSED_LOST', updatedAt: new Date().toISOString() }
+ save(items)
+ }
+ },
+
+ async linkInquiry(id: string, inquiryId: string) {
+ const items = load()
+ const idx = items.findIndex(i => i.id === id)
+ if (idx !== -1) {
+ items[idx] = { ...items[idx], inquiryId }
+ save(items)
+ }
+ },
+}
diff --git a/src/services/pipelineService.ts b/src/services/pipelineService.ts
new file mode 100644
index 0000000..c361a30
--- /dev/null
+++ b/src/services/pipelineService.ts
@@ -0,0 +1,85 @@
+import { MockupPipelineProvider } from '../provider/MockupPipelineProvider'
+import type { PipelineItem, PipelineStage, PendingPipelineItem } from '../domain/pipeline'
+import type { ListResponse, ItemResponse } from './types'
+import { throwServiceError } from './errors'
+
+const provider = MockupPipelineProvider
+
+export const pipelineService = {
+ async getAll(): Promise> {
+ try {
+ const data = await provider.getAll()
+ return { data, meta: { total: data.length, page: 1, pageSize: data.length, hasMore: false } }
+ } catch (err) {
+ throwServiceError(err)
+ }
+ },
+
+ async confirmSaved(pending: PendingPipelineItem, notes?: string): Promise> {
+ try {
+ const items = await provider.getAll()
+ const alreadyExists = items.some(
+ i => i.id === pending.resultId || (pending.propertyId && i.propertyId === pending.propertyId)
+ )
+ if (alreadyExists) return { data: 'duplicate' }
+ const newItem: PipelineItem = {
+ id: pending.resultId,
+ matchId: pending.resultId,
+ title: pending.title,
+ location: pending.location ?? '–',
+ matchScore: pending.matchScore,
+ resultType: pending.resultType,
+ stage: 'SAVED',
+ propertyId: pending.propertyId,
+ unitId: pending.unitId,
+ propertyAddress: pending.propertyAddress,
+ areaLabel: pending.areaLabel,
+ rentLabel: pending.rentLabel,
+ availabilityLabel: pending.availabilityLabel,
+ notes: notes || undefined,
+ addedAt: new Date().toISOString(),
+ updatedAt: new Date().toISOString(),
+ }
+ await provider.add(newItem)
+ return { data: 'added' }
+ } catch (err) {
+ throwServiceError(err)
+ }
+ },
+
+ async moveStage(id: string, stage: PipelineStage): Promise> {
+ try {
+ await provider.moveStage(id, stage)
+ return { data: undefined }
+ } catch (err) {
+ throwServiceError(err)
+ }
+ },
+
+ async updateNotes(id: string, notes: string): Promise> {
+ try {
+ await provider.updateNotes(id, notes)
+ return { data: undefined }
+ } catch (err) {
+ throwServiceError(err)
+ }
+ },
+
+ async loseItem(id: string): Promise> {
+ try {
+ await provider.loseItem(id)
+ return { data: undefined }
+ } catch (err) {
+ throwServiceError(err)
+ }
+ },
+
+ async linkInquiry(id: string, inquiryId: string): Promise> {
+ try {
+ await provider.linkInquiry(id, inquiryId)
+ return { data: undefined }
+ } catch (err) {
+ throwServiceError(err)
+ }
+ },
+}
diff --git a/src/stores/pipelineStore.ts b/src/stores/pipelineStore.ts
index a8d52fd..1480284 100644
--- a/src/stores/pipelineStore.ts
+++ b/src/stores/pipelineStore.ts
@@ -1,97 +1,18 @@
import { create } from 'zustand'
-import { mockPipelineItems } from '../mock-data/pipelineItems'
-import type { PipelineItem, PipelineStage } from '../domain/pipeline'
+import type { PendingPipelineItem } from '../domain/pipeline'
-export interface PendingPipelineItem {
- resultId: string
- resultType: PipelineItem['resultType']
- title: string
- location?: string
- matchScore: number
- propertyId?: string
- unitId?: string
- propertyAddress?: string
- areaLabel?: string
- rentLabel?: string
- availabilityLabel?: string
-}
+export type { PendingPipelineItem }
-interface PipelineStore {
- items: PipelineItem[]
+interface PipelineUIStore {
dialogOpen: boolean
pendingItem: PendingPipelineItem | null
openSavedDialog: (item: PendingPipelineItem) => void
closeSavedDialog: () => void
- confirmSaved: (notes?: string) => 'added' | 'duplicate'
- moveStage: (id: string, stage: PipelineStage) => void
- updateNotes: (id: string, notes: string) => void
- loseItem: (id: string) => void
- linkInquiry: (id: string, inquiryId: string) => void
- findByPropertyId: (propertyId: string) => PipelineItem | undefined
- findByInquiryId: (inquiryId: string) => PipelineItem | undefined
}
-export const usePipelineStore = create((set, get) => ({
- items: mockPipelineItems,
+export const usePipelineStore = create((set) => ({
dialogOpen: false,
pendingItem: null,
-
openSavedDialog: (item) => set({ dialogOpen: true, pendingItem: item }),
closeSavedDialog: () => set({ dialogOpen: false, pendingItem: null }),
-
- confirmSaved: (notes) => {
- const { pendingItem, items } = get()
- if (!pendingItem) return 'duplicate'
- const alreadyExists = items.some(
- i => i.id === pendingItem.resultId ||
- (pendingItem.propertyId && i.propertyId === pendingItem.propertyId)
- )
- if (!alreadyExists) {
- const newItem: PipelineItem = {
- id: pendingItem.resultId,
- matchId: pendingItem.resultId,
- title: pendingItem.title,
- location: pendingItem.location ?? '–',
- matchScore: pendingItem.matchScore,
- resultType: pendingItem.resultType,
- stage: 'SAVED',
- propertyId: pendingItem.propertyId,
- unitId: pendingItem.unitId,
- propertyAddress: pendingItem.propertyAddress,
- areaLabel: pendingItem.areaLabel,
- rentLabel: pendingItem.rentLabel,
- availabilityLabel: pendingItem.availabilityLabel,
- notes: notes || undefined,
- addedAt: new Date().toISOString(),
- updatedAt: new Date().toISOString(),
- }
- set({ items: [...items, newItem], dialogOpen: false, pendingItem: null })
- return 'added'
- }
- set({ dialogOpen: false, pendingItem: null })
- return 'duplicate'
- },
-
- moveStage: (id, stage) => set(state => ({
- items: state.items.map(i =>
- i.id === id ? { ...i, stage, updatedAt: new Date().toISOString() } : i
- ),
- })),
-
- updateNotes: (id, notes) => set(state => ({
- items: state.items.map(i => i.id === id ? { ...i, notes } : i),
- })),
-
- loseItem: (id) => set(state => ({
- items: state.items.map(i =>
- i.id === id ? { ...i, stage: 'CLOSED_LOST' as PipelineStage, updatedAt: new Date().toISOString() } : i
- ),
- })),
-
- linkInquiry: (id, inquiryId) => set(state => ({
- items: state.items.map(i => i.id === id ? { ...i, inquiryId } : i),
- })),
-
- findByPropertyId: (propertyId) => get().items.find(i => i.propertyId === propertyId),
- findByInquiryId: (inquiryId) => get().items.find(i => i.inquiryId === inquiryId),
}))