diff --git a/src/components/AdhocOrderCard.tsx b/src/components/AdhocOrderCard.tsx index 72c8985e..9780a5a8 100644 --- a/src/components/AdhocOrderCard.tsx +++ b/src/components/AdhocOrderCard.tsx @@ -18,6 +18,7 @@ import MultipleCustomerAvatars from './MultipleCustomerAvatars'; import LoadingText from './LoadingText'; import LoadingOverlay from './LoadingOverlay'; import Badge from './Badge'; +import { useLanguage } from '../contexts/LanguageContext'; const INFO_FIELD_VALUE_MIN_HEIGHT = 30; export const AdhocOrderCard = ({ order, onPress, onAccept, onDismiss }) => { @@ -27,6 +28,7 @@ export const AdhocOrderCard = ({ order, onPress, onAccept, onDismiss }) => { const { location } = useLocation(); const { isDarkMode } = useAppTheme(); const [isAccepting, setIsAccepting] = useState(false); + const { t } = useLanguage(); const destination = useMemo(() => { const pickup = order.getAttribute('payload.pickup'); @@ -44,13 +46,13 @@ export const AdhocOrderCard = ({ order, onPress, onAccept, onDismiss }) => { }, [location, destination]); const handleAccept = useCallback(async () => { - Alert.alert('Accept Ad-Hoc order?', 'By accepting this ad-hoc order it will become assigned to you and the order will start immediatley.', [ + Alert.alert(t('common.cancel'), t('AdhocOrderCard.byAcceptingThisAdHocOrderItWillBecomeAssignedToYouAndTheOrderWillStartImmediatley'), [ { - text: 'Cancel', + text: t('common.cancel'), style: 'cancel', }, { - text: 'Accept', + text: t('AdhocOrderCard.acceptOrder'), onPress: async () => { setIsAccepting(true); @@ -70,13 +72,13 @@ export const AdhocOrderCard = ({ order, onPress, onAccept, onDismiss }) => { }, [order, setIsAccepting]); const handleDismiss = useCallback(() => { - Alert.alert('Dismiss Ad-Hoc order?', 'By dimissing this ad-hoc order it will no longer display as an available order.', [ + Alert.alert(t('common.cancel'), t('AdhocOrderCard.byDimissingThisAdHocOrderItWillNoLongerDisplayAsAnAvailableOrder'), [ { - text: 'Cancel', + text: t('common.cancel'), style: 'cancel', }, { - text: 'OK', + text: t('common.close'), onPress: () => { if (typeof onDismiss === 'function') { onDismiss(order); @@ -88,7 +90,7 @@ export const AdhocOrderCard = ({ order, onPress, onAccept, onDismiss }) => { return ( - + { - Order Available Nearby: {formatMeters(distance)} + {t('AdhocOrderCard.orderAvailableNearby')}: {formatMeters(distance)} @@ -126,7 +128,7 @@ export const AdhocOrderCard = ({ order, onPress, onAccept, onDismiss }) => { {formatWhatsAppTimestamp(new Date(order.getAttribute('created_at')))} - {formatMeters(distance)} away + {formatMeters(distance)} {t('AdhocOrderCard.away')} @@ -139,7 +141,7 @@ export const AdhocOrderCard = ({ order, onPress, onAccept, onDismiss }) => { icon={faLocationDot} iconColor={theme['$textPrimary'].val} waypoint={destination.serialize()} - title='Pickup Destination' + title={t('AdhocOrderCard.pickupDestination')} titleStyle={{ fontWeight: 'bold', fontSize: 14, textTransform: 'uppercase' }} /> @@ -147,7 +149,7 @@ export const AdhocOrderCard = ({ order, onPress, onAccept, onDismiss }) => { @@ -155,7 +157,7 @@ export const AdhocOrderCard = ({ order, onPress, onAccept, onDismiss }) => { - Dismiss Order + {t('AdhocOrderCard.dismissOrder')} @@ -165,4 +167,4 @@ export const AdhocOrderCard = ({ order, onPress, onAccept, onDismiss }) => { ); }; -export default AdhocOrderCard; +export default AdhocOrderCard; \ No newline at end of file diff --git a/src/components/Buttons.tsx b/src/components/Buttons.tsx index cadd95ba..b0fc82ee 100644 --- a/src/components/Buttons.tsx +++ b/src/components/Buttons.tsx @@ -5,22 +5,25 @@ import { faFacebook, faInstagram, faGoogle, faApple } from '@fortawesome/free-br import { faPhone } from '@fortawesome/free-solid-svg-icons'; import LinearGradient from 'react-native-linear-gradient'; import { useTheme } from 'tamagui'; +import { useLanguage } from '../contexts/LanguageContext'; export const PhoneLoginButton = ({ onPress, ...props }) => { const theme = useTheme(); + const { t } = useLanguage(); return ( ); }; export const AppleLoginButton = ({ onPress, ...props }) => { const theme = useTheme(); + const { t } = useLanguage(); return ( -); +export const GoogleLoginButton = ({ onPress, ...props }) => { + const { t } = useLanguage(); + return ( + + ); +}; \ No newline at end of file diff --git a/src/components/CameraCapture.tsx b/src/components/CameraCapture.tsx index 865e1c55..a3162fde 100644 --- a/src/components/CameraCapture.tsx +++ b/src/components/CameraCapture.tsx @@ -1,5 +1,5 @@ import React, { useEffect, useState, useRef, useCallback } from 'react'; -import { Dimensions, Platform } from 'react-native'; +import { Dimensions, Platform, Alert } from 'react-native'; import { YStack, XStack, Button, Text, Image, Card, ScrollView } from 'tamagui'; import { Camera, useCameraDevice, useFrameProcessor } from 'react-native-vision-camera'; import type { Camera as CameraRef } from 'react-native-vision-camera'; @@ -7,6 +7,7 @@ import { CameraRoll } from '@react-native-camera-roll/camera-roll'; import RNFS from 'react-native-fs'; import useDimensions from '../hooks/use-dimensions'; import { toast, ToastPosition } from '../utils/toast'; +import { useLanguage } from '../contexts/LanguageContext'; const MENU_BAR_HEIGHT = 160; @@ -19,6 +20,7 @@ interface CameraCaptureScreenProps { } const CameraCapture = ({ onDone }: CameraCaptureScreenProps) => { + const { t } = useLanguage(); const cameraRef = useRef(null); const device = useCameraDevice('back'); const { screenHeight } = useDimensions(); @@ -46,7 +48,7 @@ const CameraCapture = ({ onDone }: CameraCaptureScreenProps) => { flash: 'off', qualityPrioritization: 'balanced', }); - toast.info('Photo captured.', { position: ToastPosition.TOP }); + toast.info(t('CameraCapture.photoCaptured'), { position: ToastPosition.TOP }); const filePath = (Platform.OS === 'ios' ? '' : 'file://') + photo.path; const base64Data = await RNFS.readFile(filePath, 'base64'); @@ -59,7 +61,7 @@ const CameraCapture = ({ onDone }: CameraCaptureScreenProps) => { } catch (error) { console.warn('Error taking photo:', error); } - }, []); + }, [t]); // Let the user pick images from their camera roll const handleSelectFromCameraRoll = useCallback(async () => { @@ -74,13 +76,13 @@ const CameraCapture = ({ onDone }: CameraCaptureScreenProps) => { // For simplicity, let's just take the first photo (in a real scenario you'd present a UI). if (photosFromGallery.edges.length > 0) { const { node } = photosFromGallery.edges[0]; - toast.info('Photo added from gallery.', { position: ToastPosition.TOP }); + toast.info(t('CameraCapture.photoAddedFromGallery'), { position: ToastPosition.TOP }); setPhotos((prev) => [...prev, { uri: node.image.uri }]); } } catch (error) { console.warn('Error selecting from camera roll:', error); } - }, []); + }, [t]); const openGalleryOverlay = () => setShowGalleryOverlay(true); const closeGalleryOverlay = () => setShowGalleryOverlay(false); @@ -102,7 +104,7 @@ const CameraCapture = ({ onDone }: CameraCaptureScreenProps) => { if (!device || !hasPermission) { return ( - Loading camera or awaiting permission... + {t('CameraCapture.loadingCameraOrAwaitingPermission')} ); } @@ -115,21 +117,21 @@ const CameraCapture = ({ onDone }: CameraCaptureScreenProps) => { @@ -139,7 +141,7 @@ const CameraCapture = ({ onDone }: CameraCaptureScreenProps) => { @@ -175,4 +177,4 @@ const CameraCapture = ({ onDone }: CameraCaptureScreenProps) => { ); }; -export default CameraCapture; +export default CameraCapture; \ No newline at end of file diff --git a/src/components/ChatKeyboard.tsx b/src/components/ChatKeyboard.tsx index 683f42d7..ef6b5f2d 100644 --- a/src/components/ChatKeyboard.tsx +++ b/src/components/ChatKeyboard.tsx @@ -6,10 +6,12 @@ import { FontAwesomeIcon } from '@fortawesome/react-native-fontawesome'; import { faCamera, faPlus, faPaperPlane } from '@fortawesome/free-solid-svg-icons'; import useAppTheme from '../hooks/use-app-theme'; import CameraCapture from './CameraCapture'; +import { useLanguage } from '../contexts/LanguageContext'; const INPUT_MIN_HEIGHT = 40; const INPUT_MAX_HEIGHT = 120; const ChatKeyboard = ({ onSend, onAttach, onCamera, onFocus, onBlur }) => { + const { t } = useLanguage(); const { isDarkMode } = useAppTheme(); const theme = useTheme(); const headerHeight = useHeaderHeight(); @@ -69,7 +71,7 @@ const ChatKeyboard = ({ onSend, onAttach, onCamera, onFocus, onBlur }) => { maxHeight={INPUT_MAX_HEIGHT} textAlignVertical='top' lineHeight={20} - placeholder='Type a message' + placeholder={t('ChatKeyboard.typeAMessage')} multiline backgroundColor='$surface' borderColor='$borderColor' @@ -104,4 +106,4 @@ const ChatKeyboard = ({ onSend, onAttach, onCamera, onFocus, onBlur }) => { ); }; -export default ChatKeyboard; +export default ChatKeyboard; \ No newline at end of file diff --git a/src/components/ChatParticipants.tsx b/src/components/ChatParticipants.tsx index 05820c0a..9d82682e 100644 --- a/src/components/ChatParticipants.tsx +++ b/src/components/ChatParticipants.tsx @@ -2,15 +2,17 @@ import React from 'react'; import { Pressable } from 'react-native'; import { Avatar, XStack, YStack, Text, useTheme } from 'tamagui'; import useAppTheme from '../hooks/use-app-theme'; +import { useLanguage } from '../contexts/LanguageContext'; export const ChatParticipants = ({ participants = [], size = 30, onPress }) => { const { isDarkMode } = useAppTheme(); + const { t } = useLanguage(); // Display a friendly message when no participants exist if (participants.length === 0) { return ( - No participants + {t('ChatParticipants.noParticipants')} ); } @@ -69,4 +71,4 @@ export const ChatParticipants = ({ participants = [], size = 30, onPress }) => { ); }; -export default ChatParticipants; +export default ChatParticipants; \ No newline at end of file diff --git a/src/components/Comment.tsx b/src/components/Comment.tsx index fc3f5e38..d4268bb6 100644 --- a/src/components/Comment.tsx +++ b/src/components/Comment.tsx @@ -5,10 +5,12 @@ import { FontAwesomeIcon } from '@fortawesome/react-native-fontawesome'; import { faReply, faPenToSquare, faTrash, faSave } from '@fortawesome/free-solid-svg-icons'; import { formatDistanceToNow } from 'date-fns'; import useFleetbase from '../hooks/use-fleetbase'; +import { useLanguage } from '../contexts/LanguageContext'; const Comment = ({ comment: _comment, reloadComments, isCommentInvalid }) => { const theme = useTheme(); const { adapter } = useFleetbase(); + const { t } = useLanguage(); const [comment, setComment] = useState(_comment); const [replying, setReplying] = useState(false); const [editing, setEditing] = useState(false); @@ -18,10 +20,10 @@ const Comment = ({ comment: _comment, reloadComments, isCommentInvalid }) => { const [isDeleting, setIsDeleting] = useState(false); const handleDelete = useCallback(() => { - Alert.alert('Delete Comment', 'Are you sure you want to delete this comment?', [ - { text: 'Cancel', style: 'cancel' }, + Alert.alert(t('common.delete'), t('Comment.areYouSureYouWantToDeleteThisComment'), [ + { text: t('common.cancel'), style: 'cancel' }, { - text: 'Delete', + text: t('common.delete'), style: 'destructive', onPress: async () => { setIsDeleting(true); @@ -96,7 +98,7 @@ const Comment = ({ comment: _comment, reloadComments, isCommentInvalid }) => {