diff --git a/web/components/command-palette/change-interface-theme.tsx b/web/components/command-palette/change-interface-theme.tsx index 7b295d38a..0b899f811 100644 --- a/web/components/command-palette/change-interface-theme.tsx +++ b/web/components/command-palette/change-interface-theme.tsx @@ -1,12 +1,13 @@ import React, { FC, Dispatch, SetStateAction, useEffect, useState } from "react"; import { Command } from "cmdk"; -import { THEME_OPTIONS } from "constants/themes"; import { useTheme } from "next-themes"; import { Settings } from "lucide-react"; import { observer } from "mobx-react-lite"; // hooks import useToast from "hooks/use-toast"; import { useMobxStore } from "lib/mobx/store-provider"; +// constants +import { THEME_OPTIONS } from "constants/themes"; type Props = { setIsPaletteOpen: Dispatch>; diff --git a/web/components/command-palette/issue/change-issue-assignee.tsx b/web/components/command-palette/issue/change-issue-assignee.tsx index 9a833278c..2d655571c 100644 --- a/web/components/command-palette/issue/change-issue-assignee.tsx +++ b/web/components/command-palette/issue/change-issue-assignee.tsx @@ -1,19 +1,19 @@ import { Dispatch, SetStateAction, useCallback, FC } from "react"; import { useRouter } from "next/router"; +import { observer } from "mobx-react-lite"; import { mutate } from "swr"; import { Command } from "cmdk"; +import { Check } from "lucide-react"; +// mobx store +import { useMobxStore } from "lib/mobx/store-provider"; // services import { IssueService } from "services/issue"; -// hooks -import useProjectMembers from "hooks/use-project-members"; -// constants -import { ISSUE_DETAILS, PROJECT_ISSUES_ACTIVITY } from "constants/fetch-keys"; // ui import { Avatar } from "@plane/ui"; -// icons -import { Check } from "lucide-react"; // types import { IUser, IIssue } from "types"; +// constants +import { ISSUE_DETAILS, PROJECT_ISSUES_ACTIVITY } from "constants/fetch-keys"; type Props = { setIsPaletteOpen: Dispatch>; @@ -24,11 +24,14 @@ type Props = { // services const issueService = new IssueService(); -export const ChangeIssueAssignee: FC = ({ setIsPaletteOpen, issue, user }) => { +export const ChangeIssueAssignee: FC = observer((props) => { + const { setIsPaletteOpen, issue, user } = props; + const router = useRouter(); const { workspaceSlug, projectId, issueId } = router.query; - const { members } = useProjectMembers(workspaceSlug as string, projectId as string); + const { project: projectStore } = useMobxStore(); + const members = projectId ? projectStore.members?.[projectId.toString()] : undefined; const options = members?.map(({ member }) => ({ @@ -104,4 +107,4 @@ export const ChangeIssueAssignee: FC = ({ setIsPaletteOpen, issue, user } ))} ); -}; +}); diff --git a/web/components/core/activity.tsx b/web/components/core/activity.tsx index b44447fb9..1712dd53e 100644 --- a/web/components/core/activity.tsx +++ b/web/components/core/activity.tsx @@ -89,6 +89,7 @@ const LabelPill = ({ labelId }: { labelId: string }) => { /> ); }; + const EstimatePoint = ({ point }: { point: string }) => { const { estimateValue, isEstimateActive } = useEstimateOption(Number(point)); const currentPoint = Number(point) + 1; diff --git a/web/components/core/filters/filters-list.tsx b/web/components/core/filters/filters-list.tsx deleted file mode 100644 index 0480413c2..000000000 --- a/web/components/core/filters/filters-list.tsx +++ /dev/null @@ -1,349 +0,0 @@ -import React from "react"; -import { X } from "lucide-react"; -// ui -import { Avatar, PriorityIcon, StateGroupIcon } from "@plane/ui"; -// helpers -import { replaceUnderscoreIfSnakeCase } from "helpers/string.helper"; -import { renderShortDateWithYearFormat } from "helpers/date-time.helper"; -// types -import { IIssueFilterOptions, IIssueLabels, IState, IUserLite, TStateGroups } from "types"; -// constants -import { STATE_GROUP_COLORS } from "constants/state"; - -type Props = { - filters: Partial; - setFilters: (updatedFilter: Partial) => void; - clearAllFilters: (...args: any) => void; - labels: IIssueLabels[] | undefined; - members: IUserLite[] | undefined; - states: IState[] | undefined; -}; - -export const FiltersList: React.FC = ({ filters, setFilters, clearAllFilters, labels, members, states }) => { - if (!filters) return <>; - - const nullFilters = Object.keys(filters).filter((key) => filters[key as keyof IIssueFilterOptions] === null); - - return ( -
- {Object.keys(filters).map((filterKey) => { - const key = filterKey as keyof typeof filters; - - if (filters[key] === null) return null; - - return ( -
- - {key === "target_date" ? "Due Date" : replaceUnderscoreIfSnakeCase(key)}: - - {filters[key] === null || (filters[key]?.length ?? 0) <= 0 ? ( - None - ) : Array.isArray(filters[key]) ? ( -
-
- {key === "state" - ? filters.state?.map((stateId: string) => { - const state = states?.find((s) => s.id === stateId); - - return ( -

- - - - {state?.name ?? ""} - - setFilters({ - state: filters.state?.filter((s: any) => s !== stateId), - }) - } - > - - -

- ); - }) - : key === "state_group" - ? filters.state_group?.map((stateGroup) => { - const group = stateGroup as TStateGroups; - - return ( -

- - - - {group} - - setFilters({ - state_group: filters.state_group?.filter((g) => g !== group), - }) - } - > - - -

- ); - }) - : key === "priority" - ? filters.priority?.map((priority: any) => ( -

- - - - {priority === "null" ? "None" : priority} - - setFilters({ - priority: filters.priority?.filter((p: any) => p !== priority), - }) - } - > - - -

- )) - : key === "mentions" - ? filters.mentions?.map((mentionId: string) => { - const member = members?.find((m) => m.id === mentionId); - return ( -
- - {member?.display_name} - - setFilters({ - mentions: filters.mentions?.filter((p: any) => p !== mentionId), - }) - } - > - - -
- ); - }) - : key === "assignees" - ? filters.assignees?.map((memberId: string) => { - const member = members?.find((m) => m.id === memberId); - - return ( -
- - {member?.display_name} - - setFilters({ - subscriber: filters.subscriber?.filter((p: any) => p !== memberId), - }) - } - > - - -
- ); - }) - : key === "created_by" - ? filters.created_by?.map((memberId: string) => { - const member = members?.find((m) => m.id === memberId); - - return ( -
- - {member?.display_name} - - setFilters({ - created_by: filters.created_by?.filter((p: any) => p !== memberId), - }) - } - > - - -
- ); - }) - : key === "labels" - ? filters.labels?.map((labelId: string) => { - const label = labels?.find((l) => l.id === labelId); - - if (!label) return null; - const color = label.color !== "" ? label.color : "#0f172a"; - return ( -
-
- {label.name} - - setFilters({ - labels: filters.labels?.filter((l: any) => l !== labelId), - }) - } - > - - -
- ); - }) - : key === "start_date" - ? filters.start_date?.map((date: string) => { - if (filters.start_date && filters.start_date.length <= 0) return null; - - const splitDate = date.split(";"); - - return ( -
-
- - {splitDate[1]} {renderShortDateWithYearFormat(splitDate[0])} - - - setFilters({ - start_date: filters.start_date?.filter((d: any) => d !== date), - }) - } - > - - -
- ); - }) - : key === "target_date" - ? filters.target_date?.map((date: string) => { - if (filters.target_date && filters.target_date.length <= 0) return null; - - const splitDate = date.split(";"); - - return ( -
-
- - {splitDate[1]} {renderShortDateWithYearFormat(splitDate[0])} - - - setFilters({ - target_date: filters.target_date?.filter((d: any) => d !== date), - }) - } - > - - -
- ); - }) - : (filters[key] as any)?.join(", ")} - -
-
- ) : ( -
- {filters[key as keyof typeof filters]} - -
- )} -
- ); - })} - {Object.keys(filters).length > 0 && nullFilters.length !== Object.keys(filters).length && ( - - )} -
- ); -}; diff --git a/web/components/core/filters/index.ts b/web/components/core/filters/index.ts index 9c7c727ca..28e36d3e6 100644 --- a/web/components/core/filters/index.ts +++ b/web/components/core/filters/index.ts @@ -1,3 +1,2 @@ export * from "./date-filter-modal"; export * from "./date-filter-select"; -export * from "./filters-list"; diff --git a/web/components/core/index.ts b/web/components/core/index.ts index 6989b05c0..ff0fabc4e 100644 --- a/web/components/core/index.ts +++ b/web/components/core/index.ts @@ -2,7 +2,6 @@ export * from "./filters"; export * from "./modals"; export * from "./sidebar"; export * from "./theme"; -export * from "./views"; export * from "./activity"; export * from "./reaction-selector"; export * from "./image-picker-popover"; diff --git a/web/components/core/modals/bulk-delete-issues-modal.tsx b/web/components/core/modals/bulk-delete-issues-modal.tsx index 6392fc557..c2bc466d5 100644 --- a/web/components/core/modals/bulk-delete-issues-modal.tsx +++ b/web/components/core/modals/bulk-delete-issues-modal.tsx @@ -1,6 +1,6 @@ import React, { useState } from "react"; import { useRouter } from "next/router"; -import useSWR, { mutate } from "swr"; +import useSWR from "swr"; // react hook form import { SubmitHandler, useForm } from "react-hook-form"; // headless ui @@ -9,7 +9,6 @@ import { Combobox, Dialog, Transition } from "@headlessui/react"; import { IssueService } from "services/issue"; // hooks import useToast from "hooks/use-toast"; -import useIssuesView from "hooks/use-issues-view"; // ui import { Button, LayersIcon } from "@plane/ui"; // icons @@ -17,15 +16,7 @@ import { Search } from "lucide-react"; // types import { IUser, IIssue } from "types"; // fetch keys -import { - CYCLE_DETAILS, - CYCLE_ISSUES_WITH_PARAMS, - MODULE_DETAILS, - MODULE_ISSUES_WITH_PARAMS, - PROJECT_ISSUES_LIST, - PROJECT_ISSUES_LIST_WITH_PARAMS, - VIEW_ISSUES, -} from "constants/fetch-keys"; +import { PROJECT_ISSUES_LIST } from "constants/fetch-keys"; type FormInput = { delete_issue_ids: string[]; @@ -43,7 +34,7 @@ export const BulkDeleteIssuesModal: React.FC = (props) => { const { isOpen, onClose, user } = props; // router const router = useRouter(); - const { workspaceSlug, projectId, cycleId, moduleId, viewId } = router.query; + const { workspaceSlug, projectId } = router.query; // states const [query, setQuery] = useState(""); // fetching project issues. @@ -53,9 +44,6 @@ export const BulkDeleteIssuesModal: React.FC = (props) => { ); const { setToastAlert } = useToast(); - const { displayFilters, params } = useIssuesView(); - // eslint-disable-next-line @typescript-eslint/no-unused-vars - const { order_by, group_by, ...viewGanttParams } = params; const { handleSubmit, @@ -89,14 +77,6 @@ export const BulkDeleteIssuesModal: React.FC = (props) => { if (!Array.isArray(data.delete_issue_ids)) data.delete_issue_ids = [data.delete_issue_ids]; - const ganttFetchKey = cycleId - ? CYCLE_ISSUES_WITH_PARAMS(cycleId.toString()) - : moduleId - ? MODULE_ISSUES_WITH_PARAMS(moduleId.toString()) - : viewId - ? VIEW_ISSUES(viewId.toString(), viewGanttParams) - : PROJECT_ISSUES_LIST_WITH_PARAMS(projectId?.toString() ?? ""); - await issueService .bulkDeleteIssues( workspaceSlug as string, @@ -113,17 +93,6 @@ export const BulkDeleteIssuesModal: React.FC = (props) => { message: "Issues deleted successfully!", }); - if (displayFilters.layout === "gantt_chart") mutate(ganttFetchKey); - else { - if (cycleId) { - mutate(CYCLE_ISSUES_WITH_PARAMS(cycleId.toString(), params)); - mutate(CYCLE_DETAILS(cycleId.toString())); - } else if (moduleId) { - mutate(MODULE_ISSUES_WITH_PARAMS(moduleId as string, params)); - mutate(MODULE_DETAILS(moduleId as string)); - } else mutate(PROJECT_ISSUES_LIST_WITH_PARAMS(projectId.toString(), params)); - } - handleClose(); }) .catch(() => diff --git a/web/components/core/modals/existing-issues-list-modal.tsx b/web/components/core/modals/existing-issues-list-modal.tsx index 799968791..663dbfc83 100644 --- a/web/components/core/modals/existing-issues-list-modal.tsx +++ b/web/components/core/modals/existing-issues-list-modal.tsx @@ -1,30 +1,16 @@ import React, { useEffect, useState } from "react"; - import { useRouter } from "next/router"; - -import { mutate } from "swr"; - -// headless ui import { Combobox, Dialog, Transition } from "@headlessui/react"; +import { Rocket, Search, X } from "lucide-react"; // services import { ProjectService } from "services/project"; // hooks import useToast from "hooks/use-toast"; -import useIssuesView from "hooks/use-issues-view"; import useDebounce from "hooks/use-debounce"; // ui import { Button, LayersIcon, Loader, ToggleSwitch, Tooltip } from "@plane/ui"; -// icons -import { Rocket, Search, X } from "lucide-react"; // types import { ISearchIssueResponse, TProjectIssuesSearchParams } from "types"; -// fetch-keys -import { - CYCLE_DETAILS, - CYCLE_ISSUES_WITH_PARAMS, - MODULE_DETAILS, - MODULE_ISSUES_WITH_PARAMS, -} from "constants/fetch-keys"; type Props = { isOpen: boolean; @@ -53,12 +39,10 @@ export const ExistingIssuesListModal: React.FC = ({ const debouncedSearchTerm: string = useDebounce(searchTerm, 500); const router = useRouter(); - const { workspaceSlug, projectId, cycleId, moduleId } = router.query; + const { workspaceSlug, projectId } = router.query; const { setToastAlert } = useToast(); - const { params } = useIssuesView(); - const handleClose = () => { onClose(); setSearchTerm(""); @@ -81,16 +65,6 @@ export const ExistingIssuesListModal: React.FC = ({ await handleOnSubmit(selectedIssues).finally(() => setIsSubmitting(false)); - if (cycleId) { - mutate(CYCLE_ISSUES_WITH_PARAMS(cycleId as string, params)); - mutate(CYCLE_DETAILS(cycleId as string)); - } - - if (moduleId) { - mutate(MODULE_ISSUES_WITH_PARAMS(moduleId as string, params)); - mutate(MODULE_DETAILS(moduleId as string)); - } - handleClose(); setToastAlert({ diff --git a/web/components/core/sidebar/links-list.tsx b/web/components/core/sidebar/links-list.tsx index ff8d30927..2437b31a3 100644 --- a/web/components/core/sidebar/links-list.tsx +++ b/web/components/core/sidebar/links-list.tsx @@ -15,6 +15,7 @@ type Props = { export const LinksList: React.FC = ({ links, handleDeleteLink, handleEditLink, userAuth }) => { const isNotAllowed = userAuth.isGuest || userAuth.isViewer; + return ( <> {links.map((link) => ( diff --git a/web/components/core/sidebar/sidebar-progress-stats.tsx b/web/components/core/sidebar/sidebar-progress-stats.tsx index 268802fec..66a841205 100644 --- a/web/components/core/sidebar/sidebar-progress-stats.tsx +++ b/web/components/core/sidebar/sidebar-progress-stats.tsx @@ -5,7 +5,6 @@ import Image from "next/image"; import { Tab } from "@headlessui/react"; // hooks import useLocalStorage from "hooks/use-local-storage"; -import useIssuesView from "hooks/use-issues-view"; // images import emptyLabel from "public/empty-state/empty_label.svg"; import emptyMembers from "public/empty-state/empty_members.svg"; @@ -47,8 +46,6 @@ export const SidebarProgressStats: React.FC = ({ noBackground, isPeekView = false, }) => { - const { filters, setFilters } = useIssuesView(); - const { storedValue: tab, setValue: setTab } = useLocalStorage("tab", "Assignees"); const currentValue = (tab: string | null) => { @@ -145,16 +142,17 @@ export const SidebarProgressStats: React.FC = ({ total={assignee.total_issues} {...(!isPeekView && { onClick: () => { - if (filters?.assignees?.includes(assignee.assignee_id ?? "")) - setFilters({ - assignees: filters?.assignees?.filter((a) => a !== assignee.assignee_id), - }); - else - setFilters({ - assignees: [...(filters?.assignees ?? []), assignee.assignee_id ?? ""], - }); + // TODO: set filters here + // if (filters?.assignees?.includes(assignee.assignee_id ?? "")) + // setFilters({ + // assignees: filters?.assignees?.filter((a) => a !== assignee.assignee_id), + // }); + // else + // setFilters({ + // assignees: [...(filters?.assignees ?? []), assignee.assignee_id ?? ""], + // }); }, - selected: filters?.assignees?.includes(assignee.assignee_id ?? ""), + // selected: filters?.assignees?.includes(assignee.assignee_id ?? ""), })} /> ); @@ -203,14 +201,15 @@ export const SidebarProgressStats: React.FC = ({ completed={label.completed_issues} total={label.total_issues} {...(!isPeekView && { + // TODO: set filters here onClick: () => { - if (filters.labels?.includes(label.label_id ?? "")) - setFilters({ - labels: filters?.labels?.filter((l) => l !== label.label_id), - }); - else setFilters({ labels: [...(filters?.labels ?? []), label.label_id ?? ""] }); + // if (filters.labels?.includes(label.label_id ?? "")) + // setFilters({ + // labels: filters?.labels?.filter((l) => l !== label.label_id), + // }); + // else setFilters({ labels: [...(filters?.labels ?? []), label.label_id ?? ""] }); }, - selected: filters?.labels?.includes(label.label_id ?? ""), + // selected: filters?.labels?.includes(label.label_id ?? ""), })} /> )) diff --git a/web/components/core/views/gantt-chart-view/inline-create-issue-form.tsx b/web/components/core/views/gantt-chart-view/inline-create-issue-form.tsx deleted file mode 100644 index 785eb3c5a..000000000 --- a/web/components/core/views/gantt-chart-view/inline-create-issue-form.tsx +++ /dev/null @@ -1,62 +0,0 @@ -import { useEffect } from "react"; - -// react hook form -import { useFormContext } from "react-hook-form"; - -// hooks -import useProjectDetails from "hooks/use-project-details"; - -// components -import { InlineCreateIssueFormWrapper } from "components/core"; - -// types -import { IIssue } from "types"; - -type Props = { - isOpen: boolean; - handleClose: () => void; - onSuccess?: (data: IIssue) => Promise | void; - prePopulatedData?: Partial; -}; - -const InlineInput = () => { - const { projectDetails } = useProjectDetails(); - - const { register, setFocus } = useFormContext(); - - useEffect(() => { - setFocus("name"); - }, [setFocus]); - - return ( - <> -
-

