diff --git a/src/photo/PhotoForm.tsx b/src/photo/PhotoForm.tsx index e02dcde9..b62d1c41 100644 --- a/src/photo/PhotoForm.tsx +++ b/src/photo/PhotoForm.tsx @@ -1,6 +1,6 @@ 'use client'; -import { useCallback, useState } from 'react'; +import { useCallback, useEffect, useState } from 'react'; import { FORM_METADATA_ENTRIES, PhotoFormData, @@ -13,6 +13,10 @@ import Link from 'next/link'; import { cc } from '@/utility/css'; import CanvasBlurCapture from '@/components/CanvasBlurCapture'; import { PATH_ADMIN_PHOTOS } from '@/site/paths'; +import { + generateLocalNaivePostgresString, + generateLocalPostgresString, +} from '@/utility/date'; const THUMBNAIL_WIDTH = 300; const THUMBNAIL_HEIGHT = 200; @@ -29,6 +33,22 @@ export default function PhotoForm({ const [formData, setFormData] = useState>(initialPhotoForm); + // Generate local date strings when + // none can be harvested from EXIF + useEffect(() => { + if (!formData.takenAt || !formData.takenAtNaive) { + setFormData(data => ({ + ...data, + ...!formData.takenAt && { + takenAt: generateLocalPostgresString(), + }, + ...!formData.takenAtNaive && { + takenAtNaive: generateLocalNaivePostgresString(), + }, + })); + } + }, [formData.takenAt, formData.takenAtNaive]); + const url = formData.url ?? ''; const updateBlurData = useCallback((blurData: string) => { diff --git a/src/photo/PhotoLarge.tsx b/src/photo/PhotoLarge.tsx index bede78a7..bb923ba5 100644 --- a/src/photo/PhotoLarge.tsx +++ b/src/photo/PhotoLarge.tsx @@ -1,4 +1,4 @@ -import { Photo, titleForPhoto } from '.'; +import { Photo, photoHasCameraData, photoHasExifData, titleForPhoto } from '.'; import SiteGrid from '@/components/SiteGrid'; import ImageLarge from '@/components/ImageLarge'; import { cc } from '@/utility/css'; @@ -72,7 +72,7 @@ export default function PhotoLarge({ {tagsToShow.length > 0 && } - {showCamera && + {showCamera && photoHasCameraData(photo) && } )} {renderMiniGrid(<> -
    -
  • - {photo.focalLengthFormatted} - {' '} - - {photo.focalLengthIn35MmFormatFormatted} - -
  • -
  • {photo.fNumberFormatted}
  • -
  • {photo.isoFormatted}
  • -
  • {photo.exposureTimeFormatted}
  • -
  • {photo.exposureCompensationFormatted ?? '—'}
  • -
+ {photoHasExifData(photo) && +
    +
  • + {photo.focalLengthFormatted} + {photo.focalLengthIn35MmFormatFormatted && + <> + {' '} + + {photo.focalLengthIn35MmFormatFormatted} + + } +
  • +
  • {photo.fNumberFormatted}
  • +
  • {photo.isoFormatted}
  • +
  • {photo.exposureTimeFormatted}
  • +
  • {photo.exposureCompensationFormatted ?? '—'}
  • +
}
{ const photoForm = Object.fromEntries(formData) as PhotoFormData; - // Remove Server Action ID + // Parse FormData: + // - remove server action ID + // - remove empty strings Object.keys(photoForm).forEach(key => { - if (key.startsWith('$ACTION_ID_')) { + if ( + key.startsWith('$ACTION_ID_') || + (photoForm as any)[key] === '' + ) { delete (photoForm as any)[key]; } }); diff --git a/src/photo/index.ts b/src/photo/index.ts index bf1b86f1..3d44a2c3 100644 --- a/src/photo/index.ts +++ b/src/photo/index.ts @@ -201,3 +201,15 @@ export const dateRangeForPhotos = ( : `${start}–${end}`; return { start, end, description }; }; + +export const photoHasCameraData = (photo: Photo) => + photo.make || + photo.model; + +export const photoHasExifData = (photo: Photo) => + photo.focalLength || + photo.focalLengthIn35MmFormat || + photo.fNumberFormatted || + photo.isoFormatted || + photo.exposureTimeFormatted || + photo.exposureCompensationFormatted; diff --git a/src/utility/date.ts b/src/utility/date.ts index 90ccdb8c..67b1a165 100644 --- a/src/utility/date.ts +++ b/src/utility/date.ts @@ -16,24 +16,34 @@ export const formatDateForPostgres = (date: Date) => '$1-$2-$3 $4', ); -const createNaiveDateWithOffset = ( - dateTimestamp = 0, - offset = '+00:00', -) => { - const date = new Date(dateTimestamp * 1000); +const dateFromTimestamp = (timestamp?: number) => + timestamp !== undefined ? new Date(timestamp * 1000) : new Date(); + +const createNaiveDateWithOffset = (timestamp?: number, offset = '+00:00') => { + const date = dateFromTimestamp(timestamp); const dateString = `${date.toISOString()}`.replace(/\.[\d]+Z/, offset); return parseISO(dateString); }; -export const convertTimestampWithOffsetToPostgresString = ( - dateTimestamp?: number, - offset?: string, -) => formatDateForPostgres( - createNaiveDateWithOffset(dateTimestamp, offset) -); +// Run on the server, when there are date/timestamp/offset inputs -export const convertTimestampToNaivePostgresString = (timestamp = 0) => - new Date(timestamp * 1000).toISOString().replace( - /(\d{4}-\d{2}-\d{2})T(\d{2}:\d{2}:\d{2})(.[\d]+Z)*/, - '$1 $2', - ); +export const convertTimestampWithOffsetToPostgresString = ( + timestamp?: number, + offset?: string, +) => + formatDateForPostgres(createNaiveDateWithOffset(timestamp, offset)); + +export const convertTimestampToNaivePostgresString = (timestamp?: number) => + dateFromTimestamp(timestamp) + .toISOString().replace( + /(\d{4}-\d{2}-\d{2})T(\d{2}:\d{2}:\d{2})(.[\d]+Z)*/, + '$1 $2', + ); + +// Run in the browser, to get generate local date time strings + +export const generateLocalPostgresString = () => + formatDateForPostgres(new Date()); + +export const generateLocalNaivePostgresString = () => + format(new Date(), DATE_STRING_FORMAT_POSTGRES); diff --git a/src/utility/exif.ts b/src/utility/exif.ts index ff19ecde..0e6f2f8e 100644 --- a/src/utility/exif.ts +++ b/src/utility/exif.ts @@ -10,16 +10,16 @@ export const getOffsetFromExif = (data: ExifData) => ) as string | undefined; export const formatFocalLength = (focalLength?: number) => - focalLength !== undefined ? `${focalLength}mm` : undefined; + focalLength ? `${focalLength}mm` : undefined; export const formatAperture = (aperture?: number) => - aperture !== undefined ? `ƒ/${aperture}` : undefined; + aperture ? `ƒ/${aperture}` : undefined; export const formatIso = (iso?: number) => - iso !== undefined ? `ISO ${iso}` : undefined; + iso ? `ISO ${iso}` : undefined; export const formatExposureTime = (exposureTime?: number) => - exposureTime !== undefined + exposureTime ? `Shutter 1/${Math.floor(1 / (exposureTime ?? 1))}` : undefined; @@ -37,7 +37,7 @@ const fractionForDecimal = (decimal: number, fractionCharacter?: boolean) => { export const formatExposureCompensation = (exposureCompensation?: number) => { if ( - exposureCompensation !== undefined && + exposureCompensation && Math.abs(exposureCompensation) >= 0.33 ) { const decimal = exposureCompensation % 1;