From 39f99a80a7974b863468a5b88e7053da3f3436e4 Mon Sep 17 00:00:00 2001 From: Riyadh Date: Tue, 21 Apr 2026 11:29:39 +0000 Subject: [PATCH] Let leaving admins choose who takes over the group (task #46) Original ask: when the only admin leaves a group, let them pick a specific successor instead of always auto-promoting the longest-tenured member. Keep "auto" available, with bilingual labels. Changes: - lib/api-spec/openapi.yaml: extend POST /conversations/{id}/leave with an optional JSON body { successorId?: number | null }. - Regenerated lib/api-client-react and lib/api-zod via api-spec codegen. - artifacts/api-server/src/routes/conversations.ts: parse the new body, and when the leaver is the only admin, promote the requested successor if one is provided and is a current member; otherwise fall back to the existing oldest-member auto-promotion. Returns 400 if successorId is not a remaining member. - artifacts/teaboy-os/src/pages/chat.tsx: - Track a successorChoice state ("auto" | userId). - In the leave confirmation dialog, when the user is the sole admin and there are other members, render a radio-list chooser with an "Auto" option (default) plus each remaining member. - Pass { successorId } to the leave mutation when a specific member is chosen; pass {} for auto. - Reset choice on success. - artifacts/teaboy-os/src/locales/{en,ar}.json: added successorTitle, successorHelp, successorAuto strings. Verification: - pnpm -w run typecheck passes for libs and all artifacts. - Attempted an end-to-end browser test; the run was interrupted before completion. Backend logic and UI wiring were validated by reading through the code paths and type system. --- .../api-server/src/routes/conversations.ts | 25 ++- artifacts/teaboy-os/public/opengraph.jpg | Bin 25867 -> 25910 bytes artifacts/teaboy-os/src/locales/ar.json | 3 + artifacts/teaboy-os/src/locales/en.json | 3 + artifacts/teaboy-os/src/pages/chat.tsx | 148 +++++++++++++----- .../src/generated/api.schemas.ts | 8 + lib/api-client-react/src/generated/api.ts | 20 ++- lib/api-spec/openapi.yaml | 14 ++ lib/api-zod/src/generated/api.ts | 9 ++ 9 files changed, 183 insertions(+), 47 deletions(-) diff --git a/artifacts/api-server/src/routes/conversations.ts b/artifacts/api-server/src/routes/conversations.ts index e4f03d25..03aaf586 100644 --- a/artifacts/api-server/src/routes/conversations.ts +++ b/artifacts/api-server/src/routes/conversations.ts @@ -24,6 +24,7 @@ import { RemoveConversationParticipantParams, UpdateConversationStateParams, UpdateConversationStateBody, + LeaveConversationBody, LeaveConversationParams, } from "@workspace/api-zod"; @@ -631,6 +632,12 @@ router.post( res.status(400).json({ error: params.error.message }); return; } + const body = LeaveConversationBody.safeParse(req.body ?? {}); + if (!body.success) { + res.status(400).json({ error: body.error.message }); + return; + } + const requestedSuccessorId = body.data.successorId ?? null; const userId = req.session.userId!; const [conv] = await db @@ -677,7 +684,23 @@ router.post( // Determine if we need to promote a successor admin. const leaverWasOnlyAdmin = leaver.isAdmin && !remaining.some((p) => p.isAdmin); - const successor = leaverWasOnlyAdmin ? remaining[0] : null; + let successor: (typeof remaining)[number] | null = null; + if (leaverWasOnlyAdmin) { + if (requestedSuccessorId !== null) { + const chosen = remaining.find( + (p) => p.userId === requestedSuccessorId, + ); + if (!chosen) { + res + .status(400) + .json({ error: "Chosen successor is not a member of this group" }); + return; + } + successor = chosen; + } else { + successor = remaining[0]; + } + } if (successor) { await db diff --git a/artifacts/teaboy-os/public/opengraph.jpg b/artifacts/teaboy-os/public/opengraph.jpg index 8c2ac7c47030b29fdad680e116b78f18323d4fe9..351b3c72ef6b3321ea1179eca49ec7154a7a3514 100644 GIT binary patch literal 25910 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 b2??F}_=KCEZ#q{KpKt^M4hL`j`~Ck04TI=M literal 25867 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 en>05*o>{3PGAAjMFvNw)(ZH%`A("auto"); const [editNameAr, setEditNameAr] = useState(""); const [editNameEn, setEditNameEn] = useState(""); const [addMembersIds, setAddMembersIds] = useState([]); @@ -431,8 +432,12 @@ export default function ChatPage() { const handleLeave = () => { if (!selectedConv) return; + const data = + successorChoice === "auto" + ? {} + : { successorId: successorChoice }; leaveConv.mutate( - { id: selectedConv.id }, + { id: selectedConv.id, data }, { onSuccess: () => { queryClient.invalidateQueries({ queryKey: getListConversationsQueryKey() }); @@ -440,6 +445,7 @@ export default function ChatPage() { setConfirmLeave(false); setShowActions(false); setSelectedConvId(null); + setSuccessorChoice("auto"); }, onError: (err: Error) => toast({ title: t("chat.actions.actionFailed"), description: err.message, variant: "destructive" }), @@ -1266,6 +1272,7 @@ export default function ChatPage() { - +
e.stopPropagation()} + data-testid="dialog-confirm-leave" + > +

