import Text from '@/components/Text'; import Styles from '@/constants/Styles'; import { useTheme } from '@/providers/ThemeProvider'; import { Feather } from '@expo/vector-icons'; import React, { useEffect, useRef, useState } from 'react'; import { Animated, Dimensions, Modal, TouchableOpacity, View, } from 'react-native'; export type GuideStep = { title: string; description: string; // posisi card: pixel absolut atau rasio layar (0.0-1.0), rasio lebih aman untuk layout dinamis cardTop?: number; cardTopRatio?: number; // arrow menunjuk ke atas (elemen ada di atas card) atau ke bawah (elemen ada di bawah card) arrowDirection?: 'up' | 'down' | 'none'; // offset horizontal arrow dari kiri card (0.0-1.0), default 0.5 = tengah arrowOffset?: number; }; type Props = { visible: boolean; steps: GuideStep[]; onDismiss: () => void; }; const { height: SCREEN_H } = Dimensions.get('window'); const CARD_MARGIN = 24; export default function GuideOverlay({ visible, steps, onDismiss }: Props) { const { colors } = useTheme(); const [currentStep, setCurrentStep] = useState(0); const fadeAnim = useRef(new Animated.Value(0)).current; const slideAnim = useRef(new Animated.Value(20)).current; const step = steps[currentStep]; const isLast = currentStep === steps.length - 1; const arrowDirection = step?.arrowDirection ?? 'none'; const arrowOffset = step?.arrowOffset ?? 0.5; const cardTop = step?.cardTopRatio != null ? SCREEN_H * step.cardTopRatio : (step?.cardTop ?? SCREEN_H * 0.35); const cardPositionStyle = { top: cardTop }; useEffect(() => { if (visible) { setCurrentStep(0); Animated.parallel([ Animated.timing(fadeAnim, { toValue: 1, duration: 300, useNativeDriver: true }), Animated.timing(slideAnim, { toValue: 0, duration: 300, useNativeDriver: true }), ]).start(); } else { fadeAnim.setValue(0); slideAnim.setValue(20); } }, [visible]); function animateStep(next: number) { Animated.sequence([ Animated.timing(slideAnim, { toValue: 12, duration: 120, useNativeDriver: true }), Animated.timing(slideAnim, { toValue: 0, duration: 180, useNativeDriver: true }), ]).start(); setCurrentStep(next); } if (!visible) return null; return ( {/* Arrow atas — menunjuk ke elemen di atas card */} {arrowDirection === 'up' && ( )} {/* Header */} {currentStep + 1} / {steps.length} {/* Content */} {step.title} {step.description} {/* Dot indicator */} {steps.map((_, i) => ( ))} {/* Footer */} {currentStep > 0 ? ( animateStep(currentStep - 1)} style={Styles.guideButtonSecondary}> Kembali ) : ( Lewati )} isLast ? onDismiss() : animateStep(currentStep + 1)} style={[Styles.guideButtonPrimary, { backgroundColor: colors.icon }]} > {isLast ? 'Selesai' : 'Lanjut'} {!isLast && } {/* Arrow bawah — menunjuk ke elemen di bawah card */} {arrowDirection === 'down' && ( )} ); }