Apply full photo set behavior to all sets
This commit is contained in:
parent
dcfc04c842
commit
bc87d2ec0f
@ -1,4 +1,5 @@
|
||||
import {
|
||||
RELATED_GRID_PHOTOS_TO_SHOW,
|
||||
descriptionForPhoto,
|
||||
titleForPhoto,
|
||||
} from '@/photo';
|
||||
@ -10,12 +11,21 @@ import {
|
||||
absolutePathForPhotoImage,
|
||||
} from '@/site/paths';
|
||||
import PhotoDetailPage from '@/photo/PhotoDetailPage';
|
||||
import { getPhotoCached } from '@/photo/cache';
|
||||
import { ReactNode, cache } from 'react';
|
||||
import { FilmSimulation } from '@/simulation';
|
||||
import { getPhotosFilmSimulationDataCached } from '@/simulation/data';
|
||||
import {
|
||||
getPhotosFilmSimulationMetaCached,
|
||||
getPhotosNearIdCached,
|
||||
} from '@/photo/cache';
|
||||
|
||||
const getPhotoCachedCached = cache(getPhotoCached);
|
||||
const getPhotosNearIdCachedCached = cache((
|
||||
photoId: string,
|
||||
simulation: FilmSimulation,
|
||||
) =>
|
||||
getPhotosNearIdCached(
|
||||
photoId,
|
||||
{ simulation, limit: RELATED_GRID_PHOTOS_TO_SHOW + 2 },
|
||||
));
|
||||
|
||||
interface PhotoFilmSimulationProps {
|
||||
params: { photoId: string, simulation: FilmSimulation }
|
||||
@ -24,7 +34,7 @@ interface PhotoFilmSimulationProps {
|
||||
export async function generateMetadata({
|
||||
params: { photoId, simulation },
|
||||
}: PhotoFilmSimulationProps): Promise<Metadata> {
|
||||
const photo = await getPhotoCachedCached(photoId);
|
||||
const { photo } = await getPhotosNearIdCachedCached(photoId, simulation);
|
||||
|
||||
if (!photo) { return {}; }
|
||||
|
||||
@ -55,17 +65,24 @@ export default async function PhotoFilmSimulationPage({
|
||||
params: { photoId, simulation },
|
||||
children,
|
||||
}: PhotoFilmSimulationProps & { children: ReactNode }) {
|
||||
const photo = await getPhotoCachedCached(photoId);
|
||||
const { photo, photos, photosGrid, indexNumber } =
|
||||
await getPhotosNearIdCachedCached(photoId, simulation);
|
||||
|
||||
if (!photo) { redirect(PATH_ROOT); }
|
||||
|
||||
const [
|
||||
photos,
|
||||
{ count, dateRange },
|
||||
] = await getPhotosFilmSimulationDataCached({ simulation });
|
||||
const { count, dateRange } =
|
||||
await getPhotosFilmSimulationMetaCached(simulation);
|
||||
|
||||
return <>
|
||||
{children}
|
||||
<PhotoDetailPage {...{ photo, photos, simulation, count, dateRange }} />
|
||||
<PhotoDetailPage {...{
|
||||
photo,
|
||||
photos,
|
||||
photosGrid,
|
||||
simulation,
|
||||
indexNumber,
|
||||
count,
|
||||
dateRange,
|
||||
}} />
|
||||
</>;
|
||||
}
|
||||
|
||||
@ -14,10 +14,10 @@ import PhotoDetailPage from '@/photo/PhotoDetailPage';
|
||||
import { getPhotosNearIdCached } from '@/photo/cache';
|
||||
import { IS_PRODUCTION, STATICALLY_OPTIMIZED_PAGES } from '@/site/config';
|
||||
import { GENERATE_STATIC_PARAMS_LIMIT, getPhotoIds } from '@/photo/db';
|
||||
import { cache } from 'react';
|
||||
import { ReactNode, cache } from 'react';
|
||||
|
||||
const getPhotosNearIdCachedCached = cache((photoId: string, limit: number) =>
|
||||
getPhotosNearIdCached(photoId, { limit }));
|
||||
const getPhotosNearIdCachedCached = cache((photoId: string) =>
|
||||
getPhotosNearIdCached(photoId, { limit: RELATED_GRID_PHOTOS_TO_SHOW + 2 }));
|
||||
|
||||
export let generateStaticParams:
|
||||
(() => Promise<{ photoId: string }[]>) | undefined = undefined;
|
||||
@ -36,10 +36,7 @@ interface PhotoProps {
|
||||
export async function generateMetadata({
|
||||
params: { photoId },
|
||||
}:PhotoProps): Promise<Metadata> {
|
||||
const { photo } = await getPhotosNearIdCachedCached(
|
||||
photoId,
|
||||
RELATED_GRID_PHOTOS_TO_SHOW + 2,
|
||||
);
|
||||
const { photo } = await getPhotosNearIdCachedCached(photoId);
|
||||
|
||||
if (!photo) { return {}; }
|
||||
|
||||
@ -69,27 +66,14 @@ export async function generateMetadata({
|
||||
export default async function PhotoPage({
|
||||
params: { photoId },
|
||||
children,
|
||||
}: PhotoProps & { children: React.ReactNode }) {
|
||||
const { photos, photo } = await getPhotosNearIdCachedCached(
|
||||
photoId,
|
||||
RELATED_GRID_PHOTOS_TO_SHOW + 2,
|
||||
);
|
||||
}: PhotoProps & { children: ReactNode }) {
|
||||
const { photo, photos, photosGrid } =
|
||||
await getPhotosNearIdCachedCached(photoId);
|
||||
|
||||
if (!photo) { redirect(PATH_ROOT); }
|
||||
|
||||
const isPhotoFirst = photos.findIndex(p => p.id === photoId) === 0;
|
||||
|
||||
return <>
|
||||
{children}
|
||||
<PhotoDetailPage
|
||||
photo={photo}
|
||||
photos={photos}
|
||||
photosGrid={photos.slice(
|
||||
isPhotoFirst ? 1 : 2,
|
||||
isPhotoFirst
|
||||
? RELATED_GRID_PHOTOS_TO_SHOW + 1
|
||||
: RELATED_GRID_PHOTOS_TO_SHOW + 2,
|
||||
)}
|
||||
/>
|
||||
<PhotoDetailPage {...{ photo, photos, photosGrid }} />
|
||||
</>;
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import {
|
||||
INFINITE_SCROLL_GRID_PHOTO_INITIAL,
|
||||
RELATED_GRID_PHOTOS_TO_SHOW,
|
||||
descriptionForPhoto,
|
||||
titleForPhoto,
|
||||
} from '@/photo';
|
||||
@ -11,17 +11,33 @@ import {
|
||||
absolutePathForPhotoImage,
|
||||
} from '@/site/paths';
|
||||
import PhotoDetailPage from '@/photo/PhotoDetailPage';
|
||||
import { getPhotoCached } from '@/photo/cache';
|
||||
import { PhotoCameraProps, cameraFromPhoto } from '@/camera';
|
||||
import { getPhotosCameraDataCached } from '@/camera/data';
|
||||
import {
|
||||
getPhotosCameraMetaCached,
|
||||
getPhotosNearIdCached,
|
||||
} from '@/photo/cache';
|
||||
import {
|
||||
PhotoCameraProps,
|
||||
cameraFromPhoto,
|
||||
getCameraFromParams,
|
||||
} from '@/camera';
|
||||
import { ReactNode, cache } from 'react';
|
||||
|
||||
const getPhotoCachedCached = cache(getPhotoCached);
|
||||
const getPhotosNearIdCachedCached = cache((
|
||||
photoId: string,
|
||||
make: string,
|
||||
model: string,
|
||||
) =>
|
||||
getPhotosNearIdCached(
|
||||
photoId, {
|
||||
camera: getCameraFromParams({ make, model }),
|
||||
limit: RELATED_GRID_PHOTOS_TO_SHOW + 2,
|
||||
},
|
||||
));
|
||||
|
||||
export async function generateMetadata({
|
||||
params: { photoId, make, model },
|
||||
}: PhotoCameraProps): Promise<Metadata> {
|
||||
const photo = await getPhotoCachedCached(photoId);
|
||||
const { photo } = await getPhotosNearIdCachedCached(photoId, make, model);
|
||||
|
||||
if (!photo) { return {}; }
|
||||
|
||||
@ -56,22 +72,25 @@ export default async function PhotoCameraPage({
|
||||
params: { photoId, make, model },
|
||||
children,
|
||||
}: PhotoCameraProps & { children: ReactNode }) {
|
||||
const photo = await getPhotoCachedCached(photoId);
|
||||
const { photo, photos, photosGrid, indexNumber } =
|
||||
await getPhotosNearIdCachedCached(photoId, make, model);
|
||||
|
||||
if (!photo) { redirect(PATH_ROOT); }
|
||||
|
||||
const [
|
||||
photos,
|
||||
{ count, dateRange },
|
||||
camera,
|
||||
] = await getPhotosCameraDataCached(
|
||||
make,
|
||||
model,
|
||||
INFINITE_SCROLL_GRID_PHOTO_INITIAL,
|
||||
);
|
||||
const camera = cameraFromPhoto(photo, { make, model });
|
||||
|
||||
const { count, dateRange } = await getPhotosCameraMetaCached(camera);
|
||||
|
||||
return <>
|
||||
{children}
|
||||
<PhotoDetailPage {...{ photo, photos, camera, count, dateRange }} />
|
||||
<PhotoDetailPage {...{
|
||||
photo,
|
||||
photos,
|
||||
photosGrid,
|
||||
camera,
|
||||
indexNumber,
|
||||
count,
|
||||
dateRange,
|
||||
}} />
|
||||
</>;
|
||||
}
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import {
|
||||
RELATED_GRID_PHOTOS_TO_SHOW,
|
||||
descriptionForPhoto,
|
||||
titleForPhoto,
|
||||
} from '@/photo';
|
||||
@ -10,11 +11,17 @@ import {
|
||||
absolutePathForPhotoImage,
|
||||
} from '@/site/paths';
|
||||
import PhotoDetailPage from '@/photo/PhotoDetailPage';
|
||||
import { getPhotoCached } from '@/photo/cache';
|
||||
import { getPhotosTagDataCached } from '@/tag/data';
|
||||
import {
|
||||
getPhotosNearIdCached,
|
||||
getPhotosTagMetaCached,
|
||||
} from '@/photo/cache';
|
||||
import { ReactNode, cache } from 'react';
|
||||
|
||||
const getPhotoCachedCached = cache(getPhotoCached);
|
||||
const getPhotosNearIdCachedCached = cache((photoId: string, tag: string) =>
|
||||
getPhotosNearIdCached(
|
||||
photoId,
|
||||
{ tag, limit: RELATED_GRID_PHOTOS_TO_SHOW + 2 },
|
||||
));
|
||||
|
||||
interface PhotoTagProps {
|
||||
params: { photoId: string, tag: string }
|
||||
@ -23,7 +30,7 @@ interface PhotoTagProps {
|
||||
export async function generateMetadata({
|
||||
params: { photoId, tag },
|
||||
}: PhotoTagProps): Promise<Metadata> {
|
||||
const photo = await getPhotoCachedCached(photoId);
|
||||
const { photo } = await getPhotosNearIdCachedCached(photoId, tag);
|
||||
|
||||
if (!photo) { return {}; }
|
||||
|
||||
@ -54,17 +61,23 @@ export default async function PhotoTagPage({
|
||||
params: { photoId, tag },
|
||||
children,
|
||||
}: PhotoTagProps & { children: ReactNode }) {
|
||||
const photo = await getPhotoCachedCached(photoId);
|
||||
const { photo, photos, photosGrid, indexNumber } =
|
||||
await getPhotosNearIdCachedCached(photoId, tag);
|
||||
|
||||
if (!photo) { redirect(PATH_ROOT); }
|
||||
|
||||
const [
|
||||
photos,
|
||||
{ count, dateRange },
|
||||
] = await getPhotosTagDataCached({ tag });
|
||||
const { count, dateRange } = await getPhotosTagMetaCached(tag);
|
||||
|
||||
return <>
|
||||
{children}
|
||||
<PhotoDetailPage {...{ photo, photos, tag, count, dateRange }} />
|
||||
<PhotoDetailPage {...{
|
||||
photo,
|
||||
photos,
|
||||
photosGrid,
|
||||
tag,
|
||||
indexNumber,
|
||||
count,
|
||||
dateRange,
|
||||
}} />
|
||||
</>;
|
||||
}
|
||||
|
||||
@ -1,13 +1,24 @@
|
||||
import { descriptionForPhoto, titleForPhoto } from '@/photo';
|
||||
import {
|
||||
RELATED_GRID_PHOTOS_TO_SHOW,
|
||||
descriptionForPhoto,
|
||||
titleForPhoto,
|
||||
} from '@/photo';
|
||||
import PhotoDetailPage from '@/photo/PhotoDetailPage';
|
||||
import { getPhotoCached, getPhotosCached } from '@/photo/cache';
|
||||
import {
|
||||
getPhotosNearIdCached,
|
||||
getPhotosTagHiddenMetaCached,
|
||||
} from '@/photo/cache';
|
||||
import { PATH_ROOT, absolutePathForPhoto } from '@/site/paths';
|
||||
import { TAG_HIDDEN } from '@/tag';
|
||||
import { Metadata } from 'next';
|
||||
import { redirect } from 'next/navigation';
|
||||
import { cache } from 'react';
|
||||
|
||||
const getPhotoCachedCached = cache(getPhotoCached);
|
||||
const getPhotosNearIdCachedCached = cache((photoId: string) =>
|
||||
getPhotosNearIdCached(
|
||||
photoId,
|
||||
{ hidden: 'only' , limit: RELATED_GRID_PHOTOS_TO_SHOW + 2 },
|
||||
));
|
||||
|
||||
interface PhotoTagProps {
|
||||
params: { photoId: string }
|
||||
@ -16,7 +27,7 @@ interface PhotoTagProps {
|
||||
export async function generateMetadata({
|
||||
params: { photoId },
|
||||
}: PhotoTagProps): Promise<Metadata> {
|
||||
const photo = await getPhotoCachedCached(photoId, true);
|
||||
const { photo } = await getPhotosNearIdCachedCached(photoId);
|
||||
|
||||
if (!photo) { return {}; }
|
||||
|
||||
@ -43,14 +54,22 @@ export async function generateMetadata({
|
||||
export default async function PhotoTagHiddenPage({
|
||||
params: { photoId },
|
||||
}: PhotoTagProps) {
|
||||
const photo = await getPhotoCachedCached(photoId, true);
|
||||
const { photo, photos, photosGrid, indexNumber } =
|
||||
await getPhotosNearIdCachedCached(photoId);
|
||||
|
||||
if (!photo) { redirect(PATH_ROOT); }
|
||||
|
||||
const photos = await getPhotosCached({ hidden: 'only' });
|
||||
const count = photos.length;
|
||||
const { count, dateRange } = await getPhotosTagHiddenMetaCached();
|
||||
|
||||
return (
|
||||
<PhotoDetailPage {...{ photo, photos, count, tag: TAG_HIDDEN }} />
|
||||
<PhotoDetailPage {...{
|
||||
photo,
|
||||
photos,
|
||||
photosGrid,
|
||||
indexNumber,
|
||||
count,
|
||||
dateRange,
|
||||
tag: TAG_HIDDEN,
|
||||
}} />
|
||||
);
|
||||
}
|
||||
|
||||
@ -44,7 +44,7 @@ export const {
|
||||
},
|
||||
});
|
||||
|
||||
export const safelyRunAdminServerAction = async <T>(
|
||||
export const runAuthenticatedAdminServerAction = async <T>(
|
||||
callback: () => T,
|
||||
): Promise<T> => {
|
||||
const session = await auth();
|
||||
|
||||
@ -9,12 +9,14 @@ export default function CameraHeader({
|
||||
camera: cameraProp,
|
||||
photos,
|
||||
selectedPhoto,
|
||||
indexNumber,
|
||||
count,
|
||||
dateRange,
|
||||
}: {
|
||||
camera: Camera
|
||||
photos: Photo[]
|
||||
selectedPhoto?: Photo
|
||||
indexNumber?: number
|
||||
count?: number
|
||||
dateRange?: PhotoDateRange
|
||||
}) {
|
||||
@ -28,6 +30,7 @@ export default function CameraHeader({
|
||||
photos={photos}
|
||||
selectedPhoto={selectedPhoto}
|
||||
sharePath={pathForCameraShare(camera)}
|
||||
indexNumber={indexNumber}
|
||||
count={count}
|
||||
dateRange={dateRange}
|
||||
/>
|
||||
|
||||
@ -20,6 +20,7 @@ export default function PhotoDetailPage({
|
||||
tag,
|
||||
camera,
|
||||
simulation,
|
||||
indexNumber,
|
||||
count,
|
||||
dateRange,
|
||||
}: {
|
||||
@ -29,6 +30,7 @@ export default function PhotoDetailPage({
|
||||
tag?: string
|
||||
camera?: Camera
|
||||
simulation?: FilmSimulation
|
||||
indexNumber?: number
|
||||
count?: number
|
||||
dateRange?: PhotoDateRange
|
||||
}) {
|
||||
@ -41,6 +43,7 @@ export default function PhotoDetailPage({
|
||||
? <HiddenHeader
|
||||
photos={photos}
|
||||
selectedPhoto={photo}
|
||||
indexNumber={indexNumber}
|
||||
count={count ?? 0}
|
||||
/>
|
||||
: <TagHeader
|
||||
@ -48,6 +51,8 @@ export default function PhotoDetailPage({
|
||||
tag={tag}
|
||||
photos={photos}
|
||||
selectedPhoto={photo}
|
||||
indexNumber={indexNumber}
|
||||
count={count}
|
||||
dateRange={dateRange}
|
||||
/>}
|
||||
/>}
|
||||
@ -59,6 +64,7 @@ export default function PhotoDetailPage({
|
||||
camera={camera}
|
||||
photos={photos}
|
||||
selectedPhoto={photo}
|
||||
indexNumber={indexNumber}
|
||||
count={count}
|
||||
dateRange={dateRange}
|
||||
/>}
|
||||
@ -71,6 +77,7 @@ export default function PhotoDetailPage({
|
||||
simulation={simulation}
|
||||
photos={photos}
|
||||
selectedPhoto={photo}
|
||||
indexNumber={indexNumber}
|
||||
count={count}
|
||||
dateRange={dateRange}
|
||||
/>}
|
||||
|
||||
@ -13,6 +13,7 @@ export default function PhotoSetHeader({
|
||||
photos,
|
||||
selectedPhoto,
|
||||
sharePath,
|
||||
indexNumber,
|
||||
count,
|
||||
dateRange,
|
||||
}: {
|
||||
@ -22,6 +23,7 @@ export default function PhotoSetHeader({
|
||||
photos: Photo[]
|
||||
selectedPhoto?: Photo
|
||||
sharePath?: string
|
||||
indexNumber?: number
|
||||
count?: number
|
||||
dateRange?: PhotoDateRange
|
||||
}) {
|
||||
@ -59,7 +61,7 @@ export default function PhotoSetHeader({
|
||||
)}>
|
||||
{selectedPhotoIndex !== undefined
|
||||
// eslint-disable-next-line max-len
|
||||
? `${entityVerb ? `${entityVerb} ` : ''}${selectedPhotoIndex + 1} of ${count ?? photos.length}`
|
||||
? `${entityVerb ? `${entityVerb} ` : ''}${indexNumber || (selectedPhotoIndex + 1)} of ${count ?? photos.length}`
|
||||
: entityDescription}
|
||||
{selectedPhotoIndex === undefined && sharePath &&
|
||||
<ShareButton
|
||||
|
||||
@ -38,7 +38,7 @@ import {
|
||||
import { blurImageFromUrl, extractImageDataFromBlobPath } from './server';
|
||||
import { TAG_FAVS, isTagFavs } from '@/tag';
|
||||
import { convertPhotoToPhotoDbInsert } from '.';
|
||||
import { safelyRunAdminServerAction } from '@/auth';
|
||||
import { runAuthenticatedAdminServerAction } from '@/auth';
|
||||
import { AI_IMAGE_QUERIES, AiImageQuery } from './ai';
|
||||
import { streamOpenAiImageQuery } from '@/services/openai';
|
||||
import { BLUR_ENABLED } from '@/site/config';
|
||||
@ -46,7 +46,7 @@ import { BLUR_ENABLED } from '@/site/config';
|
||||
// Private actions
|
||||
|
||||
export const createPhotoAction = async (formData: FormData) =>
|
||||
safelyRunAdminServerAction(async () => {
|
||||
runAuthenticatedAdminServerAction(async () => {
|
||||
const photo = convertFormDataToPhotoDbInsert(formData, true);
|
||||
|
||||
const updatedUrl = await convertUploadToPhoto(photo.url);
|
||||
@ -60,7 +60,7 @@ export const createPhotoAction = async (formData: FormData) =>
|
||||
});
|
||||
|
||||
export const updatePhotoAction = async (formData: FormData) =>
|
||||
safelyRunAdminServerAction(async () => {
|
||||
runAuthenticatedAdminServerAction(async () => {
|
||||
const photo = convertFormDataToPhotoDbInsert(formData);
|
||||
|
||||
let url: string | undefined;
|
||||
@ -82,7 +82,7 @@ export const toggleFavoritePhotoAction = async (
|
||||
photoId: string,
|
||||
shouldRedirect?: boolean,
|
||||
) =>
|
||||
safelyRunAdminServerAction(async () => {
|
||||
runAuthenticatedAdminServerAction(async () => {
|
||||
const photo = await getPhoto(photoId);
|
||||
if (photo) {
|
||||
const { tags } = photo;
|
||||
@ -102,7 +102,7 @@ export const deletePhotoAction = async (
|
||||
photoUrl: string,
|
||||
shouldRedirect?: boolean,
|
||||
) =>
|
||||
safelyRunAdminServerAction(async () => {
|
||||
runAuthenticatedAdminServerAction(async () => {
|
||||
await sqlDeletePhoto(photoId).then(() => deleteStorageUrl(photoUrl));
|
||||
revalidateAllKeysAndPaths();
|
||||
if (shouldRedirect) {
|
||||
@ -111,7 +111,7 @@ export const deletePhotoAction = async (
|
||||
});
|
||||
|
||||
export const deletePhotoFormAction = async (formData: FormData) =>
|
||||
safelyRunAdminServerAction(() =>
|
||||
runAuthenticatedAdminServerAction(() =>
|
||||
deletePhotoAction(
|
||||
formData.get('id') as string,
|
||||
formData.get('url') as string,
|
||||
@ -119,7 +119,7 @@ export const deletePhotoFormAction = async (formData: FormData) =>
|
||||
);
|
||||
|
||||
export const deletePhotoTagGloballyAction = async (formData: FormData) =>
|
||||
safelyRunAdminServerAction(async () => {
|
||||
runAuthenticatedAdminServerAction(async () => {
|
||||
const tag = formData.get('tag') as string;
|
||||
|
||||
await sqlDeletePhotoTagGlobally(tag);
|
||||
@ -129,7 +129,7 @@ export const deletePhotoTagGloballyAction = async (formData: FormData) =>
|
||||
});
|
||||
|
||||
export const renamePhotoTagGloballyAction = async (formData: FormData) =>
|
||||
safelyRunAdminServerAction(async () => {
|
||||
runAuthenticatedAdminServerAction(async () => {
|
||||
const tag = formData.get('tag') as string;
|
||||
const updatedTag = formData.get('updatedTag') as string;
|
||||
|
||||
@ -142,7 +142,7 @@ export const renamePhotoTagGloballyAction = async (formData: FormData) =>
|
||||
});
|
||||
|
||||
export const deleteBlobPhotoAction = async (formData: FormData) =>
|
||||
safelyRunAdminServerAction(async () => {
|
||||
runAuthenticatedAdminServerAction(async () => {
|
||||
await deleteStorageUrl(formData.get('url') as string);
|
||||
|
||||
revalidateAdminPaths();
|
||||
@ -157,7 +157,7 @@ export const deleteBlobPhotoAction = async (formData: FormData) =>
|
||||
export const getExifDataAction = async (
|
||||
photoFormPrevious: Partial<PhotoFormData>,
|
||||
): Promise<Partial<PhotoFormData>> =>
|
||||
safelyRunAdminServerAction(async () => {
|
||||
runAuthenticatedAdminServerAction(async () => {
|
||||
const { url } = photoFormPrevious;
|
||||
if (url) {
|
||||
const { photoFormExif } = await extractImageDataFromBlobPath(url);
|
||||
@ -171,7 +171,7 @@ export const getExifDataAction = async (
|
||||
// Accessed from admin photo table
|
||||
// will update blur data
|
||||
export const syncPhotoExifDataAction = async (formData: FormData) =>
|
||||
safelyRunAdminServerAction(async () => {
|
||||
runAuthenticatedAdminServerAction(async () => {
|
||||
const photoId = formData.get('id') as string;
|
||||
if (photoId) {
|
||||
const photo = await getPhoto(photoId);
|
||||
@ -193,32 +193,32 @@ export const syncPhotoExifDataAction = async (formData: FormData) =>
|
||||
});
|
||||
|
||||
export const syncCacheAction = async () =>
|
||||
safelyRunAdminServerAction(revalidateAllKeysAndPaths);
|
||||
runAuthenticatedAdminServerAction(revalidateAllKeysAndPaths);
|
||||
|
||||
export const streamAiImageQueryAction = async (
|
||||
imageBase64: string,
|
||||
query: AiImageQuery,
|
||||
) =>
|
||||
safelyRunAdminServerAction(() =>
|
||||
runAuthenticatedAdminServerAction(() =>
|
||||
streamOpenAiImageQuery(imageBase64, AI_IMAGE_QUERIES[query]));
|
||||
|
||||
export const getImageBlurAction = async (url: string) =>
|
||||
safelyRunAdminServerAction(() => blurImageFromUrl(url));
|
||||
runAuthenticatedAdminServerAction(() => blurImageFromUrl(url));
|
||||
|
||||
export const getPhotosTagHiddenMetaCachedAction = async () =>
|
||||
safelyRunAdminServerAction(getPhotosTagHiddenMetaCached);
|
||||
runAuthenticatedAdminServerAction(getPhotosTagHiddenMetaCached);
|
||||
|
||||
// Public/Private actions
|
||||
|
||||
export const getPhotosAction = async (options: GetPhotosOptions) =>
|
||||
(options.hidden === 'include' || options.hidden === 'only')
|
||||
? safelyRunAdminServerAction(() =>
|
||||
? runAuthenticatedAdminServerAction(() =>
|
||||
getPhotos(options))
|
||||
: getPhotos(options);
|
||||
|
||||
export const getPhotosCachedAction = async (options: GetPhotosOptions) =>
|
||||
(options.hidden === 'include' || options.hidden === 'only')
|
||||
? safelyRunAdminServerAction(() =>
|
||||
? runAuthenticatedAdminServerAction(() =>
|
||||
getPhotosCached (options))
|
||||
: getPhotosCached(options);
|
||||
|
||||
|
||||
@ -141,11 +141,23 @@ export const getPhotosNearIdCached = (
|
||||
...args: Parameters<typeof getPhotosNearId>
|
||||
) => unstable_cache(
|
||||
getPhotosNearId,
|
||||
[KEY_PHOTOS],
|
||||
)(...args).then(({ photos, photo }) => ({
|
||||
photos: parseCachedPhotosDates(photos),
|
||||
photo: photo ? parseCachedPhotoDates(photo) : undefined,
|
||||
}));
|
||||
[KEY_PHOTOS, ...getPhotosCacheKeys(args[1])],
|
||||
)(...args).then(({ photos, indexNumber }) => {
|
||||
const [photoId, { limit }] = args;
|
||||
const photo = photos.find(({ id }) => id === photoId);
|
||||
const isPhotoFirst = photos.findIndex(p => p.id === photoId) === 0;
|
||||
return {
|
||||
photo: photo ? parseCachedPhotoDates(photo) : undefined,
|
||||
photos: parseCachedPhotosDates(photos),
|
||||
...limit && {
|
||||
photosGrid: photos.slice(
|
||||
isPhotoFirst ? 1 : 2,
|
||||
isPhotoFirst ? limit - 1 : limit,
|
||||
),
|
||||
},
|
||||
indexNumber,
|
||||
};
|
||||
});
|
||||
|
||||
export const getPhotosDateRangeCached =
|
||||
unstable_cache(
|
||||
|
||||
@ -488,10 +488,11 @@ export const getPhotosNearId = async (
|
||||
);
|
||||
}, `getPhotosNearId: ${photoId}`)
|
||||
.then(({ rows }) => {
|
||||
const photos = rows.map(parsePhotoFromDb);
|
||||
const photo = rows.find(({ id }) => id === photoId);
|
||||
const indexNumber = photo ? parseInt(photo.row_number) : undefined;
|
||||
return {
|
||||
photos,
|
||||
photo: photos.find(photo => photo.id === photoId),
|
||||
photos: rows.map(parsePhotoFromDb),
|
||||
indexNumber,
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
@ -6,7 +6,7 @@ import { createOpenAI } from '@ai-sdk/openai';
|
||||
import { kv } from '@vercel/kv';
|
||||
import { Ratelimit } from '@upstash/ratelimit';
|
||||
import { AI_TEXT_GENERATION_ENABLED, HAS_VERCEL_KV } from '@/site/config';
|
||||
import { safelyRunAdminServerAction } from '@/auth';
|
||||
import { runAuthenticatedAdminServerAction } from '@/auth';
|
||||
import { removeBase64Prefix } from '@/utility/image';
|
||||
|
||||
const RATE_LIMIT_IDENTIFIER = 'openai-image-query';
|
||||
@ -28,7 +28,7 @@ export const streamOpenAiImageQuery = async (
|
||||
imageBase64: string,
|
||||
query: string,
|
||||
) => {
|
||||
return safelyRunAdminServerAction(async () => {
|
||||
return runAuthenticatedAdminServerAction(async () => {
|
||||
if (ratelimit) {
|
||||
let success = false;
|
||||
try {
|
||||
|
||||
@ -9,12 +9,14 @@ export default function FilmSimulationHeader({
|
||||
simulation,
|
||||
photos,
|
||||
selectedPhoto,
|
||||
indexNumber,
|
||||
count,
|
||||
dateRange,
|
||||
}: {
|
||||
simulation: FilmSimulation
|
||||
photos: Photo[]
|
||||
selectedPhoto?: Photo
|
||||
indexNumber?: number
|
||||
count?: number
|
||||
dateRange?: PhotoDateRange
|
||||
}) {
|
||||
@ -27,6 +29,7 @@ export default function FilmSimulationHeader({
|
||||
photos={photos}
|
||||
selectedPhoto={selectedPhoto}
|
||||
sharePath={pathForFilmSimulationShare(simulation)}
|
||||
indexNumber={indexNumber}
|
||||
count={count}
|
||||
dateRange={dateRange}
|
||||
/>
|
||||
|
||||
@ -5,10 +5,12 @@ import HiddenTag from './HiddenTag';
|
||||
export default function HiddenHeader({
|
||||
photos,
|
||||
selectedPhoto,
|
||||
indexNumber,
|
||||
count,
|
||||
}: {
|
||||
photos: Photo[]
|
||||
selectedPhoto?: Photo
|
||||
indexNumber?: number
|
||||
count: number
|
||||
}) {
|
||||
return (
|
||||
@ -18,6 +20,8 @@ export default function HiddenHeader({
|
||||
entityDescription={photoQuantityText(count, false)}
|
||||
photos={photos}
|
||||
selectedPhoto={selectedPhoto}
|
||||
indexNumber={indexNumber}
|
||||
count={count}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@ -9,12 +9,14 @@ export default function TagHeader({
|
||||
tag,
|
||||
photos,
|
||||
selectedPhoto,
|
||||
indexNumber,
|
||||
count,
|
||||
dateRange,
|
||||
}: {
|
||||
tag: string
|
||||
photos: Photo[]
|
||||
selectedPhoto?: Photo
|
||||
indexNumber?: number
|
||||
count?: number
|
||||
dateRange?: PhotoDateRange
|
||||
}) {
|
||||
@ -28,6 +30,7 @@ export default function TagHeader({
|
||||
photos={photos}
|
||||
selectedPhoto={selectedPhoto}
|
||||
sharePath={pathForTagShare(tag)}
|
||||
indexNumber={indexNumber}
|
||||
count={count}
|
||||
dateRange={dateRange}
|
||||
/>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user