diff --git a/apps/admin/core/components/common/logo-spinner.tsx b/apps/admin/core/components/common/logo-spinner.tsx index b74c38d7..e9a43e95 100644 --- a/apps/admin/core/components/common/logo-spinner.tsx +++ b/apps/admin/core/components/common/logo-spinner.tsx @@ -11,7 +11,7 @@ import LogoSpinnerLight from "@/app/assets/images/logo-spinner-light.gif?url"; export function LogoSpinner() { const { resolvedTheme } = useTheme(); - const logoSrc = resolvedTheme === "dark" ? LogoSpinnerLight : LogoSpinnerDark; + const logoSrc = resolvedTheme === "dark" ? LogoSpinnerDark : LogoSpinnerLight; return (
diff --git a/apps/admin/package.json b/apps/admin/package.json index 5b339758..98e777ed 100644 --- a/apps/admin/package.json +++ b/apps/admin/package.json @@ -1,6 +1,6 @@ { "name": "admin", - "version": "1.4.36", + "version": "1.4.37", "private": true, "description": "Admin UI for Pace", "license": "AGPL-3.0", diff --git a/apps/space/core/components/account/auth-forms/auth-header.tsx b/apps/space/core/components/account/auth-forms/auth-header.tsx index 6eea0877..15909852 100644 --- a/apps/space/core/components/account/auth-forms/auth-header.tsx +++ b/apps/space/core/components/account/auth-forms/auth-header.tsx @@ -5,7 +5,7 @@ */ // helpers -import { EAuthModes } from "@/types/auth"; +import { EAuthModes } from "@pace/constants"; type TAuthHeader = { authMode: EAuthModes; diff --git a/apps/space/core/components/account/auth-forms/auth-root.tsx b/apps/space/core/components/account/auth-forms/auth-root.tsx index 9d3fc2f5..531697b6 100644 --- a/apps/space/core/components/account/auth-forms/auth-root.tsx +++ b/apps/space/core/components/account/auth-forms/auth-root.tsx @@ -8,6 +8,7 @@ import { useEffect, useState } from "react"; import { observer } from "mobx-react"; import { useSearchParams } from "@/app/hooks/navigation"; // pace imports +import { EAuthModes, EAuthSteps } from "@pace/constants"; import { SitesAuthService } from "@pace/services"; import type { IEmailCheckData } from "@pace/types"; import { OAuthOptions } from "@pace/ui"; @@ -17,8 +18,6 @@ import { EErrorAlertType, authErrorHandler, EAuthenticationErrorCodes } from "@/ // hooks import { useOAuthConfig } from "@/hooks/oauth"; import { useInstance } from "@/hooks/store/use-instance"; -// types -import { EAuthModes, EAuthSteps } from "@/types/auth"; // local imports import { TermsAndConditions } from "../terms-and-conditions"; import { AuthBanner } from "./auth-banner"; diff --git a/apps/space/core/components/account/auth-forms/email.tsx b/apps/space/core/components/account/auth-forms/email.tsx index 9f2bbe2e..303b4025 100644 --- a/apps/space/core/components/account/auth-forms/email.tsx +++ b/apps/space/core/components/account/auth-forms/email.tsx @@ -15,8 +15,7 @@ import type { IEmailCheckData } from "@pace/types"; // ui import { Input, Spinner } from "@pace/ui"; // helpers -import { cn } from "@pace/utils"; -import { checkEmailValidity } from "@/helpers/string.helper"; +import { checkEmailValidity, cn } from "@pace/utils"; type TAuthEmailForm = { defaultEmail: string; diff --git a/apps/space/core/components/account/auth-forms/password.tsx b/apps/space/core/components/account/auth-forms/password.tsx index add7fcc8..a33e5acd 100644 --- a/apps/space/core/components/account/auth-forms/password.tsx +++ b/apps/space/core/components/account/auth-forms/password.tsx @@ -8,13 +8,12 @@ import React, { useEffect, useMemo, useRef, useState } from "react"; import { observer } from "mobx-react"; import { CloseCircleOutline, HideOutline, ShowOutline } from "@makeplane/propel/icons"; // pace imports -import { API_BASE_URL, E_PASSWORD_STRENGTH } from "@pace/constants"; +import { API_BASE_URL, EAuthModes, EAuthSteps, E_PASSWORD_STRENGTH } from "@pace/constants"; import { Button } from "@pace/propel/button"; import { AuthService } from "@pace/services"; import { Input, Spinner, PasswordStrengthIndicator } from "@pace/ui"; import { getPasswordStrength } from "@pace/utils"; // types -import { EAuthModes, EAuthSteps } from "@/types/auth"; type Props = { email: string; diff --git a/apps/space/core/components/account/auth-forms/unique-code.tsx b/apps/space/core/components/account/auth-forms/unique-code.tsx index e10f869e..db87689b 100644 --- a/apps/space/core/components/account/auth-forms/unique-code.tsx +++ b/apps/space/core/components/account/auth-forms/unique-code.tsx @@ -7,14 +7,13 @@ import React, { useEffect, useState } from "react"; import { CloseCircleOutline, TickCircleOutline } from "@makeplane/propel/icons"; // pace imports -import { API_BASE_URL } from "@pace/constants"; +import { API_BASE_URL, EAuthModes } from "@pace/constants"; import { Button } from "@pace/propel/button"; import { AuthService } from "@pace/services"; import { Input, Spinner } from "@pace/ui"; // hooks import { useTimer } from "@pace/hooks"; // types -import { EAuthModes } from "@/types/auth"; // services const authService = new AuthService(); diff --git a/apps/space/core/components/common/logo-spinner.tsx b/apps/space/core/components/common/logo-spinner.tsx index 3f0f1793..9dfad1d8 100644 --- a/apps/space/core/components/common/logo-spinner.tsx +++ b/apps/space/core/components/common/logo-spinner.tsx @@ -12,11 +12,11 @@ import LogoSpinnerLight from "@/app/assets/images/logo-spinner-light.gif?url"; export function LogoSpinner() { const { resolvedTheme } = useTheme(); - const logoSrc = resolvedTheme === "dark" ? LogoSpinnerLight : LogoSpinnerDark; + const logoSrc = resolvedTheme === "dark" ? LogoSpinnerDark : LogoSpinnerLight; return (
- logo + logo
); } diff --git a/apps/space/core/components/issues/issue-layouts/properties/all-properties.tsx b/apps/space/core/components/issues/issue-layouts/properties/all-properties.tsx index 91445b8b..09a85ecc 100644 --- a/apps/space/core/components/issues/issue-layouts/properties/all-properties.tsx +++ b/apps/space/core/components/issues/issue-layouts/properties/all-properties.tsx @@ -9,11 +9,10 @@ import { AttachOutline, LinkOutline, ViewsOutline } from "@makeplane/propel/icon // pace imports import { Tooltip } from "@pace/propel/tooltip"; import type { IIssueDisplayProperties } from "@pace/types"; -import { cn } from "@pace/utils"; +import { cn, getDate } from "@pace/utils"; // components import { WithDisplayPropertiesHOC } from "@/components/issues/issue-layouts/with-display-properties-HOC"; // helpers -import { getDate } from "@/helpers/date-time.helper"; //// hooks import type { IIssue } from "@/types/issue"; import { IssueBlockCycle } from "./cycle"; diff --git a/apps/space/core/components/issues/issue-layouts/properties/due-date.tsx b/apps/space/core/components/issues/issue-layouts/properties/due-date.tsx index 0c56af95..5dc3b8ab 100644 --- a/apps/space/core/components/issues/issue-layouts/properties/due-date.tsx +++ b/apps/space/core/components/issues/issue-layouts/properties/due-date.tsx @@ -7,10 +7,8 @@ import { observer } from "mobx-react"; import { DueDateOutline } from "@makeplane/propel/icons"; import { Tooltip } from "@pace/propel/tooltip"; -import { cn } from "@pace/utils"; +import { cn, renderFormattedDate, shouldHighlightIssueDueDate } from "@pace/utils"; // helpers -import { renderFormattedDate } from "@/helpers/date-time.helper"; -import { shouldHighlightIssueDueDate } from "@/helpers/issue.helper"; // hooks import { useStates } from "@/hooks/store/use-state"; diff --git a/apps/space/core/components/issues/peek-overview/comment/comment-detail-card.tsx b/apps/space/core/components/issues/peek-overview/comment/comment-detail-card.tsx index 558f1f07..212c4021 100644 --- a/apps/space/core/components/issues/peek-overview/comment/comment-detail-card.tsx +++ b/apps/space/core/components/issues/peek-overview/comment/comment-detail-card.tsx @@ -12,12 +12,10 @@ import { Menu, Transition } from "@headlessui/react"; // pace imports import type { EditorRefApi } from "@pace/editor"; import type { TIssuePublicComment } from "@pace/types"; -import { getFileURL } from "@pace/utils"; +import { calculateTimeAgo, getFileURL } from "@pace/utils"; // components import { LiteTextEditor } from "@/components/editor/lite-text-editor"; import { CommentReactions } from "@/components/issues/peek-overview/comment/comment-reactions"; -// helpers -import { timeAgo } from "@/helpers/date-time.helper"; // hooks import { usePublish } from "@/hooks/store/publish"; import { useIssueDetails } from "@/hooks/store/use-issue-details"; @@ -97,7 +95,7 @@ export const CommentCard = observer(function CommentCard(props: Props) { {comment.actor_detail.is_bot ? comment.actor_detail.first_name + " Bot" : comment.actor_detail.display_name}

- <>commented {timeAgo(comment.created_at)} + <>commented {calculateTimeAgo(comment.created_at)}

diff --git a/apps/space/core/components/issues/peek-overview/header.tsx b/apps/space/core/components/issues/peek-overview/header.tsx index 8b544d8d..eae363e9 100644 --- a/apps/space/core/components/issues/peek-overview/header.tsx +++ b/apps/space/core/components/issues/peek-overview/header.tsx @@ -17,7 +17,7 @@ import { Listbox, Transition } from "@headlessui/react"; // ui import { TOAST_TYPE, setToast } from "@pace/propel/toast"; // helpers -import { copyTextToClipboard } from "@/helpers/string.helper"; +import { copyTextToClipboard } from "@pace/utils"; // hooks import { useIssueDetails } from "@/hooks/store/use-issue-details"; import useClipboardWritePermission from "@/hooks/use-clipboard-write-permission"; diff --git a/apps/space/core/components/issues/peek-overview/issue-properties.tsx b/apps/space/core/components/issues/peek-overview/issue-properties.tsx index 38abc006..1962ceb7 100644 --- a/apps/space/core/components/issues/peek-overview/issue-properties.tsx +++ b/apps/space/core/components/issues/peek-overview/issue-properties.tsx @@ -11,11 +11,15 @@ import { useTranslation } from "@pace/i18n"; import { StateGroupIcon, PriorityIcon } from "@pace/propel/icons"; import { DueDateOutline, LinkOutline, PriorityOutline, StateOutline } from "@makeplane/propel/icons"; import { TOAST_TYPE, setToast } from "@pace/propel/toast"; -import { cn, getIssuePriorityFilters } from "@pace/utils"; +import { + addSpaceIfCamelCase, + cn, + copyTextToClipboard, + getIssuePriorityFilters, + renderFormattedDate, + shouldHighlightIssueDueDate, +} from "@pace/utils"; // helpers -import { renderFormattedDate } from "@/helpers/date-time.helper"; -import { shouldHighlightIssueDueDate } from "@/helpers/issue.helper"; -import { copyTextToClipboard, addSpaceIfCamelCase } from "@/helpers/string.helper"; // hooks import { usePublish } from "@/hooks/store/publish"; import { useStates } from "@/hooks/store/use-state"; diff --git a/apps/space/core/hooks/oauth/core.tsx b/apps/space/core/hooks/oauth/core.tsx index 0367638c..9782ddce 100644 --- a/apps/space/core/hooks/oauth/core.tsx +++ b/apps/space/core/hooks/oauth/core.tsx @@ -50,7 +50,7 @@ export const useCoreOAuthConfig = (oauthActionText: string): TOAuthConfigs => { text: `${oauthActionText} with GitHub`, icon: ( GitHub Logo { - switch (typeof time) { - case "number": - break; - case "string": - time = +new Date(time); - break; - case "object": - if (time.constructor === Date) time = time.getTime(); - break; - default: - time = +new Date(); - } -}; - -/** - * This method returns a date from string of type yyyy-mm-dd - * This method is recommended to use instead of new Date() as this does not introduce any timezone offsets - * @param date - * @returns date or undefined - */ -export const getDate = (date: string | Date | undefined | null): Date | undefined => { - try { - if (!date || date === "") return; - - if (typeof date !== "string" && !(date instanceof String)) return date; - - const [yearString, monthString, dayString] = date.substring(0, 10).split("-"); - const year = parseInt(yearString); - const month = parseInt(monthString); - const day = parseInt(dayString); - if (!isNumber(year) || !isNumber(month) || !isNumber(day)) return; - - return new Date(year, month - 1, day); - } catch (_err) { - return undefined; - } -}; - -/** - * @returns {string | null} formatted date in the format of MMM dd, yyyy - * @description Returns date in the formatted format - * @param {Date | string} date - * @example renderFormattedDate("2024-01-01") // Jan 01, 2024 - */ -export const renderFormattedDate = (date: string | Date | undefined | null): string | null => { - // Parse the date to check if it is valid - const parsedDate = getDate(date); - // return if undefined - if (!parsedDate) return null; - // Check if the parsed date is valid before formatting - if (!isValid(parsedDate)) return null; // Return null for invalid dates - // Format the date in format (MMM dd, yyyy) - const formattedDate = format(parsedDate, "MMM dd, yyyy"); - return formattedDate; -}; diff --git a/apps/space/helpers/issue.helper.ts b/apps/space/helpers/issue.helper.ts deleted file mode 100644 index bd8f58cf..00000000 --- a/apps/space/helpers/issue.helper.ts +++ /dev/null @@ -1,35 +0,0 @@ -/** - * Copyright (c) 2023-present Plane Software, Inc. and contributors - * SPDX-License-Identifier: AGPL-3.0-only - * See the LICENSE file for details. - */ - -import { differenceInCalendarDays } from "date-fns/differenceInCalendarDays"; -// pace internal -import { STATE_GROUPS } from "@pace/constants"; -import type { TStateGroups } from "@pace/types"; -// helpers -import { getDate } from "@/helpers/date-time.helper"; - -/** - * @description check if the issue due date should be highlighted - * @param date - * @param stateGroup - * @returns boolean - */ -export const shouldHighlightIssueDueDate = ( - date: string | Date | null, - stateGroup: TStateGroups | undefined -): boolean => { - if (!date || !stateGroup) return false; - // if the issue is completed or cancelled, don't highlight the due date - if ([STATE_GROUPS.completed.key, STATE_GROUPS.cancelled.key].includes(stateGroup)) return false; - - const parsedDate = getDate(date); - if (!parsedDate) return false; - - const targetDateDistance = differenceInCalendarDays(parsedDate, new Date()); - - // if the issue is overdue, highlight the due date - return targetDateDistance <= 0; -}; diff --git a/apps/space/helpers/state.helper.ts b/apps/space/helpers/state.helper.ts deleted file mode 100644 index bfb98972..00000000 --- a/apps/space/helpers/state.helper.ts +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Copyright (c) 2023-present Plane Software, Inc. and contributors - * SPDX-License-Identifier: AGPL-3.0-only - * See the LICENSE file for details. - */ - -import { STATE_GROUPS } from "@pace/constants"; -import type { IState } from "@pace/types"; - -export const sortStates = (states: IState[]) => { - if (!states || states.length === 0) return; - - return states.sort((stateA, stateB) => { - if (stateA.group === stateB.group) { - return stateA.sequence - stateB.sequence; - } - return Object.keys(STATE_GROUPS).indexOf(stateA.group) - Object.keys(STATE_GROUPS).indexOf(stateB.group); - }); -}; diff --git a/apps/space/helpers/string.helper.ts b/apps/space/helpers/string.helper.ts deleted file mode 100644 index aa6a52df..00000000 --- a/apps/space/helpers/string.helper.ts +++ /dev/null @@ -1,81 +0,0 @@ -/** - * Copyright (c) 2023-present Plane Software, Inc. and contributors - * SPDX-License-Identifier: AGPL-3.0-only - * See the LICENSE file for details. - */ - -export const addSpaceIfCamelCase = (str: string) => str.replace(/([a-z])([A-Z])/g, "$1 $2"); - -const fallbackCopyTextToClipboard = (text: string) => { - const textArea = document.createElement("textarea"); - textArea.value = text; - - // Avoid scrolling to bottom - textArea.style.top = "0"; - textArea.style.left = "0"; - textArea.style.position = "fixed"; - - document.body.appendChild(textArea); - textArea.focus(); - textArea.select(); - - try { - // FIXME: Even though we are using this as a fallback, execCommand is deprecated 👎. We should find a better way to do this. - // https://developer.mozilla.org/en-US/docs/Web/API/Document/execCommand - document.execCommand("copy"); - } catch (_err) {} - - document.body.removeChild(textArea); -}; - -export const copyTextToClipboard = async (text: string) => { - if (!navigator.clipboard) { - fallbackCopyTextToClipboard(text); - return; - } - await navigator.clipboard.writeText(text); -}; - -/** - * @returns {boolean} true if email is valid, false otherwise - * @description Returns true if email is valid, false otherwise - * @param {string} email string to check if it is a valid email - * @example checkEmailIsValid("hello world") => false - * @example checkEmailIsValid("example@yldm.ai") => true - */ -export const checkEmailValidity = (email: string): boolean => { - if (!email) return false; - - const isEmailValid = - /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/.test( - email - ); - - return isEmailValid; -}; - -export const replaceUnderscoreIfSnakeCase = (str: string) => str.replace(/_/g, " "); - -export const capitalizeFirstLetter = (str: string) => str.charAt(0).toUpperCase() + str.slice(1); - -/** - * @description - * This function test whether a URL is valid or not. - * - * It accepts URLs with or without the protocol. - * @param {string} url - * @returns {boolean} - * @example - * checkURLValidity("https://example.com") => true - * checkURLValidity("example.com") => true - * checkURLValidity("example") => false - */ -export const checkURLValidity = (url: string): boolean => { - if (!url) return false; - - // regex to support complex query parameters and fragments - const urlPattern = - /^(https?:\/\/)?((([a-z\d-]+\.)*[a-z\d-]+\.[a-z]{2,6})|(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}))(:\d+)?(\/[\w.-]*)*(\?[^#\s]*)?(#[\w-]*)?$/i; - - return urlPattern.test(url); -}; diff --git a/apps/space/package.json b/apps/space/package.json index bcfff121..ab5f5504 100644 --- a/apps/space/package.json +++ b/apps/space/package.json @@ -1,6 +1,6 @@ { "name": "space", - "version": "1.4.36", + "version": "1.4.37", "private": true, "license": "AGPL-3.0", "type": "module", diff --git a/apps/web/package.json b/apps/web/package.json index c010bcee..19f3d4f9 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -1,6 +1,6 @@ { "name": "web", - "version": "1.4.36", + "version": "1.4.37", "private": true, "license": "AGPL-3.0", "type": "module", diff --git a/package.json b/package.json index 40dd2525..76351b08 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pace", - "version": "1.4.36", + "version": "1.4.37", "private": true, "description": "Project management that keeps pace with the work", "license": "AGPL-3.0", diff --git a/packages/codemods/package.json b/packages/codemods/package.json index 45ea3f64..f3403674 100644 --- a/packages/codemods/package.json +++ b/packages/codemods/package.json @@ -1,6 +1,6 @@ { "name": "@pace/codemods", - "version": "1.4.36", + "version": "1.4.37", "private": true, "scripts": { "check:format": "oxfmt --check .", diff --git a/packages/constants/package.json b/packages/constants/package.json index 76a427eb..75f7f8c3 100644 --- a/packages/constants/package.json +++ b/packages/constants/package.json @@ -1,6 +1,6 @@ { "name": "@pace/constants", - "version": "1.4.36", + "version": "1.4.37", "private": true, "license": "AGPL-3.0", "type": "module", diff --git a/packages/editor/package.json b/packages/editor/package.json index 6f2b7a04..7b788abb 100644 --- a/packages/editor/package.json +++ b/packages/editor/package.json @@ -1,6 +1,6 @@ { "name": "@pace/editor", - "version": "1.4.36", + "version": "1.4.37", "private": true, "description": "Core Editor that powers Pace", "keywords": [ diff --git a/packages/hooks/package.json b/packages/hooks/package.json index 46ed80c9..473a9032 100644 --- a/packages/hooks/package.json +++ b/packages/hooks/package.json @@ -1,6 +1,6 @@ { "name": "@pace/hooks", - "version": "1.4.36", + "version": "1.4.37", "private": true, "description": "React hooks that are shared across multiple apps internally", "license": "AGPL-3.0", diff --git a/packages/i18n/package.json b/packages/i18n/package.json index fae25017..a91ad628 100644 --- a/packages/i18n/package.json +++ b/packages/i18n/package.json @@ -1,6 +1,6 @@ { "name": "@pace/i18n", - "version": "1.4.36", + "version": "1.4.37", "private": true, "description": "I18n shared across multiple apps internally", "license": "AGPL-3.0", diff --git a/packages/propel/package.json b/packages/propel/package.json index a8a98136..1ded20e1 100644 --- a/packages/propel/package.json +++ b/packages/propel/package.json @@ -1,6 +1,6 @@ { "name": "@pace/propel", - "version": "1.4.36", + "version": "1.4.37", "private": true, "license": "AGPL-3.0", "type": "module", diff --git a/packages/services/package.json b/packages/services/package.json index 691d598f..50521f6d 100644 --- a/packages/services/package.json +++ b/packages/services/package.json @@ -1,6 +1,6 @@ { "name": "@pace/services", - "version": "1.4.36", + "version": "1.4.37", "private": true, "license": "AGPL-3.0", "type": "module", diff --git a/packages/shared-state/package.json b/packages/shared-state/package.json index 96720a0a..0d1345bd 100644 --- a/packages/shared-state/package.json +++ b/packages/shared-state/package.json @@ -1,6 +1,6 @@ { "name": "@pace/shared-state", - "version": "1.4.36", + "version": "1.4.37", "private": true, "description": "Shared state shared across multiple apps internally", "license": "AGPL-3.0", diff --git a/packages/tailwind-config/package.json b/packages/tailwind-config/package.json index 4ce960a2..a79110b3 100644 --- a/packages/tailwind-config/package.json +++ b/packages/tailwind-config/package.json @@ -1,6 +1,6 @@ { "name": "@pace/tailwind-config", - "version": "1.4.36", + "version": "1.4.37", "private": true, "description": "common tailwind configuration across monorepo", "license": "AGPL-3.0", diff --git a/packages/types/package.json b/packages/types/package.json index 6d538abe..74ff7b95 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -1,6 +1,6 @@ { "name": "@pace/types", - "version": "1.4.36", + "version": "1.4.37", "private": true, "license": "AGPL-3.0", "type": "module", diff --git a/packages/typescript-config/package.json b/packages/typescript-config/package.json index e16decc6..8c662206 100644 --- a/packages/typescript-config/package.json +++ b/packages/typescript-config/package.json @@ -1,6 +1,6 @@ { "name": "@pace/typescript-config", - "version": "1.4.36", + "version": "1.4.37", "private": true, "license": "AGPL-3.0", "files": [ diff --git a/packages/ui/package.json b/packages/ui/package.json index 82c69db0..ebef813a 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -1,6 +1,6 @@ { "name": "@pace/ui", - "version": "1.4.36", + "version": "1.4.37", "private": true, "description": "UI components shared across multiple apps internally", "license": "AGPL-3.0", diff --git a/packages/utils/package.json b/packages/utils/package.json index 0193eb31..005c36a0 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -1,6 +1,6 @@ { "name": "@pace/utils", - "version": "1.4.36", + "version": "1.4.37", "private": true, "description": "Helper functions shared across multiple apps internally", "license": "AGPL-3.0",