feat: loading toasts for all photo actions
Add loading→success/error toast transition to every bulk operation (archive, restore, delete, approve, add-to-heap, metadata patch). Also wires gridKeyNav + CauseGroupCard into the bulkAction store so keyboard-triggered actions show the same per-tile pending/done/error feedback as BulkActionBar buttons.
This commit is contained in:
@@ -66,21 +66,20 @@ export function cachedPhoto(uid: string): PpPhoto | undefined {
|
||||
*/
|
||||
export async function dismissPhotos(uids: string[]): Promise<void> {
|
||||
if (uids.length === 0) return;
|
||||
const tid = toast.loading(`Dismissing ${uids.length}…`);
|
||||
const { updated, errors } = await batchEdit(uids, (id) => approvePhoto(id));
|
||||
// Advance focus past the dismissed set before the timeline refetches
|
||||
// so the cursor doesn't snap back to photo[0]; clear the now-stale
|
||||
// selection ring for the same reason.
|
||||
focusAfter(uids);
|
||||
clearSelection();
|
||||
invalidatePhotos(uids);
|
||||
void queryClient.invalidateQueries({ queryKey: ['review-groups'] });
|
||||
if (errors.length) {
|
||||
toast.error(`Dismissed ${updated.length}; ${errors.length} failed`, {
|
||||
id: tid,
|
||||
description: errors[0].message
|
||||
});
|
||||
return;
|
||||
}
|
||||
toast.success(`Dismissed ${uids.length}`);
|
||||
toast.success(`Dismissed ${uids.length}`, { id: tid });
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -93,6 +92,7 @@ export async function dismissPhotos(uids: string[]): Promise<void> {
|
||||
*/
|
||||
export async function acceptDateAndKeep(uids: string[]): Promise<void> {
|
||||
if (uids.length === 0) return;
|
||||
const tid = toast.loading(`Updating & keeping ${uids.length}…`);
|
||||
const { updated, errors } = await batchEdit(uids, async (id) => {
|
||||
const p = cachedPhoto(id);
|
||||
if (p) {
|
||||
@@ -113,11 +113,12 @@ export async function acceptDateAndKeep(uids: string[]): Promise<void> {
|
||||
void queryClient.invalidateQueries({ queryKey: ['review-groups'] });
|
||||
if (errors.length) {
|
||||
toast.error(`Kept ${updated.length}; ${errors.length} failed`, {
|
||||
id: tid,
|
||||
description: errors[0].message
|
||||
});
|
||||
return;
|
||||
}
|
||||
toast.success(`Kept ${uids.length}`);
|
||||
toast.success(`Kept ${uids.length}`, { id: tid });
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -125,10 +126,11 @@ export async function acceptDateAndKeep(uids: string[]): Promise<void> {
|
||||
*/
|
||||
export async function archivePhotos(uids: string[]): Promise<void> {
|
||||
if (uids.length === 0) return;
|
||||
const tid = toast.loading(`Archiving ${uids.length}…`);
|
||||
try {
|
||||
await batchArchive(uids);
|
||||
} catch (err) {
|
||||
toast.error(err instanceof Error ? err.message : 'Archive failed');
|
||||
toast.error(err instanceof Error ? err.message : 'Archive failed', { id: tid });
|
||||
return;
|
||||
}
|
||||
pushUndo(`Archived ${uids.length}`, async () => {
|
||||
@@ -140,5 +142,5 @@ export async function archivePhotos(uids: string[]): Promise<void> {
|
||||
clearSelection();
|
||||
invalidatePhotos(uids);
|
||||
void queryClient.invalidateQueries({ queryKey: ['review-groups'] });
|
||||
toast.success(`Archived ${uids.length}`);
|
||||
toast.success(`Archived ${uids.length}`, { id: tid });
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user