[feat] Group Admin can remove settle-up member.
This commit is contained in:
parent
92ae97a57b
commit
e9854e3cb7
@ -53,6 +53,14 @@ const BalancePage: NextPageWithUser<{
|
||||
const expensesQuery = api.group.getExpenses.useQuery({ groupId });
|
||||
const deleteGroupMutation = api.group.delete.useMutation();
|
||||
const leaveGroupMutation = api.group.leaveGroup.useMutation();
|
||||
const removeMemberMutation = api.group.removeMember.useMutation({
|
||||
onSuccess: () => {
|
||||
void groupDetailQuery.refetch();
|
||||
},
|
||||
onError: (err) => {
|
||||
toast.error(err.message ?? 'Failed to remove member');
|
||||
},
|
||||
});
|
||||
|
||||
const [isInviteCopied, setIsInviteCopied] = useState(false);
|
||||
const [showDeleteTrigger, setShowDeleteTrigger] = useState(false);
|
||||
@ -188,15 +196,54 @@ const BalancePage: NextPageWithUser<{
|
||||
<div className="">
|
||||
<p className="font-semibold">Members</p>
|
||||
<div className="mt-2 flex flex-col gap-2">
|
||||
{groupDetailQuery.data?.groupUsers.map((groupUser) => (
|
||||
<div
|
||||
key={groupUser.userId}
|
||||
className={clsx('flex items-center gap-2 rounded-md py-1.5')}
|
||||
>
|
||||
<UserAvatar user={groupUser.user} />
|
||||
<p>{groupUser.user.name ?? groupUser.user.email}</p>
|
||||
</div>
|
||||
))}
|
||||
{groupDetailQuery.data?.groupUsers.map((groupUser) => {
|
||||
const hasBalance = groupDetailQuery.data?.groupBalances.some(
|
||||
(b) => b.userId === groupUser.userId && b.amount !== 0
|
||||
);
|
||||
const canDeleteUser =
|
||||
isAdmin && groupUser.userId !== user.id && !hasBalance;
|
||||
|
||||
return (
|
||||
<div
|
||||
key={groupUser.userId}
|
||||
className="flex items-center justify-between gap-2 rounded-md py-1.5"
|
||||
>
|
||||
<div className="flex items-center gap-2">
|
||||
<UserAvatar user={groupUser.user} />
|
||||
<p>{groupUser.user.name ?? groupUser.user.email}</p>
|
||||
</div>
|
||||
{canDeleteUser && (
|
||||
<AlertDialog>
|
||||
<AlertDialogTrigger asChild>
|
||||
<button>
|
||||
<Trash2 className="h-4 w-4 text-red-500 hover:opacity-70" />
|
||||
</button>
|
||||
</AlertDialogTrigger>
|
||||
<AlertDialogContent className="max-w-xs rounded-lg">
|
||||
<AlertDialogHeader>
|
||||
<AlertDialogTitle>Remove member?</AlertDialogTitle>
|
||||
<AlertDialogDescription>
|
||||
This action cannot be undone. The user will be removed from this group.
|
||||
</AlertDialogDescription>
|
||||
</AlertDialogHeader>
|
||||
<AlertDialogFooter>
|
||||
<AlertDialogCancel>Cancel</AlertDialogCancel>
|
||||
<Button
|
||||
variant="destructive"
|
||||
onClick={() =>
|
||||
removeMemberMutation.mutate({ groupId, userId: groupUser.userId })
|
||||
}
|
||||
>
|
||||
Remove
|
||||
</Button>
|
||||
</AlertDialogFooter>
|
||||
</AlertDialogContent>
|
||||
</AlertDialog>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
{groupDetailQuery?.data?.createdAt && (
|
||||
|
||||
@ -350,4 +350,47 @@ export const groupRouter = createTRPCRouter({
|
||||
|
||||
return group;
|
||||
}),
|
||||
});
|
||||
|
||||
removeMember: groupProcedure
|
||||
.input(z.object({ groupId: z.number(), userId: z.number() }))
|
||||
.mutation(async ({ ctx, input }) => {
|
||||
const { groupId, userId } = input;
|
||||
|
||||
// 確保呼叫者是 group 擁有者
|
||||
const group = await ctx.db.group.findUnique({
|
||||
where: { id: groupId },
|
||||
});
|
||||
|
||||
if (group?.userId !== ctx.session.user.id) {
|
||||
throw new TRPCError({ code: 'UNAUTHORIZED', message: 'Only admin can remove members' });
|
||||
}
|
||||
|
||||
if (userId === ctx.session.user.id) {
|
||||
throw new TRPCError({ code: 'BAD_REQUEST', message: 'You cannot remove yourself' });
|
||||
}
|
||||
|
||||
const balance = await ctx.db.groupBalance.findFirst({
|
||||
where: {
|
||||
groupId,
|
||||
userId,
|
||||
amount: { not: 0 },
|
||||
},
|
||||
});
|
||||
|
||||
if (balance) {
|
||||
throw new TRPCError({
|
||||
code: 'BAD_REQUEST',
|
||||
message: 'This member has unsettled balance and cannot be removed',
|
||||
});
|
||||
}
|
||||
|
||||
await ctx.db.groupUser.delete({
|
||||
where: {
|
||||
groupId_userId: { groupId, userId },
|
||||
},
|
||||
});
|
||||
|
||||
return { success: true };
|
||||
}),
|
||||
|
||||
});
|
||||
Loading…
x
Reference in New Issue
Block a user