diff --git a/packages/client/src/handlers/mutations/index.ts b/packages/client/src/handlers/mutations/index.ts index fbf0b564..9116fb69 100644 --- a/packages/client/src/handlers/mutations/index.ts +++ b/packages/client/src/handlers/mutations/index.ts @@ -57,7 +57,6 @@ import { ServerCreateMutationHandler } from './servers/server-create'; import { ServerDeleteMutationHandler } from './servers/server-delete'; import { ServerSyncMutationHandler } from './servers/server-sync'; import { SpaceChildReorderMutationHandler } from './spaces/space-child-reorder'; -import { SpaceCreateMutationHandler } from './spaces/space-create'; import { SpaceUpdateMutationHandler } from './spaces/space-update'; import { UserRoleUpdateMutationHandler } from './users/user-role-update'; import { UserStorageUpdateMutationHandler } from './users/user-storage-update'; @@ -109,7 +108,6 @@ export const buildMutationHandlerMap = ( 'server.create': new ServerCreateMutationHandler(app), 'server.delete': new ServerDeleteMutationHandler(app), 'server.sync': new ServerSyncMutationHandler(app), - 'space.create': new SpaceCreateMutationHandler(app), 'user.role.update': new UserRoleUpdateMutationHandler(app), 'users.create': new UsersCreateMutationHandler(app), 'workspace.create': new WorkspaceCreateMutationHandler(app), diff --git a/packages/client/src/handlers/mutations/spaces/space-create.ts b/packages/client/src/handlers/mutations/spaces/space-create.ts deleted file mode 100644 index d9ce57c7..00000000 --- a/packages/client/src/handlers/mutations/spaces/space-create.ts +++ /dev/null @@ -1,87 +0,0 @@ -import { WorkspaceMutationHandlerBase } from '@colanode/client/handlers/mutations/workspace-mutation-handler-base'; -import { MutationHandler } from '@colanode/client/lib/types'; -import { MutationError, MutationErrorCode } from '@colanode/client/mutations'; -import { - SpaceCreateMutationInput, - SpaceCreateMutationOutput, -} from '@colanode/client/mutations/spaces/space-create'; -import { - ChannelAttributes, - generateId, - IdType, - PageAttributes, - SpaceAttributes, -} from '@colanode/core'; - -export class SpaceCreateMutationHandler - extends WorkspaceMutationHandlerBase - implements MutationHandler -{ - async handleMutation( - input: SpaceCreateMutationInput - ): Promise { - const workspace = this.getWorkspace(input.userId); - - if (!workspace) { - throw new MutationError( - MutationErrorCode.WorkspaceNotFound, - 'Workspace was not found or has been deleted.' - ); - } - - if (workspace.role === 'guest' || workspace.role === 'none') { - throw new MutationError( - MutationErrorCode.SpaceCreateForbidden, - "You don't have permission to create spaces in this workspace." - ); - } - - const spaceId = generateId(IdType.Space); - const spaceAttributes: SpaceAttributes = { - type: 'space', - name: input.name, - visibility: 'private', - collaborators: { - [workspace.userId]: 'admin', - }, - description: input.description, - avatar: input.avatar, - }; - - await workspace.nodes.createNode({ - id: spaceId, - attributes: spaceAttributes, - parentId: null, - }); - - const pageId = generateId(IdType.Page); - const pageAttributes: PageAttributes = { - type: 'page', - name: 'Home', - parentId: spaceId, - }; - - await workspace.nodes.createNode({ - id: pageId, - attributes: pageAttributes, - parentId: spaceId, - }); - - const channelId = generateId(IdType.Channel); - const channelAttributes: ChannelAttributes = { - type: 'channel', - name: 'Discussions', - parentId: spaceId, - }; - - await workspace.nodes.createNode({ - id: channelId, - attributes: channelAttributes, - parentId: spaceId, - }); - - return { - id: spaceId, - }; - } -} diff --git a/packages/client/src/mutations/index.ts b/packages/client/src/mutations/index.ts index 1744a554..397b6840 100644 --- a/packages/client/src/mutations/index.ts +++ b/packages/client/src/mutations/index.ts @@ -45,7 +45,6 @@ export * from './records/record-field-value-set'; export * from './records/record-name-update'; export * from './servers/server-create'; export * from './servers/server-delete'; -export * from './spaces/space-create'; export * from './spaces/space-update'; export * from './spaces/space-child-reorder'; export * from './workspaces/workspace-create'; diff --git a/packages/client/src/mutations/spaces/space-create.ts b/packages/client/src/mutations/spaces/space-create.ts deleted file mode 100644 index efedef32..00000000 --- a/packages/client/src/mutations/spaces/space-create.ts +++ /dev/null @@ -1,20 +0,0 @@ -export type SpaceCreateMutationInput = { - type: 'space.create'; - userId: string; - name: string; - description: string; - avatar?: string | null; -}; - -export type SpaceCreateMutationOutput = { - id: string; -}; - -declare module '@colanode/client/mutations' { - interface MutationMap { - 'space.create': { - input: SpaceCreateMutationInput; - output: SpaceCreateMutationOutput; - }; - } -} diff --git a/packages/ui/src/components/spaces/space-container.tsx b/packages/ui/src/components/spaces/space-container.tsx index 75b2b577..84214b79 100644 --- a/packages/ui/src/components/spaces/space-container.tsx +++ b/packages/ui/src/components/spaces/space-container.tsx @@ -16,7 +16,7 @@ interface SpaceContainerProps { export const SpaceContainer = ({ space, role }: SpaceContainerProps) => { const workspace = useWorkspace(); - const { mutate, isPending } = useMutation(); + const { mutate } = useMutation(); const canEdit = hasNodeRole(role, 'admin'); const canDelete = hasNodeRole(role, 'admin'); @@ -53,8 +53,7 @@ export const SpaceContainer = ({ space, role }: SpaceContainerProps) => { }, }); }} - isSaving={isPending} - saveText="Update" + submitText="Update" /> diff --git a/packages/ui/src/components/spaces/space-create-dialog.tsx b/packages/ui/src/components/spaces/space-create-dialog.tsx index bdfed1cb..71fddc5a 100644 --- a/packages/ui/src/components/spaces/space-create-dialog.tsx +++ b/packages/ui/src/components/spaces/space-create-dialog.tsx @@ -1,6 +1,13 @@ +import { useMutation } from '@tanstack/react-query'; import { toast } from 'sonner'; -import { SpaceForm } from '@colanode/ui/components/spaces/space-form'; +import { LocalPageNode, LocalSpaceNode } from '@colanode/client/types'; +import { generateId, IdType } from '@colanode/core'; +import { collections } from '@colanode/ui/collections'; +import { + SpaceForm, + SpaceFormValues, +} from '@colanode/ui/components/spaces/space-form'; import { Dialog, DialogContent, @@ -9,7 +16,6 @@ import { DialogTitle, } from '@colanode/ui/components/ui/dialog'; import { useWorkspace } from '@colanode/ui/contexts/workspace'; -import { useMutation } from '@colanode/ui/hooks/use-mutation'; interface SpaceCreateDialogProps { open: boolean; @@ -21,7 +27,65 @@ export const SpaceCreateDialog = ({ onOpenChange, }: SpaceCreateDialogProps) => { const workspace = useWorkspace(); - const { mutate, isPending } = useMutation(); + + const { mutate } = useMutation({ + mutationFn: async (values: SpaceFormValues) => { + const nodes = collections.workspace(workspace.userId).nodes; + + const spaceId = generateId(IdType.Space); + const space: LocalSpaceNode = { + id: spaceId, + type: 'space', + attributes: { + type: 'space', + name: values.name, + description: values.description, + avatar: values.avatar, + collaborators: { + [workspace.userId]: 'admin', + }, + visibility: 'private', + }, + parentId: '', + rootId: spaceId, + createdAt: new Date().toISOString(), + createdBy: workspace.userId, + updatedAt: null, + updatedBy: null, + localRevision: '0', + serverRevision: '0', + }; + console.log('space', JSON.stringify(space, null, 2)); + + const pageId = generateId(IdType.Page); + const page: LocalPageNode = { + id: pageId, + type: 'page', + attributes: { + type: 'page', + name: 'Home', + parentId: spaceId, + }, + parentId: spaceId, + rootId: spaceId, + createdAt: new Date().toISOString(), + createdBy: workspace.userId, + updatedAt: null, + updatedBy: null, + localRevision: '0', + serverRevision: '0', + }; + + nodes.insert([space, page]); + return space; + }, + onSuccess: () => { + onOpenChange(false); + }, + onError: (error) => { + toast.error(error.message); + }, + }); return ( @@ -33,36 +97,9 @@ export const SpaceCreateDialog = ({ { - if (isPending) { - return; - } - - if (values.name.length < 3) { - return; - } - - mutate({ - input: { - type: 'space.create', - name: values.name, - description: values.description, - avatar: values.avatar, - userId: workspace.userId, - }, - onSuccess() { - onOpenChange(false); - }, - onError(error) { - toast.error(error.message); - }, - }); - }} - isSaving={isPending} - onCancel={() => { - onOpenChange(false); - }} - saveText="Create" + onSubmit={(values) => mutate(values)} + submitText="Create" + onCancel={() => onOpenChange(false)} /> diff --git a/packages/ui/src/components/spaces/space-form.tsx b/packages/ui/src/components/spaces/space-form.tsx index d7a17965..ca9707ce 100644 --- a/packages/ui/src/components/spaces/space-form.tsx +++ b/packages/ui/src/components/spaces/space-form.tsx @@ -17,7 +17,6 @@ import { FormMessage, } from '@colanode/ui/components/ui/form'; import { Input } from '@colanode/ui/components/ui/input'; -import { Spinner } from '@colanode/ui/components/ui/spinner'; import { Textarea } from '@colanode/ui/components/ui/textarea'; import { useIsMobile } from '@colanode/ui/hooks/use-is-mobile'; import { cn } from '@colanode/ui/lib/utils'; @@ -28,29 +27,27 @@ const formSchema = z.object({ avatar: z.string().optional().nullable(), }); -type formSchemaType = z.infer; +export type SpaceFormValues = z.infer; interface SpaceFormProps { - values?: formSchemaType; - onSubmit: (values: formSchemaType) => void; - isSaving: boolean; + values?: SpaceFormValues; + onSubmit: (values: SpaceFormValues) => void; onCancel?: () => void; - saveText: string; + submitText: string; readOnly?: boolean; } export const SpaceForm = ({ values, onSubmit, - isSaving, onCancel, - saveText, + submitText, readOnly = false, }: SpaceFormProps) => { const id = useRef(generateId(IdType.Space)); const isMobile = useIsMobile(); - const form = useForm({ + const form = useForm({ resolver: zodResolver(formSchema), defaultValues: { name: values?.name ?? '', @@ -136,7 +133,6 @@ export const SpaceForm = ({ {onCancel && ( )} - )}