feat: add share modal with visibility picker and link management

Create ShareModal component with three-tier visibility picker
(private/link/public), share link creation with configurable expiration,
clipboard copy, and link revocation. Wire into setup detail page
replacing the static visibility badge with an interactive share button.

Plan: 32-03 (Setup Sharing System - Share Modal UI)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-13 18:02:41 +02:00
parent e10f0eda3d
commit 7003e998f9
4 changed files with 374 additions and 29 deletions

View File

@@ -0,0 +1,42 @@
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { apiDelete, apiGet, apiPost } from "../lib/api";
interface ShareLink {
id: number;
setupId: number;
token: string;
permission: string;
expiresAt: string | null;
createdAt: string;
revokedAt: string | null;
}
export function useShareLinks(setupId: number | null) {
return useQuery({
queryKey: ["shares", setupId],
queryFn: () => apiGet<ShareLink[]>(`/api/setups/${setupId}/shares`),
enabled: !!setupId,
});
}
export function useCreateShareLink(setupId: number) {
const queryClient = useQueryClient();
return useMutation({
mutationFn: (data: { expiresInDays: number | null }) =>
apiPost<ShareLink>(`/api/setups/${setupId}/shares`, data),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ["shares", setupId] });
},
});
}
export function useRevokeShareLink(setupId: number) {
const queryClient = useQueryClient();
return useMutation({
mutationFn: (shareId: number) =>
apiDelete<ShareLink>(`/api/setups/${setupId}/shares/${shareId}`),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ["shares", setupId] });
},
});
}