Add server action to rename tag globally

This commit is contained in:
Sam Becker 2023-10-06 08:54:23 -05:00
parent bdad8507c5
commit d2d5a8875c
5 changed files with 31 additions and 6 deletions

View File

@ -6,6 +6,8 @@ import { Fragment } from 'react';
import DeleteButton from '@/admin/DeleteButton'; import DeleteButton from '@/admin/DeleteButton';
import { photoQuantityText } from '@/photo'; import { photoQuantityText } from '@/photo';
import { getUniqueTagsWithCountCached } from '@/cache'; import { getUniqueTagsWithCountCached } from '@/cache';
import PhotoTag from '@/tag/PhotoTag';
import { formatTag } from '@/tag';
export const runtime = 'edge'; export const runtime = 'edge';
@ -21,9 +23,9 @@ export default async function AdminPhotosPage() {
{tags.map(({ tag, count }) => {tags.map(({ tag, count }) =>
<Fragment key={tag}> <Fragment key={tag}>
<div className="pr-2"> <div className="pr-2">
{tag} <PhotoTag {...{ tag }} />
</div> </div>
<div className="text-dim"> <div className="text-dim uppercase">
{photoQuantityText(count, false)} {photoQuantityText(count, false)}
</div> </div>
<div /> <div />
@ -31,7 +33,7 @@ export default async function AdminPhotosPage() {
action={deletePhotoTagGloballyAction} action={deletePhotoTagGloballyAction}
confirmText={ confirmText={
// eslint-disable-next-line max-len // eslint-disable-next-line max-len
`Are you sure you want to remove "${tag}?" from ${photoQuantityText(count, false).toLowerCase()}?`} `Are you sure you want to remove "${formatTag(tag)}?" from ${photoQuantityText(count, false).toLowerCase()}?`}
> >
<input type="hidden" name="tag" value={tag} /> <input type="hidden" name="tag" value={tag} />
<DeleteButton /> <DeleteButton />

View File

@ -5,6 +5,7 @@ import {
sqlInsertPhoto, sqlInsertPhoto,
sqlDeletePhotoTagGlobally, sqlDeletePhotoTagGlobally,
sqlUpdatePhoto, sqlUpdatePhoto,
sqlRenamePhotoTagGlobally,
} from '@/services/postgres'; } from '@/services/postgres';
import { convertFormDataToPhoto } from './form'; import { convertFormDataToPhoto } from './form';
import { redirect } from 'next/navigation'; import { redirect } from 'next/navigation';
@ -71,6 +72,17 @@ export async function deletePhotoTagGloballyAction(formData: FormData) {
revalidatePhotosKey(); revalidatePhotosKey();
} }
export async function renamePhotoTagGloballyAction(formData: FormData) {
const tag = formData.get('tag') as string;
const newTag = formData.get('newTag') as string;
if (tag && newTag && tag !== newTag) {
await sqlRenamePhotoTagGlobally(tag, newTag);
revalidatePhotosKey();
}
}
export async function deleteBlobPhotoAction(formData: FormData) { export async function deleteBlobPhotoAction(formData: FormData) {
await deleteBlobPhoto(formData.get('url') as string); await deleteBlobPhoto(formData.get('url') as string);

View File

@ -135,7 +135,14 @@ export const sqlUpdatePhoto = (photo: PhotoDbInsert) =>
export const sqlDeletePhotoTagGlobally = (tag: string) => export const sqlDeletePhotoTagGlobally = (tag: string) =>
sql` sql`
UPDATE photos UPDATE photos
SET tags=array_remove(tags, ${tag}) SET tags=ARRAY_REMOVE(tags, ${tag})
WHERE ${tag}=ANY(tags)
`;
export const sqlRenamePhotoTagGlobally = (tag: string, newTag: string) =>
sql`
UPDATE photos
SET tags=ARRAY_REPLACE(tags, ${tag}, ${newTag})
WHERE ${tag}=ANY(tags) WHERE ${tag}=ANY(tags)
`; `;

View File

@ -2,6 +2,7 @@ import Link from 'next/link';
import { pathForTag } from '@/site/paths'; import { pathForTag } from '@/site/paths';
import { FaTag } from 'react-icons/fa'; import { FaTag } from 'react-icons/fa';
import { cc } from '@/utility/css'; import { cc } from '@/utility/css';
import { formatTag } from '.';
export default function PhotoTag({ export default function PhotoTag({
tag, tag,
@ -27,7 +28,7 @@ export default function PhotoTag({
)} )}
/>} />}
<span className="uppercase"> <span className="uppercase">
{tag.replaceAll('-', ' ')} {formatTag(tag)}
</span> </span>
</Link> </Link>
); );

View File

@ -7,12 +7,15 @@ import {
import { absolutePathForTag, absolutePathForTagImage } from '@/site/paths'; import { absolutePathForTag, absolutePathForTagImage } from '@/site/paths';
import { capitalizeWords } from '@/utility/string'; import { capitalizeWords } from '@/utility/string';
export const formatTag = (tag: string) =>
capitalizeWords(tag.replaceAll('-', ' '));
export const titleForTag = ( export const titleForTag = (
tag: string, tag: string,
photos:Photo[], photos:Photo[],
explicitCount?: number, explicitCount?: number,
) => [ ) => [
capitalizeWords(tag.replaceAll('-', ' ')), formatTag(tag),
photoQuantityText(explicitCount ?? photos.length), photoQuantityText(explicitCount ?? photos.length),
].join(' '); ].join(' ');