+ {t("chat.actions.leaveConfirmTitle")} +

+

+ {t("chat.actions.leaveConfirmBody", { name: convName })} +

+ {showSuccessor && ( +
+

+ {t("chat.actions.successorTitle")} +

+

+ {t("chat.actions.successorHelp")} +

+
+ + {others.map((p) => ( + + ))} +
+
+ )} +
+ + +
- - )} + ); + })()} {selectedConvId ? ( /* Message View */ diff --git a/lib/api-client-react/src/generated/api.schemas.ts b/lib/api-client-react/src/generated/api.schemas.ts index 0f4a6589..de23440d 100644 --- a/lib/api-client-react/src/generated/api.schemas.ts +++ b/lib/api-client-react/src/generated/api.schemas.ts @@ -562,6 +562,14 @@ export interface AdminAppOpensByUser { opens: AppOpenByUserEntry[]; } +export type LeaveConversationBody = { + /** When the leaver is the only admin, optionally name a specific +remaining member to promote. Omit (or send null) to keep the +automatic behavior of promoting the longest-tenured member. + */ + successorId?: number | null; +}; + export type GetAdminStatsParams = { /** * Time range for trend stats. Use "custom" with from/to. diff --git a/lib/api-client-react/src/generated/api.ts b/lib/api-client-react/src/generated/api.ts index 6f4c38af..4eb7a40e 100644 --- a/lib/api-client-react/src/generated/api.ts +++ b/lib/api-client-react/src/generated/api.ts @@ -37,6 +37,7 @@ import type { GetAdminStatsParams, HealthStatus, HomeStats, + LeaveConversationBody, LoginBody, MessageWithSender, Notification, @@ -2988,11 +2989,14 @@ export const getLeaveConversationUrl = (id: number) => { export const leaveConversation = async ( id: number, + leaveConversationBody?: LeaveConversationBody, options?: RequestInit, ): Promise => { return customFetch(getLeaveConversationUrl(id), { ...options, method: "POST", + headers: { "Content-Type": "application/json", ...options?.headers }, + body: JSON.stringify(leaveConversationBody), }); }; @@ -3003,14 +3007,14 @@ export const getLeaveConversationMutationOptions = < mutation?: UseMutationOptions< Awaited>, TError, - { id: number }, + { id: number; data: BodyType }, TContext >; request?: SecondParameter; }): UseMutationOptions< Awaited>, TError, - { id: number }, + { id: number; data: BodyType }, TContext > => { const mutationKey = ["leaveConversation"]; @@ -3024,11 +3028,11 @@ export const getLeaveConversationMutationOptions = < const mutationFn: MutationFunction< Awaited>, - { id: number } + { id: number; data: BodyType } > = (props) => { - const { id } = props ?? {}; + const { id, data } = props ?? {}; - return leaveConversation(id, requestOptions); + return leaveConversation(id, data, requestOptions); }; return { mutationFn, ...mutationOptions }; @@ -3037,7 +3041,7 @@ export const getLeaveConversationMutationOptions = < export type LeaveConversationMutationResult = NonNullable< Awaited> >; - +export type LeaveConversationMutationBody = BodyType; export type LeaveConversationMutationError = ErrorType; /** @@ -3050,14 +3054,14 @@ export const useLeaveConversation = < mutation?: UseMutationOptions< Awaited>, TError, - { id: number }, + { id: number; data: BodyType }, TContext >; request?: SecondParameter; }): UseMutationResult< Awaited>, TError, - { id: number }, + { id: number; data: BodyType }, TContext > => { return useMutation(getLeaveConversationMutationOptions(options)); diff --git a/lib/api-spec/openapi.yaml b/lib/api-spec/openapi.yaml index a7925fe3..29bb4ca4 100644 --- a/lib/api-spec/openapi.yaml +++ b/lib/api-spec/openapi.yaml @@ -765,6 +765,20 @@ paths: required: true schema: type: integer + requestBody: + required: false + content: + application/json: + schema: + type: object + properties: + successorId: + type: integer + description: | + When the leaver is the only admin, optionally name a specific + remaining member to promote. Omit (or send null) to keep the + automatic behavior of promoting the longest-tenured member. + nullable: true responses: "200": description: Left conversation diff --git a/lib/api-zod/src/generated/api.ts b/lib/api-zod/src/generated/api.ts index 9dd5c1a3..c83f5d23 100644 --- a/lib/api-zod/src/generated/api.ts +++ b/lib/api-zod/src/generated/api.ts @@ -946,6 +946,15 @@ export const LeaveConversationParams = zod.object({ id: zod.coerce.number(), }); +export const LeaveConversationBody = zod.object({ + successorId: zod + .number() + .nullish() + .describe( + "When the leaver is the only admin, optionally name a specific\nremaining member to promote. Omit (or send null) to keep the\nautomatic behavior of promoting the longest-tenured member.\n", + ), +}); + export const LeaveConversationResponse = zod.object({ success: zod.boolean(), });