{projectDetails?.identifier ?? "..."}

- - - ); -}; - -export const GanttInlineCreateIssueForm: React.FC = (props) => ( - <> - - - - {props.isOpen && ( -

- Press {"'"}Enter{"'"} to add another issue -

- )} - -); diff --git a/web/components/core/views/index.ts b/web/components/core/views/index.ts deleted file mode 100644 index 3323690a1..000000000 --- a/web/components/core/views/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./inline-issue-create-wrapper"; diff --git a/web/components/core/views/inline-issue-create-wrapper.tsx b/web/components/core/views/inline-issue-create-wrapper.tsx deleted file mode 100644 index b17a6b34b..000000000 --- a/web/components/core/views/inline-issue-create-wrapper.tsx +++ /dev/null @@ -1,238 +0,0 @@ -import { useEffect, useRef } from "react"; -import { useRouter } from "next/router"; -import { mutate } from "swr"; -import { useForm, FormProvider } from "react-hook-form"; -import { Transition } from "@headlessui/react"; -// services -import { ModuleService } from "services/module.service"; -import { IssueService, IssueDraftService } from "services/issue"; -// hooks -import useToast from "hooks/use-toast"; -import useUser from "hooks/use-user"; -import useKeypress from "hooks/use-keypress"; -import useIssuesView from "hooks/use-issues-view"; -import useMyIssues from "hooks/my-issues/use-my-issues"; -import useGanttChartIssues from "hooks/gantt-chart/issue-view"; -// import useCalendarIssuesView from "hooks/use-calendar-issues-view"; -import useOutsideClickDetector from "hooks/use-outside-click-detector"; -// import useSpreadsheetIssuesView from "hooks/use-spreadsheet-issues-view"; -// helpers -import { getFetchKeysForIssueMutation } from "helpers/string.helper"; - -// fetch-keys -import { - USER_ISSUE, - SUB_ISSUES, - CYCLE_ISSUES_WITH_PARAMS, - MODULE_ISSUES_WITH_PARAMS, - CYCLE_DETAILS, - MODULE_DETAILS, - PROJECT_ISSUES_LIST_WITH_PARAMS, - PROJECT_DRAFT_ISSUES_LIST_WITH_PARAMS, -} from "constants/fetch-keys"; - -// types -import { IIssue } from "types"; - -const defaultValues: Partial = { - name: "", -}; - -type Props = { - isOpen: boolean; - handleClose: () => void; - onSuccess?: (data: IIssue) => Promise | void; - prePopulatedData?: Partial; - className?: string; - children?: React.ReactNode; -}; - -const issueService = new IssueService(); -const issueDraftService = new IssueDraftService(); -const moduleService = new ModuleService(); - -export const addIssueToCycle = async ( - workspaceSlug: string, - projectId: string, - issueId: string, - cycleId: string, - user: any, - params: any -) => { - if (!workspaceSlug || !projectId) return; - - await issueService - .addIssueToCycle( - workspaceSlug as string, - projectId.toString(), - cycleId, - { - issues: [issueId], - }, - user - ) - .then(() => { - if (cycleId) { - mutate(CYCLE_ISSUES_WITH_PARAMS(cycleId, params)); - mutate(CYCLE_DETAILS(cycleId as string)); - } - }); -}; - -export const addIssueToModule = async ( - workspaceSlug: string, - projectId: string, - issueId: string, - moduleId: string, - user: any, - params: any -) => { - await moduleService - .addIssuesToModule( - workspaceSlug as string, - projectId.toString(), - moduleId as string, - { - issues: [issueId], - }, - user - ) - .then(() => { - if (moduleId) { - mutate(MODULE_ISSUES_WITH_PARAMS(moduleId as string, params)); - mutate(MODULE_DETAILS(moduleId as string)); - } - }); -}; - -export const InlineCreateIssueFormWrapper: React.FC = (props) => { - const { isOpen, handleClose, onSuccess, prePopulatedData, children, className } = props; - - const ref = useRef(null); - - const router = useRouter(); - const { workspaceSlug, projectId, cycleId, moduleId, viewId } = router.query; - - const isDraftIssues = router.pathname?.split("/")?.[4] === "draft-issues"; - - const { user } = useUser(); - - const { setToastAlert } = useToast(); - - const { displayFilters, params } = useIssuesView(); - // const { params: calendarParams } = useCalendarIssuesView(); - const { ...viewGanttParams } = params; - // const { params: spreadsheetParams } = useSpreadsheetIssuesView(); - const { groupedIssues, mutateMyIssues } = useMyIssues(workspaceSlug?.toString()); - const { params: ganttParams } = useGanttChartIssues(workspaceSlug?.toString(), projectId?.toString()); - - const method = useForm({ defaultValues }); - const { - reset, - handleSubmit, - getValues, - formState: { errors, isSubmitting }, - } = method; - - useOutsideClickDetector(ref, handleClose); - useKeypress("Escape", handleClose); - - useEffect(() => { - const values = getValues(); - - if (prePopulatedData) reset({ ...defaultValues, ...values, ...prePopulatedData }); - }, [reset, prePopulatedData, getValues]); - - useEffect(() => { - if (!isOpen) reset({ ...defaultValues }); - }, [isOpen, reset]); - - useEffect(() => { - if (!errors) return; - - Object.keys(errors).forEach((key) => { - const error = errors[key as keyof IIssue]; - - setToastAlert({ - type: "error", - title: "Error!", - message: error?.message?.toString() || "Some error occurred. Please try again.", - }); - }); - }, [errors, setToastAlert]); - - const { ganttFetchKey } = getFetchKeysForIssueMutation({ - cycleId: cycleId, - moduleId: moduleId, - viewId: viewId, - projectId: projectId?.toString() ?? "", - viewGanttParams, - ganttParams, - }); - - const onSubmitHandler = async (formData: IIssue) => { - if (!workspaceSlug || !projectId || !user || isSubmitting) return; - - reset({ ...defaultValues }); - - await (!isDraftIssues - ? issueService.createIssue(workspaceSlug.toString(), projectId.toString(), formData, user) - : issueDraftService.createDraftIssue(workspaceSlug.toString(), projectId.toString(), formData) - ) - .then(async (res) => { - await mutate(PROJECT_ISSUES_LIST_WITH_PARAMS(projectId.toString(), params)); - if (formData.cycle && formData.cycle !== "") - await addIssueToCycle(workspaceSlug.toString(), projectId.toString(), res.id, formData.cycle, user, params); - if (formData.module && formData.module !== "") - await addIssueToModule(workspaceSlug.toString(), projectId.toString(), res.id, formData.module, user, params); - - if (isDraftIssues) await mutate(PROJECT_DRAFT_ISSUES_LIST_WITH_PARAMS(projectId.toString() ?? "", params)); - if (displayFilters.layout === "gantt_chart") await mutate(ganttFetchKey); - if (groupedIssues) await mutateMyIssues(); - - setToastAlert({ - type: "success", - title: "Success!", - message: "Issue created successfully.", - }); - - if (onSuccess) await onSuccess(res); - - if (formData.assignees?.some((assignee) => assignee === user?.id)) mutate(USER_ISSUE(workspaceSlug as string)); - - if (formData.parent && formData.parent !== "") mutate(SUB_ISSUES(formData.parent)); - }) - .catch((err) => { - Object.keys(err || {}).forEach((key) => { - const error = err?.[key]; - const errorTitle = error ? (Array.isArray(error) ? error.join(", ") : error) : null; - - setToastAlert({ - type: "error", - title: "Error!", - message: errorTitle || "Some error occurred. Please try again.", - }); - }); - }); - }; - - return ( - <> - - -
- {children} -
-
-
- - ); -}; diff --git a/web/components/cycles/transfer-issues-modal.tsx b/web/components/cycles/transfer-issues-modal.tsx index 28964551b..5ce1a47fd 100644 --- a/web/components/cycles/transfer-issues-modal.tsx +++ b/web/components/cycles/transfer-issues-modal.tsx @@ -1,17 +1,16 @@ import React, { useState } from "react"; import { useRouter } from "next/router"; -import useSWR, { mutate } from "swr"; +import useSWR from "swr"; import { Dialog, Transition } from "@headlessui/react"; // services import { CycleService } from "services/cycle.service"; // hooks import useToast from "hooks/use-toast"; -import useIssuesView from "hooks/use-issues-view"; //icons import { ContrastIcon, TransferIcon } from "@plane/ui"; import { AlertCircle, Search, X } from "lucide-react"; // fetch-key -import { CYCLE_ISSUES_WITH_PARAMS, INCOMPLETE_CYCLES_LIST } from "constants/fetch-keys"; +import { INCOMPLETE_CYCLES_LIST } from "constants/fetch-keys"; // types import { ICycle } from "types"; //helper @@ -30,15 +29,12 @@ export const TransferIssuesModal: React.FC = ({ isOpen, handleClose }) => const router = useRouter(); const { workspaceSlug, projectId, cycleId } = router.query; - const { params } = useIssuesView(); - const { setToastAlert } = useToast(); const transferIssue = async (payload: any) => { await cycleService .transferIssues(workspaceSlug as string, projectId as string, cycleId as string, payload) .then(() => { - mutate(CYCLE_ISSUES_WITH_PARAMS(cycleId as string, params)); setToastAlert({ type: "success", title: "Issues transfered successfully", diff --git a/web/components/inbox/actions-header.tsx b/web/components/inbox/actions-header.tsx index a5e05edac..3c1fb758c 100644 --- a/web/components/inbox/actions-header.tsx +++ b/web/components/inbox/actions-header.tsx @@ -6,8 +6,6 @@ import { Popover } from "@headlessui/react"; // mobx store import { useMobxStore } from "lib/mobx/store-provider"; -// contexts -import { useProjectMyMembership } from "contexts/project-member.context"; // hooks import useToast from "hooks/use-toast"; // components @@ -38,9 +36,9 @@ export const InboxActionsHeader = observer(() => { const { inboxIssues: inboxIssuesStore, inboxIssueDetails: inboxIssueDetailsStore, user: userStore } = useMobxStore(); const user = userStore?.currentUser; + const userRole = userStore.currentProjectRole; const issuesList = inboxId ? inboxIssuesStore.inboxIssues[inboxId.toString()] : null; - const { memberRole } = useProjectMyMembership(); const { setToastAlert } = useToast(); const markInboxStatus = async (data: TInboxStatus) => { @@ -73,7 +71,7 @@ export const InboxActionsHeader = observer(() => { }, [issue]); const issueStatus = issue?.issue_inbox[0].status; - const isAllowed = memberRole.isMember || memberRole.isOwner; + const isAllowed = userRole === 15 || userRole === 20; const today = new Date(); const tomorrow = new Date(today); diff --git a/web/components/inbox/main-content.tsx b/web/components/inbox/main-content.tsx index a978dc7ce..02ead34cb 100644 --- a/web/components/inbox/main-content.tsx +++ b/web/components/inbox/main-content.tsx @@ -7,8 +7,6 @@ import { AlertTriangle, CheckCircle2, Clock, Copy, ExternalLink, Inbox, XCircle // mobx store import { useMobxStore } from "lib/mobx/store-provider"; -// contexts -import { useProjectMyMembership } from "contexts/project-member.context"; // components import { IssueDescriptionForm, IssueDetailsSidebar, IssueReaction } from "components/issues"; import { InboxIssueActivity } from "components/inbox"; @@ -35,8 +33,7 @@ export const InboxMainContent: React.FC = observer(() => { const { inboxIssues: inboxIssuesStore, inboxIssueDetails: inboxIssueDetailsStore, user: userStore } = useMobxStore(); const user = userStore.currentUser; - - const { memberRole } = useProjectMyMembership(); + const userRole = userStore.currentProjectRole; const { reset, control, watch } = useForm({ defaultValues, @@ -225,7 +222,7 @@ export const InboxMainContent: React.FC = observer(() => { description_html: issueDetails.description_html, }} handleFormSubmit={submitChanges} - isAllowed={memberRole.isMember || memberRole.isOwner || user?.id === issueDetails.created_by} + isAllowed={userRole === 15 || userRole === 20 || user?.id === issueDetails.created_by} />
diff --git a/web/components/inbox/modals/create-issue-modal.tsx b/web/components/inbox/modals/create-issue-modal.tsx index 8a4741bb3..a468580f4 100644 --- a/web/components/inbox/modals/create-issue-modal.tsx +++ b/web/components/inbox/modals/create-issue-modal.tsx @@ -3,7 +3,7 @@ import { useRouter } from "next/router"; import { observer } from "mobx-react-lite"; import { Dialog, Transition } from "@headlessui/react"; import { Controller, useForm } from "react-hook-form"; -import { IMentionHighlight, IMentionSuggestion, RichTextEditorWithRef } from "@plane/rich-text-editor"; +import { RichTextEditorWithRef } from "@plane/rich-text-editor"; // mobx store import { useMobxStore } from "lib/mobx/store-provider"; @@ -15,8 +15,6 @@ import { IssuePrioritySelect } from "components/issues/select"; import { Button, Input, ToggleSwitch } from "@plane/ui"; // types import { IIssue } from "types"; -import useProjectMembers from "hooks/use-project-members"; -import useUser from "hooks/use-user"; type Props = { isOpen: boolean; diff --git a/web/components/issues/delete-draft-issue-modal.tsx b/web/components/issues/delete-draft-issue-modal.tsx index 4a0b0fd9a..3b3efaea0 100644 --- a/web/components/issues/delete-draft-issue-modal.tsx +++ b/web/components/issues/delete-draft-issue-modal.tsx @@ -1,17 +1,12 @@ import React, { useEffect, useState } from "react"; - import { useRouter } from "next/router"; - -import { mutate } from "swr"; - -import useUser from "hooks/use-user"; - -// headless ui +import { observer } from "mobx-react-lite"; import { Dialog, Transition } from "@headlessui/react"; +// mobx store +import { useMobxStore } from "lib/mobx/store-provider"; // services import { IssueDraftService } from "services/issue"; // hooks -import useIssuesView from "hooks/use-issues-view"; import useToast from "hooks/use-toast"; // icons import { AlertTriangle } from "lucide-react"; @@ -19,8 +14,6 @@ import { AlertTriangle } from "lucide-react"; import { Button } from "@plane/ui"; // types import type { IIssue } from "types"; -// fetch-keys -import { PROJECT_DRAFT_ISSUES_LIST_WITH_PARAMS } from "constants/fetch-keys"; type Props = { isOpen: boolean; @@ -31,20 +24,19 @@ type Props = { const issueDraftService = new IssueDraftService(); -export const DeleteDraftIssueModal: React.FC = (props) => { +export const DeleteDraftIssueModal: React.FC = observer((props) => { const { isOpen, handleClose, data, onSubmit } = props; const [isDeleteLoading, setIsDeleteLoading] = useState(false); - const router = useRouter(); - const { workspaceSlug, projectId } = router.query; + const { user: userStore } = useMobxStore(); + const user = userStore.currentUser; - const { params } = useIssuesView(); + const router = useRouter(); + const { workspaceSlug } = router.query; const { setToastAlert } = useToast(); - const { user } = useUser(); - useEffect(() => { setIsDeleteLoading(false); }, [isOpen]); @@ -64,7 +56,7 @@ export const DeleteDraftIssueModal: React.FC = (props) => { .then(() => { setIsDeleteLoading(false); handleClose(); - mutate(PROJECT_DRAFT_ISSUES_LIST_WITH_PARAMS(projectId as string, params)); + setToastAlert({ title: "Success", message: "Draft Issue deleted successfully", @@ -146,4 +138,4 @@ export const DeleteDraftIssueModal: React.FC = (props) => { ); -}; +}); diff --git a/web/components/issues/draft-issue-modal.tsx b/web/components/issues/draft-issue-modal.tsx index 80aebcbbd..1987a4fd9 100644 --- a/web/components/issues/draft-issue-modal.tsx +++ b/web/components/issues/draft-issue-modal.tsx @@ -9,28 +9,14 @@ import { useMobxStore } from "lib/mobx/store-provider"; import { IssueService, IssueDraftService } from "services/issue"; import { ModuleService } from "services/module.service"; // hooks -import useUser from "hooks/use-user"; -import useIssuesView from "hooks/use-issues-view"; import useToast from "hooks/use-toast"; import useLocalStorage from "hooks/use-local-storage"; -import useMyIssues from "hooks/my-issues/use-my-issues"; // components import { DraftIssueForm } from "components/issues"; // types import type { IIssue } from "types"; // fetch-keys -import { - PROJECT_ISSUES_DETAILS, - USER_ISSUE, - SUB_ISSUES, - PROJECT_ISSUES_LIST_WITH_PARAMS, - CYCLE_ISSUES_WITH_PARAMS, - MODULE_ISSUES_WITH_PARAMS, - VIEW_ISSUES, - PROJECT_DRAFT_ISSUES_LIST_WITH_PARAMS, - CYCLE_DETAILS, - MODULE_DETAILS, -} from "constants/fetch-keys"; +import { PROJECT_ISSUES_DETAILS, USER_ISSUE, SUB_ISSUES } from "constants/fetch-keys"; interface IssuesModalProps { data?: IIssue | null; @@ -77,21 +63,15 @@ export const CreateUpdateDraftIssueModal: React.FC = observer( const [prePopulateData, setPreloadedData] = useState | undefined>(undefined); const router = useRouter(); - const { workspaceSlug, projectId, cycleId, moduleId, viewId } = router.query; + const { workspaceSlug, projectId, cycleId, moduleId } = router.query; - const { project: projectStore } = useMobxStore(); + const { project: projectStore, user: userStore } = useMobxStore(); + const user = userStore.currentUser; const projects = workspaceSlug ? projectStore.projects[workspaceSlug.toString()] : undefined; - const { displayFilters, params } = useIssuesView(); - const { ...viewGanttParams } = params; - - const { user } = useUser(); - const { clearValue: clearDraftIssueLocalStorage } = useLocalStorage("draftedIssue", {}); - const { groupedIssues, mutateMyIssues } = useMyIssues(workspaceSlug?.toString()); - const { setToastAlert } = useToast(); const onClose = () => { @@ -184,31 +164,19 @@ export const CreateUpdateDraftIssueModal: React.FC = observer( setActiveProject(projects?.find((p) => p.id === projectId)?.id ?? projects?.[0].id ?? null); }, [activeProject, data, projectId, projects, isOpen, prePopulateData]); - const ganttFetchKey = cycleId - ? CYCLE_ISSUES_WITH_PARAMS(cycleId.toString()) - : moduleId - ? MODULE_ISSUES_WITH_PARAMS(moduleId.toString()) - : viewId - ? VIEW_ISSUES(viewId.toString(), viewGanttParams) - : PROJECT_ISSUES_LIST_WITH_PARAMS(activeProject?.toString() ?? ""); - const createDraftIssue = async (payload: Partial) => { if (!workspaceSlug || !activeProject || !user) return; await issueDraftService .createDraftIssue(workspaceSlug as string, activeProject ?? "", payload) .then(async () => { - mutate(PROJECT_DRAFT_ISSUES_LIST_WITH_PARAMS(activeProject ?? "", params)); - - if (groupedIssues) mutateMyIssues(); - setToastAlert({ type: "success", title: "Success!", message: "Issue created successfully.", }); - if (payload.assignees?.some((assignee) => assignee === user?.id)) mutate(USER_ISSUE(workspaceSlug as string)); + if (payload.assignees?.some((assignee) => assignee === user?.id)) mutate(USER_ISSUE(workspaceSlug.toString())); }) .catch(() => { setToastAlert({ @@ -231,8 +199,6 @@ export const CreateUpdateDraftIssueModal: React.FC = observer( mutate(PROJECT_ISSUES_DETAILS, (prevData) => ({ ...prevData, ...res }), false); } else { if (payload.parent) mutate(SUB_ISSUES(payload.parent.toString())); - mutate(PROJECT_ISSUES_LIST_WITH_PARAMS(activeProject ?? "", params)); - mutate(PROJECT_DRAFT_ISSUES_LIST_WITH_PARAMS(activeProject ?? "", params)); } if (!payload.is_draft) { @@ -258,64 +224,42 @@ export const CreateUpdateDraftIssueModal: React.FC = observer( }; const addIssueToCycle = async (issueId: string, cycleId: string) => { - if (!workspaceSlug || !activeProject) return; + if (!workspaceSlug || !activeProject || !user) return; - await issueService - .addIssueToCycle( - workspaceSlug as string, - activeProject ?? "", - cycleId, - { - issues: [issueId], - }, - user - ) - .then(() => { - if (cycleId) { - mutate(CYCLE_ISSUES_WITH_PARAMS(cycleId, params)); - mutate(CYCLE_DETAILS(cycleId as string)); - } - }); + await issueService.addIssueToCycle( + workspaceSlug as string, + activeProject ?? "", + cycleId, + { + issues: [issueId], + }, + user + ); }; const addIssueToModule = async (issueId: string, moduleId: string) => { - if (!workspaceSlug || !activeProject) return; + if (!workspaceSlug || !activeProject || !user) return; - await moduleService - .addIssuesToModule( - workspaceSlug as string, - activeProject ?? "", - moduleId as string, - { - issues: [issueId], - }, - user - ) - .then(() => { - if (moduleId) { - mutate(MODULE_ISSUES_WITH_PARAMS(moduleId as string, params)); - mutate(MODULE_DETAILS(moduleId as string)); - } - }); + await moduleService.addIssuesToModule( + workspaceSlug as string, + activeProject ?? "", + moduleId as string, + { + issues: [issueId], + }, + user + ); }; const createIssue = async (payload: Partial) => { - if (!workspaceSlug || !activeProject) return; + if (!workspaceSlug || !activeProject || !user) return; await issueService - .createIssue(workspaceSlug as string, activeProject ?? "", payload, user) + .createIssue(workspaceSlug.toString(), 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); if (payload.module && payload.module !== "") await addIssueToModule(res.id, payload.module); - if (displayFilters.layout === "gantt_chart") - mutate(ganttFetchKey, { - start_target_date: true, - order_by: "sort_order", - }); - if (groupedIssues) mutateMyIssues(); - setToastAlert({ type: "success", title: "Success!", @@ -400,7 +344,7 @@ export const CreateUpdateDraftIssueModal: React.FC = observer( projectId={activeProject ?? ""} setActiveProject={setActiveProject} status={data ? true : false} - user={user} + user={user ?? undefined} fieldsToShow={fieldsToShow} /> diff --git a/web/components/issues/issue-peek-overview/properties.tsx b/web/components/issues/issue-peek-overview/properties.tsx index b336beeec..d1d609f7b 100644 --- a/web/components/issues/issue-peek-overview/properties.tsx +++ b/web/components/issues/issue-peek-overview/properties.tsx @@ -1,7 +1,9 @@ import { FC, useState } from "react"; import { mutate } from "swr"; import { useRouter } from "next/router"; - +import { observer } from "mobx-react-lite"; +// mobx store +import { useMobxStore } from "lib/mobx/store-provider"; // ui icons import { DiceIcon, DoubleCircleIcon, UserGroupIcon } from "@plane/ui"; import { CalendarDays, ContrastIcon, Link2, Plus, Signal, Tag, Triangle, User2 } from "lucide-react"; @@ -23,10 +25,7 @@ import { CustomDatePicker } from "components/ui"; import { LinkModal, LinksList } from "components/core"; // types import { ICycle, IIssue, IIssueLink, IModule, TIssuePriorities, linkDetails } from "types"; -// contexts -import { useProjectMyMembership } from "contexts/project-member.context"; import { ISSUE_DETAILS } from "constants/fetch-keys"; - // services import { IssueService } from "services/issue"; @@ -38,18 +37,19 @@ interface IPeekOverviewProperties { const issueService = new IssueService(); -export const PeekOverviewProperties: FC = (props) => { +export const PeekOverviewProperties: FC = observer((props) => { const { issue, issueUpdate, user } = props; const [linkModal, setLinkModal] = useState(false); const [selectedLinkToUpdate, setSelectedLinkToUpdate] = useState(null); + const { user: userStore } = useMobxStore(); + const userRole = userStore.currentProjectRole; + const router = useRouter(); const { workspaceSlug, projectId } = router.query; const { setToastAlert } = useToast(); - const { memberRole } = useProjectMyMembership(); - const handleState = (_state: string) => { issueUpdate({ ...issue, state: _state }); }; @@ -346,7 +346,12 @@ export const PeekOverviewProperties: FC = (props) => { links={issue.issue_link} handleDeleteLink={handleDeleteLink} handleEditLink={handleEditLink} - userAuth={memberRole} + userAuth={{ + isGuest: userRole === 5, + isViewer: userRole === 10, + isMember: userRole === 15, + isOwner: userRole === 20, + }} /> ) : null}
@@ -355,4 +360,4 @@ export const PeekOverviewProperties: FC = (props) => {
); -}; +}); diff --git a/web/components/issues/main-content.tsx b/web/components/issues/main-content.tsx index 6f228a8a0..ce1c820f5 100644 --- a/web/components/issues/main-content.tsx +++ b/web/components/issues/main-content.tsx @@ -1,16 +1,13 @@ import Link from "next/link"; import { useRouter } from "next/router"; - +import { observer } from "mobx-react-lite"; import useSWR, { mutate } from "swr"; - +// mobx store +import { useMobxStore } from "lib/mobx/store-provider"; // services import { IssueService, IssueCommentService } from "services/issue"; // hooks -import useUserAuth from "hooks/use-user-auth"; import useToast from "hooks/use-toast"; -import useProjectDetails from "hooks/use-project-details"; -// contexts -import { useProjectMyMembership } from "contexts/project-member.context"; // components import { AddComment, @@ -40,16 +37,18 @@ type Props = { const issueService = new IssueService(); const issueCommentService = new IssueCommentService(); -export const IssueMainContent: React.FC = ({ issueDetails, submitChanges, uneditable = false }) => { +export const IssueMainContent: React.FC = observer((props) => { + const { issueDetails, submitChanges, uneditable = false } = props; + const router = useRouter(); const { workspaceSlug, projectId, issueId } = router.query; const { setToastAlert } = useToast(); - const { user } = useUserAuth(); - const { memberRole } = useProjectMyMembership(); - - const { projectDetails } = useProjectDetails(); + const { user: userStore, project: projectStore } = useMobxStore(); + const user = userStore.currentUser ?? undefined; + const userRole = userStore.currentProjectRole; + const projectDetails = projectId ? projectStore.project_details[projectId.toString()] : undefined; const { data: siblingIssues } = useSWR( workspaceSlug && projectId && issueDetails?.parent ? SUB_ISSUES(issueDetails.parent) : null, @@ -75,7 +74,7 @@ export const IssueMainContent: React.FC = ({ issueDetails, submitChanges, }; const handleCommentDelete = async (commentId: string) => { - if (!workspaceSlug || !projectId || !issueId) return; + if (!workspaceSlug || !projectId || !issueId || !user) return; mutateIssueActivity((prevData: any) => prevData?.filter((p: any) => p.id !== commentId), false); @@ -85,7 +84,7 @@ export const IssueMainContent: React.FC = ({ issueDetails, submitChanges, }; const handleAddComment = async (formData: IIssueComment) => { - if (!workspaceSlug || !issueDetails) return; + if (!workspaceSlug || !issueDetails || !user) return; await issueCommentService .createIssueComment(workspaceSlug.toString(), issueDetails.project, issueDetails.id, formData, user) @@ -167,7 +166,7 @@ export const IssueMainContent: React.FC = ({ issueDetails, submitChanges, workspaceSlug={workspaceSlug as string} issue={issueDetails} handleFormSubmit={submitChanges} - isAllowed={memberRole.isMember || memberRole.isOwner || !uneditable} + isAllowed={userRole === 20 || userRole === 15 || !uneditable} /> @@ -199,4 +198,4 @@ export const IssueMainContent: React.FC = ({ issueDetails, submitChanges,
); -}; +}); diff --git a/web/components/issues/sidebar.tsx b/web/components/issues/sidebar.tsx index e8c4d2431..5ce7ff59a 100644 --- a/web/components/issues/sidebar.tsx +++ b/web/components/issues/sidebar.tsx @@ -1,17 +1,17 @@ import React, { useCallback, useState } from "react"; import { useRouter } from "next/router"; +import { observer } from "mobx-react-lite"; import { mutate } from "swr"; import { Controller, UseFormWatch } from "react-hook-form"; +// mobx store +import { useMobxStore } from "lib/mobx/store-provider"; // hooks import useToast from "hooks/use-toast"; -import useUserAuth from "hooks/use-user-auth"; import useUserIssueNotificationSubscription from "hooks/use-issue-notification-subscription"; import useEstimateOption from "hooks/use-estimate-option"; // services import { IssueService } from "services/issue"; import { ModuleService } from "services/module.service"; -// contexts -import { useProjectMyMembership } from "contexts/project-member.context"; // components import { LinkModal, LinksList } from "components/core"; import { @@ -72,23 +72,20 @@ type Props = { const issueService = new IssueService(); const moduleService = new ModuleService(); -export const IssueDetailsSidebar: React.FC = ({ - control, - submitChanges, - issueDetail, - watch: watchIssue, - fieldsToShow = ["all"], - uneditable = false, -}) => { +export const IssueDetailsSidebar: React.FC = observer((props) => { + const { control, submitChanges, issueDetail, watch: watchIssue, fieldsToShow = ["all"], uneditable = false } = props; + const [deleteIssueModal, setDeleteIssueModal] = useState(false); const [linkModal, setLinkModal] = useState(false); const [selectedLinkToUpdate, setSelectedLinkToUpdate] = useState(null); + const { user: userStore } = useMobxStore(); + const user = userStore.currentUser; + const userRole = userStore.currentProjectRole; + const router = useRouter(); const { workspaceSlug, projectId, issueId } = router.query; - const { user } = useUserAuth(); - const { isEstimateActive } = useEstimateOption(); const { loading, handleSubscribe, handleUnsubscribe, subscribed } = useUserIssueNotificationSubscription( @@ -97,13 +94,11 @@ export const IssueDetailsSidebar: React.FC = ({ issueId ); - const { memberRole } = useProjectMyMembership(); - const { setToastAlert } = useToast(); const handleCycleChange = useCallback( (cycleDetails: ICycle) => { - if (!workspaceSlug || !projectId || !issueDetail) return; + if (!workspaceSlug || !projectId || !issueDetail || !user) return; issueService .addIssueToCycle( @@ -124,7 +119,7 @@ export const IssueDetailsSidebar: React.FC = ({ const handleModuleChange = useCallback( (moduleDetail: IModule) => { - if (!workspaceSlug || !projectId || !issueDetail) return; + if (!workspaceSlug || !projectId || !issueDetail || !user) return; moduleService .addIssuesToModule( @@ -262,7 +257,7 @@ export const IssueDetailsSidebar: React.FC = ({ setLinkModal(true); }; - const isNotAllowed = memberRole.isGuest || memberRole.isViewer; + const isNotAllowed = userRole === 5 || userRole === 10; return ( <> @@ -341,7 +336,7 @@ export const IssueDetailsSidebar: React.FC = ({ submitChanges({ state: val })} - disabled={memberRole.isGuest || memberRole.isViewer || uneditable} + disabled={isNotAllowed || uneditable} /> )} /> @@ -362,7 +357,7 @@ export const IssueDetailsSidebar: React.FC = ({ submitChanges({ assignees: val })} - disabled={memberRole.isGuest || memberRole.isViewer || uneditable} + disabled={isNotAllowed || uneditable} /> )} /> @@ -383,7 +378,7 @@ export const IssueDetailsSidebar: React.FC = ({ submitChanges({ priority: val })} - disabled={memberRole.isGuest || memberRole.isViewer || uneditable} + disabled={isNotAllowed || uneditable} /> )} /> @@ -404,7 +399,7 @@ export const IssueDetailsSidebar: React.FC = ({ submitChanges({ estimate_point: val })} - disabled={memberRole.isGuest || memberRole.isViewer || uneditable} + disabled={isNotAllowed || uneditable} /> )} /> @@ -432,7 +427,7 @@ export const IssueDetailsSidebar: React.FC = ({ onChange(val); }} issueDetails={issueDetail} - disabled={memberRole.isGuest || memberRole.isViewer || uneditable} + disabled={isNotAllowed || uneditable} /> )} /> @@ -457,7 +452,7 @@ export const IssueDetailsSidebar: React.FC = ({ mutate(PROJECT_ISSUES_ACTIVITY(issueId as string)); }} watch={watchIssue} - disabled={memberRole.isGuest || memberRole.isViewer || uneditable} + disabled={isNotAllowed || uneditable} /> )} {(fieldsToShow.includes("all") || fieldsToShow.includes("blocked")) && ( @@ -478,7 +473,7 @@ export const IssueDetailsSidebar: React.FC = ({ mutate(PROJECT_ISSUES_ACTIVITY(issueId as string)); }} watch={watchIssue} - disabled={memberRole.isGuest || memberRole.isViewer || uneditable} + disabled={isNotAllowed || uneditable} /> )} {(fieldsToShow.includes("all") || fieldsToShow.includes("duplicate")) && ( @@ -496,7 +491,7 @@ export const IssueDetailsSidebar: React.FC = ({ mutate(PROJECT_ISSUES_ACTIVITY(issueId as string)); }} watch={watchIssue} - disabled={memberRole.isGuest || memberRole.isViewer || uneditable} + disabled={isNotAllowed || uneditable} /> )} {(fieldsToShow.includes("all") || fieldsToShow.includes("relates_to")) && ( @@ -514,7 +509,7 @@ export const IssueDetailsSidebar: React.FC = ({ mutate(PROJECT_ISSUES_ACTIVITY(issueId as string)); }} watch={watchIssue} - disabled={memberRole.isGuest || memberRole.isViewer || uneditable} + disabled={isNotAllowed || uneditable} /> )} {(fieldsToShow.includes("all") || fieldsToShow.includes("startDate")) && ( @@ -587,7 +582,7 @@ export const IssueDetailsSidebar: React.FC = ({ @@ -602,7 +597,7 @@ export const IssueDetailsSidebar: React.FC = ({ @@ -650,7 +645,12 @@ export const IssueDetailsSidebar: React.FC = ({ links={issueDetail.issue_link} handleDeleteLink={handleDeleteLink} handleEditLink={handleEditLink} - userAuth={memberRole} + userAuth={{ + isGuest: userRole === 5, + isViewer: userRole === 10, + isMember: userRole === 15, + isOwner: userRole === 20, + }} /> ) : null} @@ -660,4 +660,4 @@ export const IssueDetailsSidebar: React.FC = ({ ); -}; +}); diff --git a/web/components/issues/sub-issues/root.tsx b/web/components/issues/sub-issues/root.tsx index 88dab132c..3e8a345f8 100644 --- a/web/components/issues/sub-issues/root.tsx +++ b/web/components/issues/sub-issues/root.tsx @@ -1,10 +1,10 @@ import React, { useCallback } from "react"; -// next imports import { useRouter } from "next/router"; -// swr +import { observer } from "mobx-react-lite"; import useSWR, { mutate } from "swr"; -// lucide icons import { Plus, ChevronRight, ChevronDown } from "lucide-react"; +// mobx store +import { useMobxStore } from "lib/mobx/store-provider"; // components import { ExistingIssuesListModal } from "components/core"; import { CreateUpdateIssueModal, DeleteIssueModal } from "components/issues"; @@ -13,8 +13,6 @@ import { ProgressBar } from "./progressbar"; // ui import { CustomMenu } from "@plane/ui"; // hooks -import { useMobxStore } from "lib/mobx/store-provider"; -import { useProjectMyMembership } from "contexts/project-member.context"; import useToast from "hooks/use-toast"; // helpers import { copyTextToClipboard } from "helpers/string.helper"; @@ -42,23 +40,21 @@ export interface ISubIssuesRootLoadersHandler { const issueService = new IssueService(); -export const SubIssuesRoot: React.FC = ({ parentIssue, user }) => { +export const SubIssuesRoot: React.FC = observer((props) => { + const { parentIssue, user } = props; + + const { user: userStore, issue: issueStore, issueDetail: issueDetailStore } = useMobxStore(); + const userRole = userStore.currentProjectRole; + const router = useRouter(); - const { workspaceSlug, projectId } = router.query as { - workspaceSlug: string; - projectId: string; - peekIssue: string; - }; + const { workspaceSlug, projectId } = router.query; - const { issue: issueStore, issueDetail: issueDetailStore } = useMobxStore(); - - const { memberRole } = useProjectMyMembership(); const { setToastAlert } = useToast(); const { data: issues, isLoading } = useSWR( workspaceSlug && projectId && parentIssue && parentIssue?.id ? SUB_ISSUES(parentIssue?.id) : null, workspaceSlug && projectId && parentIssue && parentIssue?.id - ? () => issueService.subIssues(workspaceSlug, projectId, parentIssue.id) + ? () => issueService.subIssues(workspaceSlug.toString(), projectId.toString(), parentIssue.id) : null ); @@ -117,20 +113,20 @@ export const SubIssuesRoot: React.FC = ({ parentIssue, user }) = }; const addAsSubIssueFromExistingIssues = async (data: ISearchIssueResponse[]) => { - if (!workspaceSlug || !parentIssue || issueCrudOperation?.existing?.issueId === null) return; + if (!workspaceSlug || !projectId || !parentIssue || issueCrudOperation?.existing?.issueId === null) return; const issueId = issueCrudOperation?.existing?.issueId; const payload = { sub_issue_ids: data.map((i) => i.id), }; - await issueService.addSubIssues(workspaceSlug, projectId, issueId, payload).finally(() => { + await issueService.addSubIssues(workspaceSlug.toString(), projectId.toString(), issueId, payload).finally(() => { if (issueId) mutate(SUB_ISSUES(issueId)); }); }; const removeIssueFromSubIssues = async (parentIssueId: string, issue: IIssue) => { - if (!workspaceSlug || !parentIssue || !issue?.id) return; + if (!workspaceSlug || !projectId || !parentIssue || !issue?.id) return; issueService - .patchIssue(workspaceSlug, projectId, issue.id, { parent: null }, user) + .patchIssue(workspaceSlug.toString(), projectId.toString(), issue.id, { parent: null }, user) .then(async () => { if (parentIssueId) await mutate(SUB_ISSUES(parentIssueId)); handleIssuesLoader({ key: "delete", issueId: issue?.id }); @@ -176,7 +172,7 @@ export const SubIssuesRoot: React.FC = ({ parentIssue, user }) = [issueStore, issueDetailStore, projectId, user, workspaceSlug] ); - const isEditable = memberRole?.isGuest || memberRole?.isViewer ? false : true; + const isEditable = userRole === 5 || userRole === 10 ? false : true; const mutateSubIssues = (parentIssueId: string | null) => { if (parentIssueId) mutate(SUB_ISSUES(parentIssueId)); @@ -233,11 +229,11 @@ export const SubIssuesRoot: React.FC = ({ parentIssue, user }) = {/* issues */} - {issuesLoader.visibility.includes(parentIssue?.id) && ( + {issuesLoader.visibility.includes(parentIssue?.id) && workspaceSlug && projectId && (
= ({ parentIssue, user }) = )}
); -}; +}); diff --git a/web/components/modules/sidebar.tsx b/web/components/modules/sidebar.tsx index 67f55898a..320896845 100644 --- a/web/components/modules/sidebar.tsx +++ b/web/components/modules/sidebar.tsx @@ -8,8 +8,6 @@ import { Disclosure, Transition } from "@headlessui/react"; import { useMobxStore } from "lib/mobx/store-provider"; // services import { ModuleService } from "services/module.service"; -// contexts -import { useProjectMyMembership } from "contexts/project-member.context"; // hooks import useToast from "hooks/use-toast"; // components @@ -60,10 +58,9 @@ export const ModuleDetailsSidebar: React.FC = observer((props) => { const { module: moduleStore, user: userStore } = useMobxStore(); const user = userStore.currentUser ?? undefined; + const userRole = userStore.currentProjectRole; const moduleDetails = moduleStore.moduleDetails[moduleId] ?? undefined; - const { memberRole } = useProjectMyMembership(); - const { setToastAlert } = useToast(); const { reset, control } = useForm({ @@ -429,7 +426,7 @@ export const ModuleDetailsSidebar: React.FC = observer((props) => {
- {memberRole && moduleDetails.link_module && moduleDetails.link_module.length > 0 ? ( + {userRole && moduleDetails.link_module && moduleDetails.link_module.length > 0 ? ( <>