feat(T-563): integreer Sync-tab in IdeaDetailLayout + page-loader
- TabKey union uitgebreid met 'sync'. - Sync-tab alleen zichtbaar als syncData !== null && idea.status === 'planned' (M12 keuze 6: na Materialiseer-actie). - page.tsx roept loadIdeaSyncData alleen aan bij PLANNED + pbi_id, anders null doorgeven aan layout. - showSync-flag bepaalt of de tab in TAB_KEYS array zit en in de UI gerenderd wordt. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
dbf30a2fcb
commit
678069a3d8
2 changed files with 23 additions and 2 deletions
|
|
@ -7,6 +7,7 @@ import { prisma } from '@/lib/prisma'
|
||||||
import { productAccessFilter } from '@/lib/product-access'
|
import { productAccessFilter } from '@/lib/product-access'
|
||||||
import { ideaToDto } from '@/lib/idea-dto'
|
import { ideaToDto } from '@/lib/idea-dto'
|
||||||
import { IdeaDetailLayout } from '@/components/ideas/idea-detail-layout'
|
import { IdeaDetailLayout } from '@/components/ideas/idea-detail-layout'
|
||||||
|
import { loadIdeaSyncData } from './sync-tab-server'
|
||||||
|
|
||||||
export const dynamic = 'force-dynamic'
|
export const dynamic = 'force-dynamic'
|
||||||
|
|
||||||
|
|
@ -76,6 +77,14 @@ export default async function IdeaDetailPage({ params, searchParams }: PageProps
|
||||||
select: { id: true, question: true, answer: true, status: true, created_at: true },
|
select: { id: true, question: true, answer: true, status: true, created_at: true },
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Sync-tab data — alleen geladen als idea PLANNED is en pbi_id gevuld.
|
||||||
|
// loadIdeaSyncData past zelf user_id-scope toe en retourneert null als
|
||||||
|
// het idee geen pbi heeft.
|
||||||
|
const syncData =
|
||||||
|
idea.status === 'PLANNED' && idea.pbi_id
|
||||||
|
? await loadIdeaSyncData(id, session.userId)
|
||||||
|
: null
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<IdeaDetailLayout
|
<IdeaDetailLayout
|
||||||
idea={ideaToDto(idea)}
|
idea={ideaToDto(idea)}
|
||||||
|
|
@ -107,6 +116,7 @@ export default async function IdeaDetailPage({ params, searchParams }: PageProps
|
||||||
}))}
|
}))}
|
||||||
isDemo={session.isDemo ?? false}
|
isDemo={session.isDemo ?? false}
|
||||||
initialTab={tab ?? 'idee'}
|
initialTab={tab ?? 'idee'}
|
||||||
|
syncData={syncData}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,9 @@ import { IdeaRowActions } from '@/components/ideas/idea-row-actions'
|
||||||
import { IdeaMdEditor } from '@/components/ideas/idea-md-editor'
|
import { IdeaMdEditor } from '@/components/ideas/idea-md-editor'
|
||||||
import { IdeaPbiLinkCard } from '@/components/ideas/idea-pbi-link-card'
|
import { IdeaPbiLinkCard } from '@/components/ideas/idea-pbi-link-card'
|
||||||
import { IdeaTimeline } from '@/components/ideas/idea-timeline'
|
import { IdeaTimeline } from '@/components/ideas/idea-timeline'
|
||||||
|
import { IdeaSyncTab } from '@/components/ideas/idea-sync-tab'
|
||||||
import { DownloadMdButton } from '@/components/ideas/download-md-button'
|
import { DownloadMdButton } from '@/components/ideas/download-md-button'
|
||||||
|
import type { IdeaSyncData } from '@/app/(app)/ideas/[id]/sync-tab-server'
|
||||||
|
|
||||||
const API_TO_DB: Record<IdeaStatusApi, Parameters<typeof getIdeaStatusBadge>[0]> = {
|
const API_TO_DB: Record<IdeaStatusApi, Parameters<typeof getIdeaStatusBadge>[0]> = {
|
||||||
draft: 'DRAFT',
|
draft: 'DRAFT',
|
||||||
|
|
@ -38,7 +40,7 @@ const API_TO_DB: Record<IdeaStatusApi, Parameters<typeof getIdeaStatusBadge>[0]>
|
||||||
planned: 'PLANNED',
|
planned: 'PLANNED',
|
||||||
}
|
}
|
||||||
|
|
||||||
type TabKey = 'idee' | 'grill' | 'plan' | 'timeline'
|
type TabKey = 'idee' | 'grill' | 'plan' | 'timeline' | 'sync'
|
||||||
|
|
||||||
interface IdeaLog {
|
interface IdeaLog {
|
||||||
id: string
|
id: string
|
||||||
|
|
@ -82,6 +84,7 @@ interface Props {
|
||||||
userQuestions: IdeaUserQuestionDto[]
|
userQuestions: IdeaUserQuestionDto[]
|
||||||
isDemo: boolean
|
isDemo: boolean
|
||||||
initialTab: string
|
initialTab: string
|
||||||
|
syncData: IdeaSyncData | null
|
||||||
}
|
}
|
||||||
|
|
||||||
export function IdeaDetailLayout({
|
export function IdeaDetailLayout({
|
||||||
|
|
@ -94,12 +97,16 @@ export function IdeaDetailLayout({
|
||||||
userQuestions,
|
userQuestions,
|
||||||
isDemo,
|
isDemo,
|
||||||
initialTab,
|
initialTab,
|
||||||
|
syncData,
|
||||||
}: Props) {
|
}: Props) {
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const searchParams = useSearchParams()
|
const searchParams = useSearchParams()
|
||||||
const [pending, startTransition] = useTransition()
|
const [pending, startTransition] = useTransition()
|
||||||
|
|
||||||
const TAB_KEYS: TabKey[] = ['idee', 'grill', 'plan', 'timeline']
|
const showSync = syncData !== null && idea.status === 'planned'
|
||||||
|
const TAB_KEYS: TabKey[] = showSync
|
||||||
|
? ['idee', 'grill', 'plan', 'timeline', 'sync']
|
||||||
|
: ['idee', 'grill', 'plan', 'timeline']
|
||||||
const tab = (TAB_KEYS.includes(initialTab as TabKey) ? initialTab : 'idee') as TabKey
|
const tab = (TAB_KEYS.includes(initialTab as TabKey) ? initialTab : 'idee') as TabKey
|
||||||
|
|
||||||
function setTab(key: TabKey) {
|
function setTab(key: TabKey) {
|
||||||
|
|
@ -170,6 +177,9 @@ export function IdeaDetailLayout({
|
||||||
{ key: 'grill' as TabKey, label: 'Grill', disabled: !grill_md, hasContent: !!grill_md },
|
{ key: 'grill' as TabKey, label: 'Grill', disabled: !grill_md, hasContent: !!grill_md },
|
||||||
{ key: 'plan' as TabKey, label: 'Plan', disabled: !plan_md, hasContent: !!plan_md },
|
{ key: 'plan' as TabKey, label: 'Plan', disabled: !plan_md, hasContent: !!plan_md },
|
||||||
{ key: 'timeline' as TabKey, label: 'Timeline', disabled: false, hasContent: true },
|
{ key: 'timeline' as TabKey, label: 'Timeline', disabled: false, hasContent: true },
|
||||||
|
...(showSync
|
||||||
|
? [{ key: 'sync' as TabKey, label: 'Sync', disabled: false, hasContent: true }]
|
||||||
|
: []),
|
||||||
] as const).map((t) => (
|
] as const).map((t) => (
|
||||||
<button
|
<button
|
||||||
key={t.key}
|
key={t.key}
|
||||||
|
|
@ -227,6 +237,7 @@ export function IdeaDetailLayout({
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{tab === 'timeline' && <IdeaTimeline logs={logs} questions={questions} />}
|
{tab === 'timeline' && <IdeaTimeline logs={logs} questions={questions} />}
|
||||||
|
{tab === 'sync' && showSync && syncData && <IdeaSyncTab data={syncData} />}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue