import React, { useState } from 'react'; import { View, Text, Modal, TouchableOpacity, StyleSheet, ScrollView, Image, ActivityIndicator, Platform, Alert, } from 'react-native'; import * as ImagePicker from 'expo-image-picker'; import { KurdistanColors } from '../theme/colors'; import { useAuth } from '../contexts/AuthContext'; import { supabase } from '../lib/supabase'; // Cross-platform alert helper const showAlert = (title: string, message: string, buttons?: Array<{text: string; onPress?: () => void}>) => { if (Platform.OS === 'web') { window.alert(`${title}\n\n${message}`); if (buttons?.[0]?.onPress) buttons[0].onPress(); } else { Alert.alert(title, message, buttons); } }; // Avatar pool - Kurdish/Middle Eastern themed avatars const AVATAR_POOL = [ { id: 'avatar1', emoji: 'πŸ‘¨πŸ»', label: 'Man 1' }, { id: 'avatar2', emoji: 'πŸ‘¨πŸΌ', label: 'Man 2' }, { id: 'avatar3', emoji: 'πŸ‘¨πŸ½', label: 'Man 3' }, { id: 'avatar4', emoji: 'πŸ‘¨πŸΎ', label: 'Man 4' }, { id: 'avatar5', emoji: 'πŸ‘©πŸ»', label: 'Woman 1' }, { id: 'avatar6', emoji: 'πŸ‘©πŸΌ', label: 'Woman 2' }, { id: 'avatar7', emoji: 'πŸ‘©πŸ½', label: 'Woman 3' }, { id: 'avatar8', emoji: 'πŸ‘©πŸΎ', label: 'Woman 4' }, { id: 'avatar9', emoji: 'πŸ§”πŸ»', label: 'Beard 1' }, { id: 'avatar10', emoji: 'πŸ§”πŸΌ', label: 'Beard 2' }, { id: 'avatar11', emoji: 'πŸ§”πŸ½', label: 'Beard 3' }, { id: 'avatar12', emoji: 'πŸ§”πŸΎ', label: 'Beard 4' }, { id: 'avatar13', emoji: 'πŸ‘³πŸ»β€β™‚οΈ', label: 'Turban 1' }, { id: 'avatar14', emoji: 'πŸ‘³πŸΌβ€β™‚οΈ', label: 'Turban 2' }, { id: 'avatar15', emoji: 'πŸ‘³πŸ½β€β™‚οΈ', label: 'Turban 3' }, { id: 'avatar16', emoji: 'πŸ§•πŸ»', label: 'Hijab 1' }, { id: 'avatar17', emoji: 'πŸ§•πŸΌ', label: 'Hijab 2' }, { id: 'avatar18', emoji: 'πŸ§•πŸ½', label: 'Hijab 3' }, { id: 'avatar19', emoji: 'πŸ‘΄πŸ»', label: 'Elder 1' }, { id: 'avatar20', emoji: 'πŸ‘΄πŸΌ', label: 'Elder 2' }, { id: 'avatar21', emoji: 'πŸ‘΅πŸ»', label: 'Elder Woman 1' }, { id: 'avatar22', emoji: 'πŸ‘΅πŸΌ', label: 'Elder Woman 2' }, { id: 'avatar23', emoji: 'πŸ‘¦πŸ»', label: 'Boy 1' }, { id: 'avatar24', emoji: 'πŸ‘¦πŸΌ', label: 'Boy 2' }, { id: 'avatar25', emoji: 'πŸ‘§πŸ»', label: 'Girl 1' }, { id: 'avatar26', emoji: 'πŸ‘§πŸΌ', label: 'Girl 2' }, ]; interface AvatarPickerModalProps { visible: boolean; onClose: () => void; currentAvatar?: string; onAvatarSelected?: (avatarUrl: string) => void; } const AvatarPickerModal: React.FC = ({ visible, onClose, currentAvatar, onAvatarSelected, }) => { const { user } = useAuth(); const [selectedAvatar, setSelectedAvatar] = useState(currentAvatar || null); const [uploadedImageUri, setUploadedImageUri] = useState(null); const [isSaving, setIsSaving] = useState(false); const [isUploading, setIsUploading] = useState(false); const handleAvatarSelect = (avatarId: string) => { setSelectedAvatar(avatarId); setUploadedImageUri(null); // Clear uploaded image when selecting from pool }; const requestPermissions = async () => { if (Platform.OS !== 'web') { const { status } = await ImagePicker.requestMediaLibraryPermissionsAsync(); if (status !== 'granted') { showAlert( 'Permission Required', 'Sorry, we need camera roll permissions to upload your photo!' ); return false; } } return true; }; const handlePickImage = async () => { const hasPermission = await requestPermissions(); if (!hasPermission) return; try { const result = await ImagePicker.launchImageLibraryAsync({ mediaTypes: 'images', allowsEditing: true, aspect: [1, 1], quality: 0.8, }); if (!result.canceled && result.assets[0]) { setIsUploading(true); const imageUri = result.assets[0].uri; if (__DEV__) console.warn('[AvatarPicker] Uploading image:', imageUri); // Upload to Supabase Storage const uploadedUrl = await uploadImageToSupabase(imageUri); setIsUploading(false); if (uploadedUrl) { if (__DEV__) console.warn('[AvatarPicker] Upload successful:', uploadedUrl); setUploadedImageUri(uploadedUrl); setSelectedAvatar(null); // Clear emoji selection showAlert('Success', 'Photo uploaded successfully!'); } else { if (__DEV__) console.error('[AvatarPicker] Upload failed: no URL returned'); showAlert('Upload Failed', 'Could not upload your photo. Please check your internet connection and try again.'); } } } catch (error) { setIsUploading(false); if (__DEV__) console.error('[AvatarPicker] Error picking image:', error); showAlert('Error', 'Failed to pick image. Please try again.'); } }; const uploadImageToSupabase = async (imageUri: string): Promise => { if (!user) { if (__DEV__) console.warn('[AvatarPicker] No user found'); return null; } try { if (__DEV__) console.warn('[AvatarPicker] Starting upload for URI:', imageUri.substring(0, 50) + '...'); // Convert image URI to blob const response = await fetch(imageUri); const blob = await response.blob(); if (__DEV__) console.warn('[AvatarPicker] Blob created - size:', blob.size, 'bytes, type:', blob.type); if (blob.size === 0) { if (__DEV__) console.warn('[AvatarPicker] Blob is empty!'); return null; } // Get file extension from blob type or URI let fileExt = 'jpg'; if (blob.type) { // Extract extension from MIME type (e.g., 'image/jpeg' -> 'jpeg') const mimeExt = blob.type.split('/')[1]; if (mimeExt && mimeExt !== 'octet-stream') { fileExt = mimeExt === 'jpeg' ? 'jpg' : mimeExt; } } else if (!imageUri.startsWith('blob:') && !imageUri.startsWith('data:')) { // Try to get extension from URI for non-blob URIs const uriExt = imageUri.split('.').pop()?.toLowerCase(); if (uriExt && ['jpg', 'jpeg', 'png', 'gif', 'webp'].includes(uriExt)) { fileExt = uriExt; } } const fileName = `${user.id}-${Date.now()}.${fileExt}`; const filePath = `avatars/${fileName}`; const contentType = blob.type || `image/${fileExt}`; if (__DEV__) console.warn('[AvatarPicker] Uploading to path:', filePath, 'contentType:', contentType); // Upload to Supabase Storage const { data: uploadData, error: uploadError } = await supabase.storage .from('avatars') .upload(filePath, blob, { contentType: contentType, upsert: true, // Allow overwriting if file exists }); if (uploadError) { if (__DEV__) console.warn('[AvatarPicker] Supabase upload error:', uploadError.message, uploadError); // Show more specific error to user showAlert('Upload Error', `Storage error: ${uploadError.message}`); return null; } if (__DEV__) console.warn('[AvatarPicker] Upload successful:', uploadData); // Get public URL const { data } = supabase.storage .from('avatars') .getPublicUrl(filePath); if (__DEV__) console.warn('[AvatarPicker] Public URL:', data.publicUrl); return data.publicUrl; } catch (error: unknown) { const errorMessage = error instanceof Error ? error.message : 'Unknown error'; if (__DEV__) console.warn('[AvatarPicker] Error uploading to Supabase:', errorMessage); showAlert('Upload Error', `Failed to upload: ${errorMessage}`); return null; } }; const handleSave = async () => { const avatarToSave = uploadedImageUri || selectedAvatar; if (!avatarToSave || !user) { showAlert('Error', 'Please select an avatar or upload a photo'); return; } if (__DEV__) console.warn('[AvatarPicker] Saving avatar:', avatarToSave); setIsSaving(true); try { // Update avatar in Supabase profiles table const { data, error } = await supabase .from('profiles') .update({ avatar_url: avatarToSave }) .eq('id', user.id) .select(); if (error) { if (__DEV__) console.error('[AvatarPicker] Save error:', error); throw error; } if (__DEV__) console.warn('[AvatarPicker] Avatar saved successfully:', data); showAlert('Success', 'Avatar updated successfully!'); if (onAvatarSelected) { onAvatarSelected(avatarToSave); } onClose(); } catch (error) { if (__DEV__) console.error('[AvatarPicker] Error updating avatar:', error); showAlert('Error', 'Failed to update avatar. Please try again.'); } finally { setIsSaving(false); } }; return ( {/* Header */} Choose Your Avatar βœ• {/* Upload Photo Button */} {isUploading ? ( ) : ( <> πŸ“· Upload Your Photo )} {/* Uploaded Image Preview */} {uploadedImageUri && ( setUploadedImageUri(null)} > βœ• )} {/* Divider */} OR CHOOSE FROM POOL {/* Avatar Grid */} {AVATAR_POOL.map((avatar) => ( handleAvatarSelect(avatar.id)} > {avatar.emoji} {selectedAvatar === avatar.id && ( βœ“ )} ))} {/* Footer Actions */} Cancel {isSaving ? ( ) : ( Save Avatar )} ); }; const styles = StyleSheet.create({ modalOverlay: { flex: 1, backgroundColor: 'rgba(0, 0, 0, 0.5)', justifyContent: 'flex-end', }, modalContainer: { backgroundColor: KurdistanColors.spi, borderTopLeftRadius: 24, borderTopRightRadius: 24, maxHeight: '80%', paddingBottom: 20, }, modalHeader: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', padding: 20, borderBottomWidth: 1, borderBottomColor: '#E0E0E0', }, modalTitle: { fontSize: 20, fontWeight: 'bold', color: KurdistanColors.reş, }, closeButton: { width: 32, height: 32, borderRadius: 16, backgroundColor: '#F0F0F0', justifyContent: 'center', alignItems: 'center', }, closeButtonText: { fontSize: 18, color: '#666', }, avatarScroll: { padding: 20, }, avatarGrid: { flexDirection: 'row', flexWrap: 'wrap', justifyContent: 'space-between', }, avatarOption: { width: '22%', aspectRatio: 1, backgroundColor: '#F8F9FA', borderRadius: 16, justifyContent: 'center', alignItems: 'center', marginBottom: 12, borderWidth: 3, borderColor: 'transparent', }, avatarOptionSelected: { borderColor: KurdistanColors.kesk, backgroundColor: '#E8F5E9', }, avatarEmoji: { fontSize: 36, }, selectedBadge: { position: 'absolute', top: -4, right: -4, width: 24, height: 24, borderRadius: 12, backgroundColor: KurdistanColors.kesk, justifyContent: 'center', alignItems: 'center', }, selectedBadgeText: { fontSize: 14, color: KurdistanColors.spi, fontWeight: 'bold', }, modalFooter: { flexDirection: 'row', paddingHorizontal: 20, paddingTop: 16, gap: 12, }, cancelButton: { flex: 1, padding: 16, borderRadius: 12, backgroundColor: '#F0F0F0', alignItems: 'center', }, cancelButtonText: { fontSize: 16, fontWeight: '600', color: '#666', }, saveButton: { flex: 1, padding: 16, borderRadius: 12, backgroundColor: KurdistanColors.kesk, alignItems: 'center', }, saveButtonDisabled: { opacity: 0.6, }, saveButtonText: { fontSize: 16, fontWeight: 'bold', color: KurdistanColors.spi, }, uploadSection: { paddingHorizontal: 20, paddingVertical: 16, borderBottomWidth: 1, borderBottomColor: '#E0E0E0', }, uploadButton: { flexDirection: 'row', alignItems: 'center', justifyContent: 'center', backgroundColor: KurdistanColors.kesk, paddingVertical: 14, paddingHorizontal: 20, borderRadius: 12, gap: 8, }, uploadButtonDisabled: { opacity: 0.6, }, uploadButtonIcon: { fontSize: 20, }, uploadButtonText: { fontSize: 16, fontWeight: '600', color: KurdistanColors.spi, }, uploadedPreview: { marginTop: 12, alignItems: 'center', position: 'relative', }, uploadedImage: { width: 100, height: 100, borderRadius: 50, borderWidth: 3, borderColor: KurdistanColors.kesk, }, removeUploadButton: { position: 'absolute', top: -4, right: '38%', width: 28, height: 28, borderRadius: 14, backgroundColor: KurdistanColors.sor, justifyContent: 'center', alignItems: 'center', boxShadow: '0px 2px 3px rgba(0, 0, 0, 0.3)', elevation: 4, }, removeUploadText: { color: KurdistanColors.spi, fontSize: 14, fontWeight: 'bold', }, divider: { flexDirection: 'row', alignItems: 'center', paddingHorizontal: 20, paddingVertical: 16, }, dividerLine: { flex: 1, height: 1, backgroundColor: '#E0E0E0', }, dividerText: { fontSize: 11, fontWeight: '600', color: '#999', marginHorizontal: 12, letterSpacing: 0.5, }, }); export default AvatarPickerModal;