import { useState, useEffect, Fragment, FC, ChangeEvent } from "react"; import { useForm, Controller } from "react-hook-form"; import { Dialog, Transition } from "@headlessui/react"; import { observer } from "mobx-react-lite"; import { X } from "lucide-react"; // hooks import { useEventTracker, useProject, useUser } from "hooks/store"; // ui import { Button, CustomSelect, Input, TextArea, TOAST_TYPE, setToast } from "@plane/ui"; // components import { ImagePickerPopover } from "components/core"; import EmojiIconPicker from "components/emoji-icon-picker"; import { MemberDropdown } from "components/dropdowns"; // helpers import { getRandomEmoji, renderEmoji } from "helpers/emoji.helper"; // constants import { NETWORK_CHOICES, PROJECT_UNSPLASH_COVERS } from "constants/project"; // constants import { EUserWorkspaceRoles } from "constants/workspace"; import { PROJECT_CREATED } from "constants/event-tracker"; type Props = { isOpen: boolean; onClose: () => void; setToFavorite?: boolean; workspaceSlug: string; }; interface IIsGuestCondition { onClose: () => void; } const IsGuestCondition: FC = ({ onClose }) => { useEffect(() => { onClose(); setToast({ title: "Error", type: TOAST_TYPE.ERROR, message: "You don't have permission to create project.", }); }, [onClose]); return null; }; export interface ICreateProjectForm { name: string; identifier: string; description: string; emoji_and_icon: string; network: number; project_lead_member: string; project_lead: string; cover_image: string; icon_prop: any; emoji: string; } export const CreateProjectModal: FC = observer((props) => { const { isOpen, onClose, setToFavorite = false, workspaceSlug } = props; // store const { captureProjectEvent } = useEventTracker(); const { membership: { currentWorkspaceRole }, } = useUser(); const { addProjectToFavorites, createProject } = useProject(); // states const [isChangeInIdentifierRequired, setIsChangeInIdentifierRequired] = useState(true); // form info const cover_image = PROJECT_UNSPLASH_COVERS[Math.floor(Math.random() * PROJECT_UNSPLASH_COVERS.length)]; const { formState: { errors, isSubmitting }, handleSubmit, reset, control, watch, setValue, } = useForm({ defaultValues: { cover_image, description: "", emoji_and_icon: getRandomEmoji(), identifier: "", name: "", network: 2, project_lead: undefined, }, reValidateMode: "onChange", }); const currentNetwork = NETWORK_CHOICES.find((n) => n.key === watch("network")); if (currentWorkspaceRole && isOpen) if (currentWorkspaceRole < EUserWorkspaceRoles.MEMBER) return ; const handleClose = () => { onClose(); setIsChangeInIdentifierRequired(true); reset(); }; const handleAddToFavorites = (projectId: string) => { if (!workspaceSlug) return; addProjectToFavorites(workspaceSlug.toString(), projectId).catch(() => { setToast({ type: TOAST_TYPE.ERROR, title: "Error!", message: "Couldn't remove the project from favorites. Please try again.", }); }); }; const onSubmit = async (formData: ICreateProjectForm) => { // eslint-disable-next-line @typescript-eslint/no-unused-vars const { emoji_and_icon, project_lead_member, ...payload } = formData; if (typeof formData.emoji_and_icon === "object") payload.icon_prop = formData.emoji_and_icon; else payload.emoji = formData.emoji_and_icon; payload.project_lead = formData.project_lead_member; // Upper case identifier payload.identifier = payload.identifier.toUpperCase(); return createProject(workspaceSlug.toString(), payload) .then((res) => { const newPayload = { ...res, state: "SUCCESS", }; captureProjectEvent({ eventName: PROJECT_CREATED, payload: newPayload, }); setToast({ type: TOAST_TYPE.SUCCESS, title: "Success!", message: "Project created successfully.", }); if (setToFavorite) { handleAddToFavorites(res.id); } handleClose(); }) .catch((err) => { Object.keys(err.data).map((key) => { setToast({ type: TOAST_TYPE.ERROR, title: "Error!", message: err.data[key], }); captureProjectEvent({ eventName: PROJECT_CREATED, payload: { ...payload, state: "FAILED", }, }); }); }); }; const handleNameChange = (onChange: any) => (e: ChangeEvent) => { if (!isChangeInIdentifierRequired) { onChange(e); return; } if (e.target.value === "") setValue("identifier", ""); else setValue("identifier", e.target.value.replace(/[^ÇŞĞIİÖÜA-Za-z0-9]/g, "").substring(0, 5)); onChange(e); }; const handleIdentifierChange = (onChange: any) => (e: ChangeEvent) => { const { value } = e.target; const alphanumericValue = value.replace(/[^ÇŞĞIİÖÜA-Za-z0-9]/g, ""); setIsChangeInIdentifierRequired(false); onChange(alphanumericValue); }; return (
{watch("cover_image") !== null && ( Cover Image )}
{ setValue("cover_image", image); }} control={control} value={watch("cover_image")} tabIndex={9} />
( {value ? renderEmoji(value) : "Icon"}
} onChange={onChange} value={value} tabIndex={10} /> )} />
( )} /> {errors?.name?.message}
/^[ÇŞĞIİÖÜA-Z0-9]+$/.test(value.toUpperCase()) || "Only Alphanumeric & Non-latin characters are allowed.", minLength: { value: 1, message: "Identifier must at least be of 1 character", }, maxLength: { value: 12, message: "Identifier must at most be of 12 characters", }, }} render={({ field: { value, onChange } }) => ( )} /> {errors?.identifier?.message}
(