diff --git a/src/app/(main)/websites/[websiteId]/settings/ShareCreateForm.tsx b/src/app/(main)/websites/[websiteId]/settings/ShareCreateForm.tsx index a16f2dc5..bf2e050d 100644 --- a/src/app/(main)/websites/[websiteId]/settings/ShareCreateForm.tsx +++ b/src/app/(main)/websites/[websiteId]/settings/ShareCreateForm.tsx @@ -7,6 +7,7 @@ import { FormSubmitButton, Row, Text, + TextField, } from '@umami/react-zen'; import { useState } from 'react'; import { useApi, useMessages, useModified } from '@/components/hooks'; @@ -32,6 +33,9 @@ export function ShareCreateForm({ websiteId, onSave, onClose }: ShareCreateFormP }); }); + // Get all item ids for validation + const allItemIds = SHARE_NAV_ITEMS.flatMap(section => section.items.map(item => item.id)); + const handleSubmit = async (data: any) => { setIsPending(true); try { @@ -41,7 +45,7 @@ export function ShareCreateForm({ websiteId, onSave, onClose }: ShareCreateFormP parameters[item.id] = data[item.id] ?? false; }); }); - await post(`/websites/${websiteId}/shares`, { parameters }); + await post(`/websites/${websiteId}/shares`, { name: data.name, parameters }); touch('shares'); onSave?.(); onClose?.(); @@ -52,30 +56,46 @@ export function ShareCreateForm({ websiteId, onSave, onClose }: ShareCreateFormP return (
- - {SHARE_NAV_ITEMS.map(section => ( - - - {formatMessage((labels as any)[section.section])} - - - {section.items.map(item => ( - - {formatMessage((labels as any)[item.label])} - - ))} - + {({ watch }) => { + const values = watch(); + const hasSelection = allItemIds.some(id => values[id]); + + return ( + + + + + {SHARE_NAV_ITEMS.map(section => ( + + + {formatMessage((labels as any)[section.section])} + + + {section.items.map(item => ( + + {formatMessage((labels as any)[item.label])} + + ))} + + + ))} + + {onClose && ( + + )} + + {formatMessage(labels.save)} + + - ))} - - {onClose && ( - - )} - {formatMessage(labels.save)} - - + ); + }} ); } diff --git a/src/app/(main)/websites/[websiteId]/settings/ShareEditForm.tsx b/src/app/(main)/websites/[websiteId]/settings/ShareEditForm.tsx index c5bd85a6..dc8a41e6 100644 --- a/src/app/(main)/websites/[websiteId]/settings/ShareEditForm.tsx +++ b/src/app/(main)/websites/[websiteId]/settings/ShareEditForm.tsx @@ -5,6 +5,7 @@ import { Form, FormField, FormSubmitButton, + Grid, Label, Loading, Row, @@ -62,7 +63,7 @@ export function ShareEditForm({ }); await mutateAsync( - { slug: share.slug, parameters }, + { name: data.name, slug: share.slug, parameters }, { onSuccess: async () => { toast(formatMessage(messages.saved)); @@ -81,7 +82,9 @@ export function ShareEditForm({ const url = getUrl(share?.slug || ''); // Build default values from share parameters - const defaultValues: Record = {}; + const defaultValues: Record = { + name: share?.name || '', + }; SHARE_NAV_ITEMS.forEach(section => { section.items.forEach(item => { const defaultSelected = item.id === 'overview' || item.id === 'events'; @@ -89,34 +92,55 @@ export function ShareEditForm({ }); }); + // Get all item ids for validation + const allItemIds = SHARE_NAV_ITEMS.flatMap(section => section.items.map(item => item.id)); + return (
- - - - - - {SHARE_NAV_ITEMS.map(section => ( - - {formatMessage((labels as any)[section.section])} - - {section.items.map(item => ( - - {formatMessage((labels as any)[item.label])} - - ))} + {({ watch }) => { + const values = watch(); + const hasSelection = allItemIds.some(id => values[id]); + + return ( + + + + + + + + + {SHARE_NAV_ITEMS.map(section => ( + + {formatMessage((labels as any)[section.section])} + + {section.items.map(item => ( + + {formatMessage((labels as any)[item.label])} + + ))} + + + ))} + + + {onClose && ( + + )} + + {formatMessage(labels.save)} + + - ))} - - {onClose && ( - - )} - {formatMessage(labels.save)} - - + ); + }} ); } diff --git a/src/app/(main)/websites/[websiteId]/settings/SharesTable.tsx b/src/app/(main)/websites/[websiteId]/settings/SharesTable.tsx index 05e8b357..a95ffaf5 100644 --- a/src/app/(main)/websites/[websiteId]/settings/SharesTable.tsx +++ b/src/app/(main)/websites/[websiteId]/settings/SharesTable.tsx @@ -18,6 +18,9 @@ export function SharesTable(props: DataTableProps) { return ( + + {({ name }: any) => name} + {({ slug }: any) => { const url = getUrl(slug); diff --git a/src/app/api/share/id/[shareId]/route.ts b/src/app/api/share/id/[shareId]/route.ts index da7dcf56..80da17b8 100644 --- a/src/app/api/share/id/[shareId]/route.ts +++ b/src/app/api/share/id/[shareId]/route.ts @@ -25,6 +25,7 @@ export async function GET(request: Request, { params }: { params: Promise<{ shar export async function POST(request: Request, { params }: { params: Promise<{ shareId: string }> }) { const schema = z.object({ + name: z.string().max(200), slug: z.string().max(100), parameters: anyObjectParam, }); @@ -36,7 +37,7 @@ export async function POST(request: Request, { params }: { params: Promise<{ sha } const { shareId } = await params; - const { slug, parameters } = body; + const { name, slug, parameters } = body; const share = await getShare(shareId); @@ -49,6 +50,7 @@ export async function POST(request: Request, { params }: { params: Promise<{ sha } const result = await updateShare(shareId, { + name, slug, parameters, } as any); diff --git a/src/app/api/websites/[websiteId]/shares/route.ts b/src/app/api/websites/[websiteId]/shares/route.ts index db079d49..65d53771 100644 --- a/src/app/api/websites/[websiteId]/shares/route.ts +++ b/src/app/api/websites/[websiteId]/shares/route.ts @@ -44,6 +44,7 @@ export async function POST( { params }: { params: Promise<{ websiteId: string }> }, ) { const schema = z.object({ + name: z.string().max(200), parameters: anyObjectParam.optional(), }); @@ -54,7 +55,8 @@ export async function POST( } const { websiteId } = await params; - const { parameters = {} } = body; + const { name, parameters } = body; + const shareParameters = parameters ?? {}; if (!(await canUpdateWebsite(auth, websiteId))) { return unauthorized(); @@ -66,8 +68,9 @@ export async function POST( id: uuid(), entityId: websiteId, shareType: ENTITY_TYPE.website, + name, slug, - parameters, + parameters: shareParameters, }); return json(share);