diff --git a/apps/app/components/core/issues-view-filter.tsx b/apps/app/components/core/issues-view-filter.tsx index 5d6c909fe..6868cf7b0 100644 --- a/apps/app/components/core/issues-view-filter.tsx +++ b/apps/app/components/core/issues-view-filter.tsx @@ -134,7 +134,7 @@ export const IssuesFilterView: React.FC = () => { leaveFrom="opacity-100 translate-y-0" leaveTo="opacity-0 translate-y-1" > - +
{issueView !== "calendar" && ( diff --git a/apps/app/components/cycles/completed-cycles-list.tsx b/apps/app/components/cycles/completed-cycles-list.tsx index bf1971368..6729ceeeb 100644 --- a/apps/app/components/cycles/completed-cycles-list.tsx +++ b/apps/app/components/cycles/completed-cycles-list.tsx @@ -65,7 +65,11 @@ export const CompletedCyclesList: React.FC = ({ completedCycles.completed_cycles.length > 0 ? (
- + Completed cycles are not editable.
diff --git a/apps/app/components/cycles/form.tsx b/apps/app/components/cycles/form.tsx index f977bc74b..a0bd781ce 100644 --- a/apps/app/components/cycles/form.tsx +++ b/apps/app/components/cycles/form.tsx @@ -1,21 +1,10 @@ -import { useEffect, useState } from "react"; - -import { useRouter } from "next/router"; +import { useEffect } from "react"; // react-hook-form import { Controller, useForm } from "react-hook-form"; -// services -import cyclesService from "services/cycles.service"; -// hooks -import useToast from "hooks/use-toast"; + // ui import { DateSelect, Input, PrimaryButton, SecondaryButton, TextArea } from "components/ui"; -// helpers -import { - getDateRangeStatus, - isDateGreaterThanToday, - isDateRangeValid, -} from "helpers/date-time.helper"; // types import { ICycle } from "types"; @@ -34,13 +23,6 @@ const defaultValues: Partial = { }; export const CycleForm: React.FC = ({ handleFormSubmit, handleClose, status, data }) => { - const router = useRouter(); - const { workspaceSlug, projectId } = router.query; - - const { setToastAlert } = useToast(); - - const [isDateValid, setIsDateValid] = useState(true); - const { register, formState: { errors, isSubmitting }, @@ -60,43 +42,6 @@ export const CycleForm: React.FC = ({ handleFormSubmit, handleClose, stat }); }; - const cycleStatus = - data?.start_date && data?.end_date ? getDateRangeStatus(data?.start_date, data?.end_date) : ""; - - const dateChecker = async (payload: any) => { - if (isDateGreaterThanToday(payload.end_date)) { - await cyclesService - .cycleDateCheck(workspaceSlug as string, projectId as string, payload) - .then((res) => { - if (res.status) { - setIsDateValid(true); - } else { - setIsDateValid(false); - setToastAlert({ - type: "error", - title: "Error!", - message: - "You have a cycle already on the given dates, if you want to create your draft cycle you can do that by removing dates", - }); - } - }) - .catch((err) => { - console.log(err); - }); - } else { - setIsDateValid(false); - setToastAlert({ - type: "error", - title: "Error!", - message: "Unable to create cycle in past date. Please enter a valid date.", - }); - } - }; - - const checkEmptyDate = - (watch("start_date") === "" && watch("end_date") === "") || - (!watch("start_date") && !watch("end_date")); - useEffect(() => { reset({ ...defaultValues, @@ -147,30 +92,7 @@ export const CycleForm: React.FC = ({ handleFormSubmit, handleClose, stat control={control} name="start_date" render={({ field: { value, onChange } }) => ( - { - onChange(val); - if (val && watch("end_date")) { - if (isDateRangeValid(val, `${watch("end_date")}`)) { - cycleStatus != "current" && - dateChecker({ - start_date: val, - end_date: watch("end_date"), - }); - } else { - setIsDateValid(false); - setToastAlert({ - type: "error", - title: "Error!", - message: - "The date you have entered is invalid. Please check and enter a valid date.", - }); - } - } - }} - /> + onChange(val)} /> )} />
@@ -179,30 +101,7 @@ export const CycleForm: React.FC = ({ handleFormSubmit, handleClose, stat control={control} name="end_date" render={({ field: { value, onChange } }) => ( - { - onChange(val); - if (watch("start_date") && val) { - if (isDateRangeValid(`${watch("start_date")}`, val)) { - cycleStatus != "current" && - dateChecker({ - start_date: watch("start_date"), - end_date: val, - }); - } else { - setIsDateValid(false); - setToastAlert({ - type: "error", - title: "Error!", - message: - "The date you have entered is invalid. Please check and enter a valid date.", - }); - } - } - }} - /> + onChange(val)} /> )} />
@@ -211,18 +110,7 @@ export const CycleForm: React.FC = ({ handleFormSubmit, handleClose, stat
Cancel - + {status ? isSubmitting ? "Updating Cycle..." diff --git a/apps/app/components/cycles/modal.tsx b/apps/app/components/cycles/modal.tsx index cd439c372..968c6f46e 100644 --- a/apps/app/components/cycles/modal.tsx +++ b/apps/app/components/cycles/modal.tsx @@ -13,7 +13,7 @@ import useToast from "hooks/use-toast"; // components import { CycleForm } from "components/cycles"; // helper -import { getDateRangeStatus } from "helpers/date-time.helper"; +import { getDateRangeStatus, isDateGreaterThanToday } from "helpers/date-time.helper"; // types import type { ICycle } from "types"; // fetch keys @@ -128,6 +128,21 @@ export const CreateUpdateCycleModal: React.FC = ({ }); }; + const dateChecker = async (payload: any) => { + try { + const res = await cycleService.cycleDateCheck( + workspaceSlug as string, + projectId as string, + payload + ); + console.log(res); + return res.status; + } catch (err) { + console.log(err); + return false; + } + }; + const handleFormSubmit = async (formData: Partial) => { if (!workspaceSlug || !projectId) return; @@ -135,8 +150,63 @@ export const CreateUpdateCycleModal: React.FC = ({ ...formData, }; - if (!data) await createCycle(payload); - else await updateCycle(data.id, payload); + if (payload.start_date && payload.end_date) { + if (!isDateGreaterThanToday(payload.end_date)) { + setToastAlert({ + type: "error", + title: "Error!", + message: "Unable to create cycle in past date. Please enter a valid date.", + }); + return; + } + + const isDateValid = await dateChecker({ + start_date: payload.start_date, + end_date: payload.end_date, + }); + + if (data?.start_date && data?.end_date) { + const isDateValidForExistingCycle = await dateChecker({ + start_date: payload.start_date, + end_date: payload.end_date, + cycle_id: data.id, + }); + + if (isDateValidForExistingCycle) { + await updateCycle(data.id, payload); + return; + } else { + setToastAlert({ + type: "error", + title: "Error!", + message: + "You have a cycle already on the given dates, if you want to create your draft cycle you can do that by removing dates", + }); + return; + } + } + + if (isDateValid) { + if (data) { + await updateCycle(data.id, payload); + } else { + await createCycle(payload); + } + } else { + setToastAlert({ + type: "error", + title: "Error!", + message: + "You have a cycle already on the given dates, if you want to create your draft cycle you can do that by removing dates", + }); + } + } else { + if (data) { + await updateCycle(data.id, payload); + } else { + await createCycle(payload); + } + } }; return ( diff --git a/apps/app/components/cycles/sidebar.tsx b/apps/app/components/cycles/sidebar.tsx index 863da7934..91e592e7d 100644 --- a/apps/app/components/cycles/sidebar.tsx +++ b/apps/app/components/cycles/sidebar.tsx @@ -370,7 +370,11 @@ export const CycleDetailsSidebar: React.FC = ({ ) : (
- + {cycleStatus === "upcoming" ? "Cycle is yet to start." @@ -444,7 +448,11 @@ export const CycleDetailsSidebar: React.FC = ({ ) : (
- + No issues found. Please add issue. diff --git a/apps/app/components/cycles/transfer-issues-modal.tsx b/apps/app/components/cycles/transfer-issues-modal.tsx index 366ef67f7..c857e154e 100644 --- a/apps/app/components/cycles/transfer-issues-modal.tsx +++ b/apps/app/components/cycles/transfer-issues-modal.tsx @@ -148,7 +148,11 @@ export const TransferIssuesModal: React.FC = ({ isOpen, handleClose }) => )) ) : (
- + You don’t have any current cycle. Please create one to transfer the issues. diff --git a/apps/app/components/cycles/transfer-issues.tsx b/apps/app/components/cycles/transfer-issues.tsx index 067147bed..77b1f59f1 100644 --- a/apps/app/components/cycles/transfer-issues.tsx +++ b/apps/app/components/cycles/transfer-issues.tsx @@ -39,7 +39,7 @@ export const TransferIssues: React.FC = ({ handleClick }) => { return (
- + Completed cycles are not editable.
diff --git a/apps/app/components/icons/exclamation-icon.tsx b/apps/app/components/icons/exclamation-icon.tsx index d904263f5..243329647 100644 --- a/apps/app/components/icons/exclamation-icon.tsx +++ b/apps/app/components/icons/exclamation-icon.tsx @@ -3,14 +3,14 @@ import React from "react"; import type { Props } from "./types"; export const ExclamationIcon: React.FC = ({ width, height, className }) => ( - - - - ); + + + +); diff --git a/apps/app/components/issues/activity.tsx b/apps/app/components/issues/activity.tsx index b3e419e17..87c3cf5b6 100644 --- a/apps/app/components/issues/activity.tsx +++ b/apps/app/components/issues/activity.tsx @@ -231,6 +231,16 @@ export const IssueActivitySection: React.FC = () => { action = `${activityItem.verb} the`; } else if (activityItem.field === "estimate") { action = "updated the"; + } else if (activityItem.field === "cycles") { + action = + activityItem.new_value && activityItem.new_value !== "" + ? "set the cycle to" + : "removed the cycle"; + } else if (activityItem.field === "modules") { + action = + activityItem.new_value && activityItem.new_value !== "" + ? "set the module to" + : "removed the module"; } // for values that are after the action clause let value: any = activityItem.new_value ? activityItem.new_value : activityItem.old_value; @@ -282,6 +292,18 @@ export const IssueActivitySection: React.FC = () => { value = "description"; } else if (activityItem.field === "attachment") { value = "attachment"; + } else if (activityItem.field === "cycles") { + const cycles = + activityItem.new_value && activityItem.new_value !== "" + ? activityItem.new_value + : activityItem.old_value; + value = cycles ? addSpaceIfCamelCase(cycles) : "None"; + } else if (activityItem.field === "modules") { + const modules = + activityItem.new_value && activityItem.new_value !== "" + ? activityItem.new_value + : activityItem.old_value; + value = modules ? addSpaceIfCamelCase(modules) : "None"; } else if (activityItem.field === "link") { value = "link"; } else if (activityItem.field === "estimate_point") { diff --git a/apps/app/components/issues/attachments.tsx b/apps/app/components/issues/attachments.tsx index 13fc0d972..7f4be47dd 100644 --- a/apps/app/components/issues/attachments.tsx +++ b/apps/app/components/issues/attachments.tsx @@ -82,7 +82,7 @@ export const IssueAttachments = () => { } uploaded on ${renderLongDateFormat(file.updated_at)}`} > - +
diff --git a/apps/app/components/issues/my-issues-list-item.tsx b/apps/app/components/issues/my-issues-list-item.tsx index ebf063719..648cb4bbe 100644 --- a/apps/app/components/issues/my-issues-list-item.tsx +++ b/apps/app/components/issues/my-issues-list-item.tsx @@ -82,7 +82,7 @@ export const MyIssuesListItem: React.FC = ({ issue, properties, projectId const isNotAllowed = false; return ( -
+
@@ -91,13 +91,13 @@ export const MyIssuesListItem: React.FC = ({ issue, properties, projectId tooltipHeading="Issue ID" tooltipContent={`${issue.project_detail?.identifier}-${issue.sequence_id}`} > - + {issue.project_detail?.identifier}-{issue.sequence_id} )} - + {truncateText(issue.name, 50)} @@ -127,7 +127,7 @@ export const MyIssuesListItem: React.FC = ({ issue, properties, projectId /> )} {properties.sub_issue_count && ( -
+
{issue?.sub_issues_count} {issue?.sub_issues_count === 1 ? "sub-issue" : "sub-issues"}
)} @@ -136,10 +136,10 @@ export const MyIssuesListItem: React.FC = ({ issue, properties, projectId {issue.label_details.map((label) => ( = ({ issue, properties, projectId )} {properties.link && ( -
+
-
- +
+ {issue.link_count}
)} {properties.attachment_count && ( -
+
-
- +
+ {issue.attachment_count}
diff --git a/apps/app/components/issues/sidebar-select/cycle.tsx b/apps/app/components/issues/sidebar-select/cycle.tsx index c412c9fda..7db9cd906 100644 --- a/apps/app/components/issues/sidebar-select/cycle.tsx +++ b/apps/app/components/issues/sidebar-select/cycle.tsx @@ -78,7 +78,7 @@ export const SidebarCycleSelect: React.FC = ({ } - value={issueCycle?.cycle_detail.id} + value={issueCycle ? issueCycle.cycle_detail.id : null} onChange={(value: any) => { !value ? removeIssueFromCycle(issueCycle?.id ?? "", issueCycle?.cycle ?? "") diff --git a/apps/app/components/issues/sidebar-select/module.tsx b/apps/app/components/issues/sidebar-select/module.tsx index 282ccb533..d1b0f999b 100644 --- a/apps/app/components/issues/sidebar-select/module.tsx +++ b/apps/app/components/issues/sidebar-select/module.tsx @@ -82,7 +82,7 @@ export const SidebarModuleSelect: React.FC = ({ } - value={issueModule?.module_detail?.id} + value={issueModule ? issueModule.module_detail?.id : null} onChange={(value: any) => { !value ? removeIssueFromModule(issueModule?.id ?? "", issueModule?.module ?? "") diff --git a/apps/app/components/modules/sidebar.tsx b/apps/app/components/modules/sidebar.tsx index 3b3076e05..e5a932608 100644 --- a/apps/app/components/modules/sidebar.tsx +++ b/apps/app/components/modules/sidebar.tsx @@ -416,7 +416,11 @@ export const ModuleDetailsSidebar: React.FC = ({ issues, module, isOpen, ) : (
- + Invalid date. Please enter valid date. @@ -488,7 +492,11 @@ export const ModuleDetailsSidebar: React.FC = ({ issues, module, isOpen, ) : (
- + No issues found. Please add issue. diff --git a/apps/app/components/modules/single-module-card.tsx b/apps/app/components/modules/single-module-card.tsx index f7192de6f..c4a580db5 100644 --- a/apps/app/components/modules/single-module-card.tsx +++ b/apps/app/components/modules/single-module-card.tsx @@ -44,7 +44,8 @@ export const SingleModuleCard: React.FC = ({ module, handleEditModule }) const { setToastAlert } = useToast(); - const completionPercentage = (module.completed_issues / module.total_issues) * 100; + const completionPercentage = + ((module.completed_issues + module.cancelled_issues) / module.total_issues) * 100; const handleDeleteModule = () => { if (!module) return; diff --git a/apps/app/components/pages/single-page-detailed-item.tsx b/apps/app/components/pages/single-page-detailed-item.tsx index 9c025f21d..4be70384e 100644 --- a/apps/app/components/pages/single-page-detailed-item.tsx +++ b/apps/app/components/pages/single-page-detailed-item.tsx @@ -162,7 +162,7 @@ export const SinglePageDetailedItem: React.FC = ({ } on ${renderLongDateFormat(`${page.created_at}`)}`} > - + diff --git a/apps/app/components/pages/single-page-list-item.tsx b/apps/app/components/pages/single-page-list-item.tsx index bb9589502..876d94102 100644 --- a/apps/app/components/pages/single-page-list-item.tsx +++ b/apps/app/components/pages/single-page-list-item.tsx @@ -161,7 +161,7 @@ export const SinglePageListItem: React.FC = ({ } on ${renderLongDateFormat(`${page.created_at}`)}`} > - + diff --git a/apps/app/components/project/single-sidebar-project.tsx b/apps/app/components/project/single-sidebar-project.tsx index a3f265032..4ff2b2cd3 100644 --- a/apps/app/components/project/single-sidebar-project.tsx +++ b/apps/app/components/project/single-sidebar-project.tsx @@ -172,8 +172,8 @@ export const SingleSidebarProject: React.FC = ({
diff --git a/apps/app/components/workspace/sidebar-menu.tsx b/apps/app/components/workspace/sidebar-menu.tsx index 58712a30b..8e5bc65ab 100644 --- a/apps/app/components/workspace/sidebar-menu.tsx +++ b/apps/app/components/workspace/sidebar-menu.tsx @@ -47,8 +47,8 @@ export const WorkspaceSidebarMenu: React.FC = () => { ? router.asPath === link.href : router.asPath.includes(link.href) ) - ? "bg-brand-base text-brand-base" - : "text-brand-secondary hover:bg-brand-surface-1 hover:text-brand-secondary focus:bg-brand-base focus:text-brand-secondary" + ? "bg-brand-surface-2 text-brand-base" + : "text-brand-secondary hover:bg-brand-surface-2 hover:text-brand-secondary focus:bg-brand-surface-2 focus:text-brand-secondary" } group flex w-full items-center gap-3 rounded-md p-2 text-sm font-medium outline-none ${ sidebarCollapse ? "justify-center" : "" }`} diff --git a/apps/app/pages/[workspaceSlug]/me/my-issues.tsx b/apps/app/pages/[workspaceSlug]/me/my-issues.tsx index 8e48db44a..610502b08 100644 --- a/apps/app/pages/[workspaceSlug]/me/my-issues.tsx +++ b/apps/app/pages/[workspaceSlug]/me/my-issues.tsx @@ -52,7 +52,7 @@ const MyIssuesPage: NextPage = () => { <> View @@ -69,29 +69,27 @@ const MyIssuesPage: NextPage = () => { leaveTo="opacity-0 translate-y-1" > -
-
-

Properties

-
- {Object.keys(properties).map((key) => { - if (key === "estimate") return null; +
+

Properties

+
+ {Object.keys(properties).map((key) => { + if (key === "estimate") return null; - return ( - - ); - })} -
+ return ( + + ); + })}
@@ -107,7 +105,7 @@ const MyIssuesPage: NextPage = () => { document.dispatchEvent(e); }} > - + Add Issue
diff --git a/apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/integrations.tsx b/apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/integrations.tsx index 101044f5c..7d8592400 100644 --- a/apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/integrations.tsx +++ b/apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/integrations.tsx @@ -16,6 +16,7 @@ import { EmptySpace, EmptySpaceItem, Loader } from "components/ui"; import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs"; // icons import { PlusIcon, PuzzlePieceIcon } from "@heroicons/react/24/outline"; +import { ExclamationIcon } from "components/icons"; // types import { IProject } from "types"; import type { NextPage } from "next"; @@ -56,7 +57,17 @@ const ProjectIntegrations: NextPage = () => { {workspaceIntegrations ? ( workspaceIntegrations.length > 0 ? (
-

Integrations

+
+

Integrations

+
+ +

+ Integrations and importers are only available on the cloud version. We plan to + open-source our SDKs in the near future so that the community can request or + contribute integrations as needed. +

+
+
{workspaceIntegrations.map((integration) => ( { } >
-

Integrations

+
+

Integrations

+
+ +

+ Integrations and importers are only available on the cloud version. We plan to + open-source our SDKs in the near future so that the community can request or + contribute integrations as needed. +

+
+
{appIntegrations ? ( appIntegrations.map((integration) => ( diff --git a/apps/app/pages/_app.tsx b/apps/app/pages/_app.tsx index 6f372b4e3..0f50b3b8c 100644 --- a/apps/app/pages/_app.tsx +++ b/apps/app/pages/_app.tsx @@ -8,6 +8,7 @@ import "styles/globals.css"; import "styles/editor.css"; import "styles/command-pallette.css"; import "styles/nprogress.css"; +import "styles/react-datepicker.css"; // router import Router from "next/router"; diff --git a/apps/app/styles/react-datepicker.css b/apps/app/styles/react-datepicker.css new file mode 100644 index 000000000..3c5f9a5ca --- /dev/null +++ b/apps/app/styles/react-datepicker.css @@ -0,0 +1,118 @@ +.react-datepicker-wrapper input::placeholder { + color: rgba(var(--color-text-secondary)); + opacity: 1; +} + +.react-datepicker-wrapper input:-ms-input-placeholder { + color: rgba(var(--color-text-secondary)); +} + +.react-datepicker-wrapper .react-datepicker__close-icon::after { + background: transparent; + color: rgba(var(--color-text-secondary)); +} + +.react-datepicker-popper { + z-index: 30 !important; +} + +.react-datepicker-wrapper { + position: relative; + background-color: rgba(var(--color-bg-base)) !important; +} + +.react-datepicker { + font-family: "Inter" !important; + border: none !important; + background-color: rgba(var(--color-bg-base)) !important; +} + +.react-datepicker__month-container { + width: 300px; + background-color: rgba(var(--color-bg-base)) !important; + color: rgba(var(--color-text-base)) !important; + border-radius: 10px !important; + /* border: 1px solid rgba(var(--color-border)) !important; */ +} + +.react-datepicker__header { + border-radius: 10px !important; + background-color: rgba(var(--color-bg-base)) !important; + border: none !important; +} + +.react-datepicker__navigation { + line-height: 0.78; +} + +.react-datepicker__triangle { + border-color: rgba(var(--color-bg-base)) transparent transparent transparent !important; +} + +.react-datepicker__triangle:before { + border-bottom-color: rgba(var(--color-border)) !important; +} +.react-datepicker__triangle:after { + border-bottom-color: rgba(var(--color-bg-base)) !important; +} + +.react-datepicker__current-month { + font-weight: 500 !important; + color: rgba(var(--color-text-base)) !important; +} + +.react-datepicker__month { + border-collapse: collapse; + color: rgba(var(--color-text-base)) !important; +} + +.react-datepicker__day-names { + margin-top: 10px; + margin-left: 14px; + width: 280px; + display: grid; + grid-template-columns: repeat(7, 1fr); + gap: 0; +} + +.react-datepicker__day-name { + color: rgba(var(--color-text-base)) !important; +} + +.react-datepicker__week { + display: grid; + grid-template-columns: repeat(7, 1fr); + margin-left: 8px; +} + +.react-datepicker__day { + color: rgba(var(--color-text-base)) !important; +} + +.react-datepicker__day { + border-radius: 50% !important; + transition: all 0.15s ease-in-out; +} + +.react-datepicker__day:hover { + background-color: rgba(var(--color-bg-surface-2)) !important; + color: rgba(var(--color-text-base)) !important; +} + +.react-datepicker__day--selected { + background-color: #216ba5 !important; + color: white !important; +} + +.react-datepicker__day--today { + font-weight: 800; +} + +.react-datepicker__day--highlighted { + background-color: rgba(var(--color-bg-surface-2)) !important; +} + +.react-datepicker__day--keyboard-selected { + background-color: #216ba5 !important; + color: white !important; +}