mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-19 05:26:47 +00:00
fix(dashboard): a refused archive, delete or copy says why instead of only that it failed
A member without the right to archive a trip clicked Archive and read "Failed to archive trip", while the server had answered why. The archive, restore, delete and copy toasts now show the server's reason, as creating and editing a trip already did; a failure without one keeps the old line. The buttons stay where they are. Refs #2604
This commit is contained in:
@@ -207,7 +207,7 @@ describe('useDashboard', () => {
|
||||
});
|
||||
|
||||
it('FE-HOOK-DASH-014: a failing delete toasts and keeps the trip', async () => {
|
||||
server.use(http.delete('/api/trips/:id', () => HttpResponse.json({ error: 'nope' }, { status: 500 })));
|
||||
server.use(http.delete('/api/trips/:id', () => HttpResponse.json({}, { status: 500 })));
|
||||
const { result } = await mountLoaded();
|
||||
|
||||
act(() => { result.current.setDeleteTrip(PARIS); });
|
||||
@@ -230,7 +230,7 @@ describe('useDashboard', () => {
|
||||
});
|
||||
|
||||
it('FE-HOOK-DASH-016: a failing archive only toasts', async () => {
|
||||
server.use(http.put('/api/trips/:id', () => HttpResponse.json({ error: 'nope' }, { status: 500 })));
|
||||
server.use(http.put('/api/trips/:id', () => HttpResponse.json({}, { status: 500 })));
|
||||
const { result } = await mountLoaded();
|
||||
|
||||
await act(async () => { await result.current.handleArchive(101); });
|
||||
@@ -238,6 +238,35 @@ describe('useDashboard', () => {
|
||||
expect(toastCalls).toContainEqual(['Failed to archive trip', 'error']);
|
||||
});
|
||||
|
||||
it('FE-HOOK-DASH-016b: an archive the server refuses says why (#2604)', async () => {
|
||||
server.use(http.put('/api/trips/:id', () => HttpResponse.json({ error: 'No permission to archive/unarchive this trip' }, { status: 403 })));
|
||||
const { result } = await mountLoaded();
|
||||
|
||||
await act(async () => { await result.current.handleArchive(101); });
|
||||
await act(async () => { await result.current.handleUnarchive(103); });
|
||||
|
||||
expect(toastCalls.filter(c => c[1] === 'error')).toEqual([
|
||||
['No permission to archive/unarchive this trip', 'error'],
|
||||
['No permission to archive/unarchive this trip', 'error'],
|
||||
]);
|
||||
});
|
||||
|
||||
it('FE-HOOK-DASH-016c: a delete or copy the server refuses says why (#2604)', async () => {
|
||||
server.use(
|
||||
http.delete('/api/trips/:id', () => HttpResponse.json({ error: 'No permission to delete this trip' }, { status: 403 })),
|
||||
http.post('/api/trips/:id/copy', () => HttpResponse.json({ error: 'No permission to create trips' }, { status: 403 })),
|
||||
);
|
||||
const { result } = await mountLoaded();
|
||||
|
||||
act(() => { result.current.setDeleteTrip(PARIS); });
|
||||
await act(async () => { await result.current.confirmDelete(); });
|
||||
act(() => { result.current.setCopyTrip(PARIS); });
|
||||
await act(async () => { await result.current.confirmCopy(); });
|
||||
|
||||
expect(toastCalls).toContainEqual(['No permission to delete this trip', 'error']);
|
||||
expect(toastCalls).toContainEqual(['No permission to create trips', 'error']);
|
||||
});
|
||||
|
||||
it('FE-HOOK-DASH-017: restoring moves the trip back into the active list', async () => {
|
||||
server.use(http.put('/api/trips/:id', () => HttpResponse.json({ trip: { ...ROME, is_archived: 0 } })));
|
||||
const { result } = await mountLoaded();
|
||||
@@ -252,7 +281,7 @@ describe('useDashboard', () => {
|
||||
});
|
||||
|
||||
it('FE-HOOK-DASH-018: a failing restore only toasts', async () => {
|
||||
server.use(http.put('/api/trips/:id', () => HttpResponse.json({ error: 'nope' }, { status: 500 })));
|
||||
server.use(http.put('/api/trips/:id', () => HttpResponse.json({}, { status: 500 })));
|
||||
const { result } = await mountLoaded();
|
||||
|
||||
await act(async () => { await result.current.handleUnarchive(103); });
|
||||
@@ -284,7 +313,7 @@ describe('useDashboard', () => {
|
||||
});
|
||||
|
||||
it('FE-HOOK-DASH-021: a failing copy only toasts', async () => {
|
||||
server.use(http.post('/api/trips/:id/copy', () => HttpResponse.json({ error: 'nope' }, { status: 500 })));
|
||||
server.use(http.post('/api/trips/:id/copy', () => HttpResponse.json({}, { status: 500 })));
|
||||
const { result } = await mountLoaded();
|
||||
|
||||
act(() => { result.current.setCopyTrip(PARIS); });
|
||||
|
||||
@@ -140,6 +140,8 @@ export function useDashboard() {
|
||||
}
|
||||
}
|
||||
|
||||
// A refusal says why (no right to archive or delete this trip, say) rather
|
||||
// than only that it failed; the generic line stays for a failure without one.
|
||||
const confirmDelete = async () => {
|
||||
if (!deleteTrip) return
|
||||
try {
|
||||
@@ -147,8 +149,8 @@ export function useDashboard() {
|
||||
setTrips(prev => prev.filter(t => t.id !== deleteTrip.id))
|
||||
setArchivedTrips(prev => prev.filter(t => t.id !== deleteTrip.id))
|
||||
toast.success(t('dashboard.toast.deleted'))
|
||||
} catch {
|
||||
toast.error(t('dashboard.toast.deleteError'))
|
||||
} catch (err: unknown) {
|
||||
toast.error(getApiErrorMessage(err, t('dashboard.toast.deleteError')))
|
||||
}
|
||||
setDeleteTrip(null)
|
||||
}
|
||||
@@ -159,8 +161,8 @@ export function useDashboard() {
|
||||
setTrips(prev => prev.filter(t => t.id !== id))
|
||||
setArchivedTrips(prev => sortTrips([data.trip, ...prev]))
|
||||
toast.success(t('dashboard.toast.archived'))
|
||||
} catch {
|
||||
toast.error(t('dashboard.toast.archiveError'))
|
||||
} catch (err: unknown) {
|
||||
toast.error(getApiErrorMessage(err, t('dashboard.toast.archiveError')))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -170,8 +172,8 @@ export function useDashboard() {
|
||||
setArchivedTrips(prev => prev.filter(t => t.id !== id))
|
||||
setTrips(prev => sortTrips([data.trip, ...prev]))
|
||||
toast.success(t('dashboard.toast.restored'))
|
||||
} catch {
|
||||
toast.error(t('dashboard.toast.restoreError'))
|
||||
} catch (err: unknown) {
|
||||
toast.error(getApiErrorMessage(err, t('dashboard.toast.restoreError')))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -181,8 +183,8 @@ export function useDashboard() {
|
||||
const data = await tripsApi.copy(copyTrip.id, { title: `${copyTrip.title} (${t('dashboard.copySuffix')})` })
|
||||
setTrips(prev => sortTrips([data.trip, ...prev]))
|
||||
toast.success(t('dashboard.toast.copied'))
|
||||
} catch {
|
||||
toast.error(t('dashboard.toast.copyError'))
|
||||
} catch (err: unknown) {
|
||||
toast.error(getApiErrorMessage(err, t('dashboard.toast.copyError')))
|
||||
}
|
||||
setCopyTrip(null)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user