import React, { forwardRef, useState, useEffect, useMemo } from 'react'; import { View, TouchableOpacity, Alert } from 'react-native'; import { Formik } from 'formik'; import * as Yup from 'yup'; import { MyTextInput, BottomDropdown, MyText, tw, ImageUploaderNeo } from 'common-ui'; import ProductsSelector from './ProductsSelector'; import { trpc } from '../src/trpc-client'; import usePickImage from 'common-ui/src/components/use-pick-image'; import { useUploadToObjectStorage } from '../hooks/useUploadToObjectStorage'; export interface StoreFormData { name: string; description: string; imageUrl?: string; owner: number; products: number[]; } interface StoreImage { uri: string; mimeType: string; isExisting: boolean; } export interface StoreFormRef { // Add methods if needed } interface StoreFormProps { mode: 'create' | 'edit'; initialValues: StoreFormData; onSubmit: (values: StoreFormData) => void; isLoading: boolean; storeId?: number; } // Extend Formik values with images array interface FormikStoreValues extends StoreFormData { images: StoreImage[]; } const validationSchema = Yup.object().shape({ name: Yup.string().required('Name is required'), description: Yup.string(), imageUrl: Yup.string(), owner: Yup.number().required('Owner is required'), products: Yup.array().of(Yup.number()), }); const StoreForm = forwardRef((props, ref) => { const { mode, initialValues, onSubmit, isLoading, storeId } = props; const { data: staffData } = trpc.admin.staffUser.getStaff.useQuery(); const { data: productsData } = trpc.admin.product.getProducts.useQuery(); // Build initial form values with images array const buildInitialValues = (): FormikStoreValues => { const images: StoreImage[] = []; if (initialValues.imageUrl) { images.push({ uri: initialValues.imageUrl, mimeType: 'image/jpeg', isExisting: true, }); } return { ...initialValues, images, }; }; const [formInitialValues, setFormInitialValues] = useState(buildInitialValues()); // For edit mode, pre-select products belonging to this store const initialSelectedProducts = useMemo(() => { if (mode !== 'edit' || !productsData?.products) return []; return productsData.products .filter(p => p.storeId === storeId) .map(p => p.id); }, [mode, productsData?.products, storeId]); useEffect(() => { setFormInitialValues({ ...buildInitialValues(), products: initialSelectedProducts, }); }, [initialValues, initialSelectedProducts]); const staffOptions = staffData?.staff.map(staff => ({ label: staff.name, value: staff.id, })) || []; const { uploadSingle, isUploading } = useUploadToObjectStorage(); return ( {({ handleChange, handleSubmit, values, setFieldValue, errors, touched }) => { // Image picker that adds to Formik field const handleImagePick = usePickImage({ setFile: async (assets: any) => { if (!assets || (Array.isArray(assets) && assets.length === 0)) { return; } const files = Array.isArray(assets) ? assets : [assets]; const newImages: StoreImage[] = files.map((asset) => ({ uri: asset.uri, mimeType: asset.mimeType || 'image/jpeg', isExisting: false, })); // Add to Formik images field const currentImages = values.images || []; setFieldValue('images', [...currentImages, ...newImages]); }, multiple: false, }); // Remove image - works for both existing and new const handleRemoveImage = (image: { uri: string; mimeType: string }) => { const currentImages = values.images || []; const removedImage = currentImages.find(img => img.uri === image.uri); const newImages = currentImages.filter(img => img.uri !== image.uri); setFieldValue('images', newImages); // If we removed an existing image, also clear the imageUrl if (removedImage?.isExisting) { setFieldValue('imageUrl', undefined); } }; const submit = async () => { try { let imageUrl: string | undefined; // Get new images that need to be uploaded const newImages = values.images.filter(img => !img.isExisting); if (newImages.length > 0) { // Upload the first new image (single image for stores) const image = newImages[0]; const response = await fetch(image.uri); const imageBlob = await response.blob(); const { key } = await uploadSingle(imageBlob, image.mimeType, 'store'); imageUrl = key; } else { // Check if there's an existing image remaining const existingImage = values.images.find(img => img.isExisting); if (existingImage) { imageUrl = existingImage.uri; } } // Submit form with imageUrl (without images array) const { images, ...submitValues } = values; onSubmit({ ...submitValues, imageUrl }); } catch (error) { console.error('Upload error:', error); Alert.alert('Error', error instanceof Error ? error.message : 'Failed to upload image'); } }; // Prepare images for ImageUploaderNeo (convert to expected format) const imagesForUploader = (values.images || []).map(img => ({ uri: img.uri, mimeType: img.mimeType, })); return ( setFieldValue('owner', value)} placeholder="Select owner" error={!!(touched.owner && errors.owner)} style={{ marginBottom: 16 }} /> setFieldValue('products', value)} multiple={true} label="Products" placeholder="Select products" isDisabled={(product) => product.storeId !== null && product.storeId !== storeId} labelFormat={(product) => `${product.name} - ₹${product.price}`} /> Store Image {isUploading ? 'Uploading...' : isLoading ? (mode === 'create' ? 'Creating...' : 'Updating...') : (mode === 'create' ? 'Create Store' : 'Update Store')} ); }} ); }); StoreForm.displayName = 'StoreForm'; export default StoreForm;