import type { ComposerImage } from '#/lib/media/composer-image';
import * as Toast from '#/components/Toast';
import { m } from '#/paraglide/messages';
import { MAX_GALLERY_IMAGES, type PostAction } from './state/composer';
/** Clamps a batch of incoming images against the remaining gallery slots. Never mutates its inputs. */
export function applyGalleryCap(
currentCount: number,
incoming: ComposerImage[],
):
| { status: 'full' }
| { status: 'partial'; accepted: ComposerImage[]; dropped: number }
| { status: 'ok'; accepted: ComposerImage[] } {
const remaining = MAX_GALLERY_IMAGES - currentCount;
if (remaining <= 0) {
return { status: 'full' };
}
if (incoming.length > remaining) {
return {
status: 'partial',
accepted: incoming.slice(0, remaining),
dropped: incoming.length - remaining,
};
}
return { status: 'ok', accepted: incoming };
}
/**
* returns an adder that applies the gallery cap, toasting when the batch is fully or partially rejected.
*
* @param currentCount the number of images already in the gallery
* @param dispatchPostAction dispatches accepted images to the composer
* @returns an image-adder callback constrained by the remaining gallery capacity
*/
export function createAddImagesWithCap(
currentCount: number,
dispatchPostAction: (action: PostAction) => void,
) {
return (next: ComposerImage[]) => {
const result = applyGalleryCap(currentCount, next);
if (result.status === 'full') {
Toast.show(m['view.composer.gallery.error.maxAdd']({ max: MAX_GALLERY_IMAGES }), { type: 'warning' });
return;
}
if (result.status === 'partial') {
Toast.show(
m['view.composer.gallery.error.limit']({
accepted: result.accepted.length,
count: next.length,
total: next.length,
max: MAX_GALLERY_IMAGES,
}),
{ type: 'warning' },
);
}
dispatchPostAction({
type: 'embedAddImages',
images: result.accepted,
});
};
}