fix(showcase): block financial data from AI Q&A, fix FAB overflow, fix presenter slide mapping
Build pitch-deck / build-push-deploy (push) Successful in 1m47s
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / test-go-consent (push) Successful in 41s
CI / test-python-voice (push) Successful in 32s
CI / test-bqas (push) Successful in 32s

AI Q&A: fetch is_showcase from DB; showcase sessions receive no financial/funding
context and have an explicit LLM guard refusing to discuss investment details.
FAQ context and financial slide IDs stripped from system prompt.

FAB: flex layout so Fullscreen button is always visible regardless of panel height.

Presenter: pass activeSlideOrder to usePresenterMode so buildSlideAudioPlan maps
slideIdx → slideId from the filtered list, not the full SLIDE_ORDER. Progress
calculation also filters to active scripts only.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Sharang Parnerkar
2026-05-04 23:00:55 +02:00
parent be126a7a39
commit 2bd9b015eb
4 changed files with 88 additions and 48 deletions
+17 -9
View File
@@ -5,6 +5,7 @@ import { Language } from '../types'
import { PresenterState, SlideScript } from '../presenter/types'
import { PRESENTER_SCRIPT } from '../presenter/presenter-script'
import { SLIDE_ORDER } from './useSlideNavigation'
import { SlideId } from '../types'
interface UsePresenterModeConfig {
goToSlide: (index: number) => void
@@ -12,6 +13,7 @@ interface UsePresenterModeConfig {
totalSlides: number
language: Language
ttsEnabled?: boolean
slideOrder?: SlideId[]
}
interface UsePresenterModeReturn {
@@ -57,8 +59,8 @@ interface SlideAudioPlan {
segments: AudioSegment[]
}
function buildSlideAudioPlan(slideIdx: number, lang: Language): SlideAudioPlan | null {
const slideId = SLIDE_ORDER[slideIdx]
function buildSlideAudioPlan(slideIdx: number, lang: Language, activeSlideOrder: SlideId[]): SlideAudioPlan | null {
const slideId = activeSlideOrder[slideIdx]
const script = PRESENTER_SCRIPT.find(s => s.slideId === slideId)
if (!script || script.paragraphs.length === 0) return null
@@ -121,7 +123,9 @@ export function usePresenterMode({
totalSlides,
language,
ttsEnabled: initialTtsEnabled = true,
slideOrder: slideOrderProp,
}: UsePresenterModeConfig): UsePresenterModeReturn {
const activeSlideOrder = slideOrderProp ?? SLIDE_ORDER
const [state, setState] = useState<PresenterState>('idle')
const [currentParagraph, setCurrentParagraph] = useState(0)
const [displayText, setDisplayText] = useState('')
@@ -193,7 +197,7 @@ export function usePresenterMode({
playSlideRef.current = async (slideIdx: number) => {
if (stateRef.current !== 'presenting') return
const plan = buildSlideAudioPlan(slideIdx, language)
const plan = buildSlideAudioPlan(slideIdx, language, activeSlideOrder)
if (!plan) {
// No script for this slide — skip to next
if (slideIdx < totalSlides - 1) {
@@ -216,7 +220,7 @@ export function usePresenterMode({
// Pre-fetch next slide's audio in background
if (slideIdx < totalSlides - 1) {
const nextPlan = buildSlideAudioPlan(slideIdx + 1, language)
const nextPlan = buildSlideAudioPlan(slideIdx + 1, language, activeSlideOrder)
if (nextPlan) fetchAudio(nextPlan.fullText, language).catch(() => {})
}
@@ -329,7 +333,7 @@ export function usePresenterMode({
setIsSpeaking(false)
}
}
}, [language, totalSlides, goToSlide, ttsAvailable, ttsEnabled])
}, [language, totalSlides, goToSlide, ttsAvailable, ttsEnabled, activeSlideOrder])
const start = useCallback(() => {
unlockAudio()
@@ -410,14 +414,18 @@ export function usePresenterMode({
}
}, [unlockAudio, start, stop])
// Calculate overall progress
// Calculate overall progress against the active slide order's scripts
const progress = (() => {
if (state === 'idle') return 0
const totalScripts = PRESENTER_SCRIPT.length
const currentScriptIdx = PRESENTER_SCRIPT.findIndex(s => s.slideId === SLIDE_ORDER[currentSlide])
const currentSlideId = activeSlideOrder[currentSlide]
const activeScripts = activeSlideOrder
.map(id => PRESENTER_SCRIPT.find(s => s.slideId === id))
.filter(Boolean) as typeof PRESENTER_SCRIPT
const totalScripts = activeScripts.length || 1
const currentScriptIdx = activeScripts.findIndex(s => s.slideId === currentSlideId)
if (currentScriptIdx < 0) return (currentSlide / totalSlides) * 100
const script = PRESENTER_SCRIPT[currentScriptIdx]
const script = activeScripts[currentScriptIdx]
const slideProgress = script.paragraphs.length > 0
? currentParagraph / script.paragraphs.length
: 0