diff --git a/src/components/modals/ImageModal.tsx b/src/components/modals/ImageModal.tsx index 37a1940..6ca155e 100644 --- a/src/components/modals/ImageModal.tsx +++ b/src/components/modals/ImageModal.tsx @@ -2,7 +2,7 @@ import { useState, useMemo, useEffect } from 'react'; import { Download, Package, Monitor, Terminal, Zap, Star, Layers, Shield, FlaskConical, AppWindow, Box } from 'lucide-react'; import { useTranslation } from 'react-i18next'; import { Modal } from './Modal'; -import { ErrorDisplay, ListItemSkeleton } from '../shared'; +import { ErrorDisplay, ListItemSkeleton, ConfirmationDialog } from '../shared'; import type { BoardInfo, ImageInfo, ImageFilterType } from '../../types'; import { getImagesForBoard } from '../../hooks/useTauri'; import { useAsyncDataWhen } from '../../hooks/useAsyncData'; @@ -75,6 +75,9 @@ export function ImageModal({ isOpen, onClose, onSelect, board }: ImageModalProps const { t } = useTranslation(); const [filterType, setFilterType] = useState('all'); const [showSkeleton, setShowSkeleton] = useState(false); + // State for unstable image warning + const [pendingImage, setPendingImage] = useState(null); + const [showUnstableWarning, setShowUnstableWarning] = useState(false); // Use hook for async data fetching const { data: allImages, loading, error, reload } = useAsyncDataWhen( @@ -109,6 +112,53 @@ export function ImageModal({ isOpen, onClose, onSelect, board }: ImageModalProps }; }, [loading, imagesReady]); + // Reset warning state when modal is closed + useEffect(() => { + if (!isOpen) { + // eslint-disable-next-line react-hooks/set-state-in-effect -- Reset warning state when modal closes to prevent stale state from leaking into next session + setPendingImage(null); + setShowUnstableWarning(false); + } + }, [isOpen]); + + /** + * Handle image click - show warning for unstable images before selecting + */ + function handleImageClick(image: ImageInfo) { + // Check if warning is needed + const isNightly = image.armbian_version.includes('trunk'); + const isCommunityBoard = board?.has_community_support === true; + + // No warning for custom images or stable images on supported boards + if (!isNightly && !isCommunityBoard) { + onSelect(image); + return; + } + + // Show warning for nightly builds or community-supported boards + setPendingImage(image); + setShowUnstableWarning(true); + } + + /** + * Confirm unstable image selection - proceed with pending image + */ + function handleUnstableWarningConfirm() { + if (pendingImage) { + onSelect(pendingImage); + setPendingImage(null); + } + setShowUnstableWarning(false); + } + + /** + * Cancel unstable image selection - return to image list + */ + function handleUnstableWarningCancel() { + setPendingImage(null); + setShowUnstableWarning(false); + } + // Calculate available filters based on all images const availableFilters = useMemo(() => { if (!allImages) return { recommended: false, stable: false, nightly: false, apps: false, barebone: false }; @@ -181,7 +231,7 @@ export function ImageModal({ isOpen, onClose, onSelect, board }: ImageModalProps