From 6f2a38ad66f60f305d871d6b694fd52c79793d81 Mon Sep 17 00:00:00 2001 From: Anmol Singh Bhatia <121005188+anmolsinghbhatia@users.noreply.github.com> Date: Tue, 6 Jun 2023 21:36:00 +0530 Subject: [PATCH] fix: bug and auth fixes (#1224) * fix: sign in and invitation page fixes * fix: project and workspace services track event fix * fix: user onboarding complete track event fix * fix: issue track event fix * fix: partial property , issue comment and mark as done issue track event fix * fix: bulk delete , move to cycle or module and issue label track event fix * fix: state , cycle and module track event fix * fix: pages and block track event fix * fix: integration , estimate , importer , analytics and gpt track event fix * fix: view track event fix * fix: build fix * fix: build fix --- .../custom-analytics/custom-analytics.tsx | 5 +- .../analytics/custom-analytics/sidebar.tsx | 6 +- .../components/analytics/project-modal.tsx | 7 +- .../command-palette/change-issue-assignee.tsx | 7 +- .../command-palette/change-issue-priority.tsx | 7 +- .../command-palette/change-issue-state.tsx | 7 +- .../command-palette/command-pallette.tsx | 17 +- .../components/core/board-view/all-boards.tsx | 5 +- .../core/board-view/single-board.tsx | 5 +- .../core/board-view/single-issue.tsx | 11 +- .../core/bulk-delete-issues-modal.tsx | 16 +- .../core/calendar-view/calendar.tsx | 17 +- .../core/calendar-view/single-date.tsx | 5 +- .../core/calendar-view/single-issue.tsx | 11 +- .../components/core/gpt-assistant-modal.tsx | 25 ++- apps/app/components/core/issues-view.tsx | 43 ++++-- .../components/core/list-view/all-lists.tsx | 5 +- .../core/list-view/single-issue.tsx | 11 +- .../components/core/list-view/single-list.tsx | 12 +- apps/app/components/cycles/cycles-view.tsx | 4 + .../components/cycles/delete-cycle-modal.tsx | 6 +- apps/app/components/cycles/modal.tsx | 8 +- apps/app/components/cycles/select.tsx | 9 +- apps/app/components/cycles/sidebar.tsx | 13 +- .../create-update-estimate-modal.tsx | 15 +- .../components/estimates/single-estimate.tsx | 6 +- .../integration/delete-import-modal.tsx | 7 +- .../components/integration/github/root.tsx | 10 +- apps/app/components/integration/guide.tsx | 9 +- apps/app/components/integration/jira/root.tsx | 10 +- apps/app/components/issues/activity.tsx | 14 +- .../components/issues/comment/add-comment.tsx | 16 +- .../components/issues/delete-issue-modal.tsx | 7 +- apps/app/components/issues/form.tsx | 25 ++- apps/app/components/issues/modal.tsx | 29 +++- .../components/issues/my-issues-list-item.tsx | 9 +- apps/app/components/issues/sidebar.tsx | 30 +++- .../app/components/issues/sub-issues-list.tsx | 7 +- .../issues/view-select/assignee.tsx | 7 +- .../issues/view-select/due-date.tsx | 13 +- .../issues/view-select/estimate.tsx | 7 +- .../issues/view-select/priority.tsx | 7 +- .../components/issues/view-select/state.tsx | 26 ++-- .../components/labels/create-label-modal.tsx | 7 +- .../labels/create-update-label-inline.tsx | 9 +- .../components/labels/delete-label-modal.tsx | 7 +- .../components/labels/labels-list-modal.tsx | 17 +- .../components/labels/single-label-group.tsx | 16 +- .../modules/delete-module-modal.tsx | 7 +- apps/app/components/modules/modal.tsx | 9 +- apps/app/components/modules/sidebar.tsx | 14 +- .../components/modules/single-module-card.tsx | 6 +- .../components/onboarding/invite-members.tsx | 7 +- apps/app/components/onboarding/workspace.tsx | 13 +- apps/app/components/pages/create-block.tsx | 20 ++- .../pages/create-update-block-inline.tsx | 66 +++++--- .../pages/create-update-page-modal.tsx | 9 +- .../components/pages/delete-page-modal.tsx | 6 +- apps/app/components/pages/pages-view.tsx | 7 +- .../components/pages/single-page-block.tsx | 66 +++++--- .../project/create-project-modal.tsx | 7 +- .../project/delete-project-modal.tsx | 6 +- .../project/send-project-invitation-modal.tsx | 7 +- apps/app/components/project/sidebar-list.tsx | 11 +- .../components/states/create-state-modal.tsx | 7 +- .../states/create-update-state-inline.tsx | 24 ++- .../components/states/delete-state-modal.tsx | 7 +- apps/app/components/states/single-state.tsx | 52 +++++-- .../components/views/delete-view-modal.tsx | 7 +- apps/app/components/views/modal.tsx | 8 +- .../workspace/create-workspace-form.tsx | 6 +- .../workspace/delete-workspace-modal.tsx | 7 +- .../send-workspace-invitation-modal.tsx | 11 +- .../workspace/single-invitation.tsx | 5 +- apps/app/contexts/issue-view.context.tsx | 101 ++++++++---- apps/app/pages/[workspaceSlug]/analytics.tsx | 10 +- .../projects/[projectId]/cycles/[cycleId].tsx | 6 +- .../projects/[projectId]/cycles/index.tsx | 4 + .../projects/[projectId]/issues/[issueId].tsx | 12 +- .../[projectId]/modules/[moduleId].tsx | 12 +- .../projects/[projectId]/modules/index.tsx | 6 + .../projects/[projectId]/pages/[pageId].tsx | 12 +- .../projects/[projectId]/pages/index.tsx | 4 + .../projects/[projectId]/settings/control.tsx | 5 +- .../[projectId]/settings/estimates.tsx | 9 +- .../[projectId]/settings/features.tsx | 8 +- .../projects/[projectId]/settings/index.tsx | 6 +- .../projects/[projectId]/settings/labels.tsx | 7 + .../projects/[projectId]/settings/members.tsx | 1 + .../projects/[projectId]/settings/states.tsx | 7 + .../projects/[projectId]/views/index.tsx | 6 + .../pages/[workspaceSlug]/projects/index.tsx | 4 + .../pages/[workspaceSlug]/settings/index.tsx | 8 +- .../[workspaceSlug]/settings/members.tsx | 1 + apps/app/pages/api/track-event.ts | 18 +-- apps/app/pages/create-workspace.tsx | 1 + apps/app/pages/index.tsx | 8 +- apps/app/pages/invitations.tsx | 2 +- apps/app/pages/magic-sign-in.tsx | 8 +- apps/app/pages/onboarding.tsx | 6 +- .../[invitationId].tsx | 13 +- apps/app/services/ai.service.ts | 7 +- apps/app/services/cycles.service.ts | 30 ++-- apps/app/services/estimates.service.ts | 21 ++- .../services/integration/github.service.ts | 7 +- apps/app/services/integration/index.ts | 12 +- apps/app/services/integration/jira.service.ts | 10 +- apps/app/services/issues.service.ts | 90 ++++++++--- apps/app/services/modules.service.ts | 36 +++-- apps/app/services/pages.service.ts | 52 +++++-- apps/app/services/project.service.ts | 32 +++- apps/app/services/state.service.ts | 30 ++-- apps/app/services/track-event.service.ts | 145 +++++++++++++++--- apps/app/services/user.service.ts | 13 +- apps/app/services/views.service.ts | 29 +++- apps/app/services/workspace.service.ts | 46 ++++-- apps/app/types/workspace.d.ts | 1 + 117 files changed, 1319 insertions(+), 494 deletions(-) diff --git a/apps/app/components/analytics/custom-analytics/custom-analytics.tsx b/apps/app/components/analytics/custom-analytics/custom-analytics.tsx index f9be7d1dd..f46b7f2b2 100644 --- a/apps/app/components/analytics/custom-analytics/custom-analytics.tsx +++ b/apps/app/components/analytics/custom-analytics/custom-analytics.tsx @@ -18,7 +18,7 @@ import { Loader, PrimaryButton } from "components/ui"; // helpers import { convertResponseToBarGraphData } from "helpers/analytics.helper"; // types -import { IAnalyticsParams, IAnalyticsResponse } from "types"; +import { IAnalyticsParams, IAnalyticsResponse, ICurrentUserResponse } from "types"; // fetch-keys import { ANALYTICS } from "constants/fetch-keys"; @@ -29,6 +29,7 @@ type Props = { control: Control; setValue: UseFormSetValue; fullScreen: boolean; + user: ICurrentUserResponse | undefined; }; export const CustomAnalytics: React.FC = ({ @@ -38,6 +39,7 @@ export const CustomAnalytics: React.FC = ({ control, setValue, fullScreen, + user, }) => { const router = useRouter(); const { workspaceSlug, projectId } = router.query; @@ -124,6 +126,7 @@ export const CustomAnalytics: React.FC = ({ params={params} fullScreen={fullScreen} isProjectLevel={isProjectLevel} + user={user} /> ); diff --git a/apps/app/components/analytics/custom-analytics/sidebar.tsx b/apps/app/components/analytics/custom-analytics/sidebar.tsx index 7910c2cc8..5f4700f29 100644 --- a/apps/app/components/analytics/custom-analytics/sidebar.tsx +++ b/apps/app/components/analytics/custom-analytics/sidebar.tsx @@ -27,6 +27,7 @@ import { renderShortDate } from "helpers/date-time.helper"; import { IAnalyticsParams, IAnalyticsResponse, + ICurrentUserResponse, IExportAnalyticsFormData, IProject, IWorkspace, @@ -41,6 +42,7 @@ type Props = { params: IAnalyticsParams; fullScreen: boolean; isProjectLevel: boolean; + user: ICurrentUserResponse | undefined; }; export const AnalyticsSidebar: React.FC = ({ @@ -48,6 +50,7 @@ export const AnalyticsSidebar: React.FC = ({ params, fullScreen, isProjectLevel = false, + user, }) => { const router = useRouter(); const { workspaceSlug, projectId, cycleId, moduleId } = router.query; @@ -138,7 +141,8 @@ export const AnalyticsSidebar: React.FC = ({ ? "MODULE_ANALYTICS_EXPORT" : projectId ? "PROJECT_ANALYTICS_EXPORT" - : "WORKSPACE_ANALYTICS_EXPORT" + : "WORKSPACE_ANALYTICS_EXPORT", + user ); }; diff --git a/apps/app/components/analytics/project-modal.tsx b/apps/app/components/analytics/project-modal.tsx index 728ca4ed5..da308582f 100644 --- a/apps/app/components/analytics/project-modal.tsx +++ b/apps/app/components/analytics/project-modal.tsx @@ -26,6 +26,7 @@ import { import { IAnalyticsParams, IWorkspace } from "types"; // fetch-keys import { ANALYTICS, CYCLE_DETAILS, MODULE_DETAILS, PROJECT_DETAILS } from "constants/fetch-keys"; +import useUserAuth from "hooks/use-user-auth"; type Props = { isOpen: boolean; @@ -47,6 +48,8 @@ export const AnalyticsProjectModal: React.FC = ({ isOpen, onClose }) => { const router = useRouter(); const { workspaceSlug, projectId, cycleId, moduleId } = router.query; + const { user } = useUserAuth(); + const { control, watch, setValue } = useForm({ defaultValues }); const params: IAnalyticsParams = { @@ -136,7 +139,8 @@ export const AnalyticsProjectModal: React.FC = ({ isOpen, onClose }) => { trackEventServices.trackAnalyticsEvent( eventPayload, - cycleId ? `CYCLE_${eventType}` : moduleId ? `MODULE_${eventType}` : `PROJECT_${eventType}` + cycleId ? `CYCLE_${eventType}` : moduleId ? `MODULE_${eventType}` : `PROJECT_${eventType}`, + user ); }; @@ -210,6 +214,7 @@ export const AnalyticsProjectModal: React.FC = ({ isOpen, onClose }) => { control={control} setValue={setValue} fullScreen={fullScreen} + user={user} /> diff --git a/apps/app/components/command-palette/change-issue-assignee.tsx b/apps/app/components/command-palette/change-issue-assignee.tsx index fd853ef0f..56351335e 100644 --- a/apps/app/components/command-palette/change-issue-assignee.tsx +++ b/apps/app/components/command-palette/change-issue-assignee.tsx @@ -7,7 +7,7 @@ import { Command } from "cmdk"; // services import issuesService from "services/issues.service"; // types -import { IIssue } from "types"; +import { ICurrentUserResponse, IIssue } from "types"; // constants import { ISSUE_DETAILS, PROJECT_ISSUES_ACTIVITY, PROJECT_MEMBERS } from "constants/fetch-keys"; // icons @@ -18,9 +18,10 @@ import { Avatar } from "components/ui"; type Props = { setIsPaletteOpen: Dispatch>; issue: IIssue; + user: ICurrentUserResponse | undefined; }; -export const ChangeIssueAssignee: React.FC = ({ setIsPaletteOpen, issue }) => { +export const ChangeIssueAssignee: React.FC = ({ setIsPaletteOpen, issue, user }) => { const router = useRouter(); const { workspaceSlug, projectId, issueId } = router.query; @@ -71,7 +72,7 @@ export const ChangeIssueAssignee: React.FC = ({ setIsPaletteOpen, issue } const payload = { ...formData }; await issuesService - .patchIssue(workspaceSlug as string, projectId as string, issueId as string, payload) + .patchIssue(workspaceSlug as string, projectId as string, issueId as string, payload, user) .then(() => { mutate(PROJECT_ISSUES_ACTIVITY(issueId as string)); }) diff --git a/apps/app/components/command-palette/change-issue-priority.tsx b/apps/app/components/command-palette/change-issue-priority.tsx index d0e6258c5..2db03268d 100644 --- a/apps/app/components/command-palette/change-issue-priority.tsx +++ b/apps/app/components/command-palette/change-issue-priority.tsx @@ -7,7 +7,7 @@ import { Command } from "cmdk"; // services import issuesService from "services/issues.service"; // types -import { IIssue } from "types"; +import { ICurrentUserResponse, IIssue } from "types"; // constants import { ISSUE_DETAILS, PROJECT_ISSUES_ACTIVITY } from "constants/fetch-keys"; import { PRIORITIES } from "constants/project"; @@ -17,9 +17,10 @@ import { CheckIcon, getPriorityIcon } from "components/icons"; type Props = { setIsPaletteOpen: Dispatch>; issue: IIssue; + user: ICurrentUserResponse; }; -export const ChangeIssuePriority: React.FC = ({ setIsPaletteOpen, issue }) => { +export const ChangeIssuePriority: React.FC = ({ setIsPaletteOpen, issue, user }) => { const router = useRouter(); const { workspaceSlug, projectId, issueId } = router.query; @@ -42,7 +43,7 @@ export const ChangeIssuePriority: React.FC = ({ setIsPaletteOpen, issue } const payload = { ...formData }; await issuesService - .patchIssue(workspaceSlug as string, projectId as string, issueId as string, payload) + .patchIssue(workspaceSlug as string, projectId as string, issueId as string, payload, user) .then(() => { mutate(PROJECT_ISSUES_ACTIVITY(issueId as string)); }) diff --git a/apps/app/components/command-palette/change-issue-state.tsx b/apps/app/components/command-palette/change-issue-state.tsx index 8e3255b0a..0378df878 100644 --- a/apps/app/components/command-palette/change-issue-state.tsx +++ b/apps/app/components/command-palette/change-issue-state.tsx @@ -12,7 +12,7 @@ import { getStatesList } from "helpers/state.helper"; import issuesService from "services/issues.service"; import stateService from "services/state.service"; // types -import { IIssue } from "types"; +import { ICurrentUserResponse, IIssue } from "types"; // fetch keys import { ISSUE_DETAILS, PROJECT_ISSUES_ACTIVITY, STATES_LIST } from "constants/fetch-keys"; // icons @@ -21,9 +21,10 @@ import { CheckIcon, getStateGroupIcon } from "components/icons"; type Props = { setIsPaletteOpen: Dispatch>; issue: IIssue; + user: ICurrentUserResponse | undefined; }; -export const ChangeIssueState: React.FC = ({ setIsPaletteOpen, issue }) => { +export const ChangeIssueState: React.FC = ({ setIsPaletteOpen, issue, user }) => { const router = useRouter(); const { workspaceSlug, projectId, issueId } = router.query; @@ -53,7 +54,7 @@ export const ChangeIssueState: React.FC = ({ setIsPaletteOpen, issue }) = const payload = { ...formData }; await issuesService - .patchIssue(workspaceSlug as string, projectId as string, issueId as string, payload) + .patchIssue(workspaceSlug as string, projectId as string, issueId as string, payload, user) .then(() => { mutateIssueDetails(); mutate(PROJECT_ISSUES_ACTIVITY(issueId as string)); diff --git a/apps/app/components/command-palette/command-pallette.tsx b/apps/app/components/command-palette/command-pallette.tsx index 06f4f3c2b..ff889898e 100644 --- a/apps/app/components/command-palette/command-pallette.tsx +++ b/apps/app/components/command-palette/command-pallette.tsx @@ -136,7 +136,7 @@ export const CommandPalette: React.FC = () => { const payload = { ...formData }; await issuesService - .patchIssue(workspaceSlug as string, projectId as string, issueId as string, payload) + .patchIssue(workspaceSlug as string, projectId as string, issueId as string, payload, user) .then(() => { mutate(PROJECT_ISSUES_ACTIVITY(issueId as string)); mutate(ISSUE_DETAILS(issueId as string)); @@ -330,25 +330,33 @@ export const CommandPalette: React.FC = () => { <> {workspaceSlug && ( - + )} {projectId && ( <> setIsCreateCycleModalOpen(false)} + user={user} /> setIsCreateViewModalOpen(false)} isOpen={isCreateViewModalOpen} + user={user} /> setIsCreateUpdatePageModalOpen(false)} + user={user} /> )} @@ -357,6 +365,7 @@ export const CommandPalette: React.FC = () => { handleClose={() => setDeleteIssueModal(false)} isOpen={deleteIssueModal} data={issueDetails} + user={user} /> )} @@ -367,6 +376,7 @@ export const CommandPalette: React.FC = () => { { )} @@ -861,12 +872,14 @@ export const CommandPalette: React.FC = () => { )} {page === "change-issue-assignee" && issueDetails && ( )} {page === "change-interface-theme" && ( diff --git a/apps/app/components/core/board-view/all-boards.tsx b/apps/app/components/core/board-view/all-boards.tsx index 495cee0a5..3e67e86b5 100644 --- a/apps/app/components/core/board-view/all-boards.tsx +++ b/apps/app/components/core/board-view/all-boards.tsx @@ -5,7 +5,7 @@ import { SingleBoard } from "components/core/board-view/single-board"; // helpers import { addSpaceIfCamelCase } from "helpers/string.helper"; // types -import { IIssue, IState, UserAuth } from "types"; +import { ICurrentUserResponse, IIssue, IState, UserAuth } from "types"; import { getStateGroupIcon } from "components/icons"; type Props = { @@ -19,6 +19,7 @@ type Props = { handleTrashBox: (isDragging: boolean) => void; removeIssue: ((bridgeId: string, issueId: string) => void) | null; isCompleted?: boolean; + user: ICurrentUserResponse | undefined; userAuth: UserAuth; }; @@ -33,6 +34,7 @@ export const AllBoards: React.FC = ({ handleTrashBox, removeIssue, isCompleted = false, + user, userAuth, }) => { const { @@ -65,6 +67,7 @@ export const AllBoards: React.FC = ({ handleTrashBox={handleTrashBox} removeIssue={removeIssue} isCompleted={isCompleted} + user={user} userAuth={userAuth} /> ); diff --git a/apps/app/components/core/board-view/single-board.tsx b/apps/app/components/core/board-view/single-board.tsx index 16fe0e887..f7816cd5b 100644 --- a/apps/app/components/core/board-view/single-board.tsx +++ b/apps/app/components/core/board-view/single-board.tsx @@ -17,7 +17,7 @@ import { PlusIcon } from "@heroicons/react/24/outline"; // helpers import { replaceUnderscoreIfSnakeCase } from "helpers/string.helper"; // types -import { IIssue, IState, UserAuth } from "types"; +import { ICurrentUserResponse, IIssue, IState, UserAuth } from "types"; type Props = { type?: "issue" | "cycle" | "module"; @@ -31,6 +31,7 @@ type Props = { handleTrashBox: (isDragging: boolean) => void; removeIssue: ((bridgeId: string, issueId: string) => void) | null; isCompleted?: boolean; + user: ICurrentUserResponse | undefined; userAuth: UserAuth; }; @@ -46,6 +47,7 @@ export const SingleBoard: React.FC = ({ handleTrashBox, removeIssue, isCompleted = false, + user, userAuth, }) => { // collapse/expand @@ -129,6 +131,7 @@ export const SingleBoard: React.FC = ({ removeIssue(issue.bridge_id, issue.id); }} isCompleted={isCompleted} + user={user} userAuth={userAuth} /> )} diff --git a/apps/app/components/core/board-view/single-issue.tsx b/apps/app/components/core/board-view/single-issue.tsx index 7f8a89aa2..e2d530153 100644 --- a/apps/app/components/core/board-view/single-issue.tsx +++ b/apps/app/components/core/board-view/single-issue.tsx @@ -44,7 +44,7 @@ import { LayerDiagonalIcon } from "components/icons"; import { handleIssuesMutation } from "constants/issue"; import { copyTextToClipboard, truncateText } from "helpers/string.helper"; // types -import { IIssue, Properties, TIssueGroupByOptions, UserAuth } from "types"; +import { ICurrentUserResponse, IIssue, Properties, TIssueGroupByOptions, UserAuth } from "types"; // fetch-keys import { CYCLE_DETAILS, @@ -69,6 +69,7 @@ type Props = { handleDeleteIssue: (issue: IIssue) => void; handleTrashBox: (isDragging: boolean) => void; isCompleted?: boolean; + user: ICurrentUserResponse | undefined; userAuth: UserAuth; }; @@ -87,6 +88,7 @@ export const SingleBoardIssue: React.FC = ({ handleDeleteIssue, handleTrashBox, isCompleted = false, + user, userAuth, }) => { // context menu @@ -170,7 +172,7 @@ export const SingleBoardIssue: React.FC = ({ } issuesService - .patchIssue(workspaceSlug as string, projectId as string, issueId, formData) + .patchIssue(workspaceSlug as string, projectId as string, issueId, formData, user) .then(() => { if (cycleId) { mutate(CYCLE_ISSUES_WITH_PARAMS(cycleId as string, params)); @@ -342,6 +344,7 @@ export const SingleBoardIssue: React.FC = ({ issue={issue} partialUpdateIssue={partialUpdateIssue} isNotAllowed={isNotAllowed} + user={user} selfPositioned /> )} @@ -350,6 +353,7 @@ export const SingleBoardIssue: React.FC = ({ issue={issue} partialUpdateIssue={partialUpdateIssue} isNotAllowed={isNotAllowed} + user={user} selfPositioned /> )} @@ -357,6 +361,7 @@ export const SingleBoardIssue: React.FC = ({ )} @@ -384,6 +389,7 @@ export const SingleBoardIssue: React.FC = ({ partialUpdateIssue={partialUpdateIssue} isNotAllowed={isNotAllowed} tooltipPosition="left" + user={user} selfPositioned /> )} @@ -392,6 +398,7 @@ export const SingleBoardIssue: React.FC = ({ issue={issue} partialUpdateIssue={partialUpdateIssue} isNotAllowed={isNotAllowed} + user={user} selfPositioned /> )} diff --git a/apps/app/components/core/bulk-delete-issues-modal.tsx b/apps/app/components/core/bulk-delete-issues-modal.tsx index 7fe2181f6..603efe8e3 100644 --- a/apps/app/components/core/bulk-delete-issues-modal.tsx +++ b/apps/app/components/core/bulk-delete-issues-modal.tsx @@ -18,7 +18,7 @@ import { DangerButton, SecondaryButton } from "components/ui"; import { MagnifyingGlassIcon } from "@heroicons/react/24/outline"; import { LayerDiagonalIcon } from "components/icons"; // types -import { IIssue } from "types"; +import { ICurrentUserResponse, IIssue } from "types"; // fetch keys import { PROJECT_ISSUES_LIST } from "constants/fetch-keys"; @@ -29,9 +29,10 @@ type FormInput = { type Props = { isOpen: boolean; setIsOpen: React.Dispatch>; + user: ICurrentUserResponse | undefined; }; -export const BulkDeleteIssuesModal: React.FC = ({ isOpen, setIsOpen }) => { +export const BulkDeleteIssuesModal: React.FC = ({ isOpen, setIsOpen, user }) => { const [query, setQuery] = useState(""); const router = useRouter(); @@ -91,9 +92,14 @@ export const BulkDeleteIssuesModal: React.FC = ({ isOpen, setIsOpen }) => if (workspaceSlug && projectId) { await issuesServices - .bulkDeleteIssues(workspaceSlug as string, projectId as string, { - issue_ids: data.delete_issue_ids, - }) + .bulkDeleteIssues( + workspaceSlug as string, + projectId as string, + { + issue_ids: data.delete_issue_ids, + }, + user + ) .then((res) => { setToastAlert({ title: "Success", diff --git a/apps/app/components/core/calendar-view/calendar.tsx b/apps/app/components/core/calendar-view/calendar.tsx index ce453f898..fa29eb9f7 100644 --- a/apps/app/components/core/calendar-view/calendar.tsx +++ b/apps/app/components/core/calendar-view/calendar.tsx @@ -24,7 +24,7 @@ import { formatDate, } from "helpers/calendar.helper"; // types -import { ICalendarRange, IIssue, UserAuth } from "types"; +import { ICalendarRange, ICurrentUserResponse, IIssue, UserAuth } from "types"; // fetch-keys import { CYCLE_ISSUES_WITH_PARAMS, @@ -38,6 +38,7 @@ type Props = { handleDeleteIssue: (issue: IIssue) => void; addIssueToDate: (date: string) => void; isCompleted: boolean; + user: ICurrentUserResponse | undefined; userAuth: UserAuth; }; @@ -46,6 +47,7 @@ export const CalendarView: React.FC = ({ handleDeleteIssue, addIssueToDate, isCompleted = false, + user, userAuth, }) => { const [showWeekEnds, setShowWeekEnds] = useState(false); @@ -134,9 +136,15 @@ export const CalendarView: React.FC = ({ ); issuesService - .patchIssue(workspaceSlug as string, projectId as string, draggableId, { - target_date: destination?.droppableId, - }) + .patchIssue( + workspaceSlug as string, + projectId as string, + draggableId, + { + target_date: destination?.droppableId, + }, + user + ) .then(() => mutate(fetchKey)); }; @@ -219,6 +227,7 @@ export const CalendarView: React.FC = ({ addIssueToDate={addIssueToDate} isMonthlyView={isMonthlyView} showWeekEnds={showWeekEnds} + user={user} isNotAllowed={isNotAllowed} /> ))} diff --git a/apps/app/components/core/calendar-view/single-date.tsx b/apps/app/components/core/calendar-view/single-date.tsx index fd552188c..2dbfe5dfd 100644 --- a/apps/app/components/core/calendar-view/single-date.tsx +++ b/apps/app/components/core/calendar-view/single-date.tsx @@ -10,7 +10,7 @@ import { PlusSmallIcon } from "@heroicons/react/24/outline"; // helper import { formatDate } from "helpers/calendar.helper"; // types -import { IIssue } from "types"; +import { ICurrentUserResponse, IIssue } from "types"; type Props = { handleEditIssue: (issue: IIssue) => void; @@ -23,6 +23,7 @@ type Props = { addIssueToDate: (date: string) => void; isMonthlyView: boolean; showWeekEnds: boolean; + user: ICurrentUserResponse | undefined; isNotAllowed: boolean; }; @@ -34,6 +35,7 @@ export const SingleCalendarDate: React.FC = ({ addIssueToDate, isMonthlyView, showWeekEnds, + user, isNotAllowed, }) => { const [showAllIssues, setShowAllIssues] = useState(false); @@ -72,6 +74,7 @@ export const SingleCalendarDate: React.FC = ({ issue={issue} handleEditIssue={handleEditIssue} handleDeleteIssue={handleDeleteIssue} + user={user} isNotAllowed={isNotAllowed} /> )} diff --git a/apps/app/components/core/calendar-view/single-issue.tsx b/apps/app/components/core/calendar-view/single-issue.tsx index 9102f7338..4fa9def3b 100644 --- a/apps/app/components/core/calendar-view/single-issue.tsx +++ b/apps/app/components/core/calendar-view/single-issue.tsx @@ -28,7 +28,7 @@ import { LayerDiagonalIcon } from "components/icons"; // helper import { copyTextToClipboard, truncateText } from "helpers/string.helper"; // type -import { IIssue } from "types"; +import { ICurrentUserResponse, IIssue } from "types"; // fetch-keys import { CYCLE_ISSUES_WITH_PARAMS, @@ -44,6 +44,7 @@ type Props = { provided: DraggableProvided; snapshot: DraggableStateSnapshot; issue: IIssue; + user: ICurrentUserResponse | undefined; isNotAllowed: boolean; }; @@ -54,6 +55,7 @@ export const SingleCalendarIssue: React.FC = ({ provided, snapshot, issue, + user, isNotAllowed, }) => { const router = useRouter(); @@ -95,7 +97,7 @@ export const SingleCalendarIssue: React.FC = ({ ); issuesService - .patchIssue(workspaceSlug as string, projectId as string, issueId as string, formData) + .patchIssue(workspaceSlug as string, projectId as string, issueId as string, formData, user) .then(() => { mutate(fetchKey); }) @@ -183,6 +185,7 @@ export const SingleCalendarIssue: React.FC = ({ issue={issue} partialUpdateIssue={partialUpdateIssue} position="left" + user={user} isNotAllowed={isNotAllowed} /> )} @@ -192,6 +195,7 @@ export const SingleCalendarIssue: React.FC = ({ partialUpdateIssue={partialUpdateIssue} position="left" isNotAllowed={isNotAllowed} + user={user} /> )} @@ -199,6 +203,7 @@ export const SingleCalendarIssue: React.FC = ({ )} @@ -227,6 +232,7 @@ export const SingleCalendarIssue: React.FC = ({ issue={issue} partialUpdateIssue={partialUpdateIssue} position="left" + user={user} isNotAllowed={isNotAllowed} /> )} @@ -235,6 +241,7 @@ export const SingleCalendarIssue: React.FC = ({ issue={issue} partialUpdateIssue={partialUpdateIssue} position="left" + user={user} isNotAllowed={isNotAllowed} /> )} diff --git a/apps/app/components/core/gpt-assistant-modal.tsx b/apps/app/components/core/gpt-assistant-modal.tsx index 90c558717..a62b3e413 100644 --- a/apps/app/components/core/gpt-assistant-modal.tsx +++ b/apps/app/components/core/gpt-assistant-modal.tsx @@ -10,6 +10,7 @@ import aiService from "services/ai.service"; import trackEventServices from "services/track-event.service"; // hooks import useToast from "hooks/use-toast"; +import useUserAuth from "hooks/use-user-auth"; // ui import { Input, PrimaryButton, SecondaryButton } from "components/ui"; @@ -60,6 +61,8 @@ export const GptAssistantModal: React.FC = ({ const router = useRouter(); const { workspaceSlug } = router.query; + const { user } = useUserAuth(); + const editorRef = useRef(null); const { setToastAlert } = useToast(); @@ -97,10 +100,15 @@ export const GptAssistantModal: React.FC = ({ } await aiService - .createGptTask(workspaceSlug as string, projectId as string, { - prompt: content && content !== "" ? content : htmlContent ?? "", - task: formData.task, - }) + .createGptTask( + workspaceSlug as string, + projectId as string, + { + prompt: content && content !== "" ? content : htmlContent ?? "", + task: formData.task, + }, + user + ) .then((res) => { setResponse(res.response_html); setFocus("task"); @@ -190,10 +198,15 @@ export const GptAssistantModal: React.FC = ({ if (block) trackEventServices.trackUseGPTResponseEvent( block, - "USE_GPT_RESPONSE_IN_PAGE_BLOCK" + "USE_GPT_RESPONSE_IN_PAGE_BLOCK", + user ); else if (issue) - trackEventServices.trackUseGPTResponseEvent(issue, "USE_GPT_RESPONSE_IN_ISSUE"); + trackEventServices.trackUseGPTResponseEvent( + issue, + "USE_GPT_RESPONSE_IN_ISSUE", + user + ); }} > Use this response diff --git a/apps/app/components/core/issues-view.tsx b/apps/app/components/core/issues-view.tsx index cc0672843..bfa6b9f46 100644 --- a/apps/app/components/core/issues-view.tsx +++ b/apps/app/components/core/issues-view.tsx @@ -17,6 +17,7 @@ import { useProjectMyMembership } from "contexts/project-member.context"; // hooks import useToast from "hooks/use-toast"; import useIssuesView from "hooks/use-issues-view"; +import useUserAuth from "hooks/use-user-auth"; // components import { AllLists, AllBoards, FilterList, CalendarView, GanttChartView } from "components/core"; import { CreateUpdateIssueModal, DeleteIssueModal } from "components/issues"; @@ -89,6 +90,8 @@ export const IssuesView: React.FC = ({ const { memberRole } = useProjectMyMembership(); + const { user } = useUserAuth(); + const { setToastAlert } = useToast(); const { @@ -220,11 +223,17 @@ export const IssuesView: React.FC = ({ // patch request issuesService - .patchIssue(workspaceSlug as string, projectId as string, draggedItem.id, { - priority: draggedItem.priority, - state: draggedItem.state, - sort_order: draggedItem.sort_order, - }) + .patchIssue( + workspaceSlug as string, + projectId as string, + draggedItem.id, + { + priority: draggedItem.priority, + state: draggedItem.state, + sort_order: draggedItem.sort_order, + }, + user + ) .then((response) => { const sourceStateBeforeDrag = states.find((state) => state.name === source.droppableId); @@ -232,14 +241,17 @@ export const IssuesView: React.FC = ({ sourceStateBeforeDrag?.group !== "completed" && response?.state_detail?.group === "completed" ) - trackEventServices.trackIssueMarkedAsDoneEvent({ - workspaceSlug, - workspaceId: draggedItem.workspace, - projectName: draggedItem.project_detail.name, - projectIdentifier: draggedItem.project_detail.identifier, - projectId, - issueId: draggedItem.id, - }); + trackEventServices.trackIssueMarkedAsDoneEvent( + { + workspaceSlug, + workspaceId: draggedItem.workspace, + projectName: draggedItem.project_detail.name, + projectIdentifier: draggedItem.project_detail.identifier, + projectId, + issueId: draggedItem.id, + }, + user + ); if (cycleId) { mutate(CYCLE_ISSUES_WITH_PARAMS(cycleId as string, params)); @@ -419,6 +431,7 @@ export const IssuesView: React.FC = ({ isOpen={createViewModal !== null} handleClose={() => setCreateViewModal(null)} preLoadedData={createViewModal} + user={user} /> = ({ handleClose={() => setDeleteIssueModal(false)} isOpen={deleteIssueModal} data={issueToDelete} + user={user} /> setTransferIssuesModal(false)} @@ -508,6 +522,7 @@ export const IssuesView: React.FC = ({ : null } isCompleted={isCompleted} + user={user} userAuth={memberRole} /> ) : issueView === "kanban" ? ( @@ -528,6 +543,7 @@ export const IssuesView: React.FC = ({ : null } isCompleted={isCompleted} + user={user} userAuth={memberRole} /> ) : issueView === "calendar" ? ( @@ -536,6 +552,7 @@ export const IssuesView: React.FC = ({ handleDeleteIssue={handleDeleteIssue} addIssueToDate={addIssueToDate} isCompleted={isCompleted} + user={user} userAuth={memberRole} /> ) : ( diff --git a/apps/app/components/core/list-view/all-lists.tsx b/apps/app/components/core/list-view/all-lists.tsx index d8fa8b9ee..fd063728a 100644 --- a/apps/app/components/core/list-view/all-lists.tsx +++ b/apps/app/components/core/list-view/all-lists.tsx @@ -3,7 +3,7 @@ import useIssuesView from "hooks/use-issues-view"; // components import { SingleList } from "components/core/list-view/single-list"; // types -import { IIssue, IState, UserAuth } from "types"; +import { ICurrentUserResponse, IIssue, IState, UserAuth } from "types"; // types type Props = { @@ -16,6 +16,7 @@ type Props = { openIssuesListModal?: (() => void) | null; removeIssue: ((bridgeId: string, issueId: string) => void) | null; isCompleted?: boolean; + user: ICurrentUserResponse | undefined; userAuth: UserAuth; }; @@ -29,6 +30,7 @@ export const AllLists: React.FC = ({ handleDeleteIssue, removeIssue, isCompleted = false, + user, userAuth, }) => { const { groupedByIssues, groupByProperty: selectedGroup, showEmptyGroups } = useIssuesView(); @@ -58,6 +60,7 @@ export const AllLists: React.FC = ({ openIssuesListModal={type !== "issue" ? openIssuesListModal : null} removeIssue={removeIssue} isCompleted={isCompleted} + user={user} userAuth={userAuth} /> ); diff --git a/apps/app/components/core/list-view/single-issue.tsx b/apps/app/components/core/list-view/single-issue.tsx index 6f6a5ab4f..ea4ebc811 100644 --- a/apps/app/components/core/list-view/single-issue.tsx +++ b/apps/app/components/core/list-view/single-issue.tsx @@ -36,7 +36,7 @@ import { LayerDiagonalIcon } from "components/icons"; import { copyTextToClipboard, truncateText } from "helpers/string.helper"; import { handleIssuesMutation } from "constants/issue"; // types -import { IIssue, Properties, UserAuth } from "types"; +import { ICurrentUserResponse, IIssue, Properties, UserAuth } from "types"; // fetch-keys import { CYCLE_DETAILS, @@ -57,6 +57,7 @@ type Props = { removeIssue?: (() => void) | null; handleDeleteIssue: (issue: IIssue) => void; isCompleted?: boolean; + user: ICurrentUserResponse | undefined; userAuth: UserAuth; }; @@ -71,6 +72,7 @@ export const SingleListIssue: React.FC = ({ groupTitle, handleDeleteIssue, isCompleted = false, + user, userAuth, }) => { // context menu @@ -141,7 +143,7 @@ export const SingleListIssue: React.FC = ({ ); issuesService - .patchIssue(workspaceSlug as string, projectId as string, issueId, formData) + .patchIssue(workspaceSlug as string, projectId as string, issueId, formData, user) .then(() => { if (cycleId) { mutate(CYCLE_ISSUES_WITH_PARAMS(cycleId as string, params)); @@ -241,6 +243,7 @@ export const SingleListIssue: React.FC = ({ issue={issue} partialUpdateIssue={partialUpdateIssue} position="right" + user={user} isNotAllowed={isNotAllowed} /> )} @@ -249,6 +252,7 @@ export const SingleListIssue: React.FC = ({ issue={issue} partialUpdateIssue={partialUpdateIssue} position="right" + user={user} isNotAllowed={isNotAllowed} /> )} @@ -256,6 +260,7 @@ export const SingleListIssue: React.FC = ({ )} @@ -284,6 +289,7 @@ export const SingleListIssue: React.FC = ({ issue={issue} partialUpdateIssue={partialUpdateIssue} position="right" + user={user} isNotAllowed={isNotAllowed} /> )} @@ -292,6 +298,7 @@ export const SingleListIssue: React.FC = ({ issue={issue} partialUpdateIssue={partialUpdateIssue} position="right" + user={user} isNotAllowed={isNotAllowed} /> )} diff --git a/apps/app/components/core/list-view/single-list.tsx b/apps/app/components/core/list-view/single-list.tsx index dd5ffb110..a8c6e4a51 100644 --- a/apps/app/components/core/list-view/single-list.tsx +++ b/apps/app/components/core/list-view/single-list.tsx @@ -19,7 +19,14 @@ import { getPriorityIcon, getStateGroupIcon } from "components/icons"; // helpers import { addSpaceIfCamelCase } from "helpers/string.helper"; // types -import { IIssue, IIssueLabels, IState, TIssueGroupByOptions, UserAuth } from "types"; +import { + ICurrentUserResponse, + IIssue, + IIssueLabels, + IState, + TIssueGroupByOptions, + UserAuth, +} from "types"; // fetch-keys import { PROJECT_ISSUE_LABELS, PROJECT_MEMBERS } from "constants/fetch-keys"; @@ -39,6 +46,7 @@ type Props = { openIssuesListModal?: (() => void) | null; removeIssue: ((bridgeId: string, issueId: string) => void) | null; isCompleted?: boolean; + user: ICurrentUserResponse | undefined; userAuth: UserAuth; }; @@ -56,6 +64,7 @@ export const SingleList: React.FC = ({ openIssuesListModal, removeIssue, isCompleted = false, + user, userAuth, }) => { const router = useRouter(); @@ -208,6 +217,7 @@ export const SingleList: React.FC = ({ removeIssue(issue.bridge_id, issue.id); }} isCompleted={isCompleted} + user={user} userAuth={userAuth} /> )) diff --git a/apps/app/components/cycles/cycles-view.tsx b/apps/app/components/cycles/cycles-view.tsx index fc720c251..261e81018 100644 --- a/apps/app/components/cycles/cycles-view.tsx +++ b/apps/app/components/cycles/cycles-view.tsx @@ -8,6 +8,7 @@ import { mutate } from "swr"; import cyclesService from "services/cycles.service"; // hooks import useToast from "hooks/use-toast"; +import useUserAuth from "hooks/use-user-auth"; // components import { CreateUpdateCycleModal, @@ -48,6 +49,7 @@ export const CyclesView: React.FC = ({ cycles, viewType }) => { const router = useRouter(); const { workspaceSlug, projectId } = router.query; + const { user } = useUserAuth(); const { setToastAlert } = useToast(); const handleEditCycle = (cycle: ICycle) => { @@ -158,11 +160,13 @@ export const CyclesView: React.FC = ({ cycles, viewType }) => { isOpen={createUpdateCycleModal} handleClose={() => setCreateUpdateCycleModal(false)} data={selectedCycleToUpdate} + user={user} /> {cycles ? ( cycles.length > 0 ? ( diff --git a/apps/app/components/cycles/delete-cycle-modal.tsx b/apps/app/components/cycles/delete-cycle-modal.tsx index 187c9694c..3f2de2913 100644 --- a/apps/app/components/cycles/delete-cycle-modal.tsx +++ b/apps/app/components/cycles/delete-cycle-modal.tsx @@ -14,11 +14,12 @@ import { DangerButton, SecondaryButton } from "components/ui"; // icons import { ExclamationTriangleIcon } from "@heroicons/react/24/outline"; // types -import type { ICycle } from "types"; +import type { ICurrentUserResponse, ICycle } from "types"; type TConfirmCycleDeletionProps = { isOpen: boolean; setIsOpen: React.Dispatch>; data?: ICycle | null; + user: ICurrentUserResponse | undefined; }; // fetch-keys import { @@ -34,6 +35,7 @@ export const DeleteCycleModal: React.FC = ({ isOpen, setIsOpen, data, + user, }) => { const [isDeleteLoading, setIsDeleteLoading] = useState(false); @@ -53,7 +55,7 @@ export const DeleteCycleModal: React.FC = ({ setIsDeleteLoading(true); await cycleService - .deleteCycle(workspaceSlug as string, data.project, data.id) + .deleteCycle(workspaceSlug as string, data.project, data.id, user) .then(() => { const cycleType = getDateRangeStatus(data.start_date, data.end_date); const fetchKey = diff --git a/apps/app/components/cycles/modal.tsx b/apps/app/components/cycles/modal.tsx index e27b5ac32..3c1c16506 100644 --- a/apps/app/components/cycles/modal.tsx +++ b/apps/app/components/cycles/modal.tsx @@ -15,7 +15,7 @@ import { CycleForm } from "components/cycles"; // helper import { getDateRangeStatus, isDateGreaterThanToday } from "helpers/date-time.helper"; // types -import type { ICycle } from "types"; +import type { ICurrentUserResponse, ICycle } from "types"; // fetch keys import { COMPLETED_CYCLES_LIST, @@ -30,12 +30,14 @@ type CycleModalProps = { isOpen: boolean; handleClose: () => void; data?: ICycle | null; + user: ICurrentUserResponse | undefined; }; export const CreateUpdateCycleModal: React.FC = ({ isOpen, handleClose, data, + user, }) => { const router = useRouter(); const { workspaceSlug, projectId } = router.query; @@ -46,7 +48,7 @@ export const CreateUpdateCycleModal: React.FC = ({ if (!workspaceSlug || !projectId) return; await cycleService - .createCycle(workspaceSlug.toString(), projectId.toString(), payload) + .createCycle(workspaceSlug.toString(), projectId.toString(), payload, user) .then((res) => { switch (getDateRangeStatus(res.start_date, res.end_date)) { case "completed": @@ -84,7 +86,7 @@ export const CreateUpdateCycleModal: React.FC = ({ if (!workspaceSlug || !projectId) return; await cycleService - .updateCycle(workspaceSlug.toString(), projectId.toString(), cycleId, payload) + .updateCycle(workspaceSlug.toString(), projectId.toString(), cycleId, payload, user) .then((res) => { switch (getDateRangeStatus(data?.start_date, data?.end_date)) { case "completed": diff --git a/apps/app/components/cycles/select.tsx b/apps/app/components/cycles/select.tsx index b5ec8a462..2fdda69b5 100644 --- a/apps/app/components/cycles/select.tsx +++ b/apps/app/components/cycles/select.tsx @@ -4,6 +4,7 @@ import { useRouter } from "next/router"; import useSWR from "swr"; +import useUserAuth from "hooks/use-user-auth"; // headless ui import { Listbox, Transition } from "@headlessui/react"; // icons @@ -35,6 +36,8 @@ export const CycleSelect: React.FC = ({ const router = useRouter(); const { workspaceSlug } = router.query; + const { user } = useUserAuth(); + const { data: cycles } = useSWR( workspaceSlug && projectId ? CYCLES_LIST(projectId) : null, workspaceSlug && projectId @@ -54,7 +57,11 @@ export const CycleSelect: React.FC = ({ return ( <> - + {({ open }) => ( <> diff --git a/apps/app/components/cycles/sidebar.tsx b/apps/app/components/cycles/sidebar.tsx index 494383fc4..9a7d04f3e 100644 --- a/apps/app/components/cycles/sidebar.tsx +++ b/apps/app/components/cycles/sidebar.tsx @@ -39,7 +39,7 @@ import { renderShortDate, } from "helpers/date-time.helper"; // types -import { ICycle, IIssue } from "types"; +import { ICurrentUserResponse, ICycle, IIssue } from "types"; // fetch-keys import { CYCLE_DETAILS, CYCLE_ISSUES } from "constants/fetch-keys"; @@ -48,6 +48,7 @@ type Props = { isOpen: boolean; cycleStatus: string; isCompleted: boolean; + user: ICurrentUserResponse | undefined; }; export const CycleDetailsSidebar: React.FC = ({ @@ -55,6 +56,7 @@ export const CycleDetailsSidebar: React.FC = ({ isOpen, cycleStatus, isCompleted, + user, }) => { const [cycleDeleteModal, setCycleDeleteModal] = useState(false); @@ -94,7 +96,7 @@ export const CycleDetailsSidebar: React.FC = ({ ); cyclesService - .patchCycle(workspaceSlug as string, projectId as string, cycleId as string, data) + .patchCycle(workspaceSlug as string, projectId as string, cycleId as string, data, user) .then(() => mutate(CYCLE_DETAILS(cycleId as string))) .catch((e) => console.log(e)); }; @@ -294,7 +296,12 @@ export const CycleDetailsSidebar: React.FC = ({ return ( <> - +
void; data?: IEstimate; + user: ICurrentUserResponse | undefined; }; type FormValues = { @@ -49,7 +50,7 @@ const defaultValues: Partial = { value6: "", }; -export const CreateUpdateEstimateModal: React.FC = ({ handleClose, data, isOpen }) => { +export const CreateUpdateEstimateModal: React.FC = ({ handleClose, data, isOpen, user }) => { const { register, formState: { isSubmitting }, @@ -73,7 +74,7 @@ export const CreateUpdateEstimateModal: React.FC = ({ handleClose, data, if (!workspaceSlug || !projectId) return; await estimatesService - .createEstimate(workspaceSlug as string, projectId as string, payload) + .createEstimate(workspaceSlug as string, projectId as string, payload, user) .then(() => { mutate(ESTIMATES_LIST(projectId as string)); onClose(); @@ -118,7 +119,13 @@ export const CreateUpdateEstimateModal: React.FC = ({ handleClose, data, ); await estimatesService - .patchEstimate(workspaceSlug as string, projectId as string, data?.id as string, payload) + .patchEstimate( + workspaceSlug as string, + projectId as string, + data?.id as string, + payload, + user + ) .then(() => { mutate(ESTIMATES_LIST(projectId.toString())); mutate(ESTIMATE_DETAILS(data.id)); diff --git a/apps/app/components/estimates/single-estimate.tsx b/apps/app/components/estimates/single-estimate.tsx index 43dcc45b7..5e331c139 100644 --- a/apps/app/components/estimates/single-estimate.tsx +++ b/apps/app/components/estimates/single-estimate.tsx @@ -16,15 +16,17 @@ import { PencilIcon, TrashIcon } from "@heroicons/react/24/outline"; // helpers import { orderArrayBy } from "helpers/array.helper"; // types -import { IEstimate } from "types"; +import { ICurrentUserResponse, IEstimate } from "types"; type Props = { + user: ICurrentUserResponse | undefined; estimate: IEstimate; editEstimate: (estimate: IEstimate) => void; handleEstimateDelete: (estimateId: string) => void; }; export const SingleEstimate: React.FC = ({ + user, estimate, editEstimate, handleEstimateDelete, @@ -52,7 +54,7 @@ export const SingleEstimate: React.FC = ({ }, false); await projectService - .updateProject(workspaceSlug as string, projectId as string, payload) + .updateProject(workspaceSlug as string, projectId as string, payload, user) .catch(() => { setToastAlert({ type: "error", diff --git a/apps/app/components/integration/delete-import-modal.tsx b/apps/app/components/integration/delete-import-modal.tsx index 8c5ab3803..cd0b12a2a 100644 --- a/apps/app/components/integration/delete-import-modal.tsx +++ b/apps/app/components/integration/delete-import-modal.tsx @@ -15,7 +15,7 @@ import { DangerButton, Input, SecondaryButton } from "components/ui"; // icons import { ExclamationTriangleIcon } from "@heroicons/react/24/outline"; // types -import { IImporterService } from "types"; +import { ICurrentUserResponse, IImporterService } from "types"; // fetch-keys import { IMPORTER_SERVICES_LIST } from "constants/fetch-keys"; @@ -23,9 +23,10 @@ type Props = { isOpen: boolean; handleClose: () => void; data: IImporterService | null; + user: ICurrentUserResponse | undefined; }; -export const DeleteImportModal: React.FC = ({ isOpen, handleClose, data }) => { +export const DeleteImportModal: React.FC = ({ isOpen, handleClose, data, user }) => { const [deleteLoading, setDeleteLoading] = useState(false); const [confirmDeleteImport, setConfirmDeleteImport] = useState(false); @@ -45,7 +46,7 @@ export const DeleteImportModal: React.FC = ({ isOpen, handleClose, data } false ); - IntegrationService.deleteImporterService(workspaceSlug as string, data.service, data.id) + IntegrationService.deleteImporterService(workspaceSlug as string, data.service, data.id, user) .catch(() => setToastAlert({ type: "error", diff --git a/apps/app/components/integration/github/root.tsx b/apps/app/components/integration/github/root.tsx index b8bfb346b..96ce845c4 100644 --- a/apps/app/components/integration/github/root.tsx +++ b/apps/app/components/integration/github/root.tsx @@ -27,7 +27,7 @@ import { ArrowLeftIcon, ListBulletIcon } from "@heroicons/react/24/outline"; // images import GithubLogo from "public/services/github.png"; // types -import { IGithubRepoCollaborator, IGithubServiceImportFormData } from "types"; +import { ICurrentUserResponse, IGithubRepoCollaborator, IGithubServiceImportFormData } from "types"; // fetch-keys import { APP_INTEGRATIONS, @@ -89,7 +89,11 @@ const integrationWorkflowData = [ }, ]; -export const GithubImporterRoot = () => { +type Props = { + user: ICurrentUserResponse | undefined; +}; + +export const GithubImporterRoot: React.FC = ({ user }) => { const [currentStep, setCurrentStep] = useState({ state: "import-configure", }); @@ -157,7 +161,7 @@ export const GithubImporterRoot = () => { project_id: formData.project, }; - await GithubIntegrationService.createGithubServiceImport(workspaceSlug as string, payload) + await GithubIntegrationService.createGithubServiceImport(workspaceSlug as string, payload, user) .then(() => { router.push(`/${workspaceSlug}/settings/import-export`); mutate(IMPORTER_SERVICES_LIST(workspaceSlug as string)); diff --git a/apps/app/components/integration/guide.tsx b/apps/app/components/integration/guide.tsx index 06f13b752..2db8ef010 100644 --- a/apps/app/components/integration/guide.tsx +++ b/apps/app/components/integration/guide.tsx @@ -6,6 +6,8 @@ import { useRouter } from "next/router"; import useSWR, { mutate } from "swr"; +// hooks +import useUserAuth from "hooks/use-user-auth"; // services import IntegrationService from "services/integration"; // components @@ -35,6 +37,8 @@ const IntegrationGuide = () => { const router = useRouter(); const { workspaceSlug, provider } = router.query; + const { user } = useUserAuth(); + const { data: importerServices } = useSWR( workspaceSlug ? IMPORTER_SERVICES_LIST(workspaceSlug as string) : null, workspaceSlug ? () => IntegrationService.getImporterServicesList(workspaceSlug as string) : null @@ -51,6 +55,7 @@ const IntegrationGuide = () => { isOpen={deleteImportModal} handleClose={() => setDeleteImportModal(false)} data={importToDelete} + user={user} />
{!provider && ( @@ -156,8 +161,8 @@ const IntegrationGuide = () => { )} - {provider && provider === "github" && } - {provider && provider === "jira" && } + {provider && provider === "github" && } + {provider && provider === "jira" && }
); diff --git a/apps/app/components/integration/jira/root.tsx b/apps/app/components/integration/jira/root.tsx index 6ec39a36a..b1098c9cb 100644 --- a/apps/app/components/integration/jira/root.tsx +++ b/apps/app/components/integration/jira/root.tsx @@ -35,7 +35,7 @@ import { import JiraLogo from "public/services/jira.png"; -import { IJiraImporterForm } from "types"; +import { ICurrentUserResponse, IJiraImporterForm } from "types"; const integrationWorkflowData: Array<{ title: string; @@ -64,7 +64,11 @@ const integrationWorkflowData: Array<{ }, ]; -export const JiraImporterRoot = () => { +type Props = { + user: ICurrentUserResponse | undefined; +}; + +export const JiraImporterRoot: React.FC = ({ user }) => { const [currentStep, setCurrentStep] = useState({ state: "import-configure", }); @@ -85,7 +89,7 @@ export const JiraImporterRoot = () => { if (!workspaceSlug) return; await jiraImporterService - .createJiraImporter(workspaceSlug.toString(), data) + .createJiraImporter(workspaceSlug.toString(), data, user) .then(() => { mutate(IMPORTER_SERVICES_LIST(workspaceSlug.toString())); router.push(`/${workspaceSlug}/settings/import-export`); diff --git a/apps/app/components/issues/activity.tsx b/apps/app/components/issues/activity.tsx index 7a3aed4a6..1ccafae56 100644 --- a/apps/app/components/issues/activity.tsx +++ b/apps/app/components/issues/activity.tsx @@ -27,7 +27,7 @@ import { Loader } from "components/ui"; import { renderShortNumericDateFormat, timeAgo } from "helpers/date-time.helper"; import { addSpaceIfCamelCase } from "helpers/string.helper"; // types -import { IIssueComment, IIssueLabels } from "types"; +import { ICurrentUserResponse, IIssueComment, IIssueLabels } from "types"; import { PROJECT_ISSUES_ACTIVITY, PROJECT_ISSUE_LABELS } from "constants/fetch-keys"; import useEstimateOption from "hooks/use-estimate-option"; @@ -110,7 +110,11 @@ const activityDetails: { }, }; -export const IssueActivitySection: React.FC = () => { +type Props = { + user: ICurrentUserResponse | undefined; +}; + +export const IssueActivitySection: React.FC = ({ user }) => { const router = useRouter(); const { workspaceSlug, projectId, issueId } = router.query; @@ -143,7 +147,8 @@ export const IssueActivitySection: React.FC = () => { projectId as string, issueId as string, comment.id, - comment + comment, + user ) .then((res) => { mutateIssueActivities(); @@ -160,7 +165,8 @@ export const IssueActivitySection: React.FC = () => { workspaceSlug as string, projectId as string, issueId as string, - commentId + commentId, + user ) .then(() => mutateIssueActivities()); }; diff --git a/apps/app/components/issues/comment/add-comment.tsx b/apps/app/components/issues/comment/add-comment.tsx index b088be77a..7a5e62636 100644 --- a/apps/app/components/issues/comment/add-comment.tsx +++ b/apps/app/components/issues/comment/add-comment.tsx @@ -14,7 +14,7 @@ import useToast from "hooks/use-toast"; // ui import { Loader, SecondaryButton } from "components/ui"; // types -import type { IIssueComment } from "types"; +import type { ICurrentUserResponse, IIssueComment } from "types"; // fetch-keys import { PROJECT_ISSUES_ACTIVITY } from "constants/fetch-keys"; @@ -40,7 +40,11 @@ const defaultValues: Partial = { comment_html: "", }; -export const AddComment: React.FC = () => { +type Props = { + user: ICurrentUserResponse | undefined; +}; + +export const AddComment: React.FC = ({ user }) => { const { handleSubmit, control, @@ -67,7 +71,13 @@ export const AddComment: React.FC = () => { ) return; await issuesServices - .createIssueComment(workspaceSlug as string, projectId as string, issueId as string, formData) + .createIssueComment( + workspaceSlug as string, + projectId as string, + issueId as string, + formData, + user + ) .then(() => { mutate(PROJECT_ISSUES_ACTIVITY(issueId as string)); reset(defaultValues); diff --git a/apps/app/components/issues/delete-issue-modal.tsx b/apps/app/components/issues/delete-issue-modal.tsx index 5f4d0c2b2..525858b0c 100644 --- a/apps/app/components/issues/delete-issue-modal.tsx +++ b/apps/app/components/issues/delete-issue-modal.tsx @@ -17,7 +17,7 @@ import { ExclamationTriangleIcon } from "@heroicons/react/24/outline"; // ui import { SecondaryButton, DangerButton } from "components/ui"; // types -import type { IIssue } from "types"; +import type { ICurrentUserResponse, IIssue } from "types"; // fetch-keys import { CYCLE_ISSUES_WITH_PARAMS, @@ -30,9 +30,10 @@ type Props = { isOpen: boolean; handleClose: () => void; data: IIssue | null; + user: ICurrentUserResponse | undefined; }; -export const DeleteIssueModal: React.FC = ({ isOpen, handleClose, data }) => { +export const DeleteIssueModal: React.FC = ({ isOpen, handleClose, data, user }) => { const [isDeleteLoading, setIsDeleteLoading] = useState(false); const router = useRouter(); @@ -57,7 +58,7 @@ export const DeleteIssueModal: React.FC = ({ isOpen, handleClose, data }) if (!workspaceSlug || !projectId || !data) return; await issueServices - .deleteIssue(workspaceSlug as string, projectId as string, data.id) + .deleteIssue(workspaceSlug as string, projectId as string, data.id, user) .then(() => { if (issueView === "calendar") { const calendarFetchKey = cycleId diff --git a/apps/app/components/issues/form.tsx b/apps/app/components/issues/form.tsx index f09e5aedd..894830bd7 100644 --- a/apps/app/components/issues/form.tsx +++ b/apps/app/components/issues/form.tsx @@ -39,7 +39,7 @@ import { SparklesIcon, XMarkIcon } from "@heroicons/react/24/outline"; // helpers import { cosineSimilarity } from "helpers/string.helper"; // types -import type { IIssue } from "types"; +import type { ICurrentUserResponse, IIssue } from "types"; // rich-text-editor const RemirrorRichTextEditor = dynamic(() => import("components/rich-text-editor"), { ssr: false, @@ -91,6 +91,7 @@ export interface IssueFormProps { setCreateMore: React.Dispatch>; handleClose: () => void; status: boolean; + user: ICurrentUserResponse | undefined; } export const IssueForm: FC = ({ @@ -103,6 +104,7 @@ export const IssueForm: FC = ({ setCreateMore, handleClose, status, + user, }) => { // states const [mostSimilarIssue, setMostSimilarIssue] = useState(); @@ -177,10 +179,15 @@ export const IssueForm: FC = ({ setIAmFeelingLucky(true); aiService - .createGptTask(workspaceSlug as string, projectId as string, { - prompt: issueName, - task: "Generate a proper description for this issue in context of a project management software.", - }) + .createGptTask( + workspaceSlug as string, + projectId as string, + { + prompt: issueName, + task: "Generate a proper description for this issue in context of a project management software.", + }, + user + ) .then((res) => { if (res.response === "") setToastAlert({ @@ -227,12 +234,18 @@ export const IssueForm: FC = ({ isOpen={stateModal} handleClose={() => setStateModal(false)} projectId={projectId} + user={user} + /> + setCycleModal(false)} + user={user} /> - setCycleModal(false)} /> setLabelModal(false)} projectId={projectId} + user={user} /> )} diff --git a/apps/app/components/issues/modal.tsx b/apps/app/components/issues/modal.tsx index 3be8e58ae..3210e350a 100644 --- a/apps/app/components/issues/modal.tsx +++ b/apps/app/components/issues/modal.tsx @@ -102,9 +102,15 @@ export const CreateUpdateIssueModal: React.FC = ({ if (!workspaceSlug || !projectId) return; await issuesService - .addIssueToCycle(workspaceSlug as string, activeProject ?? "", cycleId, { - issues: [issueId], - }) + .addIssueToCycle( + workspaceSlug as string, + activeProject ?? "", + cycleId, + { + issues: [issueId], + }, + user + ) .then(() => { if (cycleId) { mutate(CYCLE_ISSUES_WITH_PARAMS(cycleId, params)); @@ -117,9 +123,15 @@ export const CreateUpdateIssueModal: React.FC = ({ if (!workspaceSlug || !projectId) return; await modulesService - .addIssuesToModule(workspaceSlug as string, activeProject ?? "", moduleId as string, { - issues: [issueId], - }) + .addIssuesToModule( + workspaceSlug as string, + activeProject ?? "", + moduleId as string, + { + issues: [issueId], + }, + user + ) .then(() => { if (moduleId) { mutate(MODULE_ISSUES_WITH_PARAMS(moduleId as string, params)); @@ -148,7 +160,7 @@ export const CreateUpdateIssueModal: React.FC = ({ if (!workspaceSlug) return; await issuesService - .createIssues(workspaceSlug as string, activeProject ?? "", payload) + .createIssues(workspaceSlug as string, activeProject ?? "", payload, user) .then(async (res) => { mutate(PROJECT_ISSUES_LIST_WITH_PARAMS(activeProject ?? "", params)); if (payload.cycle && payload.cycle !== "") await addIssueToCycle(res.id, payload.cycle); @@ -180,7 +192,7 @@ export const CreateUpdateIssueModal: React.FC = ({ const updateIssue = async (payload: Partial) => { await issuesService - .updateIssue(workspaceSlug as string, activeProject ?? "", data?.id ?? "", payload) + .updateIssue(workspaceSlug as string, activeProject ?? "", data?.id ?? "", payload, user) .then((res) => { if (isUpdatingSingleIssue) { mutate(PROJECT_ISSUES_DETAILS, (prevData) => ({ ...prevData, ...res }), false); @@ -261,6 +273,7 @@ export const CreateUpdateIssueModal: React.FC = ({ projectId={activeProject ?? ""} setActiveProject={setActiveProject} status={data ? true : false} + user={user} /> diff --git a/apps/app/components/issues/my-issues-list-item.tsx b/apps/app/components/issues/my-issues-list-item.tsx index 06cd6f87f..e026b2f89 100644 --- a/apps/app/components/issues/my-issues-list-item.tsx +++ b/apps/app/components/issues/my-issues-list-item.tsx @@ -7,6 +7,7 @@ import { mutate } from "swr"; // hooks import useToast from "hooks/use-toast"; +import useUserAuth from "hooks/use-user-auth"; // services import issuesService from "services/issues.service"; // components @@ -37,6 +38,9 @@ type Props = { export const MyIssuesListItem: React.FC = ({ issue, properties, projectId }) => { const router = useRouter(); const { workspaceSlug } = router.query; + + const { user } = useUserAuth(); + const { setToastAlert } = useToast(); const partialUpdateIssue = useCallback( @@ -55,7 +59,7 @@ export const MyIssuesListItem: React.FC = ({ issue, properties, projectId ); issuesService - .patchIssue(workspaceSlug as string, projectId as string, issueId, formData) + .patchIssue(workspaceSlug as string, projectId as string, issueId, formData, user) .then((res) => { mutate(USER_ISSUE(workspaceSlug as string)); }) @@ -110,6 +114,7 @@ export const MyIssuesListItem: React.FC = ({ issue, properties, projectId )} @@ -117,6 +122,7 @@ export const MyIssuesListItem: React.FC = ({ issue, properties, projectId )} @@ -124,6 +130,7 @@ export const MyIssuesListItem: React.FC = ({ issue, properties, projectId )} diff --git a/apps/app/components/issues/sidebar.tsx b/apps/app/components/issues/sidebar.tsx index 869dda5c1..5b15fd46f 100644 --- a/apps/app/components/issues/sidebar.tsx +++ b/apps/app/components/issues/sidebar.tsx @@ -12,6 +12,7 @@ import { TwitterPicker } from "react-color"; import { Popover, Listbox, Transition } from "@headlessui/react"; // hooks import useToast from "hooks/use-toast"; +import useUserAuth from "hooks/use-user-auth"; // services import issuesService from "services/issues.service"; import modulesService from "services/modules.service"; @@ -76,6 +77,8 @@ export const IssueDetailsSidebar: React.FC = ({ const router = useRouter(); const { workspaceSlug, projectId, issueId } = router.query; + const { user } = useUserAuth(); + const { memberRole } = useProjectMyMembership(); const { setToastAlert } = useToast(); @@ -110,7 +113,7 @@ export const IssueDetailsSidebar: React.FC = ({ const handleNewLabel = (formData: any) => { if (!workspaceSlug || !projectId || isSubmitting) return; issuesService - .createIssueLabel(workspaceSlug as string, projectId as string, formData) + .createIssueLabel(workspaceSlug as string, projectId as string, formData, user) .then((res) => { reset(defaultValues); issueLabelMutate((prevData) => [...(prevData ?? []), res], false); @@ -124,9 +127,15 @@ export const IssueDetailsSidebar: React.FC = ({ if (!workspaceSlug || !projectId || !issueDetail) return; issuesService - .addIssueToCycle(workspaceSlug as string, projectId as string, cycleDetails.id, { - issues: [issueDetail.id], - }) + .addIssueToCycle( + workspaceSlug as string, + projectId as string, + cycleDetails.id, + { + issues: [issueDetail.id], + }, + user + ) .then((res) => { mutate(ISSUE_DETAILS(issueId as string)); }); @@ -139,9 +148,15 @@ export const IssueDetailsSidebar: React.FC = ({ if (!workspaceSlug || !projectId || !issueDetail) return; modulesService - .addIssuesToModule(workspaceSlug as string, projectId as string, moduleDetail.id, { - issues: [issueDetail.id], - }) + .addIssuesToModule( + workspaceSlug as string, + projectId as string, + moduleDetail.id, + { + issues: [issueDetail.id], + }, + user + ) .then((res) => { mutate(ISSUE_DETAILS(issueId as string)); }); @@ -228,6 +243,7 @@ export const IssueDetailsSidebar: React.FC = ({ handleClose={() => setDeleteIssueModal(false)} isOpen={deleteIssueModal} data={issueDetail ?? null} + user={user} />
diff --git a/apps/app/components/issues/sub-issues-list.tsx b/apps/app/components/issues/sub-issues-list.tsx index 351bf47c5..76424767e 100644 --- a/apps/app/components/issues/sub-issues-list.tsx +++ b/apps/app/components/issues/sub-issues-list.tsx @@ -21,15 +21,16 @@ import { ChevronRightIcon, PlusIcon, XMarkIcon } from "@heroicons/react/24/outli // helpers import { orderArrayBy } from "helpers/array.helper"; // types -import { IIssue, ISubIssueResponse } from "types"; +import { ICurrentUserResponse, IIssue, ISubIssueResponse } from "types"; // fetch-keys import { PROJECT_ISSUES_LIST, SUB_ISSUES } from "constants/fetch-keys"; type Props = { parentIssue: IIssue; + user: ICurrentUserResponse | undefined; }; -export const SubIssuesList: FC = ({ parentIssue }) => { +export const SubIssuesList: FC = ({ parentIssue, user }) => { // states const [createIssueModal, setCreateIssueModal] = useState(false); const [subIssuesListModal, setSubIssuesListModal] = useState(false); @@ -134,7 +135,7 @@ export const SubIssuesList: FC = ({ parentIssue }) => { ); issuesService - .patchIssue(workspaceSlug.toString(), projectId.toString(), issueId, { parent: null }) + .patchIssue(workspaceSlug.toString(), projectId.toString(), issueId, { parent: null }, user) .then((res) => { mutate(SUB_ISSUES(parentIssue.id ?? "")); diff --git a/apps/app/components/issues/view-select/assignee.tsx b/apps/app/components/issues/view-select/assignee.tsx index 71e16a092..b15b17176 100644 --- a/apps/app/components/issues/view-select/assignee.tsx +++ b/apps/app/components/issues/view-select/assignee.tsx @@ -12,7 +12,7 @@ import { AssigneesList, Avatar, CustomSearchSelect, Tooltip } from "components/u // icons import { UserGroupIcon } from "@heroicons/react/24/outline"; // types -import { IIssue } from "types"; +import { ICurrentUserResponse, IIssue } from "types"; // fetch-keys import { PROJECT_MEMBERS } from "constants/fetch-keys"; @@ -22,6 +22,7 @@ type Props = { position?: "left" | "right"; selfPositioned?: boolean; tooltipPosition?: "left" | "right"; + user: ICurrentUserResponse | undefined; isNotAllowed: boolean; }; @@ -31,6 +32,7 @@ export const ViewAssigneeSelect: React.FC = ({ position = "left", selfPositioned = false, tooltipPosition = "right", + user, isNotAllowed, }) => { const router = useRouter(); @@ -83,7 +85,8 @@ export const ViewAssigneeSelect: React.FC = ({ projectName: issue.project_detail.name, issueId: issue.id, }, - "ISSUE_PROPERTY_UPDATE_ASSIGNEE" + "ISSUE_PROPERTY_UPDATE_ASSIGNEE", + user ); }} options={options} diff --git a/apps/app/components/issues/view-select/due-date.tsx b/apps/app/components/issues/view-select/due-date.tsx index 60fa8c718..bea5ff045 100644 --- a/apps/app/components/issues/view-select/due-date.tsx +++ b/apps/app/components/issues/view-select/due-date.tsx @@ -7,15 +7,21 @@ import { findHowManyDaysLeft } from "helpers/date-time.helper"; // services import trackEventServices from "services/track-event.service"; // types -import { IIssue } from "types"; +import { ICurrentUserResponse, IIssue } from "types"; type Props = { issue: IIssue; partialUpdateIssue: (formData: Partial, issueId: string) => void; + user: ICurrentUserResponse | undefined; isNotAllowed: boolean; }; -export const ViewDueDateSelect: React.FC = ({ issue, partialUpdateIssue, isNotAllowed }) => { +export const ViewDueDateSelect: React.FC = ({ + issue, + partialUpdateIssue, + user, + isNotAllowed, +}) => { const router = useRouter(); const { workspaceSlug } = router.query; @@ -51,7 +57,8 @@ export const ViewDueDateSelect: React.FC = ({ issue, partialUpdateIssue, projectName: issue.project_detail.name, issueId: issue.id, }, - "ISSUE_PROPERTY_UPDATE_DUE_DATE" + "ISSUE_PROPERTY_UPDATE_DUE_DATE", + user ); }} className={issue?.target_date ? "w-[6.5rem]" : "w-[5rem] text-center"} diff --git a/apps/app/components/issues/view-select/estimate.tsx b/apps/app/components/issues/view-select/estimate.tsx index 586f930bc..914a5286e 100644 --- a/apps/app/components/issues/view-select/estimate.tsx +++ b/apps/app/components/issues/view-select/estimate.tsx @@ -11,13 +11,14 @@ import { CustomSelect, Tooltip } from "components/ui"; // icons import { PlayIcon } from "@heroicons/react/24/outline"; // types -import { IIssue } from "types"; +import { ICurrentUserResponse, IIssue } from "types"; type Props = { issue: IIssue; partialUpdateIssue: (formData: Partial, issueId: string) => void; position?: "left" | "right"; selfPositioned?: boolean; + user: ICurrentUserResponse | undefined; isNotAllowed: boolean; }; @@ -26,6 +27,7 @@ export const ViewEstimateSelect: React.FC = ({ partialUpdateIssue, position = "left", selfPositioned = false, + user, isNotAllowed, }) => { const router = useRouter(); @@ -51,7 +53,8 @@ export const ViewEstimateSelect: React.FC = ({ projectName: issue.project_detail.name, issueId: issue.id, }, - "ISSUE_PROPERTY_UPDATE_ESTIMATE" + "ISSUE_PROPERTY_UPDATE_ESTIMATE", + user ); }} label={ diff --git a/apps/app/components/issues/view-select/priority.tsx b/apps/app/components/issues/view-select/priority.tsx index aa9a5306e..a0c5cd47c 100644 --- a/apps/app/components/issues/view-select/priority.tsx +++ b/apps/app/components/issues/view-select/priority.tsx @@ -7,7 +7,7 @@ import { CustomSelect, Tooltip } from "components/ui"; // icons import { getPriorityIcon } from "components/icons/priority-icon"; // types -import { IIssue } from "types"; +import { ICurrentUserResponse, IIssue } from "types"; // constants import { PRIORITIES } from "constants/project"; // services @@ -18,6 +18,7 @@ type Props = { partialUpdateIssue: (formData: Partial, issueId: string) => void; position?: "left" | "right"; selfPositioned?: boolean; + user: ICurrentUserResponse | undefined; isNotAllowed: boolean; }; @@ -26,6 +27,7 @@ export const ViewPrioritySelect: React.FC = ({ partialUpdateIssue, position = "left", selfPositioned = false, + user, isNotAllowed, }) => { const router = useRouter(); @@ -45,7 +47,8 @@ export const ViewPrioritySelect: React.FC = ({ projectName: issue.project_detail.name, issueId: issue.id, }, - "ISSUE_PROPERTY_UPDATE_PRIORITY" + "ISSUE_PROPERTY_UPDATE_PRIORITY", + user ); }} maxHeight="md" diff --git a/apps/app/components/issues/view-select/state.tsx b/apps/app/components/issues/view-select/state.tsx index 68a99ac72..2b904eb1e 100644 --- a/apps/app/components/issues/view-select/state.tsx +++ b/apps/app/components/issues/view-select/state.tsx @@ -13,7 +13,7 @@ import { getStateGroupIcon } from "components/icons"; import { addSpaceIfCamelCase } from "helpers/string.helper"; import { getStatesList } from "helpers/state.helper"; // types -import { IIssue } from "types"; +import { ICurrentUserResponse, IIssue } from "types"; // fetch-keys import { STATES_LIST } from "constants/fetch-keys"; @@ -22,6 +22,7 @@ type Props = { partialUpdateIssue: (formData: Partial, issueId: string) => void; position?: "left" | "right"; selfPositioned?: boolean; + user: ICurrentUserResponse | undefined; isNotAllowed: boolean; }; @@ -30,6 +31,7 @@ export const ViewStateSelect: React.FC = ({ partialUpdateIssue, position = "left", selfPositioned = false, + user, isNotAllowed, }) => { const router = useRouter(); @@ -77,21 +79,25 @@ export const ViewStateSelect: React.FC = ({ projectName: issue.project_detail.name, issueId: issue.id, }, - "ISSUE_PROPERTY_UPDATE_STATE" + "ISSUE_PROPERTY_UPDATE_STATE", + user ); const oldState = states.find((s) => s.id === issue.state); const newState = states.find((s) => s.id === data); if (oldState?.group !== "completed" && newState?.group !== "completed") { - trackEventServices.trackIssueMarkedAsDoneEvent({ - workspaceSlug: issue.workspace_detail.slug, - workspaceId: issue.workspace_detail.id, - projectId: issue.project_detail.id, - projectIdentifier: issue.project_detail.identifier, - projectName: issue.project_detail.name, - issueId: issue.id, - }); + trackEventServices.trackIssueMarkedAsDoneEvent( + { + workspaceSlug: issue.workspace_detail.slug, + workspaceId: issue.workspace_detail.id, + projectId: issue.project_detail.id, + projectIdentifier: issue.project_detail.identifier, + projectName: issue.project_detail.name, + issueId: issue.id, + }, + user + ); } }} options={options} diff --git a/apps/app/components/labels/create-label-modal.tsx b/apps/app/components/labels/create-label-modal.tsx index 858f7f7b5..c7566dc77 100644 --- a/apps/app/components/labels/create-label-modal.tsx +++ b/apps/app/components/labels/create-label-modal.tsx @@ -17,7 +17,7 @@ import { Input, PrimaryButton, SecondaryButton } from "components/ui"; // icons import { ChevronDownIcon } from "@heroicons/react/24/outline"; // types -import type { IIssueLabels, IState } from "types"; +import type { ICurrentUserResponse, IIssueLabels, IState } from "types"; // constants import { PROJECT_ISSUE_LABELS } from "constants/fetch-keys"; @@ -26,6 +26,7 @@ type Props = { isOpen: boolean; projectId: string; handleClose: () => void; + user: ICurrentUserResponse | undefined; }; const defaultValues: Partial = { @@ -33,7 +34,7 @@ const defaultValues: Partial = { color: "#858E96", }; -export const CreateLabelModal: React.FC = ({ isOpen, projectId, handleClose }) => { +export const CreateLabelModal: React.FC = ({ isOpen, projectId, handleClose, user }) => { const router = useRouter(); const { workspaceSlug } = router.query; @@ -57,7 +58,7 @@ export const CreateLabelModal: React.FC = ({ isOpen, projectId, handleClo if (!workspaceSlug) return; await issuesService - .createIssueLabel(workspaceSlug as string, projectId as string, formData) + .createIssueLabel(workspaceSlug as string, projectId as string, formData, user) .then((res) => { mutate( PROJECT_ISSUE_LABELS(projectId), diff --git a/apps/app/components/labels/create-update-label-inline.tsx b/apps/app/components/labels/create-update-label-inline.tsx index 7010d564e..7b1a04b91 100644 --- a/apps/app/components/labels/create-update-label-inline.tsx +++ b/apps/app/components/labels/create-update-label-inline.tsx @@ -6,6 +6,8 @@ import { mutate } from "swr"; // react-hook-form import { Controller, SubmitHandler, useForm } from "react-hook-form"; +// hooks +import useUserAuth from "hooks/use-user-auth"; // react-color import { TwitterPicker } from "react-color"; // headless ui @@ -42,6 +44,8 @@ export const CreateUpdateLabelInline = forwardRef(function CreateUpd const router = useRouter(); const { workspaceSlug, projectId } = router.query; + const { user } = useUserAuth(); + const { handleSubmit, control, @@ -58,7 +62,7 @@ export const CreateUpdateLabelInline = forwardRef(function CreateUpd if (!workspaceSlug || !projectId || isSubmitting) return; await issuesService - .createIssueLabel(workspaceSlug as string, projectId as string, formData) + .createIssueLabel(workspaceSlug as string, projectId as string, formData, user) .then((res) => { mutate( PROJECT_ISSUE_LABELS(projectId as string), @@ -78,7 +82,8 @@ export const CreateUpdateLabelInline = forwardRef(function CreateUpd workspaceSlug as string, projectId as string, labelToUpdate?.id ?? "", - formData + formData, + user ) .then(() => { reset(defaultValues); diff --git a/apps/app/components/labels/delete-label-modal.tsx b/apps/app/components/labels/delete-label-modal.tsx index 772c9d064..dd3df0fc4 100644 --- a/apps/app/components/labels/delete-label-modal.tsx +++ b/apps/app/components/labels/delete-label-modal.tsx @@ -15,7 +15,7 @@ import useToast from "hooks/use-toast"; // ui import { DangerButton, SecondaryButton } from "components/ui"; // types -import type { IIssueLabels } from "types"; +import type { ICurrentUserResponse, IIssueLabels } from "types"; // fetch-keys import { PROJECT_ISSUE_LABELS } from "constants/fetch-keys"; @@ -23,9 +23,10 @@ type Props = { isOpen: boolean; onClose: () => void; data: IIssueLabels | null; + user: ICurrentUserResponse | undefined; }; -export const DeleteLabelModal: React.FC = ({ isOpen, onClose, data }) => { +export const DeleteLabelModal: React.FC = ({ isOpen, onClose, data, user }) => { const [isDeleteLoading, setIsDeleteLoading] = useState(false); const router = useRouter(); @@ -50,7 +51,7 @@ export const DeleteLabelModal: React.FC = ({ isOpen, onClose, data }) => ); await issuesService - .deleteIssueLabel(workspaceSlug.toString(), projectId.toString(), data.id) + .deleteIssueLabel(workspaceSlug.toString(), projectId.toString(), data.id, user) .then(() => handleClose()) .catch(() => { setIsDeleteLoading(false); diff --git a/apps/app/components/labels/labels-list-modal.tsx b/apps/app/components/labels/labels-list-modal.tsx index 8d3c04672..23f60ab7f 100644 --- a/apps/app/components/labels/labels-list-modal.tsx +++ b/apps/app/components/labels/labels-list-modal.tsx @@ -11,7 +11,7 @@ import { RectangleStackIcon, MagnifyingGlassIcon } from "@heroicons/react/24/out // services import issuesService from "services/issues.service"; // types -import { IIssueLabels } from "types"; +import { ICurrentUserResponse, IIssueLabels } from "types"; // constants import { PROJECT_ISSUE_LABELS } from "constants/fetch-keys"; @@ -19,9 +19,10 @@ type Props = { isOpen: boolean; handleClose: () => void; parent: IIssueLabels | undefined; + user: ICurrentUserResponse | undefined; }; -export const LabelsListModal: React.FC = ({ isOpen, handleClose, parent }) => { +export const LabelsListModal: React.FC = ({ isOpen, handleClose, parent, user }) => { const [query, setQuery] = useState(""); const router = useRouter(); @@ -58,9 +59,15 @@ export const LabelsListModal: React.FC = ({ isOpen, handleClose, parent } ); await issuesService - .patchIssueLabel(workspaceSlug as string, projectId as string, label.id, { - parent: parent?.id ?? "", - }) + .patchIssueLabel( + workspaceSlug as string, + projectId as string, + label.id, + { + parent: parent?.id ?? "", + }, + user + ) .then(() => mutate()); }; diff --git a/apps/app/components/labels/single-label-group.tsx b/apps/app/components/labels/single-label-group.tsx index 00837a05c..f1a74f296 100644 --- a/apps/app/components/labels/single-label-group.tsx +++ b/apps/app/components/labels/single-label-group.tsx @@ -20,7 +20,7 @@ import { TrashIcon, } from "@heroicons/react/24/outline"; // types -import { IIssueLabels } from "types"; +import { ICurrentUserResponse, IIssueLabels } from "types"; // fetch-keys import { PROJECT_ISSUE_LABELS } from "constants/fetch-keys"; @@ -30,6 +30,7 @@ type Props = { addLabelToGroup: (parentLabel: IIssueLabels) => void; editLabel: (label: IIssueLabels) => void; handleLabelDelete: () => void; + user: ICurrentUserResponse | undefined; }; export const SingleLabelGroup: React.FC = ({ @@ -38,6 +39,7 @@ export const SingleLabelGroup: React.FC = ({ addLabelToGroup, editLabel, handleLabelDelete, + user, }) => { const router = useRouter(); const { workspaceSlug, projectId } = router.query; @@ -57,9 +59,15 @@ export const SingleLabelGroup: React.FC = ({ ); issuesService - .patchIssueLabel(workspaceSlug as string, projectId as string, label.id, { - parent: null, - }) + .patchIssueLabel( + workspaceSlug as string, + projectId as string, + label.id, + { + parent: null, + }, + user + ) .then(() => { mutate(PROJECT_ISSUE_LABELS(projectId as string)); }); diff --git a/apps/app/components/modules/delete-module-modal.tsx b/apps/app/components/modules/delete-module-modal.tsx index f8d803732..f2a9ec7ee 100644 --- a/apps/app/components/modules/delete-module-modal.tsx +++ b/apps/app/components/modules/delete-module-modal.tsx @@ -15,7 +15,7 @@ import { SecondaryButton, DangerButton } from "components/ui"; // icons import { ExclamationTriangleIcon } from "@heroicons/react/24/outline"; // types -import type { IModule } from "types"; +import type { ICurrentUserResponse, IModule } from "types"; // fetch-keys import { MODULE_LIST } from "constants/fetch-keys"; @@ -23,9 +23,10 @@ type Props = { isOpen: boolean; setIsOpen: React.Dispatch>; data?: IModule; + user: ICurrentUserResponse | undefined; }; -export const DeleteModuleModal: React.FC = ({ isOpen, setIsOpen, data }) => { +export const DeleteModuleModal: React.FC = ({ isOpen, setIsOpen, data, user }) => { const [isDeleteLoading, setIsDeleteLoading] = useState(false); const router = useRouter(); @@ -50,7 +51,7 @@ export const DeleteModuleModal: React.FC = ({ isOpen, setIsOpen, data }) ); await modulesService - .deleteModule(workspaceSlug as string, projectId as string, data.id) + .deleteModule(workspaceSlug as string, projectId as string, data.id, user) .then(() => { if (moduleId) router.push(`/${workspaceSlug}/projects/${data.project}/modules`); handleClose(); diff --git a/apps/app/components/modules/modal.tsx b/apps/app/components/modules/modal.tsx index 69dcba34a..c06be46d5 100644 --- a/apps/app/components/modules/modal.tsx +++ b/apps/app/components/modules/modal.tsx @@ -15,7 +15,7 @@ import modulesService from "services/modules.service"; // hooks import useToast from "hooks/use-toast"; // types -import type { IModule } from "types"; +import type { ICurrentUserResponse, IModule } from "types"; // fetch-keys import { MODULE_LIST } from "constants/fetch-keys"; @@ -23,6 +23,7 @@ type Props = { isOpen: boolean; setIsOpen: React.Dispatch>; data?: IModule; + user: ICurrentUserResponse | undefined; }; const defaultValues: Partial = { @@ -33,7 +34,7 @@ const defaultValues: Partial = { members_list: [], }; -export const CreateUpdateModuleModal: React.FC = ({ isOpen, setIsOpen, data }) => { +export const CreateUpdateModuleModal: React.FC = ({ isOpen, setIsOpen, data, user }) => { const router = useRouter(); const { workspaceSlug, projectId } = router.query; @@ -50,7 +51,7 @@ export const CreateUpdateModuleModal: React.FC = ({ isOpen, setIsOpen, da const createModule = async (payload: Partial) => { await modulesService - .createModule(workspaceSlug as string, projectId as string, payload) + .createModule(workspaceSlug as string, projectId as string, payload, user) .then(() => { mutate(MODULE_LIST(projectId as string)); handleClose(); @@ -72,7 +73,7 @@ export const CreateUpdateModuleModal: React.FC = ({ isOpen, setIsOpen, da const updateModule = async (payload: Partial) => { await modulesService - .updateModule(workspaceSlug as string, projectId as string, data?.id ?? "", payload) + .updateModule(workspaceSlug as string, projectId as string, data?.id ?? "", payload, user) .then((res) => { mutate( MODULE_LIST(projectId as string), diff --git a/apps/app/components/modules/sidebar.tsx b/apps/app/components/modules/sidebar.tsx index c1b4674b7..f453e4c68 100644 --- a/apps/app/components/modules/sidebar.tsx +++ b/apps/app/components/modules/sidebar.tsx @@ -37,7 +37,7 @@ import { LinkIcon } from "@heroicons/react/20/solid"; import { renderDateFormat, renderShortDate } from "helpers/date-time.helper"; import { capitalizeFirstLetter, copyTextToClipboard } from "helpers/string.helper"; // types -import { IIssue, IModule, ModuleLink } from "types"; +import { ICurrentUserResponse, IIssue, IModule, ModuleLink } from "types"; // fetch-keys import { MODULE_DETAILS } from "constants/fetch-keys"; // constant @@ -56,9 +56,16 @@ type Props = { module?: IModule; isOpen: boolean; moduleIssues?: IIssue[]; + user: ICurrentUserResponse | undefined; }; -export const ModuleDetailsSidebar: React.FC = ({ issues, module, isOpen, moduleIssues }) => { +export const ModuleDetailsSidebar: React.FC = ({ + issues, + module, + isOpen, + moduleIssues, + user, +}) => { const [moduleDeleteModal, setModuleDeleteModal] = useState(false); const [moduleLinkModal, setModuleLinkModal] = useState(false); @@ -86,7 +93,7 @@ export const ModuleDetailsSidebar: React.FC = ({ issues, module, isOpen, ); modulesService - .patchModule(workspaceSlug as string, projectId as string, moduleId as string, data) + .patchModule(workspaceSlug as string, projectId as string, moduleId as string, data, user) .then(() => mutate(MODULE_DETAILS(moduleId as string))) .catch((e) => console.log(e)); }; @@ -181,6 +188,7 @@ export const ModuleDetailsSidebar: React.FC = ({ issues, module, isOpen, isOpen={moduleDeleteModal} setIsOpen={setModuleDeleteModal} data={module} + user={user} />
void; + user: ICurrentUserResponse | undefined; }; -export const SingleModuleCard: React.FC = ({ module, handleEditModule }) => { +export const SingleModuleCard: React.FC = ({ module, handleEditModule, user }) => { const [moduleDeleteModal, setModuleDeleteModal] = useState(false); const router = useRouter(); @@ -128,6 +129,7 @@ export const SingleModuleCard: React.FC = ({ module, handleEditModule }) isOpen={moduleDeleteModal} setIsOpen={setModuleDeleteModal} data={module} + user={user} />
diff --git a/apps/app/components/onboarding/invite-members.tsx b/apps/app/components/onboarding/invite-members.tsx index e1ebdf117..0114b2dcd 100644 --- a/apps/app/components/onboarding/invite-members.tsx +++ b/apps/app/components/onboarding/invite-members.tsx @@ -2,16 +2,17 @@ import { useForm } from "react-hook-form"; import useToast from "hooks/use-toast"; import workspaceService from "services/workspace.service"; -import { IUser } from "types"; +import { ICurrentUserResponse, IUser } from "types"; // ui components import { MultiInput, PrimaryButton, SecondaryButton } from "components/ui"; type Props = { setStep: React.Dispatch>; workspace: any; + user: ICurrentUserResponse | undefined; }; -export const InviteMembers: React.FC = ({ setStep, workspace }) => { +export const InviteMembers: React.FC = ({ setStep, workspace, user }) => { const { setToastAlert } = useToast(); const { @@ -23,7 +24,7 @@ export const InviteMembers: React.FC = ({ setStep, workspace }) => { const onSubmit = async (formData: IUser) => { await workspaceService - .inviteWorkspace(workspace.slug, formData) + .inviteWorkspace(workspace.slug, formData, user) .then(() => { setToastAlert({ type: "success", diff --git a/apps/app/components/onboarding/workspace.tsx b/apps/app/components/onboarding/workspace.tsx index 344fb74fe..137d58057 100644 --- a/apps/app/components/onboarding/workspace.tsx +++ b/apps/app/components/onboarding/workspace.tsx @@ -9,7 +9,7 @@ import { Tab } from "@headlessui/react"; // services import workspaceService from "services/workspace.service"; // types -import { IWorkspaceMemberInvitation } from "types"; +import { ICurrentUserResponse, IWorkspaceMemberInvitation } from "types"; // fetch-keys import { USER_WORKSPACE_INVITATIONS } from "constants/fetch-keys"; // constants @@ -21,9 +21,10 @@ import { getFirstCharacters, truncateText } from "helpers/string.helper"; type Props = { setStep: React.Dispatch>; setWorkspace: React.Dispatch>; + user: ICurrentUserResponse | undefined; }; -export const Workspace: React.FC = ({ setStep, setWorkspace }) => { +export const Workspace: React.FC = ({ setStep, setWorkspace, user }) => { const [isJoiningWorkspaces, setIsJoiningWorkspaces] = useState(false); const [invitationsRespond, setInvitationsRespond] = useState([]); const [defaultValues, setDefaultValues] = useState({ @@ -98,7 +99,7 @@ export const Workspace: React.FC = ({ setStep, setWorkspace }) => { >
-

Workspaces

+

Workspace

Create or join the workspace to get started with Plane.

@@ -161,7 +162,10 @@ export const Workspace: React.FC = ({ setStep, setWorkspace }) => { {truncateText(invitation.workspace.name, 30)}

- Invited by {invitation.workspace.owner.first_name} + Invited by{" "} + {invitation.created_by_detail + ? invitation.created_by_detail.first_name + : invitation.workspace.owner.first_name}

@@ -237,6 +241,7 @@ export const Workspace: React.FC = ({ setStep, setWorkspace }) => { }} defaultValues={defaultValues} setDefaultValues={setDefaultValues} + user={user} /> diff --git a/apps/app/components/pages/create-block.tsx b/apps/app/components/pages/create-block.tsx index 59bb81898..d4098db93 100644 --- a/apps/app/components/pages/create-block.tsx +++ b/apps/app/components/pages/create-block.tsx @@ -16,7 +16,7 @@ import useToast from "hooks/use-toast"; // ui import { TextArea } from "components/ui"; // types -import { IPageBlock } from "types"; +import { ICurrentUserResponse, IPageBlock } from "types"; // fetch-keys import { PAGE_BLOCKS_LIST } from "constants/fetch-keys"; @@ -24,7 +24,11 @@ const defaultValues = { name: "", }; -export const CreateBlock = () => { +type Props = { + user: ICurrentUserResponse | undefined; +}; + +export const CreateBlock: React.FC = ({ user }) => { const [blockTitle, setBlockTitle] = useState(""); const router = useRouter(); @@ -49,9 +53,15 @@ export const CreateBlock = () => { if (!workspaceSlug || !projectId || !pageId) return; await pagesService - .createPageBlock(workspaceSlug as string, projectId as string, pageId as string, { - name: watch("name"), - }) + .createPageBlock( + workspaceSlug as string, + projectId as string, + pageId as string, + { + name: watch("name"), + }, + user + ) .then((res) => { mutate( PAGE_BLOCKS_LIST(pageId as string), diff --git a/apps/app/components/pages/create-update-block-inline.tsx b/apps/app/components/pages/create-update-block-inline.tsx index 528c83f9e..27e6bd419 100644 --- a/apps/app/components/pages/create-update-block-inline.tsx +++ b/apps/app/components/pages/create-update-block-inline.tsx @@ -20,7 +20,7 @@ import { GptAssistantModal } from "components/core"; // ui import { Loader, PrimaryButton, SecondaryButton, TextArea } from "components/ui"; // types -import { IPageBlock } from "types"; +import { ICurrentUserResponse, IPageBlock } from "types"; // fetch-keys import { PAGE_BLOCKS_LIST } from "constants/fetch-keys"; @@ -30,6 +30,7 @@ type Props = { handleAiAssistance?: (response: string) => void; setIsSyncing?: React.Dispatch>; focus?: keyof IPageBlock; + user: ICurrentUserResponse | undefined; }; const defaultValues = { @@ -61,6 +62,7 @@ export const CreateUpdateBlockInline: React.FC = ({ handleAiAssistance, setIsSyncing, focus, + user, }) => { const [iAmFeelingLucky, setIAmFeelingLucky] = useState(false); const [gptAssistantModal, setGptAssistantModal] = useState(false); @@ -96,11 +98,17 @@ export const CreateUpdateBlockInline: React.FC = ({ if (!workspaceSlug || !projectId || !pageId) return; await pagesService - .createPageBlock(workspaceSlug as string, projectId as string, pageId as string, { - name: formData.name, - description: formData.description ?? "", - description_html: formData.description_html ?? "

", - }) + .createPageBlock( + workspaceSlug as string, + projectId as string, + pageId as string, + { + name: formData.name, + description: formData.description ?? "", + description_html: formData.description_html ?? "

", + }, + user + ) .then((res) => { mutate( PAGE_BLOCKS_LIST(pageId as string), @@ -139,21 +147,34 @@ export const CreateUpdateBlockInline: React.FC = ({ ); await pagesService - .patchPageBlock(workspaceSlug as string, projectId as string, pageId as string, data.id, { - name: formData.name, - description: formData.description, - description_html: formData.description_html, - }) + .patchPageBlock( + workspaceSlug as string, + projectId as string, + pageId as string, + data.id, + { + name: formData.name, + description: formData.description, + description_html: formData.description_html, + }, + user + ) .then((res) => { mutate(PAGE_BLOCKS_LIST(pageId as string)); editorRef.current?.setEditorValue(res.description_html); if (data.issue && data.sync) issuesService - .patchIssue(workspaceSlug as string, projectId as string, data.issue, { - name: res.name, - description: res.description, - description_html: res.description_html, - }) + .patchIssue( + workspaceSlug as string, + projectId as string, + data.issue, + { + name: res.name, + description: res.description, + description_html: res.description_html, + }, + user + ) .finally(() => { if (setIsSyncing) setIsSyncing(false); }); @@ -169,10 +190,15 @@ export const CreateUpdateBlockInline: React.FC = ({ setIAmFeelingLucky(true); aiService - .createGptTask(workspaceSlug as string, projectId as string, { - prompt: watch("name"), - task: "Generate a proper description for this issue in context of a project management software.", - }) + .createGptTask( + workspaceSlug as string, + projectId as string, + { + prompt: watch("name"), + task: "Generate a proper description for this issue in context of a project management software.", + }, + user + ) .then((res) => { if (res.response === "") setToastAlert({ diff --git a/apps/app/components/pages/create-update-page-modal.tsx b/apps/app/components/pages/create-update-page-modal.tsx index 8c26e0d00..57e25b5f7 100644 --- a/apps/app/components/pages/create-update-page-modal.tsx +++ b/apps/app/components/pages/create-update-page-modal.tsx @@ -13,7 +13,7 @@ import useToast from "hooks/use-toast"; // components import { PageForm } from "./page-form"; // types -import { IPage } from "types"; +import { ICurrentUserResponse, IPage } from "types"; // fetch-keys import { ALL_PAGES_LIST, @@ -26,9 +26,10 @@ type Props = { isOpen: boolean; handleClose: () => void; data?: IPage | null; + user: ICurrentUserResponse | undefined; }; -export const CreateUpdatePageModal: React.FC = ({ isOpen, handleClose, data }) => { +export const CreateUpdatePageModal: React.FC = ({ isOpen, handleClose, data, user }) => { const router = useRouter(); const { workspaceSlug, projectId } = router.query; @@ -40,7 +41,7 @@ export const CreateUpdatePageModal: React.FC = ({ isOpen, handleClose, da const createPage = async (payload: IPage) => { await pagesService - .createPage(workspaceSlug as string, projectId as string, payload) + .createPage(workspaceSlug as string, projectId as string, payload, user) .then((res) => { mutate(RECENT_PAGES_LIST(projectId as string)); mutate( @@ -82,7 +83,7 @@ export const CreateUpdatePageModal: React.FC = ({ isOpen, handleClose, da const updatePage = async (payload: IPage) => { await pagesService - .patchPage(workspaceSlug as string, projectId as string, data?.id ?? "", payload) + .patchPage(workspaceSlug as string, projectId as string, data?.id ?? "", payload, user) .then((res) => { mutate(RECENT_PAGES_LIST(projectId as string)); mutate( diff --git a/apps/app/components/pages/delete-page-modal.tsx b/apps/app/components/pages/delete-page-modal.tsx index b2f202284..6277870d1 100644 --- a/apps/app/components/pages/delete-page-modal.tsx +++ b/apps/app/components/pages/delete-page-modal.tsx @@ -15,7 +15,7 @@ import { DangerButton, SecondaryButton } from "components/ui"; // icons import { ExclamationTriangleIcon } from "@heroicons/react/24/outline"; // types -import type { IPage } from "types"; +import type { ICurrentUserResponse, IPage } from "types"; // fetch-keys import { ALL_PAGES_LIST, @@ -28,12 +28,14 @@ type TConfirmPageDeletionProps = { isOpen: boolean; setIsOpen: React.Dispatch>; data?: IPage | null; + user: ICurrentUserResponse | undefined; }; export const DeletePageModal: React.FC = ({ isOpen, setIsOpen, data, + user, }) => { const [isDeleteLoading, setIsDeleteLoading] = useState(false); @@ -52,7 +54,7 @@ export const DeletePageModal: React.FC = ({ if (!data || !workspaceSlug || !projectId) return; await pagesService - .deletePage(workspaceSlug as string, data.project, data.id) + .deletePage(workspaceSlug as string, data.project, data.id, user) .then(() => { mutate(RECENT_PAGES_LIST(projectId as string)); mutate( diff --git a/apps/app/components/pages/pages-view.tsx b/apps/app/components/pages/pages-view.tsx index a1c0d083f..7d1eac724 100644 --- a/apps/app/components/pages/pages-view.tsx +++ b/apps/app/components/pages/pages-view.tsx @@ -8,6 +8,7 @@ import pagesService from "services/pages.service"; import projectService from "services/project.service"; // hooks import useToast from "hooks/use-toast"; +import useUserAuth from "hooks/use-user-auth"; // components import { CreateUpdatePageModal, @@ -44,6 +45,8 @@ export const PagesView: React.FC = ({ pages, viewType }) => { const router = useRouter(); const { workspaceSlug, projectId } = router.query; + const { user } = useUserAuth(); + const { setToastAlert } = useToast(); const { data: people } = useSWR( @@ -181,7 +184,7 @@ export const PagesView: React.FC = ({ pages, viewType }) => { ); pagesService - .patchPage(workspaceSlug.toString(), projectId.toString(), page.id, formData) + .patchPage(workspaceSlug.toString(), projectId.toString(), page.id, formData, user) .then(() => { mutate(RECENT_PAGES_LIST(projectId.toString())); }); @@ -193,11 +196,13 @@ export const PagesView: React.FC = ({ pages, viewType }) => { isOpen={createUpdatePageModal} handleClose={() => setCreateUpdatePageModal(false)} data={selectedPageToUpdate} + user={user} /> {pages ? (
diff --git a/apps/app/components/pages/single-page-block.tsx b/apps/app/components/pages/single-page-block.tsx index 42f0e5523..3efbd33eb 100644 --- a/apps/app/components/pages/single-page-block.tsx +++ b/apps/app/components/pages/single-page-block.tsx @@ -35,7 +35,7 @@ import { // helpers import { copyTextToClipboard } from "helpers/string.helper"; // types -import { IIssue, IPageBlock, IProject } from "types"; +import { ICurrentUserResponse, IIssue, IPageBlock, IProject } from "types"; // fetch-keys import { PAGE_BLOCKS_LIST } from "constants/fetch-keys"; @@ -43,9 +43,10 @@ type Props = { block: IPageBlock; projectDetails: IProject | undefined; index: number; + user: ICurrentUserResponse | undefined; }; -export const SinglePageBlock: React.FC = ({ block, projectDetails, index }) => { +export const SinglePageBlock: React.FC = ({ block, projectDetails, index, user }) => { const [isSyncing, setIsSyncing] = useState(false); const [createBlockForm, setCreateBlockForm] = useState(false); const [iAmFeelingLucky, setIAmFeelingLucky] = useState(false); @@ -87,20 +88,33 @@ export const SinglePageBlock: React.FC = ({ block, projectDetails, index ); await pagesService - .patchPageBlock(workspaceSlug as string, projectId as string, pageId as string, block.id, { - name: formData.name, - description: formData.description, - description_html: formData.description_html, - }) + .patchPageBlock( + workspaceSlug as string, + projectId as string, + pageId as string, + block.id, + { + name: formData.name, + description: formData.description, + description_html: formData.description_html, + }, + user + ) .then((res) => { mutate(PAGE_BLOCKS_LIST(pageId as string)); if (block.issue && block.sync) issuesService - .patchIssue(workspaceSlug as string, projectId as string, block.issue, { - name: res.name, - description: res.description, - description_html: res.description_html, - }) + .patchIssue( + workspaceSlug as string, + projectId as string, + block.issue, + { + name: res.name, + description: res.description, + description_html: res.description_html, + }, + user + ) .finally(() => setIsSyncing(false)); }); }; @@ -113,7 +127,8 @@ export const SinglePageBlock: React.FC = ({ block, projectDetails, index workspaceSlug as string, projectId as string, pageId as string, - block.id + block.id, + user ) .then((res: IIssue) => { mutate( @@ -152,7 +167,13 @@ export const SinglePageBlock: React.FC = ({ block, projectDetails, index ); await pagesService - .deletePageBlock(workspaceSlug as string, projectId as string, pageId as string, block.id) + .deletePageBlock( + workspaceSlug as string, + projectId as string, + pageId as string, + block.id, + user + ) .catch(() => { setToastAlert({ type: "error", @@ -168,10 +189,15 @@ export const SinglePageBlock: React.FC = ({ block, projectDetails, index setIAmFeelingLucky(true); aiService - .createGptTask(workspaceSlug as string, projectId as string, { - prompt: block.name, - task: "Generate a proper description for this issue in context of a project management software.", - }) + .createGptTask( + workspaceSlug as string, + projectId as string, + { + prompt: block.name, + task: "Generate a proper description for this issue in context of a project management software.", + }, + user + ) .then((res) => { if (res.response === "") setToastAlert({ @@ -243,7 +269,8 @@ export const SinglePageBlock: React.FC = ({ block, projectDetails, index block.id, { sync: !block.sync, - } + }, + user ); }; @@ -281,6 +308,7 @@ export const SinglePageBlock: React.FC = ({ block, projectDetails, index data={block} setIsSyncing={setIsSyncing} focus="name" + user={user} />
) : ( diff --git a/apps/app/components/project/create-project-modal.tsx b/apps/app/components/project/create-project-modal.tsx index c731c12f0..ca60adde1 100644 --- a/apps/app/components/project/create-project-modal.tsx +++ b/apps/app/components/project/create-project-modal.tsx @@ -24,7 +24,7 @@ import EmojiIconPicker from "components/emoji-icon-picker"; // helpers import { getRandomEmoji } from "helpers/common.helper"; // types -import { IProject } from "types"; +import { ICurrentUserResponse, IProject } from "types"; // fetch-keys import { PROJECTS_LIST, WORKSPACE_MEMBERS_ME } from "constants/fetch-keys"; // constants @@ -33,6 +33,7 @@ import { NETWORK_CHOICES } from "constants/project"; type Props = { isOpen: boolean; setIsOpen: React.Dispatch>; + user: ICurrentUserResponse | undefined; }; const defaultValues: Partial = { @@ -63,7 +64,7 @@ const IsGuestCondition: React.FC<{ }; export const CreateProjectModal: React.FC = (props) => { - const { isOpen, setIsOpen } = props; + const { isOpen, setIsOpen, user } = props; const [isChangeIdentifierRequired, setIsChangeIdentifierRequired] = useState(true); @@ -120,7 +121,7 @@ export const CreateProjectModal: React.FC = (props) => { else payload.emoji = formData.emoji_and_icon; await projectServices - .createProject(workspaceSlug as string, payload) + .createProject(workspaceSlug as string, payload, user) .then((res) => { mutate( PROJECTS_LIST(workspaceSlug as string), diff --git a/apps/app/components/project/delete-project-modal.tsx b/apps/app/components/project/delete-project-modal.tsx index 49d3f745b..5a4be1706 100644 --- a/apps/app/components/project/delete-project-modal.tsx +++ b/apps/app/components/project/delete-project-modal.tsx @@ -13,7 +13,7 @@ import { ExclamationTriangleIcon } from "@heroicons/react/24/outline"; // ui import { DangerButton, Input, SecondaryButton } from "components/ui"; // types -import type { IProject, IWorkspace } from "types"; +import type { ICurrentUserResponse, IProject, IWorkspace } from "types"; // fetch-keys import { PROJECTS_LIST } from "constants/fetch-keys"; @@ -22,6 +22,7 @@ type TConfirmProjectDeletionProps = { onClose: () => void; onSuccess?: () => void; data: IProject | null; + user: ICurrentUserResponse | undefined; }; export const DeleteProjectModal: React.FC = ({ @@ -29,6 +30,7 @@ export const DeleteProjectModal: React.FC = ({ data, onClose, onSuccess, + user, }) => { const [isDeleteLoading, setIsDeleteLoading] = useState(false); const [confirmProjectName, setConfirmProjectName] = useState(""); @@ -65,7 +67,7 @@ export const DeleteProjectModal: React.FC = ({ setIsDeleteLoading(true); if (!data || !workspaceSlug || !canDelete) return; await projectService - .deleteProject(workspaceSlug, data.id) + .deleteProject(workspaceSlug, data.id, user) .then(() => { handleClose(); mutate(PROJECTS_LIST(workspaceSlug), (prevData) => diff --git a/apps/app/components/project/send-project-invitation-modal.tsx b/apps/app/components/project/send-project-invitation-modal.tsx index d21cf07f3..e08b92e8c 100644 --- a/apps/app/components/project/send-project-invitation-modal.tsx +++ b/apps/app/components/project/send-project-invitation-modal.tsx @@ -15,7 +15,7 @@ import useToast from "hooks/use-toast"; import projectService from "services/project.service"; import workspaceService from "services/workspace.service"; // types -import { IProjectMemberInvitation } from "types"; +import { ICurrentUserResponse, IProjectMemberInvitation } from "types"; // fetch-keys import { PROJECT_INVITATIONS, WORKSPACE_MEMBERS } from "constants/fetch-keys"; // constants @@ -25,6 +25,7 @@ type Props = { isOpen: boolean; setIsOpen: React.Dispatch>; members: any[]; + user: ICurrentUserResponse | undefined; }; type ProjectMember = IProjectMemberInvitation & { @@ -40,7 +41,7 @@ const defaultValues: Partial = { user_id: "", }; -const SendProjectInvitationModal: React.FC = ({ isOpen, setIsOpen, members }) => { +const SendProjectInvitationModal: React.FC = ({ isOpen, setIsOpen, members, user }) => { const router = useRouter(); const { workspaceSlug, projectId } = router.query; @@ -70,7 +71,7 @@ const SendProjectInvitationModal: React.FC = ({ isOpen, setIsOpen, member const onSubmit = async (formData: ProjectMember) => { if (!workspaceSlug || !projectId || isSubmitting) return; await projectService - .inviteProject(workspaceSlug as string, projectId as string, formData) + .inviteProject(workspaceSlug as string, projectId as string, formData, user) .then((response) => { setIsOpen(false); mutate( diff --git a/apps/app/components/project/sidebar-list.tsx b/apps/app/components/project/sidebar-list.tsx index 9d4b9f415..f9b6c5760 100644 --- a/apps/app/components/project/sidebar-list.tsx +++ b/apps/app/components/project/sidebar-list.tsx @@ -9,6 +9,7 @@ import { PlusIcon } from "@heroicons/react/24/outline"; // hooks import useToast from "hooks/use-toast"; import useTheme from "hooks/use-theme"; +import useUserAuth from "hooks/use-user-auth"; // services import projectService from "services/project.service"; // components @@ -29,6 +30,9 @@ export const ProjectSidebarList: FC = () => { // router const router = useRouter(); const { workspaceSlug } = router.query; + + const { user } = useUserAuth(); + // states const [isCreateProjectModal, setCreateProjectModal] = useState(false); // theme @@ -136,11 +140,16 @@ export const ProjectSidebarList: FC = () => { return ( <> - + setDeleteProjectModal(false)} data={projectToDelete} + user={user} />
{favoriteProjects && favoriteProjects.length > 0 && ( diff --git a/apps/app/components/states/create-state-modal.tsx b/apps/app/components/states/create-state-modal.tsx index ed62bb9ac..dca001932 100644 --- a/apps/app/components/states/create-state-modal.tsx +++ b/apps/app/components/states/create-state-modal.tsx @@ -19,7 +19,7 @@ import { CustomSelect, Input, PrimaryButton, SecondaryButton, TextArea } from "c // icons import { ChevronDownIcon } from "@heroicons/react/24/outline"; // types -import type { IState, IStateResponse } from "types"; +import type { ICurrentUserResponse, IState, IStateResponse } from "types"; // fetch keys import { STATES_LIST } from "constants/fetch-keys"; // constants @@ -30,6 +30,7 @@ type Props = { isOpen: boolean; projectId: string; handleClose: () => void; + user: ICurrentUserResponse | undefined; }; const defaultValues: Partial = { @@ -39,7 +40,7 @@ const defaultValues: Partial = { group: "backlog", }; -export const CreateStateModal: React.FC = ({ isOpen, projectId, handleClose }) => { +export const CreateStateModal: React.FC = ({ isOpen, projectId, handleClose, user }) => { const router = useRouter(); const { workspaceSlug } = router.query; @@ -69,7 +70,7 @@ export const CreateStateModal: React.FC = ({ isOpen, projectId, handleClo }; await stateService - .createState(workspaceSlug as string, projectId, payload) + .createState(workspaceSlug as string, projectId, payload, user) .then((res) => { mutate( STATES_LIST(projectId.toString()), diff --git a/apps/app/components/states/create-update-state-inline.tsx b/apps/app/components/states/create-update-state-inline.tsx index 42ab52945..8a9d81968 100644 --- a/apps/app/components/states/create-update-state-inline.tsx +++ b/apps/app/components/states/create-update-state-inline.tsx @@ -17,7 +17,7 @@ import useToast from "hooks/use-toast"; // ui import { CustomSelect, Input, PrimaryButton, SecondaryButton } from "components/ui"; // types -import type { IState, IStateResponse } from "types"; +import type { ICurrentUserResponse, IState, IStateResponse } from "types"; // fetch-keys import { STATES_LIST } from "constants/fetch-keys"; // constants @@ -27,6 +27,7 @@ type Props = { data: IState | null; onClose: () => void; selectedGroup: StateGroup | null; + user: ICurrentUserResponse | undefined; }; export type StateGroup = "backlog" | "unstarted" | "started" | "completed" | "cancelled" | null; @@ -37,7 +38,12 @@ const defaultValues: Partial = { group: "backlog", }; -export const CreateUpdateStateInline: React.FC = ({ data, onClose, selectedGroup }) => { +export const CreateUpdateStateInline: React.FC = ({ + data, + onClose, + selectedGroup, + user, +}) => { const router = useRouter(); const { workspaceSlug, projectId } = router.query; @@ -83,7 +89,7 @@ export const CreateUpdateStateInline: React.FC = ({ data, onClose, select if (!data) { await stateService - .createState(workspaceSlug.toString(), projectId.toString(), { ...payload }) + .createState(workspaceSlug.toString(), projectId.toString(), { ...payload }, user) .then((res) => { mutate( STATES_LIST(projectId.toString()), @@ -121,9 +127,15 @@ export const CreateUpdateStateInline: React.FC = ({ data, onClose, select }); } else { await stateService - .updateState(workspaceSlug.toString(), projectId.toString(), data.id, { - ...payload, - }) + .updateState( + workspaceSlug.toString(), + projectId.toString(), + data.id, + { + ...payload, + }, + user + ) .then(() => { mutate(STATES_LIST(projectId.toString())); handleClose(); diff --git a/apps/app/components/states/delete-state-modal.tsx b/apps/app/components/states/delete-state-modal.tsx index 7fdce5d44..a92f235c4 100644 --- a/apps/app/components/states/delete-state-modal.tsx +++ b/apps/app/components/states/delete-state-modal.tsx @@ -15,7 +15,7 @@ import useToast from "hooks/use-toast"; // ui import { DangerButton, SecondaryButton } from "components/ui"; // types -import type { IState, IStateResponse } from "types"; +import type { ICurrentUserResponse, IState, IStateResponse } from "types"; // fetch-keys import { STATES_LIST } from "constants/fetch-keys"; @@ -23,9 +23,10 @@ type Props = { isOpen: boolean; onClose: () => void; data: IState | null; + user: ICurrentUserResponse | undefined; }; -export const DeleteStateModal: React.FC = ({ isOpen, onClose, data }) => { +export const DeleteStateModal: React.FC = ({ isOpen, onClose, data, user }) => { const [isDeleteLoading, setIsDeleteLoading] = useState(false); const router = useRouter(); @@ -44,7 +45,7 @@ export const DeleteStateModal: React.FC = ({ isOpen, onClose, data }) => setIsDeleteLoading(true); await stateServices - .deleteState(workspaceSlug as string, data.project, data.id) + .deleteState(workspaceSlug as string, data.project, data.id, user) .then(() => { mutate( STATES_LIST(data.project), diff --git a/apps/app/components/states/single-state.tsx b/apps/app/components/states/single-state.tsx index d9425c524..8bf4198fe 100644 --- a/apps/app/components/states/single-state.tsx +++ b/apps/app/components/states/single-state.tsx @@ -21,7 +21,7 @@ import { addSpaceIfCamelCase } from "helpers/string.helper"; import { groupBy, orderArrayBy } from "helpers/array.helper"; import { orderStateGroups } from "helpers/state.helper"; // types -import { IState } from "types"; +import { ICurrentUserResponse, IState } from "types"; // fetch-keys import { STATES_LIST } from "constants/fetch-keys"; @@ -31,6 +31,7 @@ type Props = { statesList: IState[]; handleEditState: () => void; handleDeleteState: () => void; + user: ICurrentUserResponse | undefined; }; export const SingleState: React.FC = ({ @@ -39,6 +40,7 @@ export const SingleState: React.FC = ({ statesList, handleEditState, handleDeleteState, + user, }) => { const [isSubmitting, setIsSubmitting] = useState(false); @@ -67,14 +69,26 @@ export const SingleState: React.FC = ({ if (currentDefaultState) stateService - .patchState(workspaceSlug as string, projectId as string, currentDefaultState?.id ?? "", { - default: false, - }) + .patchState( + workspaceSlug as string, + projectId as string, + currentDefaultState?.id ?? "", + { + default: false, + }, + user + ) .then(() => { stateService - .patchState(workspaceSlug as string, projectId as string, state.id, { - default: true, - }) + .patchState( + workspaceSlug as string, + projectId as string, + state.id, + { + default: true, + }, + user + ) .then(() => { mutate(STATES_LIST(projectId as string)); setIsSubmitting(false); @@ -85,9 +99,15 @@ export const SingleState: React.FC = ({ }); else stateService - .patchState(workspaceSlug as string, projectId as string, state.id, { - default: true, - }) + .patchState( + workspaceSlug as string, + projectId as string, + state.id, + { + default: true, + }, + user + ) .then(() => { mutate(STATES_LIST(projectId as string)); setIsSubmitting(false); @@ -121,9 +141,15 @@ export const SingleState: React.FC = ({ ); stateService - .patchState(workspaceSlug as string, projectId as string, state.id, { - sequence: newSequence, - }) + .patchState( + workspaceSlug as string, + projectId as string, + state.id, + { + sequence: newSequence, + }, + user + ) .then((res) => { console.log(res); mutate(STATES_LIST(projectId as string)); diff --git a/apps/app/components/views/delete-view-modal.tsx b/apps/app/components/views/delete-view-modal.tsx index 31cfc33e9..c57c29dc3 100644 --- a/apps/app/components/views/delete-view-modal.tsx +++ b/apps/app/components/views/delete-view-modal.tsx @@ -15,7 +15,7 @@ import { DangerButton, SecondaryButton } from "components/ui"; // icons import { ExclamationTriangleIcon } from "@heroicons/react/24/outline"; // types -import type { IView } from "types"; +import type { ICurrentUserResponse, IView } from "types"; // fetch-keys import { VIEWS_LIST } from "constants/fetch-keys"; @@ -23,9 +23,10 @@ type Props = { isOpen: boolean; setIsOpen: React.Dispatch>; data: IView | null; + user: ICurrentUserResponse | undefined; }; -export const DeleteViewModal: React.FC = ({ isOpen, data, setIsOpen }) => { +export const DeleteViewModal: React.FC = ({ isOpen, data, setIsOpen, user }) => { const [isDeleteLoading, setIsDeleteLoading] = useState(false); const router = useRouter(); @@ -43,7 +44,7 @@ export const DeleteViewModal: React.FC = ({ isOpen, data, setIsOpen }) => if (!workspaceSlug || !data || !projectId) return; await viewsService - .deleteView(workspaceSlug as string, projectId as string, data.id) + .deleteView(workspaceSlug as string, projectId as string, data.id, user) .then(() => { mutate(VIEWS_LIST(projectId as string), (views) => views?.filter((view) => view.id !== data.id) diff --git a/apps/app/components/views/modal.tsx b/apps/app/components/views/modal.tsx index a04c19b64..755251356 100644 --- a/apps/app/components/views/modal.tsx +++ b/apps/app/components/views/modal.tsx @@ -13,7 +13,7 @@ import useToast from "hooks/use-toast"; // components import { ViewForm } from "components/views"; // types -import { IView } from "types"; +import { ICurrentUserResponse, IView } from "types"; // fetch-keys import { VIEWS_LIST } from "constants/fetch-keys"; @@ -22,6 +22,7 @@ type Props = { handleClose: () => void; data?: IView | null; preLoadedData?: Partial | null; + user: ICurrentUserResponse | undefined; }; export const CreateUpdateViewModal: React.FC = ({ @@ -29,6 +30,7 @@ export const CreateUpdateViewModal: React.FC = ({ handleClose, data, preLoadedData, + user, }) => { const router = useRouter(); const { workspaceSlug, projectId } = router.query; @@ -45,7 +47,7 @@ export const CreateUpdateViewModal: React.FC = ({ query_data: payload.query, }; await viewsService - .createView(workspaceSlug as string, projectId as string, payload) + .createView(workspaceSlug as string, projectId as string, payload, user) .then(() => { mutate(VIEWS_LIST(projectId as string)); handleClose(); @@ -71,7 +73,7 @@ export const CreateUpdateViewModal: React.FC = ({ query_data: payload.query, }; await viewsService - .updateView(workspaceSlug as string, projectId as string, data?.id ?? "", payloadData) + .updateView(workspaceSlug as string, projectId as string, data?.id ?? "", payloadData, user) .then((res) => { mutate( VIEWS_LIST(projectId as string), diff --git a/apps/app/components/workspace/create-workspace-form.tsx b/apps/app/components/workspace/create-workspace-form.tsx index b3415b2c8..e3da82c10 100644 --- a/apps/app/components/workspace/create-workspace-form.tsx +++ b/apps/app/components/workspace/create-workspace-form.tsx @@ -11,7 +11,7 @@ import useToast from "hooks/use-toast"; // ui import { CustomSelect, Input, PrimaryButton } from "components/ui"; // types -import { IWorkspace } from "types"; +import { ICurrentUserResponse, IWorkspace } from "types"; // fetch-keys import { USER_WORKSPACES } from "constants/fetch-keys"; // constants @@ -25,6 +25,7 @@ type Props = { company_size: number | null; }; setDefaultValues: Dispatch>; + user: ICurrentUserResponse | undefined; }; const restrictedUrls = [ @@ -44,6 +45,7 @@ export const CreateWorkspaceForm: React.FC = ({ onSubmit, defaultValues, setDefaultValues, + user, }) => { const [slugError, setSlugError] = useState(false); const [invalidSlug, setInvalidSlug] = useState(false); @@ -66,7 +68,7 @@ export const CreateWorkspaceForm: React.FC = ({ if (res.status === true && !restrictedUrls.includes(formData.slug)) { setSlugError(false); await workspaceService - .createWorkspace(formData) + .createWorkspace(formData, user) .then((res) => { setToastAlert({ type: "success", diff --git a/apps/app/components/workspace/delete-workspace-modal.tsx b/apps/app/components/workspace/delete-workspace-modal.tsx index ceacd11e7..344d700b0 100644 --- a/apps/app/components/workspace/delete-workspace-modal.tsx +++ b/apps/app/components/workspace/delete-workspace-modal.tsx @@ -15,7 +15,7 @@ import { ExclamationTriangleIcon } from "@heroicons/react/24/outline"; // ui import { DangerButton, Input, SecondaryButton } from "components/ui"; // types -import type { IWorkspace } from "types"; +import type { ICurrentUserResponse, IWorkspace } from "types"; // fetch-keys import { USER_WORKSPACES } from "constants/fetch-keys"; @@ -23,9 +23,10 @@ type Props = { isOpen: boolean; data: IWorkspace | null; onClose: () => void; + user: ICurrentUserResponse | undefined; }; -export const DeleteWorkspaceModal: React.FC = ({ isOpen, data, onClose }) => { +export const DeleteWorkspaceModal: React.FC = ({ isOpen, data, onClose, user }) => { const [isDeleteLoading, setIsDeleteLoading] = useState(false); const [confirmWorkspaceName, setConfirmWorkspaceName] = useState(""); @@ -57,7 +58,7 @@ export const DeleteWorkspaceModal: React.FC = ({ isOpen, data, onClose }) setIsDeleteLoading(true); if (!data || !canDelete) return; await workspaceService - .deleteWorkspace(data.slug) + .deleteWorkspace(data.slug, user) .then(() => { handleClose(); router.push("/"); diff --git a/apps/app/components/workspace/send-workspace-invitation-modal.tsx b/apps/app/components/workspace/send-workspace-invitation-modal.tsx index f58269b89..52dc74149 100644 --- a/apps/app/components/workspace/send-workspace-invitation-modal.tsx +++ b/apps/app/components/workspace/send-workspace-invitation-modal.tsx @@ -10,7 +10,7 @@ import { CustomSelect, Input, PrimaryButton, SecondaryButton } from "components/ // hooks import useToast from "hooks/use-toast"; // types -import { IWorkspaceMemberInvitation } from "types"; +import { ICurrentUserResponse, IWorkspaceMemberInvitation } from "types"; // fetch keys import { WORKSPACE_INVITATIONS } from "constants/fetch-keys"; // constants @@ -21,6 +21,7 @@ type Props = { setIsOpen: React.Dispatch>; workspace_slug: string; members: any[]; + user: ICurrentUserResponse | undefined; }; const defaultValues: Partial = { @@ -33,6 +34,7 @@ const SendWorkspaceInvitationModal: React.FC = ({ setIsOpen, workspace_slug, members, + user, }) => { const { setToastAlert } = useToast(); @@ -54,7 +56,7 @@ const SendWorkspaceInvitationModal: React.FC = ({ const onSubmit = async (formData: IWorkspaceMemberInvitation) => { await workspaceService - .inviteWorkspace(workspace_slug, { emails: [formData] }) + .inviteWorkspace(workspace_slug, { emails: [formData] }, user) .then((res) => { setIsOpen(false); handleClose(); @@ -101,7 +103,10 @@ const SendWorkspaceInvitationModal: React.FC = ({
- + Members

diff --git a/apps/app/components/workspace/single-invitation.tsx b/apps/app/components/workspace/single-invitation.tsx index 9dbdc62ce..6d89c7675 100644 --- a/apps/app/components/workspace/single-invitation.tsx +++ b/apps/app/components/workspace/single-invitation.tsx @@ -46,7 +46,10 @@ const SingleInvitation: React.FC = ({

{truncateText(invitation.workspace.name, 30)}

- Invited by {invitation.workspace.owner.first_name} + Invited by{" "} + {invitation.created_by_detail + ? invitation.created_by_detail.first_name + : invitation.workspace.owner.first_name}

diff --git a/apps/app/contexts/issue-view.context.tsx b/apps/app/contexts/issue-view.context.tsx index aa3ec586c..619027866 100644 --- a/apps/app/contexts/issue-view.context.tsx +++ b/apps/app/contexts/issue-view.context.tsx @@ -18,6 +18,7 @@ import { IProjectMember, TIssueGroupByOptions, TIssueOrderByOptions, + ICurrentUserResponse, } from "types"; // fetch-keys import { @@ -26,6 +27,7 @@ import { USER_PROJECT_VIEW, VIEW_DETAILS, } from "constants/fetch-keys"; +import useUserAuth from "hooks/use-user-auth"; export const issueViewContext = createContext({} as ContextType); @@ -212,33 +214,54 @@ const saveCycleFilters = async ( workspaceSlug: string, projectId: string, cycleId: string, - state: any + state: any, + user: ICurrentUserResponse | undefined ) => { - await cyclesService.patchCycle(workspaceSlug, projectId, cycleId, { - ...state, - }); + await cyclesService.patchCycle( + workspaceSlug, + projectId, + cycleId, + { + ...state, + }, + user + ); }; const saveModuleFilters = async ( workspaceSlug: string, projectId: string, moduleId: string, - state: any + state: any, + user: ICurrentUserResponse | undefined ) => { - await modulesService.patchModule(workspaceSlug, projectId, moduleId, { - ...state, - }); + await modulesService.patchModule( + workspaceSlug, + projectId, + moduleId, + { + ...state, + }, + user + ); }; const saveViewFilters = async ( workspaceSlug: string, projectId: string, viewId: string, - state: any + state: any, + user: ICurrentUserResponse | undefined ) => { - await viewsService.patchView(workspaceSlug, projectId, viewId, { - ...state, - }); + await viewsService.patchView( + workspaceSlug, + projectId, + viewId, + { + ...state, + }, + user + ); }; const setNewDefault = async (workspaceSlug: string, projectId: string, state: any) => { @@ -267,6 +290,8 @@ export const IssueViewContextProvider: React.FC<{ children: React.ReactNode }> = const router = useRouter(); const { workspaceSlug, projectId, cycleId, moduleId, viewId } = router.query; + const { user } = useUserAuth(); + const { data: myViewProps, mutate: mutateMyViewProps } = useSWR( workspaceSlug && projectId ? USER_PROJECT_VIEW(projectId as string) : null, workspaceSlug && projectId @@ -505,14 +530,20 @@ export const IssueViewContextProvider: React.FC<{ children: React.ReactNode }> = }; }, false); - saveCycleFilters(workspaceSlug.toString(), projectId.toString(), cycleId.toString(), { - view_props: { - filters: { - ...state.filters, - ...property, + saveCycleFilters( + workspaceSlug.toString(), + projectId.toString(), + cycleId.toString(), + { + view_props: { + filters: { + ...state.filters, + ...property, + }, }, }, - }); + user + ); } else if (moduleId) { mutateModuleDetails((prevData: any) => { if (!prevData) return prevData; @@ -528,14 +559,20 @@ export const IssueViewContextProvider: React.FC<{ children: React.ReactNode }> = }; }, false); - saveModuleFilters(workspaceSlug.toString(), projectId.toString(), moduleId.toString(), { - view_props: { - filters: { - ...state.filters, - ...property, + saveModuleFilters( + workspaceSlug.toString(), + projectId.toString(), + moduleId.toString(), + { + view_props: { + filters: { + ...state.filters, + ...property, + }, }, }, - }); + user + ); } else if (viewId) { mutateViewDetails((prevData: any) => { if (!prevData) return prevData; @@ -548,12 +585,18 @@ export const IssueViewContextProvider: React.FC<{ children: React.ReactNode }> = }; }, false); if (saveToServer) - saveViewFilters(workspaceSlug as string, projectId as string, viewId as string, { - query_data: { - ...state.filters, - ...property, + saveViewFilters( + workspaceSlug as string, + projectId as string, + viewId as string, + { + query_data: { + ...state.filters, + ...property, + }, }, - }); + user + ); } else { mutateMyViewProps((prevData) => { if (!prevData) return prevData; diff --git a/apps/app/pages/[workspaceSlug]/analytics.tsx b/apps/app/pages/[workspaceSlug]/analytics.tsx index ce161fbc4..eb2816b56 100644 --- a/apps/app/pages/[workspaceSlug]/analytics.tsx +++ b/apps/app/pages/[workspaceSlug]/analytics.tsx @@ -6,6 +6,8 @@ import useSWR from "swr"; // react-hook-form import { useForm } from "react-hook-form"; +// hooks +import useUserAuth from "hooks/use-user-auth"; // headless ui import { Tab } from "@headlessui/react"; // services @@ -35,6 +37,8 @@ const Analytics = () => { const router = useRouter(); const { workspaceSlug } = router.query; + const { user } = useUserAuth(); + const { control, watch, setValue } = useForm({ defaultValues }); const params: IAnalyticsParams = { @@ -59,7 +63,7 @@ const Analytics = () => { ? "WORKSPACE_SCOPE_AND_DEMAND_ANALYTICS" : "WORKSPACE_CUSTOM_ANALYTICS"; - trackEventServices.trackAnalyticsEvent(eventPayload, eventType); + trackEventServices.trackAnalyticsEvent(eventPayload, eventType, user); }; useEffect(() => { @@ -67,7 +71,8 @@ const Analytics = () => { trackEventServices.trackAnalyticsEvent( { workspaceSlug: workspaceSlug?.toString() }, - "WORKSPACE_SCOPE_AND_DEMAND_ANALYTICS" + "WORKSPACE_SCOPE_AND_DEMAND_ANALYTICS", + user ); }, [workspaceSlug]); @@ -119,6 +124,7 @@ const Analytics = () => { params={params} control={control} setValue={setValue} + user={user} fullScreen /> diff --git a/apps/app/pages/[workspaceSlug]/projects/[projectId]/cycles/[cycleId].tsx b/apps/app/pages/[workspaceSlug]/projects/[projectId]/cycles/[cycleId].tsx index 087747153..718a8bd3a 100644 --- a/apps/app/pages/[workspaceSlug]/projects/[projectId]/cycles/[cycleId].tsx +++ b/apps/app/pages/[workspaceSlug]/projects/[projectId]/cycles/[cycleId].tsx @@ -19,6 +19,7 @@ import cycleServices from "services/cycles.service"; import projectService from "services/project.service"; // hooks import useToast from "hooks/use-toast"; +import useUserAuth from "hooks/use-user-auth"; // components import { AnalyticsProjectModal } from "components/analytics"; // ui @@ -44,6 +45,8 @@ const SingleCycle: React.FC = () => { const router = useRouter(); const { workspaceSlug, projectId, cycleId } = router.query; + const { user } = useUserAuth(); + const { setToastAlert } = useToast(); const { data: activeProject } = useSWR( @@ -94,7 +97,7 @@ const SingleCycle: React.FC = () => { if (!workspaceSlug || !projectId) return; await issuesService - .addIssueToCycle(workspaceSlug as string, projectId as string, cycleId as string, data) + .addIssueToCycle(workspaceSlug as string, projectId as string, cycleId as string, data, user) .then(() => { mutate(CYCLE_ISSUES(cycleId as string)); }) @@ -185,6 +188,7 @@ const SingleCycle: React.FC = () => { cycle={cycleDetails} isOpen={cycleSidebar} isCompleted={cycleStatus === "completed" ?? false} + user={user} /> diff --git a/apps/app/pages/[workspaceSlug]/projects/[projectId]/cycles/index.tsx b/apps/app/pages/[workspaceSlug]/projects/[projectId]/cycles/index.tsx index bac59acc9..97519f41a 100644 --- a/apps/app/pages/[workspaceSlug]/projects/[projectId]/cycles/index.tsx +++ b/apps/app/pages/[workspaceSlug]/projects/[projectId]/cycles/index.tsx @@ -8,6 +8,7 @@ import useSWR from "swr"; import { Tab } from "@headlessui/react"; // hooks import useLocalStorage from "hooks/use-local-storage"; +import useUserAuth from "hooks/use-user-auth"; // services import cycleService from "services/cycles.service"; import projectService from "services/project.service"; @@ -62,6 +63,8 @@ const ProjectCycles: NextPage = () => { const router = useRouter(); const { workspaceSlug, projectId } = router.query; + const { user } = useUserAuth(); + const { data: activeProject } = useSWR( workspaceSlug && projectId ? PROJECT_DETAILS(projectId as string) : null, workspaceSlug && projectId @@ -110,6 +113,7 @@ const ProjectCycles: NextPage = () => { isOpen={createUpdateCycleModal} handleClose={() => setCreateUpdateCycleModal(false)} data={selectedCycle} + user={user} />
diff --git a/apps/app/pages/[workspaceSlug]/projects/[projectId]/issues/[issueId].tsx b/apps/app/pages/[workspaceSlug]/projects/[projectId]/issues/[issueId].tsx index 29eaee83c..5f6615f55 100644 --- a/apps/app/pages/[workspaceSlug]/projects/[projectId]/issues/[issueId].tsx +++ b/apps/app/pages/[workspaceSlug]/projects/[projectId]/issues/[issueId].tsx @@ -7,6 +7,8 @@ import useSWR, { mutate } from "swr"; // react-hook-form import { useForm } from "react-hook-form"; +// hooks +import useUserAuth from "hooks/use-user-auth"; // services import issuesService from "services/issues.service"; // layouts @@ -50,6 +52,8 @@ const IssueDetailsPage: NextPage = () => { const router = useRouter(); const { workspaceSlug, projectId, issueId } = router.query; + const { user } = useUserAuth(); + const { data: issueDetails, mutate: mutateIssueDetails } = useSWR( workspaceSlug && projectId && issueId ? ISSUE_DETAILS(issueId as string) : null, workspaceSlug && projectId && issueId @@ -92,7 +96,7 @@ const IssueDetailsPage: NextPage = () => { const payload = { ...formData }; await issuesService - .patchIssue(workspaceSlug as string, projectId as string, issueId as string, payload) + .patchIssue(workspaceSlug as string, projectId as string, issueId as string, payload, user) .then((res) => { mutateIssueDetails(); mutate(PROJECT_ISSUES_ACTIVITY(issueId as string)); @@ -192,7 +196,7 @@ const IssueDetailsPage: NextPage = () => { ) : null}
- +
@@ -204,8 +208,8 @@ const IssueDetailsPage: NextPage = () => {

Comments/Activity

- - + +
diff --git a/apps/app/pages/[workspaceSlug]/projects/[projectId]/modules/[moduleId].tsx b/apps/app/pages/[workspaceSlug]/projects/[projectId]/modules/[moduleId].tsx index f9df68e7e..657f48fe2 100644 --- a/apps/app/pages/[workspaceSlug]/projects/[projectId]/modules/[moduleId].tsx +++ b/apps/app/pages/[workspaceSlug]/projects/[projectId]/modules/[moduleId].tsx @@ -17,6 +17,7 @@ import modulesService from "services/modules.service"; import issuesService from "services/issues.service"; // hooks import useToast from "hooks/use-toast"; +import useUserAuth from "hooks/use-user-auth"; // layouts import { ProjectAuthorizationWrapper } from "layouts/auth-layout"; // contexts @@ -49,6 +50,8 @@ const SingleModule: React.FC = () => { const router = useRouter(); const { workspaceSlug, projectId, moduleId } = router.query; + const { user } = useUserAuth(); + const { setToastAlert } = useToast(); const { data: issues } = useSWR( @@ -95,7 +98,13 @@ const SingleModule: React.FC = () => { if (!workspaceSlug || !projectId) return; await modulesService - .addIssuesToModule(workspaceSlug as string, projectId as string, moduleId as string, data) + .addIssuesToModule( + workspaceSlug as string, + projectId as string, + moduleId as string, + data, + user + ) .then(() => mutate(MODULE_ISSUES(moduleId as string))) .catch(() => setToastAlert({ @@ -186,6 +195,7 @@ const SingleModule: React.FC = () => { module={moduleDetails} isOpen={moduleSidebar} moduleIssues={moduleIssues} + user={user} /> diff --git a/apps/app/pages/[workspaceSlug]/projects/[projectId]/modules/index.tsx b/apps/app/pages/[workspaceSlug]/projects/[projectId]/modules/index.tsx index 7e2cd1565..be92a9f86 100644 --- a/apps/app/pages/[workspaceSlug]/projects/[projectId]/modules/index.tsx +++ b/apps/app/pages/[workspaceSlug]/projects/[projectId]/modules/index.tsx @@ -6,6 +6,8 @@ import useSWR from "swr"; // layouts import { ProjectAuthorizationWrapper } from "layouts/auth-layout"; +// hooks +import useUserAuth from "hooks/use-user-auth"; // services import projectService from "services/project.service"; import modulesService from "services/modules.service"; @@ -37,6 +39,8 @@ const ProjectModules: NextPage = () => { const router = useRouter(); const { workspaceSlug, projectId } = router.query; + const { user } = useUserAuth(); + const { data: activeProject } = useSWR( workspaceSlug && projectId ? PROJECT_DETAILS(projectId as string) : null, workspaceSlug && projectId @@ -89,6 +93,7 @@ const ProjectModules: NextPage = () => { isOpen={createUpdateModule} setIsOpen={setCreateUpdateModule} data={selectedModule} + user={user} /> {modules ? ( modules.length > 0 ? ( @@ -126,6 +131,7 @@ const ProjectModules: NextPage = () => { key={module.id} module={module} handleEditModule={() => handleEditModule(module)} + user={user} /> ))}
diff --git a/apps/app/pages/[workspaceSlug]/projects/[projectId]/pages/[pageId].tsx b/apps/app/pages/[workspaceSlug]/projects/[projectId]/pages/[pageId].tsx index 61b49a049..c157d7b96 100644 --- a/apps/app/pages/[workspaceSlug]/projects/[projectId]/pages/[pageId].tsx +++ b/apps/app/pages/[workspaceSlug]/projects/[projectId]/pages/[pageId].tsx @@ -116,7 +116,7 @@ const SinglePage: NextPage = () => { if (!formData.name || formData.name.length === 0 || formData.name === "") return; await pagesService - .patchPage(workspaceSlug as string, projectId as string, pageId as string, formData) + .patchPage(workspaceSlug as string, projectId as string, pageId as string, formData, user) .then(() => { mutate( PAGE_DETAILS(pageId as string), @@ -143,7 +143,7 @@ const SinglePage: NextPage = () => { ); await pagesService - .patchPage(workspaceSlug as string, projectId as string, pageId as string, formData) + .patchPage(workspaceSlug as string, projectId as string, pageId as string, formData, user) .then(() => { mutate(PAGE_DETAILS(pageId as string)); }); @@ -237,7 +237,8 @@ const SinglePage: NextPage = () => { result.draggableId, { sort_order: newSortOrder, - } + }, + user ); }; @@ -529,6 +530,7 @@ const SinglePage: NextPage = () => { block={block} projectDetails={projectDetails} index={index} + user={user} /> ))} {provided.placeholder} @@ -542,6 +544,7 @@ const SinglePage: NextPage = () => { setCreateBlockForm(false)} focus="name" + user={user} />
)} @@ -550,6 +553,7 @@ const SinglePage: NextPage = () => { isOpen={labelModal} handleClose={() => setLabelModal(false)} projectId={projectId} + user={user} /> )} @@ -562,7 +566,7 @@ const SinglePage: NextPage = () => {
- +
) : ( diff --git a/apps/app/pages/[workspaceSlug]/projects/[projectId]/pages/index.tsx b/apps/app/pages/[workspaceSlug]/projects/[projectId]/pages/index.tsx index dba6cce54..a51c8b44f 100644 --- a/apps/app/pages/[workspaceSlug]/projects/[projectId]/pages/index.tsx +++ b/apps/app/pages/[workspaceSlug]/projects/[projectId]/pages/index.tsx @@ -27,6 +27,7 @@ import { TPageViewProps } from "types"; import type { NextPage } from "next"; // fetch-keys import { PROJECT_DETAILS } from "constants/fetch-keys"; +import useUserAuth from "hooks/use-user-auth"; const AllPagesList = dynamic( () => import("components/pages").then((a) => a.AllPagesList), @@ -66,6 +67,8 @@ const ProjectPages: NextPage = () => { const router = useRouter(); const { workspaceSlug, projectId } = router.query; + const { user } = useUserAuth(); + const { storedValue: pageTab, setValue: setPageTab } = useLocalStorage("pageTab", "Recent"); const { data: projectDetails } = useSWR( @@ -98,6 +101,7 @@ const ProjectPages: NextPage = () => { setCreateUpdatePageModal(false)} + user={user} /> { const router = useRouter(); const { workspaceSlug, projectId } = router.query; + const { user } = useUserAuth(); + const { data: projectDetails } = useSWR( workspaceSlug && projectId ? PROJECT_DETAILS(projectId as string) : null, workspaceSlug && projectId @@ -65,7 +68,7 @@ const ControlSettings: NextPage = () => { }; await projectService - .updateProject(workspaceSlug as string, projectId as string, payload) + .updateProject(workspaceSlug as string, projectId as string, payload, user) .then((res) => { mutate(PROJECT_DETAILS(projectId as string)); mutate(PROJECTS_LIST(workspaceSlug as string)); diff --git a/apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/estimates.tsx b/apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/estimates.tsx index 3f3c0331f..76e353319 100644 --- a/apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/estimates.tsx +++ b/apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/estimates.tsx @@ -16,6 +16,7 @@ import { CreateUpdateEstimateModal, SingleEstimate } from "components/estimates" import { SettingsHeader } from "components/project"; //hooks import useToast from "hooks/use-toast"; +import useUserAuth from "hooks/use-user-auth"; // ui import { EmptyState, Loader, SecondaryButton } from "components/ui"; import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs"; @@ -37,6 +38,8 @@ const EstimatesSettings: NextPage = () => { const router = useRouter(); const { workspaceSlug, projectId } = router.query; + const { user } = useUserAuth(); + const { setToastAlert } = useToast(); const { projectDetails } = useProjectDetails(); @@ -63,7 +66,7 @@ const EstimatesSettings: NextPage = () => { ); estimatesService - .deleteEstimate(workspaceSlug as string, projectId as string, estimateId) + .deleteEstimate(workspaceSlug as string, projectId as string, estimateId, user) .catch(() => { setToastAlert({ type: "error", @@ -87,7 +90,7 @@ const EstimatesSettings: NextPage = () => { ); projectService - .updateProject(workspaceSlug as string, projectId as string, { estimate: null }) + .updateProject(workspaceSlug as string, projectId as string, { estimate: null }, user) .catch(() => setToastAlert({ type: "error", @@ -106,6 +109,7 @@ const EstimatesSettings: NextPage = () => { setEstimateFormOpen(false); setEstimateToUpdate(undefined); }} + user={user} /> { estimate={estimate} editEstimate={(estimate) => editEstimate(estimate)} handleEstimateDelete={(estimateId) => removeEstimate(estimateId)} + user={user} /> ))} diff --git a/apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/features.tsx b/apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/features.tsx index 9f8d06b3a..6932ffbd7 100644 --- a/apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/features.tsx +++ b/apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/features.tsx @@ -11,6 +11,7 @@ import trackEventServices, { MiscellaneousEventType } from "services/track-event import { ProjectAuthorizationWrapper } from "layouts/auth-layout"; // hooks import useToast from "hooks/use-toast"; +import useUserAuth from "hooks/use-user-auth"; // components import { SettingsHeader } from "components/project"; // ui @@ -75,6 +76,8 @@ const FeaturesSettings: NextPage = () => { const router = useRouter(); const { workspaceSlug, projectId } = router.query; + const { user } = useUserAuth(); + const { setToastAlert } = useToast(); const { data: projectDetails } = useSWR( @@ -134,7 +137,7 @@ const FeaturesSettings: NextPage = () => { }); await projectService - .updateProject(workspaceSlug as string, projectId as string, formData) + .updateProject(workspaceSlug as string, projectId as string, formData, user) .then(() => { mutate( projectDetails.is_favorite @@ -194,7 +197,8 @@ const FeaturesSettings: NextPage = () => { }, !projectDetails?.[feature.property as keyof IProject] ? getEventType(feature.title, true) - : getEventType(feature.title, false) + : getEventType(feature.title, false), + user ); handleSubmit({ [feature.property]: !projectDetails?.[feature.property as keyof IProject], diff --git a/apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/index.tsx b/apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/index.tsx index 5210c9ebe..14e20811a 100644 --- a/apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/index.tsx +++ b/apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/index.tsx @@ -17,6 +17,7 @@ import { ImagePickerPopover } from "components/core"; import EmojiIconPicker from "components/emoji-icon-picker"; // hooks import useToast from "hooks/use-toast"; +import useUserAuth from "hooks/use-user-auth"; // ui import { Input, @@ -45,6 +46,8 @@ const defaultValues: Partial = { const GeneralSettings: NextPage = () => { const [selectProject, setSelectedProject] = useState(null); + const { user } = useUserAuth(); + const { setToastAlert } = useToast(); const router = useRouter(); @@ -83,7 +86,7 @@ const GeneralSettings: NextPage = () => { if (!workspaceSlug || !projectDetails) return; await projectService - .updateProject(workspaceSlug as string, projectDetails.id, payload) + .updateProject(workspaceSlug as string, projectDetails.id, payload, user) .then((res) => { mutate( PROJECT_DETAILS(projectDetails.id), @@ -154,6 +157,7 @@ const GeneralSettings: NextPage = () => { onSuccess={() => { router.push(`/${workspaceSlug}/projects`); }} + user={user} /> diff --git a/apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/labels.tsx b/apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/labels.tsx index eea76527a..6d48c5ee0 100644 --- a/apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/labels.tsx +++ b/apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/labels.tsx @@ -4,6 +4,8 @@ import { useRouter } from "next/router"; import useSWR from "swr"; +// hooks +import useUserAuth from "hooks/use-user-auth"; // services import projectService from "services/project.service"; import issuesService from "services/issues.service"; @@ -47,6 +49,8 @@ const LabelsSettings: NextPage = () => { const router = useRouter(); const { workspaceSlug, projectId } = router.query; + const { user } = useUserAuth(); + const scrollToRef = useRef(null); const { data: projectDetails } = useSWR( @@ -85,11 +89,13 @@ const LabelsSettings: NextPage = () => { isOpen={labelsListModal} handleClose={() => setLabelsListModal(false)} parent={parentLabel} + user={user} /> setSelectDeleteLabel(null)} + user={user} /> { }); }} handleLabelDelete={() => setSelectDeleteLabel(label)} + user={user} /> ); }) diff --git a/apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/members.tsx b/apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/members.tsx index ce9110aad..942ed7037 100644 --- a/apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/members.tsx +++ b/apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/members.tsx @@ -135,6 +135,7 @@ const MembersSettings: NextPage = () => { isOpen={inviteModal} setIsOpen={setInviteModal} members={members} + user={user} /> { const router = useRouter(); const { workspaceSlug, projectId } = router.query; + const { user } = useUserAuth(); + const { projectDetails } = useProjectDetails(); const { data: states } = useSWR( @@ -55,6 +58,7 @@ const StatesSettings: NextPage = () => { isOpen={!!selectDeleteState} data={statesList?.find((s) => s.id === selectDeleteState) ?? null} onClose={() => setSelectDeleteState(null)} + user={user} /> { }} data={null} selectedGroup={key as keyof StateGroup} + user={user} /> )} {orderedStateGroups[key].map((state, index) => @@ -111,6 +116,7 @@ const StatesSettings: NextPage = () => { statesList={statesList} handleEditState={() => setSelectedState(state.id)} handleDeleteState={() => setSelectDeleteState(state.id)} + user={user} /> ) : (
{ statesList?.find((state) => state.id === selectedState) ?? null } selectedGroup={key as keyof StateGroup} + user={user} />
) diff --git a/apps/app/pages/[workspaceSlug]/projects/[projectId]/views/index.tsx b/apps/app/pages/[workspaceSlug]/projects/[projectId]/views/index.tsx index 6d2798d87..44c25cdf0 100644 --- a/apps/app/pages/[workspaceSlug]/projects/[projectId]/views/index.tsx +++ b/apps/app/pages/[workspaceSlug]/projects/[projectId]/views/index.tsx @@ -4,6 +4,8 @@ import { useRouter } from "next/router"; import useSWR from "swr"; +// hooks +import useUserAuth from "hooks/use-user-auth"; // services import viewsService from "services/views.service"; import projectService from "services/project.service"; @@ -34,6 +36,8 @@ const ProjectViews: NextPage = () => { const router = useRouter(); const { workspaceSlug, projectId } = router.query; + const { user } = useUserAuth(); + const { data: activeProject } = useSWR( workspaceSlug && projectId ? PROJECT_DETAILS(projectId as string) : null, workspaceSlug && projectId @@ -86,11 +90,13 @@ const ProjectViews: NextPage = () => { isOpen={createUpdateViewModal} handleClose={() => setCreateUpdateViewModal(false)} data={selectedViewToUpdate} + user={user} /> {views ? ( views.length > 0 ? ( diff --git a/apps/app/pages/[workspaceSlug]/projects/index.tsx b/apps/app/pages/[workspaceSlug]/projects/index.tsx index 6b29d41c5..fa34f02c0 100644 --- a/apps/app/pages/[workspaceSlug]/projects/index.tsx +++ b/apps/app/pages/[workspaceSlug]/projects/index.tsx @@ -9,6 +9,7 @@ import projectService from "services/project.service"; // hooks import useProjects from "hooks/use-projects"; import useWorkspaces from "hooks/use-workspaces"; +import useUserAuth from "hooks/use-user-auth"; // layouts import { WorkspaceAuthorizationLayout } from "layouts/auth-layout"; // components @@ -30,6 +31,8 @@ const ProjectsPage: NextPage = () => { // router const router = useRouter(); const { workspaceSlug } = router.query; + + const { user } = useUserAuth(); // context data const { activeWorkspace } = useWorkspaces(); const { projects } = useProjects(); @@ -81,6 +84,7 @@ const ProjectsPage: NextPage = () => { isOpen={!!deleteProject} onClose={() => setDeleteProject(null)} data={projects?.find((item) => item.id === deleteProject) ?? null} + user={user} /> {projects ? (
diff --git a/apps/app/pages/[workspaceSlug]/settings/index.tsx b/apps/app/pages/[workspaceSlug]/settings/index.tsx index 0913b28ab..0400ecaee 100644 --- a/apps/app/pages/[workspaceSlug]/settings/index.tsx +++ b/apps/app/pages/[workspaceSlug]/settings/index.tsx @@ -12,6 +12,7 @@ import workspaceService from "services/workspace.service"; import fileService from "services/file.service"; // hooks import useToast from "hooks/use-toast"; +import useUserAuth from "hooks/use-user-auth"; // layouts import { WorkspaceAuthorizationLayout } from "layouts/auth-layout"; import SettingsNavbar from "layouts/settings-navbar"; @@ -49,6 +50,8 @@ const WorkspaceSettings: NextPage = () => { const router = useRouter(); const { workspaceSlug } = router.query; + const { user } = useUserAuth(); + const { setToastAlert } = useToast(); const { data: activeWorkspace } = useSWR( @@ -82,7 +85,7 @@ const WorkspaceSettings: NextPage = () => { }; await workspaceService - .updateWorkspace(activeWorkspace.slug, payload) + .updateWorkspace(activeWorkspace.slug, payload, user) .then((res) => { mutate(USER_WORKSPACES, (prevData) => prevData?.map((workspace) => (workspace.id === res.id ? res : workspace)) @@ -114,7 +117,7 @@ const WorkspaceSettings: NextPage = () => { fileService.deleteFile(asset).then(() => { workspaceService - .updateWorkspace(activeWorkspace.slug, { logo: "" }) + .updateWorkspace(activeWorkspace.slug, { logo: "" }, user) .then((res) => { setToastAlert({ type: "success", @@ -169,6 +172,7 @@ const WorkspaceSettings: NextPage = () => { setIsOpen(false); }} data={activeWorkspace ?? null} + user={user} />
diff --git a/apps/app/pages/[workspaceSlug]/settings/members.tsx b/apps/app/pages/[workspaceSlug]/settings/members.tsx index fd80de11b..10969dde5 100644 --- a/apps/app/pages/[workspaceSlug]/settings/members.tsx +++ b/apps/app/pages/[workspaceSlug]/settings/members.tsx @@ -135,6 +135,7 @@ const MembersSettings: NextPage = () => { setIsOpen={setInviteModal} workspace_slug={workspaceSlug as string} members={members} + user={user} /> res.json()) - .then((data) => data.user) - .catch(() => res.status(401).json({ message: "Unauthorized" })); - if (!user) return res.status(401).json({ message: "Unauthorized" }); // TODO: cache user info diff --git a/apps/app/pages/create-workspace.tsx b/apps/app/pages/create-workspace.tsx index 389cdd7ec..82f0d2001 100644 --- a/apps/app/pages/create-workspace.tsx +++ b/apps/app/pages/create-workspace.tsx @@ -47,6 +47,7 @@ const CreateWorkspace: NextPage = () => { defaultValues={defaultValues} setDefaultValues={() => {}} onSubmit={(res) => router.push(`/${res.slug}`)} + user={user} />
diff --git a/apps/app/pages/index.tsx b/apps/app/pages/index.tsx index 9f3ef51ba..d135cc704 100644 --- a/apps/app/pages/index.tsx +++ b/apps/app/pages/index.tsx @@ -95,21 +95,21 @@ const HomePage: NextPage = () => {
) : ( -
+
Plane Web Logo -
+
Sign In to your Plane Account
-
+
{parseInt(process.env.NEXT_PUBLIC_ENABLE_OAUTH || "0") ? ( <> -
+
diff --git a/apps/app/pages/invitations.tsx b/apps/app/pages/invitations.tsx index 107af4051..ed5545557 100644 --- a/apps/app/pages/invitations.tsx +++ b/apps/app/pages/invitations.tsx @@ -124,7 +124,7 @@ const OnBoard: NextPage = () => {
) : workspaces && workspaces.length > 0 ? ( -
+

Your workspaces

{workspaces.map((workspace) => ( diff --git a/apps/app/pages/magic-sign-in.tsx b/apps/app/pages/magic-sign-in.tsx index f7308d1d2..0a2c2493f 100644 --- a/apps/app/pages/magic-sign-in.tsx +++ b/apps/app/pages/magic-sign-in.tsx @@ -49,18 +49,18 @@ const MagicSignIn: NextPage = () => { return ( -
+
{isSigningIn ? (

Signing you in...

-

+

Please wait while we are preparing your take off.

) : errorSigningIn ? (

Error

-

+

{errorSigningIn}. { ) : (

Success

-

Redirecting you to the app...

+

Redirecting you to the app...

)}
diff --git a/apps/app/pages/onboarding.tsx b/apps/app/pages/onboarding.tsx index 64b08e2f8..db056cf5c 100644 --- a/apps/app/pages/onboarding.tsx +++ b/apps/app/pages/onboarding.tsx @@ -53,9 +53,9 @@ const Onboarding: NextPage = () => { {step === 1 ? ( ) : step === 2 ? ( - + ) : ( - + )}
) : ( @@ -80,7 +80,7 @@ const Onboarding: NextPage = () => { onClick={() => { if (step === 8) { userService - .updateUserOnBoard({ userRole }) + .updateUserOnBoard({ userRole }, user) .then(async () => { mutate( CURRENT_USER, diff --git a/apps/app/pages/workspace-member-invitation/[invitationId].tsx b/apps/app/pages/workspace-member-invitation/[invitationId].tsx index cc4c5ec6d..8fae9547b 100644 --- a/apps/app/pages/workspace-member-invitation/[invitationId].tsx +++ b/apps/app/pages/workspace-member-invitation/[invitationId].tsx @@ -41,10 +41,15 @@ const WorkspaceInvitation: NextPage = () => { const handleAccept = () => { if (!invitationDetail) return; workspaceService - .joinWorkspace(invitationDetail.workspace.slug, invitationDetail.id, { - accepted: true, - email: invitationDetail.email, - }) + .joinWorkspace( + invitationDetail.workspace.slug, + invitationDetail.id, + { + accepted: true, + email: invitationDetail.email, + }, + user + ) .then(() => { if (email === user?.email) { router.push("/invitations"); diff --git a/apps/app/services/ai.service.ts b/apps/app/services/ai.service.ts index 6d1e3b0f9..ecb1ada52 100644 --- a/apps/app/services/ai.service.ts +++ b/apps/app/services/ai.service.ts @@ -3,7 +3,7 @@ import APIService from "services/api.service"; import trackEventServices from "services/track-event.service"; // types -import { IGptResponse } from "types"; +import { ICurrentUserResponse, IGptResponse } from "types"; const { NEXT_PUBLIC_API_BASE_URL } = process.env; @@ -18,11 +18,12 @@ class AiServices extends APIService { async createGptTask( workspaceSlug: string, projectId: string, - data: { prompt: string; task: string } + data: { prompt: string; task: string }, + user: ICurrentUserResponse | undefined ): Promise { return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/ai-assistant/`, data) .then((response) => { - if (trackEvent) trackEventServices.trackAskGptEvent(response?.data, "ASK_GPT"); + if (trackEvent) trackEventServices.trackAskGptEvent(response?.data, "ASK_GPT", user); return response?.data; }) .catch((error) => { diff --git a/apps/app/services/cycles.service.ts b/apps/app/services/cycles.service.ts index d2cb4f5f3..d305ee63e 100644 --- a/apps/app/services/cycles.service.ts +++ b/apps/app/services/cycles.service.ts @@ -3,7 +3,7 @@ import APIService from "services/api.service"; import trackEventServices from "services/track-event.service"; // types -import type { ICycle, IIssue, IIssueViewOptions } from "types"; +import type { ICurrentUserResponse, ICycle, IIssue, IIssueViewOptions } from "types"; const { NEXT_PUBLIC_API_BASE_URL } = process.env; @@ -15,10 +15,15 @@ class ProjectCycleServices extends APIService { super(NEXT_PUBLIC_API_BASE_URL || "http://localhost:8000"); } - async createCycle(workspaceSlug: string, projectId: string, data: any): Promise { + async createCycle( + workspaceSlug: string, + projectId: string, + data: any, + user: ICurrentUserResponse | undefined + ): Promise { return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/cycles/`, data) .then((response) => { - if (trackEvent) trackEventServices.trackCycleEvent(response?.data, "CYCLE_CREATE"); + if (trackEvent) trackEventServices.trackCycleEvent(response?.data, "CYCLE_CREATE", user); return response?.data; }) .catch((error) => { @@ -88,14 +93,15 @@ class ProjectCycleServices extends APIService { workspaceSlug: string, projectId: string, cycleId: string, - data: any + data: any, + user: ICurrentUserResponse | undefined ): Promise { return this.put( `/api/workspaces/${workspaceSlug}/projects/${projectId}/cycles/${cycleId}/`, data ) .then((response) => { - if (trackEvent) trackEventServices.trackCycleEvent(response?.data, "CYCLE_UPDATE"); + if (trackEvent) trackEventServices.trackCycleEvent(response?.data, "CYCLE_UPDATE", user); return response?.data; }) .catch((error) => { @@ -107,14 +113,15 @@ class ProjectCycleServices extends APIService { workspaceSlug: string, projectId: string, cycleId: string, - data: Partial + data: Partial, + user: ICurrentUserResponse | undefined ): Promise { return this.patch( `/api/workspaces/${workspaceSlug}/projects/${projectId}/cycles/${cycleId}/`, data ) .then((response) => { - if (trackEvent) trackEventServices.trackCycleEvent(response?.data, "CYCLE_UPDATE"); + if (trackEvent) trackEventServices.trackCycleEvent(response?.data, "CYCLE_UPDATE", user); return response?.data; }) .catch((error) => { @@ -122,10 +129,15 @@ class ProjectCycleServices extends APIService { }); } - async deleteCycle(workspaceSlug: string, projectId: string, cycleId: string): Promise { + async deleteCycle( + workspaceSlug: string, + projectId: string, + cycleId: string, + user: ICurrentUserResponse | undefined + ): Promise { return this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/cycles/${cycleId}/`) .then((response) => { - if (trackEvent) trackEventServices.trackCycleEvent(response?.data, "CYCLE_DELETE"); + if (trackEvent) trackEventServices.trackCycleEvent(response?.data, "CYCLE_DELETE", user); return response?.data; }) .catch((error) => { diff --git a/apps/app/services/estimates.service.ts b/apps/app/services/estimates.service.ts index d64f37f28..8b0fe25f4 100644 --- a/apps/app/services/estimates.service.ts +++ b/apps/app/services/estimates.service.ts @@ -1,7 +1,7 @@ // services import APIService from "services/api.service"; // types -import type { IEstimate, IEstimateFormData } from "types"; +import type { ICurrentUserResponse, IEstimate, IEstimateFormData } from "types"; import trackEventServices from "services/track-event.service"; const { NEXT_PUBLIC_API_BASE_URL } = process.env; @@ -17,12 +17,13 @@ class ProjectEstimateServices extends APIService { async createEstimate( workspaceSlug: string, projectId: string, - data: IEstimateFormData + data: IEstimateFormData, + user: ICurrentUserResponse | undefined ): Promise { return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/estimates/`, data) .then((response) => { if (trackEvent) - trackEventServices.trackIssueEstimateEvent(response?.data, "ESTIMATE_CREATE"); + trackEventServices.trackIssueEstimateEvent(response?.data, "ESTIMATE_CREATE", user); return response?.data; }) .catch((error) => { @@ -34,7 +35,8 @@ class ProjectEstimateServices extends APIService { workspaceSlug: string, projectId: string, estimateId: string, - data: IEstimateFormData + data: IEstimateFormData, + user: ICurrentUserResponse | undefined ): Promise { return this.patch( `/api/workspaces/${workspaceSlug}/projects/${projectId}/estimates/${estimateId}/`, @@ -42,7 +44,7 @@ class ProjectEstimateServices extends APIService { ) .then((response) => { if (trackEvent) - trackEventServices.trackIssueEstimateEvent(response?.data, "ESTIMATE_UPDATE"); + trackEventServices.trackIssueEstimateEvent(response?.data, "ESTIMATE_UPDATE", user); return response?.data; }) .catch((error) => { @@ -72,13 +74,18 @@ class ProjectEstimateServices extends APIService { }); } - async deleteEstimate(workspaceSlug: string, projectId: string, estimateId: string): Promise { + async deleteEstimate( + workspaceSlug: string, + projectId: string, + estimateId: string, + user: ICurrentUserResponse | undefined + ): Promise { return this.delete( `/api/workspaces/${workspaceSlug}/projects/${projectId}/estimates/${estimateId}/` ) .then((response) => { if (trackEvent) - trackEventServices.trackIssueEstimateEvent(response?.data, "ESTIMATE_DELETE"); + trackEventServices.trackIssueEstimateEvent(response?.data, "ESTIMATE_DELETE", user); return response?.data; }) .catch((error) => { diff --git a/apps/app/services/integration/github.service.ts b/apps/app/services/integration/github.service.ts index 101e7ac67..494785f04 100644 --- a/apps/app/services/integration/github.service.ts +++ b/apps/app/services/integration/github.service.ts @@ -1,7 +1,7 @@ import APIService from "services/api.service"; import trackEventServices from "services/track-event.service"; -import { IGithubRepoInfo, IGithubServiceImportFormData } from "types"; +import { ICurrentUserResponse, IGithubRepoInfo, IGithubServiceImportFormData } from "types"; const { NEXT_PUBLIC_API_BASE_URL } = process.env; @@ -39,7 +39,8 @@ class GithubIntegrationService extends APIService { async createGithubServiceImport( workspaceSlug: string, - data: IGithubServiceImportFormData + data: IGithubServiceImportFormData, + user: ICurrentUserResponse | undefined ): Promise { return this.post( `/api/workspaces/${workspaceSlug}/projects/importers/${integrationServiceType}/`, @@ -47,7 +48,7 @@ class GithubIntegrationService extends APIService { ) .then((response) => { if (trackEvent) - trackEventServices.trackImporterEvent(response?.data, "GITHUB_IMPORTER_CREATE"); + trackEventServices.trackImporterEvent(response?.data, "GITHUB_IMPORTER_CREATE", user); return response?.data; }) .catch((error) => { diff --git a/apps/app/services/integration/index.ts b/apps/app/services/integration/index.ts index 51ecd33c1..9cc146866 100644 --- a/apps/app/services/integration/index.ts +++ b/apps/app/services/integration/index.ts @@ -2,7 +2,12 @@ import APIService from "services/api.service"; import trackEventServices from "services/track-event.service"; // types -import { IAppIntegration, IImporterService, IWorkspaceIntegration } from "types"; +import { + IAppIntegration, + ICurrentUserResponse, + IImporterService, + IWorkspaceIntegration, +} from "types"; const { NEXT_PUBLIC_API_BASE_URL } = process.env; @@ -51,13 +56,14 @@ class IntegrationService extends APIService { async deleteImporterService( workspaceSlug: string, service: string, - importerId: string + importerId: string, + user: ICurrentUserResponse | undefined ): Promise { return this.delete(`/api/workspaces/${workspaceSlug}/importers/${service}/${importerId}/`) .then((response) => { const eventName = service === "github" ? "GITHUB_IMPORTER_DELETE" : "JIRA_IMPORTER_DELETE"; - if (trackEvent) trackEventServices.trackImporterEvent(response?.data, eventName); + if (trackEvent) trackEventServices.trackImporterEvent(response?.data, eventName, user); return response?.data; }) .catch((error) => { diff --git a/apps/app/services/integration/jira.service.ts b/apps/app/services/integration/jira.service.ts index 456530308..8f6a9fec9 100644 --- a/apps/app/services/integration/jira.service.ts +++ b/apps/app/services/integration/jira.service.ts @@ -2,7 +2,7 @@ import APIService from "services/api.service"; import trackEventServices from "services/track-event.service"; // types -import { IJiraMetadata, IJiraResponse, IJiraImporterForm } from "types"; +import { IJiraMetadata, IJiraResponse, IJiraImporterForm, ICurrentUserResponse } from "types"; const { NEXT_PUBLIC_API_BASE_URL } = process.env; @@ -24,11 +24,15 @@ class JiraImportedService extends APIService { }); } - async createJiraImporter(workspaceSlug: string, data: IJiraImporterForm): Promise { + async createJiraImporter( + workspaceSlug: string, + data: IJiraImporterForm, + user: ICurrentUserResponse | undefined + ): Promise { return this.post(`/api/workspaces/${workspaceSlug}/projects/importers/jira/`, data) .then((response) => { if (trackEvent) - trackEventServices.trackImporterEvent(response?.data, "JIRA_IMPORTER_CREATE"); + trackEventServices.trackImporterEvent(response?.data, "JIRA_IMPORTER_CREATE", user); return response?.data; }) .catch((error) => { diff --git a/apps/app/services/issues.service.ts b/apps/app/services/issues.service.ts index c5a23b232..658272e7a 100644 --- a/apps/app/services/issues.service.ts +++ b/apps/app/services/issues.service.ts @@ -2,7 +2,14 @@ import APIService from "services/api.service"; import trackEventServices from "services/track-event.service"; // type -import type { IIssue, IIssueActivity, IIssueComment, IIssueLabels, IIssueViewOptions } from "types"; +import type { + ICurrentUserResponse, + IIssue, + IIssueActivity, + IIssueComment, + IIssueLabels, + IIssueViewOptions, +} from "types"; const { NEXT_PUBLIC_API_BASE_URL } = process.env; @@ -14,10 +21,15 @@ class ProjectIssuesServices extends APIService { super(NEXT_PUBLIC_API_BASE_URL || "http://localhost:8000"); } - async createIssues(workspaceSlug: string, projectId: string, data: any): Promise { + async createIssues( + workspaceSlug: string, + projectId: string, + data: any, + user: ICurrentUserResponse | undefined + ): Promise { return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/`, data) .then((response) => { - if (trackEvent) trackEventServices.trackIssueEvent(response.data, "ISSUE_CREATE"); + if (trackEvent) trackEventServices.trackIssueEvent(response.data, "ISSUE_CREATE", user); return response?.data; }) .catch((error) => { @@ -93,7 +105,8 @@ class ProjectIssuesServices extends APIService { cycleId: string, data: { issues: string[]; - } + }, + user: ICurrentUserResponse | undefined ) { return this.post( `/api/workspaces/${workspaceSlug}/projects/${projectId}/cycles/${cycleId}/cycle-issues/`, @@ -111,7 +124,8 @@ class ProjectIssuesServices extends APIService { issueId: response?.data?.[0]?.issue_detail?.id, cycleId, }, - response.data.length > 1 ? "ISSUE_MOVED_TO_CYCLE_IN_BULK" : "ISSUE_MOVED_TO_CYCLE" + response.data.length > 1 ? "ISSUE_MOVED_TO_CYCLE_IN_BULK" : "ISSUE_MOVED_TO_CYCLE", + user ); return response?.data; }) @@ -167,7 +181,8 @@ class ProjectIssuesServices extends APIService { workspaceSlug: string, projectId: string, issueId: string, - data: any + data: any, + user: ICurrentUserResponse | undefined ): Promise { return this.post( `/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/${issueId}/comments/`, @@ -175,7 +190,7 @@ class ProjectIssuesServices extends APIService { ) .then((response) => { if (trackEvent) - trackEventServices.trackIssueCommentEvent(response.data, "ISSUE_COMMENT_CREATE"); + trackEventServices.trackIssueCommentEvent(response.data, "ISSUE_COMMENT_CREATE", user); return response?.data; }) .catch((error) => { @@ -188,7 +203,8 @@ class ProjectIssuesServices extends APIService { projectId: string, issueId: string, commentId: string, - data: IIssueComment + data: IIssueComment, + user: ICurrentUserResponse | undefined ): Promise { return this.patch( `/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/${issueId}/comments/${commentId}/`, @@ -196,7 +212,7 @@ class ProjectIssuesServices extends APIService { ) .then((response) => { if (trackEvent) - trackEventServices.trackIssueCommentEvent(response.data, "ISSUE_COMMENT_UPDATE"); + trackEventServices.trackIssueCommentEvent(response.data, "ISSUE_COMMENT_UPDATE", user); return response?.data; }) .catch((error) => { @@ -208,7 +224,8 @@ class ProjectIssuesServices extends APIService { workspaceSlug: string, projectId: string, issueId: string, - commentId: string + commentId: string, + user: ICurrentUserResponse | undefined ): Promise { return this.delete( `/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/${issueId}/comments/${commentId}/` @@ -220,7 +237,8 @@ class ProjectIssuesServices extends APIService { issueId, commentId, }, - "ISSUE_COMMENT_DELETE" + "ISSUE_COMMENT_DELETE", + user ); return response?.data; }) @@ -240,7 +258,8 @@ class ProjectIssuesServices extends APIService { async createIssueLabel( workspaceSlug: string, projectId: string, - data: any + data: any, + user: ICurrentUserResponse | undefined ): Promise { return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/issue-labels/`, data) .then((response: { data: IIssueLabels; [key: string]: any }) => { @@ -256,7 +275,8 @@ class ProjectIssuesServices extends APIService { labelId: response?.data?.id, color: response?.data?.color, }, - "ISSUE_LABEL_CREATE" + "ISSUE_LABEL_CREATE", + user ); return response?.data; }) @@ -269,7 +289,8 @@ class ProjectIssuesServices extends APIService { workspaceSlug: string, projectId: string, labelId: string, - data: any + data: any, + user: ICurrentUserResponse | undefined ): Promise { return this.patch( `/api/workspaces/${workspaceSlug}/projects/${projectId}/issue-labels/${labelId}/`, @@ -288,7 +309,8 @@ class ProjectIssuesServices extends APIService { labelId: response?.data?.id, color: response?.data?.color, }, - "ISSUE_LABEL_UPDATE" + "ISSUE_LABEL_UPDATE", + user ); return response?.data; }) @@ -297,7 +319,12 @@ class ProjectIssuesServices extends APIService { }); } - async deleteIssueLabel(workspaceSlug: string, projectId: string, labelId: string): Promise { + async deleteIssueLabel( + workspaceSlug: string, + projectId: string, + labelId: string, + user: ICurrentUserResponse | undefined + ): Promise { return this.delete( `/api/workspaces/${workspaceSlug}/projects/${projectId}/issue-labels/${labelId}/` ) @@ -308,7 +335,8 @@ class ProjectIssuesServices extends APIService { workspaceSlug, projectId, }, - "ISSUE_LABEL_DELETE" + "ISSUE_LABEL_DELETE", + user ); return response?.data; }) @@ -321,14 +349,15 @@ class ProjectIssuesServices extends APIService { workspaceSlug: string, projectId: string, issueId: string, - data: any + data: any, + user: ICurrentUserResponse | undefined ): Promise { return this.put( `/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/${issueId}/`, data ) .then((response) => { - if (trackEvent) trackEventServices.trackIssueEvent(response.data, "ISSUE_UPDATE"); + if (trackEvent) trackEventServices.trackIssueEvent(response.data, "ISSUE_UPDATE", user); return response?.data; }) .catch((error) => { @@ -340,14 +369,15 @@ class ProjectIssuesServices extends APIService { workspaceSlug: string, projectId: string, issueId: string, - data: Partial + data: Partial, + user: ICurrentUserResponse | undefined ): Promise { return this.patch( `/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/${issueId}/`, data ) .then((response) => { - if (trackEvent) trackEventServices.trackIssueEvent(response.data, "ISSUE_UPDATE"); + if (trackEvent) trackEventServices.trackIssueEvent(response.data, "ISSUE_UPDATE", user); return response?.data; }) .catch((error) => { @@ -355,10 +385,15 @@ class ProjectIssuesServices extends APIService { }); } - async deleteIssue(workspaceSlug: string, projectId: string, issuesId: string): Promise { + async deleteIssue( + workspaceSlug: string, + projectId: string, + issuesId: string, + user: ICurrentUserResponse | undefined + ): Promise { return this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/${issuesId}/`) .then((response) => { - if (trackEvent) trackEventServices.trackIssueEvent({ issuesId }, "ISSUE_DELETE"); + if (trackEvent) trackEventServices.trackIssueEvent({ issuesId }, "ISSUE_DELETE", user); return response?.data; }) .catch((error) => { @@ -366,13 +401,18 @@ class ProjectIssuesServices extends APIService { }); } - async bulkDeleteIssues(workspaceSlug: string, projectId: string, data: any): Promise { + async bulkDeleteIssues( + workspaceSlug: string, + projectId: string, + data: any, + user: ICurrentUserResponse | undefined + ): Promise { return this.delete( `/api/workspaces/${workspaceSlug}/projects/${projectId}/bulk-delete-issues/`, data ) .then((response) => { - if (trackEvent) trackEventServices.trackIssueBulkDeleteEvent(data); + if (trackEvent) trackEventServices.trackIssueBulkDeleteEvent(data, user); return response?.data; }) .catch((error) => { diff --git a/apps/app/services/modules.service.ts b/apps/app/services/modules.service.ts index 89227982c..ec4165c9b 100644 --- a/apps/app/services/modules.service.ts +++ b/apps/app/services/modules.service.ts @@ -3,7 +3,7 @@ import APIService from "services/api.service"; import trackEventServices from "./track-event.service"; // types -import type { IIssueViewOptions, IModule, IIssue } from "types"; +import type { IIssueViewOptions, IModule, IIssue, ICurrentUserResponse } from "types"; const { NEXT_PUBLIC_API_BASE_URL } = process.env; @@ -23,10 +23,15 @@ class ProjectIssuesServices extends APIService { }); } - async createModule(workspaceSlug: string, projectId: string, data: any): Promise { + async createModule( + workspaceSlug: string, + projectId: string, + data: any, + user: ICurrentUserResponse | undefined + ): Promise { return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/modules/`, data) .then((response) => { - if (trackEvent) trackEventServices.trackModuleEvent(response?.data, "MODULE_CREATE"); + if (trackEvent) trackEventServices.trackModuleEvent(response?.data, "MODULE_CREATE", user); return response?.data; }) .catch((error) => { @@ -38,14 +43,15 @@ class ProjectIssuesServices extends APIService { workspaceSlug: string, projectId: string, moduleId: string, - data: any + data: any, + user: ICurrentUserResponse | undefined ): Promise { return this.put( `/api/workspaces/${workspaceSlug}/projects/${projectId}/modules/${moduleId}/`, data ) .then((response) => { - if (trackEvent) trackEventServices.trackModuleEvent(response?.data, "MODULE_UPDATE"); + if (trackEvent) trackEventServices.trackModuleEvent(response?.data, "MODULE_UPDATE", user); return response?.data; }) .catch((error) => { @@ -69,14 +75,15 @@ class ProjectIssuesServices extends APIService { workspaceSlug: string, projectId: string, moduleId: string, - data: any + data: any, + user: ICurrentUserResponse | undefined ): Promise { return this.patch( `/api/workspaces/${workspaceSlug}/projects/${projectId}/modules/${moduleId}/`, data ) .then((response) => { - if (trackEvent) trackEventServices.trackModuleEvent(response?.data, "MODULE_UPDATE"); + if (trackEvent) trackEventServices.trackModuleEvent(response?.data, "MODULE_UPDATE", user); return response?.data; }) .catch((error) => { @@ -84,12 +91,17 @@ class ProjectIssuesServices extends APIService { }); } - async deleteModule(workspaceSlug: string, projectId: string, moduleId: string): Promise { + async deleteModule( + workspaceSlug: string, + projectId: string, + moduleId: string, + user: ICurrentUserResponse | undefined + ): Promise { return this.delete( `/api/workspaces/${workspaceSlug}/projects/${projectId}/modules/${moduleId}/` ) .then((response) => { - if (trackEvent) trackEventServices.trackModuleEvent(response?.data, "MODULE_DELETE"); + if (trackEvent) trackEventServices.trackModuleEvent(response?.data, "MODULE_DELETE", user); return response?.data; }) .catch((error) => { @@ -136,7 +148,8 @@ class ProjectIssuesServices extends APIService { workspaceSlug: string, projectId: string, moduleId: string, - data: { issues: string[] } + data: { issues: string[] }, + user: ICurrentUserResponse | undefined ): Promise { return this.post( `/api/workspaces/${workspaceSlug}/projects/${projectId}/modules/${moduleId}/module-issues/`, @@ -154,7 +167,8 @@ class ProjectIssuesServices extends APIService { issueId: response?.data?.[0]?.issue_detail?.id, moduleId, }, - response?.data?.length > 1 ? "ISSUE_MOVED_TO_MODULE_IN_BULK" : "ISSUE_MOVED_TO_MODULE" + response?.data?.length > 1 ? "ISSUE_MOVED_TO_MODULE_IN_BULK" : "ISSUE_MOVED_TO_MODULE", + user ); return response?.data; }) diff --git a/apps/app/services/pages.service.ts b/apps/app/services/pages.service.ts index 5805ac538..72b12012e 100644 --- a/apps/app/services/pages.service.ts +++ b/apps/app/services/pages.service.ts @@ -3,7 +3,7 @@ import APIService from "services/api.service"; import trackEventServices from "services/track-event.service"; // types -import { IPage, IPageBlock, RecentPagesResponse, IIssue } from "types"; +import { IPage, IPageBlock, RecentPagesResponse, IIssue, ICurrentUserResponse } from "types"; const { NEXT_PUBLIC_API_BASE_URL } = process.env; @@ -15,10 +15,15 @@ class PageServices extends APIService { super(NEXT_PUBLIC_API_BASE_URL || "http://localhost:8000"); } - async createPage(workspaceSlug: string, projectId: string, data: Partial): Promise { + async createPage( + workspaceSlug: string, + projectId: string, + data: Partial, + user: ICurrentUserResponse | undefined + ): Promise { return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/pages/`, data) .then((response) => { - if (trackEvent) trackEventServices.trackPageEvent(response?.data, "PAGE_CREATE"); + if (trackEvent) trackEventServices.trackPageEvent(response?.data, "PAGE_CREATE", user); return response?.data; }) .catch((error) => { @@ -30,14 +35,15 @@ class PageServices extends APIService { workspaceSlug: string, projectId: string, pageId: string, - data: Partial + data: Partial, + user: ICurrentUserResponse | undefined ): Promise { return this.patch( `/api/workspaces/${workspaceSlug}/projects/${projectId}/pages/${pageId}/`, data ) .then((response) => { - if (trackEvent) trackEventServices.trackPageEvent(response?.data, "PAGE_UPDATE"); + if (trackEvent) trackEventServices.trackPageEvent(response?.data, "PAGE_UPDATE", user); return response?.data; }) .catch((error) => { @@ -45,10 +51,15 @@ class PageServices extends APIService { }); } - async deletePage(workspaceSlug: string, projectId: string, pageId: string): Promise { + async deletePage( + workspaceSlug: string, + projectId: string, + pageId: string, + user: ICurrentUserResponse | undefined + ): Promise { return this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/pages/${pageId}/`) .then((response) => { - if (trackEvent) trackEventServices.trackPageEvent(response?.data, "PAGE_DELETE"); + if (trackEvent) trackEventServices.trackPageEvent(response?.data, "PAGE_DELETE", user); return response?.data; }) .catch((error) => { @@ -123,14 +134,16 @@ class PageServices extends APIService { workspaceSlug: string, projectId: string, pageId: string, - data: Partial + data: Partial, + user: ICurrentUserResponse | undefined ): Promise { return this.post( `/api/workspaces/${workspaceSlug}/projects/${projectId}/pages/${pageId}/page-blocks/`, data ) .then((response) => { - if (trackEvent) trackEventServices.trackPageBlockEvent(response?.data, "PAGE_BLOCK_CREATE"); + if (trackEvent) + trackEventServices.trackPageBlockEvent(response?.data, "PAGE_BLOCK_CREATE", user); return response?.data; }) .catch((error) => { @@ -158,14 +171,16 @@ class PageServices extends APIService { projectId: string, pageId: string, pageBlockId: string, - data: Partial + data: Partial, + user: ICurrentUserResponse | undefined ): Promise { return this.patch( `/api/workspaces/${workspaceSlug}/projects/${projectId}/pages/${pageId}/page-blocks/${pageBlockId}/`, data ) .then((response) => { - if (trackEvent) trackEventServices.trackPageBlockEvent(response?.data, "PAGE_BLOCK_UPDATE"); + if (trackEvent) + trackEventServices.trackPageBlockEvent(response?.data, "PAGE_BLOCK_UPDATE", user); return response?.data; }) .catch((error) => { @@ -177,13 +192,15 @@ class PageServices extends APIService { workspaceSlug: string, projectId: string, pageId: string, - pageBlockId: string + pageBlockId: string, + user: ICurrentUserResponse | undefined ): Promise { return this.delete( `/api/workspaces/${workspaceSlug}/projects/${projectId}/pages/${pageId}/page-blocks/${pageBlockId}/` ) .then((response) => { - if (trackEvent) trackEventServices.trackPageBlockEvent(response?.data, "PAGE_BLOCK_DELETE"); + if (trackEvent) + trackEventServices.trackPageBlockEvent(response?.data, "PAGE_BLOCK_DELETE", user); return response?.data; }) .catch((error) => { @@ -209,14 +226,19 @@ class PageServices extends APIService { workspaceSlug: string, projectId: string, pageId: string, - blockId: string + blockId: string, + user: ICurrentUserResponse | undefined ): Promise { return this.post( `/api/workspaces/${workspaceSlug}/projects/${projectId}/pages/${pageId}/page-blocks/${blockId}/issues/` ) .then((response) => { if (trackEvent) - trackEventServices.trackPageBlockEvent(response?.data, "PAGE_BLOCK_CONVERTED_TO_ISSUE"); + trackEventServices.trackPageBlockEvent( + response?.data, + "PAGE_BLOCK_CONVERTED_TO_ISSUE", + user + ); return response?.data; }) .catch((error) => { diff --git a/apps/app/services/project.service.ts b/apps/app/services/project.service.ts index 1443fee69..2f04f622b 100644 --- a/apps/app/services/project.service.ts +++ b/apps/app/services/project.service.ts @@ -5,6 +5,7 @@ import trackEventServices from "services/track-event.service"; // types import type { GithubRepositoriesResponse, + ICurrentUserResponse, IFavoriteProject, IProject, IProjectMember, @@ -22,10 +23,14 @@ class ProjectServices extends APIService { super(NEXT_PUBLIC_API_BASE_URL || "http://localhost:8000"); } - async createProject(workspaceSlug: string, data: Partial): Promise { + async createProject( + workspaceSlug: string, + data: Partial, + user: ICurrentUserResponse | undefined + ): Promise { return this.post(`/api/workspaces/${workspaceSlug}/projects/`, data) .then((response) => { - if (trackEvent) trackEventServices.trackProjectEvent(response.data, "CREATE_PROJECT"); + if (trackEvent) trackEventServices.trackProjectEvent(response.data, "CREATE_PROJECT", user); return response?.data; }) .catch((error) => { @@ -64,11 +69,12 @@ class ProjectServices extends APIService { async updateProject( workspaceSlug: string, projectId: string, - data: Partial + data: Partial, + user: ICurrentUserResponse | undefined ): Promise { return this.patch(`/api/workspaces/${workspaceSlug}/projects/${projectId}/`, data) .then((response) => { - if (trackEvent) trackEventServices.trackProjectEvent(response.data, "UPDATE_PROJECT"); + if (trackEvent) trackEventServices.trackProjectEvent(response.data, "UPDATE_PROJECT", user); return response?.data; }) .catch((error) => { @@ -76,10 +82,14 @@ class ProjectServices extends APIService { }); } - async deleteProject(workspaceSlug: string, projectId: string): Promise { + async deleteProject( + workspaceSlug: string, + projectId: string, + user: ICurrentUserResponse | undefined + ): Promise { return this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/`) .then((response) => { - if (trackEvent) trackEventServices.trackProjectEvent({ projectId }, "DELETE_PROJECT"); + if (trackEvent) trackEventServices.trackProjectEvent({ projectId }, "DELETE_PROJECT", user); return response?.data; }) .catch((error) => { @@ -87,7 +97,12 @@ class ProjectServices extends APIService { }); } - async inviteProject(workspaceSlug: string, projectId: string, data: any): Promise { + async inviteProject( + workspaceSlug: string, + projectId: string, + data: any, + user: ICurrentUserResponse | undefined + ): Promise { return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/members/add/`, data) .then((response) => { if (trackEvent) @@ -99,7 +114,8 @@ class ProjectServices extends APIService { projectName: response?.data?.project?.name, memberEmail: response?.data?.member?.email, }, - "PROJECT_MEMBER_INVITE" + "PROJECT_MEMBER_INVITE", + user ); return response?.data; }) diff --git a/apps/app/services/state.service.ts b/apps/app/services/state.service.ts index a9d0e4cdb..52481f8bb 100644 --- a/apps/app/services/state.service.ts +++ b/apps/app/services/state.service.ts @@ -8,17 +8,22 @@ const trackEvent = process.env.NEXT_PUBLIC_TRACK_EVENTS === "true" || process.env.NEXT_PUBLIC_TRACK_EVENTS === "1"; // types -import type { IState, IStateResponse } from "types"; +import type { ICurrentUserResponse, IState, IStateResponse } from "types"; class ProjectStateServices extends APIService { constructor() { super(NEXT_PUBLIC_API_BASE_URL || "http://localhost:8000"); } - async createState(workspaceSlug: string, projectId: string, data: any): Promise { + async createState( + workspaceSlug: string, + projectId: string, + data: any, + user: ICurrentUserResponse | undefined + ): Promise { return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/states/`, data) .then((response) => { - if (trackEvent) trackEventServices.trackStateEvent(response?.data, "STATE_CREATE"); + if (trackEvent) trackEventServices.trackStateEvent(response?.data, "STATE_CREATE", user); return response?.data; }) .catch((error) => { @@ -55,14 +60,15 @@ class ProjectStateServices extends APIService { workspaceSlug: string, projectId: string, stateId: string, - data: IState + data: IState, + user: ICurrentUserResponse | undefined ): Promise { return this.put( `/api/workspaces/${workspaceSlug}/projects/${projectId}/states/${stateId}/`, data ) .then((response) => { - if (trackEvent) trackEventServices.trackStateEvent(response?.data, "STATE_UPDATE"); + if (trackEvent) trackEventServices.trackStateEvent(response?.data, "STATE_UPDATE", user); return response?.data; }) .catch((error) => { @@ -74,14 +80,15 @@ class ProjectStateServices extends APIService { workspaceSlug: string, projectId: string, stateId: string, - data: Partial + data: Partial, + user: ICurrentUserResponse | undefined ): Promise { return this.patch( `/api/workspaces/${workspaceSlug}/projects/${projectId}/states/${stateId}/`, data ) .then((response) => { - if (trackEvent) trackEventServices.trackStateEvent(response?.data, "STATE_UPDATE"); + if (trackEvent) trackEventServices.trackStateEvent(response?.data, "STATE_UPDATE", user); return response?.data; }) .catch((error) => { @@ -89,10 +96,15 @@ class ProjectStateServices extends APIService { }); } - async deleteState(workspaceSlug: string, projectId: string, stateId: string): Promise { + async deleteState( + workspaceSlug: string, + projectId: string, + stateId: string, + user: ICurrentUserResponse | undefined + ): Promise { return this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/states/${stateId}/`) .then((response) => { - if (trackEvent) trackEventServices.trackStateEvent(response?.data, "STATE_DELETE"); + if (trackEvent) trackEventServices.trackStateEvent(response?.data, "STATE_DELETE", user); return response?.data; }) .catch((error) => { diff --git a/apps/app/services/track-event.service.ts b/apps/app/services/track-event.service.ts index 29ea0084a..cfd7e155c 100644 --- a/apps/app/services/track-event.service.ts +++ b/apps/app/services/track-event.service.ts @@ -6,6 +6,7 @@ const trackEvent = // types import type { + ICurrentUserResponse, ICycle, IEstimate, IGptResponse, @@ -104,7 +105,11 @@ class TrackEventServices extends APIService { super("/"); } - async trackWorkspaceEvent(data: IWorkspace | any, eventName: WorkspaceEventType): Promise { + async trackWorkspaceEvent( + data: IWorkspace | any, + eventName: WorkspaceEventType, + user: ICurrentUserResponse | undefined + ): Promise { let payload: any; if ( eventName !== "DELETE_WORKSPACE" && @@ -127,13 +132,15 @@ class TrackEventServices extends APIService { extra: { ...payload, }, + user: user, }, }); } async trackProjectEvent( data: Partial | any, - eventName: ProjectEventType + eventName: ProjectEventType, + user: ICurrentUserResponse | undefined ): Promise { let payload: any; if (eventName !== "DELETE_PROJECT" && eventName !== "PROJECT_MEMBER_INVITE") @@ -154,11 +161,15 @@ class TrackEventServices extends APIService { extra: { ...payload, }, + user: user, }, }); } - async trackUserOnboardingCompleteEvent(data: any): Promise { + async trackUserOnboardingCompleteEvent( + data: any, + user: ICurrentUserResponse | undefined + ): Promise { return this.request({ url: "/api/track-event", method: "POST", @@ -167,11 +178,16 @@ class TrackEventServices extends APIService { extra: { ...data, }, + user: user, }, }); } - async trackIssueEvent(data: IIssue | any, eventName: IssueEventType): Promise { + async trackIssueEvent( + data: IIssue | any, + eventName: IssueEventType, + user: ICurrentUserResponse | undefined + ): Promise { let payload: any; if (eventName !== "ISSUE_DELETE") payload = { @@ -193,11 +209,15 @@ class TrackEventServices extends APIService { extra: { ...payload, }, + user: user, }, }); } - async trackIssueMarkedAsDoneEvent(data: any): Promise { + async trackIssueMarkedAsDoneEvent( + data: any, + user: ICurrentUserResponse | undefined + ): Promise { if (!trackEvent) return; return this.request({ url: "/api/track-event", @@ -207,6 +227,7 @@ class TrackEventServices extends APIService { extra: { ...data, }, + user: user, }, }); } @@ -218,7 +239,8 @@ class TrackEventServices extends APIService { | "ISSUE_PROPERTY_UPDATE_STATE" | "ISSUE_PROPERTY_UPDATE_ASSIGNEE" | "ISSUE_PROPERTY_UPDATE_DUE_DATE" - | "ISSUE_PROPERTY_UPDATE_ESTIMATE" + | "ISSUE_PROPERTY_UPDATE_ESTIMATE", + user: ICurrentUserResponse | undefined ): Promise { if (!trackEvent) return; return this.request({ @@ -229,13 +251,15 @@ class TrackEventServices extends APIService { extra: { ...data, }, + user: user, }, }); } async trackIssueCommentEvent( data: Partial | any, - eventName: IssueCommentEventType + eventName: IssueCommentEventType, + user: ICurrentUserResponse | undefined ): Promise { let payload: any; if (eventName !== "ISSUE_COMMENT_DELETE") @@ -257,6 +281,7 @@ class TrackEventServices extends APIService { extra: { ...payload, }, + user: user, }, }); } @@ -267,7 +292,8 @@ class TrackEventServices extends APIService { | "ISSUE_MOVED_TO_CYCLE" | "ISSUE_MOVED_TO_MODULE" | "ISSUE_MOVED_TO_CYCLE_IN_BULK" - | "ISSUE_MOVED_TO_MODULE_IN_BULK" + | "ISSUE_MOVED_TO_MODULE_IN_BULK", + user: ICurrentUserResponse | undefined ): Promise { return this.request({ url: "/api/track-event", @@ -277,11 +303,12 @@ class TrackEventServices extends APIService { extra: { ...data, }, + user: user, }, }); } - async trackIssueBulkDeleteEvent(data: any): Promise { + async trackIssueBulkDeleteEvent(data: any, user: ICurrentUserResponse | undefined): Promise { return this.request({ url: "/api/track-event", method: "POST", @@ -290,11 +317,16 @@ class TrackEventServices extends APIService { extra: { ...data, }, + user: user, }, }); } - async trackIssueLabelEvent(data: any, eventName: IssueLabelEventType): Promise { + async trackIssueLabelEvent( + data: any, + eventName: IssueLabelEventType, + user: ICurrentUserResponse | undefined + ): Promise { return this.request({ url: "/api/track-event", method: "POST", @@ -303,11 +335,16 @@ class TrackEventServices extends APIService { extra: { ...data, }, + user: user, }, }); } - async trackStateEvent(data: IState | any, eventName: StateEventType): Promise { + async trackStateEvent( + data: IState | any, + eventName: StateEventType, + user: ICurrentUserResponse | undefined + ): Promise { let payload: any; if (eventName !== "STATE_DELETE") payload = { @@ -329,11 +366,16 @@ class TrackEventServices extends APIService { extra: { ...payload, }, + user: user, }, }); } - async trackCycleEvent(data: ICycle | any, eventName: CycleEventType): Promise { + async trackCycleEvent( + data: ICycle | any, + eventName: CycleEventType, + user: ICurrentUserResponse | undefined + ): Promise { let payload: any; if (eventName !== "CYCLE_DELETE") payload = { @@ -355,11 +397,16 @@ class TrackEventServices extends APIService { extra: { ...payload, }, + user: user, }, }); } - async trackModuleEvent(data: IModule | any, eventName: ModuleEventType): Promise { + async trackModuleEvent( + data: IModule | any, + eventName: ModuleEventType, + user: ICurrentUserResponse | undefined + ): Promise { let payload: any; if (eventName !== "MODULE_DELETE") payload = { @@ -381,11 +428,16 @@ class TrackEventServices extends APIService { extra: { ...payload, }, + user: user, }, }); } - async trackPageEvent(data: Partial | any, eventName: PagesEventType): Promise { + async trackPageEvent( + data: Partial | any, + eventName: PagesEventType, + user: ICurrentUserResponse | undefined + ): Promise { let payload: any; if (eventName !== "PAGE_DELETE") payload = { @@ -407,13 +459,15 @@ class TrackEventServices extends APIService { extra: { ...payload, }, + user: user, }, }); } async trackPageBlockEvent( data: Partial | IIssue, - eventName: PageBlocksEventType + eventName: PageBlocksEventType, + user: ICurrentUserResponse | undefined ): Promise { let payload: any; if (eventName !== "PAGE_BLOCK_DELETE" && eventName !== "PAGE_BLOCK_CONVERTED_TO_ISSUE") @@ -447,11 +501,16 @@ class TrackEventServices extends APIService { extra: { ...payload, }, + user: user, }, }); } - async trackAskGptEvent(data: IGptResponse, eventName: GptEventType): Promise { + async trackAskGptEvent( + data: IGptResponse, + eventName: GptEventType, + user: ICurrentUserResponse | undefined + ): Promise { const payload = { workspaceId: data?.workspace_detail?.id, workspaceName: data?.workspace_detail?.name, @@ -469,11 +528,16 @@ class TrackEventServices extends APIService { extra: { ...payload, }, + user: user, }, }); } - async trackUseGPTResponseEvent(data: IIssue | IPageBlock, eventName: GptEventType): Promise { + async trackUseGPTResponseEvent( + data: IIssue | IPageBlock, + eventName: GptEventType, + user: ICurrentUserResponse | undefined + ): Promise { if (!trackEvent) return; let payload: any; @@ -509,11 +573,16 @@ class TrackEventServices extends APIService { extra: { ...payload, }, + user: user, }, }); } - async trackViewEvent(data: IView, eventName: ViewEventType): Promise { + async trackViewEvent( + data: IView, + eventName: ViewEventType, + user: ICurrentUserResponse | undefined + ): Promise { let payload: any; if (eventName === "VIEW_DELETE") payload = data; else @@ -533,11 +602,16 @@ class TrackEventServices extends APIService { extra: { ...payload, }, + user: user, }, }); } - async trackMiscellaneousEvent(data: any, eventName: MiscellaneousEventType): Promise { + async trackMiscellaneousEvent( + data: any, + eventName: MiscellaneousEventType, + user: ICurrentUserResponse | undefined + ): Promise { return this.request({ url: "/api/track-event", method: "POST", @@ -546,11 +620,16 @@ class TrackEventServices extends APIService { extra: { ...data, }, + user: user, }, }); } - async trackAppIntegrationEvent(data: any, eventName: IntegrationEventType): Promise { + async trackAppIntegrationEvent( + data: any, + eventName: IntegrationEventType, + user: ICurrentUserResponse | undefined + ): Promise { return this.request({ url: "/api/track-event", method: "POST", @@ -559,11 +638,16 @@ class TrackEventServices extends APIService { extra: { ...data, }, + user: user, }, }); } - async trackGitHubSyncEvent(data: any, eventName: GitHubSyncEventType): Promise { + async trackGitHubSyncEvent( + data: any, + eventName: GitHubSyncEventType, + user: ICurrentUserResponse | undefined + ): Promise { return this.request({ url: "/api/track-event", method: "POST", @@ -572,13 +656,15 @@ class TrackEventServices extends APIService { extra: { ...data, }, + user: user, }, }); } async trackIssueEstimateEvent( data: { estimate: IEstimate }, - eventName: IssueEstimateEventType + eventName: IssueEstimateEventType, + user: ICurrentUserResponse | undefined ): Promise { let payload: any; if (eventName === "ESTIMATE_DELETE") payload = data; @@ -601,11 +687,16 @@ class TrackEventServices extends APIService { extra: { ...payload, }, + user: user, }, }); } - async trackImporterEvent(data: any, eventName: ImporterEventType): Promise { + async trackImporterEvent( + data: any, + eventName: ImporterEventType, + user: ICurrentUserResponse | undefined + ): Promise { let payload: any; if (eventName === "GITHUB_IMPORTER_DELETE" || eventName === "JIRA_IMPORTER_DELETE") payload = data; @@ -627,11 +718,16 @@ class TrackEventServices extends APIService { extra: { ...payload, }, + user: user, }, }); } - async trackAnalyticsEvent(data: any, eventName: AnalyticsEventType): Promise { + async trackAnalyticsEvent( + data: any, + eventName: AnalyticsEventType, + user: ICurrentUserResponse | undefined + ): Promise { const payload = { ...data }; return this.request({ @@ -640,6 +736,7 @@ class TrackEventServices extends APIService { data: { eventName, extra: payload, + user: user, }, }); } diff --git a/apps/app/services/user.service.ts b/apps/app/services/user.service.ts index 5f0786b81..209d3cc4f 100644 --- a/apps/app/services/user.service.ts +++ b/apps/app/services/user.service.ts @@ -50,16 +50,19 @@ class UserService extends APIService { }); } - async updateUserOnBoard({ userRole }: any): Promise { + async updateUserOnBoard({ userRole }: any, user: ICurrentUserResponse | undefined): Promise { return this.patch("/api/users/me/onboard/", { is_onboarded: true, }) .then((response) => { if (trackEvent) - trackEventServices.trackUserOnboardingCompleteEvent({ - ...response.data, - user_role: userRole ?? "None", - }); + trackEventServices.trackUserOnboardingCompleteEvent( + { + ...response.data, + user_role: userRole ?? "None", + }, + user + ); return response?.data; }) .catch((error) => { diff --git a/apps/app/services/views.service.ts b/apps/app/services/views.service.ts index af2426a7c..e1d25925e 100644 --- a/apps/app/services/views.service.ts +++ b/apps/app/services/views.service.ts @@ -1,6 +1,7 @@ // services import APIService from "services/api.service"; import trackEventServices from "services/track-event.service"; +import { ICurrentUserResponse } from "types"; // types import { IView } from "types/views"; @@ -15,10 +16,15 @@ class ViewServices extends APIService { super(NEXT_PUBLIC_API_BASE_URL || "http://localhost:8000"); } - async createView(workspaceSlug: string, projectId: string, data: IView): Promise { + async createView( + workspaceSlug: string, + projectId: string, + data: IView, + user: ICurrentUserResponse | undefined + ): Promise { return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/views/`, data) .then((response) => { - if (trackEvent) trackEventServices.trackViewEvent(response?.data, "VIEW_CREATE"); + if (trackEvent) trackEventServices.trackViewEvent(response?.data, "VIEW_CREATE", user); return response?.data; }) .catch((error) => { @@ -30,11 +36,12 @@ class ViewServices extends APIService { workspaceSlug: string, projectId: string, viewId: string, - data: IView + data: IView, + user: ICurrentUserResponse | undefined ): Promise { return this.put(`/api/workspaces/${workspaceSlug}/projects/${projectId}/views/${viewId}/`, data) .then((response) => { - if (trackEvent) trackEventServices.trackViewEvent(response?.data, "VIEW_UPDATE"); + if (trackEvent) trackEventServices.trackViewEvent(response?.data, "VIEW_UPDATE", user); return response?.data; }) .catch((error) => { @@ -46,14 +53,15 @@ class ViewServices extends APIService { workspaceSlug: string, projectId: string, viewId: string, - data: Partial + data: Partial, + user: ICurrentUserResponse | undefined ): Promise { return this.patch( `/api/workspaces/${workspaceSlug}/projects/${projectId}/views/${viewId}/`, data ) .then((response) => { - if (trackEvent) trackEventServices.trackViewEvent(response?.data, "VIEW_UPDATE"); + if (trackEvent) trackEventServices.trackViewEvent(response?.data, "VIEW_UPDATE", user); return response?.data; }) .catch((error) => { @@ -61,10 +69,15 @@ class ViewServices extends APIService { }); } - async deleteView(workspaceSlug: string, projectId: string, viewId: string): Promise { + async deleteView( + workspaceSlug: string, + projectId: string, + viewId: string, + user: ICurrentUserResponse | undefined + ): Promise { return this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/views/${viewId}/`) .then((response) => { - if (trackEvent) trackEventServices.trackViewEvent(response?.data, "VIEW_DELETE"); + if (trackEvent) trackEventServices.trackViewEvent(response?.data, "VIEW_DELETE", user); return response?.data; }) .catch((error) => { diff --git a/apps/app/services/workspace.service.ts b/apps/app/services/workspace.service.ts index 004240e5d..21ec7c1df 100644 --- a/apps/app/services/workspace.service.ts +++ b/apps/app/services/workspace.service.ts @@ -12,6 +12,7 @@ import { ILastActiveWorkspaceDetails, IWorkspaceSearchResults, IProductUpdateResponse, + ICurrentUserResponse, } from "types"; const trackEvent = @@ -38,10 +39,14 @@ class WorkspaceService extends APIService { }); } - async createWorkspace(data: Partial): Promise { + async createWorkspace( + data: Partial, + user: ICurrentUserResponse | undefined + ): Promise { return this.post("/api/workspaces/", data) .then((response) => { - if (trackEvent) trackEventServices.trackWorkspaceEvent(response.data, "CREATE_WORKSPACE"); + if (trackEvent) + trackEventServices.trackWorkspaceEvent(response.data, "CREATE_WORKSPACE", user); return response?.data; }) .catch((error) => { @@ -49,10 +54,15 @@ class WorkspaceService extends APIService { }); } - async updateWorkspace(workspaceSlug: string, data: Partial): Promise { + async updateWorkspace( + workspaceSlug: string, + data: Partial, + user: ICurrentUserResponse | undefined + ): Promise { return this.patch(`/api/workspaces/${workspaceSlug}/`, data) .then((response) => { - if (trackEvent) trackEventServices.trackWorkspaceEvent(response.data, "UPDATE_WORKSPACE"); + if (trackEvent) + trackEventServices.trackWorkspaceEvent(response.data, "UPDATE_WORKSPACE", user); return response?.data; }) .catch((error) => { @@ -60,11 +70,14 @@ class WorkspaceService extends APIService { }); } - async deleteWorkspace(workspaceSlug: string): Promise { + async deleteWorkspace( + workspaceSlug: string, + user: ICurrentUserResponse | undefined + ): Promise { return this.delete(`/api/workspaces/${workspaceSlug}/`) .then((response) => { if (trackEvent) - trackEventServices.trackWorkspaceEvent({ workspaceSlug }, "DELETE_WORKSPACE"); + trackEventServices.trackWorkspaceEvent({ workspaceSlug }, "DELETE_WORKSPACE", user); return response?.data; }) .catch((error) => { @@ -72,11 +85,15 @@ class WorkspaceService extends APIService { }); } - async inviteWorkspace(workspaceSlug: string, data: any): Promise { + async inviteWorkspace( + workspaceSlug: string, + data: any, + user: ICurrentUserResponse | undefined + ): Promise { return this.post(`/api/workspaces/${workspaceSlug}/invite/`, data) .then((response) => { if (trackEvent) - trackEventServices.trackWorkspaceEvent(response.data, "WORKSPACE_USER_INVITE"); + trackEventServices.trackWorkspaceEvent(response.data, "WORKSPACE_USER_INVITE", user); return response?.data; }) .catch((error) => { @@ -84,7 +101,12 @@ class WorkspaceService extends APIService { }); } - async joinWorkspace(workspaceSlug: string, invitationId: string, data: any): Promise { + async joinWorkspace( + workspaceSlug: string, + invitationId: string, + data: any, + user: ICurrentUserResponse | undefined + ): Promise { return this.post( `/api/users/me/invitations/workspaces/${workspaceSlug}/${invitationId}/join/`, data, @@ -94,7 +116,11 @@ class WorkspaceService extends APIService { ) .then((response) => { if (trackEvent) - trackEventServices.trackWorkspaceEvent(response.data, "WORKSPACE_USER_INVITE_ACCEPT"); + trackEventServices.trackWorkspaceEvent( + response.data, + "WORKSPACE_USER_INVITE_ACCEPT", + user + ); return response?.data; }) .catch((error) => { diff --git a/apps/app/types/workspace.d.ts b/apps/app/types/workspace.d.ts index a88a0f15b..ee0458bfe 100644 --- a/apps/app/types/workspace.d.ts +++ b/apps/app/types/workspace.d.ts @@ -30,6 +30,7 @@ export interface IWorkspaceMemberInvitation { message: string; responded_at: Date; role: 5 | 10 | 15 | 20; + created_by_detail: IUser; workspace: IWorkspace; }