NODEDC_TASKMANAGER/plane-src/apps/web/app/(all)/create-workspace/page.tsx

157 lines
6.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* Copyright (c) 2023-present Plane Software, Inc. and contributors
* SPDX-License-Identifier: AGPL-3.0-only
* See the LICENSE file for details.
*/
import { useEffect, useState } from "react";
import { observer } from "mobx-react";
// plane imports
import { useTranslation } from "@plane/i18n";
import { Button, getButtonStyling } from "@plane/propel/button";
import type { IWorkspace } from "@plane/types";
// assets
import WorkspaceCreationDisabled from "@/app/assets/workspace/workspace-creation-disabled.png?url";
import { AuthHeaderBase } from "@/components/auth-screens/header";
// components
import { CreateWorkspaceForm } from "@/components/workspace/create-workspace-form";
// hooks
import { useUser, useUserProfile } from "@/hooks/store/user";
import { useInstance } from "@/hooks/store/use-instance";
import { useAppRouter } from "@/hooks/use-app-router";
// wrappers
import { AuthenticationWrapper } from "@/lib/wrappers/authentication-wrapper";
import { WorkspaceService, type NodeDCWorkspacePolicy } from "@/services/workspace.service";
const workspaceService = new WorkspaceService();
const CreateWorkspacePage = observer(function CreateWorkspacePage() {
const { t } = useTranslation();
// router
const router = useAppRouter();
// store hooks
const { config } = useInstance();
const { data: currentUser } = useUser();
const { updateUserProfile } = useUserProfile();
// states
const [defaultValues, setDefaultValues] = useState<Pick<IWorkspace, "name" | "slug" | "organization_size">>({
name: "",
slug: "",
organization_size: "",
});
const [workspacePolicy, setWorkspacePolicy] = useState<NodeDCWorkspacePolicy | null>(null);
const [workspacePolicyLoading, setWorkspacePolicyLoading] = useState(true);
// derived values
const isWorkspaceCreationDisabled = config?.is_workspace_creation_disabled ?? false;
const isWorkspaceCreationDeniedByNodeDC = Boolean(workspacePolicy?.enabled && !workspacePolicy.can_create_workspace);
const shouldBlockWorkspaceCreation = isWorkspaceCreationDisabled || isWorkspaceCreationDeniedByNodeDC;
useEffect(() => {
let mounted = true;
workspaceService
.getNodeDCWorkspacePolicy()
.then((policy) => {
if (mounted) setWorkspacePolicy(policy);
})
.catch(() => {
if (mounted) {
setWorkspacePolicy({
enabled: false,
can_create_workspace: true,
mode: "unavailable",
managed_by: "tasker",
default_managed_by: "tasker",
workspaces: [],
reason: "NODE.DC workspace policy is unavailable.",
});
}
})
.finally(() => {
if (mounted) setWorkspacePolicyLoading(false);
});
return () => {
mounted = false;
};
}, []);
// methods
const getMailtoHref = () => {
const subject = t("workspace_creation.request_email.subject");
const body = t("workspace_creation.request_email.body", {
firstName: currentUser?.first_name || "",
lastName: currentUser?.last_name || "",
email: currentUser?.email || "",
});
return `mailto:?subject=${encodeURIComponent(subject)}&body=${encodeURIComponent(body)}`;
};
const onSubmit = async (workspace: IWorkspace) => {
await updateUserProfile({ last_workspace_id: workspace.id }).then(() => router.push(`/${workspace.slug}`));
};
return (
<AuthenticationWrapper>
<div className="relative z-10 flex min-h-screen w-screen flex-col overflow-hidden overflow-y-auto bg-canvas px-8 pt-10 pb-12">
<AuthHeaderBase pageTitle={t("workspace_creation.heading")} />
<main className="grid flex-1 place-items-center py-8">
{workspacePolicyLoading ? (
<section className="nodedc-auth-shell flex flex-col items-start justify-center gap-4">
<div className="space-y-3">
<h1 className="m-0 text-30 font-semibold leading-tight text-primary">Работайте во всех измерениях.</h1>
<p className="m-0 text-28 font-semibold leading-tight text-secondary">Проверяем доступ к workspace.</p>
</div>
<p className="m-0 text-14 leading-6 text-secondary">
Сверяем платформенную policy NODE.DC перед созданием рабочего пространства.
</p>
</section>
) : shouldBlockWorkspaceCreation ? (
<section className="nodedc-auth-shell flex flex-col items-center justify-center gap-4 text-center">
<img
src={WorkspaceCreationDisabled}
className="max-h-56 w-full object-contain"
alt="Workspace creation disabled"
/>
<h1 className="m-0 text-24 font-semibold text-primary">
{isWorkspaceCreationDeniedByNodeDC
? "Workspace создаёт администратор."
: t("workspace_creation.errors.creation_disabled.title")}
</h1>
<p className="m-0 text-14 leading-6 text-secondary">
{isWorkspaceCreationDeniedByNodeDC
? workspacePolicy?.reason || "Дождитесь назначения в рабочее пространство администратором NODE.DC."
: t("workspace_creation.errors.creation_disabled.description")}
</p>
<div className="mt-6 flex w-full flex-col gap-3">
<Button variant="primary" className="nodedc-auth-primary-button" onClick={() => router.back()}>
{t("common.go_back")}
</Button>
<a href={getMailtoHref()} className={getButtonStyling("secondary", "base") + " nodedc-auth-secondary-button"}>
{t("workspace_creation.errors.creation_disabled.request_button")}
</a>
</div>
</section>
) : (
<section className="nodedc-auth-shell nodedc-create-workspace-card space-y-7">
<div className="space-y-3">
<h1 className="m-0 text-30 font-semibold leading-tight text-primary">Работайте во всех измерениях.</h1>
<p className="m-0 text-28 font-semibold leading-tight text-secondary">Создайте рабочее пространство.</p>
</div>
<CreateWorkspaceForm
variant="nodedc-auth"
onSubmit={onSubmit}
defaultValues={defaultValues}
setDefaultValues={setDefaultValues}
/>
</section>
)}
</main>
</div>
</AuthenticationWrapper>
);
});
export default CreateWorkspacePage;