[WEB-5782]chore: migrated modals to @plane/ui (#8420)

* chore: migrated modal to @plane/ui

* chore: fixed spacings
This commit is contained in:
Vamsi Krishna 2025-12-24 19:45:55 +05:30 committed by GitHub
parent 39728d4cc4
commit 5b28327551
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
25 changed files with 1530 additions and 2412 deletions

View file

@ -1,11 +1,11 @@
import React, { useState } from "react";
import { useState } from "react";
import { Trash2 } from "lucide-react";
import { Dialog, Transition } from "@headlessui/react";
import { PROFILE_SETTINGS_TRACKER_EVENTS } from "@plane/constants";
import { useTranslation } from "@plane/i18n";
// ui
import { Button } from "@plane/propel/button";
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
import { EModalPosition, EModalWidth, ModalCore } from "@plane/ui";
// hooks
import { captureError, captureSuccess } from "@/helpers/event-tracker.helper";
import { useUser } from "@/hooks/store/user";
@ -47,6 +47,7 @@ export function DeactivateAccountModal(props: Props) {
signOut();
router.push("/");
handleClose();
return;
})
.catch((err: any) => {
captureError({
@ -62,45 +63,15 @@ export function DeactivateAccountModal(props: Props) {
};
return (
<Transition.Root show={isOpen} as={React.Fragment}>
<Dialog as="div" className="relative z-20" onClose={handleClose}>
<Transition.Child
as={React.Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0"
enterTo="opacity-100"
leave="ease-in duration-200"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<div className="fixed inset-0 bg-backdrop transition-opacity" />
</Transition.Child>
<div className="fixed inset-0 z-20 overflow-y-auto">
<div className="flex min-h-full items-end justify-center p-4 text-center sm:items-center sm:p-0">
<Transition.Child
as={React.Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
enterTo="opacity-100 translate-y-0 sm:scale-100"
leave="ease-in duration-200"
leaveFrom="opacity-100 translate-y-0 sm:scale-100"
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
>
<Dialog.Panel className="relative transform overflow-hidden rounded-lg bg-surface-1 text-left shadow-raised-200 transition-all sm:my-8 sm:w-[40rem]">
<ModalCore isOpen={isOpen} handleClose={handleClose} position={EModalPosition.CENTER} width={EModalWidth.XXL}>
<div className="px-4 pb-4 pt-5 sm:p-6 sm:pb-4">
<div className="">
<div className="flex items-start gap-x-4">
<div className="mt-3 grid place-items-center rounded-full bg-red-500/20 p-2 sm:mt-3 sm:p-2 md:mt-0 md:p-4 lg:mt-0 lg:p-4 ">
<Trash2
className="h-4 w-4 text-red-600 sm:h-4 sm:w-4 md:h-6 md:w-6 lg:h-6 lg:w-6"
aria-hidden="true"
/>
<Trash2 className="h-4 w-4 text-red-600 sm:h-4 sm:w-4 md:h-6 md:w-6 lg:h-6 lg:w-6" aria-hidden="true" />
</div>
<div>
<Dialog.Title as="h3" className="my-4 text-20 font-medium leading-6 text-primary">
{t("deactivate_your_account")}
</Dialog.Title>
<h3 className="my-4 text-20 font-medium leading-6 text-primary">{t("deactivate_your_account")}</h3>
<p className="mt-6 list-disc pr-4 text-14 font-regular text-secondary">
{t("deactivate_your_account_description")}
</p>
@ -109,18 +80,13 @@ export function DeactivateAccountModal(props: Props) {
</div>
</div>
<div className="mb-2 flex items-center justify-end gap-2 p-4 sm:px-6">
<Button variant="secondary" size="lg" onClick={onClose}>
<Button variant="secondary" size="lg" onClick={handleClose}>
{t("cancel")}
</Button>
<Button variant="error-fill" size="lg" onClick={handleDeleteAccount}>
{isDeactivating ? t("deactivating") : t("confirm")}
</Button>
</div>
</Dialog.Panel>
</Transition.Child>
</div>
</div>
</Dialog>
</Transition.Root>
</ModalCore>
);
}

View file

@ -1,14 +1,10 @@
import React from "react";
import { useParams } from "next/navigation";
// react-hook-form
import { Controller, useForm } from "react-hook-form";
// headless ui
import { Dialog, Transition } from "@headlessui/react";
import { Button } from "@plane/propel/button";
import type { IProject } from "@plane/types";
// ui
import { Input } from "@plane/ui";
// types
import { Input, EModalPosition, EModalWidth, ModalCore } from "@plane/ui";
// types
type Props = {
@ -43,37 +39,10 @@ export function SelectMonthModal({ type, initialValues, isOpen, handleClose, han
};
return (
<Transition.Root show={isOpen} as={React.Fragment}>
<Dialog as="div" className="relative z-30" onClose={onClose}>
<Transition.Child
as={React.Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0"
enterTo="opacity-100"
leave="ease-in duration-200"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<div className="fixed inset-0 bg-backdrop transition-opacity" />
</Transition.Child>
<div className="fixed inset-0 z-10 overflow-y-auto">
<div className="flex min-h-full items-center justify-center p-4 text-center sm:p-0">
<Transition.Child
as={React.Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
enterTo="opacity-100 translate-y-0 sm:scale-100"
leave="ease-in duration-200"
leaveFrom="opacity-100 translate-y-0 sm:scale-100"
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
>
<Dialog.Panel className="relative transform rounded-lg bg-surface-1 px-4 pb-4 pt-5 text-left shadow-raised-200 transition-all sm:my-8 sm:w-full sm:max-w-2xl sm:p-6">
<ModalCore isOpen={isOpen} handleClose={onClose} position={EModalPosition.CENTER} width={EModalWidth.XXL}>
<form onSubmit={handleSubmit(onSubmit)}>
<div>
<Dialog.Title as="h3" className="text-16 font-medium leading-6 text-primary">
Customize time range
</Dialog.Title>
<h3 className="text-16 font-medium leading-6 text-primary">Customize time range</h3>
<div className="mt-8 flex items-center gap-2">
<div className="flex w-full flex-col justify-center gap-1">
{type === "auto-close" ? (
@ -156,11 +125,6 @@ export function SelectMonthModal({ type, initialValues, isOpen, handleClose, han
</Button>
</div>
</form>
</Dialog.Panel>
</Transition.Child>
</div>
</div>
</Dialog>
</Transition.Root>
</ModalCore>
);
}

View file

@ -1,12 +1,8 @@
import { Fragment } from "react";
import { Controller, useForm } from "react-hook-form";
import { Dialog, Transition } from "@headlessui/react";
import { Button } from "@plane/propel/button";
import { Calendar } from "@plane/propel/calendar";
import { CloseIcon } from "@plane/propel/icons";
import { EModalPosition, EModalWidth, ModalCore } from "@plane/ui";
import { renderFormattedPayloadDate, renderFormattedDate, getDate } from "@plane/utils";
import { DateFilterSelect } from "./date-filter-select";
type Props = {
@ -49,32 +45,8 @@ export function DateFilterModal({ title, handleClose, isOpen, onSelect }: Props)
const isInvalid = watch("filterType") === "range" && date1 && date2 ? date1 > date2 : false;
return (
<Transition.Root show={isOpen} as={Fragment}>
<Dialog as="div" className="relative z-30" onClose={handleClose}>
<Transition.Child
as={Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0"
enterTo="opacity-100"
leave="ease-in duration-200"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<div className="fixed inset-0 bg-backdrop transition-opacity" />
</Transition.Child>
<div className="fixed inset-0 z-20 flex w-full justify-center overflow-y-auto">
<div className="flex min-h-full items-center justify-center p-4 text-center sm:p-0">
<Transition.Child
as={Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
enterTo="opacity-100 translate-y-0 sm:scale-100"
leave="ease-in duration-200"
leaveFrom="opacity-100 translate-y-0 sm:scale-100"
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
>
<Dialog.Panel className="relative flex transform rounded-lg bg-surface-1 px-5 py-8 text-left shadow-raised-200 transition-all sm:my-8 sm:w-full sm:max-w-2xl sm:p-6">
<form className="space-y-4">
<ModalCore isOpen={isOpen} handleClose={handleClose} position={EModalPosition.CENTER} width={EModalWidth.XXL}>
<form className="space-y-4 px-5 py-8 sm:p-6">
<div className="flex w-full justify-between">
<Controller
control={control}
@ -156,11 +128,6 @@ export function DateFilterModal({ title, handleClose, isOpen, onSelect }: Props)
</Button>
</div>
</form>
</Dialog.Panel>
</Transition.Child>
</div>
</div>
</Dialog>
</Transition.Root>
</ModalCore>
);
}

View file

@ -1,18 +1,18 @@
import React, { useEffect, useState } from "react";
import { useEffect, useState } from "react";
import { observer } from "mobx-react";
import { useParams } from "next/navigation";
import { useTheme } from "next-themes";
import type { SubmitHandler } from "react-hook-form";
import { useForm } from "react-hook-form";
import { Search } from "lucide-react";
import { Combobox, Dialog, Transition } from "@headlessui/react";
import { Combobox } from "@headlessui/react";
// plane imports
import { useTranslation } from "@plane/i18n";
import { Button } from "@plane/propel/button";
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
import type { ISearchIssueResponse, IUser } from "@plane/types";
import { EIssuesStoreType } from "@plane/types";
import { Loader } from "@plane/ui";
import { Loader, EModalPosition, EModalWidth, ModalCore } from "@plane/ui";
// assets
import darkIssuesAsset from "@/app/assets/empty-state/search/issues-dark.webp?url";
import lightIssuesAsset from "@/app/assets/empty-state/search/issues-light.webp?url";
@ -150,20 +150,7 @@ export const BulkDeleteIssuesModal = observer(function BulkDeleteIssuesModal(pro
);
return (
<Transition.Root show={isOpen} as={React.Fragment} afterLeave={() => setQuery("")} appear>
<Dialog as="div" className="relative z-20" onClose={handleClose}>
<div className="fixed inset-0 z-20 overflow-y-auto bg-backdrop p-4 transition-opacity sm:p-6 md:p-20">
<Transition.Child
as={React.Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0 scale-95"
enterTo="opacity-100 scale-100"
leave="ease-in duration-200"
leaveFrom="opacity-100 scale-100"
leaveTo="opacity-0 scale-95"
>
<Dialog.Panel className="relative flex w-full items-center justify-center ">
<div className="w-full max-w-2xl transform divide-y divide-subtle-1 divide-opacity-10 rounded-lg bg-surface-1 shadow-raised-200 transition-all">
<ModalCore isOpen={isOpen} handleClose={handleClose} position={EModalPosition.CENTER} width={EModalWidth.XXL}>
<form>
<Combobox
onChange={(val: string) => {
@ -208,22 +195,12 @@ export const BulkDeleteIssuesModal = observer(function BulkDeleteIssuesModal(pro
<Button variant="secondary" size="lg" onClick={handleClose}>
Cancel
</Button>
<Button
variant="error-fill"
size="lg"
onClick={handleSubmit(handleDelete)}
loading={isSubmitting}
>
<Button variant="error-fill" size="lg" onClick={handleSubmit(handleDelete)} loading={isSubmitting}>
{isSubmitting ? "Deleting..." : "Delete selected work items"}
</Button>
</div>
)}
</form>
</div>
</Dialog.Panel>
</Transition.Child>
</div>
</Dialog>
</Transition.Root>
</ModalCore>
);
});

View file

@ -1,12 +1,11 @@
import React, { useState } from "react";
import { useState } from "react";
import { observer } from "mobx-react";
import { Controller, useForm } from "react-hook-form";
import { Transition, Dialog } from "@headlessui/react";
// plane imports
import { useTranslation } from "@plane/i18n";
import { Button } from "@plane/propel/button";
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
import { Input } from "@plane/ui";
import { Input, EModalPosition, EModalWidth, ModalCore } from "@plane/ui";
import { cn } from "@plane/utils";
// helpers
import { authErrorHandler } from "@/helpers/authentication.helper";
@ -127,43 +126,14 @@ export const ChangeEmailModal = observer(function ChangeEmailModal(props: Props)
};
return (
<Transition.Root show={isOpen} as={React.Fragment}>
<Dialog as="div" className="relative z-30" onClose={handleClose}>
<Transition.Child
as={React.Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0"
enterTo="opacity-100"
leave="ease-in duration-200"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<div className="fixed inset-0 transition-opacity bg-backdrop" />
</Transition.Child>
<div className="overflow-y-auto fixed inset-0 z-30">
<div className="flex justify-center items-center p-4 min-h-full text-center sm:p-0">
<Transition.Child
as={React.Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
enterTo="opacity-100 translate-y-0 sm:scale-100"
leave="ease-in duration-200"
leaveFrom="opacity-100 translate-y-0 sm:scale-100"
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
>
<Dialog.Panel className="relative transform overflow-hidden rounded-lg bg-surface-1 px-4 text-left shadow-raised-200 transition-all sm:my-8 sm:w-[30rem]">
<div className="py-4 space-y-0">
<Dialog.Title as="h3" className="text-16 font-medium leading-6 text-primary">
{changeEmailT("title")}
</Dialog.Title>
<ModalCore isOpen={isOpen} handleClose={handleClose} position={EModalPosition.CENTER} width={EModalWidth.XXL}>
<div className="py-4 space-y-0 px-4">
<h3 className="text-16 font-medium leading-6 text-primary">{changeEmailT("title")}</h3>
<p className="my-4 text-13 text-secondary">{changeEmailT("description")}</p>
</div>
<form onSubmit={handleSubmit(onSubmit)} className="space-y-4" noValidate>
<form onSubmit={handleSubmit(onSubmit)} className="space-y-4 px-4" noValidate>
<div className="flex flex-col gap-1">
{secondStep && (
<h4 className="text-13 font-medium text-secondary">{changeEmailT("form.email.label")}</h4>
)}
{secondStep && <h4 className="text-13 font-medium text-secondary">{changeEmailT("form.email.label")}</h4>}
<Controller
control={control}
name="email"
@ -184,10 +154,7 @@ export const ChangeEmailModal = observer(function ChangeEmailModal(props: Props)
ref={ref}
hasError={Boolean(errors.email)}
placeholder={changeEmailT("form.email.placeholder")}
className={cn(
{ "border-red-500": errors.email },
{ "cursor-not-allowed !bg-surface-2": secondStep }
)}
className={cn({ "border-red-500": errors.email }, { "cursor-not-allowed !bg-surface-2": secondStep })}
disabled={secondStep}
/>
)}
@ -235,11 +202,6 @@ export const ChangeEmailModal = observer(function ChangeEmailModal(props: Props)
</Button>
</div>
</form>
</Dialog.Panel>
</Transition.Child>
</div>
</div>
</Dialog>
</Transition.Root>
</ModalCore>
);
});

View file

@ -1,6 +1,6 @@
import React, { useEffect, useState, useRef } from "react";
import { useEffect, useState, useRef } from "react";
import { Rocket, Search } from "lucide-react";
import { Combobox, Dialog, Transition } from "@headlessui/react";
import { Combobox } from "@headlessui/react";
// i18n
import { useTranslation } from "@plane/i18n";
// types
@ -10,7 +10,7 @@ import { TOAST_TYPE, setToast } from "@plane/propel/toast";
import { Tooltip } from "@plane/propel/tooltip";
import type { ISearchIssueResponse, TProjectIssuesSearchParams } from "@plane/types";
// ui
import { Loader, ToggleSwitch } from "@plane/ui";
import { Loader, ToggleSwitch, EModalPosition, EModalWidth, ModalCore } from "@plane/ui";
import { generateWorkItemLink, getTabIndex } from "@plane/utils";
// helpers
// hooks
@ -131,32 +131,7 @@ export function ExistingIssuesListModal(props: Props) {
const filteredIssues = issues.filter((issue) => !shouldHideIssue?.(issue));
return (
<>
<Transition.Root show={isOpen} as={React.Fragment} afterLeave={() => setSearchTerm("")} appear>
<Dialog as="div" className="relative z-30" onClose={handleClose}>
<Transition.Child
as={React.Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0"
enterTo="opacity-100"
leave="ease-in duration-200"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<div className="fixed inset-0 bg-backdrop transition-opacity" />
</Transition.Child>
<div className="fixed inset-0 z-30 overflow-y-auto p-4 sm:p-6 md:p-20">
<Transition.Child
as={React.Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0 scale-95"
enterTo="opacity-100 scale-100"
leave="ease-in duration-200"
leaveFrom="opacity-100 scale-100"
leaveTo="opacity-0 scale-95"
>
<Dialog.Panel className="relative mx-auto max-w-2xl transform rounded-lg bg-surface-1 shadow-raised-200 transition-all">
<ModalCore isOpen={isOpen} handleClose={handleClose} position={EModalPosition.CENTER} width={EModalWidth.XXL}>
<Combobox
as="div"
onChange={(val: ISearchIssueResponse) => {
@ -217,10 +192,7 @@ export function ExistingIssuesListModal(props: Props) {
isWorkspaceLevel ? "text-primary" : "text-secondary"
}`}
>
<ToggleSwitch
value={isWorkspaceLevel}
onChange={() => setIsWorkspaceLevel((prevData) => !prevData)}
/>
<ToggleSwitch value={isWorkspaceLevel} onChange={() => setIsWorkspaceLevel((prevData) => !prevData)} />
<button
type="button"
onClick={() => setIsWorkspaceLevel((prevData) => !prevData)}
@ -233,10 +205,7 @@ export function ExistingIssuesListModal(props: Props) {
)}
</div>
<Combobox.Options
static
className="vertical-scrollbar scrollbar-md max-h-80 scroll-py-2 overflow-y-auto"
>
<Combobox.Options static className="vertical-scrollbar scrollbar-md max-h-80 scroll-py-2 overflow-y-auto">
{/* TODO: Translate here */}
{searchTerm !== "" && (
<h5 className="mx-2 text-13 text-secondary">
@ -334,9 +303,7 @@ export function ExistingIssuesListModal(props: Props) {
disabled={filteredIssues.length === 0}
className={filteredIssues.length === 0 ? "p-0" : ""}
>
{selectedIssues.length === issues.length
? t("issue.select.deselect_all")
: t("issue.select.select_all")}
{selectedIssues.length === issues.length ? t("issue.select.deselect_all") : t("issue.select.select_all")}
</Button>
<div className="flex items-center justify-end gap-2">
<Button variant="secondary" size="lg" onClick={handleClose}>
@ -353,11 +320,6 @@ export function ExistingIssuesListModal(props: Props) {
</Button>
</div>
</div>
</Dialog.Panel>
</Transition.Child>
</div>
</Dialog>
</Transition.Root>
</>
</ModalCore>
);
}

View file

@ -1,13 +1,13 @@
import React, { useState } from "react";
import { useState } from "react";
import { observer } from "mobx-react";
import { useDropzone } from "react-dropzone";
import { Transition, Dialog } from "@headlessui/react";
// plane imports
import { ACCEPTED_AVATAR_IMAGE_MIME_TYPES_FOR_REACT_DROPZONE, MAX_FILE_SIZE } from "@plane/constants";
import { Button } from "@plane/propel/button";
import { UserCirclePropertyIcon } from "@plane/propel/icons";
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
import { EFileAssetType } from "@plane/types";
import { EModalPosition, EModalWidth, ModalCore } from "@plane/ui";
import { getAssetIdFromUrl, getFileURL, checkURLValidity } from "@plane/utils";
// services
import { FileService } from "@/services/file.service";
@ -88,36 +88,9 @@ export const UserImageUploadModal = observer(function UserImageUploadModal(props
};
return (
<Transition.Root show={isOpen} as={React.Fragment}>
<Dialog as="div" className="relative z-30" onClose={handleClose}>
<Transition.Child
as={React.Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0"
enterTo="opacity-100"
leave="ease-in duration-200"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<div className="fixed inset-0 bg-backdrop transition-opacity" />
</Transition.Child>
<div className="fixed inset-0 z-30 overflow-y-auto">
<div className="flex min-h-full items-center justify-center p-4 text-center sm:p-0">
<Transition.Child
as={React.Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
enterTo="opacity-100 translate-y-0 sm:scale-100"
leave="ease-in duration-200"
leaveFrom="opacity-100 translate-y-0 sm:scale-100"
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
>
<Dialog.Panel className="relative transform overflow-hidden rounded-lg bg-surface-1 px-5 py-8 text-left shadow-raised-200 transition-all sm:w-full sm:max-w-xl sm:p-6">
<div className="space-y-5">
<Dialog.Title as="h3" className="text-16 font-medium leading-6 text-primary">
Upload Image
</Dialog.Title>
<ModalCore isOpen={isOpen} handleClose={handleClose} position={EModalPosition.CENTER} width={EModalWidth.XL}>
<div className="space-y-5 px-5 py-8 sm:p-6">
<h3 className="text-16 font-medium leading-6 text-primary">Upload Image</h3>
<div className="space-y-3">
<div className="flex items-center justify-center gap-3">
<div
@ -162,7 +135,6 @@ export const UserImageUploadModal = observer(function UserImageUploadModal(props
</p>
)}
</div>
</div>
<p className="my-4 text-13 text-secondary">File formats supported- .jpeg, .jpg, .png, .webp</p>
<div className="flex items-center justify-between">
<Button variant="error-fill" size="lg" onClick={handleImageRemove} disabled={!value}>
@ -172,22 +144,12 @@ export const UserImageUploadModal = observer(function UserImageUploadModal(props
<Button variant="secondary" size="lg" onClick={handleClose}>
Cancel
</Button>
<Button
variant="primary"
size="lg"
onClick={handleSubmit}
disabled={!image}
loading={isImageUploading}
>
<Button variant="primary" size="lg" onClick={handleSubmit} disabled={!image} loading={isImageUploading}>
{isImageUploading ? "Uploading" : "Upload & Save"}
</Button>
</div>
</div>
</Dialog.Panel>
</Transition.Child>
</div>
</div>
</Dialog>
</Transition.Root>
</ModalCore>
);
});

View file

@ -1,14 +1,14 @@
import React, { useState } from "react";
import { useState } from "react";
import { observer } from "mobx-react";
import { useParams } from "next/navigation";
import { useDropzone } from "react-dropzone";
import { Transition, Dialog } from "@headlessui/react";
// plane imports
import { ACCEPTED_AVATAR_IMAGE_MIME_TYPES_FOR_REACT_DROPZONE, MAX_FILE_SIZE } from "@plane/constants";
import { Button } from "@plane/propel/button";
import { UserCirclePropertyIcon } from "@plane/propel/icons";
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
import { EFileAssetType } from "@plane/types";
import { EModalPosition, EModalWidth, ModalCore } from "@plane/ui";
import { getAssetIdFromUrl, getFileURL, checkURLValidity } from "@plane/utils";
// hooks
import { useWorkspace } from "@/hooks/store/use-workspace";
@ -101,36 +101,9 @@ export const WorkspaceImageUploadModal = observer(function WorkspaceImageUploadM
};
return (
<Transition.Root show={isOpen} as={React.Fragment}>
<Dialog as="div" className="relative z-30" onClose={handleClose}>
<Transition.Child
as={React.Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0"
enterTo="opacity-100"
leave="ease-in duration-200"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<div className="fixed inset-0 bg-backdrop transition-opacity" />
</Transition.Child>
<div className="fixed inset-0 z-30 overflow-y-auto">
<div className="flex min-h-full items-center justify-center p-4 text-center sm:p-0">
<Transition.Child
as={React.Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
enterTo="opacity-100 translate-y-0 sm:scale-100"
leave="ease-in duration-200"
leaveFrom="opacity-100 translate-y-0 sm:scale-100"
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
>
<Dialog.Panel className="relative transform overflow-hidden rounded-lg bg-surface-1 px-5 py-8 text-left shadow-raised-200 transition-all sm:w-full sm:max-w-xl sm:p-6">
<div className="space-y-5">
<Dialog.Title as="h3" className="text-16 font-medium leading-6 text-primary">
Upload image
</Dialog.Title>
<ModalCore isOpen={isOpen} handleClose={handleClose} position={EModalPosition.CENTER} width={EModalWidth.XL}>
<div className="space-y-5 px-5 py-8 sm:p-6">
<h3 className="text-16 font-medium leading-6 text-primary">Upload image</h3>
<div className="space-y-3">
<div className="flex items-center justify-center gap-3">
<div
@ -175,38 +148,21 @@ export const WorkspaceImageUploadModal = observer(function WorkspaceImageUploadM
</p>
)}
</div>
</div>
<p className="my-4 text-13 text-secondary">File formats supported- .jpeg, .jpg, .png, .webp</p>
<div className="flex items-center justify-between">
<Button
variant="error-fill"
size="lg"
onClick={handleImageRemove}
disabled={!value}
loading={isRemoving}
>
<Button variant="error-fill" size="lg" onClick={handleImageRemove} disabled={!value} loading={isRemoving}>
{isRemoving ? "Removing" : "Remove"}
</Button>
<div className="flex items-center gap-2">
<Button variant="secondary" size="lg" onClick={handleClose}>
Cancel
</Button>
<Button
variant="primary"
size="lg"
onClick={handleSubmit}
disabled={!image}
loading={isImageUploading}
>
<Button variant="primary" size="lg" onClick={handleSubmit} disabled={!image} loading={isImageUploading}>
{isImageUploading ? "Uploading" : "Upload & Save"}
</Button>
</div>
</div>
</Dialog.Panel>
</Transition.Child>
</div>
</div>
</Dialog>
</Transition.Root>
</ModalCore>
);
});

View file

@ -1,9 +1,9 @@
import { useState, Fragment } from "react";
import { Dialog, Transition } from "@headlessui/react";
import { useState } from "react";
// ui
import { CYCLE_TRACKER_EVENTS } from "@plane/constants";
import { Button } from "@plane/propel/button";
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
import { EModalPosition, EModalWidth, ModalCore } from "@plane/ui";
// hooks
import { captureError, captureSuccess } from "@/helpers/event-tracker.helper";
import { useCycle } from "@/hooks/store/use-cycle";
@ -51,6 +51,7 @@ export function ArchiveCycleModal(props: Props) {
});
onClose();
router.push(`/${workspaceSlug}/projects/${projectId}/cycles`);
return;
})
.catch(() => {
setToast({
@ -69,32 +70,7 @@ export function ArchiveCycleModal(props: Props) {
};
return (
<Transition.Root show={isOpen} as={Fragment}>
<Dialog as="div" className="relative z-20" onClose={onClose}>
<Transition.Child
as={Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0"
enterTo="opacity-100"
leave="ease-in duration-200"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<div className="fixed inset-0 bg-backdrop transition-opacity" />
</Transition.Child>
<div className="fixed inset-0 z-10 overflow-y-auto">
<div className="flex min-h-full items-end justify-center p-4 text-center sm:items-center sm:p-0">
<Transition.Child
as={Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
enterTo="opacity-100 translate-y-0 sm:scale-100"
leave="ease-in duration-200"
leaveFrom="opacity-100 translate-y-0 sm:scale-100"
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
>
<Dialog.Panel className="relative transform overflow-hidden rounded-lg bg-surface-1 text-left shadow-raised-200 transition-all sm:my-8 sm:w-full sm:max-w-lg">
<ModalCore isOpen={isOpen} handleClose={onClose} position={EModalPosition.CENTER} width={EModalWidth.LG}>
<div className="px-5 py-4">
<h3 className="text-18 font-medium 2xl:text-20">Archive cycle {cycleName}</h3>
<p className="mt-3 text-13 text-secondary">
@ -109,11 +85,6 @@ export function ArchiveCycleModal(props: Props) {
</Button>
</div>
</div>
</Dialog.Panel>
</Transition.Child>
</div>
</div>
</Dialog>
</Transition.Root>
</ModalCore>
);
}

View file

@ -1,15 +1,13 @@
import React, { useState } from "react";
import { useState } from "react";
import { observer } from "mobx-react";
import { useParams } from "next/navigation";
import { AlertCircle, Search } from "lucide-react";
import { Dialog, Transition } from "@headlessui/react";
import { CycleIcon, TransferIcon, CloseIcon } from "@plane/propel/icons";
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
import { EIssuesStoreType } from "@plane/types";
import { EModalPosition, EModalWidth, ModalCore } from "@plane/ui";
import { useCycle } from "@/hooks/store/use-cycle";
import { useIssues } from "@/hooks/store/use-issues";
//icons
// constants
type Props = {
isOpen: boolean;
@ -72,42 +70,9 @@ export const TransferIssuesModal = observer(function TransferIssuesModal(props:
return cycleDetails?.name?.toLowerCase().includes(query?.toLowerCase());
});
// useEffect(() => {
// const handleKeyDown = (e: KeyboardEvent) => {
// if (e.key === "Escape") {
// handleClose();
// }
// };
// }, [handleClose]);
return (
<Transition.Root show={isOpen} as={React.Fragment}>
<Dialog as="div" className="relative z-20" onClose={handleClose}>
<Transition.Child
as={React.Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0"
enterTo="opacity-100"
leave="ease-in duration-200"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<div className="fixed inset-0 bg-backdrop transition-opacity" />
</Transition.Child>
<div className="fixed inset-0 z-10">
<div className="mt-10 flex min-h-full items-start justify-center p-4 text-center sm:p-0 md:mt-20">
<Transition.Child
as={React.Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
enterTo="opacity-100 translate-y-0 sm:scale-100"
leave="ease-in duration-200"
leaveFrom="opacity-100 translate-y-0 sm:scale-100"
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
>
<Dialog.Panel className="relative transform rounded-lg bg-surface-1 py-5 text-left shadow-raised-200 transition-all sm:w-full sm:max-w-2xl">
<div className="flex flex-col gap-4">
<ModalCore isOpen={isOpen} handleClose={handleClose} position={EModalPosition.TOP} width={EModalWidth.XXL}>
<div className="flex flex-col gap-4 py-5">
<div className="flex items-center justify-between px-5">
<div className="flex items-center gap-1">
<TransferIcon className="w-5 fill-primary" />
@ -170,11 +135,6 @@ export const TransferIssuesModal = observer(function TransferIssuesModal(props:
)}
</div>
</div>
</Dialog.Panel>
</Transition.Child>
</div>
</div>
</Dialog>
</Transition.Root>
</ModalCore>
);
});

View file

@ -2,14 +2,13 @@ import React, { useState } from "react";
import { intersection } from "lodash-es";
import { observer } from "mobx-react";
import { useParams } from "next/navigation";
import { Dialog, Transition } from "@headlessui/react";
// types
import { useTranslation } from "@plane/i18n";
import { Button } from "@plane/propel/button";
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
import type { IUser, IImporterService } from "@plane/types";
// ui
import { Checkbox, CustomSearchSelect } from "@plane/ui";
import { Checkbox, CustomSearchSelect, EModalPosition, EModalWidth, ModalCore } from "@plane/ui";
// hooks
import { useProject } from "@/hooks/store/use-project";
import { useUser } from "@/hooks/store/user";
@ -99,38 +98,14 @@ export const Exporter = observer(function Exporter(props: Props) {
}
return (
<Transition.Root show={isOpen} as={React.Fragment}>
<Dialog
as="div"
className="relative z-20"
onClose={() => {
<ModalCore
isOpen={isOpen}
handleClose={() => {
if (!isSelectOpen) handleClose();
}}
position={EModalPosition.CENTER}
width={EModalWidth.XL}
>
<Transition.Child
as={React.Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0"
enterTo="opacity-100"
leave="ease-in duration-200"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<div className="fixed inset-0 bg-backdrop transition-opacity" />
</Transition.Child>
<div className="fixed inset-0 z-20 overflow-y-auto">
<div className="flex min-h-full items-center justify-center p-4 text-center sm:p-0">
<Transition.Child
as={React.Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
enterTo="opacity-100 translate-y-0 sm:scale-100"
leave="ease-in duration-200"
leaveFrom="opacity-100 translate-y-0 sm:scale-100"
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
>
<Dialog.Panel className="relative transform rounded-lg bg-surface-1 text-left shadow-raised-200 transition-all sm:my-8 sm:w-full sm:max-w-xl">
<div className="flex flex-col gap-6 gap-y-4 p-6">
<div className="flex w-full items-center justify-start gap-6">
<span className="flex items-center justify-start">
@ -164,10 +139,7 @@ export const Exporter = observer(function Exporter(props: Props) {
multiple
/>
</div>
<div
onClick={() => setMultiple(!multiple)}
className="flex max-w-min cursor-pointer items-center gap-2"
>
<div className="flex max-w-min cursor-pointer items-center gap-2">
<Checkbox checked={multiple} onChange={() => setMultiple(!multiple)} />
<div className="whitespace-nowrap text-13">
{t("workspace_settings.settings.exports.export_separate_files")}
@ -177,23 +149,13 @@ export const Exporter = observer(function Exporter(props: Props) {
<Button variant="secondary" onClick={handleClose}>
{t("cancel")}
</Button>
<Button
variant="primary"
onClick={ExportCSVToMail}
disabled={exportLoading}
loading={exportLoading}
>
<Button variant="primary" onClick={ExportCSVToMail} disabled={exportLoading} loading={exportLoading}>
{exportLoading
? `${t("workspace_settings.settings.exports.exporting")}...`
: t("workspace_settings.settings.exports.title")}
</Button>
</div>
</div>
</Dialog.Panel>
</Transition.Child>
</div>
</div>
</Dialog>
</Transition.Root>
</ModalCore>
);
});

View file

@ -1,13 +1,13 @@
import React, { useEffect, useState } from "react";
import { useEffect, useState } from "react";
import { useParams } from "next/navigation";
import { useTheme } from "next-themes";
import { Search } from "lucide-react";
import { Combobox, Dialog, Transition } from "@headlessui/react";
import { Combobox } from "@headlessui/react";
// plane imports
import { useTranslation } from "@plane/i18n";
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
import type { ISearchIssueResponse } from "@plane/types";
import { Loader } from "@plane/ui";
import { Loader, EModalPosition, EModalWidth, ModalCore } from "@plane/ui";
// assets
import darkIssuesAsset from "@/app/assets/empty-state/search/issues-dark.webp?url";
import lightIssuesAsset from "@/app/assets/empty-state/search/issues-light.webp?url";
@ -65,6 +65,7 @@ export function SelectDuplicateInboxIssueModal(props: Props) {
const handleClose = () => {
onClose();
setQuery("");
};
const handleSubmit = (selectedItem: string) => {
@ -124,33 +125,7 @@ export function SelectDuplicateInboxIssueModal(props: Props) {
);
return (
<Transition.Root show={isOpen} as={React.Fragment} afterLeave={() => setQuery("")} appear>
<div className="flex flex-wrap items-start">
<div className="space-y-1 sm:basis-1/2">
<Dialog as="div" className="relative z-30" onClose={handleClose}>
<Transition.Child
as={React.Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0"
enterTo="opacity-100"
leave="ease-in duration-200"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<div className="fixed inset-0 bg-backdrop transition-opacity" />
</Transition.Child>
<div className="fixed inset-0 z-30 overflow-y-auto p-4 sm:p-6 md:p-20">
<Transition.Child
as={React.Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0 scale-95"
enterTo="opacity-100 scale-100"
leave="ease-in duration-200"
leaveFrom="opacity-100 scale-100"
leaveTo="opacity-0 scale-95"
>
<Dialog.Panel className="relative mx-auto max-w-2xl transform rounded-lg bg-surface-1 shadow-raised-200 transition-all">
<ModalCore isOpen={isOpen} handleClose={handleClose} position={EModalPosition.CENTER} width={EModalWidth.XXL}>
<Combobox value={value} onChange={handleSubmit}>
<div className="relative m-1">
<Search
@ -178,12 +153,6 @@ export function SelectDuplicateInboxIssueModal(props: Props) {
)}
</Combobox.Options>
</Combobox>
</Dialog.Panel>
</Transition.Child>
</div>
</Dialog>
</div>
</div>
</Transition.Root>
</ModalCore>
);
}

View file

@ -1,10 +1,9 @@
import type { FC } from "react";
import { Fragment, useState } from "react";
import { Dialog, Transition } from "@headlessui/react";
import { useState } from "react";
// ui
import { useTranslation } from "@plane/i18n";
import { Button } from "@plane/propel/button";
import { Calendar } from "@plane/propel/calendar";
import { EModalPosition, EModalWidth, ModalCore } from "@plane/ui";
export type InboxIssueSnoozeModalProps = {
isOpen: boolean;
@ -21,32 +20,8 @@ export function InboxIssueSnoozeModal(props: InboxIssueSnoozeModalProps) {
const { t } = useTranslation();
return (
<Transition.Root show={isOpen} as={Fragment}>
<Dialog as="div" className="relative z-20" onClose={handleClose}>
<Transition.Child
as={Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0"
enterTo="opacity-100"
leave="ease-in duration-200"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<div className="fixed inset-0 bg-backdrop transition-opacity" />
</Transition.Child>
<div className="fixed inset-0 z-20 flex w-full justify-center overflow-y-auto">
<div className="flex min-h-full items-center justify-center p-4 text-center sm:p-0">
<Transition.Child
as={Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
enterTo="opacity-100 translate-y-0 sm:scale-100"
leave="ease-in duration-200"
leaveFrom="opacity-100 translate-y-0 sm:scale-100"
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
>
<Dialog.Panel className="relative flex transform rounded-lg bg-surface-1 px-5 py-8 text-left shadow-raised-200 transition-all sm:my-8 sm:w-full sm:max-w-2xl sm:p-6">
<div className="flex h-full w-full flex-col gap-y-1">
<ModalCore isOpen={isOpen} handleClose={handleClose} position={EModalPosition.CENTER} width={EModalWidth.XXL}>
<div className="flex h-full w-full flex-col gap-y-1 px-5 py-8 sm:p-6">
<Calendar
className="rounded-md border border-subtle p-3"
captionLayout="dropdown"
@ -66,18 +41,13 @@ export function InboxIssueSnoozeModal(props: InboxIssueSnoozeModalProps) {
<Button
variant="primary"
onClick={() => {
close();
handleClose();
onConfirm(date);
}}
>
{t("inbox_issue.actions.snooze")}
</Button>
</div>
</Dialog.Panel>
</Transition.Child>
</div>
</div>
</Dialog>
</Transition.Root>
</ModalCore>
);
}

View file

@ -1,23 +1,15 @@
import React, { useState } from "react";
import { useState } from "react";
import { useParams } from "next/navigation";
import { mutate } from "swr";
// headless ui
// icons
import { AlertTriangle } from "lucide-react";
import { Dialog, Transition } from "@headlessui/react";
// services
import { Button } from "@plane/propel/button";
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
import type { IUser, IImporterService } from "@plane/types";
import { Input } from "@plane/ui";
import { Input, EModalPosition, EModalWidth, ModalCore } from "@plane/ui";
import { IMPORTER_SERVICES_LIST } from "@/constants/fetch-keys";
import { IntegrationService } from "@/services/integrations/integration.service";
// ui
// icons
// types
// fetch-keys
type Props = {
isOpen: boolean;
@ -64,32 +56,7 @@ export function DeleteImportModal({ isOpen, handleClose, data }: Props) {
if (!data) return <></>;
return (
<Transition.Root show={isOpen} as={React.Fragment}>
<Dialog as="div" className="relative z-20" onClose={handleClose}>
<Transition.Child
as={React.Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0"
enterTo="opacity-100"
leave="ease-in duration-200"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<div className="fixed inset-0 bg-backdrop transition-opacity" />
</Transition.Child>
<div className="fixed inset-0 z-20 overflow-y-auto">
<div className="flex min-h-full items-end justify-center p-4 text-center sm:items-center sm:p-0">
<Transition.Child
as={React.Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
enterTo="opacity-100 translate-y-0 sm:scale-100"
leave="ease-in duration-200"
leaveFrom="opacity-100 translate-y-0 sm:scale-100"
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
>
<Dialog.Panel className="relative transform overflow-hidden rounded-lg bg-surface-1 text-left shadow-raised-200 transition-all sm:my-8 sm:w-full sm:max-w-2xl">
<ModalCore isOpen={isOpen} handleClose={handleClose} position={EModalPosition.CENTER} width={EModalWidth.XXL}>
<div className="flex flex-col gap-6 p-6">
<div className="flex w-full items-center justify-start gap-6">
<span className="place-items-center rounded-full bg-red-500/20 p-4">
@ -102,8 +69,8 @@ export function DeleteImportModal({ isOpen, handleClose, data }: Props) {
<span>
<p className="text-13 leading-7 text-secondary">
Are you sure you want to delete import from{" "}
<span className="break-words font-semibold capitalize text-primary">{data?.service}</span>? All of
the data related to the import will be permanently removed. This action cannot be undone.
<span className="break-words font-semibold capitalize text-primary">{data?.service}</span>? All of the data
related to the import will be permanently removed. This action cannot be undone.
</p>
</span>
<div>
@ -138,11 +105,6 @@ export function DeleteImportModal({ isOpen, handleClose, data }: Props) {
</Button>
</div>
</div>
</Dialog.Panel>
</Transition.Child>
</div>
</div>
</Dialog>
</Transition.Root>
</ModalCore>
);
}

View file

@ -1,11 +1,11 @@
import { useState, Fragment } from "react";
import { Dialog, Transition } from "@headlessui/react";
import { useState } from "react";
// i18n
import { useTranslation } from "@plane/i18n";
// types
import { Button } from "@plane/propel/button";
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
import type { TDeDupeIssue, TIssue } from "@plane/types";
import { EModalPosition, EModalWidth, ModalCore } from "@plane/ui";
// hooks
import { useIssues } from "@/hooks/store/use-issues";
import { useProject } from "@/hooks/store/use-project";
@ -49,6 +49,7 @@ export function ArchiveIssueModal(props: Props) {
message: t("issue.archive.success.message"),
});
onClose();
return;
})
.catch(() =>
setToast({
@ -61,32 +62,7 @@ export function ArchiveIssueModal(props: Props) {
};
return (
<Transition.Root show={isOpen} as={Fragment}>
<Dialog as="div" className="relative z-30" onClose={onClose}>
<Transition.Child
as={Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0"
enterTo="opacity-100"
leave="ease-in duration-200"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<div className="fixed inset-0 bg-backdrop transition-opacity" />
</Transition.Child>
<div className="fixed inset-0 z-30 overflow-y-auto">
<div className="flex min-h-full items-end justify-center p-4 text-center sm:items-center sm:p-0">
<Transition.Child
as={Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
enterTo="opacity-100 translate-y-0 sm:scale-100"
leave="ease-in duration-200"
leaveFrom="opacity-100 translate-y-0 sm:scale-100"
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
>
<Dialog.Panel className="relative transform overflow-hidden rounded-lg bg-surface-1 text-left shadow-raised-200 transition-all sm:my-8 sm:w-full sm:max-w-lg">
<ModalCore isOpen={isOpen} handleClose={onClose} position={EModalPosition.CENTER} width={EModalWidth.LG}>
<div className="px-5 py-4">
<h3 className="text-18 font-medium 2xl:text-20">
{t("issue.archive.label")} {projectDetails?.identifier} {issue.sequence_id}
@ -101,11 +77,6 @@ export function ArchiveIssueModal(props: Props) {
</Button>
</div>
</div>
</Dialog.Panel>
</Transition.Child>
</div>
</div>
</Dialog>
</Transition.Root>
</ModalCore>
);
}

View file

@ -1,9 +1,7 @@
import React, { useState } from "react";
// headless ui
import { Dialog, Transition } from "@headlessui/react";
import { useState } from "react";
// ui
import { Button } from "@plane/propel/button";
import { EModalPosition, EModalWidth, ModalCore } from "@plane/ui";
type Props = {
isOpen: boolean;
@ -29,38 +27,11 @@ export function ConfirmIssueDiscard(props: Props) {
};
return (
<Transition.Root show={isOpen} as={React.Fragment}>
<Dialog as="div" className="relative z-30" onClose={handleClose}>
<Transition.Child
as={React.Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0"
enterTo="opacity-100"
leave="ease-in duration-200"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<div className="fixed inset-0 bg-backdrop transition-opacity" />
</Transition.Child>
<div className="fixed inset-0 z-30 overflow-y-auto">
<div className="my-10 flex items-center justify-center p-4 text-center sm:p-0 md:my-32">
<Transition.Child
as={React.Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
enterTo="opacity-100 translate-y-0 sm:scale-100"
leave="ease-in duration-200"
leaveFrom="opacity-100 translate-y-0 sm:scale-100"
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
>
<Dialog.Panel className="relative transform overflow-hidden rounded-lg bg-surface-1 text-left shadow-raised-200 transition-all sm:my-8 sm:w-[40rem]">
<ModalCore isOpen={isOpen} handleClose={handleClose} position={EModalPosition.TOP} width={EModalWidth.XXL}>
<div className="px-4 pb-4 pt-5 sm:p-6 sm:pb-4">
<div className="sm:flex sm:items-start">
<div className="mt-3 text-center sm:mt-0 sm:text-left">
<Dialog.Title as="h3" className="text-16 font-medium leading-6 text-primary">
Save this draft?
</Dialog.Title>
<h3 className="text-16 font-medium leading-6 text-primary">Save this draft?</h3>
<div className="mt-2">
<p className="text-13 text-secondary">
You can save this work item to Drafts so you can come back to it later.{" "}
@ -84,11 +55,6 @@ export function ConfirmIssueDiscard(props: Props) {
</Button>
</div>
</div>
</Dialog.Panel>
</Transition.Child>
</div>
</div>
</Dialog>
</Transition.Root>
</ModalCore>
);
}

View file

@ -3,13 +3,13 @@ import { useParams } from "next/navigation";
// icons
import { Rocket, Search } from "lucide-react";
// headless ui
import { Combobox, Dialog, Transition } from "@headlessui/react";
import { Combobox } from "@headlessui/react";
// i18n
import { useTranslation } from "@plane/i18n";
// types
import type { ISearchIssueResponse } from "@plane/types";
// ui
import { Loader } from "@plane/ui";
import { Loader, EModalPosition, EModalWidth, ModalCore } from "@plane/ui";
import { generateWorkItemLink, getTabIndex } from "@plane/utils";
// components
import { IssueSearchModalEmptyState } from "@/components/core/modals/issue-search-modal-empty-state";
@ -85,32 +85,7 @@ export function ParentIssuesListModal({
}, [debouncedSearchTerm, isOpen, issueId, projectId, workspaceSlug]);
return (
<>
<Transition.Root show={isOpen} as={React.Fragment} afterLeave={() => setSearchTerm("")} appear>
<Dialog as="div" className="relative z-30" onClose={handleClose}>
<Transition.Child
as={React.Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0"
enterTo="opacity-100"
leave="ease-in duration-200"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<div className="fixed inset-0 bg-backdrop transition-opacity" />
</Transition.Child>
<div className="fixed inset-0 z-30 overflow-y-auto p-4 sm:p-6 md:p-20">
<Transition.Child
as={React.Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0 scale-95"
enterTo="opacity-100 scale-100"
leave="ease-in duration-200"
leaveFrom="opacity-100 scale-100"
leaveTo="opacity-0 scale-95"
>
<Dialog.Panel className="relative mx-auto max-w-2xl transform rounded-lg bg-surface-1 shadow-raised-200 transition-all">
<ModalCore isOpen={isOpen} handleClose={handleClose} position={EModalPosition.CENTER} width={EModalWidth.XXL}>
<Combobox
value={value}
onChange={(val) => {
@ -132,10 +107,7 @@ export function ParentIssuesListModal({
tabIndex={baseTabIndex}
/>
</div>
<Combobox.Options
static
className="max-h-80 scroll-py-2 overflow-y-auto vertical-scrollbar scrollbar-md"
>
<Combobox.Options static className="max-h-80 scroll-py-2 overflow-y-auto vertical-scrollbar scrollbar-md">
{searchTerm !== "" && (
<h5 className="mx-2 text-13 text-secondary">
Search results for{" "}
@ -218,11 +190,6 @@ export function ParentIssuesListModal({
)}
</Combobox.Options>
</Combobox>
</Dialog.Panel>
</Transition.Child>
</div>
</Dialog>
</Transition.Root>
</>
</ModalCore>
);
}

View file

@ -1,8 +1,8 @@
import { useState, Fragment } from "react";
import { Dialog, Transition } from "@headlessui/react";
import { useState } from "react";
// ui
import { Button } from "@plane/propel/button";
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
import { EModalPosition, EModalWidth, ModalCore } from "@plane/ui";
// hooks
import { useModule } from "@/hooks/store/use-module";
import { useAppRouter } from "@/hooks/use-app-router";
@ -43,6 +43,7 @@ export function ArchiveModuleModal(props: Props) {
});
onClose();
router.push(`/${workspaceSlug}/projects/${projectId}/modules`);
return;
})
.catch(() =>
setToast({
@ -55,32 +56,7 @@ export function ArchiveModuleModal(props: Props) {
};
return (
<Transition.Root show={isOpen} as={Fragment}>
<Dialog as="div" className="relative z-20" onClose={onClose}>
<Transition.Child
as={Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0"
enterTo="opacity-100"
leave="ease-in duration-200"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<div className="fixed inset-0 bg-backdrop transition-opacity" />
</Transition.Child>
<div className="fixed inset-0 z-10 overflow-y-auto">
<div className="flex min-h-full items-end justify-center p-4 text-center sm:items-center sm:p-0">
<Transition.Child
as={Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
enterTo="opacity-100 translate-y-0 sm:scale-100"
leave="ease-in duration-200"
leaveFrom="opacity-100 translate-y-0 sm:scale-100"
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
>
<Dialog.Panel className="relative transform overflow-hidden rounded-lg bg-surface-1 text-left shadow-raised-200 transition-all sm:my-8 sm:w-full sm:max-w-lg">
<ModalCore isOpen={isOpen} handleClose={onClose} position={EModalPosition.CENTER} width={EModalWidth.LG}>
<div className="px-5 py-4">
<h3 className="text-18 font-medium 2xl:text-20">Archive module {moduleName}</h3>
<p className="mt-3 text-13 text-secondary">
@ -90,22 +66,11 @@ export function ArchiveModuleModal(props: Props) {
<Button variant="secondary" size="lg" onClick={onClose}>
Cancel
</Button>
<Button
variant="primary"
size="lg"
tabIndex={1}
onClick={handleArchiveModule}
loading={isArchiving}
>
<Button variant="primary" size="lg" tabIndex={1} onClick={handleArchiveModule} loading={isArchiving}>
{isArchiving ? "Archiving" : "Archive"}
</Button>
</div>
</div>
</Dialog.Panel>
</Transition.Child>
</div>
</div>
</Dialog>
</Transition.Root>
</ModalCore>
);
}

View file

@ -1,13 +1,12 @@
import React, { useState } from "react";
import { useState } from "react";
import { observer } from "mobx-react";
import { useParams } from "next/navigation";
import { AlertTriangle } from "lucide-react";
// headless ui
import { Dialog, Transition } from "@headlessui/react";
// types
import { Button } from "@plane/propel/button";
import type { IUserLite } from "@plane/types";
// ui
import { EModalPosition, EModalWidth, ModalCore } from "@plane/ui";
// hooks
import { useProject } from "@/hooks/store/use-project";
import { useUser } from "@/hooks/store/user";
@ -48,54 +47,27 @@ export const ConfirmProjectMemberRemove = observer(function ConfirmProjectMember
const currentProjectDetails = getProjectById(projectId.toString());
return (
<Transition.Root show={isOpen} as={React.Fragment}>
<Dialog as="div" className="relative z-20" onClose={handleClose}>
<Transition.Child
as={React.Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0"
enterTo="opacity-100"
leave="ease-in duration-200"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<div className="fixed inset-0 bg-backdrop transition-opacity" />
</Transition.Child>
<div className="fixed inset-0 z-20 overflow-y-auto">
<div className="flex min-h-full items-end justify-center p-4 text-center sm:items-center sm:p-0">
<Transition.Child
as={React.Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
enterTo="opacity-100 translate-y-0 sm:scale-100"
leave="ease-in duration-200"
leaveFrom="opacity-100 translate-y-0 sm:scale-100"
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
>
<Dialog.Panel className="relative transform overflow-hidden rounded-lg bg-surface-1 text-left shadow-raised-200 transition-all sm:my-8 sm:w-[40rem]">
<ModalCore isOpen={isOpen} handleClose={handleClose} position={EModalPosition.CENTER} width={EModalWidth.XXL}>
<div className="bg-surface-1 px-4 pb-4 pt-5 sm:p-6 sm:pb-4">
<div className="sm:flex sm:items-start">
<div className="mx-auto flex h-12 w-12 flex-shrink-0 items-center justify-center rounded-full bg-red-100 sm:mx-0 sm:h-10 sm:w-10">
<AlertTriangle className="h-6 w-6 text-red-600" aria-hidden="true" />
</div>
<div className="mt-3 text-center sm:ml-4 sm:mt-0 sm:text-left">
<Dialog.Title as="h3" className="text-16 font-medium leading-6 text-primary">
<h3 className="text-16 font-medium leading-6 text-primary">
{isCurrentUser ? "Leave project?" : `Remove ${data?.display_name}?`}
</Dialog.Title>
</h3>
<div className="mt-2">
<p className="text-13 text-secondary">
{isCurrentUser ? (
<>
Are you sure you want to leave the{" "}
<span className="font-bold">{currentProjectDetails?.name}</span> project? You will be able
to join the project if invited again or if it{"'"}s public.
Are you sure you want to leave the <span className="font-bold">{currentProjectDetails?.name}</span>{" "}
project? You will be able to join the project if invited again or if it{"'"}s public.
</>
) : (
<>
Are you sure you want to remove member-{" "}
<span className="font-bold">{data?.display_name}</span>? They will no longer have access
to this project. This action cannot be undone.
Are you sure you want to remove member- <span className="font-bold">{data?.display_name}</span>?
They will no longer have access to this project. This action cannot be undone.
</>
)}
</p>
@ -107,27 +79,10 @@ export const ConfirmProjectMemberRemove = observer(function ConfirmProjectMember
<Button variant="secondary" size="lg" onClick={handleClose}>
Cancel
</Button>
<Button
variant="error-fill"
size="lg"
tabIndex={1}
onClick={handleDeletion}
loading={isDeleteLoading}
>
{isCurrentUser
? isDeleteLoading
? "Leaving..."
: "Leave"
: isDeleteLoading
? "Removing..."
: "Remove"}
<Button variant="error-fill" size="lg" tabIndex={1} onClick={handleDeletion} loading={isDeleteLoading}>
{isCurrentUser ? (isDeleteLoading ? "Leaving..." : "Leave") : isDeleteLoading ? "Removing..." : "Remove"}
</Button>
</div>
</Dialog.Panel>
</Transition.Child>
</div>
</div>
</Dialog>
</Transition.Root>
</ModalCore>
);
});

View file

@ -1,15 +1,13 @@
import React from "react";
import { useParams } from "next/navigation";
import { Controller, useForm } from "react-hook-form";
import { AlertTriangle } from "lucide-react";
import { Dialog, Transition } from "@headlessui/react";
// types
import { PROJECT_TRACKER_EVENTS } from "@plane/constants";
import { Button } from "@plane/propel/button";
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
import type { IProject } from "@plane/types";
// ui
import { Input } from "@plane/ui";
import { Input, EModalPosition, EModalWidth, ModalCore } from "@plane/ui";
// constants
// hooks
import { captureError, captureSuccess } from "@/helpers/event-tracker.helper";
@ -90,32 +88,7 @@ export function DeleteProjectModal(props: DeleteProjectModal) {
};
return (
<Transition.Root show={isOpen} as={React.Fragment}>
<Dialog as="div" className="relative z-20" onClose={handleClose}>
<Transition.Child
as={React.Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0"
enterTo="opacity-100"
leave="ease-in duration-200"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<div className="fixed inset-0 bg-backdrop transition-opacity" />
</Transition.Child>
<div className="fixed inset-0 z-20 overflow-y-auto">
<div className="flex min-h-full items-end justify-center p-4 text-center sm:items-center sm:p-0">
<Transition.Child
as={React.Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
enterTo="opacity-100 translate-y-0 sm:scale-100"
leave="ease-in duration-200"
leaveFrom="opacity-100 translate-y-0 sm:scale-100"
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
>
<Dialog.Panel className="relative transform overflow-hidden rounded-lg bg-surface-1 text-left shadow-raised-200 transition-all sm:my-8 sm:w-full sm:max-w-2xl">
<ModalCore isOpen={isOpen} handleClose={handleClose} position={EModalPosition.CENTER} width={EModalWidth.XXL}>
<form onSubmit={handleSubmit(onSubmit)} className="flex flex-col gap-6 p-6">
<div className="flex w-full items-center justify-start gap-6">
<span className="place-items-center rounded-full bg-red-500/20 p-4">
@ -127,15 +100,13 @@ export function DeleteProjectModal(props: DeleteProjectModal) {
</div>
<span>
<p className="text-13 leading-7 text-secondary">
Are you sure you want to delete project{" "}
<span className="break-words font-semibold">{project?.name}</span>? All of the data related to the
project will be permanently removed. This action cannot be undone
Are you sure you want to delete project <span className="break-words font-semibold">{project?.name}</span>?
All of the data related to the project will be permanently removed. This action cannot be undone
</p>
</span>
<div className="text-secondary">
<p className="break-words text-13 ">
Enter the project name <span className="font-medium text-primary">{project?.name}</span> to
continue:
Enter the project name <span className="font-medium text-primary">{project?.name}</span> to continue:
</p>
<Controller
control={control}
@ -188,11 +159,6 @@ export function DeleteProjectModal(props: DeleteProjectModal) {
</Button>
</div>
</form>
</Dialog.Panel>
</Transition.Child>
</div>
</div>
</Dialog>
</Transition.Root>
</ModalCore>
);
}

View file

@ -1,10 +1,9 @@
import { useState, Fragment } from "react";
import { Transition, Dialog } from "@headlessui/react";
import { useState } from "react";
// types
import { Button } from "@plane/propel/button";
import type { IProject } from "@plane/types";
// ui
import { EModalPosition, EModalWidth, ModalCore } from "@plane/ui";
// hooks
import { useUserPermissions } from "@/hooks/store/user";
import { useAppRouter } from "@/hooks/use-app-router";
@ -26,13 +25,17 @@ export function JoinProjectModal(props: TJoinProjectModalProps) {
// router
const router = useAppRouter();
const handleJoin = () => {
const handleJoin = async () => {
setIsJoiningLoading(true);
joinProject(workspaceSlug, project.id)
await joinProject(workspaceSlug, project.id)
.then(() => {
router.push(`/${workspaceSlug}/projects/${project.id}/issues`);
handleClose();
return;
})
.catch(() => {
console.error("Error joining project");
})
.finally(() => {
setIsJoiningLoading(false);
@ -40,63 +43,23 @@ export function JoinProjectModal(props: TJoinProjectModalProps) {
};
return (
<Transition.Root show={isOpen} as={Fragment}>
<Dialog as="div" className="relative z-20" onClose={handleClose}>
<Transition.Child
as={Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0"
enterTo="opacity-100"
leave="ease-in duration-200"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<div className="fixed inset-0 bg-backdrop transition-opacity" />
</Transition.Child>
<div className="fixed inset-0 z-20 overflow-y-auto">
<div className="flex min-h-full items-center justify-center p-4 text-center sm:p-0">
<Transition.Child
as={Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
enterTo="opacity-100 translate-y-0 sm:scale-100"
leave="ease-in duration-200"
leaveFrom="opacity-100 translate-y-0 sm:scale-100"
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
>
<Dialog.Panel className="relative transform overflow-hidden rounded-lg bg-surface-1 px-5 py-8 text-left shadow-raised-200 transition-all sm:w-full sm:max-w-xl sm:p-6">
<div className="space-y-5">
<Dialog.Title as="h3" className="text-16 font-medium leading-6 text-primary">
Join Project?
</Dialog.Title>
<ModalCore isOpen={isOpen} handleClose={handleClose} position={EModalPosition.CENTER} width={EModalWidth.XL}>
<div className="space-y-5 px-5 py-8 sm:p-6">
<h3 className="text-16 font-medium leading-6 text-primary">Join Project?</h3>
<p>
Are you sure you want to join the project{" "}
<span className="break-words font-semibold">{project?.name}</span>? Please click the &apos;Join
Project&apos; button below to continue.
Are you sure you want to join the project <span className="break-words font-semibold">{project?.name}</span>?
Please click the &apos;Join Project&apos; button below to continue.
</p>
<div className="space-y-3" />
</div>
<div className="mt-5 flex justify-end gap-2">
<div className="mt-5 flex justify-end gap-2 px-5 pb-8 sm:px-6 sm:pb-6">
<Button variant="secondary" size="lg" onClick={handleClose}>
Cancel
</Button>
<Button
variant="primary"
size="lg"
tabIndex={1}
type="submit"
onClick={handleJoin}
loading={isJoiningLoading}
>
<Button variant="primary" size="lg" tabIndex={1} type="submit" onClick={handleJoin} loading={isJoiningLoading}>
{isJoiningLoading ? "Joining..." : "Join Project"}
</Button>
</div>
</Dialog.Panel>
</Transition.Child>
</div>
</div>
</Dialog>
</Transition.Root>
</ModalCore>
);
}

View file

@ -1,17 +1,15 @@
import { Fragment } from "react";
import { observer } from "mobx-react";
import { useParams } from "next/navigation";
import { Controller, useForm } from "react-hook-form";
// headless ui
import { AlertTriangleIcon } from "lucide-react";
import { Dialog, Transition } from "@headlessui/react";
// types
import { MEMBER_TRACKER_EVENTS } from "@plane/constants";
import { Button } from "@plane/propel/button";
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
import type { IProject } from "@plane/types";
// ui
import { Input } from "@plane/ui";
import { Input, EModalPosition, EModalWidth, ModalCore } from "@plane/ui";
// constants
// hooks
import { captureError, captureSuccess } from "@/helpers/event-tracker.helper";
@ -109,32 +107,7 @@ export const LeaveProjectModal = observer(function LeaveProjectModal(props: ILea
};
return (
<Transition.Root show={isOpen} as={Fragment}>
<Dialog as="div" className="relative z-20" onClose={handleClose}>
<Transition.Child
as={Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0"
enterTo="opacity-100"
leave="ease-in duration-200"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<div className="fixed inset-0 bg-backdrop transition-opacity" />
</Transition.Child>
<div className="fixed inset-0 z-20 overflow-y-auto">
<div className="flex min-h-full items-end justify-center p-4 text-center sm:items-center sm:p-0">
<Transition.Child
as={Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
enterTo="opacity-100 translate-y-0 sm:scale-100"
leave="ease-in duration-200"
leaveFrom="opacity-100 translate-y-0 sm:scale-100"
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
>
<Dialog.Panel className="relative transform overflow-hidden rounded-lg bg-surface-1 text-left shadow-raised-200 transition-all sm:my-8 sm:w-full sm:max-w-2xl">
<ModalCore isOpen={isOpen} handleClose={handleClose} position={EModalPosition.CENTER} width={EModalWidth.XXL}>
<form onSubmit={handleSubmit(onSubmit)} className="flex flex-col gap-6 p-6">
<div className="flex w-full items-center justify-start gap-6">
<span className="place-items-center rounded-full bg-red-500/20 p-4">
@ -148,15 +121,14 @@ export const LeaveProjectModal = observer(function LeaveProjectModal(props: ILea
<span>
<p className="text-13 leading-7 text-secondary">
Are you sure you want to leave the project -
<span className="font-medium text-primary">{` "${project?.name}" `}</span>? All of the work items
associated with you will become inaccessible.
<span className="font-medium text-primary">{` "${project?.name}" `}</span>? All of the work items associated
with you will become inaccessible.
</p>
</span>
<div className="text-secondary">
<p className="break-words text-13 ">
Enter the project name <span className="font-medium text-primary">{project?.name}</span> to
continue:
Enter the project name <span className="font-medium text-primary">{project?.name}</span> to continue:
</p>
<Controller
control={control}
@ -211,11 +183,6 @@ export const LeaveProjectModal = observer(function LeaveProjectModal(props: ILea
</Button>
</div>
</form>
</Dialog.Panel>
</Transition.Child>
</div>
</div>
</Dialog>
</Transition.Root>
</ModalCore>
);
});

View file

@ -2,14 +2,13 @@ import React, { useEffect } from "react";
import { observer } from "mobx-react";
import { useForm, Controller, useFieldArray } from "react-hook-form";
import { Plus } from "lucide-react";
import { Dialog, Transition } from "@headlessui/react";
// plane imports
import { ROLE, EUserPermissions, MEMBER_TRACKER_EVENTS } from "@plane/constants";
import { useTranslation } from "@plane/i18n";
import { Button } from "@plane/propel/button";
import { CloseIcon, ChevronDownIcon } from "@plane/propel/icons";
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
import { Avatar, CustomSelect, CustomSearchSelect } from "@plane/ui";
import { Avatar, CustomSelect, CustomSearchSelect, EModalPosition, EModalWidth, ModalCore } from "@plane/ui";
// helpers
import { getFileURL } from "@plane/utils";
// hooks
@ -183,49 +182,19 @@ export const SendProjectInvitationModal = observer(function SendProjectInvitatio
};
return (
<Transition.Root show={isOpen} as={React.Fragment}>
<Dialog as="div" className="relative z-20" onClose={handleClose}>
<Transition.Child
as={React.Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0"
enterTo="opacity-100"
leave="ease-in duration-200"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<div className="fixed inset-0 bg-backdrop transition-opacity" />
</Transition.Child>
<div className="fixed inset-0 z-20 overflow-y-auto">
<div className="flex min-h-full items-center justify-center p-4 text-center">
<Transition.Child
as={React.Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
enterTo="opacity-100 translate-y-0 sm:scale-100"
leave="ease-in duration-200"
leaveFrom="opacity-100 translate-y-0 sm:scale-100"
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
>
<Dialog.Panel className="relative transform rounded-lg bg-surface-1 p-5 text-left shadow-raised-200 transition-all sm:w-full sm:max-w-2xl">
<form onSubmit={handleSubmit(onSubmit)}>
<ModalCore isOpen={isOpen} handleClose={handleClose} position={EModalPosition.CENTER} width={EModalWidth.XXL}>
<form onSubmit={handleSubmit(onSubmit)} className="p-5">
<div className="space-y-5">
<Dialog.Title as="h3" className="text-16 font-medium leading-6 text-primary">
<h3 className="text-16 font-medium leading-6 text-primary">
{t("project_settings.members.invite_members.title")}
</Dialog.Title>
</h3>
<div className="mt-2">
<p className="text-13 text-secondary">
{t("project_settings.members.invite_members.sub_heading")}
</p>
<p className="text-13 text-secondary">{t("project_settings.members.invite_members.sub_heading")}</p>
</div>
<div className="mb-3 space-y-4">
{fields.map((field, index) => (
<div
key={field.id}
className="group mb-1 flex items-start justify-between gap-x-4 text-13 w-full"
>
<div key={field.id} className="group mb-1 flex items-start justify-between gap-x-4 text-13 w-full">
<div className="flex flex-col gap-1 flex-grow w-full">
<Controller
control={control}
@ -270,9 +239,7 @@ export const SendProjectInvitationModal = observer(function SendProjectInvitatio
}}
/>
{errors.members && errors.members[index]?.member_id && (
<span className="px-1 text-13 text-red-500">
{errors.members[index]?.member_id?.message}
</span>
<span className="px-1 text-13 text-red-500">{errors.members[index]?.member_id?.message}</span>
)}
</div>
@ -287,17 +254,14 @@ export const SendProjectInvitationModal = observer(function SendProjectInvitatio
{...field}
customButton={
<div className="flex w-24 items-center justify-between gap-1 rounded-md border border-subtle px-3 py-2.5 text-left text-13 text-secondary shadow-sm duration-300 hover:bg-layer-1 hover:text-primary focus:outline-none">
<span className="capitalize">
{field.value ? ROLE[field.value] : "Select role"}
</span>
<span className="capitalize">{field.value ? ROLE[field.value] : "Select role"}</span>
<ChevronDownIcon className="h-3 w-3" aria-hidden="true" />
</div>
}
input
>
{Object.entries(
checkCurrentOptionWorkspaceRole(watch(`members.${index}.member_id`))
).map(([key, label]) => {
{Object.entries(checkCurrentOptionWorkspaceRole(watch(`members.${index}.member_id`))).map(
([key, label]) => {
if (parseInt(key) > (currentProjectRole ?? EUserPermissions.GUEST)) return null;
return (
@ -305,14 +269,13 @@ export const SendProjectInvitationModal = observer(function SendProjectInvitatio
{label}
</CustomSelect.Option>
);
})}
}
)}
</CustomSelect>
)}
/>
{errors.members && errors.members[index]?.role && (
<span className="px-1 text-13 text-red-500">
{errors.members[index]?.role?.message}
</span>
<span className="px-1 text-13 text-red-500">{errors.members[index]?.role?.message}</span>
)}
</div>
@ -332,7 +295,6 @@ export const SendProjectInvitationModal = observer(function SendProjectInvitatio
))}
</div>
</div>
<div className="mt-5 flex items-center justify-between gap-2">
<button
type="button"
@ -354,11 +316,6 @@ export const SendProjectInvitationModal = observer(function SendProjectInvitatio
</div>
</div>
</form>
</Dialog.Panel>
</Transition.Child>
</div>
</div>
</Dialog>
</Transition.Root>
</ModalCore>
);
});

View file

@ -1,8 +1,8 @@
import { useState, Fragment } from "react";
import { Dialog, Transition } from "@headlessui/react";
import { useState } from "react";
// ui
import { Button } from "@plane/propel/button";
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
import { EModalPosition, EModalWidth, ModalCore } from "@plane/ui";
// hooks
import { useProject } from "@/hooks/store/use-project";
import { useAppRouter } from "@/hooks/use-app-router";
@ -44,6 +44,7 @@ export function ArchiveRestoreProjectModal(props: Props) {
});
onClose();
router.push(`/${workspaceSlug}/projects/`);
return;
})
.catch(() =>
setToast({
@ -66,6 +67,7 @@ export function ArchiveRestoreProjectModal(props: Props) {
});
onClose();
router.push(`/${workspaceSlug}/projects/`);
return;
})
.catch(() =>
setToast({
@ -78,39 +80,14 @@ export function ArchiveRestoreProjectModal(props: Props) {
};
return (
<Transition.Root show={isOpen} as={Fragment}>
<Dialog as="div" className="relative z-20" onClose={handleClose}>
<Transition.Child
as={Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0"
enterTo="opacity-100"
leave="ease-in duration-200"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<div className="fixed inset-0 bg-backdrop transition-opacity" />
</Transition.Child>
<div className="fixed inset-0 z-10 overflow-y-auto">
<div className="flex min-h-full items-end justify-center p-4 text-center sm:items-center sm:p-0">
<Transition.Child
as={Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
enterTo="opacity-100 translate-y-0 sm:scale-100"
leave="ease-in duration-200"
leaveFrom="opacity-100 translate-y-0 sm:scale-100"
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
>
<Dialog.Panel className="relative transform overflow-hidden rounded-lg bg-surface-1 text-left shadow-raised-200 transition-all sm:my-8 sm:w-full sm:max-w-lg">
<ModalCore isOpen={isOpen} handleClose={handleClose} position={EModalPosition.CENTER} width={EModalWidth.LG}>
<div className="px-5 py-4">
<h3 className="text-18 font-medium 2xl:text-20">
{archive ? "Archive" : "Restore"} {projectDetails.name}
</h3>
<p className="mt-3 text-13 text-secondary">
{archive
? "This project and its work items, cycles, modules, and pages will be archived. Its work items wont appear in search. Only project admins can restore the project."
? "This project and its work items, cycles, modules, and pages will be archived. Its work items won't appear in search. Only project admins can restore the project."
: "Restoring a project will activate it and make it visible to all members of the project. Are you sure you want to continue?"}
</p>
<div className="mt-3 flex justify-end gap-2">
@ -128,11 +105,6 @@ export function ArchiveRestoreProjectModal(props: Props) {
</Button>
</div>
</div>
</Dialog.Panel>
</Transition.Child>
</div>
</div>
</Dialog>
</Transition.Root>
</ModalCore>
);
}

View file

@ -1,16 +1,13 @@
import { Fragment } from "react";
import { useParams } from "next/navigation";
import { useForm, Controller } from "react-hook-form";
import { Transition, Dialog } from "@headlessui/react";
// plane imports
import { allTimeIn30MinutesInterval12HoursFormat } from "@plane/constants";
import { Button } from "@plane/propel/button";
import { CloseIcon } from "@plane/propel/icons";
import { CustomSelect } from "@plane/ui";
import { CustomSelect, EModalPosition, EModalWidth, ModalCore } from "@plane/ui";
// components
import { getDate, cn } from "@plane/utils";
import { DateDropdown } from "@/components/dropdowns/date";
// helpers
type TNotificationSnoozeModal = {
isOpen: boolean;
@ -110,37 +107,10 @@ export function NotificationSnoozeModal(props: TNotificationSnoozeModal) {
};
return (
<Transition.Root show={isOpen} as={Fragment}>
<Dialog as="div" className="relative z-20" onClose={handleClose}>
<Transition.Child
as={Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0"
enterTo="opacity-100"
leave="ease-in duration-200"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<div className="fixed inset-0 bg-backdrop transition-opacity" />
</Transition.Child>
<div className="fixed inset-0 z-20 overflow-y-auto">
<div className="flex min-h-full items-center justify-center p-4 text-center">
<Transition.Child
as={Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
enterTo="opacity-100 translate-y-0 sm:scale-100"
leave="ease-in duration-200"
leaveFrom="opacity-100 translate-y-0 sm:scale-100"
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
>
<Dialog.Panel className="relative w-full transform rounded-lg bg-surface-1 p-5 text-left shadow-raised-200 transition-all sm:w-full sm:max-w-2xl">
<form onSubmit={handleSubmit(onSubmit)}>
<ModalCore isOpen={isOpen} handleClose={handleClose} position={EModalPosition.CENTER} width={EModalWidth.XXL}>
<form onSubmit={handleSubmit(onSubmit)} className="p-5">
<div className="flex items-center justify-between">
<Dialog.Title as="h3" className="text-h5-medium leading-6 text-primary">
Customize Snooze Time
</Dialog.Title>
<h3 className="text-h5-medium leading-6 text-primary">Customize Snooze Time</h3>
<div>
<button type="button" onClick={handleClose}>
@ -201,13 +171,10 @@ export function NotificationSnoozeModal(props: TNotificationSnoozeModal) {
onClick={() => {
setValue("period", "AM");
}}
className={cn(
"flex h-full w-1/2 cursor-pointer items-center justify-center text-center",
{
className={cn("flex h-full w-1/2 cursor-pointer items-center justify-center text-center", {
"bg-accent-primary/90 text-on-color": watch("period") === "AM",
"bg-layer-1": watch("period") !== "AM",
}
)}
})}
>
AM
</div>
@ -215,13 +182,10 @@ export function NotificationSnoozeModal(props: TNotificationSnoozeModal) {
onClick={() => {
setValue("period", "PM");
}}
className={cn(
"flex h-full w-1/2 cursor-pointer items-center justify-center text-center",
{
className={cn("flex h-full w-1/2 cursor-pointer items-center justify-center text-center", {
"bg-accent-primary/90 text-on-color": watch("period") === "PM",
"bg-layer-1": watch("period") !== "PM",
}
)}
})}
>
PM
</div>
@ -254,11 +218,6 @@ export function NotificationSnoozeModal(props: TNotificationSnoozeModal) {
</div>
</div>
</form>
</Dialog.Panel>
</Transition.Child>
</div>
</div>
</Dialog>
</Transition.Root>
</ModalCore>
);
}