import React, { useState, useRef, useEffect, useCallback } from 'react'; import { Modal, View, Text, TextInput, TouchableOpacity, Animated, ScrollView, Image, KeyboardAvoidingView, Platform, TouchableWithoutFeedback, } from 'react-native'; import { useAppTheme } from '@theme'; import { RatingStars } from '../ratingStars/ratingStars'; import { getStyles } from './productRatingModal.styles'; import { giveRatingPayload } from '@interfaces'; // ─── Types ──────────────────────────────────────────────────────────────────── export interface ProductRatingModalProps { visible: boolean; /** Product id being rated */ productId: string; /** Display name of the product */ productName: string; /** Optional: qty badge text, e.g. "2x" */ quantity?: string | number; /** The parent order id — required by the rating API */ orderId?: string; /** Called when the user submits their rating */ onSubmit: (payload: giveRatingPayload) => void; /** Called when the modal is dismissed without submitting */ onClose: () => void; } // ─── Rating hint labels ─────────────────────────────────────────────────────── const RATING_LABELS: Record = { 1: 'Terrible 😞', 2: 'Bad 😕', 3: 'Okay 😐', 4: 'Good 😊', 5: 'Excellent 🤩', }; const MAX_COMMENT = 300; // ─── Component ──────────────────────────────────────────────────────────────── export const ProductRatingModal: React.FC = ({ visible, orderId, productId, productName, quantity, onSubmit, onClose, }) => { const { colors } = useAppTheme(); const styles = getStyles(colors); // ── State ──────────────────────────────────────────────────────────────── const [rating, setRating] = useState(0); const [comment, setComment] = useState(''); const [commentFocused, setCommentFocused] = useState(false); const [imageUris] = useState([]); // placeholder – wire launchImageLibrary here const [submitted, setSubmitted] = useState(false); // ── Animation ──────────────────────────────────────────────────────────── const slideY = useRef(new Animated.Value(400)).current; useEffect(() => { if (visible) { // reset state each time the modal opens for a new product setRating(0); setComment(''); setSubmitted(false); Animated.spring(slideY, { toValue: 0, useNativeDriver: true, damping: 18, stiffness: 160, }).start(); } else { slideY.setValue(400); } }, [visible, slideY]); // ── Handlers ───────────────────────────────────────────────────────────── const handleClose = useCallback(() => { Animated.timing(slideY, { toValue: 400, duration: 200, useNativeDriver: true, }).start(onClose); }, [slideY, onClose]); const handleSubmit = useCallback(() => { if (rating === 0) return; onSubmit({ rating, comment, images: imageUris, orderId: orderId ?? '', }); setSubmitted(true); }, [rating, comment, imageUris, orderId, onSubmit]); const canSubmit = rating > 0; // ── Render ─────────────────────────────────────────────────────────────── return ( {/* Backdrop — tap to dismiss */} {/* Drag handle */} {/* Product hero */} 🛍️ {productName} {quantity !== undefined && ( Qty: {quantity} )} {/* Already-submitted banner */} {submitted ? ( <> Thanks for your rating! {/* Show submitted stars (read-only) */} Done ) : ( {/* Star rating */} Your Rating {rating > 0 ? RATING_LABELS[rating] : 'Tap a star to rate'} {/* Comment (optional) */} Review{' '} (optional) setComment(t.slice(0, MAX_COMMENT))} multiline onFocus={() => setCommentFocused(true)} onBlur={() => setCommentFocused(false)} returnKeyType="done" blurOnSubmit /> {comment.length}/{MAX_COMMENT} {/* Image upload strip (optional) */} Photos{' '} (optional) {/* Add photo button */} 📷 Add {/* Thumbnail previews */} {imageUris.map((uri, i) => ( ))} {/* Submit */} Submit Review )} ); };