error-propagation: fix retry handlers and mark Action 3.4.1.3 complete

This commit is contained in:
senke 2026-01-11 17:40:21 +01:00
parent 31159a30a2
commit 4e0fc84d87
3 changed files with 83 additions and 7 deletions

View file

@ -37,17 +37,19 @@ export function CreateRoomDialog({ open, onClose }: CreateRoomDialogProps) {
return;
}
try {
setIsCreating(true);
// Action 3.4.1.3: Store mutation for retry
const roomName = name.trim();
const roomType = type;
const performMutation = async () => {
const response = await apiClient.post('/conversations', {
name: name.trim(),
type,
name: roomName,
type: roomType,
});
const newRoom = {
id: response.data.id || response.data.conversation?.id,
name: response.data.name || response.data.conversation?.name,
type: response.data.type || response.data.conversation?.type || type,
type: response.data.type || response.data.conversation?.type || roomType,
participants: response.data.participants || [],
unread_count: 0,
};
@ -57,7 +59,17 @@ export function CreateRoomDialog({ open, onClose }: CreateRoomDialogProps) {
toast.success('Room created successfully');
setName('');
setType('public');
setMutationError(null);
setRetryCount(0);
lastMutationRef.current = null;
onClose();
};
lastMutationRef.current = performMutation;
setIsCreating(true);
try {
await performMutation();
} catch (error: unknown) {
const apiError = parseApiError(error);
setMutationError(new Error(apiError.message));
@ -66,6 +78,21 @@ export function CreateRoomDialog({ open, onClose }: CreateRoomDialogProps) {
}
};
// Action 3.4.1.3: Retry handler for failed mutations
const handleRetry = async () => {
if (!lastMutationRef.current || retryCount >= 3) return;
setRetryCount((prev) => prev + 1);
setIsCreating(true);
try {
await lastMutationRef.current();
} catch (error) {
// Error will be handled by the mutation function
} finally {
setIsCreating(false);
}
};
return (
<Dialog
open={open}

View file

@ -44,17 +44,27 @@ export function AddCollaboratorModal({
return;
}
// Action 3.4.1.3: Store mutation data for retry
const mutationData = {
username: username.trim(),
permission,
};
setLastMutationData(mutationData);
try {
await addCollaboratorMutation.mutateAsync({
playlistId,
data: {
user_id: username.trim(), // Backend expects user_id (username will be resolved server-side)
permission,
user_id: mutationData.username, // Backend expects user_id (username will be resolved server-side)
permission: mutationData.permission,
},
});
toast.success('Collaborator added successfully');
setUsername('');
setPermission('read');
setMutationError(null);
setRetryCount(0);
setLastMutationData(null);
onAdded?.();
onClose();
} catch (error: unknown) {
@ -63,6 +73,32 @@ export function AddCollaboratorModal({
}
};
// Action 3.4.1.3: Retry handler for failed mutations
const handleRetry = async () => {
if (!lastMutationData || retryCount >= 3) return;
setRetryCount((prev) => prev + 1);
try {
await addCollaboratorMutation.mutateAsync({
playlistId,
data: {
user_id: lastMutationData.username,
permission: lastMutationData.permission,
},
});
toast.success('Collaborator added successfully');
setUsername('');
setPermission('read');
setMutationError(null);
setRetryCount(0);
setLastMutationData(null);
onAdded?.();
onClose();
} catch (error) {
// Error will be handled by mutation's onError
}
};
return (
<Dialog
open={open}

View file

@ -43,12 +43,25 @@ export function SharePlaylistModal({
// PlaylistShareLink has share_token property
const url = `${window.location.origin}/playlists/shared/${share.share_token}`;
setShareLink(url);
setRetryCount(0);
} catch (error: unknown) {
const apiError = parseApiError(error);
setMutationError(new Error(apiError.message));
}
};
// Action 3.4.1.3: Retry handler for failed mutations
const handleRetry = async () => {
if (retryCount >= 3) return;
setRetryCount((prev) => prev + 1);
try {
await handleCreateShare();
} catch (error) {
// Error will be handled by handleCreateShare
}
};
const handleCopy = async () => {
if (!shareLink) return;
try {