diff --git a/client/src/components/Journey/JourneyDetailPageSettingsDialog.tsx b/client/src/components/Journey/JourneyDetailPageSettingsDialog.tsx index 7c00f110..2273617c 100644 --- a/client/src/components/Journey/JourneyDetailPageSettingsDialog.tsx +++ b/client/src/components/Journey/JourneyDetailPageSettingsDialog.tsx @@ -10,6 +10,7 @@ import JourneyShareSection from './JourneyShareSection' import type { JourneyDetail } from '../../store/journeyStore' import { pickGradient } from '../../pages/journeyDetail/JourneyDetailPage.helpers' import { AddTripDialog } from './JourneyDetailPageAddTripDialog' +import { normalizeImageFile } from '../../utils/convertHeic' export function JourneySettingsDialog({ journey, onClose, onSaved, onOpenInvite, onRefresh }: { journey: JourneyDetail @@ -49,7 +50,7 @@ export function JourneySettingsDialog({ journey, onClose, onSaved, onOpenInvite, const file = e.target.files?.[0] if (!file) return const formData = new FormData() - formData.append('cover', file) + formData.append('cover', await normalizeImageFile(file)) try { await journeyApi.uploadCover(journey.id, formData) toast.success(t('journey.settings.coverUpdated')) diff --git a/client/src/components/Trips/TripFormModal.tsx b/client/src/components/Trips/TripFormModal.tsx index ef1a528a..7fe17302 100644 --- a/client/src/components/Trips/TripFormModal.tsx +++ b/client/src/components/Trips/TripFormModal.tsx @@ -8,6 +8,7 @@ import { useCanDo } from '../../store/permissionsStore' import { useToast } from '../shared/Toast' import { useTranslation } from '../../i18n' import { CustomDatePicker } from '../shared/CustomDateTimePicker' +import { normalizeImageFile } from '../../utils/convertHeic' import type { Trip } from '../../types' import type { TripCreateRequest } from '@trek/shared' @@ -141,15 +142,17 @@ export default function TripFormModal({ isOpen, onClose, onSave, trip, onCoverUp } } - const handleCoverSelect = (file) => { + const handleCoverSelect = async (file) => { if (!file) return + // HEIC/HEIF from iOS can't be rendered or stored as-is — convert to JPEG first + const normalized = await normalizeImageFile(file) if (isEditing && trip?.id) { // Existing trip: upload immediately - uploadCoverNow(file) + uploadCoverNow(normalized) } else { // New trip: stage for upload after creation - setPendingCoverFile(file) - setCoverPreview(URL.createObjectURL(file)) + setPendingCoverFile(normalized) + setCoverPreview(URL.createObjectURL(normalized)) } }