feat(web): WS handlers for friend_request_sent + friend_request_relay_failed
Multi-tab sync: friend_request_sent appends the new outbound request to socialStore (deduped by id+origin), no toast. Async rollback: friend_request_relay_failed removes the row by id and surfaces a warning toast with the target handle and reason. Wires the client side of the rollback hook from T10.
This commit is contained in:
@@ -862,6 +862,27 @@ function handleEvent(origin: string, event: ServerEvent): void {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case 'friend_request_sent': {
|
||||||
|
// Multi-tab sync: another tab/device of the same user just created an outbound request.
|
||||||
|
if (!isHome && event.request.user) normalizeUserAssets(event.request.user, origin);
|
||||||
|
const { addOutboundRequest } = useSocialStore.getState();
|
||||||
|
addOutboundRequest(event.request, origin);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 'friend_request_relay_failed': {
|
||||||
|
// Async rollback notification: the federated friend_request_create was permanently rejected.
|
||||||
|
// Drop the optimistic row and surface a warning toast.
|
||||||
|
const { removeRequestById } = useSocialStore.getState();
|
||||||
|
removeRequestById(event.requestId, origin);
|
||||||
|
const { addToast } = useUIStore.getState();
|
||||||
|
addToast(
|
||||||
|
`Friend request to ${event.targetHandle} could not be delivered: ${event.message}`,
|
||||||
|
'warning',
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case 'friend_request_accepted': {
|
case 'friend_request_accepted': {
|
||||||
if (!isHome) normalizeUserAssets(event.friend, origin);
|
if (!isHome) normalizeUserAssets(event.friend, origin);
|
||||||
const { addFriendFromAccepted } = useSocialStore.getState();
|
const { addFriendFromAccepted } = useSocialStore.getState();
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ interface SocialState {
|
|||||||
removeFriend: (id: string) => Promise<void>;
|
removeFriend: (id: string) => Promise<void>;
|
||||||
searchUsers: (query: string) => Promise<TaggedUser[]>;
|
searchUsers: (query: string) => Promise<TaggedUser[]>;
|
||||||
addIncomingRequest: (request: FriendRequest, origin: string) => void;
|
addIncomingRequest: (request: FriendRequest, origin: string) => void;
|
||||||
|
addOutboundRequest: (request: FriendRequest, origin: string) => void;
|
||||||
addFriendFromAccepted: (friend: Friend, requestId: string, origin: string) => void;
|
addFriendFromAccepted: (friend: Friend, requestId: string, origin: string) => void;
|
||||||
updateFriendPresence: (userId: string, status: string) => void;
|
updateFriendPresence: (userId: string, status: string) => void;
|
||||||
updateFriendProfile: (user: User) => void;
|
updateFriendProfile: (user: User) => void;
|
||||||
@@ -343,6 +344,17 @@ export const useSocialStore = create<SocialState>((set, get) => ({
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Called from WS handler for multi-tab sync when this user creates an outbound request
|
||||||
|
addOutboundRequest: (request: FriendRequest, origin: string) => {
|
||||||
|
set((state) => {
|
||||||
|
const canonicalId = request.user?.homeUserId ?? request.user?.id;
|
||||||
|
if (canonicalId && state.requests.some(r => (r.user?.homeUserId ?? r.user?.id) === canonicalId)) {
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
return { requests: [...state.requests, { ...request, _instanceOrigin: origin }] };
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
// Called from WS handler when someone accepts your friend request
|
// Called from WS handler when someone accepts your friend request
|
||||||
addFriendFromAccepted: (friend: Friend, requestId: string, origin: string) => {
|
addFriendFromAccepted: (friend: Friend, requestId: string, origin: string) => {
|
||||||
set((state) => {
|
set((state) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user