Add server action to rename tag globally
This commit is contained in:
parent
bdad8507c5
commit
d2d5a8875c
@ -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 />
|
||||||
|
|||||||
@ -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);
|
||||||
|
|
||||||
|
|||||||
@ -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)
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
|||||||
@ -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>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -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(' ');
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user