UNPKG

@interactify-live/pindo-wizard-react-native

Version:

React Native PindoWizard component for media capture and interaction management

312 lines (311 loc) 15.4 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const jsx_runtime_1 = require("react/jsx-runtime"); const react_1 = require("react"); const react_native_1 = require("react-native"); const CameraComponent_1 = __importDefault(require("./CameraComponent")); const components_1 = require("./components"); const MediaThumbnails_1 = __importDefault(require("./components/MediaThumbnails")); const utils_1 = require("./utils"); const PindoWizard = ({ onFinish, uploadFile: _uploadFile, handleUpload, initialData = [], settings: _settings = { isVideoActive: false, isInteractionActive: false, isCoverActive: false, numMedias: 1, flashEnabled: false, }, }) => { const [currentStep, setCurrentStep] = (0, react_1.useState)(initialData.length > 0 ? 'interactions' : 'camera'); const [medias, setMedias] = (0, react_1.useState)(initialData.map(data => ({ ...data, interactions: data.interactions || [], }))); const [activeMediaIndex, setActiveMediaIndex] = (0, react_1.useState)(0); const [activeInteraction, setActiveInteraction] = (0, react_1.useState)(-1); const [coverIndex, setCoverIndex] = (0, react_1.useState)(0); const [isAddTextModalOpen, setIsAddTextModalOpen] = (0, react_1.useState)(false); const [isEditTextModalOpen, setIsEditTextModalOpen] = (0, react_1.useState)(false); const [pendingText, setPendingText] = (0, react_1.useState)(''); const [editingInteraction, setEditingInteraction] = (0, react_1.useState)(null); const handleCameraCapture = (0, react_1.useCallback)(async (uri, type) => { const newMedia = { id: `media-${Date.now()}`, type: type === 'photo' ? 'image' : 'video', url: uri, localUri: uri, interactions: [], isUploading: true, isUploaded: false, }; setMedias(prev => { const newMedias = [...prev, newMedia]; setActiveMediaIndex(newMedias.length - 1); return newMedias; }); setCurrentStep('interactions'); // Start upload if handleUpload is provided if (handleUpload) { try { const uploadResult = await handleUpload({ uri, type }); setMedias(prev => prev.map((media, index) => index === prev.length - 1 ? { ...media, url: uploadResult.url, thumbnail: uploadResult.thumbnail, isUploading: false, isUploaded: true, response: uploadResult, } : media)); } catch (error) { console.error('Upload failed:', error); setMedias(prev => prev.map((media, index) => index === prev.length - 1 ? { ...media, isUploading: false, isUploaded: false, } : media)); } } else { // If no upload handler provided, mark as uploaded immediately setMedias(prev => prev.map((media, index) => index === prev.length - 1 ? { ...media, isUploading: false, isUploaded: true, } : media)); } }, [handleUpload]); const handleGallerySelect = (0, react_1.useCallback)(async (uri, type) => { const newMedia = { id: `media-${Date.now()}`, type: type === 'photo' ? 'image' : 'video', url: uri, localUri: uri, interactions: [], isUploading: true, isUploaded: false, }; setMedias(prev => { const newMedias = [...prev, newMedia]; setActiveMediaIndex(newMedias.length - 1); return newMedias; }); setCurrentStep('interactions'); // Start upload if handleUpload is provided if (handleUpload) { try { const uploadResult = await handleUpload({ uri, type }); setMedias(prev => prev.map((media, index) => index === prev.length - 1 ? { ...media, url: uploadResult.url, thumbnail: uploadResult.thumbnail, isUploading: false, isUploaded: true, response: uploadResult, } : media)); } catch (error) { console.error('Upload failed:', error); setMedias(prev => prev.map((media, index) => index === prev.length - 1 ? { ...media, isUploading: false, isUploaded: false, } : media)); } } else { // If no upload handler provided, mark as uploaded immediately setMedias(prev => prev.map((media, index) => index === prev.length - 1 ? { ...media, isUploading: false, isUploaded: true, } : media)); } }, [handleUpload]); const handleCameraClose = (0, react_1.useCallback)(() => { if (medias.length > 0) { setCurrentStep('interactions'); } }, [medias.length]); const handleAddTextInteraction = (0, react_1.useCallback)(() => { setPendingText(''); setIsAddTextModalOpen(true); }, []); const handleEditTextInteraction = (0, react_1.useCallback)((interaction) => { setEditingInteraction(interaction); setIsEditTextModalOpen(true); }, []); const handleSaveTextInteraction = (0, react_1.useCallback)((textData) => { const newInteraction = { interaction: 'text', payload: { text: textData.text, size: textData.size, color: textData.color, background: textData.background, borderRadius: textData.borderRadius, }, geometric: { x: 300, // Default x position y: 300, // Default y position width: textData.width, height: textData.height, }, }; setMedias(prev => prev.map((media, index) => { if (index === activeMediaIndex) { return { ...media, interactions: [...media.interactions, newInteraction], }; } return media; })); setIsAddTextModalOpen(false); }, [activeMediaIndex]); const handleSaveEditTextInteraction = (0, react_1.useCallback)((textData) => { if (!editingInteraction) return; const updatedInteraction = { ...editingInteraction, payload: { text: textData.text, size: textData.size, color: textData.color, background: textData.background, borderRadius: textData.borderRadius, }, geometric: { ...editingInteraction.geometric, width: textData.width, height: textData.height, }, }; setMedias(prev => prev.map((media, index) => { if (index === activeMediaIndex) { return { ...media, interactions: media.interactions.map((interaction, idx) => idx === activeInteraction ? updatedInteraction : interaction), }; } return media; })); setIsEditTextModalOpen(false); setEditingInteraction(null); setActiveInteraction(-1); }, [activeMediaIndex, activeInteraction, editingInteraction]); const handleFinish = (0, react_1.useCallback)(() => { const mediaWithInteractions = medias.map(media => ({ id: media.id, type: media.type, url: media.url, thumbnail: media.thumbnail, interactions: media.interactions, response: media.response, })); onFinish(mediaWithInteractions); }, [medias, onFinish]); const hasAnyActiveInteraction = activeInteraction !== -1; if (currentStep === 'camera') { return ((0, jsx_runtime_1.jsx)(react_native_1.SafeAreaView, { style: { flex: 1, backgroundColor: '#000', paddingTop: react_native_1.Platform.OS === 'android' ? react_native_1.StatusBar.currentHeight : 0, }, children: (0, jsx_runtime_1.jsx)(CameraComponent_1.default, { onCapture: handleCameraCapture, onGallerySelect: handleGallerySelect, onClose: handleCameraClose, settings: _settings }) })); } return ((0, jsx_runtime_1.jsx)(react_native_1.SafeAreaView, { style: { flex: 1, backgroundColor: '#262626', paddingTop: react_native_1.Platform.OS === 'android' ? react_native_1.StatusBar.currentHeight : 0, }, children: (0, jsx_runtime_1.jsxs)(react_native_1.View, { style: styles.container, children: [(0, jsx_runtime_1.jsx)(components_1.InteractionHeader, { activeMedia: activeMediaIndex, setActiveMedia: setActiveMediaIndex, setMedias: updater => { setMedias(prev => { const updated = typeof updater === 'function' ? updater(prev) : updater; if (updated.length === 0) { setCurrentStep('camera'); } return updated; }); }, _hasAnyActiveInteraction: hasAnyActiveInteraction, _activeInteraction: activeInteraction, _setActiveInteraction: setActiveInteraction, _medias: medias, onAddInteraction: handleAddTextInteraction, _onDeleteActiveInteraction: () => { if (activeInteraction >= 0) { setMedias(prev => prev.map((media, i) => { if (i === activeMediaIndex) { return { ...media, interactions: media.interactions.filter((_, j) => j !== activeInteraction), }; } return media; })); setActiveInteraction(-1); } }, coverIndex: coverIndex, setCoverIndex: setCoverIndex, settings: { isVideoActive: _settings.isVideoActive || false, isInteractionActive: _settings.isInteractionActive || false, isCoverActive: _settings.isCoverActive || false, numMedias: _settings.numMedias || 1, } }), (0, jsx_runtime_1.jsx)(react_native_1.View, { style: styles.content, children: (0, jsx_runtime_1.jsx)(react_native_1.View, { style: styles.mainContentWrapper, children: (0, jsx_runtime_1.jsx)(components_1.MainContent, { medias: medias, setMedias: setMedias, activeMedia: activeMediaIndex, _activeInteraction: activeInteraction, setActiveInteraction: setActiveInteraction, coverIndex: coverIndex, setCoverIndex: setCoverIndex, onEditInteraction: handleEditTextInteraction, settings: { isVideoActive: _settings.isVideoActive || false, isInteractionActive: _settings.isInteractionActive || false, isCoverActive: _settings.isCoverActive || false, numMedias: _settings.numMedias || 1, } }) }) }), _settings.numMedias && _settings.numMedias > 1 && ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(react_native_1.View, { style: styles.mediaThumbnailsWrapper, children: (0, jsx_runtime_1.jsx)(MediaThumbnails_1.default, { medias: medias, activeMedia: activeMediaIndex, setActiveMedia: setActiveMediaIndex, setActiveInteraction: setActiveInteraction, coverIndex: coverIndex, setCurrentStep: setCurrentStep, settings: { isVideoActive: _settings.isVideoActive || false, isInteractionActive: _settings.isInteractionActive || false, isCoverActive: _settings.isCoverActive || false, numMedias: _settings.numMedias || 1, } }) }), (0, jsx_runtime_1.jsx)(react_native_1.View, { style: styles.pageIndicator, children: (0, jsx_runtime_1.jsxs)(react_native_1.Text, { style: styles.pageIndicatorText, children: [(0, utils_1.toPersianNumbers)(activeMediaIndex + 1), " /", ' ', (0, utils_1.toPersianNumbers)(_settings.numMedias || 1)] }) })] })), (0, jsx_runtime_1.jsx)(components_1.BottomControls, { medias: medias, activeMedia: activeMediaIndex, onFinish: handleFinish }), (0, jsx_runtime_1.jsx)(components_1.TextInputModal, { isOpen: isAddTextModalOpen, initialText: pendingText, initialColor: "#FFFFFF", initialBackground: "#000000", initialBgOpacity: 0.6, onSave: handleSaveTextInteraction, onCancel: () => setIsAddTextModalOpen(false), title: "\u0627\u0641\u0632\u0648\u062F\u0646 \u0645\u062A\u0646" }), (0, jsx_runtime_1.jsx)(components_1.TextInputModal, { isOpen: isEditTextModalOpen, initialText: editingInteraction?.payload?.text || '', initialColor: editingInteraction?.payload?.color || '#FFFFFF', initialBackground: editingInteraction?.payload?.background || '#000000', initialBgOpacity: 0.6, initialSize: editingInteraction?.payload?.size || 16, initialBorderRadius: editingInteraction?.payload?.borderRadius || 8, onSave: handleSaveEditTextInteraction, onCancel: () => { setIsEditTextModalOpen(false); setEditingInteraction(null); }, title: "\u0648\u06CC\u0631\u0627\u06CC\u0634 \u0645\u062A\u0646" })] }) })); }; const styles = react_native_1.StyleSheet.create({ container: { flex: 1, backgroundColor: '#262626', }, content: { flex: 1, paddingHorizontal: 16, paddingBottom: 16, }, mainContentWrapper: { flex: 1, borderWidth: 2, borderColor: 'rgba(175, 177, 182, 1)', borderRadius: 8, overflow: 'visible', }, mediaThumbnailsWrapper: { height: 80, paddingHorizontal: 16, paddingBottom: 12, }, pageIndicator: { alignItems: 'center', marginBottom: 12, marginTop: 5, }, pageIndicatorText: { color: '#ffffff', fontSize: 10, borderWidth: 1.5, borderColor: 'rgba(255, 255, 255, 1)', borderRadius: 8, paddingHorizontal: 8, paddingVertical: 4, }, }); exports.default = PindoWizard;