diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index fb78f39..a1f1562 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -1,6 +1,10 @@ + + + + NSLocationWhenInUseUsageDescription + NSCameraUsageDescription + Pennyzo needs access to your camera to take photos of your company logo + NSPhotoLibraryUsageDescription + Pennyzo needs access to your photo library to select your company logo + NSPhotoLibraryAddUsageDescription + Pennyzo needs access to save photos to your library UILaunchStoryboardName LaunchScreen UIRequiredDeviceCapabilities diff --git a/package-lock.json b/package-lock.json index 26fd3df..71f3efa 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,6 +18,7 @@ "react-i18next": "^16.0.0", "react-native": "0.81.4", "react-native-gesture-handler": "^2.21.2", + "react-native-image-picker": "^8.2.1", "react-native-safe-area-context": "^5.5.2", "react-native-screens": "^4.10.1", "react-native-vector-icons": "^10.2.0" @@ -11102,6 +11103,16 @@ "react-native": "*" } }, + "node_modules/react-native-image-picker": { + "version": "8.2.1", + "resolved": "https://registry.npmjs.org/react-native-image-picker/-/react-native-image-picker-8.2.1.tgz", + "integrity": "sha512-FBeGYJGFDjMdGCcyubDJgBAPCQ4L1D3hwLXyUU91jY9ahOZMTbluceVvRmrEKqnDPFJ0gF1NVhJ0nr1nROFLdg==", + "license": "MIT", + "peerDependencies": { + "react": "*", + "react-native": "*" + } + }, "node_modules/react-native-is-edge-to-edge": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/react-native-is-edge-to-edge/-/react-native-is-edge-to-edge-1.2.1.tgz", diff --git a/package.json b/package.json index f0aa20d..aea38af 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,7 @@ "react-i18next": "^16.0.0", "react-native": "0.81.4", "react-native-gesture-handler": "^2.21.2", + "react-native-image-picker": "^8.2.1", "react-native-safe-area-context": "^5.5.2", "react-native-screens": "^4.10.1", "react-native-vector-icons": "^10.2.0" diff --git a/src/screens/BusinessSetupScreen.tsx b/src/screens/BusinessSetupScreen.tsx index 4785192..142491d 100644 --- a/src/screens/BusinessSetupScreen.tsx +++ b/src/screens/BusinessSetupScreen.tsx @@ -1,8 +1,9 @@ import React, { useMemo, useState } from 'react'; -import { StyleSheet, Text, View, TextInput, TouchableOpacity, ScrollView } from 'react-native'; +import { StyleSheet, Text, View, TextInput, TouchableOpacity, ScrollView, Image, Alert } from 'react-native'; import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons'; import { NativeStackScreenProps } from '@react-navigation/native-stack'; import { useTranslation } from 'react-i18next'; +import { launchImageLibrary, launchCamera, ImagePickerResponse } from 'react-native-image-picker'; import { colors, typography, spacing, borderRadius, shadows, iconSizes } from '../theme'; import { RootStackParamList } from '../types/navigation'; @@ -66,6 +67,7 @@ export const BusinessSetupScreen: React.FC = ({ navigation }) => { const { t } = useTranslation(); const [step, setStep] = useState('company'); const [companyName, setCompanyName] = useState(''); + const [companyLogo, setCompanyLogo] = useState(null); const [selectedIndustry, setSelectedIndustry] = useState(null); const [selectedAgents, setSelectedAgents] = useState([]); @@ -96,6 +98,81 @@ export const BusinessSetupScreen: React.FC = ({ navigation }) => { } }; + const handleImagePicker = () => { + Alert.alert( + 'Upload Company Logo', + 'Choose an option', + [ + { + text: 'Take Photo', + onPress: () => { + launchCamera( + { + mediaType: 'photo', + quality: 0.8, + maxWidth: 800, + maxHeight: 800, + includeBase64: false, + }, + handleImageResponse + ); + }, + }, + { + text: 'Choose from Gallery', + onPress: () => { + launchImageLibrary( + { + mediaType: 'photo', + quality: 0.8, + maxWidth: 800, + maxHeight: 800, + includeBase64: false, + }, + handleImageResponse + ); + }, + }, + { + text: 'Cancel', + style: 'cancel', + }, + ] + ); + }; + + const handleImageResponse = (response: ImagePickerResponse) => { + if (response.didCancel) { + console.log('User cancelled image picker'); + } else if (response.errorCode) { + console.log('ImagePicker Error: ', response.errorMessage); + Alert.alert('Error', 'Failed to pick image. Please try again.'); + } else if (response.assets && response.assets[0]) { + const imageUri = response.assets[0].uri; + if (imageUri) { + setCompanyLogo(imageUri); + } + } + }; + + const handleRemoveLogo = () => { + Alert.alert( + 'Remove Logo', + 'Are you sure you want to remove the company logo?', + [ + { + text: 'Cancel', + style: 'cancel', + }, + { + text: 'Remove', + onPress: () => setCompanyLogo(null), + style: 'destructive', + }, + ] + ); + }; + const handleContinue = () => { if (step === 'company' && companyName) { setStep('industry'); @@ -137,6 +214,7 @@ export const BusinessSetupScreen: React.FC = ({ navigation }) => { {t('businessSetup.steps.company.title')} {t('businessSetup.steps.company.subtitle')} + {/* Company Name Input */} {t('businessSetup.steps.company.label')} = ({ navigation }) => { autoFocus /> + + {/* Company Logo Upload */} + + + Company Logo (Optional) + + + Square format recommended + + + {companyLogo ? ( + + + + + + + + Change Logo + + + ) : ( + + + + + Upload Company Logo + Tap to choose from gallery or take a photo + + + + Square (1:1) or similar ratio + + + + PNG, JPG formats supported + + + + )} + )} @@ -469,4 +597,123 @@ const styles = StyleSheet.create({ fontSize: 16, color: colors.background, }, + logoUploadContainer: { + width: '100%', + marginTop: spacing.xxl, + marginBottom: spacing.xl, + }, + logoUploadButton: { + width: '100%', + minHeight: 220, + borderRadius: borderRadius.lg, + borderWidth: 3, + borderColor: colors.highlight, + borderStyle: 'dashed', + backgroundColor: `${colors.highlight}15`, + alignItems: 'center', + justifyContent: 'center', + gap: spacing.xs, + padding: spacing.lg, + paddingVertical: spacing.xl, + }, + logoUploadIcon: { + width: 70, + height: 70, + borderRadius: 35, + backgroundColor: `${colors.highlight}25`, + alignItems: 'center', + justifyContent: 'center', + marginBottom: spacing.xs, + }, + logoUploadText: { + ...typography.bodyBold, + fontSize: 16, + color: colors.highlightAlt, + }, + logoUploadHint: { + ...typography.caption, + color: colors.textSecondary, + textAlign: 'center', + marginBottom: spacing.xs, + }, + logoPreviewContainer: { + width: '100%', + alignItems: 'center', + position: 'relative', + }, + logoPreview: { + width: 200, + height: 200, + borderRadius: borderRadius.lg, + borderWidth: 3, + borderColor: colors.highlight, + }, + logoRemoveButton: { + position: 'absolute', + top: -10, + right: '50%', + marginRight: -110, + backgroundColor: colors.background, + borderRadius: 14, + ...shadows.md, + }, + logoChangeButton: { + flexDirection: 'row', + alignItems: 'center', + gap: spacing.xs, + marginTop: spacing.md, + paddingVertical: spacing.sm, + paddingHorizontal: spacing.lg, + backgroundColor: colors.highlight, + borderRadius: borderRadius.md, + ...shadows.glow, + }, + logoChangeText: { + ...typography.bodyBold, + fontSize: 14, + color: colors.background, + }, + logoHeaderContainer: { + flexDirection: 'row', + justifyContent: 'space-between', + alignItems: 'center', + marginBottom: spacing.sm, + flexWrap: 'wrap', + gap: spacing.xs, + }, + logoInfoBadge: { + flexDirection: 'row', + alignItems: 'center', + gap: spacing.xs, + paddingHorizontal: spacing.sm, + paddingVertical: spacing.xs, + backgroundColor: `${colors.highlight}15`, + borderRadius: borderRadius.sm, + borderWidth: 1, + borderColor: `${colors.highlight}30`, + }, + logoInfoText: { + ...typography.caption, + fontSize: 11, + color: colors.highlight, + fontWeight: '600', + }, + logoGuidelinesContainer: { + marginTop: spacing.sm, + gap: spacing.xs, + width: '100%', + alignItems: 'center', + }, + guidelineItem: { + flexDirection: 'row', + alignItems: 'center', + justifyContent: 'center', + gap: spacing.xs, + }, + guidelineText: { + ...typography.caption, + fontSize: 11, + color: colors.textSecondary, + flexShrink: 1, + }, });