mirror of
https://github.com/makeplane/plane
synced 2024-06-14 14:31:34 +00:00
feat: module sidebar date and status updated (#285)
This commit is contained in:
parent
9b51a918cf
commit
f21135d955
@ -1,4 +1,4 @@
|
|||||||
import { useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
|
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
@ -13,10 +13,15 @@ import {
|
|||||||
ChartPieIcon,
|
ChartPieIcon,
|
||||||
LinkIcon,
|
LinkIcon,
|
||||||
PlusIcon,
|
PlusIcon,
|
||||||
|
Squares2X2Icon,
|
||||||
TrashIcon,
|
TrashIcon,
|
||||||
} from "@heroicons/react/24/outline";
|
} from "@heroicons/react/24/outline";
|
||||||
// progress-bar
|
// progress-bar
|
||||||
import { CircularProgressbar } from "react-circular-progressbar";
|
import { CircularProgressbar } from "react-circular-progressbar";
|
||||||
|
|
||||||
|
import { Popover, Transition } from "@headlessui/react";
|
||||||
|
import DatePicker from "react-datepicker";
|
||||||
|
|
||||||
// services
|
// services
|
||||||
import modulesService from "services/modules.service";
|
import modulesService from "services/modules.service";
|
||||||
// hooks
|
// hooks
|
||||||
@ -27,16 +32,15 @@ import {
|
|||||||
ModuleLinkModal,
|
ModuleLinkModal,
|
||||||
SidebarLeadSelect,
|
SidebarLeadSelect,
|
||||||
SidebarMembersSelect,
|
SidebarMembersSelect,
|
||||||
SidebarStatusSelect,
|
|
||||||
} from "components/modules";
|
} from "components/modules";
|
||||||
|
|
||||||
import "react-circular-progressbar/dist/styles.css";
|
import "react-circular-progressbar/dist/styles.css";
|
||||||
// components
|
// components
|
||||||
import { SidebarProgressStats } from "components/core";
|
import { SidebarProgressStats } from "components/core";
|
||||||
// ui
|
// ui
|
||||||
import { CustomDatePicker, Loader } from "components/ui";
|
import { CustomSelect, Loader } from "components/ui";
|
||||||
// helpers
|
// helpers
|
||||||
import { timeAgo } from "helpers/date-time.helper";
|
import { renderShortNumericDateFormat, timeAgo } from "helpers/date-time.helper";
|
||||||
import { copyTextToClipboard } from "helpers/string.helper";
|
import { copyTextToClipboard } from "helpers/string.helper";
|
||||||
import { groupBy } from "helpers/array.helper";
|
import { groupBy } from "helpers/array.helper";
|
||||||
// types
|
// types
|
||||||
@ -44,6 +48,8 @@ import { IIssue, IModule, ModuleIssueResponse } from "types";
|
|||||||
// fetch-keys
|
// fetch-keys
|
||||||
import { MODULE_DETAILS } from "constants/fetch-keys";
|
import { MODULE_DETAILS } from "constants/fetch-keys";
|
||||||
import ProgressChart from "components/core/sidebar/progress-chart";
|
import ProgressChart from "components/core/sidebar/progress-chart";
|
||||||
|
// constant
|
||||||
|
import { MODULE_STATUS } from "constants/module";
|
||||||
|
|
||||||
const defaultValues: Partial<IModule> = {
|
const defaultValues: Partial<IModule> = {
|
||||||
lead: "",
|
lead: "",
|
||||||
@ -63,6 +69,8 @@ type Props = {
|
|||||||
export const ModuleDetailsSidebar: React.FC<Props> = ({ issues, module, isOpen, moduleIssues }) => {
|
export const ModuleDetailsSidebar: React.FC<Props> = ({ issues, module, isOpen, moduleIssues }) => {
|
||||||
const [moduleDeleteModal, setModuleDeleteModal] = useState(false);
|
const [moduleDeleteModal, setModuleDeleteModal] = useState(false);
|
||||||
const [moduleLinkModal, setModuleLinkModal] = useState(false);
|
const [moduleLinkModal, setModuleLinkModal] = useState(false);
|
||||||
|
const [startDateRange, setStartDateRange] = useState<Date | null>(new Date());
|
||||||
|
const [endDateRange, setEndDateRange] = useState<Date | null>(null);
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug, projectId, moduleId } = router.query;
|
const { workspaceSlug, projectId, moduleId } = router.query;
|
||||||
@ -134,6 +142,91 @@ export const ModuleDetailsSidebar: React.FC<Props> = ({ issues, module, isOpen,
|
|||||||
>
|
>
|
||||||
{module ? (
|
{module ? (
|
||||||
<>
|
<>
|
||||||
|
<div className="flex gap-1 text-sm my-2">
|
||||||
|
<div className="flex items-center ">
|
||||||
|
<Controller
|
||||||
|
control={control}
|
||||||
|
name="status"
|
||||||
|
render={({ field: { value } }) => (
|
||||||
|
<CustomSelect
|
||||||
|
label={
|
||||||
|
<span
|
||||||
|
className={`flex items-center gap-1 text-left capitalize p-1 text-xs h-full w-full text-gray-900`}
|
||||||
|
>
|
||||||
|
<Squares2X2Icon className="h-4 w-4 flex-shrink-0" />
|
||||||
|
{watch("status")}
|
||||||
|
</span>
|
||||||
|
}
|
||||||
|
value={value}
|
||||||
|
onChange={(value: any) => {
|
||||||
|
submitChanges({ status: value });
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{MODULE_STATUS.map((option) => (
|
||||||
|
<CustomSelect.Option key={option.value} value={option.value}>
|
||||||
|
<span className="text-xs">{option.label}</span>
|
||||||
|
</CustomSelect.Option>
|
||||||
|
))}
|
||||||
|
</CustomSelect>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<Popover className="flex justify-center items-center relative rounded-lg">
|
||||||
|
{({ open }) => (
|
||||||
|
<>
|
||||||
|
<Popover.Button
|
||||||
|
className={`group flex items-center gap-2 rounded-md border bg-transparent h-full w-full p-2 px-4 text-xs font-medium text-gray-900 hover:bg-gray-100 hover:text-gray-900 focus:outline-none ${
|
||||||
|
open ? "bg-gray-100" : ""
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<CalendarDaysIcon className="h-4 w-4 flex-shrink-0" />
|
||||||
|
<span>
|
||||||
|
{renderShortNumericDateFormat(`${module?.start_date}`)
|
||||||
|
? renderShortNumericDateFormat(`${module?.start_date}`)
|
||||||
|
: "N/A"}{" "}
|
||||||
|
-{" "}
|
||||||
|
{renderShortNumericDateFormat(`${module?.target_date}`)
|
||||||
|
? renderShortNumericDateFormat(`${module?.target_date}`)
|
||||||
|
: "N/A"}
|
||||||
|
</span>
|
||||||
|
</Popover.Button>
|
||||||
|
|
||||||
|
<Transition
|
||||||
|
as={React.Fragment}
|
||||||
|
enter="transition ease-out duration-200"
|
||||||
|
enterFrom="opacity-0 translate-y-1"
|
||||||
|
enterTo="opacity-100 translate-y-0"
|
||||||
|
leave="transition ease-in duration-150"
|
||||||
|
leaveFrom="opacity-100 translate-y-0"
|
||||||
|
leaveTo="opacity-0 translate-y-1"
|
||||||
|
>
|
||||||
|
<Popover.Panel className="absolute top-10 left-0 z-20 transform overflow-hidden">
|
||||||
|
<DatePicker
|
||||||
|
selected={startDateRange}
|
||||||
|
onChange={(dates) => {
|
||||||
|
const [start, end] = dates;
|
||||||
|
submitChanges({
|
||||||
|
start_date: start?.toISOString(),
|
||||||
|
target_date: end?.toISOString(),
|
||||||
|
});
|
||||||
|
if (setStartDateRange) {
|
||||||
|
setStartDateRange(start);
|
||||||
|
}
|
||||||
|
if (setEndDateRange) {
|
||||||
|
setEndDateRange(end);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
startDate={startDateRange}
|
||||||
|
endDate={endDateRange}
|
||||||
|
selectsRange
|
||||||
|
inline
|
||||||
|
/>
|
||||||
|
</Popover.Panel>
|
||||||
|
</Transition>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</Popover>
|
||||||
|
</div>
|
||||||
<div className="flex items-center justify-between pb-3">
|
<div className="flex items-center justify-between pb-3">
|
||||||
<h4 className="text-sm font-medium">{module.name}</h4>
|
<h4 className="text-sm font-medium">{module.name}</h4>
|
||||||
<div className="flex flex-wrap items-center gap-2">
|
<div className="flex flex-wrap items-center gap-2">
|
||||||
@ -196,59 +289,6 @@ export const ModuleDetailsSidebar: React.FC<Props> = ({ issues, module, isOpen,
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="py-1">
|
|
||||||
<div className="flex flex-wrap items-center py-2">
|
|
||||||
<div className="flex items-center gap-x-2 text-sm sm:basis-1/2">
|
|
||||||
<CalendarDaysIcon className="h-4 w-4 flex-shrink-0" />
|
|
||||||
<p>Start date</p>
|
|
||||||
</div>
|
|
||||||
<div className="sm:basis-1/2">
|
|
||||||
<Controller
|
|
||||||
control={control}
|
|
||||||
name="start_date"
|
|
||||||
render={({ field: { value } }) => (
|
|
||||||
<CustomDatePicker
|
|
||||||
value={value}
|
|
||||||
onChange={(val) =>
|
|
||||||
submitChanges({
|
|
||||||
start_date: val,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="flex flex-wrap items-center py-2">
|
|
||||||
<div className="flex items-center gap-x-2 text-sm sm:basis-1/2">
|
|
||||||
<CalendarDaysIcon className="h-4 w-4 flex-shrink-0" />
|
|
||||||
<p>End date</p>
|
|
||||||
</div>
|
|
||||||
<div className="sm:basis-1/2">
|
|
||||||
<Controller
|
|
||||||
control={control}
|
|
||||||
name="target_date"
|
|
||||||
render={({ field: { value } }) => (
|
|
||||||
<CustomDatePicker
|
|
||||||
value={value}
|
|
||||||
onChange={(val) =>
|
|
||||||
submitChanges({
|
|
||||||
target_date: val,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="py-1">
|
|
||||||
<SidebarStatusSelect
|
|
||||||
control={control}
|
|
||||||
submitChanges={submitChanges}
|
|
||||||
watch={watch}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="py-1">
|
<div className="py-1">
|
||||||
<div className="flex items-center justify-between gap-2">
|
<div className="flex items-center justify-between gap-2">
|
||||||
<h4>Links</h4>
|
<h4>Links</h4>
|
||||||
|
Loading…
Reference in New Issue
Block a user