import { useState, FC, ChangeEvent } from "react"; import { observer } from "mobx-react-lite"; import { useForm, Controller } from "react-hook-form"; import { Info, X } from "lucide-react"; import { IProject } from "@plane/types"; // ui import { Button, CustomEmojiIconPicker, CustomSelect, EmojiIconPickerTypes, Input, setToast, TextArea, TOAST_TYPE, Tooltip, } from "@plane/ui"; // components import { ImagePickerPopover } from "@/components/core"; import { MemberDropdown } from "@/components/dropdowns"; // constants import { PROJECT_CREATED } from "@/constants/event-tracker"; import { NETWORK_CHOICES, PROJECT_UNSPLASH_COVERS } from "@/constants/project"; // helpers import { cn } from "@/helpers/common.helper"; import { convertHexEmojiToDecimal, getRandomEmoji } from "@/helpers/emoji.helper"; import { projectIdentifierSanitizer } from "@/helpers/project.helper"; // hooks import { useEventTracker, useProject } from "@/hooks/store"; import { usePlatformOS } from "@/hooks/use-platform-os"; // types import { ProjectLogo } from "./project-logo"; type Props = { setToFavorite?: boolean; workspaceSlug: string; onClose: () => void; handleNextStep: (projectId: string) => void; }; const defaultValues: Partial = { cover_image: PROJECT_UNSPLASH_COVERS[Math.floor(Math.random() * PROJECT_UNSPLASH_COVERS.length)], description: "", logo_props: { in_use: "emoji", emoji: { value: getRandomEmoji(), }, }, identifier: "", name: "", network: 2, project_lead: null, }; export const CreateProjectForm: FC = observer((props) => { const { setToFavorite, workspaceSlug, onClose, handleNextStep } = props; // store const { captureProjectEvent } = useEventTracker(); const { addProjectToFavorites, createProject } = useProject(); // states const [isChangeInIdentifierRequired, setIsChangeInIdentifierRequired] = useState(true); // form info const { formState: { errors, isSubmitting }, handleSubmit, reset, control, watch, setValue, } = useForm({ defaultValues, reValidateMode: "onChange", }); const { isMobile } = usePlatformOS(); 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: Partial) => { // Upper case identifier formData.identifier = formData.identifier?.toUpperCase(); return createProject(workspaceSlug.toString(), formData) .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); } handleNextStep(res.id); }) .catch((err) => { Object.keys(err.data).map((key) => { setToast({ type: TOAST_TYPE.ERROR, title: "Error!", message: err.data[key], }); captureProjectEvent({ eventName: PROJECT_CREATED, payload: { ...formData, state: "FAILED", }, }); }); }); }; const handleNameChange = (onChange: any) => (e: ChangeEvent) => { if (!isChangeInIdentifierRequired) { onChange(e); return; } if (e.target.value === "") setValue("identifier", ""); else setValue("identifier", projectIdentifierSanitizer(e.target.value).substring(0, 5)); onChange(e); }; const handleIdentifierChange = (onChange: any) => (e: ChangeEvent) => { const { value } = e.target; const alphanumericValue = projectIdentifierSanitizer(value); setIsChangeInIdentifierRequired(false); onChange(alphanumericValue); }; const handleClose = () => { onClose(); setIsChangeInIdentifierRequired(true); setTimeout(() => { reset(); }, 300); }; return ( <>
{watch("cover_image") && ( Cover image )}
( )} />
( } onChange={(val: any) => { let logoValue = {}; if (val.type === "emoji") logoValue = { value: convertHexEmojiToDecimal(val.value.unified), url: val.value.imageUrl, }; else if (val.type === "icon") logoValue = val.value; onChange({ in_use: val.type, [val.type]: logoValue, }); }} defaultIconColor={value.in_use && value.in_use === "icon" ? value.icon?.color : undefined} defaultOpen={ value.in_use && value.in_use === "emoji" ? EmojiIconPickerTypes.EMOJI : EmojiIconPickerTypes.ICON } /> )} />
( )} /> <>{errors?.name?.message}
/^[ÇŞĞIİÖÜA-Z0-9]+$/.test(value.toUpperCase()) || "Only Alphanumeric & Non-latin characters are allowed.", minLength: { value: 1, message: "Project ID must at least be of 1 character", }, maxLength: { value: 5, message: "Project ID must at most be of 5 characters", }, }} render={({ field: { value, onChange } }) => ( )} /> {errors?.identifier?.message}
(