diff --git a/src/app/(auth-state)/admin/uploads/blob/route.tsx b/src/app/(auth-state)/admin/uploads/blob/route.tsx index cbd33089..74cabd12 100644 --- a/src/app/(auth-state)/admin/uploads/blob/route.tsx +++ b/src/app/(auth-state)/admin/uploads/blob/route.tsx @@ -1,4 +1,4 @@ -import { revalidatePhotosAndBlobKeys } from '@/cache'; +import { revalidatePhotosAndBlobKeys, revalidateAdminPaths } from '@/cache'; import { ACCEPTED_PHOTO_FILE_TYPES } from '@/photo'; import { isUploadPathnameValid } from '@/services/blob'; import { handleUpload, type HandleUploadBody } from '@vercel/blob/client'; @@ -26,12 +26,13 @@ export async function POST(request: Request): Promise { // This argument is required, but doesn't seem to fire onUploadCompleted: async () => { revalidatePhotosAndBlobKeys(); + revalidateAdminPaths(); }, }); revalidatePhotosAndBlobKeys(); + revalidateAdminPaths(); return NextResponse.json(jsonResponse); } catch (error) { - revalidatePhotosAndBlobKeys(); return NextResponse.json( { error: (error as Error).message }, { status: 400 }, diff --git a/src/cache/index.ts b/src/cache/index.ts index a13094b9..1eb3644b 100644 --- a/src/cache/index.ts +++ b/src/cache/index.ts @@ -1,4 +1,4 @@ -import { revalidateTag, unstable_cache } from 'next/cache'; +import { revalidatePath, revalidateTag, unstable_cache } from 'next/cache'; import { GetPhotosOptions, getPhoto, @@ -17,6 +17,7 @@ import { parseCachedPhotosDates, parseCachedPhotoDates } from '@/photo'; import { getBlobPhotoUrls, getBlobUploadUrls } from '@/services/blob'; import { AuthSession } from 'next-auth'; import { Camera, createCameraKey } from '@/camera'; +import { PATHS_ADMIN, PATHS_TO_CACHE } from '@/site/paths'; const KEY_PHOTOS = 'photos'; const KEY_PHOTOS_COUNT = `${KEY_PHOTOS}-count`; @@ -95,15 +96,23 @@ export const revalidateBlobKey = () => revalidateTag(KEY_BLOB); export const revalidatePhotosAndBlobKeys = () => { - revalidateTag(KEY_PHOTOS); - revalidateTag(KEY_BLOB); + revalidatePhotosKey(); + revalidateBlobKey(); }; export const revalidateAllKeys = () => { - revalidatePhotosKey(); + revalidatePhotosAndBlobKeys(); revalidateTagsKey(); revalidateCamerasKey(); - revalidateBlobKey(); +}; + +export const revalidateAllKeysAndPaths = () => { + revalidateAllKeys(); + PATHS_TO_CACHE.forEach(path => revalidatePath(path)); +}; + +export const revalidateAdminPaths = () => { + PATHS_ADMIN.forEach(path => revalidatePath(path)); }; export const getPhotosCached: typeof getPhotos = (...args) => diff --git a/src/photo/actions.ts b/src/photo/actions.ts index 2f145266..811be878 100644 --- a/src/photo/actions.ts +++ b/src/photo/actions.ts @@ -14,7 +14,8 @@ import { deleteBlobPhoto, } from '@/services/blob'; import { - revalidateAllKeys, + revalidateAdminPaths, + revalidateAllKeysAndPaths, revalidateBlobKey, revalidatePhotosKey, } from '@/cache'; @@ -29,7 +30,7 @@ export async function createPhotoAction(formData: FormData) { await sqlInsertPhoto(photo); - revalidateAllKeys(); + revalidateAllKeysAndPaths(); redirect(PATH_ADMIN_PHOTOS); } @@ -51,6 +52,7 @@ export async function deletePhotoAction(formData: FormData) { ]); revalidatePhotosKey(); + revalidateAdminPaths(); }; export async function deletePhotoTagGloballyAction(formData: FormData) { @@ -59,6 +61,7 @@ export async function deletePhotoTagGloballyAction(formData: FormData) { await sqlDeletePhotoTagGlobally(tag); revalidatePhotosKey(); + revalidateAdminPaths(); } export async function renamePhotoTagGloballyAction(formData: FormData) { @@ -76,6 +79,7 @@ export async function deleteBlobPhotoAction(formData: FormData) { await deleteBlobPhoto(formData.get('url') as string); revalidateBlobKey(); + revalidateAdminPaths(); if (formData.get('redirectToPhotos') === 'true') { redirect(PATH_ADMIN_PHOTOS); @@ -83,5 +87,5 @@ export async function deleteBlobPhotoAction(formData: FormData) { }; export async function syncCacheAction() { - revalidateAllKeys(); + revalidateAllKeysAndPaths(); } diff --git a/src/site/paths.ts b/src/site/paths.ts index d355ce9e..8528c4ce 100644 --- a/src/site/paths.ts +++ b/src/site/paths.ts @@ -6,11 +6,6 @@ import { getCameraFromKey, } from '@/camera'; -// Prefixes -export const PREFIX_PHOTO = '/p'; -export const PREFIX_TAG = '/tag'; -export const PREFIX_CAMERA = '/shot-on'; - // Core paths export const PATH_ROOT = '/'; export const PATH_GRID = '/grid'; @@ -18,6 +13,16 @@ export const PATH_ADMIN = '/admin'; export const PATH_SIGN_IN = '/sign-in'; export const PATH_OG = '/og'; +// Path prefixes +export const PREFIX_PHOTO = '/p'; +export const PREFIX_TAG = '/tag'; +export const PREFIX_CAMERA = '/shot-on'; + +// Dynamic paths +const PATH_PHOTO_DYNAMIC = `${PREFIX_PHOTO}/:photoId`; +const PATH_TAG_DYNAMIC = `${PREFIX_TAG}/:tag`; +const PATH_CAMERA_DYNAMIC = `${PREFIX_CAMERA}/:camera`; + // Admin paths export const PATH_ADMIN_PHOTOS = `${PATH_ADMIN}/photos`; export const PATH_ADMIN_UPLOADS = `${PATH_ADMIN}/uploads`; @@ -31,6 +36,26 @@ const SHARE = 'share'; const NEXT = 'next'; const EDIT = 'edit'; +export const PATHS_ADMIN = [ + PATH_ADMIN, + PATH_ADMIN_PHOTOS, + PATH_ADMIN_UPLOADS, + PATH_ADMIN_TAGS, + PATH_ADMIN_UPLOAD, + PATH_ADMIN_UPLOAD_BLOB, + PATH_ADMIN_CONFIGURATION, +]; + +export const PATHS_TO_CACHE = [ + PATH_ROOT, + PATH_GRID, + PATH_OG, + PATH_PHOTO_DYNAMIC, + PATH_TAG_DYNAMIC, + PATH_CAMERA_DYNAMIC, + ...PATHS_ADMIN, +]; + // Absolute paths export const ABSOLUTE_PATH_FOR_HOME_IMAGE = `${BASE_URL}/home-image`;