chore: remove posthog events (#8465)
* chore: remove posthog events * chore: remove event tracking * chore: lint errors * chore: minor changes based on comments * fix: type errors
This commit is contained in:
parent
a37e5e2f6a
commit
d61b157929
144 changed files with 586 additions and 3397 deletions
|
|
@ -2,7 +2,7 @@ import { useState, useEffect } from "react";
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
import { useRouter } from "next/navigation";
|
import { useRouter } from "next/navigation";
|
||||||
// plane package imports
|
// plane package imports
|
||||||
import { EUserPermissions, EUserPermissionsLevel, PROJECT_TRACKER_ELEMENTS } from "@plane/constants";
|
import { EUserPermissions, EUserPermissionsLevel } from "@plane/constants";
|
||||||
import { useTranslation } from "@plane/i18n";
|
import { useTranslation } from "@plane/i18n";
|
||||||
import { EmptyStateDetailed } from "@plane/propel/empty-state";
|
import { EmptyStateDetailed } from "@plane/propel/empty-state";
|
||||||
import { Tabs } from "@plane/propel/tabs";
|
import { Tabs } from "@plane/propel/tabs";
|
||||||
|
|
@ -11,7 +11,6 @@ import { cn } from "@plane/utils";
|
||||||
import AnalyticsFilterActions from "@/components/analytics/analytics-filter-actions";
|
import AnalyticsFilterActions from "@/components/analytics/analytics-filter-actions";
|
||||||
import { PageHead } from "@/components/core/page-title";
|
import { PageHead } from "@/components/core/page-title";
|
||||||
// hooks
|
// hooks
|
||||||
import { captureClick } from "@/helpers/event-tracker.helper";
|
|
||||||
import { useCommandPalette } from "@/hooks/store/use-command-palette";
|
import { useCommandPalette } from "@/hooks/store/use-command-palette";
|
||||||
import { useProject } from "@/hooks/store/use-project";
|
import { useProject } from "@/hooks/store/use-project";
|
||||||
import { useWorkspace } from "@/hooks/store/use-workspace";
|
import { useWorkspace } from "@/hooks/store/use-workspace";
|
||||||
|
|
@ -120,7 +119,6 @@ function AnalyticsPage({ params }: Route.ComponentProps) {
|
||||||
label: "Create a project",
|
label: "Create a project",
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
toggleCreateProjectModal(true);
|
toggleCreateProjectModal(true);
|
||||||
captureClick({ elementName: PROJECT_TRACKER_ELEMENTS.EMPTY_STATE_CREATE_PROJECT_BUTTON });
|
|
||||||
},
|
},
|
||||||
disabled: !canPerformEmptyStateActions,
|
disabled: !canPerformEmptyStateActions,
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ import { useState } from "react";
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
import { useParams, useRouter, useSearchParams } from "next/navigation";
|
import { useParams, useRouter, useSearchParams } from "next/navigation";
|
||||||
// constants
|
// constants
|
||||||
import { EPageAccess, PROJECT_PAGE_TRACKER_EVENTS, PROJECT_TRACKER_ELEMENTS } from "@plane/constants";
|
import { EPageAccess } from "@plane/constants";
|
||||||
// plane types
|
// plane types
|
||||||
import { Button } from "@plane/propel/button";
|
import { Button } from "@plane/propel/button";
|
||||||
import { PageIcon } from "@plane/propel/icons";
|
import { PageIcon } from "@plane/propel/icons";
|
||||||
|
|
@ -12,7 +12,6 @@ import type { TPage } from "@plane/types";
|
||||||
import { Breadcrumbs, Header } from "@plane/ui";
|
import { Breadcrumbs, Header } from "@plane/ui";
|
||||||
// helpers
|
// helpers
|
||||||
import { BreadcrumbLink } from "@/components/common/breadcrumb-link";
|
import { BreadcrumbLink } from "@/components/common/breadcrumb-link";
|
||||||
import { captureError, captureSuccess } from "@/helpers/event-tracker.helper";
|
|
||||||
// hooks
|
// hooks
|
||||||
import { useProject } from "@/hooks/store/use-project";
|
import { useProject } from "@/hooks/store/use-project";
|
||||||
// plane web imports
|
// plane web imports
|
||||||
|
|
@ -40,23 +39,10 @@ export const PagesListHeader = observer(function PagesListHeader() {
|
||||||
|
|
||||||
await createPage(payload)
|
await createPage(payload)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
captureSuccess({
|
|
||||||
eventName: PROJECT_PAGE_TRACKER_EVENTS.create,
|
|
||||||
payload: {
|
|
||||||
id: res?.id,
|
|
||||||
state: "SUCCESS",
|
|
||||||
},
|
|
||||||
});
|
|
||||||
const pageId = `/${workspaceSlug}/projects/${currentProjectDetails?.id}/pages/${res?.id}`;
|
const pageId = `/${workspaceSlug}/projects/${currentProjectDetails?.id}/pages/${res?.id}`;
|
||||||
router.push(pageId);
|
router.push(pageId);
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
captureError({
|
|
||||||
eventName: PROJECT_PAGE_TRACKER_EVENTS.create,
|
|
||||||
payload: {
|
|
||||||
state: "ERROR",
|
|
||||||
},
|
|
||||||
});
|
|
||||||
setToast({
|
setToast({
|
||||||
type: TOAST_TYPE.ERROR,
|
type: TOAST_TYPE.ERROR,
|
||||||
title: "Error!",
|
title: "Error!",
|
||||||
|
|
@ -86,13 +72,7 @@ export const PagesListHeader = observer(function PagesListHeader() {
|
||||||
</Header.LeftItem>
|
</Header.LeftItem>
|
||||||
{canCurrentUserCreatePage && (
|
{canCurrentUserCreatePage && (
|
||||||
<Header.RightItem>
|
<Header.RightItem>
|
||||||
<Button
|
<Button variant="primary" size="lg" onClick={handleCreatePage} loading={isCreatingPage}>
|
||||||
variant="primary"
|
|
||||||
size="lg"
|
|
||||||
onClick={handleCreatePage}
|
|
||||||
loading={isCreatingPage}
|
|
||||||
data-ph-element={PROJECT_TRACKER_ELEMENTS.CREATE_HEADER_BUTTON}
|
|
||||||
>
|
|
||||||
{isCreatingPage ? "Adding" : "Add page"}
|
{isCreatingPage ? "Adding" : "Add page"}
|
||||||
</Button>
|
</Button>
|
||||||
</Header.RightItem>
|
</Header.RightItem>
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,9 @@
|
||||||
import { useTheme } from "next-themes";
|
import { useTheme } from "next-themes";
|
||||||
// plane imports
|
// plane imports
|
||||||
import { HEADER_GITHUB_ICON, GITHUB_REDIRECTED_TRACKER_EVENT } from "@plane/constants";
|
|
||||||
import { useTranslation } from "@plane/i18n";
|
import { useTranslation } from "@plane/i18n";
|
||||||
// assets
|
// assets
|
||||||
import githubBlackImage from "@/app/assets/logos/github-black.png?url";
|
import githubBlackImage from "@/app/assets/logos/github-black.png?url";
|
||||||
import githubWhiteImage from "@/app/assets/logos/github-white.png?url";
|
import githubWhiteImage from "@/app/assets/logos/github-white.png?url";
|
||||||
// helpers
|
|
||||||
import { captureElementAndEvent } from "@/helpers/event-tracker.helper";
|
|
||||||
|
|
||||||
export function StarUsOnGitHubLink() {
|
export function StarUsOnGitHubLink() {
|
||||||
// plane hooks
|
// plane hooks
|
||||||
|
|
@ -18,17 +15,6 @@ export function StarUsOnGitHubLink() {
|
||||||
return (
|
return (
|
||||||
<a
|
<a
|
||||||
aria-label={t("home.star_us_on_github")}
|
aria-label={t("home.star_us_on_github")}
|
||||||
onClick={() =>
|
|
||||||
captureElementAndEvent({
|
|
||||||
element: {
|
|
||||||
elementName: HEADER_GITHUB_ICON,
|
|
||||||
},
|
|
||||||
event: {
|
|
||||||
eventName: GITHUB_REDIRECTED_TRACKER_EVENT,
|
|
||||||
state: "SUCCESS",
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
className="flex flex-shrink-0 items-center gap-1.5 rounded-sm bg-layer-2 px-3 py-1.5"
|
className="flex flex-shrink-0 items-center gap-1.5 rounded-sm bg-layer-2 px-3 py-1.5"
|
||||||
href="https://github.com/makeplane/plane"
|
href="https://github.com/makeplane/plane"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
|
|
|
||||||
|
|
@ -20,8 +20,6 @@ import { PageHead } from "@/components/core/page-title";
|
||||||
import { MemberListFiltersDropdown } from "@/components/project/dropdowns/filters/member-list";
|
import { MemberListFiltersDropdown } from "@/components/project/dropdowns/filters/member-list";
|
||||||
import { SettingsContentWrapper } from "@/components/settings/content-wrapper";
|
import { SettingsContentWrapper } from "@/components/settings/content-wrapper";
|
||||||
import { WorkspaceMembersList } from "@/components/workspace/settings/members-list";
|
import { WorkspaceMembersList } from "@/components/workspace/settings/members-list";
|
||||||
// helpers
|
|
||||||
import { captureError, captureSuccess } from "@/helpers/event-tracker.helper";
|
|
||||||
// hooks
|
// hooks
|
||||||
import { useMember } from "@/hooks/store/use-member";
|
import { useMember } from "@/hooks/store/use-member";
|
||||||
import { useWorkspace } from "@/hooks/store/use-workspace";
|
import { useWorkspace } from "@/hooks/store/use-workspace";
|
||||||
|
|
@ -58,13 +56,6 @@ const WorkspaceMembersSettingsPage = observer(function WorkspaceMembersSettingsP
|
||||||
|
|
||||||
setInviteModal(false);
|
setInviteModal(false);
|
||||||
|
|
||||||
captureSuccess({
|
|
||||||
eventName: MEMBER_TRACKER_EVENTS.invite,
|
|
||||||
payload: {
|
|
||||||
emails: data.emails.map((email) => email.email),
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
setToast({
|
setToast({
|
||||||
type: TOAST_TYPE.SUCCESS,
|
type: TOAST_TYPE.SUCCESS,
|
||||||
title: "Success!",
|
title: "Success!",
|
||||||
|
|
@ -76,14 +67,6 @@ const WorkspaceMembersSettingsPage = observer(function WorkspaceMembersSettingsP
|
||||||
const err = error as Error & { error?: string };
|
const err = error as Error & { error?: string };
|
||||||
message = err.error;
|
message = err.error;
|
||||||
}
|
}
|
||||||
captureError({
|
|
||||||
eventName: MEMBER_TRACKER_EVENTS.invite,
|
|
||||||
payload: {
|
|
||||||
emails: data.emails.map((email) => email.email),
|
|
||||||
},
|
|
||||||
error: error as Error,
|
|
||||||
});
|
|
||||||
|
|
||||||
setToast({
|
setToast({
|
||||||
type: TOAST_TYPE.ERROR,
|
type: TOAST_TYPE.ERROR,
|
||||||
title: "Error!",
|
title: "Error!",
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
import useSWR from "swr";
|
import useSWR from "swr";
|
||||||
import { EUserPermissions, EUserPermissionsLevel, WORKSPACE_SETTINGS_TRACKER_EVENTS } from "@plane/constants";
|
import { EUserPermissions, EUserPermissionsLevel } from "@plane/constants";
|
||||||
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
||||||
import type { IWebhook } from "@plane/types";
|
import type { IWebhook } from "@plane/types";
|
||||||
// ui
|
// ui
|
||||||
|
|
@ -11,7 +11,6 @@ import { PageHead } from "@/components/core/page-title";
|
||||||
import { SettingsContentWrapper } from "@/components/settings/content-wrapper";
|
import { SettingsContentWrapper } from "@/components/settings/content-wrapper";
|
||||||
import { DeleteWebhookModal, WebhookDeleteSection, WebhookForm } from "@/components/web-hooks";
|
import { DeleteWebhookModal, WebhookDeleteSection, WebhookForm } from "@/components/web-hooks";
|
||||||
// hooks
|
// hooks
|
||||||
import { captureError, captureSuccess } from "@/helpers/event-tracker.helper";
|
|
||||||
import { useWebhook } from "@/hooks/store/use-webhook";
|
import { useWebhook } from "@/hooks/store/use-webhook";
|
||||||
import { useWorkspace } from "@/hooks/store/use-workspace";
|
import { useWorkspace } from "@/hooks/store/use-workspace";
|
||||||
import { useUserPermissions } from "@/hooks/store/user";
|
import { useUserPermissions } from "@/hooks/store/user";
|
||||||
|
|
@ -55,12 +54,6 @@ function WebhookDetailsPage({ params }: Route.ComponentProps) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await updateWebhook(workspaceSlug, formData.id, payload);
|
await updateWebhook(workspaceSlug, formData.id, payload);
|
||||||
|
|
||||||
captureSuccess({
|
|
||||||
eventName: WORKSPACE_SETTINGS_TRACKER_EVENTS.webhook_updated,
|
|
||||||
payload: { webhook: formData.id },
|
|
||||||
});
|
|
||||||
|
|
||||||
setToast({
|
setToast({
|
||||||
type: TOAST_TYPE.SUCCESS,
|
type: TOAST_TYPE.SUCCESS,
|
||||||
title: "Success!",
|
title: "Success!",
|
||||||
|
|
@ -68,12 +61,6 @@ function WebhookDetailsPage({ params }: Route.ComponentProps) {
|
||||||
});
|
});
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
captureError({
|
|
||||||
eventName: WORKSPACE_SETTINGS_TRACKER_EVENTS.webhook_updated,
|
|
||||||
payload: { webhook: formData.id },
|
|
||||||
error: error as Error,
|
|
||||||
});
|
|
||||||
|
|
||||||
setToast({
|
setToast({
|
||||||
type: TOAST_TYPE.ERROR,
|
type: TOAST_TYPE.ERROR,
|
||||||
title: "Error!",
|
title: "Error!",
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ import { useEffect, useState } from "react";
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
import useSWR from "swr";
|
import useSWR from "swr";
|
||||||
// plane imports
|
// plane imports
|
||||||
import { EUserPermissions, EUserPermissionsLevel, WORKSPACE_SETTINGS_TRACKER_ELEMENTS } from "@plane/constants";
|
import { EUserPermissions, EUserPermissionsLevel } from "@plane/constants";
|
||||||
import { useTranslation } from "@plane/i18n";
|
import { useTranslation } from "@plane/i18n";
|
||||||
// components
|
// components
|
||||||
import { EmptyStateCompact } from "@plane/propel/empty-state";
|
import { EmptyStateCompact } from "@plane/propel/empty-state";
|
||||||
|
|
@ -13,7 +13,6 @@ import { SettingsHeading } from "@/components/settings/heading";
|
||||||
import { WebhookSettingsLoader } from "@/components/ui/loader/settings/web-hook";
|
import { WebhookSettingsLoader } from "@/components/ui/loader/settings/web-hook";
|
||||||
import { WebhooksList, CreateWebhookModal } from "@/components/web-hooks";
|
import { WebhooksList, CreateWebhookModal } from "@/components/web-hooks";
|
||||||
// hooks
|
// hooks
|
||||||
import { captureClick } from "@/helpers/event-tracker.helper";
|
|
||||||
import { useWebhook } from "@/hooks/store/use-webhook";
|
import { useWebhook } from "@/hooks/store/use-webhook";
|
||||||
import { useWorkspace } from "@/hooks/store/use-workspace";
|
import { useWorkspace } from "@/hooks/store/use-workspace";
|
||||||
import { useUserPermissions } from "@/hooks/store/user";
|
import { useUserPermissions } from "@/hooks/store/user";
|
||||||
|
|
@ -72,9 +71,6 @@ function WebhooksListPage({ params }: Route.ComponentProps) {
|
||||||
button={{
|
button={{
|
||||||
label: t("workspace_settings.settings.webhooks.add_webhook"),
|
label: t("workspace_settings.settings.webhooks.add_webhook"),
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
captureClick({
|
|
||||||
elementName: WORKSPACE_SETTINGS_TRACKER_ELEMENTS.HEADER_ADD_WEBHOOK_BUTTON,
|
|
||||||
});
|
|
||||||
setShowCreateWebhookModal(true);
|
setShowCreateWebhookModal(true);
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
|
|
@ -94,9 +90,6 @@ function WebhooksListPage({ params }: Route.ComponentProps) {
|
||||||
{
|
{
|
||||||
label: t("settings_empty_state.webhooks.cta_primary"),
|
label: t("settings_empty_state.webhooks.cta_primary"),
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
captureClick({
|
|
||||||
elementName: WORKSPACE_SETTINGS_TRACKER_ELEMENTS.EMPTY_STATE_ADD_WEBHOOK_BUTTON,
|
|
||||||
});
|
|
||||||
setShowCreateWebhookModal(true);
|
setShowCreateWebhookModal(true);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
import React, { useState } from "react";
|
import { useState } from "react";
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
import useSWR from "swr";
|
import useSWR from "swr";
|
||||||
// plane imports
|
// plane imports
|
||||||
import { PROFILE_SETTINGS_TRACKER_ELEMENTS } from "@plane/constants";
|
|
||||||
import { useTranslation } from "@plane/i18n";
|
import { useTranslation } from "@plane/i18n";
|
||||||
// component
|
// component
|
||||||
import { EmptyStateCompact } from "@plane/propel/empty-state";
|
import { EmptyStateCompact } from "@plane/propel/empty-state";
|
||||||
|
|
@ -14,7 +13,6 @@ import { SettingsHeading } from "@/components/settings/heading";
|
||||||
import { APITokenSettingsLoader } from "@/components/ui/loader/settings/api-token";
|
import { APITokenSettingsLoader } from "@/components/ui/loader/settings/api-token";
|
||||||
import { API_TOKENS_LIST } from "@/constants/fetch-keys";
|
import { API_TOKENS_LIST } from "@/constants/fetch-keys";
|
||||||
// store hooks
|
// store hooks
|
||||||
import { captureClick } from "@/helpers/event-tracker.helper";
|
|
||||||
import { useWorkspace } from "@/hooks/store/use-workspace";
|
import { useWorkspace } from "@/hooks/store/use-workspace";
|
||||||
|
|
||||||
const apiTokenService = new APITokenService();
|
const apiTokenService = new APITokenService();
|
||||||
|
|
@ -51,9 +49,6 @@ function ApiTokensPage() {
|
||||||
button={{
|
button={{
|
||||||
label: t("workspace_settings.settings.api_tokens.add_token"),
|
label: t("workspace_settings.settings.api_tokens.add_token"),
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
captureClick({
|
|
||||||
elementName: PROFILE_SETTINGS_TRACKER_ELEMENTS.HEADER_ADD_PAT_BUTTON,
|
|
||||||
});
|
|
||||||
setIsCreateTokenModalOpen(true);
|
setIsCreateTokenModalOpen(true);
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
|
|
@ -72,9 +67,6 @@ function ApiTokensPage() {
|
||||||
button={{
|
button={{
|
||||||
label: t("workspace_settings.settings.api_tokens.add_token"),
|
label: t("workspace_settings.settings.api_tokens.add_token"),
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
captureClick({
|
|
||||||
elementName: PROFILE_SETTINGS_TRACKER_ELEMENTS.HEADER_ADD_PAT_BUTTON,
|
|
||||||
});
|
|
||||||
setIsCreateTokenModalOpen(true);
|
setIsCreateTokenModalOpen(true);
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
|
|
@ -89,9 +81,6 @@ function ApiTokensPage() {
|
||||||
{
|
{
|
||||||
label: t("settings_empty_state.tokens.cta_primary"),
|
label: t("settings_empty_state.tokens.cta_primary"),
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
captureClick({
|
|
||||||
elementName: PROFILE_SETTINGS_TRACKER_ELEMENTS.EMPTY_STATE_ADD_PAT_BUTTON,
|
|
||||||
});
|
|
||||||
setIsCreateTokenModalOpen(true);
|
setIsCreateTokenModalOpen(true);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
import React, { useState } from "react";
|
import { useState } from "react";
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
|
|
||||||
import useSWR, { mutate } from "swr";
|
import useSWR, { mutate } from "swr";
|
||||||
import { CheckCircle2 } from "lucide-react";
|
import { CheckCircle2 } from "lucide-react";
|
||||||
// plane imports
|
// plane imports
|
||||||
import { ROLE, MEMBER_TRACKER_EVENTS, MEMBER_TRACKER_ELEMENTS, GROUP_WORKSPACE_TRACKER_EVENT } from "@plane/constants";
|
import { ROLE } from "@plane/constants";
|
||||||
import { useTranslation } from "@plane/i18n";
|
import { useTranslation } from "@plane/i18n";
|
||||||
// types
|
// types
|
||||||
import { Button } from "@plane/propel/button";
|
import { Button } from "@plane/propel/button";
|
||||||
|
|
@ -19,9 +19,7 @@ import emptyInvitation from "@/app/assets/empty-state/invitation.svg?url";
|
||||||
import { EmptyState } from "@/components/common/empty-state";
|
import { EmptyState } from "@/components/common/empty-state";
|
||||||
import { WorkspaceLogo } from "@/components/workspace/logo";
|
import { WorkspaceLogo } from "@/components/workspace/logo";
|
||||||
import { USER_WORKSPACES_LIST } from "@/constants/fetch-keys";
|
import { USER_WORKSPACES_LIST } from "@/constants/fetch-keys";
|
||||||
// helpers
|
|
||||||
// hooks
|
// hooks
|
||||||
import { captureError, captureSuccess, joinEventGroup } from "@/helpers/event-tracker.helper";
|
|
||||||
import { useWorkspace } from "@/hooks/store/use-workspace";
|
import { useWorkspace } from "@/hooks/store/use-workspace";
|
||||||
import { useUser, useUserProfile } from "@/hooks/store/user";
|
import { useUser, useUserProfile } from "@/hooks/store/user";
|
||||||
import { useAppRouter } from "@/hooks/use-app-router";
|
import { useAppRouter } from "@/hooks/use-app-router";
|
||||||
|
|
@ -79,18 +77,6 @@ function UserInvitationsPage() {
|
||||||
const firstInviteId = invitationsRespond[0];
|
const firstInviteId = invitationsRespond[0];
|
||||||
const invitation = invitations?.find((i) => i.id === firstInviteId);
|
const invitation = invitations?.find((i) => i.id === firstInviteId);
|
||||||
const redirectWorkspace = invitations?.find((i) => i.id === firstInviteId)?.workspace;
|
const redirectWorkspace = invitations?.find((i) => i.id === firstInviteId)?.workspace;
|
||||||
if (redirectWorkspace?.id) {
|
|
||||||
joinEventGroup(GROUP_WORKSPACE_TRACKER_EVENT, redirectWorkspace?.id, {
|
|
||||||
date: new Date().toDateString(),
|
|
||||||
workspace_id: redirectWorkspace?.id,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
captureSuccess({
|
|
||||||
eventName: MEMBER_TRACKER_EVENTS.accept,
|
|
||||||
payload: {
|
|
||||||
member_id: invitation?.id,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
updateUserProfile({ last_workspace_id: redirectWorkspace?.id })
|
updateUserProfile({ last_workspace_id: redirectWorkspace?.id })
|
||||||
.then(() => {
|
.then(() => {
|
||||||
setIsJoiningWorkspaces(false);
|
setIsJoiningWorkspaces(false);
|
||||||
|
|
@ -107,14 +93,7 @@ function UserInvitationsPage() {
|
||||||
setIsJoiningWorkspaces(false);
|
setIsJoiningWorkspaces(false);
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((_err) => {
|
||||||
captureError({
|
|
||||||
eventName: MEMBER_TRACKER_EVENTS.accept,
|
|
||||||
payload: {
|
|
||||||
member_id: invitationsRespond?.[0],
|
|
||||||
},
|
|
||||||
error: err,
|
|
||||||
});
|
|
||||||
setToast({
|
setToast({
|
||||||
type: TOAST_TYPE.ERROR,
|
type: TOAST_TYPE.ERROR,
|
||||||
title: t("error"),
|
title: t("error"),
|
||||||
|
|
@ -183,7 +162,6 @@ function UserInvitationsPage() {
|
||||||
onClick={submitInvitations}
|
onClick={submitInvitations}
|
||||||
disabled={isJoiningWorkspaces || invitationsRespond.length === 0}
|
disabled={isJoiningWorkspaces || invitationsRespond.length === 0}
|
||||||
loading={isJoiningWorkspaces}
|
loading={isJoiningWorkspaces}
|
||||||
data-ph-element={MEMBER_TRACKER_ELEMENTS.ACCEPT_INVITATION_BUTTON}
|
|
||||||
>
|
>
|
||||||
{t("accept_and_join")}
|
{t("accept_and_join")}
|
||||||
</Button>
|
</Button>
|
||||||
|
|
|
||||||
|
|
@ -29,10 +29,6 @@ const ChatSupportModal = lazy(function ChatSupportModal() {
|
||||||
return import("@/components/global/chat-support-modal");
|
return import("@/components/global/chat-support-modal");
|
||||||
});
|
});
|
||||||
|
|
||||||
const PostHogProvider = lazy(function PostHogProvider() {
|
|
||||||
return import("@/lib/posthog-provider");
|
|
||||||
});
|
|
||||||
|
|
||||||
export interface IAppProvider {
|
export interface IAppProvider {
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
}
|
}
|
||||||
|
|
@ -52,9 +48,7 @@ export function AppProvider(props: IAppProvider) {
|
||||||
<InstanceWrapper>
|
<InstanceWrapper>
|
||||||
<Suspense>
|
<Suspense>
|
||||||
<ChatSupportModal />
|
<ChatSupportModal />
|
||||||
<PostHogProvider>
|
<SWRConfig value={WEB_SWR_CONFIG}>{children}</SWRConfig>
|
||||||
<SWRConfig value={WEB_SWR_CONFIG}>{children}</SWRConfig>
|
|
||||||
</PostHogProvider>
|
|
||||||
</Suspense>
|
</Suspense>
|
||||||
</InstanceWrapper>
|
</InstanceWrapper>
|
||||||
</StoreWrapper>
|
</StoreWrapper>
|
||||||
|
|
|
||||||
|
|
@ -10,8 +10,6 @@ import IssuesTour from "@/app/assets/onboarding/issues.webp?url";
|
||||||
import ModulesTour from "@/app/assets/onboarding/modules.webp?url";
|
import ModulesTour from "@/app/assets/onboarding/modules.webp?url";
|
||||||
import PagesTour from "@/app/assets/onboarding/pages.webp?url";
|
import PagesTour from "@/app/assets/onboarding/pages.webp?url";
|
||||||
import ViewsTour from "@/app/assets/onboarding/views.webp?url";
|
import ViewsTour from "@/app/assets/onboarding/views.webp?url";
|
||||||
// helpers
|
|
||||||
import { captureClick } from "@/helpers/event-tracker.helper";
|
|
||||||
// hooks
|
// hooks
|
||||||
import { useCommandPalette } from "@/hooks/store/use-command-palette";
|
import { useCommandPalette } from "@/hooks/store/use-command-palette";
|
||||||
import { useUser } from "@/hooks/store/user";
|
import { useUser } from "@/hooks/store/user";
|
||||||
|
|
@ -107,9 +105,6 @@ export const TourRoot = observer(function TourRoot(props: TOnboardingTourProps)
|
||||||
<Button
|
<Button
|
||||||
variant="primary"
|
variant="primary"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
captureClick({
|
|
||||||
elementName: PRODUCT_TOUR_TRACKER_ELEMENTS.START_BUTTON,
|
|
||||||
});
|
|
||||||
setStep("work-items");
|
setStep("work-items");
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|
@ -119,9 +114,6 @@ export const TourRoot = observer(function TourRoot(props: TOnboardingTourProps)
|
||||||
type="button"
|
type="button"
|
||||||
className="bg-transparent text-11 font-medium text-accent-primary outline-subtle-1"
|
className="bg-transparent text-11 font-medium text-accent-primary outline-subtle-1"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
captureClick({
|
|
||||||
elementName: PRODUCT_TOUR_TRACKER_ELEMENTS.SKIP_BUTTON,
|
|
||||||
});
|
|
||||||
onComplete();
|
onComplete();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|
@ -170,9 +162,6 @@ export const TourRoot = observer(function TourRoot(props: TOnboardingTourProps)
|
||||||
<Button
|
<Button
|
||||||
variant="primary"
|
variant="primary"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
captureClick({
|
|
||||||
elementName: PRODUCT_TOUR_TRACKER_ELEMENTS.CREATE_PROJECT_BUTTON,
|
|
||||||
});
|
|
||||||
onComplete();
|
onComplete();
|
||||||
toggleCreateProjectModal(true);
|
toggleCreateProjectModal(true);
|
||||||
}}
|
}}
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,7 @@ import { useState, useEffect, useRef } from "react";
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
import { LockKeyhole, LockKeyholeOpen } from "lucide-react";
|
import { LockKeyhole, LockKeyholeOpen } from "lucide-react";
|
||||||
// plane imports
|
// plane imports
|
||||||
import { PROJECT_PAGE_TRACKER_ELEMENTS } from "@plane/constants";
|
|
||||||
import { Tooltip } from "@plane/propel/tooltip";
|
import { Tooltip } from "@plane/propel/tooltip";
|
||||||
// helpers
|
|
||||||
import { captureClick } from "@/helpers/event-tracker.helper";
|
|
||||||
// hooks
|
// hooks
|
||||||
import { usePageOperations } from "@/hooks/use-page-operations";
|
import { usePageOperations } from "@/hooks/use-page-operations";
|
||||||
// store
|
// store
|
||||||
|
|
@ -79,7 +76,6 @@ export const PageLockControl = observer(function PageLockControl({ page }: Props
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={toggleLock}
|
onClick={toggleLock}
|
||||||
data-ph-element={PROJECT_PAGE_TRACKER_ELEMENTS.LOCK_BUTTON}
|
|
||||||
className="flex-shrink-0 size-6 grid place-items-center rounded-sm text-secondary hover:text-primary hover:bg-layer-1 transition-colors"
|
className="flex-shrink-0 size-6 grid place-items-center rounded-sm text-secondary hover:text-primary hover:bg-layer-1 transition-colors"
|
||||||
aria-label="Lock"
|
aria-label="Lock"
|
||||||
>
|
>
|
||||||
|
|
@ -92,7 +88,6 @@ export const PageLockControl = observer(function PageLockControl({ page }: Props
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={toggleLock}
|
onClick={toggleLock}
|
||||||
data-ph-element={PROJECT_PAGE_TRACKER_ELEMENTS.LOCK_BUTTON}
|
|
||||||
className="h-6 flex items-center gap-1 px-2 rounded-sm text-accent-primary bg-accent-primary/20 hover:bg-accent-primary/30 transition-colors"
|
className="h-6 flex items-center gap-1 px-2 rounded-sm text-accent-primary bg-accent-primary/20 hover:bg-accent-primary/30 transition-colors"
|
||||||
aria-label="Locked"
|
aria-label="Locked"
|
||||||
>
|
>
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,16 @@
|
||||||
import { PROJECT_TRACKER_EVENTS } from "@plane/constants";
|
|
||||||
import { useTranslation } from "@plane/i18n";
|
|
||||||
import { observer } from "mobx-react";
|
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
|
import { observer } from "mobx-react";
|
||||||
import { FormProvider, useForm } from "react-hook-form";
|
import { FormProvider, useForm } from "react-hook-form";
|
||||||
// ui
|
// plane imports
|
||||||
|
import { useTranslation } from "@plane/i18n";
|
||||||
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
||||||
import { EFileAssetType } from "@plane/types";
|
import { EFileAssetType } from "@plane/types";
|
||||||
// constants
|
// components
|
||||||
import ProjectCommonAttributes from "@/components/project/create/common-attributes";
|
import ProjectCommonAttributes from "@/components/project/create/common-attributes";
|
||||||
import ProjectCreateHeader from "@/components/project/create/header";
|
import ProjectCreateHeader from "@/components/project/create/header";
|
||||||
import ProjectCreateButtons from "@/components/project/create/project-create-buttons";
|
import ProjectCreateButtons from "@/components/project/create/project-create-buttons";
|
||||||
// hooks
|
// hooks
|
||||||
import { getCoverImageType, uploadCoverImage } from "@/helpers/cover-image.helper";
|
import { getCoverImageType, uploadCoverImage } from "@/helpers/cover-image.helper";
|
||||||
import { captureError, captureSuccess } from "@/helpers/event-tracker.helper";
|
|
||||||
import { useProject } from "@/hooks/store/use-project";
|
import { useProject } from "@/hooks/store/use-project";
|
||||||
import { usePlatformOS } from "@/hooks/use-platform-os";
|
import { usePlatformOS } from "@/hooks/use-platform-os";
|
||||||
// plane web types
|
// plane web types
|
||||||
|
|
@ -97,12 +95,6 @@ export const CreateProjectForm = observer(function CreateProjectForm(props: TCre
|
||||||
await updateCoverImageStatus(res.id, coverImage);
|
await updateCoverImageStatus(res.id, coverImage);
|
||||||
await updateProject(workspaceSlug.toString(), res.id, { cover_image_url: coverImage });
|
await updateProject(workspaceSlug.toString(), res.id, { cover_image_url: coverImage });
|
||||||
}
|
}
|
||||||
captureSuccess({
|
|
||||||
eventName: PROJECT_TRACKER_EVENTS.create,
|
|
||||||
payload: {
|
|
||||||
identifier: formData.identifier,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
setToast({
|
setToast({
|
||||||
type: TOAST_TYPE.SUCCESS,
|
type: TOAST_TYPE.SUCCESS,
|
||||||
title: t("success"),
|
title: t("success"),
|
||||||
|
|
@ -116,13 +108,6 @@ export const CreateProjectForm = observer(function CreateProjectForm(props: TCre
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
try {
|
try {
|
||||||
captureError({
|
|
||||||
eventName: PROJECT_TRACKER_EVENTS.create,
|
|
||||||
payload: {
|
|
||||||
identifier: formData.identifier,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
// Handle the new error format where codes are nested in arrays under field names
|
// Handle the new error format where codes are nested in arrays under field names
|
||||||
const errorData = err?.data ?? {};
|
const errorData = err?.data ?? {};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,6 @@ import {
|
||||||
SUBSCRIPTION_REDIRECTION_URLS,
|
SUBSCRIPTION_REDIRECTION_URLS,
|
||||||
SUBSCRIPTION_WITH_BILLING_FREQUENCY,
|
SUBSCRIPTION_WITH_BILLING_FREQUENCY,
|
||||||
TALK_TO_SALES_URL,
|
TALK_TO_SALES_URL,
|
||||||
WORKSPACE_SETTINGS_TRACKER_ELEMENTS,
|
|
||||||
WORKSPACE_SETTINGS_TRACKER_EVENTS,
|
|
||||||
} from "@plane/constants";
|
} from "@plane/constants";
|
||||||
import { useTranslation } from "@plane/i18n";
|
import { useTranslation } from "@plane/i18n";
|
||||||
import { Button } from "@plane/propel/button";
|
import { Button } from "@plane/propel/button";
|
||||||
|
|
@ -16,7 +14,6 @@ import { getSubscriptionName } from "@plane/utils";
|
||||||
import { DiscountInfo } from "@/components/license/modal/card/discount-info";
|
import { DiscountInfo } from "@/components/license/modal/card/discount-info";
|
||||||
import type { TPlanDetail } from "@/constants/plans";
|
import type { TPlanDetail } from "@/constants/plans";
|
||||||
// local imports
|
// local imports
|
||||||
import { captureSuccess } from "@/helpers/event-tracker.helper";
|
|
||||||
import { PlanFrequencyToggle } from "./frequency-toggle";
|
import { PlanFrequencyToggle } from "./frequency-toggle";
|
||||||
|
|
||||||
type TPlanDetailProps = {
|
type TPlanDetailProps = {
|
||||||
|
|
@ -45,12 +42,6 @@ export const PlanDetail = observer(function PlanDetail(props: TPlanDetailProps)
|
||||||
const frequency = billingFrequency ?? "year";
|
const frequency = billingFrequency ?? "year";
|
||||||
// Get the redirection URL based on the subscription type and billing frequency
|
// Get the redirection URL based on the subscription type and billing frequency
|
||||||
const redirectUrl = SUBSCRIPTION_REDIRECTION_URLS[subscriptionType][frequency] ?? TALK_TO_SALES_URL;
|
const redirectUrl = SUBSCRIPTION_REDIRECTION_URLS[subscriptionType][frequency] ?? TALK_TO_SALES_URL;
|
||||||
captureSuccess({
|
|
||||||
eventName: WORKSPACE_SETTINGS_TRACKER_EVENTS.upgrade_plan_redirected,
|
|
||||||
payload: {
|
|
||||||
subscriptionType,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
// Open the URL in a new tab
|
// Open the URL in a new tab
|
||||||
window.open(redirectUrl, "_blank");
|
window.open(redirectUrl, "_blank");
|
||||||
};
|
};
|
||||||
|
|
@ -103,17 +94,7 @@ export const PlanDetail = observer(function PlanDetail(props: TPlanDetailProps)
|
||||||
|
|
||||||
{/* Subscription button */}
|
{/* Subscription button */}
|
||||||
<div className="flex flex-col gap-1 py-3 items-start">
|
<div className="flex flex-col gap-1 py-3 items-start">
|
||||||
<Button
|
<Button variant="primary" size="lg" onClick={handleRedirection} className="w-full">
|
||||||
variant="primary"
|
|
||||||
size="lg"
|
|
||||||
onClick={handleRedirection}
|
|
||||||
className="w-full"
|
|
||||||
data-ph-element={
|
|
||||||
isSubscriptionActive
|
|
||||||
? WORKSPACE_SETTINGS_TRACKER_ELEMENTS.BILLING_UPGRADE_BUTTON(subscriptionType)
|
|
||||||
: WORKSPACE_SETTINGS_TRACKER_ELEMENTS.BILLING_TALK_TO_SALES_BUTTON
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{isSubscriptionActive ? `Upgrade to ${subscriptionName}` : t("common.upgrade_cta.talk_to_sales")}
|
{isSubscriptionActive ? `Upgrade to ${subscriptionName}` : t("common.upgrade_cta.talk_to_sales")}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,5 @@
|
||||||
// types
|
|
||||||
import {
|
|
||||||
CYCLE_TRACKER_ELEMENTS,
|
|
||||||
MODULE_TRACKER_ELEMENTS,
|
|
||||||
PROJECT_PAGE_TRACKER_ELEMENTS,
|
|
||||||
PROJECT_TRACKER_ELEMENTS,
|
|
||||||
PROJECT_VIEW_TRACKER_ELEMENTS,
|
|
||||||
WORK_ITEM_TRACKER_ELEMENTS,
|
|
||||||
} from "@plane/constants";
|
|
||||||
import type { TCommandPaletteActionList, TCommandPaletteShortcut, TCommandPaletteShortcutList } from "@plane/types";
|
import type { TCommandPaletteActionList, TCommandPaletteShortcut, TCommandPaletteShortcutList } from "@plane/types";
|
||||||
// store
|
// store
|
||||||
import { captureClick } from "@/helpers/event-tracker.helper";
|
|
||||||
import { store } from "@/lib/store-context";
|
import { store } from "@/lib/store-context";
|
||||||
|
|
||||||
export const getGlobalShortcutsList: () => TCommandPaletteActionList = () => {
|
export const getGlobalShortcutsList: () => TCommandPaletteActionList = () => {
|
||||||
|
|
@ -21,7 +11,6 @@ export const getGlobalShortcutsList: () => TCommandPaletteActionList = () => {
|
||||||
description: "Create a new work item in the current project",
|
description: "Create a new work item in the current project",
|
||||||
action: () => {
|
action: () => {
|
||||||
toggleCreateIssueModal(true);
|
toggleCreateIssueModal(true);
|
||||||
captureClick({ elementName: WORK_ITEM_TRACKER_ELEMENTS.COMMAND_PALETTE_ADD_BUTTON });
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
@ -36,7 +25,6 @@ export const getWorkspaceShortcutsList: () => TCommandPaletteActionList = () =>
|
||||||
description: "Create a new project in the current workspace",
|
description: "Create a new project in the current workspace",
|
||||||
action: () => {
|
action: () => {
|
||||||
toggleCreateProjectModal(true);
|
toggleCreateProjectModal(true);
|
||||||
captureClick({ elementName: PROJECT_TRACKER_ELEMENTS.COMMAND_PALETTE_SHORTCUT_CREATE_BUTTON });
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
@ -57,7 +45,6 @@ export const getProjectShortcutsList: () => TCommandPaletteActionList = () => {
|
||||||
description: "Create a new page in the current project",
|
description: "Create a new page in the current project",
|
||||||
action: () => {
|
action: () => {
|
||||||
toggleCreatePageModal({ isOpen: true });
|
toggleCreatePageModal({ isOpen: true });
|
||||||
captureClick({ elementName: PROJECT_PAGE_TRACKER_ELEMENTS.COMMAND_PALETTE_SHORTCUT_CREATE_BUTTON });
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
m: {
|
m: {
|
||||||
|
|
@ -65,7 +52,6 @@ export const getProjectShortcutsList: () => TCommandPaletteActionList = () => {
|
||||||
description: "Create a new module in the current project",
|
description: "Create a new module in the current project",
|
||||||
action: () => {
|
action: () => {
|
||||||
toggleCreateModuleModal(true);
|
toggleCreateModuleModal(true);
|
||||||
captureClick({ elementName: MODULE_TRACKER_ELEMENTS.COMMAND_PALETTE_ADD_ITEM });
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
q: {
|
q: {
|
||||||
|
|
@ -73,7 +59,6 @@ export const getProjectShortcutsList: () => TCommandPaletteActionList = () => {
|
||||||
description: "Create a new cycle in the current project",
|
description: "Create a new cycle in the current project",
|
||||||
action: () => {
|
action: () => {
|
||||||
toggleCreateCycleModal(true);
|
toggleCreateCycleModal(true);
|
||||||
captureClick({ elementName: CYCLE_TRACKER_ELEMENTS.COMMAND_PALETTE_ADD_ITEM });
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
v: {
|
v: {
|
||||||
|
|
@ -81,7 +66,6 @@ export const getProjectShortcutsList: () => TCommandPaletteActionList = () => {
|
||||||
description: "Create a new view in the current project",
|
description: "Create a new view in the current project",
|
||||||
action: () => {
|
action: () => {
|
||||||
toggleCreateViewModal(true);
|
toggleCreateViewModal(true);
|
||||||
captureClick({ elementName: PROJECT_VIEW_TRACKER_ELEMENTS.COMMAND_PALETTE_ADD_ITEM });
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
backspace: {
|
backspace: {
|
||||||
|
|
|
||||||
|
|
@ -5,14 +5,11 @@ import { Controller, useForm } from "react-hook-form";
|
||||||
// icons
|
// icons
|
||||||
import { CircleCheck } from "lucide-react";
|
import { CircleCheck } from "lucide-react";
|
||||||
// plane imports
|
// plane imports
|
||||||
import { AUTH_TRACKER_EVENTS } from "@plane/constants";
|
|
||||||
import { useTranslation } from "@plane/i18n";
|
import { useTranslation } from "@plane/i18n";
|
||||||
import { Button, getButtonStyling } from "@plane/propel/button";
|
import { Button, getButtonStyling } from "@plane/propel/button";
|
||||||
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
||||||
import { Input } from "@plane/ui";
|
import { Input } from "@plane/ui";
|
||||||
import { cn, checkEmailValidity } from "@plane/utils";
|
import { cn, checkEmailValidity } from "@plane/utils";
|
||||||
// helpers
|
|
||||||
import { captureError, captureSuccess } from "@/helpers/event-tracker.helper";
|
|
||||||
// hooks
|
// hooks
|
||||||
import useTimer from "@/hooks/use-timer";
|
import useTimer from "@/hooks/use-timer";
|
||||||
// services
|
// services
|
||||||
|
|
@ -59,12 +56,6 @@ export const ForgotPasswordForm = observer(function ForgotPasswordForm() {
|
||||||
email: formData.email,
|
email: formData.email,
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
captureSuccess({
|
|
||||||
eventName: AUTH_TRACKER_EVENTS.forgot_password,
|
|
||||||
payload: {
|
|
||||||
email: formData.email,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
setToast({
|
setToast({
|
||||||
type: TOAST_TYPE.SUCCESS,
|
type: TOAST_TYPE.SUCCESS,
|
||||||
title: t("auth.forgot_password.toast.success.title"),
|
title: t("auth.forgot_password.toast.success.title"),
|
||||||
|
|
@ -73,12 +64,6 @@ export const ForgotPasswordForm = observer(function ForgotPasswordForm() {
|
||||||
setResendCodeTimer(30);
|
setResendCodeTimer(30);
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
captureError({
|
|
||||||
eventName: AUTH_TRACKER_EVENTS.forgot_password,
|
|
||||||
payload: {
|
|
||||||
email: formData.email,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
setToast({
|
setToast({
|
||||||
type: TOAST_TYPE.ERROR,
|
type: TOAST_TYPE.ERROR,
|
||||||
title: t("auth.forgot_password.toast.error.title"),
|
title: t("auth.forgot_password.toast.error.title"),
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import React, { useEffect, useMemo, useRef, useState } from "react";
|
import { useEffect, useMemo, useRef, useState } from "react";
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
// icons
|
// icons
|
||||||
|
|
@ -15,8 +15,6 @@ import { ForgotPasswordPopover } from "@/components/account/auth-forms/forgot-pa
|
||||||
// constants
|
// constants
|
||||||
// helpers
|
// helpers
|
||||||
import { EAuthModes, EAuthSteps } from "@/helpers/authentication.helper";
|
import { EAuthModes, EAuthSteps } from "@/helpers/authentication.helper";
|
||||||
// hooks
|
|
||||||
import { captureError, captureSuccess } from "@/helpers/event-tracker.helper";
|
|
||||||
// services
|
// services
|
||||||
import { AuthService } from "@/services/auth.service";
|
import { AuthService } from "@/services/auth.service";
|
||||||
|
|
||||||
|
|
@ -154,15 +152,6 @@ export const AuthPasswordForm = observer(function AuthPasswordForm(props: Props)
|
||||||
: true;
|
: true;
|
||||||
if (isPasswordValid) {
|
if (isPasswordValid) {
|
||||||
setIsSubmitting(true);
|
setIsSubmitting(true);
|
||||||
captureSuccess({
|
|
||||||
eventName:
|
|
||||||
mode === EAuthModes.SIGN_IN
|
|
||||||
? AUTH_TRACKER_EVENTS.sign_in_with_password
|
|
||||||
: AUTH_TRACKER_EVENTS.sign_up_with_password,
|
|
||||||
payload: {
|
|
||||||
email: passwordFormData.email,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
if (formRef.current) formRef.current.submit(); // Manually submit the form if the condition is met
|
if (formRef.current) formRef.current.submit(); // Manually submit the form if the condition is met
|
||||||
} else {
|
} else {
|
||||||
setBannerMessage(true);
|
setBannerMessage(true);
|
||||||
|
|
@ -170,15 +159,6 @@ export const AuthPasswordForm = observer(function AuthPasswordForm(props: Props)
|
||||||
}}
|
}}
|
||||||
onError={() => {
|
onError={() => {
|
||||||
setIsSubmitting(false);
|
setIsSubmitting(false);
|
||||||
captureError({
|
|
||||||
eventName:
|
|
||||||
mode === EAuthModes.SIGN_IN
|
|
||||||
? AUTH_TRACKER_EVENTS.sign_in_with_password
|
|
||||||
: AUTH_TRACKER_EVENTS.sign_up_with_password,
|
|
||||||
payload: {
|
|
||||||
email: passwordFormData.email,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<input type="hidden" name="csrfmiddlewaretoken" />
|
<input type="hidden" name="csrfmiddlewaretoken" />
|
||||||
|
|
|
||||||
|
|
@ -5,15 +5,13 @@ import { useSearchParams } from "next/navigation";
|
||||||
// icons
|
// icons
|
||||||
import { Eye, EyeOff } from "lucide-react";
|
import { Eye, EyeOff } from "lucide-react";
|
||||||
// plane imports
|
// plane imports
|
||||||
import { AUTH_TRACKER_ELEMENTS, AUTH_TRACKER_EVENTS, E_PASSWORD_STRENGTH } from "@plane/constants";
|
import { E_PASSWORD_STRENGTH } from "@plane/constants";
|
||||||
import { useTranslation } from "@plane/i18n";
|
import { useTranslation } from "@plane/i18n";
|
||||||
import { Button } from "@plane/propel/button";
|
import { Button } from "@plane/propel/button";
|
||||||
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
||||||
import { Input, PasswordStrengthIndicator } from "@plane/ui";
|
import { Input, PasswordStrengthIndicator } from "@plane/ui";
|
||||||
// components
|
// components
|
||||||
import { getPasswordStrength } from "@plane/utils";
|
import { getPasswordStrength } from "@plane/utils";
|
||||||
// helpers
|
|
||||||
import { captureError, captureSuccess, captureView } from "@/helpers/event-tracker.helper";
|
|
||||||
// hooks
|
// hooks
|
||||||
import { useUser } from "@/hooks/store/user";
|
import { useUser } from "@/hooks/store/user";
|
||||||
import { useAppRouter } from "@/hooks/use-app-router";
|
import { useAppRouter } from "@/hooks/use-app-router";
|
||||||
|
|
@ -60,12 +58,6 @@ export const SetPasswordForm = observer(function SetPasswordForm() {
|
||||||
// hooks
|
// hooks
|
||||||
const { data: user, handleSetPassword } = useUser();
|
const { data: user, handleSetPassword } = useUser();
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
captureView({
|
|
||||||
elementName: AUTH_TRACKER_ELEMENTS.SET_PASSWORD_FORM,
|
|
||||||
});
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (csrfToken === undefined)
|
if (csrfToken === undefined)
|
||||||
authService.requestCSRFToken().then((data) => data?.csrf_token && setCsrfToken(data.csrf_token));
|
authService.requestCSRFToken().then((data) => data?.csrf_token && setCsrfToken(data.csrf_token));
|
||||||
|
|
@ -92,9 +84,6 @@ export const SetPasswordForm = observer(function SetPasswordForm() {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (!csrfToken) throw new Error("csrf token not found");
|
if (!csrfToken) throw new Error("csrf token not found");
|
||||||
await handleSetPassword(csrfToken, { password: passwordFormData.password });
|
await handleSetPassword(csrfToken, { password: passwordFormData.password });
|
||||||
captureSuccess({
|
|
||||||
eventName: AUTH_TRACKER_EVENTS.password_created,
|
|
||||||
});
|
|
||||||
router.push("/");
|
router.push("/");
|
||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
let message = undefined;
|
let message = undefined;
|
||||||
|
|
@ -102,9 +91,6 @@ export const SetPasswordForm = observer(function SetPasswordForm() {
|
||||||
const err = error as Error & { error?: string };
|
const err = error as Error & { error?: string };
|
||||||
message = err.error;
|
message = err.error;
|
||||||
}
|
}
|
||||||
captureError({
|
|
||||||
eventName: AUTH_TRACKER_EVENTS.password_created,
|
|
||||||
});
|
|
||||||
setToast({
|
setToast({
|
||||||
type: TOAST_TYPE.ERROR,
|
type: TOAST_TYPE.ERROR,
|
||||||
title: t("common.errors.default.title"),
|
title: t("common.errors.default.title"),
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import React, { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { CircleCheck, XCircle } from "lucide-react";
|
import { CircleCheck, XCircle } from "lucide-react";
|
||||||
import { API_BASE_URL, AUTH_TRACKER_ELEMENTS, AUTH_TRACKER_EVENTS } from "@plane/constants";
|
import { API_BASE_URL } from "@plane/constants";
|
||||||
import { useTranslation } from "@plane/i18n";
|
import { useTranslation } from "@plane/i18n";
|
||||||
import { Button } from "@plane/propel/button";
|
import { Button } from "@plane/propel/button";
|
||||||
import { Input, Spinner } from "@plane/ui";
|
import { Input, Spinner } from "@plane/ui";
|
||||||
|
|
@ -8,7 +8,6 @@ import { Input, Spinner } from "@plane/ui";
|
||||||
// helpers
|
// helpers
|
||||||
import { EAuthModes } from "@/helpers/authentication.helper";
|
import { EAuthModes } from "@/helpers/authentication.helper";
|
||||||
// hooks
|
// hooks
|
||||||
import { captureError, captureSuccess } from "@/helpers/event-tracker.helper";
|
|
||||||
import useTimer from "@/hooks/use-timer";
|
import useTimer from "@/hooks/use-timer";
|
||||||
// services
|
// services
|
||||||
import { AuthService } from "@/services/auth.service";
|
import { AuthService } from "@/services/auth.service";
|
||||||
|
|
@ -59,22 +58,10 @@ export function AuthUniqueCodeForm(props: TAuthUniqueCodeForm) {
|
||||||
setResendCodeTimer(defaultResetTimerValue);
|
setResendCodeTimer(defaultResetTimerValue);
|
||||||
handleFormChange("code", uniqueCode?.code || "");
|
handleFormChange("code", uniqueCode?.code || "");
|
||||||
setIsRequestingNewCode(false);
|
setIsRequestingNewCode(false);
|
||||||
captureSuccess({
|
|
||||||
eventName: AUTH_TRACKER_EVENTS.new_code_requested,
|
|
||||||
payload: {
|
|
||||||
email: email,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
} catch {
|
} catch {
|
||||||
setResendCodeTimer(0);
|
setResendCodeTimer(0);
|
||||||
console.error("Error while requesting new code");
|
console.error("Error while requesting new code");
|
||||||
setIsRequestingNewCode(false);
|
setIsRequestingNewCode(false);
|
||||||
captureError({
|
|
||||||
eventName: AUTH_TRACKER_EVENTS.new_code_requested,
|
|
||||||
payload: {
|
|
||||||
email: email,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -93,22 +80,9 @@ export function AuthUniqueCodeForm(props: TAuthUniqueCodeForm) {
|
||||||
action={`${API_BASE_URL}/auth/${mode === EAuthModes.SIGN_IN ? "magic-sign-in" : "magic-sign-up"}/`}
|
action={`${API_BASE_URL}/auth/${mode === EAuthModes.SIGN_IN ? "magic-sign-in" : "magic-sign-up"}/`}
|
||||||
onSubmit={() => {
|
onSubmit={() => {
|
||||||
setIsSubmitting(true);
|
setIsSubmitting(true);
|
||||||
captureSuccess({
|
|
||||||
eventName: AUTH_TRACKER_EVENTS.code_verify,
|
|
||||||
payload: {
|
|
||||||
state: "SUCCESS",
|
|
||||||
first_time: !isExistingEmail,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}}
|
}}
|
||||||
onError={() => {
|
onError={() => {
|
||||||
setIsSubmitting(false);
|
setIsSubmitting(false);
|
||||||
captureError({
|
|
||||||
eventName: AUTH_TRACKER_EVENTS.code_verify,
|
|
||||||
payload: {
|
|
||||||
state: "FAILED",
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<input type="hidden" name="csrfmiddlewaretoken" value={csrfToken} />
|
<input type="hidden" name="csrfmiddlewaretoken" value={csrfToken} />
|
||||||
|
|
@ -163,7 +137,6 @@ export function AuthUniqueCodeForm(props: TAuthUniqueCodeForm) {
|
||||||
</p>
|
</p>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
data-ph-element={AUTH_TRACKER_ELEMENTS.REQUEST_NEW_CODE}
|
|
||||||
onClick={() => generateNewCode(uniqueCodeFormData.email)}
|
onClick={() => generateNewCode(uniqueCodeFormData.email)}
|
||||||
className={
|
className={
|
||||||
isRequestNewCodeDisabled
|
isRequestNewCodeDisabled
|
||||||
|
|
@ -182,14 +155,7 @@ export function AuthUniqueCodeForm(props: TAuthUniqueCodeForm) {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="space-y-2.5">
|
<div className="space-y-2.5">
|
||||||
<Button
|
<Button type="submit" variant="primary" className="w-full" size="xl" disabled={isButtonDisabled}>
|
||||||
type="submit"
|
|
||||||
variant="primary"
|
|
||||||
className="w-full"
|
|
||||||
size="xl"
|
|
||||||
disabled={isButtonDisabled}
|
|
||||||
data-ph-element={AUTH_TRACKER_ELEMENTS.VERIFY_CODE}
|
|
||||||
>
|
|
||||||
{isRequestingNewCode ? (
|
{isRequestingNewCode ? (
|
||||||
t("auth.common.unique_code.sending_code")
|
t("auth.common.unique_code.sending_code")
|
||||||
) : isSubmitting ? (
|
) : isSubmitting ? (
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { PROFILE_SETTINGS_TRACKER_EVENTS } from "@plane/constants";
|
|
||||||
import { useTranslation } from "@plane/i18n";
|
import { useTranslation } from "@plane/i18n";
|
||||||
// ui
|
// ui
|
||||||
import { Button } from "@plane/propel/button";
|
import { Button } from "@plane/propel/button";
|
||||||
|
|
@ -7,7 +6,6 @@ import { TrashIcon } from "@plane/propel/icons";
|
||||||
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
||||||
import { EModalPosition, EModalWidth, ModalCore } from "@plane/ui";
|
import { EModalPosition, EModalWidth, ModalCore } from "@plane/ui";
|
||||||
// hooks
|
// hooks
|
||||||
import { captureError, captureSuccess } from "@/helpers/event-tracker.helper";
|
|
||||||
import { useUser } from "@/hooks/store/user";
|
import { useUser } from "@/hooks/store/user";
|
||||||
import { useAppRouter } from "@/hooks/use-app-router";
|
import { useAppRouter } from "@/hooks/use-app-router";
|
||||||
|
|
||||||
|
|
@ -36,9 +34,6 @@ export function DeactivateAccountModal(props: Props) {
|
||||||
|
|
||||||
await deactivateAccount()
|
await deactivateAccount()
|
||||||
.then(() => {
|
.then(() => {
|
||||||
captureSuccess({
|
|
||||||
eventName: PROFILE_SETTINGS_TRACKER_EVENTS.deactivate_account,
|
|
||||||
});
|
|
||||||
setToast({
|
setToast({
|
||||||
type: TOAST_TYPE.SUCCESS,
|
type: TOAST_TYPE.SUCCESS,
|
||||||
title: "Success!",
|
title: "Success!",
|
||||||
|
|
@ -50,9 +45,6 @@ export function DeactivateAccountModal(props: Props) {
|
||||||
return;
|
return;
|
||||||
})
|
})
|
||||||
.catch((err: any) => {
|
.catch((err: any) => {
|
||||||
captureError({
|
|
||||||
eventName: PROFILE_SETTINGS_TRACKER_EVENTS.deactivate_account,
|
|
||||||
});
|
|
||||||
setToast({
|
setToast({
|
||||||
type: TOAST_TYPE.ERROR,
|
type: TOAST_TYPE.ERROR,
|
||||||
title: "Error!",
|
title: "Error!",
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,6 @@
|
||||||
import type { FC } from "react";
|
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { mutate } from "swr";
|
import { mutate } from "swr";
|
||||||
// types
|
// types
|
||||||
import { PROFILE_SETTINGS_TRACKER_EVENTS } from "@plane/constants";
|
|
||||||
import { useTranslation } from "@plane/i18n";
|
import { useTranslation } from "@plane/i18n";
|
||||||
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
||||||
import { APITokenService } from "@plane/services";
|
import { APITokenService } from "@plane/services";
|
||||||
|
|
@ -11,7 +9,6 @@ import type { IApiToken } from "@plane/types";
|
||||||
import { AlertModalCore } from "@plane/ui";
|
import { AlertModalCore } from "@plane/ui";
|
||||||
// fetch-keys
|
// fetch-keys
|
||||||
import { API_TOKENS_LIST } from "@/constants/fetch-keys";
|
import { API_TOKENS_LIST } from "@/constants/fetch-keys";
|
||||||
import { captureError, captureSuccess } from "@/helpers/event-tracker.helper";
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
|
|
@ -50,32 +47,18 @@ export function DeleteApiTokenModal(props: Props) {
|
||||||
(prevData) => (prevData ?? []).filter((token) => token.id !== tokenId),
|
(prevData) => (prevData ?? []).filter((token) => token.id !== tokenId),
|
||||||
false
|
false
|
||||||
);
|
);
|
||||||
captureSuccess({
|
|
||||||
eventName: PROFILE_SETTINGS_TRACKER_EVENTS.pat_deleted,
|
|
||||||
payload: {
|
|
||||||
token: tokenId,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
handleClose();
|
handleClose();
|
||||||
|
setDeleteLoading(false);
|
||||||
})
|
})
|
||||||
.catch((err) =>
|
.catch((err) => {
|
||||||
setToast({
|
setToast({
|
||||||
type: TOAST_TYPE.ERROR,
|
type: TOAST_TYPE.ERROR,
|
||||||
title: t("workspace_settings.settings.api_tokens.delete.error.title"),
|
title: t("workspace_settings.settings.api_tokens.delete.error.title"),
|
||||||
message: err?.message ?? t("workspace_settings.settings.api_tokens.delete.error.message"),
|
message: err?.message ?? t("workspace_settings.settings.api_tokens.delete.error.message"),
|
||||||
})
|
|
||||||
)
|
|
||||||
.catch((err) => {
|
|
||||||
captureError({
|
|
||||||
eventName: PROFILE_SETTINGS_TRACKER_EVENTS.pat_deleted,
|
|
||||||
payload: {
|
|
||||||
token: tokenId,
|
|
||||||
},
|
|
||||||
error: err as Error,
|
|
||||||
});
|
});
|
||||||
})
|
setDeleteLoading(false);
|
||||||
.finally(() => setDeleteLoading(false));
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
import React, { useState } from "react";
|
import { useState } from "react";
|
||||||
import { mutate } from "swr";
|
import { mutate } from "swr";
|
||||||
// plane imports
|
// plane imports
|
||||||
import { PROFILE_SETTINGS_TRACKER_EVENTS } from "@plane/constants";
|
|
||||||
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
||||||
import { APITokenService } from "@plane/services";
|
import { APITokenService } from "@plane/services";
|
||||||
import type { IApiToken } from "@plane/types";
|
import type { IApiToken } from "@plane/types";
|
||||||
|
|
@ -9,8 +8,6 @@ import { EModalPosition, EModalWidth, ModalCore } from "@plane/ui";
|
||||||
import { renderFormattedDate, csvDownload } from "@plane/utils";
|
import { renderFormattedDate, csvDownload } from "@plane/utils";
|
||||||
// constants
|
// constants
|
||||||
import { API_TOKENS_LIST } from "@/constants/fetch-keys";
|
import { API_TOKENS_LIST } from "@/constants/fetch-keys";
|
||||||
// helpers
|
|
||||||
import { captureError, captureSuccess } from "@/helpers/event-tracker.helper";
|
|
||||||
// local imports
|
// local imports
|
||||||
import { CreateApiTokenForm } from "./form";
|
import { CreateApiTokenForm } from "./form";
|
||||||
import { GeneratedTokenDetails } from "./generated-token-details";
|
import { GeneratedTokenDetails } from "./generated-token-details";
|
||||||
|
|
@ -66,12 +63,6 @@ export function CreateApiTokenModal(props: Props) {
|
||||||
},
|
},
|
||||||
false
|
false
|
||||||
);
|
);
|
||||||
captureSuccess({
|
|
||||||
eventName: PROFILE_SETTINGS_TRACKER_EVENTS.pat_created,
|
|
||||||
payload: {
|
|
||||||
token: res.id,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
setToast({
|
setToast({
|
||||||
|
|
@ -80,10 +71,6 @@ export function CreateApiTokenModal(props: Props) {
|
||||||
message: err.message || err.detail,
|
message: err.message || err.detail,
|
||||||
});
|
});
|
||||||
|
|
||||||
captureError({
|
|
||||||
eventName: PROFILE_SETTINGS_TRACKER_EVENTS.pat_created,
|
|
||||||
});
|
|
||||||
|
|
||||||
throw err;
|
throw err;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,24 +1,16 @@
|
||||||
import React, { useMemo, useState } from "react";
|
import { useMemo, useState } from "react";
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
import { useParams } from "next/navigation";
|
import { useParams } from "next/navigation";
|
||||||
import { ArchiveRestore } from "lucide-react";
|
import { ArchiveRestore } from "lucide-react";
|
||||||
// types
|
// types
|
||||||
import {
|
import { PROJECT_AUTOMATION_MONTHS, EUserPermissions, EUserPermissionsLevel } from "@plane/constants";
|
||||||
PROJECT_AUTOMATION_MONTHS,
|
|
||||||
EUserPermissions,
|
|
||||||
EUserPermissionsLevel,
|
|
||||||
PROJECT_SETTINGS_TRACKER_ELEMENTS,
|
|
||||||
PROJECT_SETTINGS_TRACKER_EVENTS,
|
|
||||||
} from "@plane/constants";
|
|
||||||
import { useTranslation } from "@plane/i18n";
|
import { useTranslation } from "@plane/i18n";
|
||||||
import type { IProject } from "@plane/types";
|
import type { IProject } from "@plane/types";
|
||||||
// ui
|
// ui
|
||||||
import { CustomSelect, Loader, ToggleSwitch } from "@plane/ui";
|
import { CustomSelect, Loader, ToggleSwitch } from "@plane/ui";
|
||||||
// component
|
// component
|
||||||
import { SelectMonthModal } from "@/components/automation";
|
import { SelectMonthModal } from "@/components/automation";
|
||||||
// constants
|
|
||||||
// hooks
|
// hooks
|
||||||
import { captureElementAndEvent } from "@/helpers/event-tracker.helper";
|
|
||||||
import { useProject } from "@/hooks/store/use-project";
|
import { useProject } from "@/hooks/store/use-project";
|
||||||
import { useUserPermissions } from "@/hooks/store/user";
|
import { useUserPermissions } from "@/hooks/store/user";
|
||||||
|
|
||||||
|
|
@ -52,6 +44,14 @@ export const AutoArchiveAutomation = observer(function AutoArchiveAutomation(pro
|
||||||
return currentProjectDetails.archive_in !== 0;
|
return currentProjectDetails.archive_in !== 0;
|
||||||
}, [currentProjectDetails]);
|
}, [currentProjectDetails]);
|
||||||
|
|
||||||
|
const handleToggleArchive = async () => {
|
||||||
|
if (currentProjectDetails?.archive_in === 0) {
|
||||||
|
await handleChange({ archive_in: 1 });
|
||||||
|
} else {
|
||||||
|
await handleChange({ archive_in: 0 });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<SelectMonthModal
|
<SelectMonthModal
|
||||||
|
|
@ -74,27 +74,7 @@ export const AutoArchiveAutomation = observer(function AutoArchiveAutomation(pro
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<ToggleSwitch
|
<ToggleSwitch value={autoArchiveStatus} onChange={handleToggleArchive} size="sm" disabled={!isAdmin} />
|
||||||
value={autoArchiveStatus}
|
|
||||||
onChange={async () => {
|
|
||||||
if (currentProjectDetails?.archive_in === 0) {
|
|
||||||
await handleChange({ archive_in: 1 });
|
|
||||||
} else {
|
|
||||||
await handleChange({ archive_in: 0 });
|
|
||||||
}
|
|
||||||
captureElementAndEvent({
|
|
||||||
element: {
|
|
||||||
elementName: PROJECT_SETTINGS_TRACKER_ELEMENTS.AUTOMATIONS_ARCHIVE_TOGGLE_BUTTON,
|
|
||||||
},
|
|
||||||
event: {
|
|
||||||
eventName: PROJECT_SETTINGS_TRACKER_EVENTS.auto_archive_workitems,
|
|
||||||
state: "SUCCESS",
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
size="sm"
|
|
||||||
disabled={!isAdmin}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{currentProjectDetails ? (
|
{currentProjectDetails ? (
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,10 @@
|
||||||
import React, { useMemo, useState } from "react";
|
import { useMemo, useState } from "react";
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
import { useParams } from "next/navigation";
|
import { useParams } from "next/navigation";
|
||||||
// icons
|
// icons
|
||||||
import { ArchiveX } from "lucide-react";
|
import { ArchiveX } from "lucide-react";
|
||||||
// types
|
// types
|
||||||
import {
|
import { PROJECT_AUTOMATION_MONTHS, EUserPermissions, EUserPermissionsLevel, EIconSize } from "@plane/constants";
|
||||||
PROJECT_AUTOMATION_MONTHS,
|
|
||||||
EUserPermissions,
|
|
||||||
EUserPermissionsLevel,
|
|
||||||
EIconSize,
|
|
||||||
PROJECT_SETTINGS_TRACKER_ELEMENTS,
|
|
||||||
PROJECT_SETTINGS_TRACKER_EVENTS,
|
|
||||||
} from "@plane/constants";
|
|
||||||
import { useTranslation } from "@plane/i18n";
|
import { useTranslation } from "@plane/i18n";
|
||||||
import { StateGroupIcon, StatePropertyIcon } from "@plane/propel/icons";
|
import { StateGroupIcon, StatePropertyIcon } from "@plane/propel/icons";
|
||||||
import type { IProject } from "@plane/types";
|
import type { IProject } from "@plane/types";
|
||||||
|
|
@ -21,7 +14,6 @@ import { CustomSelect, CustomSearchSelect, ToggleSwitch, Loader } from "@plane/u
|
||||||
import { SelectMonthModal } from "@/components/automation";
|
import { SelectMonthModal } from "@/components/automation";
|
||||||
// constants
|
// constants
|
||||||
// hooks
|
// hooks
|
||||||
import { captureElementAndEvent } from "@/helpers/event-tracker.helper";
|
|
||||||
import { useProject } from "@/hooks/store/use-project";
|
import { useProject } from "@/hooks/store/use-project";
|
||||||
import { useProjectState } from "@/hooks/store/use-project-state";
|
import { useProjectState } from "@/hooks/store/use-project-state";
|
||||||
import { useUserPermissions } from "@/hooks/store/user";
|
import { useUserPermissions } from "@/hooks/store/user";
|
||||||
|
|
@ -111,15 +103,6 @@ export const AutoCloseAutomation = observer(function AutoCloseAutomation(props:
|
||||||
} else {
|
} else {
|
||||||
await handleChange({ close_in: 0, default_state: null });
|
await handleChange({ close_in: 0, default_state: null });
|
||||||
}
|
}
|
||||||
captureElementAndEvent({
|
|
||||||
element: {
|
|
||||||
elementName: PROJECT_SETTINGS_TRACKER_ELEMENTS.AUTOMATIONS_CLOSE_TOGGLE_BUTTON,
|
|
||||||
},
|
|
||||||
event: {
|
|
||||||
eventName: PROJECT_SETTINGS_TRACKER_EVENTS.auto_close_workitems,
|
|
||||||
state: "SUCCESS",
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}}
|
}}
|
||||||
size="sm"
|
size="sm"
|
||||||
disabled={!isAdmin}
|
disabled={!isAdmin}
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,9 @@
|
||||||
import type { FC } from "react";
|
import { useEffect } from "react";
|
||||||
import React, { useEffect } from "react";
|
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
import { Controller, useForm } from "react-hook-form";
|
import { Controller, useForm } from "react-hook-form";
|
||||||
import { ArrowRight } from "lucide-react";
|
import { ArrowRight } from "lucide-react";
|
||||||
// Plane Imports
|
// Plane Imports
|
||||||
import {
|
import { CYCLE_STATUS, EUserPermissions, EUserPermissionsLevel } from "@plane/constants";
|
||||||
CYCLE_TRACKER_EVENTS,
|
|
||||||
CYCLE_STATUS,
|
|
||||||
EUserPermissions,
|
|
||||||
EUserPermissionsLevel,
|
|
||||||
CYCLE_TRACKER_ELEMENTS,
|
|
||||||
} from "@plane/constants";
|
|
||||||
import { useTranslation } from "@plane/i18n";
|
import { useTranslation } from "@plane/i18n";
|
||||||
import { ChevronRightIcon } from "@plane/propel/icons";
|
import { ChevronRightIcon } from "@plane/propel/icons";
|
||||||
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
||||||
|
|
@ -19,7 +12,6 @@ import { getDate, renderFormattedPayloadDate } from "@plane/utils";
|
||||||
// components
|
// components
|
||||||
import { DateRangeDropdown } from "@/components/dropdowns/date-range";
|
import { DateRangeDropdown } from "@/components/dropdowns/date-range";
|
||||||
// hooks
|
// hooks
|
||||||
import { captureElementAndEvent } from "@/helpers/event-tracker.helper";
|
|
||||||
import { useCycle } from "@/hooks/store/use-cycle";
|
import { useCycle } from "@/hooks/store/use-cycle";
|
||||||
import { useUserPermissions } from "@/hooks/store/user";
|
import { useUserPermissions } from "@/hooks/store/user";
|
||||||
import { useTimeZoneConverter } from "@/hooks/use-timezone-converter";
|
import { useTimeZoneConverter } from "@/hooks/use-timezone-converter";
|
||||||
|
|
@ -64,37 +56,7 @@ export const CycleSidebarHeader = observer(function CycleSidebarHeader(props: Pr
|
||||||
|
|
||||||
const submitChanges = async (data: Partial<ICycle>) => {
|
const submitChanges = async (data: Partial<ICycle>) => {
|
||||||
if (!workspaceSlug || !projectId || !cycleDetails.id) return;
|
if (!workspaceSlug || !projectId || !cycleDetails.id) return;
|
||||||
|
await updateCycleDetails(workspaceSlug.toString(), projectId.toString(), cycleDetails.id.toString(), data);
|
||||||
await updateCycleDetails(workspaceSlug.toString(), projectId.toString(), cycleDetails.id.toString(), data)
|
|
||||||
.then(() => {
|
|
||||||
captureElementAndEvent({
|
|
||||||
element: {
|
|
||||||
elementName: CYCLE_TRACKER_ELEMENTS.RIGHT_SIDEBAR,
|
|
||||||
},
|
|
||||||
event: {
|
|
||||||
eventName: CYCLE_TRACKER_EVENTS.update,
|
|
||||||
state: "SUCCESS",
|
|
||||||
payload: {
|
|
||||||
id: cycleDetails.id,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
})
|
|
||||||
|
|
||||||
.catch(() => {
|
|
||||||
captureElementAndEvent({
|
|
||||||
element: {
|
|
||||||
elementName: CYCLE_TRACKER_ELEMENTS.RIGHT_SIDEBAR,
|
|
||||||
},
|
|
||||||
event: {
|
|
||||||
eventName: CYCLE_TRACKER_EVENTS.update,
|
|
||||||
state: "ERROR",
|
|
||||||
payload: {
|
|
||||||
id: cycleDetails.id,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,9 @@
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
// ui
|
// ui
|
||||||
import { CYCLE_TRACKER_EVENTS } from "@plane/constants";
|
|
||||||
import { Button } from "@plane/propel/button";
|
import { Button } from "@plane/propel/button";
|
||||||
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
||||||
import { EModalPosition, EModalWidth, ModalCore } from "@plane/ui";
|
import { EModalPosition, EModalWidth, ModalCore } from "@plane/ui";
|
||||||
// hooks
|
// hooks
|
||||||
import { captureError, captureSuccess } from "@/helpers/event-tracker.helper";
|
|
||||||
import { useCycle } from "@/hooks/store/use-cycle";
|
import { useCycle } from "@/hooks/store/use-cycle";
|
||||||
import { useAppRouter } from "@/hooks/use-app-router";
|
import { useAppRouter } from "@/hooks/use-app-router";
|
||||||
|
|
||||||
|
|
@ -43,12 +41,6 @@ export function ArchiveCycleModal(props: Props) {
|
||||||
title: "Archive success",
|
title: "Archive success",
|
||||||
message: "Your archives can be found in project archives.",
|
message: "Your archives can be found in project archives.",
|
||||||
});
|
});
|
||||||
captureSuccess({
|
|
||||||
eventName: CYCLE_TRACKER_EVENTS.archive,
|
|
||||||
payload: {
|
|
||||||
id: cycleId,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
onClose();
|
onClose();
|
||||||
router.push(`/${workspaceSlug}/projects/${projectId}/cycles`);
|
router.push(`/${workspaceSlug}/projects/${projectId}/cycles`);
|
||||||
return;
|
return;
|
||||||
|
|
@ -59,12 +51,6 @@ export function ArchiveCycleModal(props: Props) {
|
||||||
title: "Error!",
|
title: "Error!",
|
||||||
message: "Cycle could not be archived. Please try again.",
|
message: "Cycle could not be archived. Please try again.",
|
||||||
});
|
});
|
||||||
captureError({
|
|
||||||
eventName: CYCLE_TRACKER_EVENTS.archive,
|
|
||||||
payload: {
|
|
||||||
id: cycleId,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
})
|
})
|
||||||
.finally(() => setIsArchiving(false));
|
.finally(() => setIsArchiving(false));
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -2,14 +2,12 @@ import { useState } from "react";
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
import { useParams, useSearchParams } from "next/navigation";
|
import { useParams, useSearchParams } from "next/navigation";
|
||||||
// types
|
// types
|
||||||
import { PROJECT_ERROR_MESSAGES, CYCLE_TRACKER_EVENTS } from "@plane/constants";
|
import { PROJECT_ERROR_MESSAGES } from "@plane/constants";
|
||||||
import { useTranslation } from "@plane/i18n";
|
import { useTranslation } from "@plane/i18n";
|
||||||
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
||||||
import type { ICycle } from "@plane/types";
|
import type { ICycle } from "@plane/types";
|
||||||
// ui
|
// ui
|
||||||
import { AlertModalCore } from "@plane/ui";
|
import { AlertModalCore } from "@plane/ui";
|
||||||
// helpers
|
|
||||||
import { captureError, captureSuccess } from "@/helpers/event-tracker.helper";
|
|
||||||
// hooks
|
// hooks
|
||||||
import { useCycle } from "@/hooks/store/use-cycle";
|
import { useCycle } from "@/hooks/store/use-cycle";
|
||||||
import { useAppRouter } from "@/hooks/use-app-router";
|
import { useAppRouter } from "@/hooks/use-app-router";
|
||||||
|
|
@ -48,12 +46,6 @@ export const CycleDeleteModal = observer(function CycleDeleteModal(props: ICycle
|
||||||
title: "Success!",
|
title: "Success!",
|
||||||
message: "Cycle deleted successfully.",
|
message: "Cycle deleted successfully.",
|
||||||
});
|
});
|
||||||
captureSuccess({
|
|
||||||
eventName: CYCLE_TRACKER_EVENTS.delete,
|
|
||||||
payload: {
|
|
||||||
id: cycle.id,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
})
|
})
|
||||||
.catch((errors) => {
|
.catch((errors) => {
|
||||||
const isPermissionError = errors?.error === "You don't have the required permissions.";
|
const isPermissionError = errors?.error === "You don't have the required permissions.";
|
||||||
|
|
@ -65,13 +57,6 @@ export const CycleDeleteModal = observer(function CycleDeleteModal(props: ICycle
|
||||||
type: TOAST_TYPE.ERROR,
|
type: TOAST_TYPE.ERROR,
|
||||||
message: currentError.i18n_message && t(currentError.i18n_message),
|
message: currentError.i18n_message && t(currentError.i18n_message),
|
||||||
});
|
});
|
||||||
captureError({
|
|
||||||
eventName: CYCLE_TRACKER_EVENTS.delete,
|
|
||||||
payload: {
|
|
||||||
id: cycle.id,
|
|
||||||
},
|
|
||||||
error: errors,
|
|
||||||
});
|
|
||||||
})
|
})
|
||||||
.finally(() => handleClose());
|
.finally(() => handleClose());
|
||||||
} catch {
|
} catch {
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,11 @@
|
||||||
import type { FC, MouseEvent } from "react";
|
import type { MouseEvent } from "react";
|
||||||
import React, { useEffect, useMemo, useState } from "react";
|
import React, { useEffect, useMemo, useState } from "react";
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
import { useParams, usePathname, useSearchParams } from "next/navigation";
|
import { useParams, usePathname, useSearchParams } from "next/navigation";
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
import { Eye, ArrowRight, CalendarDays } from "lucide-react";
|
import { Eye, ArrowRight, CalendarDays } from "lucide-react";
|
||||||
// plane imports
|
// plane imports
|
||||||
import {
|
import { EUserPermissions, EUserPermissionsLevel, IS_FAVORITE_MENU_OPEN } from "@plane/constants";
|
||||||
CYCLE_TRACKER_EVENTS,
|
|
||||||
EUserPermissions,
|
|
||||||
EUserPermissionsLevel,
|
|
||||||
IS_FAVORITE_MENU_OPEN,
|
|
||||||
CYCLE_TRACKER_ELEMENTS,
|
|
||||||
} from "@plane/constants";
|
|
||||||
import { useLocalStorage } from "@plane/hooks";
|
import { useLocalStorage } from "@plane/hooks";
|
||||||
import { useTranslation } from "@plane/i18n";
|
import { useTranslation } from "@plane/i18n";
|
||||||
import { TransferIcon, WorkItemsIcon, MembersPropertyIcon } from "@plane/propel/icons";
|
import { TransferIcon, WorkItemsIcon, MembersPropertyIcon } from "@plane/propel/icons";
|
||||||
|
|
@ -25,7 +19,6 @@ import { DateRangeDropdown } from "@/components/dropdowns/date-range";
|
||||||
import { ButtonAvatars } from "@/components/dropdowns/member/avatar";
|
import { ButtonAvatars } from "@/components/dropdowns/member/avatar";
|
||||||
import { MergedDateDisplay } from "@/components/dropdowns/merged-date";
|
import { MergedDateDisplay } from "@/components/dropdowns/merged-date";
|
||||||
// hooks
|
// hooks
|
||||||
import { captureError, captureSuccess } from "@/helpers/event-tracker.helper";
|
|
||||||
import { useCycle } from "@/hooks/store/use-cycle";
|
import { useCycle } from "@/hooks/store/use-cycle";
|
||||||
import { useMember } from "@/hooks/store/use-member";
|
import { useMember } from "@/hooks/store/use-member";
|
||||||
import { useUserPermissions } from "@/hooks/store/user";
|
import { useUserPermissions } from "@/hooks/store/user";
|
||||||
|
|
@ -109,25 +102,11 @@ export const CycleListItemAction = observer(function CycleListItemAction(props:
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (!workspaceSlug || !projectId) return;
|
if (!workspaceSlug || !projectId) return;
|
||||||
|
|
||||||
const addToFavoritePromise = addCycleToFavorites(workspaceSlug?.toString(), projectId.toString(), cycleId)
|
const addToFavoritePromise = addCycleToFavorites(workspaceSlug?.toString(), projectId.toString(), cycleId).then(
|
||||||
.then(() => {
|
() => {
|
||||||
if (!isFavoriteMenuOpen) toggleFavoriteMenu(true);
|
if (!isFavoriteMenuOpen) toggleFavoriteMenu(true);
|
||||||
captureSuccess({
|
}
|
||||||
eventName: CYCLE_TRACKER_EVENTS.favorite,
|
);
|
||||||
payload: {
|
|
||||||
id: cycleId,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
captureError({
|
|
||||||
eventName: CYCLE_TRACKER_EVENTS.favorite,
|
|
||||||
payload: {
|
|
||||||
id: cycleId,
|
|
||||||
},
|
|
||||||
error,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
setPromiseToast(addToFavoritePromise, {
|
setPromiseToast(addToFavoritePromise, {
|
||||||
loading: t("project_cycles.action.favorite.loading"),
|
loading: t("project_cycles.action.favorite.loading"),
|
||||||
|
|
@ -146,24 +125,11 @@ export const CycleListItemAction = observer(function CycleListItemAction(props:
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (!workspaceSlug || !projectId) return;
|
if (!workspaceSlug || !projectId) return;
|
||||||
|
|
||||||
const removeFromFavoritePromise = removeCycleFromFavorites(workspaceSlug?.toString(), projectId.toString(), cycleId)
|
const removeFromFavoritePromise = removeCycleFromFavorites(
|
||||||
.then(() => {
|
workspaceSlug?.toString(),
|
||||||
captureSuccess({
|
projectId.toString(),
|
||||||
eventName: CYCLE_TRACKER_EVENTS.unfavorite,
|
cycleId
|
||||||
payload: {
|
);
|
||||||
id: cycleId,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
captureError({
|
|
||||||
eventName: CYCLE_TRACKER_EVENTS.unfavorite,
|
|
||||||
payload: {
|
|
||||||
id: cycleId,
|
|
||||||
},
|
|
||||||
error,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
setPromiseToast(removeFromFavoritePromise, {
|
setPromiseToast(removeFromFavoritePromise, {
|
||||||
loading: t("project_cycles.action.unfavorite.loading"),
|
loading: t("project_cycles.action.unfavorite.loading"),
|
||||||
|
|
@ -319,7 +285,6 @@ export const CycleListItemAction = observer(function CycleListItemAction(props:
|
||||||
)}
|
)}
|
||||||
{isEditingAllowed && !cycleDetails.archived_at && (
|
{isEditingAllowed && !cycleDetails.archived_at && (
|
||||||
<FavoriteStar
|
<FavoriteStar
|
||||||
data-ph-element={CYCLE_TRACKER_ELEMENTS.LIST_ITEM}
|
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,12 @@
|
||||||
import React, { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { mutate } from "swr";
|
import { mutate } from "swr";
|
||||||
// types
|
// types
|
||||||
import { CYCLE_TRACKER_EVENTS } from "@plane/constants";
|
|
||||||
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
||||||
import type { CycleDateCheckData, ICycle, TCycleTabOptions } from "@plane/types";
|
import type { CycleDateCheckData, ICycle, TCycleTabOptions } from "@plane/types";
|
||||||
// ui
|
// ui
|
||||||
import { EModalPosition, EModalWidth, ModalCore } from "@plane/ui";
|
import { EModalPosition, EModalWidth, ModalCore } from "@plane/ui";
|
||||||
// hooks
|
// hooks
|
||||||
import { renderFormattedPayloadDate } from "@plane/utils";
|
import { renderFormattedPayloadDate } from "@plane/utils";
|
||||||
import { captureError, captureSuccess } from "@/helpers/event-tracker.helper";
|
|
||||||
import { useCycle } from "@/hooks/store/use-cycle";
|
import { useCycle } from "@/hooks/store/use-cycle";
|
||||||
import { useProject } from "@/hooks/store/use-project";
|
import { useProject } from "@/hooks/store/use-project";
|
||||||
import useKeypress from "@/hooks/use-keypress";
|
import useKeypress from "@/hooks/use-keypress";
|
||||||
|
|
@ -62,12 +60,6 @@ export function CycleCreateUpdateModal(props: CycleModalProps) {
|
||||||
title: "Success!",
|
title: "Success!",
|
||||||
message: "Cycle created successfully.",
|
message: "Cycle created successfully.",
|
||||||
});
|
});
|
||||||
captureSuccess({
|
|
||||||
eventName: CYCLE_TRACKER_EVENTS.create,
|
|
||||||
payload: {
|
|
||||||
id: res.id,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
setToast({
|
setToast({
|
||||||
|
|
@ -75,10 +67,6 @@ export function CycleCreateUpdateModal(props: CycleModalProps) {
|
||||||
title: "Error!",
|
title: "Error!",
|
||||||
message: err?.detail ?? "Error in creating cycle. Please try again.",
|
message: err?.detail ?? "Error in creating cycle. Please try again.",
|
||||||
});
|
});
|
||||||
captureError({
|
|
||||||
eventName: CYCLE_TRACKER_EVENTS.create,
|
|
||||||
error: err,
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -88,12 +76,6 @@ export function CycleCreateUpdateModal(props: CycleModalProps) {
|
||||||
const selectedProjectId = payload.project_id ?? projectId.toString();
|
const selectedProjectId = payload.project_id ?? projectId.toString();
|
||||||
await updateCycleDetails(workspaceSlug, selectedProjectId, cycleId, payload)
|
await updateCycleDetails(workspaceSlug, selectedProjectId, cycleId, payload)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
captureSuccess({
|
|
||||||
eventName: CYCLE_TRACKER_EVENTS.update,
|
|
||||||
payload: {
|
|
||||||
id: res.id,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
setToast({
|
setToast({
|
||||||
type: TOAST_TYPE.SUCCESS,
|
type: TOAST_TYPE.SUCCESS,
|
||||||
title: "Success!",
|
title: "Success!",
|
||||||
|
|
@ -106,10 +88,6 @@ export function CycleCreateUpdateModal(props: CycleModalProps) {
|
||||||
title: "Error!",
|
title: "Error!",
|
||||||
message: err?.detail ?? "Error in updating cycle. Please try again.",
|
message: err?.detail ?? "Error in updating cycle. Please try again.",
|
||||||
});
|
});
|
||||||
captureError({
|
|
||||||
eventName: CYCLE_TRACKER_EVENTS.update,
|
|
||||||
error: err,
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,24 +1,16 @@
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
import { MoreHorizontal } from "lucide-react";
|
import { MoreHorizontal } from "lucide-react";
|
||||||
|
|
||||||
// ui
|
// ui
|
||||||
import {
|
import { EUserPermissions, EUserPermissionsLevel } from "@plane/constants";
|
||||||
CYCLE_TRACKER_EVENTS,
|
|
||||||
EUserPermissions,
|
|
||||||
EUserPermissionsLevel,
|
|
||||||
CYCLE_TRACKER_ELEMENTS,
|
|
||||||
} from "@plane/constants";
|
|
||||||
import { useTranslation } from "@plane/i18n";
|
import { useTranslation } from "@plane/i18n";
|
||||||
import { IconButton } from "@plane/propel/icon-button";
|
import { IconButton } from "@plane/propel/icon-button";
|
||||||
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
||||||
import type { TContextMenuItem } from "@plane/ui";
|
import type { TContextMenuItem } from "@plane/ui";
|
||||||
import { ContextMenu, CustomMenu } from "@plane/ui";
|
import { ContextMenu, CustomMenu } from "@plane/ui";
|
||||||
import { copyUrlToClipboard, cn } from "@plane/utils";
|
import { copyUrlToClipboard, cn } from "@plane/utils";
|
||||||
// helpers
|
|
||||||
// hooks
|
// hooks
|
||||||
import { useCycleMenuItems } from "@/components/common/quick-actions-helper";
|
import { useCycleMenuItems } from "@/components/common/quick-actions-helper";
|
||||||
import { captureClick, captureError, captureSuccess } from "@/helpers/event-tracker.helper";
|
|
||||||
import { useCycle } from "@/hooks/store/use-cycle";
|
import { useCycle } from "@/hooks/store/use-cycle";
|
||||||
import { useUserPermissions } from "@/hooks/store/user";
|
import { useUserPermissions } from "@/hooks/store/user";
|
||||||
import { useAppRouter } from "@/hooks/use-app-router";
|
import { useAppRouter } from "@/hooks/use-app-router";
|
||||||
|
|
@ -76,12 +68,6 @@ export const CycleQuickActions = observer(function CycleQuickActions(props: Prop
|
||||||
title: t("project_cycles.action.restore.success.title"),
|
title: t("project_cycles.action.restore.success.title"),
|
||||||
message: t("project_cycles.action.restore.success.description"),
|
message: t("project_cycles.action.restore.success.description"),
|
||||||
});
|
});
|
||||||
captureSuccess({
|
|
||||||
eventName: CYCLE_TRACKER_EVENTS.restore,
|
|
||||||
payload: {
|
|
||||||
id: cycleId,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
router.push(`/${workspaceSlug}/projects/${projectId}/archives/cycles`);
|
router.push(`/${workspaceSlug}/projects/${projectId}/archives/cycles`);
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
|
|
@ -90,12 +76,6 @@ export const CycleQuickActions = observer(function CycleQuickActions(props: Prop
|
||||||
title: t("project_cycles.action.restore.failed.title"),
|
title: t("project_cycles.action.restore.failed.title"),
|
||||||
message: t("project_cycles.action.restore.failed.description"),
|
message: t("project_cycles.action.restore.failed.description"),
|
||||||
});
|
});
|
||||||
captureError({
|
|
||||||
eventName: CYCLE_TRACKER_EVENTS.restore,
|
|
||||||
payload: {
|
|
||||||
id: cycleId,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const menuResult = useCycleMenuItems({
|
const menuResult = useCycleMenuItems({
|
||||||
|
|
@ -118,11 +98,7 @@ export const CycleQuickActions = observer(function CycleQuickActions(props: Prop
|
||||||
const CONTEXT_MENU_ITEMS = MENU_ITEMS.map(function CONTEXT_MENU_ITEMS(item) {
|
const CONTEXT_MENU_ITEMS = MENU_ITEMS.map(function CONTEXT_MENU_ITEMS(item) {
|
||||||
return {
|
return {
|
||||||
...item,
|
...item,
|
||||||
|
|
||||||
action: () => {
|
action: () => {
|
||||||
captureClick({
|
|
||||||
elementName: CYCLE_TRACKER_ELEMENTS.CONTEXT_MENU,
|
|
||||||
});
|
|
||||||
item.action();
|
item.action();
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
@ -170,9 +146,6 @@ export const CycleQuickActions = observer(function CycleQuickActions(props: Prop
|
||||||
<CustomMenu.MenuItem
|
<CustomMenu.MenuItem
|
||||||
key={item.key}
|
key={item.key}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
captureClick({
|
|
||||||
elementName: CYCLE_TRACKER_ELEMENTS.QUICK_ACTIONS,
|
|
||||||
});
|
|
||||||
item.action();
|
item.action();
|
||||||
}}
|
}}
|
||||||
className={cn(
|
className={cn(
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,10 @@
|
||||||
import type { FC } from "react";
|
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
// ui
|
// ui
|
||||||
import { PROJECT_SETTINGS_TRACKER_EVENTS } from "@plane/constants";
|
|
||||||
import { Button } from "@plane/propel/button";
|
import { Button } from "@plane/propel/button";
|
||||||
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
||||||
import { EModalPosition, EModalWidth, ModalCore } from "@plane/ui";
|
import { EModalPosition, EModalWidth, ModalCore } from "@plane/ui";
|
||||||
// hooks
|
// hooks
|
||||||
import { captureError, captureSuccess } from "@/helpers/event-tracker.helper";
|
|
||||||
import { useProjectEstimates } from "@/hooks/store/estimates";
|
import { useProjectEstimates } from "@/hooks/store/estimates";
|
||||||
import { useEstimate } from "@/hooks/store/estimates/use-estimate";
|
import { useEstimate } from "@/hooks/store/estimates/use-estimate";
|
||||||
import { useProject } from "@/hooks/store/use-project";
|
import { useProject } from "@/hooks/store/use-project";
|
||||||
|
|
@ -34,18 +31,11 @@ export const DeleteEstimateModal = observer(function DeleteEstimateModal(props:
|
||||||
try {
|
try {
|
||||||
if (!workspaceSlug || !projectId || !estimateId) return;
|
if (!workspaceSlug || !projectId || !estimateId) return;
|
||||||
setButtonLoader(true);
|
setButtonLoader(true);
|
||||||
|
|
||||||
await deleteEstimate(workspaceSlug, projectId, estimateId);
|
await deleteEstimate(workspaceSlug, projectId, estimateId);
|
||||||
if (areEstimateEnabledByProjectId(projectId)) {
|
if (areEstimateEnabledByProjectId(projectId)) {
|
||||||
await updateProject(workspaceSlug, projectId, { estimate: null });
|
await updateProject(workspaceSlug, projectId, { estimate: null });
|
||||||
}
|
}
|
||||||
setButtonLoader(false);
|
setButtonLoader(false);
|
||||||
captureSuccess({
|
|
||||||
eventName: PROJECT_SETTINGS_TRACKER_EVENTS.estimate_deleted,
|
|
||||||
payload: {
|
|
||||||
id: estimateId,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
setToast({
|
setToast({
|
||||||
type: TOAST_TYPE.SUCCESS,
|
type: TOAST_TYPE.SUCCESS,
|
||||||
title: "Estimate deleted",
|
title: "Estimate deleted",
|
||||||
|
|
@ -54,12 +44,6 @@ export const DeleteEstimateModal = observer(function DeleteEstimateModal(props:
|
||||||
handleClose();
|
handleClose();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setButtonLoader(false);
|
setButtonLoader(false);
|
||||||
captureError({
|
|
||||||
eventName: PROJECT_SETTINGS_TRACKER_EVENTS.estimate_deleted,
|
|
||||||
payload: {
|
|
||||||
id: estimateId,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
setToast({
|
setToast({
|
||||||
type: TOAST_TYPE.ERROR,
|
type: TOAST_TYPE.ERROR,
|
||||||
title: "Estimate creation failed",
|
title: "Estimate creation failed",
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,8 @@
|
||||||
import type { FC } from "react";
|
|
||||||
import { useTheme } from "next-themes";
|
import { useTheme } from "next-themes";
|
||||||
import { PROJECT_SETTINGS_TRACKER_ELEMENTS, PROJECT_SETTINGS_TRACKER_EVENTS } from "@plane/constants";
|
|
||||||
// plane imports
|
// plane imports
|
||||||
import { useTranslation } from "@plane/i18n";
|
import { useTranslation } from "@plane/i18n";
|
||||||
// components
|
// components
|
||||||
import { DetailedEmptyState } from "@/components/empty-state/detailed-empty-state-root";
|
import { DetailedEmptyState } from "@/components/empty-state/detailed-empty-state-root";
|
||||||
// helpers
|
|
||||||
import { captureElementAndEvent } from "@/helpers/event-tracker.helper";
|
|
||||||
|
|
||||||
type TEstimateEmptyScreen = {
|
type TEstimateEmptyScreen = {
|
||||||
onButtonClick: () => void;
|
onButtonClick: () => void;
|
||||||
|
|
@ -30,15 +26,6 @@ export function EstimateEmptyScreen(props: TEstimateEmptyScreen) {
|
||||||
text: t("project_settings.empty_state.estimates.primary_button"),
|
text: t("project_settings.empty_state.estimates.primary_button"),
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
onButtonClick();
|
onButtonClick();
|
||||||
captureElementAndEvent({
|
|
||||||
element: {
|
|
||||||
elementName: PROJECT_SETTINGS_TRACKER_ELEMENTS.ESTIMATES_EMPTY_STATE_CREATE_BUTTON,
|
|
||||||
},
|
|
||||||
event: {
|
|
||||||
eventName: PROJECT_SETTINGS_TRACKER_EVENTS.estimate_created,
|
|
||||||
state: "SUCCESS",
|
|
||||||
},
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,8 @@
|
||||||
import type { FC } from "react";
|
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
import { PROJECT_SETTINGS_TRACKER_ELEMENTS, PROJECT_SETTINGS_TRACKER_EVENTS } from "@plane/constants";
|
|
||||||
import { useTranslation } from "@plane/i18n";
|
import { useTranslation } from "@plane/i18n";
|
||||||
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
||||||
import { ToggleSwitch } from "@plane/ui";
|
import { ToggleSwitch } from "@plane/ui";
|
||||||
// hooks
|
// hooks
|
||||||
import { captureElementAndEvent } from "@/helpers/event-tracker.helper";
|
|
||||||
import { useProjectEstimates } from "@/hooks/store/estimates";
|
import { useProjectEstimates } from "@/hooks/store/estimates";
|
||||||
import { useProject } from "@/hooks/store/use-project";
|
import { useProject } from "@/hooks/store/use-project";
|
||||||
// i18n
|
// i18n
|
||||||
|
|
@ -32,15 +29,6 @@ export const EstimateDisableSwitch = observer(function EstimateDisableSwitch(pro
|
||||||
await updateProject(workspaceSlug, projectId, {
|
await updateProject(workspaceSlug, projectId, {
|
||||||
estimate: currentProjectActiveEstimate ? null : currentActiveEstimateId,
|
estimate: currentProjectActiveEstimate ? null : currentActiveEstimateId,
|
||||||
});
|
});
|
||||||
captureElementAndEvent({
|
|
||||||
element: {
|
|
||||||
elementName: PROJECT_SETTINGS_TRACKER_ELEMENTS.ESTIMATES_TOGGLE_BUTTON,
|
|
||||||
},
|
|
||||||
event: {
|
|
||||||
eventName: PROJECT_SETTINGS_TRACKER_EVENTS.estimates_toggle,
|
|
||||||
state: "SUCCESS",
|
|
||||||
},
|
|
||||||
});
|
|
||||||
setToast({
|
setToast({
|
||||||
type: TOAST_TYPE.SUCCESS,
|
type: TOAST_TYPE.SUCCESS,
|
||||||
title: currentProjectActiveEstimate
|
title: currentProjectActiveEstimate
|
||||||
|
|
@ -51,15 +39,6 @@ export const EstimateDisableSwitch = observer(function EstimateDisableSwitch(pro
|
||||||
: t("project_settings.estimates.toasts.enabled.success.message"),
|
: t("project_settings.estimates.toasts.enabled.success.message"),
|
||||||
});
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
captureElementAndEvent({
|
|
||||||
element: {
|
|
||||||
elementName: PROJECT_SETTINGS_TRACKER_ELEMENTS.ESTIMATES_TOGGLE_BUTTON,
|
|
||||||
},
|
|
||||||
event: {
|
|
||||||
eventName: PROJECT_SETTINGS_TRACKER_EVENTS.estimates_toggle,
|
|
||||||
state: "ERROR",
|
|
||||||
},
|
|
||||||
});
|
|
||||||
setToast({
|
setToast({
|
||||||
type: TOAST_TYPE.ERROR,
|
type: TOAST_TYPE.ERROR,
|
||||||
title: t("project_settings.estimates.toasts.disabled.error.title"),
|
title: t("project_settings.estimates.toasts.disabled.error.title"),
|
||||||
|
|
|
||||||
|
|
@ -8,8 +8,6 @@ import {
|
||||||
EUserPermissionsLevel,
|
EUserPermissionsLevel,
|
||||||
EXPORTERS_LIST,
|
EXPORTERS_LIST,
|
||||||
// ISSUE_DISPLAY_FILTERS_BY_PAGE,
|
// ISSUE_DISPLAY_FILTERS_BY_PAGE,
|
||||||
WORKSPACE_SETTINGS_TRACKER_EVENTS,
|
|
||||||
WORKSPACE_SETTINGS_TRACKER_ELEMENTS,
|
|
||||||
} from "@plane/constants";
|
} from "@plane/constants";
|
||||||
import { useTranslation } from "@plane/i18n";
|
import { useTranslation } from "@plane/i18n";
|
||||||
import { Button } from "@plane/propel/button";
|
import { Button } from "@plane/propel/button";
|
||||||
|
|
@ -20,7 +18,6 @@ import type { TWorkItemFilterExpression } from "@plane/types";
|
||||||
import { CustomSearchSelect, CustomSelect } from "@plane/ui";
|
import { CustomSearchSelect, CustomSelect } from "@plane/ui";
|
||||||
// import { WorkspaceLevelWorkItemFiltersHOC } from "@/components/work-item-filters/filters-hoc/workspace-level";
|
// import { WorkspaceLevelWorkItemFiltersHOC } from "@/components/work-item-filters/filters-hoc/workspace-level";
|
||||||
// import { WorkItemFiltersRow } from "@/components/work-item-filters/filters-row";
|
// import { WorkItemFiltersRow } from "@/components/work-item-filters/filters-row";
|
||||||
import { captureError, captureSuccess } from "@/helpers/event-tracker.helper";
|
|
||||||
import { useProject } from "@/hooks/store/use-project";
|
import { useProject } from "@/hooks/store/use-project";
|
||||||
import { useUser, useUserPermissions } from "@/hooks/store/user";
|
import { useUser, useUserPermissions } from "@/hooks/store/user";
|
||||||
import { ProjectExportService } from "@/services/project/project-export.service";
|
import { ProjectExportService } from "@/services/project/project-export.service";
|
||||||
|
|
@ -105,12 +102,6 @@ export const ExportForm = observer(function ExportForm(props: Props) {
|
||||||
await projectExportService.csvExport(workspaceSlug, payload);
|
await projectExportService.csvExport(workspaceSlug, payload);
|
||||||
mutateServices();
|
mutateServices();
|
||||||
setExportLoading(false);
|
setExportLoading(false);
|
||||||
captureSuccess({
|
|
||||||
eventName: WORKSPACE_SETTINGS_TRACKER_EVENTS.csv_exported,
|
|
||||||
payload: {
|
|
||||||
provider: formData.provider.provider,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
setToast({
|
setToast({
|
||||||
type: TOAST_TYPE.SUCCESS,
|
type: TOAST_TYPE.SUCCESS,
|
||||||
title: t("workspace_settings.settings.exports.modal.toasts.success.title"),
|
title: t("workspace_settings.settings.exports.modal.toasts.success.title"),
|
||||||
|
|
@ -127,13 +118,6 @@ export const ExportForm = observer(function ExportForm(props: Props) {
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setExportLoading(false);
|
setExportLoading(false);
|
||||||
captureError({
|
|
||||||
eventName: WORKSPACE_SETTINGS_TRACKER_EVENTS.csv_exported,
|
|
||||||
payload: {
|
|
||||||
provider: formData.provider.provider,
|
|
||||||
},
|
|
||||||
error: error as Error,
|
|
||||||
});
|
|
||||||
setToast({
|
setToast({
|
||||||
type: TOAST_TYPE.ERROR,
|
type: TOAST_TYPE.ERROR,
|
||||||
title: t("error"),
|
title: t("error"),
|
||||||
|
|
@ -258,12 +242,7 @@ export const ExportForm = observer(function ExportForm(props: Props) {
|
||||||
/>
|
/>
|
||||||
</div> */}
|
</div> */}
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<Button
|
<Button variant="primary" type="submit" loading={exportLoading}>
|
||||||
variant="primary"
|
|
||||||
type="submit"
|
|
||||||
loading={exportLoading}
|
|
||||||
data-ph-element={WORKSPACE_SETTINGS_TRACKER_ELEMENTS.EXPORT_BUTTON}
|
|
||||||
>
|
|
||||||
{exportLoading ? `${t("workspace_settings.settings.exports.exporting")}...` : t("export")}
|
{exportLoading ? `${t("workspace_settings.settings.exports.exporting")}...` : t("export")}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,8 @@
|
||||||
import { useEffect } from "react";
|
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
import { USER_TRACKER_ELEMENTS } from "@plane/constants";
|
|
||||||
// ui
|
// ui
|
||||||
import { EModalPosition, EModalWidth, ModalCore } from "@plane/ui";
|
import { EModalPosition, EModalWidth, ModalCore } from "@plane/ui";
|
||||||
// components
|
// components
|
||||||
import { ProductUpdatesFooter } from "@/components/global";
|
import { ProductUpdatesFooter } from "@/components/global";
|
||||||
// helpers
|
|
||||||
import { captureView } from "@/helpers/event-tracker.helper";
|
|
||||||
// plane web components
|
// plane web components
|
||||||
import { ProductUpdatesChangelog } from "@/plane-web/components/global/product-updates/changelog";
|
import { ProductUpdatesChangelog } from "@/plane-web/components/global/product-updates/changelog";
|
||||||
import { ProductUpdatesHeader } from "@/plane-web/components/global/product-updates/header";
|
import { ProductUpdatesHeader } from "@/plane-web/components/global/product-updates/header";
|
||||||
|
|
@ -19,12 +15,6 @@ export type ProductUpdatesModalProps = {
|
||||||
export const ProductUpdatesModal = observer(function ProductUpdatesModal(props: ProductUpdatesModalProps) {
|
export const ProductUpdatesModal = observer(function ProductUpdatesModal(props: ProductUpdatesModalProps) {
|
||||||
const { isOpen, handleClose } = props;
|
const { isOpen, handleClose } = props;
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (isOpen) {
|
|
||||||
captureView({ elementName: USER_TRACKER_ELEMENTS.PRODUCT_CHANGELOG_MODAL });
|
|
||||||
}
|
|
||||||
}, [isOpen]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ModalCore isOpen={isOpen} handleClose={handleClose} position={EModalPosition.CENTER} width={EModalWidth.XXXXL}>
|
<ModalCore isOpen={isOpen} handleClose={handleClose} position={EModalPosition.CENTER} width={EModalWidth.XXXXL}>
|
||||||
<ProductUpdatesHeader />
|
<ProductUpdatesHeader />
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,7 @@ import { observer } from "mobx-react";
|
||||||
import { useParams } from "next/navigation";
|
import { useParams } from "next/navigation";
|
||||||
import useSWR from "swr";
|
import useSWR from "swr";
|
||||||
// plane imports
|
// plane imports
|
||||||
import { PRODUCT_TOUR_TRACKER_EVENTS } from "@plane/constants";
|
|
||||||
import { ContentWrapper } from "@plane/ui";
|
import { ContentWrapper } from "@plane/ui";
|
||||||
// helpers
|
|
||||||
import { captureSuccess } from "@/helpers/event-tracker.helper";
|
|
||||||
// hooks
|
// hooks
|
||||||
import { useHome } from "@/hooks/store/use-home";
|
import { useHome } from "@/hooks/store/use-home";
|
||||||
import { useUserProfile, useUser } from "@/hooks/store/user";
|
import { useUserProfile, useUser } from "@/hooks/store/user";
|
||||||
|
|
@ -33,19 +30,12 @@ export const WorkspaceHomeView = observer(function WorkspaceHomeView() {
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleTourCompleted = () => {
|
const handleTourCompleted = async () => {
|
||||||
updateTourCompleted()
|
try {
|
||||||
.then(() => {
|
await updateTourCompleted();
|
||||||
captureSuccess({
|
} catch (error) {
|
||||||
eventName: PRODUCT_TOUR_TRACKER_EVENTS.complete,
|
console.error("Error updating tour completed", error);
|
||||||
payload: {
|
}
|
||||||
user_id: currentUser?.id,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
console.error(error);
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: refactor loader implementation
|
// TODO: refactor loader implementation
|
||||||
|
|
|
||||||
|
|
@ -5,14 +5,12 @@ import Link from "next/link";
|
||||||
import { useParams } from "next/navigation";
|
import { useParams } from "next/navigation";
|
||||||
import { Hotel } from "lucide-react";
|
import { Hotel } from "lucide-react";
|
||||||
// plane ui
|
// plane ui
|
||||||
import { EUserPermissions, EUserPermissionsLevel, PROJECT_TRACKER_ELEMENTS } from "@plane/constants";
|
import { EUserPermissions, EUserPermissionsLevel } from "@plane/constants";
|
||||||
import { useLocalStorage } from "@plane/hooks";
|
import { useLocalStorage } from "@plane/hooks";
|
||||||
import { useTranslation } from "@plane/i18n";
|
import { useTranslation } from "@plane/i18n";
|
||||||
import { MembersPropertyIcon, CheckIcon, ProjectIcon, CloseIcon } from "@plane/propel/icons";
|
import { MembersPropertyIcon, CheckIcon, ProjectIcon, CloseIcon } from "@plane/propel/icons";
|
||||||
import { cn, getFileURL } from "@plane/utils";
|
import { cn, getFileURL } from "@plane/utils";
|
||||||
// helpers
|
|
||||||
// hooks
|
// hooks
|
||||||
import { captureClick } from "@/helpers/event-tracker.helper";
|
|
||||||
import { useCommandPalette } from "@/hooks/store/use-command-palette";
|
import { useCommandPalette } from "@/hooks/store/use-command-palette";
|
||||||
import { useProject } from "@/hooks/store/use-project";
|
import { useProject } from "@/hooks/store/use-project";
|
||||||
import { useWorkspace } from "@/hooks/store/use-workspace";
|
import { useWorkspace } from "@/hooks/store/use-workspace";
|
||||||
|
|
@ -57,7 +55,6 @@ export const NoProjectsEmptyState = observer(function NoProjectsEmptyState() {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
toggleCreateProjectModal(true);
|
toggleCreateProjectModal(true);
|
||||||
captureClick({ elementName: PROJECT_TRACKER_ELEMENTS.EMPTY_STATE_CREATE_PROJECT_BUTTON });
|
|
||||||
},
|
},
|
||||||
disabled: !canCreateProject,
|
disabled: !canCreateProject,
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@ import type { Dispatch, SetStateAction } from "react";
|
||||||
import { useEffect, useMemo, useRef } from "react";
|
import { useEffect, useMemo, useRef } from "react";
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
// plane imports
|
// plane imports
|
||||||
import { WORK_ITEM_TRACKER_EVENTS } from "@plane/constants";
|
|
||||||
import type { EditorRefApi } from "@plane/editor";
|
import type { EditorRefApi } from "@plane/editor";
|
||||||
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
||||||
import type { TIssue, TNameDescriptionLoader } from "@plane/types";
|
import type { TIssue, TNameDescriptionLoader } from "@plane/types";
|
||||||
|
|
@ -17,8 +16,6 @@ import type { TIssueOperations } from "@/components/issues/issue-detail";
|
||||||
import { IssueActivity } from "@/components/issues/issue-detail/issue-activity";
|
import { IssueActivity } from "@/components/issues/issue-detail/issue-activity";
|
||||||
import { IssueReaction } from "@/components/issues/issue-detail/reactions";
|
import { IssueReaction } from "@/components/issues/issue-detail/reactions";
|
||||||
import { IssueTitleInput } from "@/components/issues/title-input";
|
import { IssueTitleInput } from "@/components/issues/title-input";
|
||||||
// helpers
|
|
||||||
import { captureError, captureSuccess } from "@/helpers/event-tracker.helper";
|
|
||||||
// hooks
|
// hooks
|
||||||
import { useIssueDetail } from "@/hooks/store/use-issue-detail";
|
import { useIssueDetail } from "@/hooks/store/use-issue-detail";
|
||||||
import { useMember } from "@/hooks/store/use-member";
|
import { useMember } from "@/hooks/store/use-member";
|
||||||
|
|
@ -102,10 +99,6 @@ export const InboxIssueMainContent = observer(function InboxIssueMainContent(pro
|
||||||
type: TOAST_TYPE.SUCCESS,
|
type: TOAST_TYPE.SUCCESS,
|
||||||
message: "Work item deleted successfully",
|
message: "Work item deleted successfully",
|
||||||
});
|
});
|
||||||
captureSuccess({
|
|
||||||
eventName: WORK_ITEM_TRACKER_EVENTS.delete,
|
|
||||||
payload: { id: _issueId },
|
|
||||||
});
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log("Error in deleting work item:", error);
|
console.log("Error in deleting work item:", error);
|
||||||
setToast({
|
setToast({
|
||||||
|
|
@ -113,47 +106,24 @@ export const InboxIssueMainContent = observer(function InboxIssueMainContent(pro
|
||||||
type: TOAST_TYPE.ERROR,
|
type: TOAST_TYPE.ERROR,
|
||||||
message: "Work item delete failed",
|
message: "Work item delete failed",
|
||||||
});
|
});
|
||||||
captureError({
|
|
||||||
eventName: WORK_ITEM_TRACKER_EVENTS.delete,
|
|
||||||
payload: { id: _issueId },
|
|
||||||
error: error as Error,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
update: async (_workspaceSlug: string, _projectId: string, _issueId: string, data: Partial<TIssue>) => {
|
update: async (_workspaceSlug: string, _projectId: string, _issueId: string, data: Partial<TIssue>) => {
|
||||||
try {
|
try {
|
||||||
await inboxIssue.updateIssue(data);
|
await inboxIssue.updateIssue(data);
|
||||||
captureSuccess({
|
|
||||||
eventName: WORK_ITEM_TRACKER_EVENTS.update,
|
|
||||||
payload: { id: _issueId },
|
|
||||||
});
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setToast({
|
setToast({
|
||||||
title: "Work item update failed",
|
title: "Work item update failed",
|
||||||
type: TOAST_TYPE.ERROR,
|
type: TOAST_TYPE.ERROR,
|
||||||
message: "Work item update failed",
|
message: "Work item update failed",
|
||||||
});
|
});
|
||||||
captureError({
|
|
||||||
eventName: WORK_ITEM_TRACKER_EVENTS.update,
|
|
||||||
payload: { id: _issueId },
|
|
||||||
error: error as Error,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
archive: async (workspaceSlug: string, projectId: string, issueId: string) => {
|
archive: async (workspaceSlug: string, projectId: string, issueId: string) => {
|
||||||
try {
|
try {
|
||||||
await archiveIssue(workspaceSlug, projectId, issueId);
|
await archiveIssue(workspaceSlug, projectId, issueId);
|
||||||
captureSuccess({
|
|
||||||
eventName: WORK_ITEM_TRACKER_EVENTS.archive,
|
|
||||||
payload: { id: issueId },
|
|
||||||
});
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error in archiving issue:", error);
|
console.error("Error in archiving issue:", error);
|
||||||
captureError({
|
|
||||||
eventName: WORK_ITEM_TRACKER_EVENTS.archive,
|
|
||||||
payload: { id: issueId },
|
|
||||||
error: error as Error,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
import type { FC, FormEvent } from "react";
|
import type { FormEvent } from "react";
|
||||||
import { useCallback, useEffect, useRef, useState } from "react";
|
import { useCallback, useEffect, useRef, useState } from "react";
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
// plane imports
|
// plane imports
|
||||||
import { ETabIndices, WORK_ITEM_TRACKER_EVENTS } from "@plane/constants";
|
import { ETabIndices } from "@plane/constants";
|
||||||
import type { EditorRefApi } from "@plane/editor";
|
import type { EditorRefApi } from "@plane/editor";
|
||||||
import { useTranslation } from "@plane/i18n";
|
import { useTranslation } from "@plane/i18n";
|
||||||
import { Button } from "@plane/propel/button";
|
import { Button } from "@plane/propel/button";
|
||||||
|
|
@ -10,8 +10,6 @@ import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
||||||
import type { TIssue } from "@plane/types";
|
import type { TIssue } from "@plane/types";
|
||||||
import { ToggleSwitch } from "@plane/ui";
|
import { ToggleSwitch } from "@plane/ui";
|
||||||
import { renderFormattedPayloadDate, getTabIndex } from "@plane/utils";
|
import { renderFormattedPayloadDate, getTabIndex } from "@plane/utils";
|
||||||
// helpers
|
|
||||||
import { captureError, captureSuccess } from "@/helpers/event-tracker.helper";
|
|
||||||
// hooks
|
// hooks
|
||||||
import { useProject } from "@/hooks/store/use-project";
|
import { useProject } from "@/hooks/store/use-project";
|
||||||
import { useProjectInbox } from "@/hooks/store/use-project-inbox";
|
import { useProjectInbox } from "@/hooks/store/use-project-inbox";
|
||||||
|
|
@ -170,12 +168,6 @@ export const InboxIssueCreateRoot = observer(function InboxIssueCreateRoot(props
|
||||||
descriptionEditorRef?.current?.clearEditor();
|
descriptionEditorRef?.current?.clearEditor();
|
||||||
setFormData(defaultIssueData);
|
setFormData(defaultIssueData);
|
||||||
}
|
}
|
||||||
captureSuccess({
|
|
||||||
eventName: WORK_ITEM_TRACKER_EVENTS.create,
|
|
||||||
payload: {
|
|
||||||
id: res?.issue?.id,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
setToast({
|
setToast({
|
||||||
type: TOAST_TYPE.SUCCESS,
|
type: TOAST_TYPE.SUCCESS,
|
||||||
title: `Success!`,
|
title: `Success!`,
|
||||||
|
|
@ -184,13 +176,6 @@ export const InboxIssueCreateRoot = observer(function InboxIssueCreateRoot(props
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
captureError({
|
|
||||||
eventName: WORK_ITEM_TRACKER_EVENTS.create,
|
|
||||||
payload: {
|
|
||||||
id: formData?.id,
|
|
||||||
},
|
|
||||||
error: error as Error,
|
|
||||||
});
|
|
||||||
setToast({
|
setToast({
|
||||||
type: TOAST_TYPE.ERROR,
|
type: TOAST_TYPE.ERROR,
|
||||||
title: `Error!`,
|
title: `Error!`,
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,6 @@
|
||||||
import React from "react";
|
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { useFormContext, Controller } from "react-hook-form";
|
import { useFormContext, Controller } from "react-hook-form";
|
||||||
|
|
||||||
import { PROJECT_TRACKER_ELEMENTS } from "@plane/constants";
|
|
||||||
import { PlusIcon } from "@plane/propel/icons";
|
import { PlusIcon } from "@plane/propel/icons";
|
||||||
import type { IJiraImporterForm } from "@plane/types";
|
import type { IJiraImporterForm } from "@plane/types";
|
||||||
// hooks
|
// hooks
|
||||||
|
|
@ -11,7 +8,6 @@ import type { IJiraImporterForm } from "@plane/types";
|
||||||
import { CustomSelect, Input } from "@plane/ui";
|
import { CustomSelect, Input } from "@plane/ui";
|
||||||
// helpers
|
// helpers
|
||||||
import { checkEmailValidity } from "@plane/utils";
|
import { checkEmailValidity } from "@plane/utils";
|
||||||
import { captureClick } from "@/helpers/event-tracker.helper";
|
|
||||||
import { useCommandPalette } from "@/hooks/store/use-command-palette";
|
import { useCommandPalette } from "@/hooks/store/use-command-palette";
|
||||||
import { useProject } from "@/hooks/store/use-project";
|
import { useProject } from "@/hooks/store/use-project";
|
||||||
// types
|
// types
|
||||||
|
|
@ -199,9 +195,7 @@ export const JiraGetImportDetail = observer(function JiraGetImportDetail() {
|
||||||
<div>
|
<div>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
data-ph-element={PROJECT_TRACKER_ELEMENTS.EMPTY_STATE_CREATE_PROJECT_BUTTON}
|
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
captureClick({ elementName: PROJECT_TRACKER_ELEMENTS.CREATE_PROJECT_JIRA_IMPORT_DETAIL_PAGE });
|
|
||||||
toggleCreateProjectModal(true);
|
toggleCreateProjectModal(true);
|
||||||
}}
|
}}
|
||||||
className="flex cursor-pointer select-none items-center space-x-2 truncate rounded-sm px-1 py-1.5 text-secondary"
|
className="flex cursor-pointer select-none items-center space-x-2 truncate rounded-sm px-1 py-1.5 text-secondary"
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,8 @@
|
||||||
import { useMemo } from "react";
|
import { useMemo } from "react";
|
||||||
import { WORK_ITEM_TRACKER_EVENTS } from "@plane/constants";
|
|
||||||
import { setPromiseToast, TOAST_TYPE, setToast } from "@plane/propel/toast";
|
import { setPromiseToast, TOAST_TYPE, setToast } from "@plane/propel/toast";
|
||||||
import type { TIssueServiceType } from "@plane/types";
|
import type { TIssueServiceType } from "@plane/types";
|
||||||
import { EIssueServiceType } from "@plane/types";
|
import { EIssueServiceType } from "@plane/types";
|
||||||
// hooks
|
// hooks
|
||||||
import { captureError, captureSuccess } from "@/helpers/event-tracker.helper";
|
|
||||||
import { useIssueDetail } from "@/hooks/store/use-issue-detail";
|
import { useIssueDetail } from "@/hooks/store/use-issue-detail";
|
||||||
// types
|
// types
|
||||||
import type { TAttachmentUploadStatus } from "@/store/issue/issue-details/attachment.store";
|
import type { TAttachmentUploadStatus } from "@/store/issue/issue-details/attachment.store";
|
||||||
|
|
@ -36,34 +34,21 @@ export const useAttachmentOperations = (
|
||||||
const attachmentOperations: TAttachmentOperations = useMemo(
|
const attachmentOperations: TAttachmentOperations = useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
create: async (file) => {
|
create: async (file) => {
|
||||||
try {
|
if (!workspaceSlug || !projectId || !issueId) throw new Error("Missing required fields");
|
||||||
if (!workspaceSlug || !projectId || !issueId) throw new Error("Missing required fields");
|
const attachmentUploadPromise = createAttachment(workspaceSlug, projectId, issueId, file);
|
||||||
const attachmentUploadPromise = createAttachment(workspaceSlug, projectId, issueId, file);
|
setPromiseToast(attachmentUploadPromise, {
|
||||||
setPromiseToast(attachmentUploadPromise, {
|
loading: "Uploading attachment...",
|
||||||
loading: "Uploading attachment...",
|
success: {
|
||||||
success: {
|
title: "Attachment uploaded",
|
||||||
title: "Attachment uploaded",
|
message: () => "The attachment has been successfully uploaded",
|
||||||
message: () => "The attachment has been successfully uploaded",
|
},
|
||||||
},
|
error: {
|
||||||
error: {
|
title: "Attachment not uploaded",
|
||||||
title: "Attachment not uploaded",
|
message: () => "The attachment could not be uploaded",
|
||||||
message: () => "The attachment could not be uploaded",
|
},
|
||||||
},
|
});
|
||||||
});
|
|
||||||
|
|
||||||
await attachmentUploadPromise;
|
await attachmentUploadPromise;
|
||||||
captureSuccess({
|
|
||||||
eventName: WORK_ITEM_TRACKER_EVENTS.attachment.add,
|
|
||||||
payload: { id: issueId },
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
captureError({
|
|
||||||
eventName: WORK_ITEM_TRACKER_EVENTS.attachment.add,
|
|
||||||
payload: { id: issueId },
|
|
||||||
error: error as Error,
|
|
||||||
});
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
remove: async (attachmentId) => {
|
remove: async (attachmentId) => {
|
||||||
try {
|
try {
|
||||||
|
|
@ -74,16 +59,7 @@ export const useAttachmentOperations = (
|
||||||
type: TOAST_TYPE.SUCCESS,
|
type: TOAST_TYPE.SUCCESS,
|
||||||
title: "Attachment removed",
|
title: "Attachment removed",
|
||||||
});
|
});
|
||||||
captureSuccess({
|
} catch (_error) {
|
||||||
eventName: WORK_ITEM_TRACKER_EVENTS.attachment.remove,
|
|
||||||
payload: { id: issueId },
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
captureError({
|
|
||||||
eventName: WORK_ITEM_TRACKER_EVENTS.attachment.remove,
|
|
||||||
payload: { id: issueId },
|
|
||||||
error: error as Error,
|
|
||||||
});
|
|
||||||
setToast({
|
setToast({
|
||||||
message: "The Attachment could not be removed",
|
message: "The Attachment could not be removed",
|
||||||
type: TOAST_TYPE.ERROR,
|
type: TOAST_TYPE.ERROR,
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,11 @@
|
||||||
import { useMemo } from "react";
|
import { useMemo } from "react";
|
||||||
// plane imports
|
// plane imports
|
||||||
import { WORK_ITEM_TRACKER_EVENTS } from "@plane/constants";
|
|
||||||
import { useTranslation } from "@plane/i18n";
|
import { useTranslation } from "@plane/i18n";
|
||||||
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
||||||
import type { TIssue, TIssueServiceType } from "@plane/types";
|
import type { TIssue, TIssueServiceType } from "@plane/types";
|
||||||
import { EIssueServiceType } from "@plane/types";
|
import { EIssueServiceType } from "@plane/types";
|
||||||
import { copyUrlToClipboard } from "@plane/utils";
|
import { copyUrlToClipboard } from "@plane/utils";
|
||||||
// hooks
|
// hooks
|
||||||
import { captureError, captureSuccess } from "@/helpers/event-tracker.helper";
|
|
||||||
import { useIssueDetail } from "@/hooks/store/use-issue-detail";
|
import { useIssueDetail } from "@/hooks/store/use-issue-detail";
|
||||||
|
|
||||||
export type TRelationIssueOperations = {
|
export type TRelationIssueOperations = {
|
||||||
|
|
@ -26,33 +24,23 @@ export const useRelationOperations = (
|
||||||
|
|
||||||
const issueOperations: TRelationIssueOperations = useMemo(
|
const issueOperations: TRelationIssueOperations = useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
copyLink: (path) => {
|
copyLink: async (path) => {
|
||||||
copyUrlToClipboard(path).then(() => {
|
await copyUrlToClipboard(path);
|
||||||
setToast({
|
setToast({
|
||||||
type: TOAST_TYPE.SUCCESS,
|
type: TOAST_TYPE.SUCCESS,
|
||||||
title: t("common.link_copied"),
|
title: t("common.link_copied"),
|
||||||
message: t("entity.link_copied_to_clipboard", { entity: entityName }),
|
message: t("entity.link_copied_to_clipboard", { entity: entityName }),
|
||||||
});
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
update: async (workspaceSlug, projectId, issueId, data) => {
|
update: async (workspaceSlug, projectId, issueId, data) => {
|
||||||
try {
|
try {
|
||||||
await updateIssue(workspaceSlug, projectId, issueId, data);
|
await updateIssue(workspaceSlug, projectId, issueId, data);
|
||||||
captureSuccess({
|
|
||||||
eventName: WORK_ITEM_TRACKER_EVENTS.update,
|
|
||||||
payload: { id: issueId },
|
|
||||||
});
|
|
||||||
setToast({
|
setToast({
|
||||||
title: t("toast.success"),
|
title: t("toast.success"),
|
||||||
type: TOAST_TYPE.SUCCESS,
|
type: TOAST_TYPE.SUCCESS,
|
||||||
message: t("entity.update.success", { entity: entityName }),
|
message: t("entity.update.success", { entity: entityName }),
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (_error) {
|
||||||
captureError({
|
|
||||||
eventName: WORK_ITEM_TRACKER_EVENTS.update,
|
|
||||||
payload: { id: issueId },
|
|
||||||
error: error as Error,
|
|
||||||
});
|
|
||||||
setToast({
|
setToast({
|
||||||
title: t("toast.error"),
|
title: t("toast.error"),
|
||||||
type: TOAST_TYPE.ERROR,
|
type: TOAST_TYPE.ERROR,
|
||||||
|
|
@ -61,20 +49,7 @@ export const useRelationOperations = (
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
remove: async (workspaceSlug, projectId, issueId) => {
|
remove: async (workspaceSlug, projectId, issueId) => {
|
||||||
try {
|
return removeIssue(workspaceSlug, projectId, issueId);
|
||||||
return removeIssue(workspaceSlug, projectId, issueId).then(() => {
|
|
||||||
captureSuccess({
|
|
||||||
eventName: WORK_ITEM_TRACKER_EVENTS.delete,
|
|
||||||
payload: { id: issueId },
|
|
||||||
});
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
captureError({
|
|
||||||
eventName: WORK_ITEM_TRACKER_EVENTS.delete,
|
|
||||||
payload: { id: issueId },
|
|
||||||
error: error as Error,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
[entityName, removeIssue, t, updateIssue]
|
[entityName, removeIssue, t, updateIssue]
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,12 @@
|
||||||
import { useMemo } from "react";
|
import { useMemo } from "react";
|
||||||
import { useParams } from "next/navigation";
|
import { useParams } from "next/navigation";
|
||||||
// plane imports
|
// plane imports
|
||||||
import { WORK_ITEM_TRACKER_EVENTS } from "@plane/constants";
|
|
||||||
import { useTranslation } from "@plane/i18n";
|
import { useTranslation } from "@plane/i18n";
|
||||||
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
||||||
import type { TIssueServiceType, TSubIssueOperations } from "@plane/types";
|
import type { TIssueServiceType, TSubIssueOperations } from "@plane/types";
|
||||||
import { EIssueServiceType } from "@plane/types";
|
import { EIssueServiceType } from "@plane/types";
|
||||||
import { copyUrlToClipboard } from "@plane/utils";
|
import { copyUrlToClipboard } from "@plane/utils";
|
||||||
// hooks
|
// hooks
|
||||||
import { captureError, captureSuccess } from "@/helpers/event-tracker.helper";
|
|
||||||
import { useIssueDetail } from "@/hooks/store/use-issue-detail";
|
import { useIssueDetail } from "@/hooks/store/use-issue-detail";
|
||||||
import { useProjectState } from "@/hooks/store/use-project-state";
|
import { useProjectState } from "@/hooks/store/use-project-state";
|
||||||
// plane web helpers
|
// plane web helpers
|
||||||
|
|
@ -39,18 +37,17 @@ export const useSubIssueOperations = (issueServiceType: TIssueServiceType): TSub
|
||||||
|
|
||||||
const subIssueOperations: TSubIssueOperations = useMemo(
|
const subIssueOperations: TSubIssueOperations = useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
copyLink: (path) => {
|
copyLink: async (path) => {
|
||||||
copyUrlToClipboard(path).then(() => {
|
await copyUrlToClipboard(path);
|
||||||
setToast({
|
setToast({
|
||||||
type: TOAST_TYPE.SUCCESS,
|
type: TOAST_TYPE.SUCCESS,
|
||||||
title: t("common.link_copied"),
|
title: t("common.link_copied"),
|
||||||
message: t("entity.link_copied_to_clipboard", {
|
message: t("entity.link_copied_to_clipboard", {
|
||||||
entity:
|
entity:
|
||||||
issueServiceType === EIssueServiceType.ISSUES
|
issueServiceType === EIssueServiceType.ISSUES
|
||||||
? t("common.sub_work_items", { count: 1 })
|
? t("common.sub_work_items", { count: 1 })
|
||||||
: t("issue.label", { count: 1 }),
|
: t("issue.label", { count: 1 }),
|
||||||
}),
|
}),
|
||||||
});
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
fetchSubIssues: async (workspaceSlug, projectId, parentIssueId) => {
|
fetchSubIssues: async (workspaceSlug, projectId, parentIssueId) => {
|
||||||
|
|
@ -131,22 +128,13 @@ export const useSubIssueOperations = (issueServiceType: TIssueServiceType): TSub
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
captureSuccess({
|
|
||||||
eventName: WORK_ITEM_TRACKER_EVENTS.sub_issue.update,
|
|
||||||
payload: { id: issueId, parent_id: parentIssueId },
|
|
||||||
});
|
|
||||||
setToast({
|
setToast({
|
||||||
type: TOAST_TYPE.SUCCESS,
|
type: TOAST_TYPE.SUCCESS,
|
||||||
title: t("toast.success"),
|
title: t("toast.success"),
|
||||||
message: t("sub_work_item.update.success"),
|
message: t("sub_work_item.update.success"),
|
||||||
});
|
});
|
||||||
setSubIssueHelpers(parentIssueId, "issue_loader", issueId);
|
setSubIssueHelpers(parentIssueId, "issue_loader", issueId);
|
||||||
} catch (error) {
|
} catch (_error) {
|
||||||
captureError({
|
|
||||||
eventName: WORK_ITEM_TRACKER_EVENTS.sub_issue.update,
|
|
||||||
payload: { id: issueId, parent_id: parentIssueId },
|
|
||||||
error: error as Error,
|
|
||||||
});
|
|
||||||
setToast({
|
setToast({
|
||||||
type: TOAST_TYPE.ERROR,
|
type: TOAST_TYPE.ERROR,
|
||||||
title: t("toast.error"),
|
title: t("toast.error"),
|
||||||
|
|
@ -178,17 +166,8 @@ export const useSubIssueOperations = (issueServiceType: TIssueServiceType): TSub
|
||||||
: t("issue.label", { count: 1 }),
|
: t("issue.label", { count: 1 }),
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
captureSuccess({
|
|
||||||
eventName: WORK_ITEM_TRACKER_EVENTS.sub_issue.remove,
|
|
||||||
payload: { id: issueId, parent_id: parentIssueId },
|
|
||||||
});
|
|
||||||
setSubIssueHelpers(parentIssueId, "issue_loader", issueId);
|
setSubIssueHelpers(parentIssueId, "issue_loader", issueId);
|
||||||
} catch (error) {
|
} catch (_error) {
|
||||||
captureError({
|
|
||||||
eventName: WORK_ITEM_TRACKER_EVENTS.sub_issue.remove,
|
|
||||||
payload: { id: issueId, parent_id: parentIssueId },
|
|
||||||
error: error as Error,
|
|
||||||
});
|
|
||||||
setToast({
|
setToast({
|
||||||
type: TOAST_TYPE.ERROR,
|
type: TOAST_TYPE.ERROR,
|
||||||
title: t("toast.error"),
|
title: t("toast.error"),
|
||||||
|
|
@ -205,18 +184,9 @@ export const useSubIssueOperations = (issueServiceType: TIssueServiceType): TSub
|
||||||
try {
|
try {
|
||||||
setSubIssueHelpers(parentIssueId, "issue_loader", issueId);
|
setSubIssueHelpers(parentIssueId, "issue_loader", issueId);
|
||||||
return deleteSubIssue(workspaceSlug, projectId, parentIssueId, issueId).then(() => {
|
return deleteSubIssue(workspaceSlug, projectId, parentIssueId, issueId).then(() => {
|
||||||
captureSuccess({
|
|
||||||
eventName: WORK_ITEM_TRACKER_EVENTS.sub_issue.delete,
|
|
||||||
payload: { id: issueId, parent_id: parentIssueId },
|
|
||||||
});
|
|
||||||
setSubIssueHelpers(parentIssueId, "issue_loader", issueId);
|
setSubIssueHelpers(parentIssueId, "issue_loader", issueId);
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (_error) {
|
||||||
captureError({
|
|
||||||
eventName: WORK_ITEM_TRACKER_EVENTS.sub_issue.delete,
|
|
||||||
payload: { id: issueId, parent_id: parentIssueId },
|
|
||||||
error: error as Error,
|
|
||||||
});
|
|
||||||
setToast({
|
setToast({
|
||||||
type: TOAST_TYPE.ERROR,
|
type: TOAST_TYPE.ERROR,
|
||||||
title: t("toast.error"),
|
title: t("toast.error"),
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,5 @@
|
||||||
import type { FC } from "react";
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
|
|
||||||
// plane imports
|
// plane imports
|
||||||
import { WORK_ITEM_TRACKER_EVENTS } from "@plane/constants";
|
import { WORK_ITEM_TRACKER_EVENTS } from "@plane/constants";
|
||||||
import { useTranslation } from "@plane/i18n";
|
import { useTranslation } from "@plane/i18n";
|
||||||
|
|
@ -9,7 +7,6 @@ import { PlusIcon, WorkItemsIcon } from "@plane/propel/icons";
|
||||||
import type { TIssue, TIssueServiceType } from "@plane/types";
|
import type { TIssue, TIssueServiceType } from "@plane/types";
|
||||||
import { CustomMenu } from "@plane/ui";
|
import { CustomMenu } from "@plane/ui";
|
||||||
// hooks
|
// hooks
|
||||||
import { captureClick } from "@/helpers/event-tracker.helper";
|
|
||||||
import { useIssueDetail } from "@/hooks/store/use-issue-detail";
|
import { useIssueDetail } from "@/hooks/store/use-issue-detail";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
|
@ -54,13 +51,11 @@ export const SubIssuesActionButton = observer(function SubIssuesActionButton(pro
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleCreateNew = () => {
|
const handleCreateNew = () => {
|
||||||
captureClick({ elementName: WORK_ITEM_TRACKER_EVENTS.sub_issue.create });
|
|
||||||
handleIssueCrudState("create", issueId, null);
|
handleIssueCrudState("create", issueId, null);
|
||||||
toggleCreateIssueModal(true);
|
toggleCreateIssueModal(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleAddExisting = () => {
|
const handleAddExisting = () => {
|
||||||
captureClick({ elementName: WORK_ITEM_TRACKER_EVENTS.sub_issue.add_existing });
|
|
||||||
handleIssueCrudState("existing", issueId, null);
|
handleIssueCrudState("existing", issueId, null);
|
||||||
toggleSubIssuesModal(issue.id);
|
toggleSubIssuesModal(issue.id);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,13 @@
|
||||||
import { useRef } from "react";
|
import { useRef } from "react";
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
// plane imports
|
// plane imports
|
||||||
import { WORK_ITEM_TRACKER_EVENTS } from "@plane/constants";
|
|
||||||
import { useTranslation } from "@plane/i18n";
|
import { useTranslation } from "@plane/i18n";
|
||||||
import { CopyLinkIcon } from "@plane/propel/icons";
|
import { CopyLinkIcon } from "@plane/propel/icons";
|
||||||
import { IconButton } from "@plane/propel/icon-button";
|
import { IconButton } from "@plane/propel/icon-button";
|
||||||
import { LinkIcon } from "@plane/propel/icons";
|
|
||||||
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
||||||
import { Tooltip } from "@plane/propel/tooltip";
|
import { Tooltip } from "@plane/propel/tooltip";
|
||||||
import { EIssuesStoreType } from "@plane/types";
|
import { EIssuesStoreType } from "@plane/types";
|
||||||
import { generateWorkItemLink, copyTextToClipboard } from "@plane/utils";
|
import { generateWorkItemLink, copyTextToClipboard } from "@plane/utils";
|
||||||
// helpers
|
|
||||||
import { captureError, captureSuccess } from "@/helpers/event-tracker.helper";
|
|
||||||
// hooks
|
// hooks
|
||||||
import { useIssueDetail } from "@/hooks/store/use-issue-detail";
|
import { useIssueDetail } from "@/hooks/store/use-issue-detail";
|
||||||
import { useIssues } from "@/hooks/store/use-issues";
|
import { useIssues } from "@/hooks/store/use-issues";
|
||||||
|
|
@ -70,15 +66,21 @@ export const IssueDetailQuickActions = observer(function IssueDetailQuickActions
|
||||||
});
|
});
|
||||||
|
|
||||||
// handlers
|
// handlers
|
||||||
const handleCopyText = () => {
|
const handleCopyText = async () => {
|
||||||
const originURL = typeof window !== "undefined" && window.location.origin ? window.location.origin : "";
|
try {
|
||||||
copyTextToClipboard(`${originURL}${workItemLink}`).then(() => {
|
const originURL = typeof window !== "undefined" && window.location.origin ? window.location.origin : "";
|
||||||
|
await copyTextToClipboard(`${originURL}${workItemLink}`);
|
||||||
setToast({
|
setToast({
|
||||||
type: TOAST_TYPE.SUCCESS,
|
type: TOAST_TYPE.SUCCESS,
|
||||||
title: t("common.link_copied"),
|
title: t("common.link_copied"),
|
||||||
message: t("common.copied_to_clipboard"),
|
message: t("common.copied_to_clipboard"),
|
||||||
});
|
});
|
||||||
});
|
} catch (_error) {
|
||||||
|
setToast({
|
||||||
|
title: t("toast.error"),
|
||||||
|
type: TOAST_TYPE.ERROR,
|
||||||
|
});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleDeleteIssue = async () => {
|
const handleDeleteIssue = async () => {
|
||||||
|
|
@ -88,24 +90,14 @@ export const IssueDetailQuickActions = observer(function IssueDetailQuickActions
|
||||||
? `/${workspaceSlug}/projects/${projectId}/archives/issues`
|
? `/${workspaceSlug}/projects/${projectId}/archives/issues`
|
||||||
: `/${workspaceSlug}/projects/${projectId}/issues`;
|
: `/${workspaceSlug}/projects/${projectId}/issues`;
|
||||||
|
|
||||||
return deleteIssue(workspaceSlug, projectId, issueId).then(() => {
|
await deleteIssue(workspaceSlug, projectId, issueId);
|
||||||
router.push(redirectionPath);
|
router.push(redirectionPath);
|
||||||
captureSuccess({
|
} catch (_error) {
|
||||||
eventName: WORK_ITEM_TRACKER_EVENTS.delete,
|
|
||||||
payload: { id: issueId },
|
|
||||||
});
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
setToast({
|
setToast({
|
||||||
title: t("toast.error "),
|
title: t("toast.error "),
|
||||||
type: TOAST_TYPE.ERROR,
|
type: TOAST_TYPE.ERROR,
|
||||||
message: t("entity.delete.failed", { entity: t("issue.label", { count: 1 }) }),
|
message: t("entity.delete.failed", { entity: t("issue.label", { count: 1 }) }),
|
||||||
});
|
});
|
||||||
captureError({
|
|
||||||
eventName: WORK_ITEM_TRACKER_EVENTS.delete,
|
|
||||||
payload: { id: issueId },
|
|
||||||
error: error as Error,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -113,38 +105,32 @@ export const IssueDetailQuickActions = observer(function IssueDetailQuickActions
|
||||||
try {
|
try {
|
||||||
await archiveIssue(workspaceSlug, projectId, issueId);
|
await archiveIssue(workspaceSlug, projectId, issueId);
|
||||||
router.push(`/${workspaceSlug}/projects/${projectId}/issues`);
|
router.push(`/${workspaceSlug}/projects/${projectId}/issues`);
|
||||||
captureSuccess({
|
} catch (_error) {
|
||||||
eventName: WORK_ITEM_TRACKER_EVENTS.archive,
|
setToast({
|
||||||
payload: { id: issueId },
|
title: t("toast.error"),
|
||||||
});
|
type: TOAST_TYPE.ERROR,
|
||||||
} catch (error) {
|
message: t("issue.archive.failed.message"),
|
||||||
captureError({
|
|
||||||
eventName: WORK_ITEM_TRACKER_EVENTS.archive,
|
|
||||||
payload: { id: issueId },
|
|
||||||
error: error as Error,
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleRestore = async () => {
|
const handleRestore = async () => {
|
||||||
if (!workspaceSlug || !projectId || !issueId) return;
|
if (!workspaceSlug || !projectId || !issueId) return;
|
||||||
|
try {
|
||||||
await restoreIssue(workspaceSlug.toString(), projectId.toString(), issueId.toString())
|
await restoreIssue(workspaceSlug.toString(), projectId.toString(), issueId.toString());
|
||||||
.then(() => {
|
setToast({
|
||||||
setToast({
|
type: TOAST_TYPE.SUCCESS,
|
||||||
type: TOAST_TYPE.SUCCESS,
|
title: t("issue.restore.success.title"),
|
||||||
title: t("issue.restore.success.title"),
|
message: t("issue.restore.success.message"),
|
||||||
message: t("issue.restore.success.message"),
|
|
||||||
});
|
|
||||||
router.push(workItemLink);
|
|
||||||
})
|
|
||||||
.catch(() => {
|
|
||||||
setToast({
|
|
||||||
type: TOAST_TYPE.ERROR,
|
|
||||||
title: t("toast.error"),
|
|
||||||
message: t("issue.restore.failed.message"),
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
router.push(workItemLink);
|
||||||
|
} catch (_error) {
|
||||||
|
setToast({
|
||||||
|
title: t("toast.error"),
|
||||||
|
type: TOAST_TYPE.ERROR,
|
||||||
|
message: t("issue.restore.failed.message"),
|
||||||
|
});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
import type { FC } from "react";
|
|
||||||
import { useMemo } from "react";
|
import { useMemo } from "react";
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
// plane imports
|
// plane imports
|
||||||
import { EUserPermissions, EUserPermissionsLevel, WORK_ITEM_TRACKER_EVENTS } from "@plane/constants";
|
import { EUserPermissions, EUserPermissionsLevel } from "@plane/constants";
|
||||||
import { useTranslation } from "@plane/i18n";
|
import { useTranslation } from "@plane/i18n";
|
||||||
import { TOAST_TYPE, setPromiseToast, setToast } from "@plane/propel/toast";
|
import { TOAST_TYPE, setPromiseToast, setToast } from "@plane/propel/toast";
|
||||||
import type { TIssue } from "@plane/types";
|
import type { TIssue } from "@plane/types";
|
||||||
|
|
@ -12,7 +11,6 @@ import emptyIssue from "@/app/assets/empty-state/issue.svg?url";
|
||||||
// components
|
// components
|
||||||
import { EmptyState } from "@/components/common/empty-state";
|
import { EmptyState } from "@/components/common/empty-state";
|
||||||
// hooks
|
// hooks
|
||||||
import { captureError, captureSuccess } from "@/helpers/event-tracker.helper";
|
|
||||||
import { useAppTheme } from "@/hooks/store/use-app-theme";
|
import { useAppTheme } from "@/hooks/store/use-app-theme";
|
||||||
import { useIssueDetail } from "@/hooks/store/use-issue-detail";
|
import { useIssueDetail } from "@/hooks/store/use-issue-detail";
|
||||||
import { useIssues } from "@/hooks/store/use-issues";
|
import { useIssues } from "@/hooks/store/use-issues";
|
||||||
|
|
@ -90,17 +88,8 @@ export const IssueDetailRoot = observer(function IssueDetailRoot(props: TIssueDe
|
||||||
update: async (workspaceSlug: string, projectId: string, issueId: string, data: Partial<TIssue>) => {
|
update: async (workspaceSlug: string, projectId: string, issueId: string, data: Partial<TIssue>) => {
|
||||||
try {
|
try {
|
||||||
await updateIssue(workspaceSlug, projectId, issueId, data);
|
await updateIssue(workspaceSlug, projectId, issueId, data);
|
||||||
captureSuccess({
|
|
||||||
eventName: WORK_ITEM_TRACKER_EVENTS.update,
|
|
||||||
payload: { id: issueId },
|
|
||||||
});
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log("Error in updating issue:", error);
|
console.log("Error in updating issue:", error);
|
||||||
captureError({
|
|
||||||
eventName: WORK_ITEM_TRACKER_EVENTS.update,
|
|
||||||
payload: { id: issueId },
|
|
||||||
error: error as Error,
|
|
||||||
});
|
|
||||||
setToast({
|
setToast({
|
||||||
title: t("common.error.label"),
|
title: t("common.error.label"),
|
||||||
type: TOAST_TYPE.ERROR,
|
type: TOAST_TYPE.ERROR,
|
||||||
|
|
@ -117,10 +106,6 @@ export const IssueDetailRoot = observer(function IssueDetailRoot(props: TIssueDe
|
||||||
type: TOAST_TYPE.SUCCESS,
|
type: TOAST_TYPE.SUCCESS,
|
||||||
message: t("entity.delete.success", { entity: t("issue.label") }),
|
message: t("entity.delete.success", { entity: t("issue.label") }),
|
||||||
});
|
});
|
||||||
captureSuccess({
|
|
||||||
eventName: WORK_ITEM_TRACKER_EVENTS.delete,
|
|
||||||
payload: { id: issueId },
|
|
||||||
});
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log("Error in deleting issue:", error);
|
console.log("Error in deleting issue:", error);
|
||||||
setToast({
|
setToast({
|
||||||
|
|
@ -128,67 +113,35 @@ export const IssueDetailRoot = observer(function IssueDetailRoot(props: TIssueDe
|
||||||
type: TOAST_TYPE.ERROR,
|
type: TOAST_TYPE.ERROR,
|
||||||
message: t("entity.delete.failed", { entity: t("issue.label") }),
|
message: t("entity.delete.failed", { entity: t("issue.label") }),
|
||||||
});
|
});
|
||||||
captureError({
|
|
||||||
eventName: WORK_ITEM_TRACKER_EVENTS.delete,
|
|
||||||
payload: { id: issueId },
|
|
||||||
error: error as Error,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
archive: async (workspaceSlug: string, projectId: string, issueId: string) => {
|
archive: async (workspaceSlug: string, projectId: string, issueId: string) => {
|
||||||
try {
|
try {
|
||||||
await archiveIssue(workspaceSlug, projectId, issueId);
|
await archiveIssue(workspaceSlug, projectId, issueId);
|
||||||
captureSuccess({
|
|
||||||
eventName: WORK_ITEM_TRACKER_EVENTS.archive,
|
|
||||||
payload: { id: issueId },
|
|
||||||
});
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log("Error in archiving issue:", error);
|
console.log("Error in archiving issue:", error);
|
||||||
captureError({
|
|
||||||
eventName: WORK_ITEM_TRACKER_EVENTS.archive,
|
|
||||||
payload: { id: issueId },
|
|
||||||
error: error as Error,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
addCycleToIssue: async (workspaceSlug: string, projectId: string, cycleId: string, issueId: string) => {
|
addCycleToIssue: async (workspaceSlug: string, projectId: string, cycleId: string, issueId: string) => {
|
||||||
try {
|
try {
|
||||||
await addCycleToIssue(workspaceSlug, projectId, cycleId, issueId);
|
await addCycleToIssue(workspaceSlug, projectId, cycleId, issueId);
|
||||||
captureSuccess({
|
} catch (_error) {
|
||||||
eventName: WORK_ITEM_TRACKER_EVENTS.update,
|
|
||||||
payload: { id: issueId },
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
setToast({
|
setToast({
|
||||||
type: TOAST_TYPE.ERROR,
|
type: TOAST_TYPE.ERROR,
|
||||||
title: t("common.error.label"),
|
title: t("common.error.label"),
|
||||||
message: t("issue.add.cycle.failed"),
|
message: t("issue.add.cycle.failed"),
|
||||||
});
|
});
|
||||||
captureError({
|
|
||||||
eventName: WORK_ITEM_TRACKER_EVENTS.update,
|
|
||||||
payload: { id: issueId },
|
|
||||||
error: error as Error,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
addIssueToCycle: async (workspaceSlug: string, projectId: string, cycleId: string, issueIds: string[]) => {
|
addIssueToCycle: async (workspaceSlug: string, projectId: string, cycleId: string, issueIds: string[]) => {
|
||||||
try {
|
try {
|
||||||
await addIssueToCycle(workspaceSlug, projectId, cycleId, issueIds);
|
await addIssueToCycle(workspaceSlug, projectId, cycleId, issueIds);
|
||||||
captureSuccess({
|
} catch (_error) {
|
||||||
eventName: WORK_ITEM_TRACKER_EVENTS.update,
|
|
||||||
payload: { id: issueId },
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
setToast({
|
setToast({
|
||||||
type: TOAST_TYPE.ERROR,
|
type: TOAST_TYPE.ERROR,
|
||||||
title: t("common.error.label"),
|
title: t("common.error.label"),
|
||||||
message: t("issue.add.cycle.failed"),
|
message: t("issue.add.cycle.failed"),
|
||||||
});
|
});
|
||||||
captureError({
|
|
||||||
eventName: WORK_ITEM_TRACKER_EVENTS.update,
|
|
||||||
payload: { id: issueId },
|
|
||||||
error: error as Error,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
removeIssueFromCycle: async (workspaceSlug: string, projectId: string, cycleId: string, issueId: string) => {
|
removeIssueFromCycle: async (workspaceSlug: string, projectId: string, cycleId: string, issueId: string) => {
|
||||||
|
|
@ -206,16 +159,8 @@ export const IssueDetailRoot = observer(function IssueDetailRoot(props: TIssueDe
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
await removeFromCyclePromise;
|
await removeFromCyclePromise;
|
||||||
captureSuccess({
|
|
||||||
eventName: WORK_ITEM_TRACKER_EVENTS.update,
|
|
||||||
payload: { id: issueId },
|
|
||||||
});
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
captureError({
|
console.log("Error in removing issue from cycle:", error);
|
||||||
eventName: WORK_ITEM_TRACKER_EVENTS.update,
|
|
||||||
payload: { id: issueId },
|
|
||||||
error: error as Error,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
removeIssueFromModule: async (workspaceSlug: string, projectId: string, moduleId: string, issueId: string) => {
|
removeIssueFromModule: async (workspaceSlug: string, projectId: string, moduleId: string, issueId: string) => {
|
||||||
|
|
@ -233,16 +178,8 @@ export const IssueDetailRoot = observer(function IssueDetailRoot(props: TIssueDe
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
await removeFromModulePromise;
|
await removeFromModulePromise;
|
||||||
captureSuccess({
|
|
||||||
eventName: WORK_ITEM_TRACKER_EVENTS.update,
|
|
||||||
payload: { id: issueId },
|
|
||||||
});
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
captureError({
|
console.log("Error in removing issue from module:", error);
|
||||||
eventName: WORK_ITEM_TRACKER_EVENTS.update,
|
|
||||||
payload: { id: issueId },
|
|
||||||
error: error as Error,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
changeModulesInIssue: async (
|
changeModulesInIssue: async (
|
||||||
|
|
@ -253,10 +190,6 @@ export const IssueDetailRoot = observer(function IssueDetailRoot(props: TIssueDe
|
||||||
removeModuleIds: string[]
|
removeModuleIds: string[]
|
||||||
) => {
|
) => {
|
||||||
const promise = await changeModulesInIssue(workspaceSlug, projectId, issueId, addModuleIds, removeModuleIds);
|
const promise = await changeModulesInIssue(workspaceSlug, projectId, issueId, addModuleIds, removeModuleIds);
|
||||||
captureSuccess({
|
|
||||||
eventName: WORK_ITEM_TRACKER_EVENTS.update,
|
|
||||||
payload: { id: issueId },
|
|
||||||
});
|
|
||||||
return promise;
|
return promise;
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
|
@ -273,7 +206,6 @@ export const IssueDetailRoot = observer(function IssueDetailRoot(props: TIssueDe
|
||||||
changeModulesInIssue,
|
changeModulesInIssue,
|
||||||
removeIssueFromModule,
|
removeIssueFromModule,
|
||||||
t,
|
t,
|
||||||
issueId,
|
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,6 @@ import type { ISearchIssueResponse } from "@plane/types";
|
||||||
import { EIssuesStoreType, EUserProjectRoles } from "@plane/types";
|
import { EIssuesStoreType, EUserProjectRoles } from "@plane/types";
|
||||||
// components
|
// components
|
||||||
import { ExistingIssuesListModal } from "@/components/core/modals/existing-issues-list-modal";
|
import { ExistingIssuesListModal } from "@/components/core/modals/existing-issues-list-modal";
|
||||||
import { captureClick } from "@/helpers/event-tracker.helper";
|
|
||||||
import { useCommandPalette } from "@/hooks/store/use-command-palette";
|
import { useCommandPalette } from "@/hooks/store/use-command-palette";
|
||||||
import { useCycle } from "@/hooks/store/use-cycle";
|
import { useCycle } from "@/hooks/store/use-cycle";
|
||||||
import { useIssues } from "@/hooks/store/use-issues";
|
import { useIssues } from "@/hooks/store/use-issues";
|
||||||
|
|
@ -107,7 +106,6 @@ export const CycleEmptyState = observer(function CycleEmptyState() {
|
||||||
{
|
{
|
||||||
label: t("project_empty_state.cycle_work_items.cta_primary"),
|
label: t("project_empty_state.cycle_work_items.cta_primary"),
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
captureClick({ elementName: WORK_ITEM_TRACKER_ELEMENTS.EMPTY_STATE_ADD_BUTTON.CYCLE });
|
|
||||||
toggleCreateIssueModal(true, EIssuesStoreType.CYCLE);
|
toggleCreateIssueModal(true, EIssuesStoreType.CYCLE);
|
||||||
},
|
},
|
||||||
disabled: !canPerformEmptyStateActions,
|
disabled: !canPerformEmptyStateActions,
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,10 @@
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
// plane imports
|
// plane imports
|
||||||
import { EUserPermissionsLevel, WORK_ITEM_TRACKER_ELEMENTS } from "@plane/constants";
|
import { EUserPermissionsLevel } from "@plane/constants";
|
||||||
import { useTranslation } from "@plane/i18n";
|
import { useTranslation } from "@plane/i18n";
|
||||||
import { EmptyStateDetailed } from "@plane/propel/empty-state";
|
import { EmptyStateDetailed } from "@plane/propel/empty-state";
|
||||||
import { EIssuesStoreType, EUserWorkspaceRoles } from "@plane/types";
|
import { EIssuesStoreType, EUserWorkspaceRoles } from "@plane/types";
|
||||||
// hooks
|
// hooks
|
||||||
import { captureClick } from "@/helpers/event-tracker.helper";
|
|
||||||
import { useCommandPalette } from "@/hooks/store/use-command-palette";
|
import { useCommandPalette } from "@/hooks/store/use-command-palette";
|
||||||
import { useProject } from "@/hooks/store/use-project";
|
import { useProject } from "@/hooks/store/use-project";
|
||||||
import { useUserPermissions } from "@/hooks/store/user";
|
import { useUserPermissions } from "@/hooks/store/user";
|
||||||
|
|
@ -35,7 +34,6 @@ export const GlobalViewEmptyState = observer(function GlobalViewEmptyState() {
|
||||||
label: t("workspace_projects.empty_state.no_projects.primary_button.text"),
|
label: t("workspace_projects.empty_state.no_projects.primary_button.text"),
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
toggleCreateProjectModal(true);
|
toggleCreateProjectModal(true);
|
||||||
captureClick({ elementName: WORK_ITEM_TRACKER_ELEMENTS.EMPTY_STATE_ADD_BUTTON.GLOBAL_VIEW });
|
|
||||||
},
|
},
|
||||||
disabled: !hasMemberLevelPermission,
|
disabled: !hasMemberLevelPermission,
|
||||||
variant: "primary",
|
variant: "primary",
|
||||||
|
|
@ -55,7 +53,6 @@ export const GlobalViewEmptyState = observer(function GlobalViewEmptyState() {
|
||||||
{
|
{
|
||||||
label: t(`workspace_empty_state.views.cta_primary`),
|
label: t(`workspace_empty_state.views.cta_primary`),
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
captureClick({ elementName: WORK_ITEM_TRACKER_ELEMENTS.EMPTY_STATE_ADD_BUTTON.GLOBAL_VIEW });
|
|
||||||
toggleCreateIssueModal(true, EIssuesStoreType.PROJECT);
|
toggleCreateIssueModal(true, EIssuesStoreType.PROJECT);
|
||||||
},
|
},
|
||||||
disabled: !hasMemberLevelPermission,
|
disabled: !hasMemberLevelPermission,
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ import { useState } from "react";
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
import { useParams } from "next/navigation";
|
import { useParams } from "next/navigation";
|
||||||
// plane imports
|
// plane imports
|
||||||
import { EUserPermissionsLevel, WORK_ITEM_TRACKER_ELEMENTS } from "@plane/constants";
|
import { EUserPermissionsLevel } from "@plane/constants";
|
||||||
import { useTranslation } from "@plane/i18n";
|
import { useTranslation } from "@plane/i18n";
|
||||||
import { EmptyStateDetailed } from "@plane/propel/empty-state";
|
import { EmptyStateDetailed } from "@plane/propel/empty-state";
|
||||||
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
||||||
|
|
@ -10,7 +10,6 @@ import type { ISearchIssueResponse } from "@plane/types";
|
||||||
import { EIssuesStoreType, EUserProjectRoles } from "@plane/types";
|
import { EIssuesStoreType, EUserProjectRoles } from "@plane/types";
|
||||||
// components
|
// components
|
||||||
import { ExistingIssuesListModal } from "@/components/core/modals/existing-issues-list-modal";
|
import { ExistingIssuesListModal } from "@/components/core/modals/existing-issues-list-modal";
|
||||||
import { captureClick } from "@/helpers/event-tracker.helper";
|
|
||||||
// hooks
|
// hooks
|
||||||
import { useCommandPalette } from "@/hooks/store/use-command-palette";
|
import { useCommandPalette } from "@/hooks/store/use-command-palette";
|
||||||
import { useIssues } from "@/hooks/store/use-issues";
|
import { useIssues } from "@/hooks/store/use-issues";
|
||||||
|
|
@ -94,7 +93,6 @@ export const ModuleEmptyState = observer(function ModuleEmptyState() {
|
||||||
{
|
{
|
||||||
label: t("project_empty_state.module_work_items.cta_primary"),
|
label: t("project_empty_state.module_work_items.cta_primary"),
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
captureClick({ elementName: WORK_ITEM_TRACKER_ELEMENTS.EMPTY_STATE_ADD_BUTTON.MODULE });
|
|
||||||
toggleCreateIssueModal(true, EIssuesStoreType.MODULE);
|
toggleCreateIssueModal(true, EIssuesStoreType.MODULE);
|
||||||
},
|
},
|
||||||
disabled: !canPerformEmptyStateActions,
|
disabled: !canPerformEmptyStateActions,
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,10 @@
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
import { useParams } from "next/navigation";
|
import { useParams } from "next/navigation";
|
||||||
// plane imports
|
// plane imports
|
||||||
import { EUserPermissionsLevel, WORK_ITEM_TRACKER_ELEMENTS } from "@plane/constants";
|
import { EUserPermissionsLevel } from "@plane/constants";
|
||||||
import { useTranslation } from "@plane/i18n";
|
import { useTranslation } from "@plane/i18n";
|
||||||
import { EmptyStateDetailed } from "@plane/propel/empty-state";
|
import { EmptyStateDetailed } from "@plane/propel/empty-state";
|
||||||
import { EIssuesStoreType, EUserProjectRoles } from "@plane/types";
|
import { EIssuesStoreType, EUserProjectRoles } from "@plane/types";
|
||||||
// components
|
|
||||||
import { captureClick } from "@/helpers/event-tracker.helper";
|
|
||||||
// hooks
|
// hooks
|
||||||
import { useCommandPalette } from "@/hooks/store/use-command-palette";
|
import { useCommandPalette } from "@/hooks/store/use-command-palette";
|
||||||
import { useUserPermissions } from "@/hooks/store/user";
|
import { useUserPermissions } from "@/hooks/store/user";
|
||||||
|
|
@ -54,7 +52,6 @@ export const ProjectEmptyState = observer(function ProjectEmptyState() {
|
||||||
{
|
{
|
||||||
label: t("project_empty_state.work_items.cta_primary"),
|
label: t("project_empty_state.work_items.cta_primary"),
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
captureClick({ elementName: WORK_ITEM_TRACKER_ELEMENTS.EMPTY_STATE_ADD_BUTTON.WORK_ITEMS });
|
|
||||||
toggleCreateIssueModal(true, EIssuesStoreType.PROJECT);
|
toggleCreateIssueModal(true, EIssuesStoreType.PROJECT);
|
||||||
},
|
},
|
||||||
disabled: !canPerformEmptyStateActions,
|
disabled: !canPerformEmptyStateActions,
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,6 @@ import { observer } from "mobx-react";
|
||||||
import { EUserPermissions, EUserPermissionsLevel, WORK_ITEM_TRACKER_ELEMENTS } from "@plane/constants";
|
import { EUserPermissions, EUserPermissionsLevel, WORK_ITEM_TRACKER_ELEMENTS } from "@plane/constants";
|
||||||
import { EmptyStateDetailed } from "@plane/propel/empty-state";
|
import { EmptyStateDetailed } from "@plane/propel/empty-state";
|
||||||
import { EIssuesStoreType } from "@plane/types";
|
import { EIssuesStoreType } from "@plane/types";
|
||||||
// components
|
|
||||||
import { captureClick } from "@/helpers/event-tracker.helper";
|
|
||||||
// hooks
|
// hooks
|
||||||
import { useCommandPalette } from "@/hooks/store/use-command-palette";
|
import { useCommandPalette } from "@/hooks/store/use-command-palette";
|
||||||
import { useUserPermissions } from "@/hooks/store/user";
|
import { useUserPermissions } from "@/hooks/store/user";
|
||||||
|
|
@ -30,7 +28,6 @@ export const ProjectViewEmptyState = observer(function ProjectViewEmptyState() {
|
||||||
{
|
{
|
||||||
label: "New work item",
|
label: "New work item",
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
captureClick({ elementName: WORK_ITEM_TRACKER_ELEMENTS.EMPTY_STATE_ADD_BUTTON.PROJECT_VIEW });
|
|
||||||
toggleCreateIssueModal(true, EIssuesStoreType.PROJECT_VIEW);
|
toggleCreateIssueModal(true, EIssuesStoreType.PROJECT_VIEW);
|
||||||
},
|
},
|
||||||
disabled: !isCreatingIssueAllowed,
|
disabled: !isCreatingIssueAllowed,
|
||||||
|
|
|
||||||
|
|
@ -5,12 +5,10 @@ import { dropTargetForElements } from "@atlaskit/pragmatic-drag-and-drop/element
|
||||||
import { autoScrollForElements } from "@atlaskit/pragmatic-drag-and-drop-auto-scroll/element";
|
import { autoScrollForElements } from "@atlaskit/pragmatic-drag-and-drop-auto-scroll/element";
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
import { useParams } from "next/navigation";
|
import { useParams } from "next/navigation";
|
||||||
import { EIssueFilterType, EUserPermissions, EUserPermissionsLevel, WORK_ITEM_TRACKER_EVENTS } from "@plane/constants";
|
import { EIssueFilterType, EUserPermissions, EUserPermissionsLevel } from "@plane/constants";
|
||||||
import type { EIssuesStoreType } from "@plane/types";
|
import type { EIssuesStoreType } from "@plane/types";
|
||||||
import { EIssueServiceType, EIssueLayoutTypes } from "@plane/types";
|
import { EIssueServiceType, EIssueLayoutTypes } from "@plane/types";
|
||||||
//constants
|
|
||||||
//hooks
|
//hooks
|
||||||
import { captureError, captureSuccess } from "@/helpers/event-tracker.helper";
|
|
||||||
import { useIssueDetail } from "@/hooks/store/use-issue-detail";
|
import { useIssueDetail } from "@/hooks/store/use-issue-detail";
|
||||||
import { useIssues } from "@/hooks/store/use-issues";
|
import { useIssues } from "@/hooks/store/use-issues";
|
||||||
import { useKanbanView } from "@/hooks/store/use-kanban-view";
|
import { useKanbanView } from "@/hooks/store/use-kanban-view";
|
||||||
|
|
@ -200,23 +198,14 @@ export const BaseKanBanRoot = observer(function BaseKanBanRoot(props: IBaseKanBa
|
||||||
|
|
||||||
if (!draggedIssueId || !draggedIssue) return;
|
if (!draggedIssueId || !draggedIssue) return;
|
||||||
|
|
||||||
await removeIssue(draggedIssue.project_id, draggedIssueId)
|
try {
|
||||||
.then(() => {
|
await removeIssue(draggedIssue.project_id, draggedIssueId);
|
||||||
captureSuccess({
|
setDeleteIssueModal(false);
|
||||||
eventName: WORK_ITEM_TRACKER_EVENTS.delete,
|
setDraggedIssueId(undefined);
|
||||||
payload: { id: draggedIssueId },
|
} catch (_error) {
|
||||||
});
|
setDeleteIssueModal(false);
|
||||||
})
|
setDraggedIssueId(undefined);
|
||||||
.catch(() => {
|
}
|
||||||
captureError({
|
|
||||||
eventName: WORK_ITEM_TRACKER_EVENTS.delete,
|
|
||||||
payload: { id: draggedIssueId },
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.finally(() => {
|
|
||||||
setDeleteIssueModal(false);
|
|
||||||
setDraggedIssueId(undefined);
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleCollapsedGroups = useCallback(
|
const handleCollapsedGroups = useCallback(
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@ import { observer } from "mobx-react";
|
||||||
import { useParams } from "next/navigation";
|
import { useParams } from "next/navigation";
|
||||||
// lucide icons
|
// lucide icons
|
||||||
import { Minimize2, Maximize2, Circle } from "lucide-react";
|
import { Minimize2, Maximize2, Circle } from "lucide-react";
|
||||||
import { WORK_ITEM_TRACKER_EVENTS } from "@plane/constants";
|
|
||||||
import { PlusIcon } from "@plane/propel/icons";
|
import { PlusIcon } from "@plane/propel/icons";
|
||||||
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
||||||
import type { TIssue, ISearchIssueResponse, TIssueKanbanFilters, TIssueGroupByOptions } from "@plane/types";
|
import type { TIssue, ISearchIssueResponse, TIssueKanbanFilters, TIssueGroupByOptions } from "@plane/types";
|
||||||
|
|
@ -13,7 +12,6 @@ import { CustomMenu } from "@plane/ui";
|
||||||
import { ExistingIssuesListModal } from "@/components/core/modals/existing-issues-list-modal";
|
import { ExistingIssuesListModal } from "@/components/core/modals/existing-issues-list-modal";
|
||||||
import { CreateUpdateIssueModal } from "@/components/issues/issue-modal/modal";
|
import { CreateUpdateIssueModal } from "@/components/issues/issue-modal/modal";
|
||||||
// constants
|
// constants
|
||||||
import { captureClick } from "@/helpers/event-tracker.helper";
|
|
||||||
import { useIssueStoreType } from "@/hooks/use-issue-layout-store";
|
import { useIssueStoreType } from "@/hooks/use-issue-layout-store";
|
||||||
import { CreateUpdateEpicModal } from "@/plane-web/components/epics/epic-modal";
|
import { CreateUpdateEpicModal } from "@/plane-web/components/epics/epic-modal";
|
||||||
// types
|
// types
|
||||||
|
|
@ -75,7 +73,7 @@ export const HeaderGroupByCard = observer(function HeaderGroupByCard(props: IHea
|
||||||
title: "Success!",
|
title: "Success!",
|
||||||
message: "Work items added to the cycle successfully.",
|
message: "Work items added to the cycle successfully.",
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (_error) {
|
||||||
setToast({
|
setToast({
|
||||||
type: TOAST_TYPE.ERROR,
|
type: TOAST_TYPE.ERROR,
|
||||||
title: "Error!",
|
title: "Error!",
|
||||||
|
|
@ -162,7 +160,6 @@ export const HeaderGroupByCard = observer(function HeaderGroupByCard(props: IHea
|
||||||
>
|
>
|
||||||
<CustomMenu.MenuItem
|
<CustomMenu.MenuItem
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
captureClick({ elementName: WORK_ITEM_TRACKER_EVENTS.create });
|
|
||||||
setIsOpen(true);
|
setIsOpen(true);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|
@ -170,7 +167,6 @@ export const HeaderGroupByCard = observer(function HeaderGroupByCard(props: IHea
|
||||||
</CustomMenu.MenuItem>
|
</CustomMenu.MenuItem>
|
||||||
<CustomMenu.MenuItem
|
<CustomMenu.MenuItem
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
captureClick({ elementName: WORK_ITEM_TRACKER_EVENTS.add_existing });
|
|
||||||
setOpenExistingIssueListModal(true);
|
setOpenExistingIssueListModal(true);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|
@ -181,7 +177,6 @@ export const HeaderGroupByCard = observer(function HeaderGroupByCard(props: IHea
|
||||||
<button
|
<button
|
||||||
className="flex h-[20px] w-[20px] flex-shrink-0 cursor-pointer overflow-hidden transition-all hover:bg-layer-transparent-hover bg-layer-transparent rounded-sm items-center justify-center"
|
className="flex h-[20px] w-[20px] flex-shrink-0 cursor-pointer overflow-hidden transition-all hover:bg-layer-transparent-hover bg-layer-transparent rounded-sm items-center justify-center"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
captureClick({ elementName: WORK_ITEM_TRACKER_EVENTS.create });
|
|
||||||
setIsOpen(true);
|
setIsOpen(true);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@ import { useState } from "react";
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
import { useParams } from "next/navigation";
|
import { useParams } from "next/navigation";
|
||||||
import { CircleDashed } from "lucide-react";
|
import { CircleDashed } from "lucide-react";
|
||||||
import { WORK_ITEM_TRACKER_EVENTS } from "@plane/constants";
|
|
||||||
import { PlusIcon } from "@plane/propel/icons";
|
import { PlusIcon } from "@plane/propel/icons";
|
||||||
// types
|
// types
|
||||||
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
||||||
|
|
@ -15,7 +14,6 @@ import { ExistingIssuesListModal } from "@/components/core/modals/existing-issue
|
||||||
import { MultipleSelectGroupAction } from "@/components/core/multiple-select";
|
import { MultipleSelectGroupAction } from "@/components/core/multiple-select";
|
||||||
import { CreateUpdateIssueModal } from "@/components/issues/issue-modal/modal";
|
import { CreateUpdateIssueModal } from "@/components/issues/issue-modal/modal";
|
||||||
// constants
|
// constants
|
||||||
import { captureClick } from "@/helpers/event-tracker.helper";
|
|
||||||
import { useIssueStoreType } from "@/hooks/use-issue-layout-store";
|
import { useIssueStoreType } from "@/hooks/use-issue-layout-store";
|
||||||
import type { TSelectionHelper } from "@/hooks/use-multiple-select";
|
import type { TSelectionHelper } from "@/hooks/use-multiple-select";
|
||||||
// plane-web
|
// plane-web
|
||||||
|
|
@ -132,7 +130,6 @@ export const HeaderGroupByCard = observer(function HeaderGroupByCard(props: IHea
|
||||||
>
|
>
|
||||||
<CustomMenu.MenuItem
|
<CustomMenu.MenuItem
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
captureClick({ elementName: WORK_ITEM_TRACKER_EVENTS.create });
|
|
||||||
setIsOpen(true);
|
setIsOpen(true);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|
@ -140,7 +137,6 @@ export const HeaderGroupByCard = observer(function HeaderGroupByCard(props: IHea
|
||||||
</CustomMenu.MenuItem>
|
</CustomMenu.MenuItem>
|
||||||
<CustomMenu.MenuItem
|
<CustomMenu.MenuItem
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
captureClick({ elementName: WORK_ITEM_TRACKER_EVENTS.add_existing });
|
|
||||||
setOpenExistingIssueListModal(true);
|
setOpenExistingIssueListModal(true);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|
@ -151,7 +147,6 @@ export const HeaderGroupByCard = observer(function HeaderGroupByCard(props: IHea
|
||||||
<div
|
<div
|
||||||
className="flex h-5 w-5 flex-shrink-0 cursor-pointer items-center justify-center overflow-hidden rounded-xs transition-all hover:bg-layer-1"
|
className="flex h-5 w-5 flex-shrink-0 cursor-pointer items-center justify-center overflow-hidden rounded-xs transition-all hover:bg-layer-1"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
captureClick({ elementName: WORK_ITEM_TRACKER_EVENTS.create });
|
|
||||||
setIsOpen(true);
|
setIsOpen(true);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,6 @@ import { observer } from "mobx-react";
|
||||||
import { useParams } from "next/navigation";
|
import { useParams } from "next/navigation";
|
||||||
// icons
|
// icons
|
||||||
import { Paperclip } from "lucide-react";
|
import { Paperclip } from "lucide-react";
|
||||||
// types
|
|
||||||
import { WORK_ITEM_TRACKER_EVENTS } from "@plane/constants";
|
|
||||||
// i18n
|
// i18n
|
||||||
import { useTranslation } from "@plane/i18n";
|
import { useTranslation } from "@plane/i18n";
|
||||||
import { LinkIcon, StartDatePropertyIcon, ViewsIcon, DueDatePropertyIcon } from "@plane/propel/icons";
|
import { LinkIcon, StartDatePropertyIcon, ViewsIcon, DueDatePropertyIcon } from "@plane/propel/icons";
|
||||||
|
|
@ -29,8 +27,6 @@ import { MemberDropdown } from "@/components/dropdowns/member/dropdown";
|
||||||
import { ModuleDropdown } from "@/components/dropdowns/module/dropdown";
|
import { ModuleDropdown } from "@/components/dropdowns/module/dropdown";
|
||||||
import { PriorityDropdown } from "@/components/dropdowns/priority";
|
import { PriorityDropdown } from "@/components/dropdowns/priority";
|
||||||
import { StateDropdown } from "@/components/dropdowns/state/dropdown";
|
import { StateDropdown } from "@/components/dropdowns/state/dropdown";
|
||||||
// helpers
|
|
||||||
import { captureSuccess } from "@/helpers/event-tracker.helper";
|
|
||||||
// hooks
|
// hooks
|
||||||
import { useProjectEstimates } from "@/hooks/store/estimates";
|
import { useProjectEstimates } from "@/hooks/store/estimates";
|
||||||
import { useIssues } from "@/hooks/store/use-issues";
|
import { useIssues } from "@/hooks/store/use-issues";
|
||||||
|
|
@ -105,44 +101,20 @@ export const IssueProperties = observer(function IssueProperties(props: IIssuePr
|
||||||
[workspaceSlug, issue, changeModulesInIssue, addCycleToIssue, removeCycleFromIssue]
|
[workspaceSlug, issue, changeModulesInIssue, addCycleToIssue, removeCycleFromIssue]
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleState = (stateId: string) => {
|
const handleState = async (stateId: string) => {
|
||||||
if (updateIssue)
|
if (updateIssue) await updateIssue(issue.project_id, issue.id, { state_id: stateId });
|
||||||
updateIssue(issue.project_id, issue.id, { state_id: stateId }).then(() => {
|
|
||||||
captureSuccess({
|
|
||||||
eventName: WORK_ITEM_TRACKER_EVENTS.update,
|
|
||||||
payload: { id: issue.id },
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handlePriority = (value: TIssuePriorities) => {
|
const handlePriority = async (value: TIssuePriorities) => {
|
||||||
if (updateIssue)
|
if (updateIssue) await updateIssue(issue.project_id, issue.id, { priority: value });
|
||||||
updateIssue(issue.project_id, issue.id, { priority: value }).then(() => {
|
|
||||||
captureSuccess({
|
|
||||||
eventName: WORK_ITEM_TRACKER_EVENTS.update,
|
|
||||||
payload: { id: issue.id },
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleLabel = (ids: string[]) => {
|
const handleLabel = async (ids: string[]) => {
|
||||||
if (updateIssue)
|
if (updateIssue) await updateIssue(issue.project_id, issue.id, { label_ids: ids });
|
||||||
updateIssue(issue.project_id, issue.id, { label_ids: ids }).then(() => {
|
|
||||||
captureSuccess({
|
|
||||||
eventName: WORK_ITEM_TRACKER_EVENTS.update,
|
|
||||||
payload: { id: issue.id },
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleAssignee = (ids: string[]) => {
|
const handleAssignee = async (ids: string[]) => {
|
||||||
if (updateIssue)
|
if (updateIssue) await updateIssue(issue.project_id, issue.id, { assignee_ids: ids });
|
||||||
updateIssue(issue.project_id, issue.id, { assignee_ids: ids }).then(() => {
|
|
||||||
captureSuccess({
|
|
||||||
eventName: WORK_ITEM_TRACKER_EVENTS.update,
|
|
||||||
payload: { id: issue.id },
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleModule = useCallback(
|
const handleModule = useCallback(
|
||||||
|
|
@ -157,11 +129,6 @@ export const IssueProperties = observer(function IssueProperties(props: IIssuePr
|
||||||
else modulesToAdd.push(moduleId);
|
else modulesToAdd.push(moduleId);
|
||||||
if (modulesToAdd.length > 0) issueOperations.addModulesToIssue(modulesToAdd);
|
if (modulesToAdd.length > 0) issueOperations.addModulesToIssue(modulesToAdd);
|
||||||
if (modulesToRemove.length > 0) issueOperations.removeModulesFromIssue(modulesToRemove);
|
if (modulesToRemove.length > 0) issueOperations.removeModulesFromIssue(modulesToRemove);
|
||||||
|
|
||||||
captureSuccess({
|
|
||||||
eventName: WORK_ITEM_TRACKER_EVENTS.update,
|
|
||||||
payload: { id: issue.id },
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
[issueOperations, issue]
|
[issueOperations, issue]
|
||||||
);
|
);
|
||||||
|
|
@ -171,47 +138,22 @@ export const IssueProperties = observer(function IssueProperties(props: IIssuePr
|
||||||
if (!issue || issue.cycle_id === cycleId) return;
|
if (!issue || issue.cycle_id === cycleId) return;
|
||||||
if (cycleId) issueOperations.addIssueToCycle?.(cycleId);
|
if (cycleId) issueOperations.addIssueToCycle?.(cycleId);
|
||||||
else issueOperations.removeIssueFromCycle?.();
|
else issueOperations.removeIssueFromCycle?.();
|
||||||
|
|
||||||
captureSuccess({
|
|
||||||
eventName: WORK_ITEM_TRACKER_EVENTS.update,
|
|
||||||
payload: { id: issue.id },
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
[issue, issueOperations]
|
[issue, issueOperations]
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleStartDate = (date: Date | null) => {
|
const handleStartDate = async (date: Date | null) => {
|
||||||
if (updateIssue)
|
if (updateIssue)
|
||||||
updateIssue(issue.project_id, issue.id, { start_date: date ? renderFormattedPayloadDate(date) : null }).then(
|
await updateIssue(issue.project_id, issue.id, { start_date: date ? renderFormattedPayloadDate(date) : null });
|
||||||
() => {
|
|
||||||
captureSuccess({
|
|
||||||
eventName: WORK_ITEM_TRACKER_EVENTS.update,
|
|
||||||
payload: { id: issue.id },
|
|
||||||
});
|
|
||||||
}
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleTargetDate = (date: Date | null) => {
|
const handleTargetDate = async (date: Date | null) => {
|
||||||
if (updateIssue)
|
if (updateIssue)
|
||||||
updateIssue(issue.project_id, issue.id, { target_date: date ? renderFormattedPayloadDate(date) : null }).then(
|
await updateIssue(issue.project_id, issue.id, { target_date: date ? renderFormattedPayloadDate(date) : null });
|
||||||
() => {
|
|
||||||
captureSuccess({
|
|
||||||
eventName: WORK_ITEM_TRACKER_EVENTS.update,
|
|
||||||
payload: { id: issue.id },
|
|
||||||
});
|
|
||||||
}
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleEstimate = (value: string | undefined) => {
|
const handleEstimate = async (value: string | undefined) => {
|
||||||
if (updateIssue)
|
if (updateIssue) await updateIssue(issue.project_id, issue.id, { estimate_point: value });
|
||||||
updateIssue(issue.project_id, issue.id, { estimate_point: value }).then(() => {
|
|
||||||
captureSuccess({
|
|
||||||
eventName: WORK_ITEM_TRACKER_EVENTS.update,
|
|
||||||
payload: { id: issue.id },
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const workItemLink = generateWorkItemLink({
|
const workItemLink = generateWorkItemLink({
|
||||||
|
|
|
||||||
|
|
@ -3,14 +3,12 @@ import { omit } from "lodash-es";
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
import { useParams } from "next/navigation";
|
import { useParams } from "next/navigation";
|
||||||
// plane imports
|
// plane imports
|
||||||
import { ARCHIVABLE_STATE_GROUPS, WORK_ITEM_TRACKER_ELEMENTS } from "@plane/constants";
|
import { ARCHIVABLE_STATE_GROUPS } from "@plane/constants";
|
||||||
import type { TIssue } from "@plane/types";
|
import type { TIssue } from "@plane/types";
|
||||||
import { EIssuesStoreType } from "@plane/types";
|
import { EIssuesStoreType } from "@plane/types";
|
||||||
import type { TContextMenuItem } from "@plane/ui";
|
|
||||||
import { ContextMenu, CustomMenu } from "@plane/ui";
|
import { ContextMenu, CustomMenu } from "@plane/ui";
|
||||||
import { cn } from "@plane/utils";
|
import { cn } from "@plane/utils";
|
||||||
// hooks
|
// hooks
|
||||||
import { captureClick } from "@/helpers/event-tracker.helper";
|
|
||||||
import { useProject } from "@/hooks/store/use-project";
|
import { useProject } from "@/hooks/store/use-project";
|
||||||
import { useProjectState } from "@/hooks/store/use-project-state";
|
import { useProjectState } from "@/hooks/store/use-project-state";
|
||||||
// plane-web components
|
// plane-web components
|
||||||
|
|
@ -88,9 +86,7 @@ export const AllIssueQuickActions = observer(function AllIssueQuickActions(props
|
||||||
const CONTEXT_MENU_ITEMS = MENU_ITEMS.map(function CONTEXT_MENU_ITEMS(item) {
|
const CONTEXT_MENU_ITEMS = MENU_ITEMS.map(function CONTEXT_MENU_ITEMS(item) {
|
||||||
return {
|
return {
|
||||||
...item,
|
...item,
|
||||||
|
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
captureClick({ elementName: WORK_ITEM_TRACKER_ELEMENTS.QUICK_ACTIONS.GLOBAL_VIEW });
|
|
||||||
item.action();
|
item.action();
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
@ -180,7 +176,6 @@ export const AllIssueQuickActions = observer(function AllIssueQuickActions(props
|
||||||
<CustomMenu.MenuItem
|
<CustomMenu.MenuItem
|
||||||
key={nestedItem.key}
|
key={nestedItem.key}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
captureClick({ elementName: WORK_ITEM_TRACKER_ELEMENTS.QUICK_ACTIONS.GLOBAL_VIEW });
|
|
||||||
nestedItem.action();
|
nestedItem.action();
|
||||||
}}
|
}}
|
||||||
className={cn(
|
className={cn(
|
||||||
|
|
@ -216,7 +211,6 @@ export const AllIssueQuickActions = observer(function AllIssueQuickActions(props
|
||||||
<CustomMenu.MenuItem
|
<CustomMenu.MenuItem
|
||||||
key={item.key}
|
key={item.key}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
captureClick({ elementName: WORK_ITEM_TRACKER_ELEMENTS.QUICK_ACTIONS.GLOBAL_VIEW });
|
|
||||||
item.action();
|
item.action();
|
||||||
}}
|
}}
|
||||||
className={cn(
|
className={cn(
|
||||||
|
|
|
||||||
|
|
@ -2,13 +2,11 @@ import { useState } from "react";
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
import { useParams } from "next/navigation";
|
import { useParams } from "next/navigation";
|
||||||
// ui
|
// ui
|
||||||
import { EUserPermissions, EUserPermissionsLevel, WORK_ITEM_TRACKER_ELEMENTS } from "@plane/constants";
|
import { EUserPermissions, EUserPermissionsLevel } from "@plane/constants";
|
||||||
import { EIssuesStoreType } from "@plane/types";
|
import { EIssuesStoreType } from "@plane/types";
|
||||||
import type { TContextMenuItem } from "@plane/ui";
|
|
||||||
import { ContextMenu, CustomMenu } from "@plane/ui";
|
import { ContextMenu, CustomMenu } from "@plane/ui";
|
||||||
import { cn } from "@plane/utils";
|
import { cn } from "@plane/utils";
|
||||||
// hooks
|
// hooks
|
||||||
import { captureClick } from "@/helpers/event-tracker.helper";
|
|
||||||
import { useIssues } from "@/hooks/store/use-issues";
|
import { useIssues } from "@/hooks/store/use-issues";
|
||||||
import { useUserPermissions } from "@/hooks/store/user";
|
import { useUserPermissions } from "@/hooks/store/user";
|
||||||
// local imports
|
// local imports
|
||||||
|
|
@ -66,7 +64,6 @@ export const ArchivedIssueQuickActions = observer(function ArchivedIssueQuickAct
|
||||||
...item,
|
...item,
|
||||||
|
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
captureClick({ elementName: WORK_ITEM_TRACKER_ELEMENTS.QUICK_ACTIONS.ARCHIVED });
|
|
||||||
item.action();
|
item.action();
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
@ -99,7 +96,6 @@ export const ArchivedIssueQuickActions = observer(function ArchivedIssueQuickAct
|
||||||
key={item.key}
|
key={item.key}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
item.action();
|
item.action();
|
||||||
captureClick({ elementName: WORK_ITEM_TRACKER_ELEMENTS.QUICK_ACTIONS.ARCHIVED });
|
|
||||||
}}
|
}}
|
||||||
className={cn(
|
className={cn(
|
||||||
"flex items-center gap-2",
|
"flex items-center gap-2",
|
||||||
|
|
|
||||||
|
|
@ -3,19 +3,12 @@ import { omit } from "lodash-es";
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
import { useParams } from "next/navigation";
|
import { useParams } from "next/navigation";
|
||||||
// plane imports
|
// plane imports
|
||||||
import {
|
import { ARCHIVABLE_STATE_GROUPS, EUserPermissions, EUserPermissionsLevel } from "@plane/constants";
|
||||||
ARCHIVABLE_STATE_GROUPS,
|
|
||||||
EUserPermissions,
|
|
||||||
EUserPermissionsLevel,
|
|
||||||
WORK_ITEM_TRACKER_ELEMENTS,
|
|
||||||
} from "@plane/constants";
|
|
||||||
import type { TIssue } from "@plane/types";
|
import type { TIssue } from "@plane/types";
|
||||||
import { EIssuesStoreType } from "@plane/types";
|
import { EIssuesStoreType } from "@plane/types";
|
||||||
import type { TContextMenuItem } from "@plane/ui";
|
|
||||||
import { ContextMenu, CustomMenu } from "@plane/ui";
|
import { ContextMenu, CustomMenu } from "@plane/ui";
|
||||||
import { cn } from "@plane/utils";
|
import { cn } from "@plane/utils";
|
||||||
// hooks
|
// hooks
|
||||||
import { captureClick } from "@/helpers/event-tracker.helper";
|
|
||||||
import { useIssues } from "@/hooks/store/use-issues";
|
import { useIssues } from "@/hooks/store/use-issues";
|
||||||
import { useProject } from "@/hooks/store/use-project";
|
import { useProject } from "@/hooks/store/use-project";
|
||||||
import { useProjectState } from "@/hooks/store/use-project-state";
|
import { useProjectState } from "@/hooks/store/use-project-state";
|
||||||
|
|
@ -107,7 +100,6 @@ export const CycleIssueQuickActions = observer(function CycleIssueQuickActions(p
|
||||||
...item,
|
...item,
|
||||||
|
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
captureClick({ elementName: WORK_ITEM_TRACKER_ELEMENTS.QUICK_ACTIONS.CYCLE });
|
|
||||||
item.action();
|
item.action();
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
@ -197,7 +189,6 @@ export const CycleIssueQuickActions = observer(function CycleIssueQuickActions(p
|
||||||
<CustomMenu.MenuItem
|
<CustomMenu.MenuItem
|
||||||
key={nestedItem.key}
|
key={nestedItem.key}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
captureClick({ elementName: WORK_ITEM_TRACKER_ELEMENTS.QUICK_ACTIONS.CYCLE });
|
|
||||||
nestedItem.action();
|
nestedItem.action();
|
||||||
}}
|
}}
|
||||||
className={cn(
|
className={cn(
|
||||||
|
|
@ -233,7 +224,6 @@ export const CycleIssueQuickActions = observer(function CycleIssueQuickActions(p
|
||||||
<CustomMenu.MenuItem
|
<CustomMenu.MenuItem
|
||||||
key={item.key}
|
key={item.key}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
captureClick({ elementName: WORK_ITEM_TRACKER_ELEMENTS.QUICK_ACTIONS.CYCLE });
|
|
||||||
item.action();
|
item.action();
|
||||||
}}
|
}}
|
||||||
className={cn(
|
className={cn(
|
||||||
|
|
|
||||||
|
|
@ -4,19 +4,12 @@ import { observer } from "mobx-react";
|
||||||
import { useParams, usePathname } from "next/navigation";
|
import { useParams, usePathname } from "next/navigation";
|
||||||
import { Ellipsis } from "lucide-react";
|
import { Ellipsis } from "lucide-react";
|
||||||
// plane imports
|
// plane imports
|
||||||
import {
|
import { ARCHIVABLE_STATE_GROUPS, EUserPermissions, EUserPermissionsLevel } from "@plane/constants";
|
||||||
ARCHIVABLE_STATE_GROUPS,
|
|
||||||
EUserPermissions,
|
|
||||||
EUserPermissionsLevel,
|
|
||||||
WORK_ITEM_TRACKER_ELEMENTS,
|
|
||||||
} from "@plane/constants";
|
|
||||||
import type { TIssue } from "@plane/types";
|
import type { TIssue } from "@plane/types";
|
||||||
import { EIssuesStoreType } from "@plane/types";
|
import { EIssuesStoreType } from "@plane/types";
|
||||||
import type { TContextMenuItem } from "@plane/ui";
|
|
||||||
import { ContextMenu, CustomMenu } from "@plane/ui";
|
import { ContextMenu, CustomMenu } from "@plane/ui";
|
||||||
import { cn } from "@plane/utils";
|
import { cn } from "@plane/utils";
|
||||||
// hooks
|
// hooks
|
||||||
import { captureClick } from "@/helpers/event-tracker.helper";
|
|
||||||
import { useIssues } from "@/hooks/store/use-issues";
|
import { useIssues } from "@/hooks/store/use-issues";
|
||||||
import { useProject } from "@/hooks/store/use-project";
|
import { useProject } from "@/hooks/store/use-project";
|
||||||
import { useProjectState } from "@/hooks/store/use-project-state";
|
import { useProjectState } from "@/hooks/store/use-project-state";
|
||||||
|
|
@ -186,7 +179,6 @@ export const WorkItemDetailQuickActions = observer(function WorkItemDetailQuickA
|
||||||
...item,
|
...item,
|
||||||
|
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
captureClick({ elementName: WORK_ITEM_TRACKER_ELEMENTS.QUICK_ACTIONS.PROJECT_VIEW });
|
|
||||||
item.action();
|
item.action();
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
@ -286,7 +278,6 @@ export const WorkItemDetailQuickActions = observer(function WorkItemDetailQuickA
|
||||||
<CustomMenu.MenuItem
|
<CustomMenu.MenuItem
|
||||||
key={nestedItem.key}
|
key={nestedItem.key}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
captureClick({ elementName: WORK_ITEM_TRACKER_ELEMENTS.QUICK_ACTIONS.PROJECT_VIEW });
|
|
||||||
nestedItem.action();
|
nestedItem.action();
|
||||||
}}
|
}}
|
||||||
className={cn(
|
className={cn(
|
||||||
|
|
@ -322,7 +313,6 @@ export const WorkItemDetailQuickActions = observer(function WorkItemDetailQuickA
|
||||||
<CustomMenu.MenuItem
|
<CustomMenu.MenuItem
|
||||||
key={item.key}
|
key={item.key}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
captureClick({ elementName: WORK_ITEM_TRACKER_ELEMENTS.QUICK_ACTIONS.PROJECT_VIEW });
|
|
||||||
item.action();
|
item.action();
|
||||||
}}
|
}}
|
||||||
className={cn(
|
className={cn(
|
||||||
|
|
|
||||||
|
|
@ -3,19 +3,12 @@ import { omit } from "lodash-es";
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
import { useParams } from "next/navigation";
|
import { useParams } from "next/navigation";
|
||||||
// plane imports
|
// plane imports
|
||||||
import {
|
import { ARCHIVABLE_STATE_GROUPS, EUserPermissions, EUserPermissionsLevel } from "@plane/constants";
|
||||||
ARCHIVABLE_STATE_GROUPS,
|
|
||||||
EUserPermissions,
|
|
||||||
EUserPermissionsLevel,
|
|
||||||
WORK_ITEM_TRACKER_ELEMENTS,
|
|
||||||
} from "@plane/constants";
|
|
||||||
import type { TIssue } from "@plane/types";
|
import type { TIssue } from "@plane/types";
|
||||||
import { EIssuesStoreType } from "@plane/types";
|
import { EIssuesStoreType } from "@plane/types";
|
||||||
import type { TContextMenuItem } from "@plane/ui";
|
|
||||||
import { ContextMenu, CustomMenu } from "@plane/ui";
|
import { ContextMenu, CustomMenu } from "@plane/ui";
|
||||||
import { cn } from "@plane/utils";
|
import { cn } from "@plane/utils";
|
||||||
// hooks
|
// hooks
|
||||||
import { captureClick } from "@/helpers/event-tracker.helper";
|
|
||||||
import { useIssues } from "@/hooks/store/use-issues";
|
import { useIssues } from "@/hooks/store/use-issues";
|
||||||
import { useProject } from "@/hooks/store/use-project";
|
import { useProject } from "@/hooks/store/use-project";
|
||||||
import { useProjectState } from "@/hooks/store/use-project-state";
|
import { useProjectState } from "@/hooks/store/use-project-state";
|
||||||
|
|
@ -107,7 +100,6 @@ export const ModuleIssueQuickActions = observer(function ModuleIssueQuickActions
|
||||||
...item,
|
...item,
|
||||||
|
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
captureClick({ elementName: WORK_ITEM_TRACKER_ELEMENTS.QUICK_ACTIONS.MODULE });
|
|
||||||
item.action();
|
item.action();
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
@ -196,7 +188,6 @@ export const ModuleIssueQuickActions = observer(function ModuleIssueQuickActions
|
||||||
<CustomMenu.MenuItem
|
<CustomMenu.MenuItem
|
||||||
key={nestedItem.key}
|
key={nestedItem.key}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
captureClick({ elementName: WORK_ITEM_TRACKER_ELEMENTS.QUICK_ACTIONS.MODULE });
|
|
||||||
nestedItem.action();
|
nestedItem.action();
|
||||||
}}
|
}}
|
||||||
className={cn(
|
className={cn(
|
||||||
|
|
@ -232,7 +223,6 @@ export const ModuleIssueQuickActions = observer(function ModuleIssueQuickActions
|
||||||
<CustomMenu.MenuItem
|
<CustomMenu.MenuItem
|
||||||
key={item.key}
|
key={item.key}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
captureClick({ elementName: WORK_ITEM_TRACKER_ELEMENTS.QUICK_ACTIONS.MODULE });
|
|
||||||
item.action();
|
item.action();
|
||||||
}}
|
}}
|
||||||
className={cn(
|
className={cn(
|
||||||
|
|
|
||||||
|
|
@ -3,19 +3,12 @@ import { omit } from "lodash-es";
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
import { useParams } from "next/navigation";
|
import { useParams } from "next/navigation";
|
||||||
// plane imports
|
// plane imports
|
||||||
import {
|
import { ARCHIVABLE_STATE_GROUPS, EUserPermissions, EUserPermissionsLevel } from "@plane/constants";
|
||||||
ARCHIVABLE_STATE_GROUPS,
|
|
||||||
EUserPermissions,
|
|
||||||
EUserPermissionsLevel,
|
|
||||||
WORK_ITEM_TRACKER_ELEMENTS,
|
|
||||||
} from "@plane/constants";
|
|
||||||
import type { TIssue } from "@plane/types";
|
import type { TIssue } from "@plane/types";
|
||||||
import { EIssuesStoreType } from "@plane/types";
|
import { EIssuesStoreType } from "@plane/types";
|
||||||
import type { TContextMenuItem } from "@plane/ui";
|
|
||||||
import { ContextMenu, CustomMenu } from "@plane/ui";
|
import { ContextMenu, CustomMenu } from "@plane/ui";
|
||||||
import { cn } from "@plane/utils";
|
import { cn } from "@plane/utils";
|
||||||
// hooks
|
// hooks
|
||||||
import { captureClick } from "@/helpers/event-tracker.helper";
|
|
||||||
import { useIssues } from "@/hooks/store/use-issues";
|
import { useIssues } from "@/hooks/store/use-issues";
|
||||||
import { useProject } from "@/hooks/store/use-project";
|
import { useProject } from "@/hooks/store/use-project";
|
||||||
import { useProjectState } from "@/hooks/store/use-project-state";
|
import { useProjectState } from "@/hooks/store/use-project-state";
|
||||||
|
|
@ -108,7 +101,6 @@ export const ProjectIssueQuickActions = observer(function ProjectIssueQuickActio
|
||||||
...item,
|
...item,
|
||||||
|
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
captureClick({ elementName: WORK_ITEM_TRACKER_ELEMENTS.QUICK_ACTIONS.PROJECT_VIEW });
|
|
||||||
item.action();
|
item.action();
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
@ -197,7 +189,6 @@ export const ProjectIssueQuickActions = observer(function ProjectIssueQuickActio
|
||||||
<CustomMenu.MenuItem
|
<CustomMenu.MenuItem
|
||||||
key={nestedItem.key}
|
key={nestedItem.key}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
captureClick({ elementName: WORK_ITEM_TRACKER_ELEMENTS.QUICK_ACTIONS.PROJECT_VIEW });
|
|
||||||
nestedItem.action();
|
nestedItem.action();
|
||||||
}}
|
}}
|
||||||
className={cn(
|
className={cn(
|
||||||
|
|
@ -233,7 +224,6 @@ export const ProjectIssueQuickActions = observer(function ProjectIssueQuickActio
|
||||||
<CustomMenu.MenuItem
|
<CustomMenu.MenuItem
|
||||||
key={item.key}
|
key={item.key}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
captureClick({ elementName: WORK_ITEM_TRACKER_ELEMENTS.QUICK_ACTIONS.PROJECT_VIEW });
|
|
||||||
item.action();
|
item.action();
|
||||||
}}
|
}}
|
||||||
className={cn(
|
className={cn(
|
||||||
|
|
|
||||||
|
|
@ -4,16 +4,12 @@ import { observer } from "mobx-react";
|
||||||
import { useParams } from "next/navigation";
|
import { useParams } from "next/navigation";
|
||||||
import type { UseFormRegister } from "react-hook-form";
|
import type { UseFormRegister } from "react-hook-form";
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
|
|
||||||
// plane imports
|
// plane imports
|
||||||
import { WORK_ITEM_TRACKER_EVENTS } from "@plane/constants";
|
|
||||||
import { useTranslation } from "@plane/i18n";
|
import { useTranslation } from "@plane/i18n";
|
||||||
import { PlusIcon } from "@plane/propel/icons";
|
import { PlusIcon } from "@plane/propel/icons";
|
||||||
import { setPromiseToast } from "@plane/propel/toast";
|
import { setPromiseToast } from "@plane/propel/toast";
|
||||||
import type { IProject, TIssue, EIssueLayoutTypes } from "@plane/types";
|
import type { IProject, TIssue, EIssueLayoutTypes } from "@plane/types";
|
||||||
import { cn, createIssuePayload } from "@plane/utils";
|
import { cn, createIssuePayload } from "@plane/utils";
|
||||||
// helpers
|
|
||||||
import { captureError, captureSuccess } from "@/helpers/event-tracker.helper";
|
|
||||||
// plane web imports
|
// plane web imports
|
||||||
import { QuickAddIssueFormRoot } from "@/plane-web/components/issues/quick-add";
|
import { QuickAddIssueFormRoot } from "@/plane-web/components/issues/quick-add";
|
||||||
// local imports
|
// local imports
|
||||||
|
|
@ -128,20 +124,7 @@ export const QuickAddIssueRoot = observer(function QuickAddIssueRoot(props: TQui
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
await quickAddPromise
|
await quickAddPromise;
|
||||||
.then((res) => {
|
|
||||||
captureSuccess({
|
|
||||||
eventName: WORK_ITEM_TRACKER_EVENTS.create,
|
|
||||||
payload: { id: res?.id },
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
captureError({
|
|
||||||
eventName: WORK_ITEM_TRACKER_EVENTS.create,
|
|
||||||
payload: { id: payload.id },
|
|
||||||
error: error as Error,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,11 @@
|
||||||
import React, { useCallback } from "react";
|
import { useCallback } from "react";
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
import { useParams } from "next/navigation";
|
import { useParams } from "next/navigation";
|
||||||
// types
|
// types
|
||||||
import { WORK_ITEM_TRACKER_EVENTS } from "@plane/constants";
|
|
||||||
import type { TIssue } from "@plane/types";
|
import type { TIssue } from "@plane/types";
|
||||||
// components
|
// components
|
||||||
import { CycleDropdown } from "@/components/dropdowns/cycle";
|
import { CycleDropdown } from "@/components/dropdowns/cycle";
|
||||||
// hooks
|
// hooks
|
||||||
import { captureSuccess } from "@/helpers/event-tracker.helper";
|
|
||||||
import { useIssuesStore } from "@/hooks/use-issue-layout-store";
|
import { useIssuesStore } from "@/hooks/use-issue-layout-store";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
|
@ -30,12 +28,6 @@ export const SpreadsheetCycleColumn = observer(function SpreadsheetCycleColumn(p
|
||||||
if (!workspaceSlug || !issue || !issue.project_id || issue.cycle_id === cycleId) return;
|
if (!workspaceSlug || !issue || !issue.project_id || issue.cycle_id === cycleId) return;
|
||||||
if (cycleId) await addCycleToIssue(workspaceSlug.toString(), issue.project_id, cycleId, issue.id);
|
if (cycleId) await addCycleToIssue(workspaceSlug.toString(), issue.project_id, cycleId, issue.id);
|
||||||
else await removeCycleFromIssue(workspaceSlug.toString(), issue.project_id, issue.id);
|
else await removeCycleFromIssue(workspaceSlug.toString(), issue.project_id, issue.id);
|
||||||
captureSuccess({
|
|
||||||
eventName: WORK_ITEM_TRACKER_EVENTS.update,
|
|
||||||
payload: {
|
|
||||||
id: issue.id,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
[workspaceSlug, issue, addCycleToIssue, removeCycleFromIssue]
|
[workspaceSlug, issue, addCycleToIssue, removeCycleFromIssue]
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,12 @@
|
||||||
import React, { useCallback } from "react";
|
import { useCallback } from "react";
|
||||||
import { xor } from "lodash-es";
|
import { xor } from "lodash-es";
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
import { useParams } from "next/navigation";
|
import { useParams } from "next/navigation";
|
||||||
// types
|
// types
|
||||||
import { WORK_ITEM_TRACKER_EVENTS } from "@plane/constants";
|
|
||||||
import type { TIssue } from "@plane/types";
|
import type { TIssue } from "@plane/types";
|
||||||
// components
|
// components
|
||||||
import { ModuleDropdown } from "@/components/dropdowns/module/dropdown";
|
import { ModuleDropdown } from "@/components/dropdowns/module/dropdown";
|
||||||
// constants
|
|
||||||
// hooks
|
// hooks
|
||||||
import { captureSuccess } from "@/helpers/event-tracker.helper";
|
|
||||||
import { useIssuesStore } from "@/hooks/use-issue-layout-store";
|
import { useIssuesStore } from "@/hooks/use-issue-layout-store";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
|
@ -39,13 +36,6 @@ export const SpreadsheetModuleColumn = observer(function SpreadsheetModuleColumn
|
||||||
else modulesToAdd.push(moduleId);
|
else modulesToAdd.push(moduleId);
|
||||||
}
|
}
|
||||||
changeModulesInIssue(workspaceSlug.toString(), issue.project_id, issue.id, modulesToAdd, modulesToRemove);
|
changeModulesInIssue(workspaceSlug.toString(), issue.project_id, issue.id, modulesToAdd, modulesToRemove);
|
||||||
|
|
||||||
captureSuccess({
|
|
||||||
eventName: WORK_ITEM_TRACKER_EVENTS.update,
|
|
||||||
payload: {
|
|
||||||
id: issue.id,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
[workspaceSlug, issue, changeModulesInIssue]
|
[workspaceSlug, issue, changeModulesInIssue]
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,7 @@
|
||||||
import { useRef } from "react";
|
import { useRef } from "react";
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
// types
|
// types
|
||||||
import { WORK_ITEM_TRACKER_EVENTS } from "@plane/constants";
|
|
||||||
import type { IIssueDisplayProperties, TIssue } from "@plane/types";
|
import type { IIssueDisplayProperties, TIssue } from "@plane/types";
|
||||||
// hooks
|
|
||||||
import { captureSuccess } from "@/helpers/event-tracker.helper";
|
|
||||||
// components
|
// components
|
||||||
import { SPREADSHEET_COLUMNS } from "@/plane-web/components/issues/issue-layouts/utils";
|
import { SPREADSHEET_COLUMNS } from "@/plane-web/components/issues/issue-layouts/utils";
|
||||||
import { shouldRenderColumn } from "@/plane-web/helpers/issue-filter.helper";
|
import { shouldRenderColumn } from "@/plane-web/helpers/issue-filter.helper";
|
||||||
|
|
@ -30,6 +27,10 @@ export const IssueColumn = observer(function IssueColumn(props: Props) {
|
||||||
|
|
||||||
if (!Column) return null;
|
if (!Column) return null;
|
||||||
|
|
||||||
|
const handleUpdateIssue = async (issue: TIssue, data: Partial<TIssue>) => {
|
||||||
|
if (updateIssue) await updateIssue(issue.project_id, issue.id, data);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<WithDisplayPropertiesHOC
|
<WithDisplayPropertiesHOC
|
||||||
displayProperties={displayProperties}
|
displayProperties={displayProperties}
|
||||||
|
|
@ -43,17 +44,7 @@ export const IssueColumn = observer(function IssueColumn(props: Props) {
|
||||||
>
|
>
|
||||||
<Column
|
<Column
|
||||||
issue={issueDetail}
|
issue={issueDetail}
|
||||||
onChange={(issue: TIssue, data: Partial<TIssue>) =>
|
onChange={handleUpdateIssue}
|
||||||
updateIssue &&
|
|
||||||
updateIssue(issue.project_id, issue.id, data).then(() => {
|
|
||||||
captureSuccess({
|
|
||||||
eventName: WORK_ITEM_TRACKER_EVENTS.update,
|
|
||||||
payload: {
|
|
||||||
id: issue.id,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
})
|
|
||||||
}
|
|
||||||
disabled={disableUserActions}
|
disabled={disableUserActions}
|
||||||
onClose={() => tableCellRef?.current?.focus()}
|
onClose={() => tableCellRef?.current?.focus()}
|
||||||
/>
|
/>
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
import React, { useEffect, useRef, useState } from "react";
|
import { useEffect, useRef, useState } from "react";
|
||||||
import { xor } from "lodash-es";
|
import { xor } from "lodash-es";
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
import { useParams } from "next/navigation";
|
import { useParams } from "next/navigation";
|
||||||
import { WORK_ITEM_TRACKER_EVENTS } from "@plane/constants";
|
|
||||||
// Plane imports
|
// Plane imports
|
||||||
import { useTranslation } from "@plane/i18n";
|
import { useTranslation } from "@plane/i18n";
|
||||||
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
||||||
|
|
@ -10,7 +9,6 @@ import type { TBaseIssue, TIssue } from "@plane/types";
|
||||||
import { EIssuesStoreType } from "@plane/types";
|
import { EIssuesStoreType } from "@plane/types";
|
||||||
import { EModalPosition, EModalWidth, ModalCore } from "@plane/ui";
|
import { EModalPosition, EModalWidth, ModalCore } from "@plane/ui";
|
||||||
// hooks
|
// hooks
|
||||||
import { captureError, captureSuccess } from "@/helpers/event-tracker.helper";
|
|
||||||
import { useIssueModal } from "@/hooks/context/use-issue-modal";
|
import { useIssueModal } from "@/hooks/context/use-issue-modal";
|
||||||
import { useCycle } from "@/hooks/store/use-cycle";
|
import { useCycle } from "@/hooks/store/use-cycle";
|
||||||
import { useIssueDetail } from "@/hooks/store/use-issue-detail";
|
import { useIssueDetail } from "@/hooks/store/use-issue-detail";
|
||||||
|
|
@ -241,10 +239,6 @@ export const CreateUpdateIssueModalBase = observer(function CreateUpdateIssueMod
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
});
|
});
|
||||||
captureSuccess({
|
|
||||||
eventName: WORK_ITEM_TRACKER_EVENTS.create,
|
|
||||||
payload: { id: response.id },
|
|
||||||
});
|
|
||||||
if (!createMore) handleClose();
|
if (!createMore) handleClose();
|
||||||
if (createMore && issueTitleRef) issueTitleRef?.current?.focus();
|
if (createMore && issueTitleRef) issueTitleRef?.current?.focus();
|
||||||
setDescription("<p></p>");
|
setDescription("<p></p>");
|
||||||
|
|
@ -256,11 +250,6 @@ export const CreateUpdateIssueModalBase = observer(function CreateUpdateIssueMod
|
||||||
title: t("error"),
|
title: t("error"),
|
||||||
message: error?.error ?? t(is_draft_issue ? "draft_creation_failed" : "issue_creation_failed"),
|
message: error?.error ?? t(is_draft_issue ? "draft_creation_failed" : "issue_creation_failed"),
|
||||||
});
|
});
|
||||||
captureError({
|
|
||||||
eventName: WORK_ITEM_TRACKER_EVENTS.create,
|
|
||||||
payload: { id: payload.id },
|
|
||||||
error: error as Error,
|
|
||||||
});
|
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -328,10 +317,6 @@ export const CreateUpdateIssueModalBase = observer(function CreateUpdateIssueMod
|
||||||
/>
|
/>
|
||||||
) : undefined,
|
) : undefined,
|
||||||
});
|
});
|
||||||
captureSuccess({
|
|
||||||
eventName: WORK_ITEM_TRACKER_EVENTS.update,
|
|
||||||
payload: { id: data.id },
|
|
||||||
});
|
|
||||||
handleClose();
|
handleClose();
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
|
|
@ -340,11 +325,6 @@ export const CreateUpdateIssueModalBase = observer(function CreateUpdateIssueMod
|
||||||
title: t("error"),
|
title: t("error"),
|
||||||
message: error?.error ?? t("issue_could_not_be_updated"),
|
message: error?.error ?? t("issue_could_not_be_updated"),
|
||||||
});
|
});
|
||||||
captureError({
|
|
||||||
eventName: WORK_ITEM_TRACKER_EVENTS.update,
|
|
||||||
payload: { id: data.id },
|
|
||||||
error: error as Error,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,12 @@
|
||||||
import React, { useState } from "react";
|
import { useState } from "react";
|
||||||
import { isEmpty } from "lodash-es";
|
import { isEmpty } from "lodash-es";
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
import { useParams } from "next/navigation";
|
import { useParams } from "next/navigation";
|
||||||
import { WORK_ITEM_TRACKER_EVENTS } from "@plane/constants";
|
// Plane imports
|
||||||
import { useTranslation } from "@plane/i18n";
|
import { useTranslation } from "@plane/i18n";
|
||||||
// types
|
|
||||||
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
||||||
import type { TIssue } from "@plane/types";
|
import type { TIssue } from "@plane/types";
|
||||||
// ui
|
|
||||||
// components
|
|
||||||
import { isEmptyHtmlString } from "@plane/utils";
|
import { isEmptyHtmlString } from "@plane/utils";
|
||||||
// helpers
|
|
||||||
import { captureError, captureSuccess } from "@/helpers/event-tracker.helper";
|
|
||||||
// hooks
|
// hooks
|
||||||
import { useIssueModal } from "@/hooks/context/use-issue-modal";
|
import { useIssueModal } from "@/hooks/context/use-issue-modal";
|
||||||
import { useWorkspaceDraftIssues } from "@/hooks/store/workspace-draft";
|
import { useWorkspaceDraftIssues } from "@/hooks/store/workspace-draft";
|
||||||
|
|
@ -90,26 +85,17 @@ export const DraftIssueLayout = observer(function DraftIssueLayout(props: DraftI
|
||||||
title: `${t("success")}!`,
|
title: `${t("success")}!`,
|
||||||
message: t("workspace_draft_issues.toasts.created.success"),
|
message: t("workspace_draft_issues.toasts.created.success"),
|
||||||
});
|
});
|
||||||
captureSuccess({
|
|
||||||
eventName: WORK_ITEM_TRACKER_EVENTS.draft.create,
|
|
||||||
payload: { id: res?.id },
|
|
||||||
});
|
|
||||||
onChange(null);
|
onChange(null);
|
||||||
setIssueDiscardModal(false);
|
setIssueDiscardModal(false);
|
||||||
onClose();
|
onClose();
|
||||||
return res;
|
return res;
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((_error) => {
|
||||||
setToast({
|
setToast({
|
||||||
type: TOAST_TYPE.ERROR,
|
type: TOAST_TYPE.ERROR,
|
||||||
title: `${t("error")}!`,
|
title: `${t("error")}!`,
|
||||||
message: t("workspace_draft_issues.toasts.created.error"),
|
message: t("workspace_draft_issues.toasts.created.error"),
|
||||||
});
|
});
|
||||||
captureError({
|
|
||||||
eventName: WORK_ITEM_TRACKER_EVENTS.draft.create,
|
|
||||||
payload: { id: payload.id },
|
|
||||||
error,
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (response && handleCreateUpdatePropertyValues) {
|
if (response && handleCreateUpdatePropertyValues) {
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,8 @@
|
||||||
import type { FC } from "react";
|
|
||||||
import { useRef } from "react";
|
import { useRef } from "react";
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { MoveDiagonal, MoveRight } from "lucide-react";
|
import { MoveDiagonal, MoveRight } from "lucide-react";
|
||||||
// plane imports
|
// plane imports
|
||||||
import { WORK_ITEM_TRACKER_EVENTS } from "@plane/constants";
|
|
||||||
import { useTranslation } from "@plane/i18n";
|
import { useTranslation } from "@plane/i18n";
|
||||||
import { CenterPanelIcon, CopyLinkIcon, FullScreenPanelIcon, SidePanelIcon } from "@plane/propel/icons";
|
import { CenterPanelIcon, CopyLinkIcon, FullScreenPanelIcon, SidePanelIcon } from "@plane/propel/icons";
|
||||||
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
||||||
|
|
@ -13,13 +11,11 @@ import type { TNameDescriptionLoader } from "@plane/types";
|
||||||
import { EIssuesStoreType } from "@plane/types";
|
import { EIssuesStoreType } from "@plane/types";
|
||||||
import { CustomSelect } from "@plane/ui";
|
import { CustomSelect } from "@plane/ui";
|
||||||
import { copyUrlToClipboard, generateWorkItemLink } from "@plane/utils";
|
import { copyUrlToClipboard, generateWorkItemLink } from "@plane/utils";
|
||||||
// helpers
|
// hooks
|
||||||
import { captureError, captureSuccess } from "@/helpers/event-tracker.helper";
|
|
||||||
import { useIssueDetail } from "@/hooks/store/use-issue-detail";
|
import { useIssueDetail } from "@/hooks/store/use-issue-detail";
|
||||||
import { useIssues } from "@/hooks/store/use-issues";
|
import { useIssues } from "@/hooks/store/use-issues";
|
||||||
import { useProject } from "@/hooks/store/use-project";
|
import { useProject } from "@/hooks/store/use-project";
|
||||||
import { useUser } from "@/hooks/store/user";
|
import { useUser } from "@/hooks/store/user";
|
||||||
// hooks
|
|
||||||
import { usePlatformOS } from "@/hooks/use-platform-os";
|
import { usePlatformOS } from "@/hooks/use-platform-os";
|
||||||
// local imports
|
// local imports
|
||||||
import { IssueSubscription } from "../issue-detail/subscription";
|
import { IssueSubscription } from "../issue-detail/subscription";
|
||||||
|
|
@ -132,42 +128,21 @@ export const IssuePeekOverviewHeader = observer(function IssuePeekOverviewHeader
|
||||||
|
|
||||||
return deleteIssue(workspaceSlug, projectId, issueId).then(() => {
|
return deleteIssue(workspaceSlug, projectId, issueId).then(() => {
|
||||||
setPeekIssue(undefined);
|
setPeekIssue(undefined);
|
||||||
captureSuccess({
|
|
||||||
eventName: WORK_ITEM_TRACKER_EVENTS.delete,
|
|
||||||
payload: { id: issueId },
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (_error) {
|
||||||
setToast({
|
setToast({
|
||||||
title: t("toast.error"),
|
title: t("toast.error"),
|
||||||
type: TOAST_TYPE.ERROR,
|
type: TOAST_TYPE.ERROR,
|
||||||
message: t("entity.delete.failed", { entity: t("issue.label", { count: 1 }) }),
|
message: t("entity.delete.failed", { entity: t("issue.label", { count: 1 }) }),
|
||||||
});
|
});
|
||||||
captureError({
|
|
||||||
eventName: WORK_ITEM_TRACKER_EVENTS.delete,
|
|
||||||
payload: { id: issueId },
|
|
||||||
error: error as Error,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleArchiveIssue = async () => {
|
const handleArchiveIssue = async () => {
|
||||||
try {
|
await archiveIssue(workspaceSlug, projectId, issueId);
|
||||||
await archiveIssue(workspaceSlug, projectId, issueId);
|
// check and remove if issue is peeked
|
||||||
// check and remove if issue is peeked
|
if (getIsIssuePeeked(issueId)) {
|
||||||
if (getIsIssuePeeked(issueId)) {
|
removeRoutePeekId();
|
||||||
removeRoutePeekId();
|
|
||||||
}
|
|
||||||
captureSuccess({
|
|
||||||
eventName: WORK_ITEM_TRACKER_EVENTS.archive,
|
|
||||||
payload: { id: issueId },
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
captureError({
|
|
||||||
eventName: WORK_ITEM_TRACKER_EVENTS.archive,
|
|
||||||
payload: { id: issueId },
|
|
||||||
error: error as Error,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,14 @@
|
||||||
import type { FC } from "react";
|
|
||||||
import { useState, useMemo, useCallback } from "react";
|
import { useState, useMemo, useCallback } from "react";
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
import { usePathname } from "next/navigation";
|
import { usePathname } from "next/navigation";
|
||||||
// Plane imports
|
// Plane imports
|
||||||
import useSWR from "swr";
|
import useSWR from "swr";
|
||||||
import { EUserPermissions, EUserPermissionsLevel, WORK_ITEM_TRACKER_EVENTS } from "@plane/constants";
|
import { EUserPermissions, EUserPermissionsLevel } from "@plane/constants";
|
||||||
import { useTranslation } from "@plane/i18n";
|
import { useTranslation } from "@plane/i18n";
|
||||||
import { TOAST_TYPE, setPromiseToast, setToast } from "@plane/propel/toast";
|
import { TOAST_TYPE, setPromiseToast, setToast } from "@plane/propel/toast";
|
||||||
import type { IWorkItemPeekOverview, TIssue } from "@plane/types";
|
import type { IWorkItemPeekOverview, TIssue } from "@plane/types";
|
||||||
import { EIssueServiceType, EIssuesStoreType } from "@plane/types";
|
import { EIssueServiceType, EIssuesStoreType } from "@plane/types";
|
||||||
// hooks
|
// hooks
|
||||||
import { captureError, captureSuccess } from "@/helpers/event-tracker.helper";
|
|
||||||
import { useIssueDetail } from "@/hooks/store/use-issue-detail";
|
import { useIssueDetail } from "@/hooks/store/use-issue-detail";
|
||||||
import { useIssues } from "@/hooks/store/use-issues";
|
import { useIssues } from "@/hooks/store/use-issues";
|
||||||
import { useUserPermissions } from "@/hooks/store/user";
|
import { useUserPermissions } from "@/hooks/store/user";
|
||||||
|
|
@ -77,18 +75,9 @@ export const IssuePeekOverview = observer(function IssuePeekOverview(props: IWor
|
||||||
.updateIssue(workspaceSlug, projectId, issueId, data)
|
.updateIssue(workspaceSlug, projectId, issueId, data)
|
||||||
.then(async () => {
|
.then(async () => {
|
||||||
fetchActivities(workspaceSlug, projectId, issueId);
|
fetchActivities(workspaceSlug, projectId, issueId);
|
||||||
captureSuccess({
|
|
||||||
eventName: WORK_ITEM_TRACKER_EVENTS.update,
|
|
||||||
payload: { id: issueId },
|
|
||||||
});
|
|
||||||
return;
|
return;
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
captureError({
|
|
||||||
eventName: WORK_ITEM_TRACKER_EVENTS.update,
|
|
||||||
payload: { id: issueId },
|
|
||||||
error: error as Error,
|
|
||||||
});
|
|
||||||
setToast({
|
setToast({
|
||||||
title: t("toast.error"),
|
title: t("toast.error"),
|
||||||
type: TOAST_TYPE.ERROR,
|
type: TOAST_TYPE.ERROR,
|
||||||
|
|
@ -100,40 +89,23 @@ export const IssuePeekOverview = observer(function IssuePeekOverview(props: IWor
|
||||||
remove: async (workspaceSlug: string, projectId: string, issueId: string) => {
|
remove: async (workspaceSlug: string, projectId: string, issueId: string) => {
|
||||||
try {
|
try {
|
||||||
return issues?.removeIssue(workspaceSlug, projectId, issueId).then(() => {
|
return issues?.removeIssue(workspaceSlug, projectId, issueId).then(() => {
|
||||||
captureSuccess({
|
|
||||||
eventName: WORK_ITEM_TRACKER_EVENTS.delete,
|
|
||||||
payload: { id: issueId },
|
|
||||||
});
|
|
||||||
removeRoutePeekId();
|
removeRoutePeekId();
|
||||||
return;
|
return;
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (_error) {
|
||||||
setToast({
|
setToast({
|
||||||
title: t("toast.error"),
|
title: t("toast.error"),
|
||||||
type: TOAST_TYPE.ERROR,
|
type: TOAST_TYPE.ERROR,
|
||||||
message: t("entity.delete.failed", { entity: t("issue.label", { count: 1 }) }),
|
message: t("entity.delete.failed", { entity: t("issue.label", { count: 1 }) }),
|
||||||
});
|
});
|
||||||
captureError({
|
|
||||||
eventName: WORK_ITEM_TRACKER_EVENTS.delete,
|
|
||||||
payload: { id: issueId },
|
|
||||||
error: error as Error,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
archive: async (workspaceSlug: string, projectId: string, issueId: string) => {
|
archive: async (workspaceSlug: string, projectId: string, issueId: string) => {
|
||||||
try {
|
try {
|
||||||
if (!issues?.archiveIssue) return;
|
if (!issues?.archiveIssue) return;
|
||||||
await issues.archiveIssue(workspaceSlug, projectId, issueId);
|
await issues.archiveIssue(workspaceSlug, projectId, issueId);
|
||||||
captureSuccess({
|
|
||||||
eventName: WORK_ITEM_TRACKER_EVENTS.archive,
|
|
||||||
payload: { id: issueId },
|
|
||||||
});
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
captureError({
|
console.error("Error archiving the issue", error);
|
||||||
eventName: WORK_ITEM_TRACKER_EVENTS.archive,
|
|
||||||
payload: { id: issueId },
|
|
||||||
error: error as Error,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
restore: async (workspaceSlug: string, projectId: string, issueId: string) => {
|
restore: async (workspaceSlug: string, projectId: string, issueId: string) => {
|
||||||
|
|
@ -144,62 +116,35 @@ export const IssuePeekOverview = observer(function IssuePeekOverview(props: IWor
|
||||||
title: t("issue.restore.success.title"),
|
title: t("issue.restore.success.title"),
|
||||||
message: t("issue.restore.success.message"),
|
message: t("issue.restore.success.message"),
|
||||||
});
|
});
|
||||||
captureSuccess({
|
} catch (_error) {
|
||||||
eventName: WORK_ITEM_TRACKER_EVENTS.restore,
|
|
||||||
payload: { id: issueId },
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
setToast({
|
setToast({
|
||||||
type: TOAST_TYPE.ERROR,
|
type: TOAST_TYPE.ERROR,
|
||||||
title: t("toast.error"),
|
title: t("toast.error"),
|
||||||
message: t("issue.restore.failed.message"),
|
message: t("issue.restore.failed.message"),
|
||||||
});
|
});
|
||||||
captureError({
|
|
||||||
eventName: WORK_ITEM_TRACKER_EVENTS.restore,
|
|
||||||
payload: { id: issueId },
|
|
||||||
error: error as Error,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
addCycleToIssue: async (workspaceSlug: string, projectId: string, cycleId: string, issueId: string) => {
|
addCycleToIssue: async (workspaceSlug: string, projectId: string, cycleId: string, issueId: string) => {
|
||||||
try {
|
try {
|
||||||
await issues.addCycleToIssue(workspaceSlug, projectId, cycleId, issueId);
|
await issues.addCycleToIssue(workspaceSlug, projectId, cycleId, issueId);
|
||||||
fetchActivities(workspaceSlug, projectId, issueId);
|
fetchActivities(workspaceSlug, projectId, issueId);
|
||||||
captureSuccess({
|
} catch (_error) {
|
||||||
eventName: WORK_ITEM_TRACKER_EVENTS.update,
|
|
||||||
payload: { id: issueId },
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
setToast({
|
setToast({
|
||||||
type: TOAST_TYPE.ERROR,
|
type: TOAST_TYPE.ERROR,
|
||||||
title: t("toast.error"),
|
title: t("toast.error"),
|
||||||
message: t("issue.add.cycle.failed"),
|
message: t("issue.add.cycle.failed"),
|
||||||
});
|
});
|
||||||
captureError({
|
|
||||||
eventName: WORK_ITEM_TRACKER_EVENTS.update,
|
|
||||||
payload: { id: issueId },
|
|
||||||
error: error as Error,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
addIssueToCycle: async (workspaceSlug: string, projectId: string, cycleId: string, issueIds: string[]) => {
|
addIssueToCycle: async (workspaceSlug: string, projectId: string, cycleId: string, issueIds: string[]) => {
|
||||||
try {
|
try {
|
||||||
await issues.addIssueToCycle(workspaceSlug, projectId, cycleId, issueIds);
|
await issues.addIssueToCycle(workspaceSlug, projectId, cycleId, issueIds);
|
||||||
captureSuccess({
|
} catch (_error) {
|
||||||
eventName: WORK_ITEM_TRACKER_EVENTS.update,
|
|
||||||
payload: { id: issueIds },
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
setToast({
|
setToast({
|
||||||
type: TOAST_TYPE.ERROR,
|
type: TOAST_TYPE.ERROR,
|
||||||
title: t("toast.error"),
|
title: t("toast.error"),
|
||||||
message: t("issue.add.cycle.failed"),
|
message: t("issue.add.cycle.failed"),
|
||||||
});
|
});
|
||||||
captureError({
|
|
||||||
eventName: WORK_ITEM_TRACKER_EVENTS.update,
|
|
||||||
payload: { id: issueIds },
|
|
||||||
error: error as Error,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
removeIssueFromCycle: async (workspaceSlug: string, projectId: string, cycleId: string, issueId: string) => {
|
removeIssueFromCycle: async (workspaceSlug: string, projectId: string, cycleId: string, issueId: string) => {
|
||||||
|
|
@ -218,16 +163,8 @@ export const IssuePeekOverview = observer(function IssuePeekOverview(props: IWor
|
||||||
});
|
});
|
||||||
await removeFromCyclePromise;
|
await removeFromCyclePromise;
|
||||||
fetchActivities(workspaceSlug, projectId, issueId);
|
fetchActivities(workspaceSlug, projectId, issueId);
|
||||||
captureSuccess({
|
|
||||||
eventName: WORK_ITEM_TRACKER_EVENTS.update,
|
|
||||||
payload: { id: issueId },
|
|
||||||
});
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
captureError({
|
console.error("Error removing issue from cycle", error);
|
||||||
eventName: WORK_ITEM_TRACKER_EVENTS.update,
|
|
||||||
payload: { id: issueId },
|
|
||||||
error: error as Error,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
changeModulesInIssue: async (
|
changeModulesInIssue: async (
|
||||||
|
|
@ -245,10 +182,6 @@ export const IssuePeekOverview = observer(function IssuePeekOverview(props: IWor
|
||||||
removeModuleIds
|
removeModuleIds
|
||||||
);
|
);
|
||||||
fetchActivities(workspaceSlug, projectId, issueId);
|
fetchActivities(workspaceSlug, projectId, issueId);
|
||||||
captureSuccess({
|
|
||||||
eventName: WORK_ITEM_TRACKER_EVENTS.update,
|
|
||||||
payload: { id: issueId },
|
|
||||||
});
|
|
||||||
return promise;
|
return promise;
|
||||||
},
|
},
|
||||||
removeIssueFromModule: async (workspaceSlug: string, projectId: string, moduleId: string, issueId: string) => {
|
removeIssueFromModule: async (workspaceSlug: string, projectId: string, moduleId: string, issueId: string) => {
|
||||||
|
|
@ -267,16 +200,8 @@ export const IssuePeekOverview = observer(function IssuePeekOverview(props: IWor
|
||||||
});
|
});
|
||||||
await removeFromModulePromise;
|
await removeFromModulePromise;
|
||||||
fetchActivities(workspaceSlug, projectId, issueId);
|
fetchActivities(workspaceSlug, projectId, issueId);
|
||||||
captureSuccess({
|
|
||||||
eventName: WORK_ITEM_TRACKER_EVENTS.update,
|
|
||||||
payload: { id: issueId },
|
|
||||||
});
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
captureError({
|
console.error("Error removing issue from module", error);
|
||||||
eventName: WORK_ITEM_TRACKER_EVENTS.update,
|
|
||||||
payload: { id: issueId },
|
|
||||||
error: error as Error,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,13 @@
|
||||||
import type { FC } from "react";
|
|
||||||
import { Fragment } from "react";
|
import { Fragment } from "react";
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
import useSWR from "swr";
|
import useSWR from "swr";
|
||||||
// plane imports
|
// plane imports
|
||||||
import { EUserPermissionsLevel, EDraftIssuePaginationType, PROJECT_TRACKER_ELEMENTS } from "@plane/constants";
|
import { EUserPermissionsLevel, EDraftIssuePaginationType } from "@plane/constants";
|
||||||
import { useTranslation } from "@plane/i18n";
|
import { useTranslation } from "@plane/i18n";
|
||||||
import { EmptyStateDetailed } from "@plane/propel/empty-state";
|
import { EmptyStateDetailed } from "@plane/propel/empty-state";
|
||||||
import { EUserWorkspaceRoles } from "@plane/types";
|
import { EUserWorkspaceRoles } from "@plane/types";
|
||||||
// components
|
// components
|
||||||
import { cn } from "@plane/utils";
|
import { cn } from "@plane/utils";
|
||||||
import { captureClick } from "@/helpers/event-tracker.helper";
|
|
||||||
// hooks
|
// hooks
|
||||||
import { useCommandPalette } from "@/hooks/store/use-command-palette";
|
import { useCommandPalette } from "@/hooks/store/use-command-palette";
|
||||||
import { useProject } from "@/hooks/store/use-project";
|
import { useProject } from "@/hooks/store/use-project";
|
||||||
|
|
@ -72,7 +70,6 @@ export const WorkspaceDraftIssuesRoot = observer(function WorkspaceDraftIssuesRo
|
||||||
label: t("workspace_projects.empty_state.no_projects.primary_button.text"),
|
label: t("workspace_projects.empty_state.no_projects.primary_button.text"),
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
toggleCreateProjectModal(true);
|
toggleCreateProjectModal(true);
|
||||||
captureClick({ elementName: PROJECT_TRACKER_ELEMENTS.EMPTY_STATE_CREATE_PROJECT_BUTTON });
|
|
||||||
},
|
},
|
||||||
disabled: !hasMemberLevelPermission,
|
disabled: !hasMemberLevelPermission,
|
||||||
variant: "primary",
|
variant: "primary",
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,6 @@ import { Button } from "@plane/propel/button";
|
||||||
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
||||||
import type { IIssueLabel } from "@plane/types";
|
import type { IIssueLabel } from "@plane/types";
|
||||||
import { Input } from "@plane/ui";
|
import { Input } from "@plane/ui";
|
||||||
import { captureError, captureSuccess } from "@/helpers/event-tracker.helper";
|
|
||||||
|
|
||||||
// error codes
|
// error codes
|
||||||
const errorCodes = {
|
const errorCodes = {
|
||||||
|
|
@ -87,25 +86,10 @@ export const CreateUpdateLabelInline = observer(
|
||||||
await labelOperationsCallbacks
|
await labelOperationsCallbacks
|
||||||
.createLabel(formData)
|
.createLabel(formData)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
captureSuccess({
|
|
||||||
eventName: PROJECT_SETTINGS_TRACKER_EVENTS.label_created,
|
|
||||||
payload: {
|
|
||||||
name: res.name,
|
|
||||||
id: res.id,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
handleClose();
|
handleClose();
|
||||||
reset(defaultValues);
|
reset(defaultValues);
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
captureError({
|
|
||||||
eventName: PROJECT_SETTINGS_TRACKER_EVENTS.label_created,
|
|
||||||
payload: {
|
|
||||||
name: formData.name,
|
|
||||||
},
|
|
||||||
error,
|
|
||||||
});
|
|
||||||
|
|
||||||
const errorMessage = getErrorMessage(error, "create");
|
const errorMessage = getErrorMessage(error, "create");
|
||||||
setToast({
|
setToast({
|
||||||
title: "Error!",
|
title: "Error!",
|
||||||
|
|
@ -122,25 +106,10 @@ export const CreateUpdateLabelInline = observer(
|
||||||
await labelOperationsCallbacks
|
await labelOperationsCallbacks
|
||||||
.updateLabel(labelToUpdate.id, formData)
|
.updateLabel(labelToUpdate.id, formData)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
captureSuccess({
|
|
||||||
eventName: PROJECT_SETTINGS_TRACKER_EVENTS.label_updated,
|
|
||||||
payload: {
|
|
||||||
name: res.name,
|
|
||||||
id: res.id,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
reset(defaultValues);
|
reset(defaultValues);
|
||||||
handleClose();
|
handleClose();
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
captureError({
|
|
||||||
eventName: PROJECT_SETTINGS_TRACKER_EVENTS.label_updated,
|
|
||||||
payload: {
|
|
||||||
name: formData.name,
|
|
||||||
id: labelToUpdate.id,
|
|
||||||
},
|
|
||||||
error,
|
|
||||||
});
|
|
||||||
const errorMessage = getErrorMessage(error, "update");
|
const errorMessage = getErrorMessage(error, "update");
|
||||||
setToast({
|
setToast({
|
||||||
title: "Oops!",
|
title: "Oops!",
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,12 @@
|
||||||
import React, { useState } from "react";
|
import { useState } from "react";
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
import { useParams } from "next/navigation";
|
import { useParams } from "next/navigation";
|
||||||
// types
|
// types
|
||||||
import { PROJECT_SETTINGS_TRACKER_EVENTS } from "@plane/constants";
|
|
||||||
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
||||||
import type { IIssueLabel } from "@plane/types";
|
import type { IIssueLabel } from "@plane/types";
|
||||||
// ui
|
// ui
|
||||||
import { AlertModalCore } from "@plane/ui";
|
import { AlertModalCore } from "@plane/ui";
|
||||||
// hooks
|
// hooks
|
||||||
import { captureError, captureSuccess } from "@/helpers/event-tracker.helper";
|
|
||||||
import { useLabel } from "@/hooks/store/use-label";
|
import { useLabel } from "@/hooks/store/use-label";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
|
@ -38,27 +36,10 @@ export const DeleteLabelModal = observer(function DeleteLabelModal(props: Props)
|
||||||
|
|
||||||
await deleteLabel(workspaceSlug.toString(), projectId.toString(), data.id)
|
await deleteLabel(workspaceSlug.toString(), projectId.toString(), data.id)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
captureSuccess({
|
|
||||||
eventName: PROJECT_SETTINGS_TRACKER_EVENTS.label_deleted,
|
|
||||||
payload: {
|
|
||||||
name: data.name,
|
|
||||||
project_id: projectId,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
handleClose();
|
handleClose();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
setIsDeleteLoading(false);
|
setIsDeleteLoading(false);
|
||||||
|
|
||||||
captureError({
|
|
||||||
eventName: PROJECT_SETTINGS_TRACKER_EVENTS.label_deleted,
|
|
||||||
payload: {
|
|
||||||
name: data.name,
|
|
||||||
project_id: projectId,
|
|
||||||
},
|
|
||||||
error: err,
|
|
||||||
});
|
|
||||||
|
|
||||||
const error = err?.error || "Label could not be deleted. Please try again.";
|
const error = err?.error || "Label could not be deleted. Please try again.";
|
||||||
setToast({
|
setToast({
|
||||||
type: TOAST_TYPE.ERROR,
|
type: TOAST_TYPE.ERROR,
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,11 @@
|
||||||
import type { Dispatch, SetStateAction } from "react";
|
import type { Dispatch, SetStateAction } from "react";
|
||||||
import React, { useState } from "react";
|
import { useState } from "react";
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
|
|
||||||
import { Disclosure, Transition } from "@headlessui/react";
|
import { Disclosure, Transition } from "@headlessui/react";
|
||||||
import { PROJECT_SETTINGS_TRACKER_ELEMENTS } from "@plane/constants";
|
// plane imports
|
||||||
import { EditIcon, TrashIcon, ChevronDownIcon } from "@plane/propel/icons";
|
import { EditIcon, TrashIcon, ChevronDownIcon } from "@plane/propel/icons";
|
||||||
// store
|
|
||||||
// icons
|
|
||||||
// types
|
|
||||||
import type { IIssueLabel } from "@plane/types";
|
import type { IIssueLabel } from "@plane/types";
|
||||||
// components
|
// components
|
||||||
import { captureClick } from "@/helpers/event-tracker.helper";
|
|
||||||
import type { TLabelOperationsCallbacks } from "./create-update-label-inline";
|
import type { TLabelOperationsCallbacks } from "./create-update-label-inline";
|
||||||
import { CreateUpdateLabelInline } from "./create-update-label-inline";
|
import { CreateUpdateLabelInline } from "./create-update-label-inline";
|
||||||
import type { ICustomMenuItem } from "./label-block/label-item-block";
|
import type { ICustomMenuItem } from "./label-block/label-item-block";
|
||||||
|
|
@ -55,9 +50,6 @@ export const ProjectSettingLabelGroup = observer(function ProjectSettingLabelGro
|
||||||
{
|
{
|
||||||
CustomIcon: EditIcon,
|
CustomIcon: EditIcon,
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
captureClick({
|
|
||||||
elementName: PROJECT_SETTINGS_TRACKER_ELEMENTS.LABELS_CONTEXT_MENU,
|
|
||||||
});
|
|
||||||
setEditLabelForm(true);
|
setEditLabelForm(true);
|
||||||
setIsUpdating(true);
|
setIsUpdating(true);
|
||||||
},
|
},
|
||||||
|
|
@ -68,9 +60,6 @@ export const ProjectSettingLabelGroup = observer(function ProjectSettingLabelGro
|
||||||
{
|
{
|
||||||
CustomIcon: TrashIcon,
|
CustomIcon: TrashIcon,
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
captureClick({
|
|
||||||
elementName: PROJECT_SETTINGS_TRACKER_ELEMENTS.LABELS_CONTEXT_MENU,
|
|
||||||
});
|
|
||||||
handleLabelDelete(label);
|
handleLabelDelete(label);
|
||||||
},
|
},
|
||||||
isVisible: true,
|
isVisible: true,
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,10 @@
|
||||||
import type { Dispatch, SetStateAction } from "react";
|
import type { Dispatch, SetStateAction } from "react";
|
||||||
import React, { useState } from "react";
|
import { useState } from "react";
|
||||||
import { useParams } from "next/navigation";
|
import { useParams } from "next/navigation";
|
||||||
|
|
||||||
import { PROJECT_SETTINGS_TRACKER_ELEMENTS } from "@plane/constants";
|
|
||||||
import { EditIcon, CloseIcon } from "@plane/propel/icons";
|
import { EditIcon, CloseIcon } from "@plane/propel/icons";
|
||||||
// types
|
// types
|
||||||
import type { IIssueLabel } from "@plane/types";
|
import type { IIssueLabel } from "@plane/types";
|
||||||
// hooks
|
// hooks
|
||||||
import { captureClick } from "@/helpers/event-tracker.helper";
|
|
||||||
import { useLabel } from "@/hooks/store/use-label";
|
import { useLabel } from "@/hooks/store/use-label";
|
||||||
// components
|
// components
|
||||||
import type { TLabelOperationsCallbacks } from "./create-update-label-inline";
|
import type { TLabelOperationsCallbacks } from "./create-update-label-inline";
|
||||||
|
|
@ -73,9 +70,6 @@ export function ProjectSettingLabelItem(props: Props) {
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
setEditLabelForm(true);
|
setEditLabelForm(true);
|
||||||
setIsUpdating(true);
|
setIsUpdating(true);
|
||||||
captureClick({
|
|
||||||
elementName: PROJECT_SETTINGS_TRACKER_ELEMENTS.LABELS_CONTEXT_MENU,
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
isVisible: true,
|
isVisible: true,
|
||||||
text: "Edit label",
|
text: "Edit label",
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
import React, { useState, useRef } from "react";
|
import { useState, useRef } from "react";
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
import { useParams } from "next/navigation";
|
import { useParams } from "next/navigation";
|
||||||
// plane imports
|
// plane imports
|
||||||
import { EUserPermissions, EUserPermissionsLevel, PROJECT_SETTINGS_TRACKER_ELEMENTS } from "@plane/constants";
|
import { EUserPermissions, EUserPermissionsLevel } from "@plane/constants";
|
||||||
import { useTranslation } from "@plane/i18n";
|
import { useTranslation } from "@plane/i18n";
|
||||||
import { EmptyStateCompact } from "@plane/propel/empty-state";
|
import { EmptyStateCompact } from "@plane/propel/empty-state";
|
||||||
import type { IIssueLabel } from "@plane/types";
|
import type { IIssueLabel } from "@plane/types";
|
||||||
|
|
@ -15,7 +15,6 @@ import {
|
||||||
ProjectSettingLabelItem,
|
ProjectSettingLabelItem,
|
||||||
} from "@/components/labels";
|
} from "@/components/labels";
|
||||||
// hooks
|
// hooks
|
||||||
import { captureClick } from "@/helpers/event-tracker.helper";
|
|
||||||
import { useLabel } from "@/hooks/store/use-label";
|
import { useLabel } from "@/hooks/store/use-label";
|
||||||
import { useUserPermissions } from "@/hooks/store/user";
|
import { useUserPermissions } from "@/hooks/store/user";
|
||||||
// local imports
|
// local imports
|
||||||
|
|
@ -81,9 +80,6 @@ export const ProjectSettingsLabelList = observer(function ProjectSettingsLabelLi
|
||||||
label: t("common.add_label"),
|
label: t("common.add_label"),
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
newLabel();
|
newLabel();
|
||||||
captureClick({
|
|
||||||
elementName: PROJECT_SETTINGS_TRACKER_ELEMENTS.LABELS_HEADER_CREATE_BUTTON,
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
showButton={isEditable}
|
showButton={isEditable}
|
||||||
|
|
@ -117,9 +113,6 @@ export const ProjectSettingsLabelList = observer(function ProjectSettingsLabelLi
|
||||||
label: t("settings_empty_state.labels.cta_primary"),
|
label: t("settings_empty_state.labels.cta_primary"),
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
newLabel();
|
newLabel();
|
||||||
captureClick({
|
|
||||||
elementName: PROJECT_SETTINGS_TRACKER_ELEMENTS.LABELS_EMPTY_STATE_CREATE_BUTTON,
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,10 @@
|
||||||
import React, { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
import { useParams } from "next/navigation";
|
import { useParams } from "next/navigation";
|
||||||
import { Controller, useForm } from "react-hook-form";
|
import { Controller, useForm } from "react-hook-form";
|
||||||
import { Info, SquareUser } from "lucide-react";
|
import { Info, SquareUser } from "lucide-react";
|
||||||
import { Disclosure, Transition } from "@headlessui/react";
|
import { Disclosure, Transition } from "@headlessui/react";
|
||||||
import {
|
import { MODULE_STATUS, EUserPermissions, EUserPermissionsLevel, EEstimateSystem } from "@plane/constants";
|
||||||
MODULE_STATUS,
|
|
||||||
EUserPermissions,
|
|
||||||
EUserPermissionsLevel,
|
|
||||||
EEstimateSystem,
|
|
||||||
MODULE_TRACKER_EVENTS,
|
|
||||||
MODULE_TRACKER_ELEMENTS,
|
|
||||||
} from "@plane/constants";
|
|
||||||
// plane types
|
// plane types
|
||||||
import { useTranslation } from "@plane/i18n";
|
import { useTranslation } from "@plane/i18n";
|
||||||
import {
|
import {
|
||||||
|
|
@ -33,7 +26,6 @@ import { getDate, renderFormattedPayloadDate } from "@plane/utils";
|
||||||
import { DateRangeDropdown } from "@/components/dropdowns/date-range";
|
import { DateRangeDropdown } from "@/components/dropdowns/date-range";
|
||||||
import { MemberDropdown } from "@/components/dropdowns/member/dropdown";
|
import { MemberDropdown } from "@/components/dropdowns/member/dropdown";
|
||||||
import { CreateUpdateModuleLinkModal, ModuleAnalyticsProgress, ModuleLinksList } from "@/components/modules";
|
import { CreateUpdateModuleLinkModal, ModuleAnalyticsProgress, ModuleLinksList } from "@/components/modules";
|
||||||
import { captureElementAndEvent, captureSuccess, captureError } from "@/helpers/event-tracker.helper";
|
|
||||||
// hooks
|
// hooks
|
||||||
import { useProjectEstimates } from "@/hooks/store/estimates";
|
import { useProjectEstimates } from "@/hooks/store/estimates";
|
||||||
import { useModule } from "@/hooks/store/use-module";
|
import { useModule } from "@/hooks/store/use-module";
|
||||||
|
|
@ -79,98 +71,39 @@ export const ModuleAnalyticsSidebar = observer(function ModuleAnalyticsSidebar(p
|
||||||
defaultValues,
|
defaultValues,
|
||||||
});
|
});
|
||||||
|
|
||||||
const submitChanges = (data: Partial<IModule>) => {
|
const submitChanges = async (data: Partial<IModule>) => {
|
||||||
if (!workspaceSlug || !projectId || !moduleId) return;
|
if (!workspaceSlug || !projectId || !moduleId) return;
|
||||||
updateModuleDetails(workspaceSlug.toString(), projectId.toString(), moduleId.toString(), data)
|
await updateModuleDetails(workspaceSlug.toString(), projectId.toString(), moduleId.toString(), data);
|
||||||
.then((res) => {
|
|
||||||
captureElementAndEvent({
|
|
||||||
element: {
|
|
||||||
elementName: MODULE_TRACKER_ELEMENTS.RIGHT_SIDEBAR,
|
|
||||||
},
|
|
||||||
event: {
|
|
||||||
eventName: MODULE_TRACKER_EVENTS.update,
|
|
||||||
payload: { id: res.id },
|
|
||||||
state: "SUCCESS",
|
|
||||||
},
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
captureError({
|
|
||||||
eventName: MODULE_TRACKER_EVENTS.update,
|
|
||||||
payload: { id: moduleId },
|
|
||||||
error,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleCreateLink = async (formData: ModuleLink) => {
|
const handleCreateLink = async (formData: ModuleLink) => {
|
||||||
if (!workspaceSlug || !projectId || !moduleId) return;
|
if (!workspaceSlug || !projectId || !moduleId) return;
|
||||||
|
|
||||||
const payload = { metadata: {}, ...formData };
|
const payload = { metadata: {}, ...formData };
|
||||||
|
await createModuleLink(workspaceSlug.toString(), projectId.toString(), moduleId.toString(), payload);
|
||||||
await createModuleLink(workspaceSlug.toString(), projectId.toString(), moduleId.toString(), payload)
|
|
||||||
.then(() =>
|
|
||||||
captureSuccess({
|
|
||||||
eventName: MODULE_TRACKER_EVENTS.link.create,
|
|
||||||
payload: { id: moduleId },
|
|
||||||
})
|
|
||||||
)
|
|
||||||
.catch((error) => {
|
|
||||||
captureError({
|
|
||||||
eventName: MODULE_TRACKER_EVENTS.link.create,
|
|
||||||
payload: { id: moduleId },
|
|
||||||
error,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleUpdateLink = async (formData: ModuleLink, linkId: string) => {
|
const handleUpdateLink = async (formData: ModuleLink, linkId: string) => {
|
||||||
if (!workspaceSlug || !projectId) return;
|
if (!workspaceSlug || !projectId) return;
|
||||||
|
|
||||||
const payload = { metadata: {}, ...formData };
|
const payload = { metadata: {}, ...formData };
|
||||||
|
await updateModuleLink(workspaceSlug.toString(), projectId.toString(), moduleId.toString(), linkId, payload);
|
||||||
await updateModuleLink(workspaceSlug.toString(), projectId.toString(), moduleId.toString(), linkId, payload)
|
|
||||||
.then(() =>
|
|
||||||
captureSuccess({
|
|
||||||
eventName: MODULE_TRACKER_EVENTS.link.update,
|
|
||||||
payload: { id: moduleId },
|
|
||||||
})
|
|
||||||
)
|
|
||||||
.catch((error) => {
|
|
||||||
captureError({
|
|
||||||
eventName: MODULE_TRACKER_EVENTS.link.update,
|
|
||||||
payload: { id: moduleId },
|
|
||||||
error,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleDeleteLink = async (linkId: string) => {
|
const handleDeleteLink = async (linkId: string) => {
|
||||||
if (!workspaceSlug || !projectId) return;
|
if (!workspaceSlug || !projectId) return;
|
||||||
|
try {
|
||||||
deleteModuleLink(workspaceSlug.toString(), projectId.toString(), moduleId.toString(), linkId)
|
await deleteModuleLink(workspaceSlug.toString(), projectId.toString(), moduleId.toString(), linkId);
|
||||||
.then(() => {
|
setToast({
|
||||||
captureSuccess({
|
type: TOAST_TYPE.SUCCESS,
|
||||||
eventName: MODULE_TRACKER_EVENTS.link.delete,
|
title: "Success!",
|
||||||
payload: { id: moduleId },
|
message: "Module link deleted successfully.",
|
||||||
});
|
|
||||||
setToast({
|
|
||||||
type: TOAST_TYPE.SUCCESS,
|
|
||||||
title: "Success!",
|
|
||||||
message: "Module link deleted successfully.",
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.catch(() => {
|
|
||||||
setToast({
|
|
||||||
type: TOAST_TYPE.ERROR,
|
|
||||||
title: "Error!",
|
|
||||||
message: "Some error occurred",
|
|
||||||
});
|
|
||||||
captureError({
|
|
||||||
eventName: MODULE_TRACKER_EVENTS.link.delete,
|
|
||||||
payload: { id: moduleId },
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
} catch (_error) {
|
||||||
|
setToast({
|
||||||
|
type: TOAST_TYPE.ERROR,
|
||||||
|
title: "Error!",
|
||||||
|
message: "Some error occurred",
|
||||||
|
});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleDateChange = async (startDate: Date | undefined, targetDate: Date | undefined) => {
|
const handleDateChange = async (startDate: Date | undefined, targetDate: Date | undefined) => {
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,14 @@
|
||||||
import React, { useState } from "react";
|
import { useState } from "react";
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
import { useParams } from "next/navigation";
|
import { useParams } from "next/navigation";
|
||||||
// types
|
// types
|
||||||
import { MODULE_TRACKER_EVENTS, PROJECT_ERROR_MESSAGES } from "@plane/constants";
|
import { PROJECT_ERROR_MESSAGES } from "@plane/constants";
|
||||||
import { useTranslation } from "@plane/i18n";
|
import { useTranslation } from "@plane/i18n";
|
||||||
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
||||||
import type { IModule } from "@plane/types";
|
import type { IModule } from "@plane/types";
|
||||||
// ui
|
// ui
|
||||||
import { AlertModalCore } from "@plane/ui";
|
import { AlertModalCore } from "@plane/ui";
|
||||||
// constants
|
// constants
|
||||||
// helpers
|
|
||||||
import { captureSuccess, captureError } from "@/helpers/event-tracker.helper";
|
|
||||||
// hooks
|
// hooks
|
||||||
import { useModule } from "@/hooks/store/use-module";
|
import { useModule } from "@/hooks/store/use-module";
|
||||||
import { useAppRouter } from "@/hooks/use-app-router";
|
import { useAppRouter } from "@/hooks/use-app-router";
|
||||||
|
|
@ -51,10 +49,6 @@ export const DeleteModuleModal = observer(function DeleteModuleModal(props: Prop
|
||||||
title: "Success!",
|
title: "Success!",
|
||||||
message: "Module deleted successfully.",
|
message: "Module deleted successfully.",
|
||||||
});
|
});
|
||||||
captureSuccess({
|
|
||||||
eventName: MODULE_TRACKER_EVENTS.delete,
|
|
||||||
payload: { id: data.id },
|
|
||||||
});
|
|
||||||
})
|
})
|
||||||
.catch((errors) => {
|
.catch((errors) => {
|
||||||
const isPermissionError = errors?.error === "You don't have the required permissions.";
|
const isPermissionError = errors?.error === "You don't have the required permissions.";
|
||||||
|
|
@ -66,11 +60,6 @@ export const DeleteModuleModal = observer(function DeleteModuleModal(props: Prop
|
||||||
type: TOAST_TYPE.ERROR,
|
type: TOAST_TYPE.ERROR,
|
||||||
message: currentError.i18n_message && t(currentError.i18n_message),
|
message: currentError.i18n_message && t(currentError.i18n_message),
|
||||||
});
|
});
|
||||||
captureError({
|
|
||||||
eventName: MODULE_TRACKER_EVENTS.delete,
|
|
||||||
payload: { id: data.id },
|
|
||||||
error: errors,
|
|
||||||
});
|
|
||||||
})
|
})
|
||||||
.finally(() => handleClose());
|
.finally(() => handleClose());
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,12 @@
|
||||||
import React, { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
// types
|
// Plane imports
|
||||||
import { MODULE_TRACKER_EVENTS } from "@plane/constants";
|
|
||||||
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
||||||
import type { IModule } from "@plane/types";
|
import type { IModule } from "@plane/types";
|
||||||
// ui
|
|
||||||
import { EModalPosition, EModalWidth, ModalCore } from "@plane/ui";
|
import { EModalPosition, EModalWidth, ModalCore } from "@plane/ui";
|
||||||
// components
|
// components
|
||||||
import { ModuleForm } from "@/components/modules";
|
import { ModuleForm } from "@/components/modules";
|
||||||
// constants
|
|
||||||
// helpers
|
|
||||||
import { captureSuccess, captureError } from "@/helpers/event-tracker.helper";
|
|
||||||
// hooks
|
// hooks
|
||||||
import { useModule } from "@/hooks/store/use-module";
|
import { useModule } from "@/hooks/store/use-module";
|
||||||
import { useProject } from "@/hooks/store/use-project";
|
import { useProject } from "@/hooks/store/use-project";
|
||||||
|
|
@ -64,10 +59,6 @@ export const CreateUpdateModuleModal = observer(function CreateUpdateModuleModal
|
||||||
title: "Success!",
|
title: "Success!",
|
||||||
message: "Module created successfully.",
|
message: "Module created successfully.",
|
||||||
});
|
});
|
||||||
captureSuccess({
|
|
||||||
eventName: MODULE_TRACKER_EVENTS.create,
|
|
||||||
payload: { id: res.id },
|
|
||||||
});
|
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
setToast({
|
setToast({
|
||||||
|
|
@ -75,11 +66,6 @@ export const CreateUpdateModuleModal = observer(function CreateUpdateModuleModal
|
||||||
title: "Error!",
|
title: "Error!",
|
||||||
message: err?.detail ?? err?.error ?? "Module could not be created. Please try again.",
|
message: err?.detail ?? err?.error ?? "Module could not be created. Please try again.",
|
||||||
});
|
});
|
||||||
captureError({
|
|
||||||
eventName: MODULE_TRACKER_EVENTS.create,
|
|
||||||
payload: { id: data?.id },
|
|
||||||
error: err,
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -96,10 +82,6 @@ export const CreateUpdateModuleModal = observer(function CreateUpdateModuleModal
|
||||||
title: "Success!",
|
title: "Success!",
|
||||||
message: "Module updated successfully.",
|
message: "Module updated successfully.",
|
||||||
});
|
});
|
||||||
captureSuccess({
|
|
||||||
eventName: MODULE_TRACKER_EVENTS.update,
|
|
||||||
payload: { id: res.id },
|
|
||||||
});
|
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
setToast({
|
setToast({
|
||||||
|
|
@ -107,11 +89,6 @@ export const CreateUpdateModuleModal = observer(function CreateUpdateModuleModal
|
||||||
title: "Error!",
|
title: "Error!",
|
||||||
message: err?.detail ?? err?.error ?? "Module could not be updated. Please try again.",
|
message: err?.detail ?? err?.error ?? "Module could not be updated. Please try again.",
|
||||||
});
|
});
|
||||||
captureError({
|
|
||||||
eventName: MODULE_TRACKER_EVENTS.update,
|
|
||||||
payload: { id: data.id },
|
|
||||||
error: err,
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,8 +11,6 @@ import {
|
||||||
EUserPermissions,
|
EUserPermissions,
|
||||||
EUserPermissionsLevel,
|
EUserPermissionsLevel,
|
||||||
IS_FAVORITE_MENU_OPEN,
|
IS_FAVORITE_MENU_OPEN,
|
||||||
MODULE_TRACKER_EVENTS,
|
|
||||||
MODULE_TRACKER_ELEMENTS,
|
|
||||||
} from "@plane/constants";
|
} from "@plane/constants";
|
||||||
import { useLocalStorage } from "@plane/hooks";
|
import { useLocalStorage } from "@plane/hooks";
|
||||||
import { WorkItemsIcon } from "@plane/propel/icons";
|
import { WorkItemsIcon } from "@plane/propel/icons";
|
||||||
|
|
@ -26,8 +24,6 @@ import { DateRangeDropdown } from "@/components/dropdowns/date-range";
|
||||||
import { ButtonAvatars } from "@/components/dropdowns/member/avatar";
|
import { ButtonAvatars } from "@/components/dropdowns/member/avatar";
|
||||||
import { ModuleQuickActions } from "@/components/modules";
|
import { ModuleQuickActions } from "@/components/modules";
|
||||||
import { ModuleStatusDropdown } from "@/components/modules/module-status-dropdown";
|
import { ModuleStatusDropdown } from "@/components/modules/module-status-dropdown";
|
||||||
// helpers
|
|
||||||
import { captureElementAndEvent } from "@/helpers/event-tracker.helper";
|
|
||||||
// hooks
|
// hooks
|
||||||
import { useMember } from "@/hooks/store/use-member";
|
import { useMember } from "@/hooks/store/use-member";
|
||||||
import { useModule } from "@/hooks/store/use-module";
|
import { useModule } from "@/hooks/store/use-module";
|
||||||
|
|
@ -72,16 +68,6 @@ export const ModuleCardItem = observer(function ModuleCardItem(props: Props) {
|
||||||
const addToFavoritePromise = addModuleToFavorites(workspaceSlug.toString(), projectId.toString(), moduleId).then(
|
const addToFavoritePromise = addModuleToFavorites(workspaceSlug.toString(), projectId.toString(), moduleId).then(
|
||||||
() => {
|
() => {
|
||||||
if (!storedValue) toggleFavoriteMenu(true);
|
if (!storedValue) toggleFavoriteMenu(true);
|
||||||
captureElementAndEvent({
|
|
||||||
element: {
|
|
||||||
elementName: MODULE_TRACKER_ELEMENTS.CARD_ITEM,
|
|
||||||
},
|
|
||||||
event: {
|
|
||||||
eventName: MODULE_TRACKER_EVENTS.favorite,
|
|
||||||
payload: { id: moduleId },
|
|
||||||
state: "SUCCESS",
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -107,18 +93,7 @@ export const ModuleCardItem = observer(function ModuleCardItem(props: Props) {
|
||||||
workspaceSlug.toString(),
|
workspaceSlug.toString(),
|
||||||
projectId.toString(),
|
projectId.toString(),
|
||||||
moduleId
|
moduleId
|
||||||
).then(() => {
|
);
|
||||||
captureElementAndEvent({
|
|
||||||
element: {
|
|
||||||
elementName: MODULE_TRACKER_ELEMENTS.CARD_ITEM,
|
|
||||||
},
|
|
||||||
event: {
|
|
||||||
eventName: MODULE_TRACKER_EVENTS.unfavorite,
|
|
||||||
payload: { id: moduleId },
|
|
||||||
state: "SUCCESS",
|
|
||||||
},
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
setPromiseToast(removeFromFavoritePromise, {
|
setPromiseToast(removeFromFavoritePromise, {
|
||||||
loading: "Removing module from favorites...",
|
loading: "Removing module from favorites...",
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,8 @@
|
||||||
import type { FC } from "react";
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
import { useParams } from "next/navigation";
|
import { useParams } from "next/navigation";
|
||||||
// icons
|
|
||||||
import { SquareUser } from "lucide-react";
|
import { SquareUser } from "lucide-react";
|
||||||
// types
|
// Plane imports
|
||||||
import {
|
import {
|
||||||
MODULE_STATUS,
|
MODULE_STATUS,
|
||||||
EUserPermissions,
|
EUserPermissions,
|
||||||
|
|
@ -18,16 +16,12 @@ import { useTranslation } from "@plane/i18n";
|
||||||
import { TOAST_TYPE, setPromiseToast, setToast } from "@plane/propel/toast";
|
import { TOAST_TYPE, setPromiseToast, setToast } from "@plane/propel/toast";
|
||||||
import { Tooltip } from "@plane/propel/tooltip";
|
import { Tooltip } from "@plane/propel/tooltip";
|
||||||
import type { IModule } from "@plane/types";
|
import type { IModule } from "@plane/types";
|
||||||
// ui
|
|
||||||
import { FavoriteStar } from "@plane/ui";
|
import { FavoriteStar } from "@plane/ui";
|
||||||
// components
|
|
||||||
import { renderFormattedPayloadDate, getDate } from "@plane/utils";
|
import { renderFormattedPayloadDate, getDate } from "@plane/utils";
|
||||||
|
// components
|
||||||
import { DateRangeDropdown } from "@/components/dropdowns/date-range";
|
import { DateRangeDropdown } from "@/components/dropdowns/date-range";
|
||||||
import { ModuleQuickActions } from "@/components/modules";
|
import { ModuleQuickActions } from "@/components/modules";
|
||||||
import { ModuleStatusDropdown } from "@/components/modules/module-status-dropdown";
|
import { ModuleStatusDropdown } from "@/components/modules/module-status-dropdown";
|
||||||
// constants
|
|
||||||
// helpers
|
|
||||||
import { captureElementAndEvent, captureError } from "@/helpers/event-tracker.helper";
|
|
||||||
// hooks
|
// hooks
|
||||||
import { useMember } from "@/hooks/store/use-member";
|
import { useMember } from "@/hooks/store/use-member";
|
||||||
import { useModule } from "@/hooks/store/use-module";
|
import { useModule } from "@/hooks/store/use-module";
|
||||||
|
|
@ -69,28 +63,12 @@ export const ModuleListItemAction = observer(function ModuleListItemAction(props
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (!workspaceSlug || !projectId) return;
|
if (!workspaceSlug || !projectId) return;
|
||||||
|
|
||||||
const addToFavoritePromise = addModuleToFavorites(workspaceSlug.toString(), projectId.toString(), moduleId)
|
const addToFavoritePromise = addModuleToFavorites(workspaceSlug.toString(), projectId.toString(), moduleId).then(
|
||||||
.then(() => {
|
() => {
|
||||||
// open favorites menu if closed
|
// open favorites menu if closed
|
||||||
if (!storedValue) toggleFavoriteMenu(true);
|
if (!storedValue) toggleFavoriteMenu(true);
|
||||||
captureElementAndEvent({
|
}
|
||||||
element: {
|
);
|
||||||
elementName: MODULE_TRACKER_ELEMENTS.LIST_ITEM,
|
|
||||||
},
|
|
||||||
event: {
|
|
||||||
eventName: MODULE_TRACKER_EVENTS.favorite,
|
|
||||||
payload: { id: moduleId },
|
|
||||||
state: "SUCCESS",
|
|
||||||
},
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
captureError({
|
|
||||||
eventName: MODULE_TRACKER_EVENTS.favorite,
|
|
||||||
payload: { id: moduleId },
|
|
||||||
error,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
setPromiseToast(addToFavoritePromise, {
|
setPromiseToast(addToFavoritePromise, {
|
||||||
loading: "Adding module to favorites...",
|
loading: "Adding module to favorites...",
|
||||||
|
|
@ -114,26 +92,7 @@ export const ModuleListItemAction = observer(function ModuleListItemAction(props
|
||||||
workspaceSlug.toString(),
|
workspaceSlug.toString(),
|
||||||
projectId.toString(),
|
projectId.toString(),
|
||||||
moduleId
|
moduleId
|
||||||
)
|
);
|
||||||
.then(() => {
|
|
||||||
captureElementAndEvent({
|
|
||||||
element: {
|
|
||||||
elementName: MODULE_TRACKER_ELEMENTS.LIST_ITEM,
|
|
||||||
},
|
|
||||||
event: {
|
|
||||||
eventName: MODULE_TRACKER_EVENTS.unfavorite,
|
|
||||||
payload: { id: moduleId },
|
|
||||||
state: "SUCCESS",
|
|
||||||
},
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
captureError({
|
|
||||||
eventName: MODULE_TRACKER_EVENTS.unfavorite,
|
|
||||||
payload: { id: moduleId },
|
|
||||||
error,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
setPromiseToast(removeFromFavoritePromise, {
|
setPromiseToast(removeFromFavoritePromise, {
|
||||||
loading: "Removing module from favorites...",
|
loading: "Removing module from favorites...",
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,8 @@
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
import { MoreHorizontal } from "lucide-react";
|
import { MoreHorizontal } from "lucide-react";
|
||||||
|
|
||||||
// plane imports
|
// plane imports
|
||||||
import {
|
import { EUserPermissions, EUserPermissionsLevel } from "@plane/constants";
|
||||||
EUserPermissions,
|
|
||||||
EUserPermissionsLevel,
|
|
||||||
MODULE_TRACKER_ELEMENTS,
|
|
||||||
MODULE_TRACKER_EVENTS,
|
|
||||||
} from "@plane/constants";
|
|
||||||
import { useTranslation } from "@plane/i18n";
|
import { useTranslation } from "@plane/i18n";
|
||||||
import { IconButton } from "@plane/propel/icon-button";
|
import { IconButton } from "@plane/propel/icon-button";
|
||||||
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
||||||
|
|
@ -18,8 +12,6 @@ import { copyUrlToClipboard, cn } from "@plane/utils";
|
||||||
// components
|
// components
|
||||||
import { useModuleMenuItems } from "@/components/common/quick-actions-helper";
|
import { useModuleMenuItems } from "@/components/common/quick-actions-helper";
|
||||||
import { ArchiveModuleModal, CreateUpdateModuleModal, DeleteModuleModal } from "@/components/modules";
|
import { ArchiveModuleModal, CreateUpdateModuleModal, DeleteModuleModal } from "@/components/modules";
|
||||||
// helpers
|
|
||||||
import { captureClick, captureSuccess, captureError } from "@/helpers/event-tracker.helper";
|
|
||||||
// hooks
|
// hooks
|
||||||
import { useModule } from "@/hooks/store/use-module";
|
import { useModule } from "@/hooks/store/use-module";
|
||||||
import { useUserPermissions } from "@/hooks/store/user";
|
import { useUserPermissions } from "@/hooks/store/user";
|
||||||
|
|
@ -68,32 +60,23 @@ export const ModuleQuickActions = observer(function ModuleQuickActions(props: Pr
|
||||||
});
|
});
|
||||||
const handleOpenInNewTab = () => window.open(`/${moduleLink}`, "_blank");
|
const handleOpenInNewTab = () => window.open(`/${moduleLink}`, "_blank");
|
||||||
|
|
||||||
const handleRestoreModule = async () =>
|
const handleRestoreModule = async () => {
|
||||||
await restoreModule(workspaceSlug, projectId, moduleId)
|
try {
|
||||||
.then(() => {
|
await restoreModule(workspaceSlug, projectId, moduleId);
|
||||||
setToast({
|
setToast({
|
||||||
type: TOAST_TYPE.SUCCESS,
|
type: TOAST_TYPE.SUCCESS,
|
||||||
title: "Restore success",
|
title: "Restore success",
|
||||||
message: "Your module can be found in project modules.",
|
message: "Your module can be found in project modules.",
|
||||||
});
|
|
||||||
captureSuccess({
|
|
||||||
eventName: MODULE_TRACKER_EVENTS.restore,
|
|
||||||
payload: { id: moduleId },
|
|
||||||
});
|
|
||||||
router.push(`/${workspaceSlug}/projects/${projectId}/archives/modules`);
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
setToast({
|
|
||||||
type: TOAST_TYPE.ERROR,
|
|
||||||
title: "Error!",
|
|
||||||
message: "Module could not be restored. Please try again.",
|
|
||||||
});
|
|
||||||
captureError({
|
|
||||||
eventName: MODULE_TRACKER_EVENTS.restore,
|
|
||||||
payload: { id: moduleId },
|
|
||||||
error,
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
router.push(`/${workspaceSlug}/projects/${projectId}/archives/modules`);
|
||||||
|
} catch (_error) {
|
||||||
|
setToast({
|
||||||
|
type: TOAST_TYPE.ERROR,
|
||||||
|
title: "Error!",
|
||||||
|
message: "Module could not be restored. Please try again.",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// Use unified menu hook from plane-web (resolves to CE or EE)
|
// Use unified menu hook from plane-web (resolves to CE or EE)
|
||||||
const menuResult = useModuleMenuItems({
|
const menuResult = useModuleMenuItems({
|
||||||
|
|
@ -119,9 +102,6 @@ export const ModuleQuickActions = observer(function ModuleQuickActions(props: Pr
|
||||||
...item,
|
...item,
|
||||||
|
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
captureClick({
|
|
||||||
elementName: MODULE_TRACKER_ELEMENTS.CONTEXT_MENU,
|
|
||||||
});
|
|
||||||
item.action();
|
item.action();
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
@ -162,9 +142,6 @@ export const ModuleQuickActions = observer(function ModuleQuickActions(props: Pr
|
||||||
<CustomMenu.MenuItem
|
<CustomMenu.MenuItem
|
||||||
key={item.key}
|
key={item.key}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
captureClick({
|
|
||||||
elementName: MODULE_TRACKER_ELEMENTS.QUICK_ACTIONS,
|
|
||||||
});
|
|
||||||
item.action();
|
item.action();
|
||||||
}}
|
}}
|
||||||
className={cn(
|
className={cn(
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
import type { FC } from "react";
|
|
||||||
import { useState, useRef } from "react";
|
import { useState, useRef } from "react";
|
||||||
import { useNavigate } from "react-router";
|
import { useNavigate } from "react-router";
|
||||||
import { LogOut, MoreHorizontal, Settings, Share2, ArchiveIcon } from "lucide-react";
|
import { LogOut, MoreHorizontal, Settings, Share2, ArchiveIcon } from "lucide-react";
|
||||||
|
|
|
||||||
|
|
@ -2,12 +2,7 @@ import { useState } from "react";
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
import { Controller, useForm } from "react-hook-form";
|
import { Controller, useForm } from "react-hook-form";
|
||||||
// constants
|
// constants
|
||||||
import {
|
import { ORGANIZATION_SIZE, RESTRICTED_URLS } from "@plane/constants";
|
||||||
ORGANIZATION_SIZE,
|
|
||||||
RESTRICTED_URLS,
|
|
||||||
WORKSPACE_TRACKER_EVENTS,
|
|
||||||
WORKSPACE_TRACKER_ELEMENTS,
|
|
||||||
} from "@plane/constants";
|
|
||||||
// types
|
// types
|
||||||
import { useTranslation } from "@plane/i18n";
|
import { useTranslation } from "@plane/i18n";
|
||||||
import { Button } from "@plane/propel/button";
|
import { Button } from "@plane/propel/button";
|
||||||
|
|
@ -16,7 +11,6 @@ import type { IUser, IWorkspace, TOnboardingSteps } from "@plane/types";
|
||||||
// ui
|
// ui
|
||||||
import { CustomSelect, Input, Spinner } from "@plane/ui";
|
import { CustomSelect, Input, Spinner } from "@plane/ui";
|
||||||
// hooks
|
// hooks
|
||||||
import { captureError, captureSuccess } from "@/helpers/event-tracker.helper";
|
|
||||||
import { useWorkspace } from "@/hooks/store/use-workspace";
|
import { useWorkspace } from "@/hooks/store/use-workspace";
|
||||||
import { useUserProfile, useUserSettings } from "@/hooks/store/user";
|
import { useUserProfile, useUserSettings } from "@/hooks/store/user";
|
||||||
// services
|
// services
|
||||||
|
|
@ -61,47 +55,26 @@ export const CreateWorkspace = observer(function CreateWorkspace(props: Props) {
|
||||||
const handleCreateWorkspace = async (formData: IWorkspace) => {
|
const handleCreateWorkspace = async (formData: IWorkspace) => {
|
||||||
if (isSubmitting) return;
|
if (isSubmitting) return;
|
||||||
|
|
||||||
await workspaceService
|
try {
|
||||||
.workspaceSlugCheck(formData.slug)
|
const res = await workspaceService.workspaceSlugCheck(formData.slug);
|
||||||
.then(async (res) => {
|
if (res?.status === true && !RESTRICTED_URLS.includes(formData.slug)) {
|
||||||
if (res.status === true && !RESTRICTED_URLS.includes(formData.slug)) {
|
setSlugError(false);
|
||||||
setSlugError(false);
|
const workspaceResponse = await createWorkspace(formData);
|
||||||
|
|
||||||
await createWorkspace(formData)
|
|
||||||
.then(async (workspaceResponse) => {
|
|
||||||
setToast({
|
|
||||||
type: TOAST_TYPE.SUCCESS,
|
|
||||||
title: t("workspace_creation.toast.success.title"),
|
|
||||||
message: t("workspace_creation.toast.success.message"),
|
|
||||||
});
|
|
||||||
captureSuccess({
|
|
||||||
eventName: WORKSPACE_TRACKER_EVENTS.create,
|
|
||||||
payload: { slug: formData.slug },
|
|
||||||
});
|
|
||||||
await fetchWorkspaces();
|
|
||||||
await completeStep(workspaceResponse.id);
|
|
||||||
})
|
|
||||||
.catch(() => {
|
|
||||||
captureError({
|
|
||||||
eventName: WORKSPACE_TRACKER_EVENTS.create,
|
|
||||||
payload: { slug: formData.slug },
|
|
||||||
error: new Error("Error creating workspace"),
|
|
||||||
});
|
|
||||||
setToast({
|
|
||||||
type: TOAST_TYPE.ERROR,
|
|
||||||
title: t("workspace_creation.toast.error.title"),
|
|
||||||
message: t("workspace_creation.toast.error.message"),
|
|
||||||
});
|
|
||||||
});
|
|
||||||
} else setSlugError(true);
|
|
||||||
})
|
|
||||||
.catch(() =>
|
|
||||||
setToast({
|
setToast({
|
||||||
type: TOAST_TYPE.ERROR,
|
type: TOAST_TYPE.SUCCESS,
|
||||||
title: t("workspace_creation.toast.error.title"),
|
title: t("workspace_creation.toast.success.title"),
|
||||||
message: t("workspace_creation.toast.error.message"),
|
message: t("workspace_creation.toast.success.message"),
|
||||||
})
|
});
|
||||||
);
|
await fetchWorkspaces();
|
||||||
|
await completeStep(workspaceResponse.id);
|
||||||
|
} else setSlugError(true);
|
||||||
|
} catch (_error) {
|
||||||
|
setToast({
|
||||||
|
type: TOAST_TYPE.ERROR,
|
||||||
|
title: t("workspace_creation.toast.error.title"),
|
||||||
|
message: t("workspace_creation.toast.error.message"),
|
||||||
|
});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const completeStep = async (workspaceId: string) => {
|
const completeStep = async (workspaceId: string) => {
|
||||||
|
|
@ -284,14 +257,7 @@ export const CreateWorkspace = observer(function CreateWorkspace(props: Props) {
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Button
|
<Button variant="primary" type="submit" size="xl" className="w-full" disabled={isButtonDisabled}>
|
||||||
data-ph-element={WORKSPACE_TRACKER_ELEMENTS.ONBOARDING_CREATE_WORKSPACE_BUTTON}
|
|
||||||
variant="primary"
|
|
||||||
type="submit"
|
|
||||||
size="xl"
|
|
||||||
className="w-full"
|
|
||||||
disabled={isButtonDisabled}
|
|
||||||
>
|
|
||||||
{isSubmitting ? <Spinner height="20px" width="20px" /> : t("workspace_creation.button.default")}
|
{isSubmitting ? <Spinner height="20px" width="20px" /> : t("workspace_creation.button.default")}
|
||||||
</Button>
|
</Button>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import React, { useState } from "react";
|
import { useState } from "react";
|
||||||
// plane imports
|
// plane imports
|
||||||
import { ROLE, MEMBER_TRACKER_EVENTS, MEMBER_TRACKER_ELEMENTS } from "@plane/constants";
|
import { ROLE } from "@plane/constants";
|
||||||
// types
|
// types
|
||||||
import { Button } from "@plane/propel/button";
|
import { Button } from "@plane/propel/button";
|
||||||
import type { IWorkspaceMemberInvitation } from "@plane/types";
|
import type { IWorkspaceMemberInvitation } from "@plane/types";
|
||||||
|
|
@ -11,7 +11,6 @@ import { truncateText } from "@plane/utils";
|
||||||
// helpers
|
// helpers
|
||||||
import { WorkspaceLogo } from "@/components/workspace/logo";
|
import { WorkspaceLogo } from "@/components/workspace/logo";
|
||||||
// hooks
|
// hooks
|
||||||
import { captureError, captureSuccess } from "@/helpers/event-tracker.helper";
|
|
||||||
import { useWorkspace } from "@/hooks/store/use-workspace";
|
import { useWorkspace } from "@/hooks/store/use-workspace";
|
||||||
import { useUserSettings } from "@/hooks/store/user";
|
import { useUserSettings } from "@/hooks/store/user";
|
||||||
// services
|
// services
|
||||||
|
|
@ -43,31 +42,15 @@ export function Invitations(props: Props) {
|
||||||
|
|
||||||
const submitInvitations = async () => {
|
const submitInvitations = async () => {
|
||||||
const invitation = invitations?.find((invitation) => invitation.id === invitationsRespond[0]);
|
const invitation = invitations?.find((invitation) => invitation.id === invitationsRespond[0]);
|
||||||
|
|
||||||
if (invitationsRespond.length <= 0 && !invitation?.role) return;
|
if (invitationsRespond.length <= 0 && !invitation?.role) return;
|
||||||
|
|
||||||
setIsJoiningWorkspaces(true);
|
setIsJoiningWorkspaces(true);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await workspaceService.joinWorkspaces({ invitations: invitationsRespond });
|
await workspaceService.joinWorkspaces({ invitations: invitationsRespond });
|
||||||
captureSuccess({
|
|
||||||
eventName: MEMBER_TRACKER_EVENTS.accept,
|
|
||||||
payload: {
|
|
||||||
member_id: invitation?.id,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
await fetchWorkspaces();
|
await fetchWorkspaces();
|
||||||
await fetchCurrentUserSettings();
|
await fetchCurrentUserSettings();
|
||||||
await handleNextStep();
|
await handleNextStep();
|
||||||
} catch (error: any) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
captureError({
|
|
||||||
eventName: MEMBER_TRACKER_EVENTS.accept,
|
|
||||||
payload: {
|
|
||||||
member_id: invitation?.id,
|
|
||||||
},
|
|
||||||
error: error,
|
|
||||||
});
|
|
||||||
setIsJoiningWorkspaces(false);
|
setIsJoiningWorkspaces(false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -114,7 +97,6 @@ export function Invitations(props: Props) {
|
||||||
className="w-full"
|
className="w-full"
|
||||||
onClick={submitInvitations}
|
onClick={submitInvitations}
|
||||||
disabled={isJoiningWorkspaces || !invitationsRespond.length}
|
disabled={isJoiningWorkspaces || !invitationsRespond.length}
|
||||||
data-ph-element={MEMBER_TRACKER_ELEMENTS.ONBOARDING_JOIN_WORKSPACE}
|
|
||||||
>
|
>
|
||||||
{isJoiningWorkspaces ? <Spinner height="20px" width="20px" /> : "Continue to workspace"}
|
{isJoiningWorkspaces ? <Spinner height="20px" width="20px" /> : "Continue to workspace"}
|
||||||
</Button>
|
</Button>
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ import { XCircle } from "lucide-react";
|
||||||
import { Listbox } from "@headlessui/react";
|
import { Listbox } from "@headlessui/react";
|
||||||
// plane imports
|
// plane imports
|
||||||
import type { EUserPermissions } from "@plane/constants";
|
import type { EUserPermissions } from "@plane/constants";
|
||||||
import { ROLE, ROLE_DETAILS, MEMBER_TRACKER_EVENTS, MEMBER_TRACKER_ELEMENTS } from "@plane/constants";
|
import { ROLE, ROLE_DETAILS } from "@plane/constants";
|
||||||
import { useTranslation } from "@plane/i18n";
|
import { useTranslation } from "@plane/i18n";
|
||||||
// types
|
// types
|
||||||
import { Button } from "@plane/propel/button";
|
import { Button } from "@plane/propel/button";
|
||||||
|
|
@ -24,8 +24,6 @@ import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
||||||
import type { IUser, IWorkspace } from "@plane/types";
|
import type { IUser, IWorkspace } from "@plane/types";
|
||||||
// ui
|
// ui
|
||||||
import { Input, Spinner } from "@plane/ui";
|
import { Input, Spinner } from "@plane/ui";
|
||||||
// helpers
|
|
||||||
import { captureError, captureSuccess } from "@/helpers/event-tracker.helper";
|
|
||||||
// services
|
// services
|
||||||
import { WorkspaceService } from "@/plane-web/services";
|
import { WorkspaceService } from "@/plane-web/services";
|
||||||
// components
|
// components
|
||||||
|
|
@ -294,28 +292,14 @@ export function InviteMembers(props: Props) {
|
||||||
})),
|
})),
|
||||||
})
|
})
|
||||||
.then(async () => {
|
.then(async () => {
|
||||||
captureSuccess({
|
|
||||||
eventName: MEMBER_TRACKER_EVENTS.invite,
|
|
||||||
payload: {
|
|
||||||
workspace: workspace.slug,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
setToast({
|
setToast({
|
||||||
type: TOAST_TYPE.SUCCESS,
|
type: TOAST_TYPE.SUCCESS,
|
||||||
title: "Success!",
|
title: "Success!",
|
||||||
message: "Invitations sent successfully.",
|
message: "Invitations sent successfully.",
|
||||||
});
|
});
|
||||||
|
|
||||||
await nextStep();
|
await nextStep();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
captureError({
|
|
||||||
eventName: MEMBER_TRACKER_EVENTS.invite,
|
|
||||||
payload: {
|
|
||||||
workspace: workspace.slug,
|
|
||||||
},
|
|
||||||
error: err,
|
|
||||||
});
|
|
||||||
setToast({
|
setToast({
|
||||||
type: TOAST_TYPE.ERROR,
|
type: TOAST_TYPE.ERROR,
|
||||||
title: "Error!",
|
title: "Error!",
|
||||||
|
|
@ -399,7 +383,6 @@ export function InviteMembers(props: Props) {
|
||||||
size="xl"
|
size="xl"
|
||||||
className="w-full"
|
className="w-full"
|
||||||
disabled={isInvitationDisabled || !isValid || isSubmitting}
|
disabled={isInvitationDisabled || !isValid || isSubmitting}
|
||||||
data-ph-element={MEMBER_TRACKER_ELEMENTS.ONBOARDING_INVITE_MEMBER}
|
|
||||||
>
|
>
|
||||||
{isSubmitting ? <Spinner height="20px" width="20px" /> : "Continue"}
|
{isSubmitting ? <Spinner height="20px" width="20px" /> : "Continue"}
|
||||||
</Button>
|
</Button>
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,8 @@
|
||||||
import React, { useMemo, useState } from "react";
|
import { useMemo, useState } from "react";
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
import { Controller, useForm } from "react-hook-form";
|
import { Controller, useForm } from "react-hook-form";
|
||||||
import { Eye, EyeOff } from "lucide-react";
|
import { Eye, EyeOff } from "lucide-react";
|
||||||
import {
|
import { E_PASSWORD_STRENGTH } from "@plane/constants";
|
||||||
AUTH_TRACKER_EVENTS,
|
|
||||||
E_PASSWORD_STRENGTH,
|
|
||||||
ONBOARDING_TRACKER_ELEMENTS,
|
|
||||||
USER_TRACKER_EVENTS,
|
|
||||||
} from "@plane/constants";
|
|
||||||
// types
|
// types
|
||||||
import { useTranslation } from "@plane/i18n";
|
import { useTranslation } from "@plane/i18n";
|
||||||
import { Button } from "@plane/propel/button";
|
import { Button } from "@plane/propel/button";
|
||||||
|
|
@ -18,10 +13,7 @@ import { Input, PasswordStrengthIndicator, Spinner } from "@plane/ui";
|
||||||
// components
|
// components
|
||||||
import { cn, getFileURL, getPasswordStrength } from "@plane/utils";
|
import { cn, getFileURL, getPasswordStrength } from "@plane/utils";
|
||||||
import { UserImageUploadModal } from "@/components/core/modals/user-image-upload-modal";
|
import { UserImageUploadModal } from "@/components/core/modals/user-image-upload-modal";
|
||||||
// constants
|
|
||||||
// helpers
|
|
||||||
// hooks
|
// hooks
|
||||||
import { captureError, captureSuccess, captureView } from "@/helpers/event-tracker.helper";
|
|
||||||
import { useUser, useUserProfile } from "@/hooks/store/user";
|
import { useUser, useUserProfile } from "@/hooks/store/user";
|
||||||
// services
|
// services
|
||||||
import { AuthService } from "@/services/auth.service";
|
import { AuthService } from "@/services/auth.service";
|
||||||
|
|
@ -118,18 +110,7 @@ export const ProfileSetup = observer(function ProfileSetup(props: Props) {
|
||||||
|
|
||||||
const handleSetPassword = async (password: string) => {
|
const handleSetPassword = async (password: string) => {
|
||||||
const token = await authService.requestCSRFToken().then((data) => data?.csrf_token);
|
const token = await authService.requestCSRFToken().then((data) => data?.csrf_token);
|
||||||
await authService
|
await authService.setPassword(token, { password });
|
||||||
.setPassword(token, { password })
|
|
||||||
.then(() => {
|
|
||||||
captureSuccess({
|
|
||||||
eventName: AUTH_TRACKER_EVENTS.password_created,
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.catch(() => {
|
|
||||||
captureError({
|
|
||||||
eventName: AUTH_TRACKER_EVENTS.password_created,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSubmitProfileSetup = async (formData: TProfileSetupFormValues) => {
|
const handleSubmitProfileSetup = async (formData: TProfileSetupFormValues) => {
|
||||||
|
|
@ -148,13 +129,6 @@ export const ProfileSetup = observer(function ProfileSetup(props: Props) {
|
||||||
updateUserProfile(profileUpdatePayload),
|
updateUserProfile(profileUpdatePayload),
|
||||||
totalSteps > 2 && stepChange({ profile_complete: true }),
|
totalSteps > 2 && stepChange({ profile_complete: true }),
|
||||||
]);
|
]);
|
||||||
captureSuccess({
|
|
||||||
eventName: USER_TRACKER_EVENTS.add_details,
|
|
||||||
payload: {
|
|
||||||
use_case: profileUpdatePayload.use_case,
|
|
||||||
role: formData.role,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
setToast({
|
setToast({
|
||||||
type: TOAST_TYPE.SUCCESS,
|
type: TOAST_TYPE.SUCCESS,
|
||||||
title: "Success",
|
title: "Success",
|
||||||
|
|
@ -165,9 +139,6 @@ export const ProfileSetup = observer(function ProfileSetup(props: Props) {
|
||||||
finishOnboarding();
|
finishOnboarding();
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
captureError({
|
|
||||||
eventName: USER_TRACKER_EVENTS.add_details,
|
|
||||||
});
|
|
||||||
setToast({
|
setToast({
|
||||||
type: TOAST_TYPE.ERROR,
|
type: TOAST_TYPE.ERROR,
|
||||||
title: "Error",
|
title: "Error",
|
||||||
|
|
@ -188,20 +159,11 @@ export const ProfileSetup = observer(function ProfileSetup(props: Props) {
|
||||||
formData.password && handleSetPassword(formData.password),
|
formData.password && handleSetPassword(formData.password),
|
||||||
]).then(() => {
|
]).then(() => {
|
||||||
if (formData.password) {
|
if (formData.password) {
|
||||||
captureView({
|
|
||||||
elementName: ONBOARDING_TRACKER_ELEMENTS.PASSWORD_CREATION_SELECTED,
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
captureView({
|
setProfileSetupStep(EProfileSetupSteps.USER_PERSONALIZATION);
|
||||||
elementName: ONBOARDING_TRACKER_ELEMENTS.PASSWORD_CREATION_SKIPPED,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
setProfileSetupStep(EProfileSetupSteps.USER_PERSONALIZATION);
|
|
||||||
});
|
});
|
||||||
} catch {
|
} catch {
|
||||||
captureError({
|
|
||||||
eventName: USER_TRACKER_EVENTS.add_details,
|
|
||||||
});
|
|
||||||
setToast({
|
setToast({
|
||||||
type: TOAST_TYPE.ERROR,
|
type: TOAST_TYPE.ERROR,
|
||||||
title: "Error",
|
title: "Error",
|
||||||
|
|
@ -220,13 +182,6 @@ export const ProfileSetup = observer(function ProfileSetup(props: Props) {
|
||||||
updateUserProfile(profileUpdatePayload),
|
updateUserProfile(profileUpdatePayload),
|
||||||
totalSteps > 2 && stepChange({ profile_complete: true }),
|
totalSteps > 2 && stepChange({ profile_complete: true }),
|
||||||
]);
|
]);
|
||||||
captureSuccess({
|
|
||||||
eventName: USER_TRACKER_EVENTS.add_details,
|
|
||||||
payload: {
|
|
||||||
use_case: profileUpdatePayload.use_case,
|
|
||||||
role: formData.role,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
setToast({
|
setToast({
|
||||||
type: TOAST_TYPE.SUCCESS,
|
type: TOAST_TYPE.SUCCESS,
|
||||||
title: "Success",
|
title: "Success",
|
||||||
|
|
@ -237,9 +192,6 @@ export const ProfileSetup = observer(function ProfileSetup(props: Props) {
|
||||||
finishOnboarding();
|
finishOnboarding();
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
captureError({
|
|
||||||
eventName: USER_TRACKER_EVENTS.add_details,
|
|
||||||
});
|
|
||||||
setToast({
|
setToast({
|
||||||
type: TOAST_TYPE.ERROR,
|
type: TOAST_TYPE.ERROR,
|
||||||
title: "Error",
|
title: "Error",
|
||||||
|
|
@ -250,9 +202,6 @@ export const ProfileSetup = observer(function ProfileSetup(props: Props) {
|
||||||
|
|
||||||
const onSubmit = async (formData: TProfileSetupFormValues) => {
|
const onSubmit = async (formData: TProfileSetupFormValues) => {
|
||||||
if (!user) return;
|
if (!user) return;
|
||||||
captureView({
|
|
||||||
elementName: ONBOARDING_TRACKER_ELEMENTS.PROFILE_SETUP_FORM,
|
|
||||||
});
|
|
||||||
if (profileSetupStep === EProfileSetupSteps.ALL) await handleSubmitProfileSetup(formData);
|
if (profileSetupStep === EProfileSetupSteps.ALL) await handleSubmitProfileSetup(formData);
|
||||||
if (profileSetupStep === EProfileSetupSteps.USER_DETAILS) await handleSubmitUserDetail(formData);
|
if (profileSetupStep === EProfileSetupSteps.USER_DETAILS) await handleSubmitUserDetail(formData);
|
||||||
if (profileSetupStep === EProfileSetupSteps.USER_PERSONALIZATION) await handleSubmitUserPersonalization(formData);
|
if (profileSetupStep === EProfileSetupSteps.USER_PERSONALIZATION) await handleSubmitUserPersonalization(formData);
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,9 @@
|
||||||
import type { FC } from "react";
|
|
||||||
import { useCallback, useEffect, useState } from "react";
|
import { useCallback, useEffect, useState } from "react";
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
// plane imports
|
// plane imports
|
||||||
import { USER_TRACKER_EVENTS } from "@plane/constants";
|
|
||||||
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
||||||
import type { IWorkspaceMemberInvitation, TOnboardingStep, TOnboardingSteps, TUserProfile } from "@plane/types";
|
import type { IWorkspaceMemberInvitation, TOnboardingStep, TOnboardingSteps, TUserProfile } from "@plane/types";
|
||||||
import { EOnboardingSteps } from "@plane/types";
|
import { EOnboardingSteps } from "@plane/types";
|
||||||
// helpers
|
|
||||||
import { captureSuccess } from "@/helpers/event-tracker.helper";
|
|
||||||
// hooks
|
// hooks
|
||||||
import { useWorkspace } from "@/hooks/store/use-workspace";
|
import { useWorkspace } from "@/hooks/store/use-workspace";
|
||||||
import { useUser, useUserProfile } from "@/hooks/store/user";
|
import { useUser, useUserProfile } from "@/hooks/store/user";
|
||||||
|
|
@ -34,24 +30,15 @@ export const OnboardingRoot = observer(function OnboardingRoot({ invitations = [
|
||||||
// complete onboarding
|
// complete onboarding
|
||||||
const finishOnboarding = useCallback(async () => {
|
const finishOnboarding = useCallback(async () => {
|
||||||
if (!user) return;
|
if (!user) return;
|
||||||
|
try {
|
||||||
await finishUserOnboarding()
|
await finishUserOnboarding();
|
||||||
.then(() => {
|
} catch (_error) {
|
||||||
captureSuccess({
|
setToast({
|
||||||
eventName: USER_TRACKER_EVENTS.onboarding_complete,
|
type: TOAST_TYPE.ERROR,
|
||||||
payload: {
|
title: "Failed",
|
||||||
email: user.email,
|
message: "Failed to finish onboarding, Please try again later.",
|
||||||
user_id: user.id,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.catch(() => {
|
|
||||||
setToast({
|
|
||||||
type: TOAST_TYPE.ERROR,
|
|
||||||
title: "Failed",
|
|
||||||
message: "Failed to finish onboarding, Please try again later.",
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
}
|
||||||
}, [user, finishUserOnboarding]);
|
}, [user, finishUserOnboarding]);
|
||||||
|
|
||||||
// handle step change
|
// handle step change
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,9 @@
|
||||||
import type { FC } from "react";
|
|
||||||
import { useMemo, useState } from "react";
|
import { useMemo, useState } from "react";
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
import { Controller, useForm } from "react-hook-form";
|
import { Controller, useForm } from "react-hook-form";
|
||||||
import { ImageIcon } from "lucide-react";
|
import { ImageIcon } from "lucide-react";
|
||||||
// plane imports
|
// plane imports
|
||||||
import { E_PASSWORD_STRENGTH, ONBOARDING_TRACKER_ELEMENTS, USER_TRACKER_EVENTS } from "@plane/constants";
|
import { E_PASSWORD_STRENGTH } from "@plane/constants";
|
||||||
import { Button } from "@plane/propel/button";
|
import { Button } from "@plane/propel/button";
|
||||||
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
||||||
import type { IUser } from "@plane/types";
|
import type { IUser } from "@plane/types";
|
||||||
|
|
@ -12,8 +11,6 @@ import { EOnboardingSteps } from "@plane/types";
|
||||||
import { cn, getFileURL, getPasswordStrength } from "@plane/utils";
|
import { cn, getFileURL, getPasswordStrength } from "@plane/utils";
|
||||||
// components
|
// components
|
||||||
import { UserImageUploadModal } from "@/components/core/modals/user-image-upload-modal";
|
import { UserImageUploadModal } from "@/components/core/modals/user-image-upload-modal";
|
||||||
// helpers
|
|
||||||
import { captureError, captureView } from "@/helpers/event-tracker.helper";
|
|
||||||
// hooks
|
// hooks
|
||||||
import { useInstance } from "@/hooks/store/use-instance";
|
import { useInstance } from "@/hooks/store/use-instance";
|
||||||
import { useUser, useUserProfile } from "@/hooks/store/user";
|
import { useUser, useUserProfile } from "@/hooks/store/user";
|
||||||
|
|
@ -94,9 +91,6 @@ export const ProfileSetupStep = observer(function ProfileSetupStep({ handleStepC
|
||||||
formData.password && handleSetPassword(formData.password),
|
formData.password && handleSetPassword(formData.password),
|
||||||
]);
|
]);
|
||||||
} catch {
|
} catch {
|
||||||
captureError({
|
|
||||||
eventName: USER_TRACKER_EVENTS.add_details,
|
|
||||||
});
|
|
||||||
setToast({
|
setToast({
|
||||||
type: TOAST_TYPE.ERROR,
|
type: TOAST_TYPE.ERROR,
|
||||||
title: "Error",
|
title: "Error",
|
||||||
|
|
@ -107,15 +101,11 @@ export const ProfileSetupStep = observer(function ProfileSetupStep({ handleStepC
|
||||||
|
|
||||||
const onSubmit = async (formData: TProfileSetupFormValues) => {
|
const onSubmit = async (formData: TProfileSetupFormValues) => {
|
||||||
if (!user) return;
|
if (!user) return;
|
||||||
captureView({
|
|
||||||
elementName: ONBOARDING_TRACKER_ELEMENTS.PROFILE_SETUP_FORM,
|
|
||||||
});
|
|
||||||
updateUserProfile({
|
updateUserProfile({
|
||||||
has_marketing_email_consent: formData.has_marketing_email_consent,
|
has_marketing_email_consent: formData.has_marketing_email_consent,
|
||||||
});
|
});
|
||||||
await handleSubmitUserDetail(formData).then(() => {
|
await handleSubmitUserDetail(formData);
|
||||||
handleStepChange(EOnboardingSteps.PROFILE_SETUP);
|
handleStepChange(EOnboardingSteps.PROFILE_SETUP);
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleDelete = (url: string | null | undefined) => {
|
const handleDelete = (url: string | null | undefined) => {
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,12 @@
|
||||||
import type { FC } from "react";
|
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
import { Controller, useForm } from "react-hook-form";
|
import { Controller, useForm } from "react-hook-form";
|
||||||
import { Box, PenTool, Rocket, Monitor, RefreshCw } from "lucide-react";
|
import { Box, PenTool, Rocket, Monitor, RefreshCw } from "lucide-react";
|
||||||
// plane imports
|
// plane imports
|
||||||
import { ONBOARDING_TRACKER_ELEMENTS, USER_TRACKER_EVENTS } from "@plane/constants";
|
|
||||||
import { Button } from "@plane/propel/button";
|
import { Button } from "@plane/propel/button";
|
||||||
import { CheckIcon, ViewsIcon } from "@plane/propel/icons";
|
import { CheckIcon, ViewsIcon } from "@plane/propel/icons";
|
||||||
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
||||||
import type { TUserProfile } from "@plane/types";
|
import type { TUserProfile } from "@plane/types";
|
||||||
import { EOnboardingSteps } from "@plane/types";
|
import { EOnboardingSteps } from "@plane/types";
|
||||||
// helpers
|
|
||||||
import { captureError, captureSuccess, captureView } from "@/helpers/event-tracker.helper";
|
|
||||||
// hooks
|
// hooks
|
||||||
import { useUserProfile } from "@/hooks/store/user";
|
import { useUserProfile } from "@/hooks/store/user";
|
||||||
// local components
|
// local components
|
||||||
|
|
@ -61,22 +57,12 @@ export const RoleSetupStep = observer(function RoleSetupStep({ handleStepChange
|
||||||
updateUserProfile(profileUpdatePayload),
|
updateUserProfile(profileUpdatePayload),
|
||||||
// totalSteps > 2 && stepChange({ profile_complete: true }),
|
// totalSteps > 2 && stepChange({ profile_complete: true }),
|
||||||
]);
|
]);
|
||||||
captureSuccess({
|
|
||||||
eventName: USER_TRACKER_EVENTS.add_details,
|
|
||||||
payload: {
|
|
||||||
use_case: formData.use_case,
|
|
||||||
role: formData.role,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
setToast({
|
setToast({
|
||||||
type: TOAST_TYPE.SUCCESS,
|
type: TOAST_TYPE.SUCCESS,
|
||||||
title: "Success",
|
title: "Success",
|
||||||
message: "Profile setup completed!",
|
message: "Profile setup completed!",
|
||||||
});
|
});
|
||||||
} catch {
|
} catch {
|
||||||
captureError({
|
|
||||||
eventName: USER_TRACKER_EVENTS.add_details,
|
|
||||||
});
|
|
||||||
setToast({
|
setToast({
|
||||||
type: TOAST_TYPE.ERROR,
|
type: TOAST_TYPE.ERROR,
|
||||||
title: "Error",
|
title: "Error",
|
||||||
|
|
@ -87,12 +73,8 @@ export const RoleSetupStep = observer(function RoleSetupStep({ handleStepChange
|
||||||
|
|
||||||
const onSubmit = async (formData: TProfileSetupFormValues) => {
|
const onSubmit = async (formData: TProfileSetupFormValues) => {
|
||||||
if (!profile) return;
|
if (!profile) return;
|
||||||
captureView({
|
await handleSubmitUserPersonalization(formData);
|
||||||
elementName: ONBOARDING_TRACKER_ELEMENTS.PROFILE_SETUP_FORM,
|
handleStepChange(EOnboardingSteps.ROLE_SETUP);
|
||||||
});
|
|
||||||
await handleSubmitUserPersonalization(formData).then(() => {
|
|
||||||
handleStepChange(EOnboardingSteps.ROLE_SETUP);
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSkip = () => {
|
const handleSkip = () => {
|
||||||
|
|
|
||||||
|
|
@ -9,26 +9,19 @@ import type {
|
||||||
UseFormWatch,
|
UseFormWatch,
|
||||||
} from "react-hook-form";
|
} from "react-hook-form";
|
||||||
import { Controller, useFieldArray, useForm } from "react-hook-form";
|
import { Controller, useFieldArray, useForm } from "react-hook-form";
|
||||||
// icons
|
|
||||||
import { usePopper } from "react-popper";
|
import { usePopper } from "react-popper";
|
||||||
import { XCircle } from "lucide-react";
|
import { XCircle } from "lucide-react";
|
||||||
import { Listbox } from "@headlessui/react";
|
import { Listbox } from "@headlessui/react";
|
||||||
// plane imports
|
// plane imports
|
||||||
import type { EUserPermissions } from "@plane/constants";
|
import type { EUserPermissions } from "@plane/constants";
|
||||||
import { ROLE, ROLE_DETAILS, MEMBER_TRACKER_EVENTS, MEMBER_TRACKER_ELEMENTS } from "@plane/constants";
|
import { ROLE, ROLE_DETAILS } from "@plane/constants";
|
||||||
import { useTranslation } from "@plane/i18n";
|
import { useTranslation } from "@plane/i18n";
|
||||||
import { Button } from "@plane/propel/button";
|
import { Button } from "@plane/propel/button";
|
||||||
import { PlusIcon, CheckIcon, ChevronDownIcon } from "@plane/propel/icons";
|
import { PlusIcon, CheckIcon, ChevronDownIcon } from "@plane/propel/icons";
|
||||||
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
||||||
// types
|
|
||||||
import { EOnboardingSteps } from "@plane/types";
|
import { EOnboardingSteps } from "@plane/types";
|
||||||
// ui
|
|
||||||
import { Input, Spinner } from "@plane/ui";
|
import { Input, Spinner } from "@plane/ui";
|
||||||
// constants
|
|
||||||
// helpers
|
|
||||||
|
|
||||||
// hooks
|
// hooks
|
||||||
import { captureError, captureSuccess } from "@/helpers/event-tracker.helper";
|
|
||||||
import { useWorkspace } from "@/hooks/store/use-workspace";
|
import { useWorkspace } from "@/hooks/store/use-workspace";
|
||||||
// services
|
// services
|
||||||
import { WorkspaceService } from "@/plane-web/services";
|
import { WorkspaceService } from "@/plane-web/services";
|
||||||
|
|
@ -299,28 +292,14 @@ export const InviteTeamStep = observer(function InviteTeamStep(props: Props) {
|
||||||
})),
|
})),
|
||||||
})
|
})
|
||||||
.then(async () => {
|
.then(async () => {
|
||||||
captureSuccess({
|
|
||||||
eventName: MEMBER_TRACKER_EVENTS.invite,
|
|
||||||
payload: {
|
|
||||||
workspace: workspace.slug,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
setToast({
|
setToast({
|
||||||
type: TOAST_TYPE.SUCCESS,
|
type: TOAST_TYPE.SUCCESS,
|
||||||
title: "Success!",
|
title: "Success!",
|
||||||
message: "Invitations sent successfully.",
|
message: "Invitations sent successfully.",
|
||||||
});
|
});
|
||||||
|
|
||||||
await nextStep();
|
await nextStep();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
captureError({
|
|
||||||
eventName: MEMBER_TRACKER_EVENTS.invite,
|
|
||||||
payload: {
|
|
||||||
workspace: workspace.slug,
|
|
||||||
},
|
|
||||||
error: err,
|
|
||||||
});
|
|
||||||
setToast({
|
setToast({
|
||||||
type: TOAST_TYPE.ERROR,
|
type: TOAST_TYPE.ERROR,
|
||||||
title: "Error!",
|
title: "Error!",
|
||||||
|
|
@ -399,7 +378,6 @@ export const InviteTeamStep = observer(function InviteTeamStep(props: Props) {
|
||||||
size="xl"
|
size="xl"
|
||||||
className="w-full"
|
className="w-full"
|
||||||
disabled={isInvitationDisabled || !isValid || isSubmitting}
|
disabled={isInvitationDisabled || !isValid || isSubmitting}
|
||||||
data-ph-element={MEMBER_TRACKER_ELEMENTS.ONBOARDING_INVITE_MEMBER}
|
|
||||||
>
|
>
|
||||||
{isSubmitting ? <Spinner height="20px" width="20px" /> : "Continue"}
|
{isSubmitting ? <Spinner height="20px" width="20px" /> : "Continue"}
|
||||||
</Button>
|
</Button>
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,13 @@
|
||||||
import type { FC } from "react";
|
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
import { Controller, useForm } from "react-hook-form";
|
import { Controller, useForm } from "react-hook-form";
|
||||||
|
|
||||||
// plane imports
|
// plane imports
|
||||||
import { ONBOARDING_TRACKER_ELEMENTS, USER_TRACKER_EVENTS, USE_CASES } from "@plane/constants";
|
import { USE_CASES } from "@plane/constants";
|
||||||
import { Button } from "@plane/propel/button";
|
import { Button } from "@plane/propel/button";
|
||||||
import { CheckIcon } from "@plane/propel/icons";
|
import { CheckIcon } from "@plane/propel/icons";
|
||||||
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
||||||
import type { TUserProfile } from "@plane/types";
|
import type { TUserProfile } from "@plane/types";
|
||||||
import { EOnboardingSteps } from "@plane/types";
|
import { EOnboardingSteps } from "@plane/types";
|
||||||
import { cn } from "@plane/utils";
|
import { cn } from "@plane/utils";
|
||||||
// helpers
|
|
||||||
import { captureError, captureSuccess, captureView } from "@/helpers/event-tracker.helper";
|
|
||||||
// hooks
|
// hooks
|
||||||
import { useUserProfile } from "@/hooks/store/user";
|
import { useUserProfile } from "@/hooks/store/user";
|
||||||
// local imports
|
// local imports
|
||||||
|
|
@ -52,21 +48,12 @@ export const UseCaseSetupStep = observer(function UseCaseSetupStep({ handleStepC
|
||||||
updateUserProfile(profileUpdatePayload),
|
updateUserProfile(profileUpdatePayload),
|
||||||
// totalSteps > 2 && stepChange({ profile_complete: true }),
|
// totalSteps > 2 && stepChange({ profile_complete: true }),
|
||||||
]);
|
]);
|
||||||
captureSuccess({
|
|
||||||
eventName: USER_TRACKER_EVENTS.add_details,
|
|
||||||
payload: {
|
|
||||||
use_case: profileUpdatePayload.use_case,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
setToast({
|
setToast({
|
||||||
type: TOAST_TYPE.SUCCESS,
|
type: TOAST_TYPE.SUCCESS,
|
||||||
title: "Success",
|
title: "Success",
|
||||||
message: "Profile setup completed!",
|
message: "Profile setup completed!",
|
||||||
});
|
});
|
||||||
} catch {
|
} catch {
|
||||||
captureError({
|
|
||||||
eventName: USER_TRACKER_EVENTS.add_details,
|
|
||||||
});
|
|
||||||
setToast({
|
setToast({
|
||||||
type: TOAST_TYPE.ERROR,
|
type: TOAST_TYPE.ERROR,
|
||||||
title: "Error",
|
title: "Error",
|
||||||
|
|
@ -78,12 +65,8 @@ export const UseCaseSetupStep = observer(function UseCaseSetupStep({ handleStepC
|
||||||
// on submit
|
// on submit
|
||||||
const onSubmit = async (formData: TProfileSetupFormValues) => {
|
const onSubmit = async (formData: TProfileSetupFormValues) => {
|
||||||
if (!profile) return;
|
if (!profile) return;
|
||||||
captureView({
|
await handleSubmitUserPersonalization(formData);
|
||||||
elementName: ONBOARDING_TRACKER_ELEMENTS.PROFILE_SETUP_FORM,
|
handleStepChange(EOnboardingSteps.USE_CASE_SETUP);
|
||||||
});
|
|
||||||
await handleSubmitUserPersonalization(formData).then(() => {
|
|
||||||
handleStepChange(EOnboardingSteps.USE_CASE_SETUP);
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// handle skip
|
// handle skip
|
||||||
|
|
|
||||||
|
|
@ -3,20 +3,13 @@ import { observer } from "mobx-react";
|
||||||
import { Controller, useForm } from "react-hook-form";
|
import { Controller, useForm } from "react-hook-form";
|
||||||
import { CircleCheck } from "lucide-react";
|
import { CircleCheck } from "lucide-react";
|
||||||
// plane imports
|
// plane imports
|
||||||
import {
|
import { ORGANIZATION_SIZE, RESTRICTED_URLS } from "@plane/constants";
|
||||||
ORGANIZATION_SIZE,
|
|
||||||
RESTRICTED_URLS,
|
|
||||||
WORKSPACE_TRACKER_ELEMENTS,
|
|
||||||
WORKSPACE_TRACKER_EVENTS,
|
|
||||||
} from "@plane/constants";
|
|
||||||
import { useTranslation } from "@plane/i18n";
|
import { useTranslation } from "@plane/i18n";
|
||||||
import { Button } from "@plane/propel/button";
|
import { Button } from "@plane/propel/button";
|
||||||
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
||||||
import type { IUser, IWorkspace } from "@plane/types";
|
import type { IUser, IWorkspace } from "@plane/types";
|
||||||
import { Spinner } from "@plane/ui";
|
import { Spinner } from "@plane/ui";
|
||||||
import { cn } from "@plane/utils";
|
import { cn } from "@plane/utils";
|
||||||
// helpers
|
|
||||||
import { captureError, captureSuccess } from "@/helpers/event-tracker.helper";
|
|
||||||
// hooks
|
// hooks
|
||||||
import { useWorkspace } from "@/hooks/store/use-workspace";
|
import { useWorkspace } from "@/hooks/store/use-workspace";
|
||||||
import { useUserProfile, useUserSettings } from "@/hooks/store/user";
|
import { useUserProfile, useUserSettings } from "@/hooks/store/user";
|
||||||
|
|
@ -82,19 +75,10 @@ export const WorkspaceCreateStep = observer(function WorkspaceCreateStep({
|
||||||
title: t("workspace_creation.toast.success.title"),
|
title: t("workspace_creation.toast.success.title"),
|
||||||
message: t("workspace_creation.toast.success.message"),
|
message: t("workspace_creation.toast.success.message"),
|
||||||
});
|
});
|
||||||
captureSuccess({
|
|
||||||
eventName: WORKSPACE_TRACKER_EVENTS.create,
|
|
||||||
payload: { slug: formData.slug },
|
|
||||||
});
|
|
||||||
await fetchWorkspaces();
|
await fetchWorkspaces();
|
||||||
await completeStep(workspaceResponse.id);
|
await completeStep(workspaceResponse.id);
|
||||||
onComplete(formData.organization_size === "Just myself");
|
onComplete(formData.organization_size === "Just myself");
|
||||||
} catch {
|
} catch {
|
||||||
captureError({
|
|
||||||
eventName: WORKSPACE_TRACKER_EVENTS.create,
|
|
||||||
payload: { slug: formData.slug },
|
|
||||||
error: new Error("Error creating workspace"),
|
|
||||||
});
|
|
||||||
setToast({
|
setToast({
|
||||||
type: TOAST_TYPE.ERROR,
|
type: TOAST_TYPE.ERROR,
|
||||||
title: t("workspace_creation.toast.error.title"),
|
title: t("workspace_creation.toast.error.title"),
|
||||||
|
|
@ -299,14 +283,7 @@ export const WorkspaceCreateStep = observer(function WorkspaceCreateStep({
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-col gap-4">
|
<div className="flex flex-col gap-4">
|
||||||
<Button
|
<Button variant="primary" type="submit" size="xl" className="w-full" disabled={isButtonDisabled}>
|
||||||
data-ph-element={WORKSPACE_TRACKER_ELEMENTS.ONBOARDING_CREATE_WORKSPACE_BUTTON}
|
|
||||||
variant="primary"
|
|
||||||
type="submit"
|
|
||||||
size="xl"
|
|
||||||
className="w-full"
|
|
||||||
disabled={isButtonDisabled}
|
|
||||||
>
|
|
||||||
{isSubmitting ? <Spinner height="20px" width="20px" /> : t("workspace_creation.button.default")}
|
{isSubmitting ? <Spinner height="20px" width="20px" /> : t("workspace_creation.button.default")}
|
||||||
</Button>
|
</Button>
|
||||||
{hasInvitations && (
|
{hasInvitations && (
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,12 @@
|
||||||
import React, { useState } from "react";
|
import { useState } from "react";
|
||||||
// plane imports
|
// plane imports
|
||||||
import { MEMBER_TRACKER_ELEMENTS, MEMBER_TRACKER_EVENTS, ROLE } from "@plane/constants";
|
import { ROLE } from "@plane/constants";
|
||||||
import { Button } from "@plane/propel/button";
|
import { Button } from "@plane/propel/button";
|
||||||
import type { IWorkspaceMemberInvitation } from "@plane/types";
|
import type { IWorkspaceMemberInvitation } from "@plane/types";
|
||||||
import { Checkbox, Spinner } from "@plane/ui";
|
import { Checkbox, Spinner } from "@plane/ui";
|
||||||
import { truncateText } from "@plane/utils";
|
import { truncateText } from "@plane/utils";
|
||||||
// constants
|
// constants
|
||||||
import { WorkspaceLogo } from "@/components/workspace/logo";
|
import { WorkspaceLogo } from "@/components/workspace/logo";
|
||||||
// helpers
|
|
||||||
import { captureError, captureSuccess } from "@/helpers/event-tracker.helper";
|
|
||||||
// hooks
|
// hooks
|
||||||
import { useWorkspace } from "@/hooks/store/use-workspace";
|
import { useWorkspace } from "@/hooks/store/use-workspace";
|
||||||
import { useUserSettings } from "@/hooks/store/user";
|
import { useUserSettings } from "@/hooks/store/user";
|
||||||
|
|
@ -52,24 +50,11 @@ export function WorkspaceJoinInvitesStep(props: Props) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await workspaceService.joinWorkspaces({ invitations: invitationsRespond });
|
await workspaceService.joinWorkspaces({ invitations: invitationsRespond });
|
||||||
captureSuccess({
|
|
||||||
eventName: MEMBER_TRACKER_EVENTS.accept,
|
|
||||||
payload: {
|
|
||||||
member_id: invitation?.id,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
await fetchWorkspaces();
|
await fetchWorkspaces();
|
||||||
await fetchCurrentUserSettings();
|
await fetchCurrentUserSettings();
|
||||||
await handleNextStep();
|
await handleNextStep();
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
captureError({
|
|
||||||
eventName: MEMBER_TRACKER_EVENTS.accept,
|
|
||||||
payload: {
|
|
||||||
member_id: invitation?.id,
|
|
||||||
},
|
|
||||||
error: error,
|
|
||||||
});
|
|
||||||
setIsJoiningWorkspaces(false);
|
setIsJoiningWorkspaces(false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -114,7 +99,6 @@ export function WorkspaceJoinInvitesStep(props: Props) {
|
||||||
className="w-full"
|
className="w-full"
|
||||||
onClick={submitInvitations}
|
onClick={submitInvitations}
|
||||||
disabled={isJoiningWorkspaces || !invitationsRespond.length}
|
disabled={isJoiningWorkspaces || !invitationsRespond.length}
|
||||||
data-ph-element={MEMBER_TRACKER_ELEMENTS.ONBOARDING_JOIN_WORKSPACE}
|
|
||||||
>
|
>
|
||||||
{isJoiningWorkspaces ? <Spinner height="20px" width="20px" /> : "Continue"}
|
{isJoiningWorkspaces ? <Spinner height="20px" width="20px" /> : "Continue"}
|
||||||
</Button>
|
</Button>
|
||||||
|
|
|
||||||
|
|
@ -3,9 +3,8 @@ import { observer } from "mobx-react";
|
||||||
import { useParams } from "next/navigation";
|
import { useParams } from "next/navigation";
|
||||||
import { ArchiveRestoreIcon, FileOutput, LockKeyhole, LockKeyholeOpen } from "lucide-react";
|
import { ArchiveRestoreIcon, FileOutput, LockKeyhole, LockKeyholeOpen } from "lucide-react";
|
||||||
// constants
|
// constants
|
||||||
import { EPageAccess, PROJECT_PAGE_TRACKER_ELEMENTS } from "@plane/constants";
|
import { EPageAccess } from "@plane/constants";
|
||||||
// plane editor
|
// plane editor
|
||||||
import type { EditorRefApi } from "@plane/editor";
|
|
||||||
import { LinkIcon, CopyIcon, LockIcon, NewTabIcon, ArchiveIcon, TrashIcon, GlobeIcon } from "@plane/propel/icons";
|
import { LinkIcon, CopyIcon, LockIcon, NewTabIcon, ArchiveIcon, TrashIcon, GlobeIcon } from "@plane/propel/icons";
|
||||||
// plane ui
|
// plane ui
|
||||||
import type { TContextMenuItem } from "@plane/ui";
|
import type { TContextMenuItem } from "@plane/ui";
|
||||||
|
|
@ -13,9 +12,7 @@ import { ContextMenu, CustomMenu } from "@plane/ui";
|
||||||
// components
|
// components
|
||||||
import { cn } from "@plane/utils";
|
import { cn } from "@plane/utils";
|
||||||
import { DeletePageModal } from "@/components/pages/modals/delete-page-modal";
|
import { DeletePageModal } from "@/components/pages/modals/delete-page-modal";
|
||||||
// helpers
|
|
||||||
// hooks
|
// hooks
|
||||||
import { captureClick } from "@/helpers/event-tracker.helper";
|
|
||||||
import { usePageOperations } from "@/hooks/use-page-operations";
|
import { usePageOperations } from "@/hooks/use-page-operations";
|
||||||
// plane web components
|
// plane web components
|
||||||
import { MovePageModal } from "@/plane-web/components/pages";
|
import { MovePageModal } from "@/plane-web/components/pages";
|
||||||
|
|
@ -82,9 +79,6 @@ export const PageActions = observer(function PageActions(props: Props) {
|
||||||
{
|
{
|
||||||
key: "toggle-lock",
|
key: "toggle-lock",
|
||||||
action: () => {
|
action: () => {
|
||||||
captureClick({
|
|
||||||
elementName: PROJECT_PAGE_TRACKER_ELEMENTS.LOCK_BUTTON,
|
|
||||||
});
|
|
||||||
pageOperations.toggleLock();
|
pageOperations.toggleLock();
|
||||||
},
|
},
|
||||||
title: is_locked ? "Unlock" : "Lock",
|
title: is_locked ? "Unlock" : "Lock",
|
||||||
|
|
@ -94,9 +88,6 @@ export const PageActions = observer(function PageActions(props: Props) {
|
||||||
{
|
{
|
||||||
key: "toggle-access",
|
key: "toggle-access",
|
||||||
action: () => {
|
action: () => {
|
||||||
captureClick({
|
|
||||||
elementName: PROJECT_PAGE_TRACKER_ELEMENTS.ACCESS_TOGGLE,
|
|
||||||
});
|
|
||||||
pageOperations.toggleAccess();
|
pageOperations.toggleAccess();
|
||||||
},
|
},
|
||||||
title: access === EPageAccess.PUBLIC ? "Make private" : "Make public",
|
title: access === EPageAccess.PUBLIC ? "Make private" : "Make public",
|
||||||
|
|
@ -120,9 +111,6 @@ export const PageActions = observer(function PageActions(props: Props) {
|
||||||
{
|
{
|
||||||
key: "make-a-copy",
|
key: "make-a-copy",
|
||||||
action: () => {
|
action: () => {
|
||||||
captureClick({
|
|
||||||
elementName: PROJECT_PAGE_TRACKER_ELEMENTS.DUPLICATE_BUTTON,
|
|
||||||
});
|
|
||||||
pageOperations.duplicate();
|
pageOperations.duplicate();
|
||||||
},
|
},
|
||||||
title: "Make a copy",
|
title: "Make a copy",
|
||||||
|
|
@ -132,9 +120,6 @@ export const PageActions = observer(function PageActions(props: Props) {
|
||||||
{
|
{
|
||||||
key: "archive-restore",
|
key: "archive-restore",
|
||||||
action: () => {
|
action: () => {
|
||||||
captureClick({
|
|
||||||
elementName: PROJECT_PAGE_TRACKER_ELEMENTS.ARCHIVE_BUTTON,
|
|
||||||
});
|
|
||||||
pageOperations.toggleArchive();
|
pageOperations.toggleArchive();
|
||||||
},
|
},
|
||||||
title: archived_at ? "Restore" : "Archive",
|
title: archived_at ? "Restore" : "Archive",
|
||||||
|
|
@ -144,9 +129,6 @@ export const PageActions = observer(function PageActions(props: Props) {
|
||||||
{
|
{
|
||||||
key: "delete",
|
key: "delete",
|
||||||
action: () => {
|
action: () => {
|
||||||
captureClick({
|
|
||||||
elementName: PROJECT_PAGE_TRACKER_ELEMENTS.CONTEXT_MENU,
|
|
||||||
});
|
|
||||||
setDeletePageModal(true);
|
setDeletePageModal(true);
|
||||||
},
|
},
|
||||||
title: "Delete",
|
title: "Delete",
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,7 @@
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
import { Star } from "lucide-react";
|
import { Star } from "lucide-react";
|
||||||
// constants
|
|
||||||
import { PROJECT_PAGE_TRACKER_ELEMENTS } from "@plane/constants";
|
|
||||||
// ui
|
// ui
|
||||||
import { IconButton } from "@plane/propel/icon-button";
|
import { IconButton } from "@plane/propel/icon-button";
|
||||||
// helpers
|
|
||||||
import { captureClick } from "@/helpers/event-tracker.helper";
|
|
||||||
// hooks
|
// hooks
|
||||||
import { usePageOperations } from "@/hooks/use-page-operations";
|
import { usePageOperations } from "@/hooks/use-page-operations";
|
||||||
// store
|
// store
|
||||||
|
|
@ -31,9 +27,6 @@ export const PageFavoriteControl = observer(function PageFavoriteControl({ page
|
||||||
size="lg"
|
size="lg"
|
||||||
icon={Star}
|
icon={Star}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
captureClick({
|
|
||||||
elementName: PROJECT_PAGE_TRACKER_ELEMENTS.FAVORITE_BUTTON,
|
|
||||||
});
|
|
||||||
pageOperations.toggleFavorite();
|
pageOperations.toggleFavorite();
|
||||||
}}
|
}}
|
||||||
aria-label={is_favorite ? "Remove favorite" : "Add to favorites"}
|
aria-label={is_favorite ? "Remove favorite" : "Add to favorites"}
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,10 @@
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
import { Earth, Info, Minus } from "lucide-react";
|
import { Earth, Info, Minus } from "lucide-react";
|
||||||
// plane imports
|
// plane imports
|
||||||
import { PROJECT_PAGE_TRACKER_ELEMENTS } from "@plane/constants";
|
|
||||||
import { LockIcon } from "@plane/propel/icons";
|
import { LockIcon } from "@plane/propel/icons";
|
||||||
import { Tooltip } from "@plane/propel/tooltip";
|
import { Tooltip } from "@plane/propel/tooltip";
|
||||||
import { Avatar, FavoriteStar } from "@plane/ui";
|
import { Avatar, FavoriteStar } from "@plane/ui";
|
||||||
import { renderFormattedDate, getFileURL } from "@plane/utils";
|
import { renderFormattedDate, getFileURL } from "@plane/utils";
|
||||||
// helpers
|
|
||||||
import { captureClick } from "@/helpers/event-tracker.helper";
|
|
||||||
// hooks
|
// hooks
|
||||||
import { useMember } from "@/hooks/store/use-member";
|
import { useMember } from "@/hooks/store/use-member";
|
||||||
import { usePageOperations } from "@/hooks/use-page-operations";
|
import { usePageOperations } from "@/hooks/use-page-operations";
|
||||||
|
|
@ -65,9 +62,6 @@ export const BlockItemAction = observer(function BlockItemAction(props: Props) {
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
captureClick({
|
|
||||||
elementName: PROJECT_PAGE_TRACKER_ELEMENTS.FAVORITE_BUTTON,
|
|
||||||
});
|
|
||||||
pageOperations.toggleFavorite();
|
pageOperations.toggleFavorite();
|
||||||
}}
|
}}
|
||||||
selected={is_favorite}
|
selected={is_favorite}
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,10 @@
|
||||||
import type { FC } from "react";
|
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
// constants
|
// constants
|
||||||
import type { EPageAccess } from "@plane/constants";
|
import type { EPageAccess } from "@plane/constants";
|
||||||
import { PROJECT_PAGE_TRACKER_EVENTS } from "@plane/constants";
|
|
||||||
import type { TPage } from "@plane/types";
|
import type { TPage } from "@plane/types";
|
||||||
// ui
|
// ui
|
||||||
import { EModalPosition, EModalWidth, ModalCore } from "@plane/ui";
|
import { EModalPosition, EModalWidth, ModalCore } from "@plane/ui";
|
||||||
// hooks
|
// hooks
|
||||||
import { captureSuccess, captureError } from "@/helpers/event-tracker.helper";
|
|
||||||
import { useAppRouter } from "@/hooks/use-app-router";
|
import { useAppRouter } from "@/hooks/use-app-router";
|
||||||
// plane web hooks
|
// plane web hooks
|
||||||
import type { EPageStoreType } from "@/plane-web/hooks/store";
|
import type { EPageStoreType } from "@/plane-web/hooks/store";
|
||||||
|
|
@ -64,20 +61,11 @@ export function CreatePageModal(props: Props) {
|
||||||
try {
|
try {
|
||||||
const pageData = await createPage(pageFormData);
|
const pageData = await createPage(pageFormData);
|
||||||
if (pageData) {
|
if (pageData) {
|
||||||
captureSuccess({
|
|
||||||
eventName: PROJECT_PAGE_TRACKER_EVENTS.create,
|
|
||||||
payload: {
|
|
||||||
id: pageData.id,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
handleStateClear();
|
handleStateClear();
|
||||||
if (redirectionEnabled) router.push(`/${workspaceSlug}/projects/${projectId}/pages/${pageData.id}`);
|
if (redirectionEnabled) router.push(`/${workspaceSlug}/projects/${projectId}/pages/${pageData.id}`);
|
||||||
}
|
}
|
||||||
} catch (error: any) {
|
} catch (error) {
|
||||||
captureError({
|
console.error(error);
|
||||||
eventName: PROJECT_PAGE_TRACKER_EVENTS.create,
|
|
||||||
error,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,13 +2,10 @@ import { useState } from "react";
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
// ui
|
// ui
|
||||||
import { useParams } from "next/navigation";
|
import { useParams } from "next/navigation";
|
||||||
import { PROJECT_PAGE_TRACKER_EVENTS } from "@plane/constants";
|
|
||||||
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
||||||
import { AlertModalCore } from "@plane/ui";
|
import { AlertModalCore } from "@plane/ui";
|
||||||
import { getPageName } from "@plane/utils";
|
import { getPageName } from "@plane/utils";
|
||||||
// constants
|
// constants
|
||||||
// hooks
|
|
||||||
import { captureError, captureSuccess } from "@/helpers/event-tracker.helper";
|
|
||||||
// plane web hooks
|
// plane web hooks
|
||||||
import { useAppRouter } from "@/hooks/use-app-router";
|
import { useAppRouter } from "@/hooks/use-app-router";
|
||||||
import type { EPageStoreType } from "@/plane-web/hooks/store";
|
import type { EPageStoreType } from "@/plane-web/hooks/store";
|
||||||
|
|
@ -46,12 +43,6 @@ export const DeletePageModal = observer(function DeletePageModal(props: TConfirm
|
||||||
setIsDeleting(true);
|
setIsDeleting(true);
|
||||||
await removePage({ pageId })
|
await removePage({ pageId })
|
||||||
.then(() => {
|
.then(() => {
|
||||||
captureSuccess({
|
|
||||||
eventName: PROJECT_PAGE_TRACKER_EVENTS.delete,
|
|
||||||
payload: {
|
|
||||||
id: pageId,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
handleClose();
|
handleClose();
|
||||||
setToast({
|
setToast({
|
||||||
type: TOAST_TYPE.SUCCESS,
|
type: TOAST_TYPE.SUCCESS,
|
||||||
|
|
@ -64,12 +55,6 @@ export const DeletePageModal = observer(function DeletePageModal(props: TConfirm
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
captureError({
|
|
||||||
eventName: PROJECT_PAGE_TRACKER_EVENTS.delete,
|
|
||||||
payload: {
|
|
||||||
id: pageId,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
setToast({
|
setToast({
|
||||||
type: TOAST_TYPE.ERROR,
|
type: TOAST_TYPE.ERROR,
|
||||||
title: "Error!",
|
title: "Error!",
|
||||||
|
|
|
||||||
|
|
@ -2,12 +2,7 @@ import { useState } from "react";
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
// plane imports
|
// plane imports
|
||||||
import { useParams, useRouter } from "next/navigation";
|
import { useParams, useRouter } from "next/navigation";
|
||||||
import {
|
import { EUserPermissionsLevel, EPageAccess } from "@plane/constants";
|
||||||
EUserPermissionsLevel,
|
|
||||||
EPageAccess,
|
|
||||||
PROJECT_PAGE_TRACKER_ELEMENTS,
|
|
||||||
PROJECT_PAGE_TRACKER_EVENTS,
|
|
||||||
} from "@plane/constants";
|
|
||||||
import { useTranslation } from "@plane/i18n";
|
import { useTranslation } from "@plane/i18n";
|
||||||
import { EmptyStateDetailed } from "@plane/propel/empty-state";
|
import { EmptyStateDetailed } from "@plane/propel/empty-state";
|
||||||
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
||||||
|
|
@ -15,7 +10,6 @@ import type { TPage, TPageNavigationTabs } from "@plane/types";
|
||||||
import { EUserProjectRoles } from "@plane/types";
|
import { EUserProjectRoles } from "@plane/types";
|
||||||
// components
|
// components
|
||||||
import { PageLoader } from "@/components/pages/loaders/page-loader";
|
import { PageLoader } from "@/components/pages/loaders/page-loader";
|
||||||
import { captureClick, captureError, captureSuccess } from "@/helpers/event-tracker.helper";
|
|
||||||
import { useProject } from "@/hooks/store/use-project";
|
import { useProject } from "@/hooks/store/use-project";
|
||||||
import { useUserPermissions } from "@/hooks/store/user";
|
import { useUserPermissions } from "@/hooks/store/user";
|
||||||
// plane web hooks
|
// plane web hooks
|
||||||
|
|
@ -60,23 +54,10 @@ export const PagesListMainContent = observer(function PagesListMainContent(props
|
||||||
|
|
||||||
await createPage(payload)
|
await createPage(payload)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
captureSuccess({
|
|
||||||
eventName: PROJECT_PAGE_TRACKER_EVENTS.create,
|
|
||||||
payload: {
|
|
||||||
id: res?.id,
|
|
||||||
state: "SUCCESS",
|
|
||||||
},
|
|
||||||
});
|
|
||||||
const pageId = `/${workspaceSlug}/projects/${currentProjectDetails?.id}/pages/${res?.id}`;
|
const pageId = `/${workspaceSlug}/projects/${currentProjectDetails?.id}/pages/${res?.id}`;
|
||||||
router.push(pageId);
|
router.push(pageId);
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
captureError({
|
|
||||||
eventName: PROJECT_PAGE_TRACKER_EVENTS.create,
|
|
||||||
payload: {
|
|
||||||
state: "ERROR",
|
|
||||||
},
|
|
||||||
});
|
|
||||||
setToast({
|
setToast({
|
||||||
type: TOAST_TYPE.ERROR,
|
type: TOAST_TYPE.ERROR,
|
||||||
title: "Error!",
|
title: "Error!",
|
||||||
|
|
@ -100,7 +81,6 @@ export const PagesListMainContent = observer(function PagesListMainContent(props
|
||||||
label: t("project_empty_state.pages.cta_primary"),
|
label: t("project_empty_state.pages.cta_primary"),
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
handleCreatePage();
|
handleCreatePage();
|
||||||
captureClick({ elementName: PROJECT_PAGE_TRACKER_ELEMENTS.EMPTY_STATE_CREATE_BUTTON });
|
|
||||||
},
|
},
|
||||||
variant: "primary",
|
variant: "primary",
|
||||||
disabled: !canPerformEmptyStateActions || isCreatingPage,
|
disabled: !canPerformEmptyStateActions || isCreatingPage,
|
||||||
|
|
@ -120,7 +100,6 @@ export const PagesListMainContent = observer(function PagesListMainContent(props
|
||||||
label: t("project_empty_state.pages.cta_primary"),
|
label: t("project_empty_state.pages.cta_primary"),
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
handleCreatePage();
|
handleCreatePage();
|
||||||
captureClick({ elementName: PROJECT_PAGE_TRACKER_ELEMENTS.EMPTY_STATE_CREATE_BUTTON });
|
|
||||||
},
|
},
|
||||||
variant: "primary",
|
variant: "primary",
|
||||||
disabled: !canPerformEmptyStateActions || isCreatingPage,
|
disabled: !canPerformEmptyStateActions || isCreatingPage,
|
||||||
|
|
@ -139,7 +118,6 @@ export const PagesListMainContent = observer(function PagesListMainContent(props
|
||||||
label: t("project_empty_state.pages.cta_primary"),
|
label: t("project_empty_state.pages.cta_primary"),
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
handleCreatePage();
|
handleCreatePage();
|
||||||
captureClick({ elementName: PROJECT_PAGE_TRACKER_ELEMENTS.EMPTY_STATE_CREATE_BUTTON });
|
|
||||||
},
|
},
|
||||||
variant: "primary",
|
variant: "primary",
|
||||||
disabled: !canPerformEmptyStateActions || isCreatingPage,
|
disabled: !canPerformEmptyStateActions || isCreatingPage,
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@ import { Controller, useForm } from "react-hook-form";
|
||||||
import { CircleUserRound } from "lucide-react";
|
import { CircleUserRound } from "lucide-react";
|
||||||
import { Disclosure, Transition } from "@headlessui/react";
|
import { Disclosure, Transition } from "@headlessui/react";
|
||||||
// plane imports
|
// plane imports
|
||||||
import { PROFILE_SETTINGS_TRACKER_ELEMENTS, PROFILE_SETTINGS_TRACKER_EVENTS } from "@plane/constants";
|
|
||||||
import { useTranslation } from "@plane/i18n";
|
import { useTranslation } from "@plane/i18n";
|
||||||
import { Button } from "@plane/propel/button";
|
import { Button } from "@plane/propel/button";
|
||||||
import { ChevronDownIcon } from "@plane/propel/icons";
|
import { ChevronDownIcon } from "@plane/propel/icons";
|
||||||
|
|
@ -21,7 +20,6 @@ import { UserImageUploadModal } from "@/components/core/modals/user-image-upload
|
||||||
import { CoverImage } from "@/components/common/cover-image";
|
import { CoverImage } from "@/components/common/cover-image";
|
||||||
// helpers
|
// helpers
|
||||||
import { handleCoverImageChange } from "@/helpers/cover-image.helper";
|
import { handleCoverImageChange } from "@/helpers/cover-image.helper";
|
||||||
import { captureSuccess, captureError } from "@/helpers/event-tracker.helper";
|
|
||||||
// hooks
|
// hooks
|
||||||
import { useInstance } from "@/hooks/store/use-instance";
|
import { useInstance } from "@/hooks/store/use-instance";
|
||||||
import { useUser, useUserProfile } from "@/hooks/store/user";
|
import { useUser, useUserProfile } from "@/hooks/store/user";
|
||||||
|
|
@ -164,16 +162,9 @@ export const ProfileForm = observer(function ProfileForm(props: TProfileFormProp
|
||||||
});
|
});
|
||||||
updateUserAndProfile
|
updateUserAndProfile
|
||||||
.then(() => {
|
.then(() => {
|
||||||
captureSuccess({
|
|
||||||
eventName: PROFILE_SETTINGS_TRACKER_EVENTS.update_profile,
|
|
||||||
});
|
|
||||||
return;
|
return;
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {});
|
||||||
captureError({
|
|
||||||
eventName: PROFILE_SETTINGS_TRACKER_EVENTS.update_profile,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
@ -385,12 +376,7 @@ export const ProfileForm = observer(function ProfileForm(props: TProfileFormProp
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-col gap-1">
|
<div className="flex flex-col gap-1">
|
||||||
<div className="flex items-center justify-between pt-6 pb-8">
|
<div className="flex items-center justify-between pt-6 pb-8">
|
||||||
<Button
|
<Button variant="primary" type="submit" loading={isLoading}>
|
||||||
variant="primary"
|
|
||||||
type="submit"
|
|
||||||
loading={isLoading}
|
|
||||||
data-ph-element={PROFILE_SETTINGS_TRACKER_ELEMENTS.SAVE_CHANGES_BUTTON}
|
|
||||||
>
|
|
||||||
{isLoading ? t("saving") : t("save_changes")}
|
{isLoading ? t("saving") : t("save_changes")}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -417,11 +403,7 @@ export const ProfileForm = observer(function ProfileForm(props: TProfileFormProp
|
||||||
<div className="flex flex-col gap-8">
|
<div className="flex flex-col gap-8">
|
||||||
<span className="text-13 tracking-tight">{t("deactivate_account_description")}</span>
|
<span className="text-13 tracking-tight">{t("deactivate_account_description")}</span>
|
||||||
<div>
|
<div>
|
||||||
<Button
|
<Button variant="error-fill" onClick={() => setDeactivateAccountModal(true)}>
|
||||||
variant="error-fill"
|
|
||||||
onClick={() => setDeactivateAccountModal(true)}
|
|
||||||
data-ph-element={PROFILE_SETTINGS_TRACKER_ELEMENTS.DEACTIVATE_ACCOUNT_BUTTON}
|
|
||||||
>
|
|
||||||
{t("deactivate_account")}
|
{t("deactivate_account")}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,11 @@
|
||||||
import type { FC } from "react";
|
import { useEffect } from "react";
|
||||||
import React, { useEffect } from "react";
|
|
||||||
import { Controller, useForm } from "react-hook-form";
|
import { Controller, useForm } from "react-hook-form";
|
||||||
import { PROFILE_SETTINGS_TRACKER_ELEMENTS, PROFILE_SETTINGS_TRACKER_EVENTS } from "@plane/constants";
|
|
||||||
import { useTranslation } from "@plane/i18n";
|
import { useTranslation } from "@plane/i18n";
|
||||||
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
||||||
import type { IUserEmailNotificationSettings } from "@plane/types";
|
import type { IUserEmailNotificationSettings } from "@plane/types";
|
||||||
// ui
|
// ui
|
||||||
import { ToggleSwitch } from "@plane/ui";
|
import { ToggleSwitch } from "@plane/ui";
|
||||||
// services
|
// services
|
||||||
import { captureClick, captureError, captureSuccess } from "@/helpers/event-tracker.helper";
|
|
||||||
import { UserService } from "@/services/user.service";
|
import { UserService } from "@/services/user.service";
|
||||||
// types
|
// types
|
||||||
interface IEmailNotificationFormProps {
|
interface IEmailNotificationFormProps {
|
||||||
|
|
@ -33,25 +30,12 @@ export function EmailNotificationForm(props: IEmailNotificationFormProps) {
|
||||||
await userService.updateCurrentUserEmailNotificationSettings({
|
await userService.updateCurrentUserEmailNotificationSettings({
|
||||||
[key]: value,
|
[key]: value,
|
||||||
});
|
});
|
||||||
captureSuccess({
|
|
||||||
eventName: PROFILE_SETTINGS_TRACKER_EVENTS.notifications_updated,
|
|
||||||
payload: {
|
|
||||||
[key]: value,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
setToast({
|
setToast({
|
||||||
title: t("success"),
|
title: t("success"),
|
||||||
type: TOAST_TYPE.SUCCESS,
|
type: TOAST_TYPE.SUCCESS,
|
||||||
message: t("email_notification_setting_updated_successfully"),
|
message: t("email_notification_setting_updated_successfully"),
|
||||||
});
|
});
|
||||||
} catch (err) {
|
} catch (_error) {
|
||||||
console.error(err);
|
|
||||||
captureError({
|
|
||||||
eventName: PROFILE_SETTINGS_TRACKER_EVENTS.notifications_updated,
|
|
||||||
payload: {
|
|
||||||
[key]: value,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
setToast({
|
setToast({
|
||||||
title: t("error"),
|
title: t("error"),
|
||||||
type: TOAST_TYPE.ERROR,
|
type: TOAST_TYPE.ERROR,
|
||||||
|
|
@ -82,9 +66,6 @@ export function EmailNotificationForm(props: IEmailNotificationFormProps) {
|
||||||
value={value}
|
value={value}
|
||||||
onChange={(newValue) => {
|
onChange={(newValue) => {
|
||||||
onChange(newValue);
|
onChange(newValue);
|
||||||
captureClick({
|
|
||||||
elementName: PROFILE_SETTINGS_TRACKER_ELEMENTS.PROPERTY_CHANGES_TOGGLE,
|
|
||||||
});
|
|
||||||
handleSettingChange("property_change", newValue);
|
handleSettingChange("property_change", newValue);
|
||||||
}}
|
}}
|
||||||
size="sm"
|
size="sm"
|
||||||
|
|
@ -107,9 +88,6 @@ export function EmailNotificationForm(props: IEmailNotificationFormProps) {
|
||||||
value={value}
|
value={value}
|
||||||
onChange={(newValue) => {
|
onChange={(newValue) => {
|
||||||
onChange(newValue);
|
onChange(newValue);
|
||||||
captureClick({
|
|
||||||
elementName: PROFILE_SETTINGS_TRACKER_ELEMENTS.STATE_CHANGES_TOGGLE,
|
|
||||||
});
|
|
||||||
handleSettingChange("state_change", newValue);
|
handleSettingChange("state_change", newValue);
|
||||||
}}
|
}}
|
||||||
size="sm"
|
size="sm"
|
||||||
|
|
@ -154,9 +132,6 @@ export function EmailNotificationForm(props: IEmailNotificationFormProps) {
|
||||||
value={value}
|
value={value}
|
||||||
onChange={(newValue) => {
|
onChange={(newValue) => {
|
||||||
onChange(newValue);
|
onChange(newValue);
|
||||||
captureClick({
|
|
||||||
elementName: PROFILE_SETTINGS_TRACKER_ELEMENTS.COMMENTS_TOGGLE,
|
|
||||||
});
|
|
||||||
handleSettingChange("comment", newValue);
|
handleSettingChange("comment", newValue);
|
||||||
}}
|
}}
|
||||||
size="sm"
|
size="sm"
|
||||||
|
|
@ -179,9 +154,6 @@ export function EmailNotificationForm(props: IEmailNotificationFormProps) {
|
||||||
value={value}
|
value={value}
|
||||||
onChange={(newValue) => {
|
onChange={(newValue) => {
|
||||||
onChange(newValue);
|
onChange(newValue);
|
||||||
captureClick({
|
|
||||||
elementName: PROFILE_SETTINGS_TRACKER_ELEMENTS.MENTIONS_TOGGLE,
|
|
||||||
});
|
|
||||||
handleSettingChange("mention", newValue);
|
handleSettingChange("mention", newValue);
|
||||||
}}
|
}}
|
||||||
size="sm"
|
size="sm"
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue