From 76cc634a46c4a564700527f2d6567260701f82b4 Mon Sep 17 00:00:00 2001 From: Aaryan Khandelwal <65252264+aaryan610@users.noreply.github.com> Date: Wed, 8 Feb 2023 10:13:07 +0530 Subject: [PATCH] feat: cycles and modules toggle in settings, refactor: folder structure (#247) * feat: link option in remirror * fix: removed link import from remirror toolbar * refactor: constants folder * refactor: layouts folder structure * fix: issue view context * feat: cycles and modules toggle in settings --- .../components/core/board-view/all-boards.tsx | 70 ++-- .../core/board-view/board-header.tsx | 16 +- .../core/board-view/single-board.tsx | 160 ++++---- .../core/board-view/single-issue.tsx | 52 +-- .../components/core/issues-view-filter.tsx | 14 +- apps/app/components/core/issues-view.tsx | 376 ++++++++---------- .../core/list-view/single-issue.tsx | 42 +- .../components/core/list-view/single-list.tsx | 1 - apps/app/components/core/select/due-date.tsx | 48 --- apps/app/components/core/select/priority.tsx | 97 ----- apps/app/components/core/select/state.tsx | 55 --- .../components/emoji-icon-picker/index.tsx | 2 +- .../icons/priority-icon.tsx} | 0 apps/app/components/issues/activity.tsx | 21 +- .../components/issues/comment/add-comment.tsx | 2 +- .../components/issues/my-issues-list-item.tsx | 25 +- apps/app/components/issues/select/label.tsx | 2 +- .../app/components/issues/select/priority.tsx | 5 +- .../issues/sidebar-select/priority.tsx | 11 +- apps/app/components/issues/sidebar.tsx | 12 +- .../view-select}/assignee.tsx | 88 ++-- .../issues/view-select/due-date.tsx | 36 ++ .../select => issues/view-select}/index.ts | 0 .../issues/view-select/priority.tsx | 88 ++++ .../components/issues/view-select/state.tsx | 75 ++++ .../modules/select/select-status.tsx | 2 +- .../modules/sidebar-select/select-status.tsx | 2 +- .../components/modules/single-module-card.tsx | 2 +- apps/app/components/onboarding/workspace.tsx | 6 +- .../project/create-project-modal.tsx | 4 +- .../project/send-project-invitation-modal.tsx | 10 +- .../project/settings/single-label.tsx | 10 +- apps/app/components/project/sidebar-list.tsx | 47 ++- .../app/components/rich-text-editor/index.tsx | 2 +- .../states/create-update-state-inline.tsx | 4 +- .../states/create-update-state-modal.tsx | 2 +- .../send-workspace-invitation-modal.tsx | 9 +- apps/app/constants/index.ts | 69 ---- apps/app/constants/issue.ts | 36 ++ apps/app/constants/module.ts | 8 + apps/app/constants/project.ts | 11 + apps/app/constants/workspace.ts | 13 + .../{functions.helper.ts => common.helper.ts} | 0 apps/app/hooks/use-issue-properties.tsx | 1 + apps/app/hooks/use-issue-view.tsx | 73 ++-- apps/app/hooks/use-my-issues-filter.tsx | 2 +- apps/app/layouts/app-layout/index.tsx | 172 ++++++-- apps/app/layouts/container.tsx | 20 +- apps/app/layouts/default-layout.tsx | 14 - apps/app/layouts/default-layout/index.tsx | 30 ++ apps/app/layouts/navbar/header.tsx | 37 -- apps/app/layouts/navbar/main-sidebar.tsx | 188 --------- apps/app/layouts/settings-layout.tsx | 177 --------- .../settings-sidebar.tsx | 1 - apps/app/layouts/types.d.ts | 17 - apps/app/pages/[workspaceSlug]/index.tsx | 28 +- .../projects/[projectId]/settings/control.tsx | 8 +- .../[projectId]/settings/features.tsx | 187 +++++++++ .../projects/[projectId]/settings/index.tsx | 25 +- .../projects/[projectId]/settings/labels.tsx | 56 +-- .../projects/[projectId]/settings/members.tsx | 34 +- .../projects/[projectId]/settings/states.tsx | 20 +- .../[workspaceSlug]/settings/billing.tsx | 16 +- .../[workspaceSlug]/settings/features.tsx | 173 -------- .../pages/[workspaceSlug]/settings/index.tsx | 16 +- .../[workspaceSlug]/settings/members.tsx | 22 +- apps/app/pages/create-workspace.tsx | 4 +- apps/app/pages/error.tsx | 26 +- apps/app/pages/magic-sign-in/index.tsx | 9 +- apps/app/pages/onboarding/index.tsx | 11 +- .../[invitationId].tsx | 3 +- apps/app/types/issues.d.ts | 2 +- apps/app/types/projects.d.ts | 24 +- 73 files changed, 1283 insertions(+), 1648 deletions(-) delete mode 100644 apps/app/components/core/select/due-date.tsx delete mode 100644 apps/app/components/core/select/priority.tsx delete mode 100644 apps/app/components/core/select/state.tsx rename apps/app/{constants/global.tsx => components/icons/priority-icon.tsx} (100%) rename apps/app/components/{core/select => issues/view-select}/assignee.tsx (50%) create mode 100644 apps/app/components/issues/view-select/due-date.tsx rename apps/app/components/{core/select => issues/view-select}/index.ts (100%) create mode 100644 apps/app/components/issues/view-select/priority.tsx create mode 100644 apps/app/components/issues/view-select/state.tsx delete mode 100644 apps/app/constants/index.ts create mode 100644 apps/app/constants/issue.ts create mode 100644 apps/app/constants/module.ts create mode 100644 apps/app/constants/project.ts create mode 100644 apps/app/constants/workspace.ts rename apps/app/helpers/{functions.helper.ts => common.helper.ts} (100%) delete mode 100644 apps/app/layouts/default-layout.tsx create mode 100644 apps/app/layouts/default-layout/index.tsx delete mode 100644 apps/app/layouts/navbar/header.tsx delete mode 100644 apps/app/layouts/navbar/main-sidebar.tsx delete mode 100644 apps/app/layouts/settings-layout.tsx rename apps/app/layouts/{navbar => settings-layout}/settings-sidebar.tsx (94%) delete mode 100644 apps/app/layouts/types.d.ts create mode 100644 apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/features.tsx delete mode 100644 apps/app/pages/[workspaceSlug]/settings/features.tsx diff --git a/apps/app/components/core/board-view/all-boards.tsx b/apps/app/components/core/board-view/all-boards.tsx index a6d99fa0f..77c36e548 100644 --- a/apps/app/components/core/board-view/all-boards.tsx +++ b/apps/app/components/core/board-view/all-boards.tsx @@ -39,48 +39,38 @@ export const AllBoards: React.FC = ({
- - {(provided) => ( -
-
- {Object.keys(groupedByIssues).map((singleGroup, index) => { - const stateId = - selectedGroup === "state_detail.name" - ? states?.find((s) => s.name === singleGroup)?.id ?? null - : null; +
+
+ {Object.keys(groupedByIssues).map((singleGroup, index) => { + const stateId = + selectedGroup === "state_detail.name" + ? states?.find((s) => s.name === singleGroup)?.id ?? null + : null; - const bgColor = - selectedGroup === "state_detail.name" - ? states?.find((s) => s.name === singleGroup)?.color - : "#000000"; + const bgColor = + selectedGroup === "state_detail.name" + ? states?.find((s) => s.name === singleGroup)?.color + : "#000000"; - return ( - addIssueToState(singleGroup, stateId)} - handleDeleteIssue={handleDeleteIssue} - openIssuesListModal={openIssuesListModal ?? null} - orderBy={orderBy} - userAuth={userAuth} - /> - ); - })} -
- {provided.placeholder} -
- )} - + return ( + addIssueToState(singleGroup, stateId)} + handleDeleteIssue={handleDeleteIssue} + openIssuesListModal={openIssuesListModal ?? null} + orderBy={orderBy} + userAuth={userAuth} + /> + ); + })} +
+
diff --git a/apps/app/components/core/board-view/board-header.tsx b/apps/app/components/core/board-view/board-header.tsx index ba4d2c02a..3a7753366 100644 --- a/apps/app/components/core/board-view/board-header.tsx +++ b/apps/app/components/core/board-view/board-header.tsx @@ -12,15 +12,13 @@ import { // helpers import { addSpaceIfCamelCase } from "helpers/string.helper"; // types -import { IIssue, NestedKeyOf } from "types"; +import { IIssue } from "types"; type Props = { - provided: DraggableProvided; isCollapsed: boolean; setIsCollapsed: React.Dispatch>; groupedByIssues: { [key: string]: IIssue[]; }; - selectedGroup: NestedKeyOf | null; groupTitle: string; createdBy: string | null; bgColor?: string; @@ -30,9 +28,7 @@ type Props = { export const BoardHeader: React.FC = ({ isCollapsed, setIsCollapsed, - provided, groupedByIssues, - selectedGroup, groupTitle, createdBy, bgColor, @@ -44,16 +40,6 @@ export const BoardHeader: React.FC = ({ }`} >
-
= ({ - index, type, bgColor, groupTitle, @@ -70,95 +68,79 @@ export const SingleBoard: React.FC = ({ : (bgColor = "#ff0000"); return ( - - {(provided, snapshot) => ( -
-
- - - {(provided, snapshot) => ( -
+
+ + + {(provided, snapshot) => ( +
+ {groupedByIssues[groupTitle].map((issue, index: number) => ( + + ))} + + {provided.placeholder} + + {type === "issue" ? ( + - ) : ( - - - Add issue - - } - className="mt-1" - optionsPosition="left" - noBorder - > - - Create new - - {openIssuesListModal && ( - - Add an existing issue - - )} - + + Create + + ) : ( + + + Add issue + + } + className="mt-1" + optionsPosition="left" + noBorder + > + Create new + {openIssuesListModal && ( + + Add an existing issue + )} -
+ )} -
-
-
- )} - +
+ )} + +
+
); }; diff --git a/apps/app/components/core/board-view/single-issue.tsx b/apps/app/components/core/board-view/single-issue.tsx index 4f7ae0591..59786ea7c 100644 --- a/apps/app/components/core/board-view/single-issue.tsx +++ b/apps/app/components/core/board-view/single-issue.tsx @@ -16,14 +16,17 @@ import { import { TrashIcon } from "@heroicons/react/24/outline"; // services import issuesService from "services/issues.service"; -import stateService from "services/state.service"; // components -import { AssigneeSelect, DueDateSelect, PrioritySelect, StateSelect } from "components/core/select"; +import { + ViewAssigneeSelect, + ViewDueDateSelect, + ViewPrioritySelect, + ViewStateSelect, +} from "components/issues/view-select"; // types import { CycleIssueResponse, IIssue, - IProjectMember, IssueResponse, ModuleIssueResponse, NestedKeyOf, @@ -31,14 +34,14 @@ import { UserAuth, } from "types"; // fetch-keys -import { STATE_LIST, CYCLE_ISSUES, MODULE_ISSUES, PROJECT_ISSUES_LIST } from "constants/fetch-keys"; +import { CYCLE_ISSUES, MODULE_ISSUES, PROJECT_ISSUES_LIST } from "constants/fetch-keys"; type Props = { index: number; type?: string; issue: IIssue; + selectedGroup: NestedKeyOf | null; properties: Properties; - members: IProjectMember[] | undefined; handleDeleteIssue: (issue: IIssue) => void; orderBy: NestedKeyOf | "manual" | null; userAuth: UserAuth; @@ -48,8 +51,8 @@ export const SingleBoardIssue: React.FC = ({ index, type, issue, + selectedGroup, properties, - members, handleDeleteIssue, orderBy, userAuth, @@ -57,13 +60,6 @@ export const SingleBoardIssue: React.FC = ({ const router = useRouter(); const { workspaceSlug, projectId, cycleId, moduleId } = router.query; - const { data: states } = useSWR( - workspaceSlug && projectId ? STATE_LIST(projectId as string) : null, - workspaceSlug && projectId - ? () => stateService.getStates(workspaceSlug as string, projectId as string) - : null - ); - const partialUpdateIssue = useCallback( (formData: Partial) => { if (!workspaceSlug || !projectId) return; @@ -125,16 +121,8 @@ export const SingleBoardIssue: React.FC = ({ issuesService .patchIssue(workspaceSlug as string, projectId as string, issue.id, formData) .then((res) => { - mutate( - cycleId - ? CYCLE_ISSUES(cycleId as string) - : CYCLE_ISSUES(issue?.issue_cycle?.cycle ?? "") - ); - mutate( - moduleId - ? MODULE_ISSUES(moduleId as string) - : MODULE_ISSUES(issue?.issue_module?.module ?? "") - ); + if (cycleId) mutate(CYCLE_ISSUES(cycleId as string)); + if (moduleId) mutate(MODULE_ISSUES(moduleId as string)); mutate(PROJECT_ISSUES_LIST(workspaceSlug as string, projectId as string)); }) @@ -164,7 +152,12 @@ export const SingleBoardIssue: React.FC = ({ const isNotAllowed = userAuth.isGuest || userAuth.isViewer; return ( - + {(provided, snapshot) => (
= ({
{properties.priority && ( - )} {properties.state && ( - )} {properties.due_date && ( - = ({
)} {properties.assignee && ( - diff --git a/apps/app/components/core/issues-view-filter.tsx b/apps/app/components/core/issues-view-filter.tsx index 3920d0e91..7225f5148 100644 --- a/apps/app/components/core/issues-view-filter.tsx +++ b/apps/app/components/core/issues-view-filter.tsx @@ -17,7 +17,7 @@ import { replaceUnderscoreIfSnakeCase } from "helpers/string.helper"; // types import { IIssue, Properties } from "types"; // common -import { filterIssueOptions, groupByOptions, orderByOptions } from "constants/"; +import { GROUP_BY_OPTIONS, ORDER_BY_OPTIONS, FILTER_ISSUE_OPTIONS } from "constants/issue"; type Props = { issues?: IIssue[]; @@ -99,12 +99,12 @@ export const IssuesFilterView: React.FC = ({ issues }) => {

Group by

option.key === groupByProperty) + GROUP_BY_OPTIONS.find((option) => option.key === groupByProperty) ?.name ?? "Select" } width="lg" > - {groupByOptions.map((option) => + {GROUP_BY_OPTIONS.map((option) => issueView === "kanban" && option.key === null ? null : ( = ({ issues }) => {

Order by

option.key === orderBy)?.name ?? + ORDER_BY_OPTIONS.find((option) => option.key === orderBy)?.name ?? "Select" } width="lg" > - {orderByOptions.map((option) => + {ORDER_BY_OPTIONS.map((option) => groupByProperty === "priority" && option.key === "priority" ? null : ( = ({ issues }) => {

Issue type

option.key === filterIssue) + FILTER_ISSUE_OPTIONS.find((option) => option.key === filterIssue) ?.name ?? "Select" } width="lg" > - {filterIssueOptions.map((option) => ( + {FILTER_ISSUE_OPTIONS.map((option) => ( setFilterIssue(option.key)} diff --git a/apps/app/components/core/issues-view.tsx b/apps/app/components/core/issues-view.tsx index 3339bfdae..5f1d2c289 100644 --- a/apps/app/components/core/issues-view.tsx +++ b/apps/app/components/core/issues-view.tsx @@ -68,7 +68,7 @@ export const IssuesView: React.FC = ({ const { issueView, groupedByIssues, groupByProperty: selectedGroup } = useIssueView(issues); - const { data: states, mutate: mutateState } = useSWR( + const { data: states } = useSWR( workspaceSlug && projectId ? STATE_LIST(projectId as string) : null, workspaceSlug ? () => stateService.getStates(workspaceSlug as string, projectId as string) @@ -86,252 +86,192 @@ export const IssuesView: React.FC = ({ (result: DropResult) => { if (!result.destination || !workspaceSlug || !projectId) return; - const { source, destination, type } = result; + const { source, destination } = result; - if (type === "state") { - const newStates = Array.from(states ?? []); - const [reorderedState] = newStates.splice(source.index, 1); - newStates.splice(destination.index, 0, reorderedState); - const prevSequenceNumber = newStates[destination.index - 1]?.sequence; - const nextSequenceNumber = newStates[destination.index + 1]?.sequence; + const draggedItem = groupedByIssues[source.droppableId][source.index]; - const sequenceNumber = - prevSequenceNumber && nextSequenceNumber - ? (prevSequenceNumber + nextSequenceNumber) / 2 - : nextSequenceNumber - ? nextSequenceNumber - 15000 / 2 - : prevSequenceNumber - ? prevSequenceNumber + 15000 / 2 - : 15000; + if (source.droppableId !== destination.droppableId) { + const sourceGroup = source.droppableId; // source group id + const destinationGroup = destination.droppableId; // destination group id - newStates[destination.index].sequence = sequenceNumber; + if (!sourceGroup || !destinationGroup) return; - mutateState(newStates, false); + if (selectedGroup === "priority") { + // update the removed item for mutation + draggedItem.priority = destinationGroup; - stateService - .patchState( - workspaceSlug as string, - projectId as string, - newStates[destination.index].id, - { - sequence: sequenceNumber, - } - ) - .then((response) => { - console.log(response); - }) - .catch((err) => { - console.error(err); - }); - } else { - const draggedItem = groupedByIssues[source.droppableId][source.index]; - if (source.droppableId !== destination.droppableId) { - const sourceGroup = source.droppableId; // source group id - const destinationGroup = destination.droppableId; // destination group id - - if (!sourceGroup || !destinationGroup) return; - - if (selectedGroup === "priority") { - // update the removed item for mutation - draggedItem.priority = destinationGroup; - - if (cycleId) - mutate( - CYCLE_ISSUES(cycleId as string), - (prevData) => { - if (!prevData) return prevData; - const updatedIssues = prevData.map((issue) => { - if (issue.issue_detail.id === draggedItem.id) { - return { - ...issue, - issue_detail: { - ...draggedItem, - priority: destinationGroup, - }, - }; - } - return issue; - }); - return [...updatedIssues]; - }, - false - ); - - if (moduleId) - mutate( - MODULE_ISSUES(moduleId as string), - (prevData) => { - if (!prevData) return prevData; - const updatedIssues = prevData.map((issue) => { - if (issue.issue_detail.id === draggedItem.id) { - return { - ...issue, - issue_detail: { - ...draggedItem, - priority: destinationGroup, - }, - }; - } - return issue; - }); - return [...updatedIssues]; - }, - false - ); - - mutate( - PROJECT_ISSUES_LIST(workspaceSlug as string, projectId as string), + if (cycleId) + mutate( + CYCLE_ISSUES(cycleId as string), (prevData) => { if (!prevData) return prevData; - - const updatedIssues = prevData.results.map((issue) => { - if (issue.id === draggedItem.id) + const updatedIssues = prevData.map((issue) => { + if (issue.issue_detail.id === draggedItem.id) { return { - ...draggedItem, - priority: destinationGroup, + ...issue, + issue_detail: { + ...draggedItem, + priority: destinationGroup, + }, }; - + } return issue; }); - - return { - ...prevData, - results: updatedIssues, - }; + return [...updatedIssues]; }, false ); - // patch request - issuesService - .patchIssue(workspaceSlug as string, projectId as string, draggedItem.id, { - priority: destinationGroup, - }) - .then((res) => { - mutate( - cycleId - ? CYCLE_ISSUES(cycleId as string) - : CYCLE_ISSUES(draggedItem.issue_cycle?.cycle ?? "") - ); - mutate( - moduleId - ? MODULE_ISSUES(moduleId as string) - : MODULE_ISSUES(draggedItem.issue_module?.module ?? "") - ); - - mutate(PROJECT_ISSUES_LIST(workspaceSlug as string, projectId as string)); - }); - } else if (selectedGroup === "state_detail.name") { - const destinationState = states?.find((s) => s.name === destinationGroup); - const destinationStateId = destinationState?.id; - - // update the removed item for mutation - if (!destinationStateId || !destinationState) return; - draggedItem.state = destinationStateId; - draggedItem.state_detail = destinationState; - - if (cycleId) - mutate( - CYCLE_ISSUES(cycleId as string), - (prevData) => { - if (!prevData) return prevData; - const updatedIssues = prevData.map((issue) => { - if (issue.issue_detail.id === draggedItem.id) { - return { - ...issue, - issue_detail: { - ...draggedItem, - state_detail: destinationState, - state: destinationStateId, - }, - }; - } - return issue; - }); - return [...updatedIssues]; - }, - false - ); - - if (moduleId) - mutate( - MODULE_ISSUES(moduleId as string), - (prevData) => { - if (!prevData) return prevData; - const updatedIssues = prevData.map((issue) => { - if (issue.issue_detail.id === draggedItem.id) { - return { - ...issue, - issue_detail: { - ...draggedItem, - state_detail: destinationState, - state: destinationStateId, - }, - }; - } - return issue; - }); - return [...updatedIssues]; - }, - false - ); - - mutate( - PROJECT_ISSUES_LIST(workspaceSlug as string, projectId as string), + if (moduleId) + mutate( + MODULE_ISSUES(moduleId as string), (prevData) => { if (!prevData) return prevData; - - const updatedIssues = prevData.results.map((issue) => { - if (issue.id === draggedItem.id) + const updatedIssues = prevData.map((issue) => { + if (issue.issue_detail.id === draggedItem.id) { return { - ...draggedItem, - state_detail: destinationState, - state: destinationStateId, + ...issue, + issue_detail: { + ...draggedItem, + priority: destinationGroup, + }, }; - + } return issue; }); - - return { - ...prevData, - results: updatedIssues, - }; + return [...updatedIssues]; }, false ); - // patch request - issuesService - .patchIssue(workspaceSlug as string, projectId as string, draggedItem.id, { - state: destinationStateId, - }) - .then((res) => { - mutate( - cycleId - ? CYCLE_ISSUES(cycleId as string) - : CYCLE_ISSUES(draggedItem.issue_cycle?.cycle ?? "") - ); - mutate( - moduleId - ? MODULE_ISSUES(moduleId as string) - : MODULE_ISSUES(draggedItem.issue_module?.module ?? "") - ); - mutate(PROJECT_ISSUES_LIST(workspaceSlug as string, projectId as string)); + mutate( + PROJECT_ISSUES_LIST(workspaceSlug as string, projectId as string), + (prevData) => { + if (!prevData) return prevData; + + const updatedIssues = prevData.results.map((issue) => { + if (issue.id === draggedItem.id) + return { + ...draggedItem, + priority: destinationGroup, + }; + + return issue; }); - } + + return { + ...prevData, + results: updatedIssues, + }; + }, + false + ); + + // patch request + issuesService + .patchIssue(workspaceSlug as string, projectId as string, draggedItem.id, { + priority: destinationGroup, + }) + .then((res) => { + if (cycleId) mutate(CYCLE_ISSUES(cycleId as string)); + if (moduleId) mutate(MODULE_ISSUES(moduleId as string)); + + mutate(PROJECT_ISSUES_LIST(workspaceSlug as string, projectId as string)); + }); + } else if (selectedGroup === "state_detail.name") { + const destinationState = states?.find((s) => s.name === destinationGroup); + const destinationStateId = destinationState?.id; + + // update the removed item for mutation + if (!destinationStateId || !destinationState) return; + draggedItem.state = destinationStateId; + draggedItem.state_detail = destinationState; + + if (cycleId) + mutate( + CYCLE_ISSUES(cycleId as string), + (prevData) => { + if (!prevData) return prevData; + const updatedIssues = prevData.map((issue) => { + if (issue.issue_detail.id === draggedItem.id) { + return { + ...issue, + issue_detail: { + ...draggedItem, + state_detail: destinationState, + state: destinationStateId, + }, + }; + } + return issue; + }); + return [...updatedIssues]; + }, + false + ); + + if (moduleId) + mutate( + MODULE_ISSUES(moduleId as string), + (prevData) => { + if (!prevData) return prevData; + const updatedIssues = prevData.map((issue) => { + if (issue.issue_detail.id === draggedItem.id) { + return { + ...issue, + issue_detail: { + ...draggedItem, + state_detail: destinationState, + state: destinationStateId, + }, + }; + } + return issue; + }); + return [...updatedIssues]; + }, + false + ); + + mutate( + PROJECT_ISSUES_LIST(workspaceSlug as string, projectId as string), + (prevData) => { + if (!prevData) return prevData; + + const updatedIssues = prevData.results.map((issue) => { + if (issue.id === draggedItem.id) + return { + ...draggedItem, + state_detail: destinationState, + state: destinationStateId, + }; + + return issue; + }); + + return { + ...prevData, + results: updatedIssues, + }; + }, + false + ); + + // patch request + issuesService + .patchIssue(workspaceSlug as string, projectId as string, draggedItem.id, { + state: destinationStateId, + }) + .then((res) => { + if (cycleId) mutate(CYCLE_ISSUES(cycleId as string)); + if (moduleId) mutate(MODULE_ISSUES(moduleId as string)); + + mutate(PROJECT_ISSUES_LIST(workspaceSlug as string, projectId as string)); + }); } } }, - [ - workspaceSlug, - cycleId, - moduleId, - mutateState, - groupedByIssues, - projectId, - selectedGroup, - states, - ] + [workspaceSlug, cycleId, moduleId, groupedByIssues, projectId, selectedGroup, states] ); const addIssueToState = (groupTitle: string, stateId: string | null) => { diff --git a/apps/app/components/core/list-view/single-issue.tsx b/apps/app/components/core/list-view/single-issue.tsx index 9ed4fa156..b779db594 100644 --- a/apps/app/components/core/list-view/single-issue.tsx +++ b/apps/app/components/core/list-view/single-issue.tsx @@ -3,20 +3,23 @@ import React, { useCallback } from "react"; import Link from "next/link"; import { useRouter } from "next/router"; -import useSWR, { mutate } from "swr"; +import { mutate } from "swr"; // services import issuesService from "services/issues.service"; -import stateService from "services/state.service"; // components -import { AssigneeSelect, DueDateSelect, PrioritySelect, StateSelect } from "components/core/select"; +import { + ViewAssigneeSelect, + ViewDueDateSelect, + ViewPrioritySelect, + ViewStateSelect, +} from "components/issues/view-select"; // ui import { CustomMenu } from "components/ui"; // types import { CycleIssueResponse, IIssue, - IProjectMember, IssueResponse, ModuleIssueResponse, Properties, @@ -29,7 +32,6 @@ type Props = { type?: string; issue: IIssue; properties: Properties; - members: IProjectMember[] | undefined; editIssue: () => void; removeIssue?: (() => void) | null; handleDeleteIssue: (issue: IIssue) => void; @@ -40,7 +42,6 @@ export const SingleListIssue: React.FC = ({ type, issue, properties, - members, editIssue, removeIssue, handleDeleteIssue, @@ -49,13 +50,6 @@ export const SingleListIssue: React.FC = ({ const router = useRouter(); const { workspaceSlug, projectId, cycleId, moduleId } = router.query; - const { data: states } = useSWR( - workspaceSlug && projectId ? STATE_LIST(projectId as string) : null, - workspaceSlug && projectId - ? () => stateService.getStates(workspaceSlug as string, projectId as string) - : null - ); - const partialUpdateIssue = useCallback( (formData: Partial) => { if (!workspaceSlug || !projectId) return; @@ -117,16 +111,8 @@ export const SingleListIssue: React.FC = ({ issuesService .patchIssue(workspaceSlug as string, projectId as string, issue.id, formData) .then((res) => { - mutate( - cycleId - ? CYCLE_ISSUES(cycleId as string) - : CYCLE_ISSUES(issue?.issue_cycle?.cycle ?? "") - ); - mutate( - moduleId - ? MODULE_ISSUES(moduleId as string) - : MODULE_ISSUES(issue?.issue_module?.module ?? "") - ); + if (cycleId) mutate(CYCLE_ISSUES(cycleId as string)); + if (moduleId) mutate(MODULE_ISSUES(moduleId as string)); mutate(PROJECT_ISSUES_LIST(workspaceSlug as string, projectId as string)); }) @@ -161,22 +147,21 @@ export const SingleListIssue: React.FC = ({
{properties.priority && ( - )} {properties.state && ( - )} {properties.due_date && ( - = ({
)} {properties.assignee && ( - diff --git a/apps/app/components/core/list-view/single-list.tsx b/apps/app/components/core/list-view/single-list.tsx index b3d478593..4309b2d33 100644 --- a/apps/app/components/core/list-view/single-list.tsx +++ b/apps/app/components/core/list-view/single-list.tsx @@ -101,7 +101,6 @@ export const SingleList: React.FC = ({ type={type} issue={issue} properties={properties} - members={members} editIssue={() => handleEditIssue(issue)} handleDeleteIssue={handleDeleteIssue} removeIssue={() => { diff --git a/apps/app/components/core/select/due-date.tsx b/apps/app/components/core/select/due-date.tsx deleted file mode 100644 index dc71a8362..000000000 --- a/apps/app/components/core/select/due-date.tsx +++ /dev/null @@ -1,48 +0,0 @@ -// ui -import { CustomDatePicker } from "components/ui"; -// helpers -import { findHowManyDaysLeft, renderShortNumericDateFormat } from "helpers/date-time.helper"; -// types -import { IIssue } from "types"; - -type Props = { - issue: IIssue; - partialUpdateIssue: (formData: Partial) => void; - isNotAllowed: boolean; -}; - -export const DueDateSelect: React.FC = ({ issue, partialUpdateIssue, isNotAllowed }) => ( -
- - partialUpdateIssue({ - target_date: val, - }) - } - className={issue?.target_date ? "w-[6.5rem]" : "w-[3rem] text-center"} - /> -
-
Due date
-
{renderShortNumericDateFormat(issue.target_date ?? "")}
-
- {issue.target_date - ? issue.target_date < new Date().toISOString() - ? `Due date has passed by ${findHowManyDaysLeft(issue.target_date)} days` - : findHowManyDaysLeft(issue.target_date) <= 3 - ? `Due date is in ${findHowManyDaysLeft(issue.target_date)} days` - : "Due date" - : "N/A"} -
-
-
-); diff --git a/apps/app/components/core/select/priority.tsx b/apps/app/components/core/select/priority.tsx deleted file mode 100644 index 8c3110cbe..000000000 --- a/apps/app/components/core/select/priority.tsx +++ /dev/null @@ -1,97 +0,0 @@ -import React from "react"; - -// ui -import { Listbox, Transition } from "@headlessui/react"; -// types -import { IIssue, IState } from "types"; -// constants -import { getPriorityIcon } from "constants/global"; -import { PRIORITIES } from "constants/"; - -type Props = { - issue: IIssue; - partialUpdateIssue: (formData: Partial) => void; - isNotAllowed: boolean; -}; - -export const PrioritySelect: React.FC = ({ issue, partialUpdateIssue, isNotAllowed }) => ( - { - partialUpdateIssue({ priority: data }); - }} - className="group relative flex-shrink-0" - disabled={isNotAllowed} - > - {({ open }) => ( - <> -
- - {getPriorityIcon( - issue.priority && issue.priority !== "" ? issue.priority ?? "" : "None", - "text-sm" - )} - - - - - {PRIORITIES?.map((priority) => ( - - `flex cursor-pointer select-none items-center gap-x-2 px-3 py-2 capitalize ${ - active ? "bg-indigo-50" : "bg-white" - }` - } - value={priority} - > - {getPriorityIcon(priority, "text-sm")} - {priority ?? "None"} - - ))} - - -
-
-
Priority
-
- {issue.priority ?? "None"} -
-
- - )} -
-); diff --git a/apps/app/components/core/select/state.tsx b/apps/app/components/core/select/state.tsx deleted file mode 100644 index d65d7e7d3..000000000 --- a/apps/app/components/core/select/state.tsx +++ /dev/null @@ -1,55 +0,0 @@ -// ui -import { CustomSelect } from "components/ui"; -// helpers -import { addSpaceIfCamelCase } from "helpers/string.helper"; -// types -import { IIssue, IState } from "types"; - -type Props = { - issue: IIssue; - states: IState[] | undefined; - partialUpdateIssue: (formData: Partial) => void; - isNotAllowed: boolean; -}; - -export const StateSelect: React.FC = ({ - issue, - states, - partialUpdateIssue, - isNotAllowed, -}) => ( - - s.id === issue.state)?.color, - }} - /> - {addSpaceIfCamelCase(states?.find((s) => s.id === issue.state)?.name ?? "")} - - } - value={issue.state} - onChange={(data: string) => { - partialUpdateIssue({ state: data }); - }} - maxHeight="md" - noChevron - disabled={isNotAllowed} - > - {states?.map((state) => ( - - <> - - {addSpaceIfCamelCase(state.name)} - - - ))} - -); diff --git a/apps/app/components/emoji-icon-picker/index.tsx b/apps/app/components/emoji-icon-picker/index.tsx index c2930e95b..a441cd4cb 100644 --- a/apps/app/components/emoji-icon-picker/index.tsx +++ b/apps/app/components/emoji-icon-picker/index.tsx @@ -7,7 +7,7 @@ import { Props } from "./types"; import emojis from "./emojis.json"; // helpers import { getRecentEmojis, saveRecentEmoji } from "./helpers"; -import { getRandomEmoji } from "helpers/functions.helper"; +import { getRandomEmoji } from "helpers/common.helper"; // hooks import useOutsideClickDetector from "hooks/use-outside-click-detector"; diff --git a/apps/app/constants/global.tsx b/apps/app/components/icons/priority-icon.tsx similarity index 100% rename from apps/app/constants/global.tsx rename to apps/app/components/icons/priority-icon.tsx diff --git a/apps/app/components/issues/activity.tsx b/apps/app/components/issues/activity.tsx index 351aff485..2bcc3853d 100644 --- a/apps/app/components/issues/activity.tsx +++ b/apps/app/components/issues/activity.tsx @@ -8,6 +8,7 @@ import { CalendarDaysIcon, ChartBarIcon, ChatBubbleBottomCenterTextIcon, + RectangleGroupIcon, Squares2X2Icon, UserIcon, } from "@heroicons/react/24/outline"; @@ -18,7 +19,7 @@ import { CommentCard } from "components/issues/comment"; // ui import { Loader } from "components/ui"; // icons -import { BlockedIcon, BlockerIcon, TagIcon, UserGroupIcon } from "components/icons"; +import { BlockedIcon, BlockerIcon, CyclesIcon, TagIcon, UserGroupIcon } from "components/icons"; // helpers import { renderShortNumericDateFormat, timeAgo } from "helpers/date-time.helper"; import { addSpaceIfCamelCase } from "helpers/string.helper"; @@ -47,9 +48,17 @@ const activityDetails: { message: "marked this issue is blocking", icon: , }, + cycles: { + message: "set the cycle to", + icon: , + }, labels: { icon: , }, + modules: { + message: "set the module to", + icon: , + }, state: { message: "set the state to", icon: , @@ -76,10 +85,12 @@ const activityDetails: { }, }; -export const IssueActivitySection: React.FC<{ +type Props = { issueActivities: IIssueActivity[]; mutate: KeyedMutator; -}> = ({ issueActivities, mutate }) => { +}; + +export const IssueActivitySection: React.FC = ({ issueActivities, mutate }) => { const router = useRouter(); const { workspaceSlug, projectId, issueId } = router.query; @@ -183,7 +194,9 @@ export const IssueActivitySection: React.FC<{ ?.message}{" "} - {activity.verb === "created" ? ( + {activity.verb === "created" && + activity.field !== "cycles" && + activity.field !== "modules" ? ( created this issue. ) : activity.field === "description" ? null : activity.field === "state" ? ( activity.new_value ? ( diff --git a/apps/app/components/issues/comment/add-comment.tsx b/apps/app/components/issues/comment/add-comment.tsx index a904a6c4a..9b31a2423 100644 --- a/apps/app/components/issues/comment/add-comment.tsx +++ b/apps/app/components/issues/comment/add-comment.tsx @@ -10,7 +10,7 @@ import issuesServices from "services/issues.service"; // ui import { Loader } from "components/ui"; // helpers -import { debounce } from "helpers/functions.helper"; +import { debounce } from "helpers/common.helper"; // types import type { IIssueActivity, IIssueComment } from "types"; import type { KeyedMutator } from "swr"; diff --git a/apps/app/components/issues/my-issues-list-item.tsx b/apps/app/components/issues/my-issues-list-item.tsx index 8e7391283..130c777af 100644 --- a/apps/app/components/issues/my-issues-list-item.tsx +++ b/apps/app/components/issues/my-issues-list-item.tsx @@ -3,20 +3,23 @@ import React, { useCallback } from "react"; import Link from "next/link"; import { useRouter } from "next/router"; -import useSWR, { mutate } from "swr"; +import { mutate } from "swr"; // services -import stateService from "services/state.service"; import issuesService from "services/issues.service"; // components -import { DueDateSelect, PrioritySelect, StateSelect } from "components/core/select"; +import { + ViewDueDateSelect, + ViewPrioritySelect, + ViewStateSelect, +} from "components/issues/view-select"; // ui import { AssigneesList } from "components/ui/avatar"; import { CustomMenu } from "components/ui"; // types import { IIssue, Properties } from "types"; // fetch-keys -import { STATE_LIST, USER_ISSUE } from "constants/fetch-keys"; +import { USER_ISSUE } from "constants/fetch-keys"; type Props = { issue: IIssue; @@ -34,13 +37,6 @@ export const MyIssuesListItem: React.FC = ({ const router = useRouter(); const { workspaceSlug } = router.query; - const { data: states } = useSWR( - workspaceSlug && projectId ? STATE_LIST(projectId) : null, - workspaceSlug && projectId - ? () => stateService.getStates(workspaceSlug as string, projectId) - : null - ); - const partialUpdateIssue = useCallback( (formData: Partial) => { if (!workspaceSlug) return; @@ -92,22 +88,21 @@ export const MyIssuesListItem: React.FC = ({
{properties.priority && ( - )} {properties.state && ( - )} {properties.due_date && ( - = ({ value, onChange, projectId } const options = issueLabels?.map((label) => ({ value: label.id, display: label.name, - color: label.colour, + color: label.color, })); const filteredOptions = diff --git a/apps/app/components/issues/select/priority.tsx b/apps/app/components/issues/select/priority.tsx index e85f2deac..1347e2765 100644 --- a/apps/app/components/issues/select/priority.tsx +++ b/apps/app/components/issues/select/priority.tsx @@ -2,9 +2,10 @@ import React from "react"; // headless ui import { Listbox, Transition } from "@headlessui/react"; +// icons +import { getPriorityIcon } from "components/icons/priority-icon"; // constants -import { getPriorityIcon } from "constants/global"; -import { PRIORITIES } from "constants/"; +import { PRIORITIES } from "constants/project"; type Props = { value: string | null; diff --git a/apps/app/components/issues/sidebar-select/priority.tsx b/apps/app/components/issues/sidebar-select/priority.tsx index 252400669..7583f16f4 100644 --- a/apps/app/components/issues/sidebar-select/priority.tsx +++ b/apps/app/components/issues/sidebar-select/priority.tsx @@ -1,17 +1,16 @@ -// react import React from "react"; + // react-hook-form -import { Control, Controller, UseFormWatch } from "react-hook-form"; +import { Control, Controller } from "react-hook-form"; // ui -import { ChartBarIcon } from "@heroicons/react/24/outline"; import { CustomSelect } from "components/ui"; // icons +import { ChartBarIcon } from "@heroicons/react/24/outline"; +import { getPriorityIcon } from "components/icons/priority-icon"; // types import { IIssue, UserAuth } from "types"; -// common // constants -import { getPriorityIcon } from "constants/global"; -import { PRIORITIES } from "constants/"; +import { PRIORITIES } from "constants/project"; type Props = { control: Control; diff --git a/apps/app/components/issues/sidebar.tsx b/apps/app/components/issues/sidebar.tsx index d5be6949f..62a99eac1 100644 --- a/apps/app/components/issues/sidebar.tsx +++ b/apps/app/components/issues/sidebar.tsx @@ -56,7 +56,7 @@ type Props = { const defaultValues: Partial = { name: "", - colour: "#ff0000", + color: "#ff0000", }; export const IssueDetailsSidebar: React.FC = ({ @@ -316,7 +316,7 @@ export const IssueDetailsSidebar: React.FC = ({ > {singleLabel.name} @@ -372,7 +372,7 @@ export const IssueDetailsSidebar: React.FC = ({ > {label.name} @@ -422,11 +422,11 @@ export const IssueDetailsSidebar: React.FC = ({ - {watch("colour") && watch("colour") !== "" && ( + {watch("color") && watch("color") !== "" && ( )} @@ -444,7 +444,7 @@ export const IssueDetailsSidebar: React.FC = ({ > ( ) => void; + position?: "left" | "right"; isNotAllowed: boolean; }; -export const AssigneeSelect: React.FC = ({ +export const ViewAssigneeSelect: React.FC = ({ issue, - members, partialUpdateIssue, + position = "right", isNotAllowed, -}) => ( - { - const newData = issue.assignees ?? []; +}) => { + const router = useRouter(); + const { workspaceSlug, projectId } = router.query; - if (newData.includes(data)) newData.splice(newData.indexOf(data), 1); - else newData.push(data); + const { data: members } = useSWR( + projectId ? PROJECT_MEMBERS(projectId as string) : null, + workspaceSlug && projectId + ? () => projectService.projectMembers(workspaceSlug as string, projectId as string) + : null + ); - partialUpdateIssue({ assignees_list: newData }); - }} - className="group relative flex-shrink-0" - disabled={isNotAllowed} - > - {({ open }) => ( - <> + return ( + { + const newData = issue.assignees ?? []; + + if (newData.includes(data)) newData.splice(newData.indexOf(data), 1); + else newData.push(data); + + partialUpdateIssue({ assignees_list: newData }); + }} + className="group relative flex-shrink-0" + disabled={isNotAllowed} + > + {({ open }) => (
= ({ leaveFrom="opacity-100" leaveTo="opacity-0" > - + {members?.map((member) => ( - `flex items-center gap-x-1 cursor-pointer select-none p-2 ${ + `flex items-center gap-x-1 cursor-pointer select-none p-2 whitespace-nowrap ${ active ? "bg-indigo-50" : "" } ${ selected || issue.assignees?.includes(member.member.id) @@ -70,25 +92,15 @@ export const AssigneeSelect: React.FC = ({ value={member.member.id} > -

- {member.member.first_name && member.member.first_name !== "" - ? member.member.first_name - : member.member.email} -

+ {member.member.first_name && member.member.first_name !== "" + ? member.member.first_name + : member.member.email}
))}
-
-
Assigned to
-
- {issue.assignee_details?.length > 0 - ? issue.assignee_details.map((assignee) => assignee.first_name).join(", ") - : "No one"} -
-
- - )} - -); + )} + + ); +}; diff --git a/apps/app/components/issues/view-select/due-date.tsx b/apps/app/components/issues/view-select/due-date.tsx new file mode 100644 index 000000000..9033e95e3 --- /dev/null +++ b/apps/app/components/issues/view-select/due-date.tsx @@ -0,0 +1,36 @@ +// ui +import { CustomDatePicker } from "components/ui"; +// helpers +import { findHowManyDaysLeft } from "helpers/date-time.helper"; +// types +import { IIssue } from "types"; + +type Props = { + issue: IIssue; + partialUpdateIssue: (formData: Partial) => void; + isNotAllowed: boolean; +}; + +export const ViewDueDateSelect: React.FC = ({ issue, partialUpdateIssue, isNotAllowed }) => ( +
+ + partialUpdateIssue({ + target_date: val, + }) + } + className={issue?.target_date ? "w-[6.5rem]" : "w-[3rem] text-center"} + disabled={isNotAllowed} + /> +
+); diff --git a/apps/app/components/core/select/index.ts b/apps/app/components/issues/view-select/index.ts similarity index 100% rename from apps/app/components/core/select/index.ts rename to apps/app/components/issues/view-select/index.ts diff --git a/apps/app/components/issues/view-select/priority.tsx b/apps/app/components/issues/view-select/priority.tsx new file mode 100644 index 000000000..5517494b2 --- /dev/null +++ b/apps/app/components/issues/view-select/priority.tsx @@ -0,0 +1,88 @@ +import React from "react"; + +// ui +import { Listbox, Transition } from "@headlessui/react"; +// icons +import { getPriorityIcon } from "components/icons/priority-icon"; +// types +import { IIssue } from "types"; +// constants +import { PRIORITIES } from "constants/project"; + +type Props = { + issue: IIssue; + partialUpdateIssue: (formData: Partial) => void; + position?: "left" | "right"; + isNotAllowed: boolean; +}; + +export const ViewPrioritySelect: React.FC = ({ + issue, + partialUpdateIssue, + position = "right", + isNotAllowed, +}) => ( + { + partialUpdateIssue({ priority: data }); + }} + className="group relative flex-shrink-0" + disabled={isNotAllowed} + > + {({ open }) => ( +
+ + {getPriorityIcon( + issue.priority && issue.priority !== "" ? issue.priority ?? "" : "None", + "text-sm" + )} + + + + + {PRIORITIES?.map((priority) => ( + + `flex cursor-pointer select-none items-center gap-x-2 px-3 py-2 capitalize ${ + active ? "bg-indigo-50" : "bg-white" + }` + } + value={priority} + > + {getPriorityIcon(priority, "text-sm")} + {priority ?? "None"} + + ))} + + +
+ )} +
+); diff --git a/apps/app/components/issues/view-select/state.tsx b/apps/app/components/issues/view-select/state.tsx new file mode 100644 index 000000000..ce54d8293 --- /dev/null +++ b/apps/app/components/issues/view-select/state.tsx @@ -0,0 +1,75 @@ +import { useRouter } from "next/router"; + +import useSWR from "swr"; + +// services +import stateService from "services/state.service"; +// ui +import { CustomSelect } from "components/ui"; +// helpers +import { addSpaceIfCamelCase } from "helpers/string.helper"; +// types +import { IIssue, IState } from "types"; +// fetch-keys +import { STATE_LIST } from "constants/fetch-keys"; + +type Props = { + issue: IIssue; + partialUpdateIssue: (formData: Partial) => void; + position?: "left" | "right"; + isNotAllowed: boolean; +}; + +export const ViewStateSelect: React.FC = ({ + issue, + partialUpdateIssue, + position, + isNotAllowed, +}) => { + const router = useRouter(); + const { workspaceSlug, projectId } = router.query; + + const { data: states } = useSWR( + workspaceSlug && projectId ? STATE_LIST(projectId as string) : null, + workspaceSlug + ? () => stateService.getStates(workspaceSlug as string, projectId as string) + : null + ); + + return ( + + s.id === issue.state)?.color, + }} + /> + {addSpaceIfCamelCase(states?.find((s) => s.id === issue.state)?.name ?? "")} + + } + value={issue.state} + onChange={(data: string) => { + partialUpdateIssue({ state: data }); + }} + maxHeight="md" + noChevron + disabled={isNotAllowed} + > + {states?.map((state) => ( + + <> + + {addSpaceIfCamelCase(state.name)} + + + ))} + + ); +}; diff --git a/apps/app/components/modules/select/select-status.tsx b/apps/app/components/modules/select/select-status.tsx index 342b854be..06e476210 100644 --- a/apps/app/components/modules/select/select-status.tsx +++ b/apps/app/components/modules/select/select-status.tsx @@ -9,7 +9,7 @@ import { Squares2X2Icon } from "@heroicons/react/24/outline"; // types import type { IModule } from "types"; // constants -import { MODULE_STATUS } from "constants/"; +import { MODULE_STATUS } from "constants/module"; type Props = { control: Control; diff --git a/apps/app/components/modules/sidebar-select/select-status.tsx b/apps/app/components/modules/sidebar-select/select-status.tsx index 12993effc..2156b4357 100644 --- a/apps/app/components/modules/sidebar-select/select-status.tsx +++ b/apps/app/components/modules/sidebar-select/select-status.tsx @@ -10,7 +10,7 @@ import { CustomSelect } from "components/ui"; import { IModule } from "types"; // common // constants -import { MODULE_STATUS } from "constants/"; +import { MODULE_STATUS } from "constants/module"; type Props = { control: Control, any>; diff --git a/apps/app/components/modules/single-module-card.tsx b/apps/app/components/modules/single-module-card.tsx index f67cd7193..6bd59d14f 100644 --- a/apps/app/components/modules/single-module-card.tsx +++ b/apps/app/components/modules/single-module-card.tsx @@ -14,7 +14,7 @@ import { renderShortNumericDateFormat } from "helpers/date-time.helper"; // types import { IModule, SelectModuleType } from "types"; // common -import { MODULE_STATUS } from "constants/"; +import { MODULE_STATUS } from "constants/module"; type Props = { module: IModule; diff --git a/apps/app/components/onboarding/workspace.tsx b/apps/app/components/onboarding/workspace.tsx index 786459c08..b8011a2c0 100644 --- a/apps/app/components/onboarding/workspace.tsx +++ b/apps/app/components/onboarding/workspace.tsx @@ -16,10 +16,10 @@ import workspaceService from "services/workspace.service"; import { CustomSelect, Input } from "components/ui"; // types import { IWorkspace, IWorkspaceMemberInvitation } from "types"; -// constants -import { companySize } from "constants/"; // fetch-keys import { USER_WORKSPACE_INVITATIONS } from "constants/fetch-keys"; +// constants +import { COMPANY_SIZE } from "constants/workspace"; type Props = { setStep: React.Dispatch>; @@ -186,7 +186,7 @@ const Workspace: React.FC = ({ setStep, setWorkspace }) => { label={value ? value.toString() : "Select company size"} input > - {companySize?.map((item) => ( + {COMPANY_SIZE?.map((item) => ( {item.label} diff --git a/apps/app/components/project/create-project-modal.tsx b/apps/app/components/project/create-project-modal.tsx index db91e43ef..08a085e49 100644 --- a/apps/app/components/project/create-project-modal.tsx +++ b/apps/app/components/project/create-project-modal.tsx @@ -17,13 +17,13 @@ import { Button, Input, TextArea, CustomSelect } from "components/ui"; // components import EmojiIconPicker from "components/emoji-icon-picker"; // helpers -import { getRandomEmoji } from "helpers/functions.helper"; +import { getRandomEmoji } from "helpers/common.helper"; // types import { IProject } from "types"; // fetch-keys import { PROJECTS_LIST, WORKSPACE_MEMBERS_ME } from "constants/fetch-keys"; // constants -import { NETWORK_CHOICES } from "constants/"; +import { NETWORK_CHOICES } from "constants/project"; type Props = { isOpen: boolean; diff --git a/apps/app/components/project/send-project-invitation-modal.tsx b/apps/app/components/project/send-project-invitation-modal.tsx index a7908421a..5eb007af0 100644 --- a/apps/app/components/project/send-project-invitation-modal.tsx +++ b/apps/app/components/project/send-project-invitation-modal.tsx @@ -8,8 +8,8 @@ import { useForm, Controller } from "react-hook-form"; import { Dialog, Transition, Listbox } from "@headlessui/react"; // ui -import { ChevronDownIcon, CheckIcon } from "@heroicons/react/20/solid"; -import { Button, CustomSelect, Select, TextArea } from "components/ui"; +import { ChevronDownIcon } from "@heroicons/react/20/solid"; +import { Button, CustomSelect, TextArea } from "components/ui"; // hooks import useToast from "hooks/use-toast"; // services @@ -17,10 +17,10 @@ import projectService from "services/project.service"; import workspaceService from "services/workspace.service"; // types import { IProjectMemberInvitation } from "types"; -// constants -import { ROLE } from "constants/"; +// fetch - keys import { PROJECT_INVITATIONS, WORKSPACE_MEMBERS } from "constants/fetch-keys"; -// icons +// constants +import { ROLE } from "constants/workspace"; type Props = { isOpen: boolean; diff --git a/apps/app/components/project/settings/single-label.tsx b/apps/app/components/project/settings/single-label.tsx index 8fc46c6b0..c58fb608f 100644 --- a/apps/app/components/project/settings/single-label.tsx +++ b/apps/app/components/project/settings/single-label.tsx @@ -21,7 +21,7 @@ type Props = { const defaultValues: Partial = { name: "", - colour: "#ff0000", + color: "#ff0000", }; const SingleLabel: React.FC = ({ label, issueLabels, editLabel, handleLabelDelete }) => { @@ -45,7 +45,7 @@ const SingleLabel: React.FC = ({ label, issueLabels, editLabel, handleLab
{label.name}
@@ -68,11 +68,11 @@ const SingleLabel: React.FC = ({ label, issueLabels, editLabel, handleLab open ? "text-gray-900" : "text-gray-500" }`} > - {watch("colour") && watch("colour") !== "" && ( + {watch("color") && watch("color") !== "" && ( )} @@ -89,7 +89,7 @@ const SingleLabel: React.FC = ({ label, issueLabels, editLabel, handleLab > ( { sidebarCollapse ? "" : "ml-[2.25rem]" } flex flex-col gap-y-1`} > - {navigation(workspaceSlug as string, project?.id).map((item) => ( - - - { + const hi = "hi"; + + if (item.name === "Cycles" && !project.cycle_view) return; + if (item.name === "Modules" && !project.module_view) return; + + return ( + + - - ))} + ? "bg-gray-200 text-gray-900" + : "text-gray-500 hover:bg-gray-100 hover:text-gray-900 focus:bg-gray-100 focus:text-gray-900" + } ${sidebarCollapse ? "justify-center" : ""}`} + > +
- + ); }; diff --git a/apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/features.tsx b/apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/features.tsx new file mode 100644 index 000000000..b75adef7b --- /dev/null +++ b/apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/features.tsx @@ -0,0 +1,187 @@ +import React from "react"; + +import { useRouter } from "next/router"; + +import useSWR, { mutate } from "swr"; + +// services +import projectService from "services/project.service"; +// lib +import { requiredAdmin } from "lib/auth"; +// layouts +import AppLayout from "layouts/app-layout"; +// hooks +import useToast from "hooks/use-toast"; +// ui +import { Button } from "components/ui"; +import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs"; +// types +import { IProject, UserAuth } from "types"; +import type { NextPage, NextPageContext } from "next"; +// fetch-keys +import { PROJECTS_LIST, PROJECT_DETAILS } from "constants/fetch-keys"; + +const FeaturesSettings: NextPage = (props) => { + const router = useRouter(); + const { workspaceSlug, projectId } = router.query; + + const { setToastAlert } = useToast(); + + const { data: projectDetails } = useSWR( + workspaceSlug && projectId ? PROJECT_DETAILS(projectId as string) : null, + workspaceSlug && projectId + ? () => projectService.getProject(workspaceSlug as string, projectId as string) + : null + ); + + const handleSubmit = async (formData: Partial) => { + if (!workspaceSlug || !projectId) return; + + mutate( + PROJECT_DETAILS(projectId as string), + (prevData) => ({ ...(prevData as IProject), ...formData }), + false + ); + + mutate( + PROJECTS_LIST(workspaceSlug as string), + (prevData) => + prevData?.map((p) => { + if (p.id === projectId) + return { + ...p, + ...formData, + }; + + return p; + }), + false + ); + + await projectService + .updateProject(workspaceSlug as string, projectId as string, formData) + .then((res) => { + mutate(PROJECT_DETAILS(projectId as string)); + mutate(PROJECTS_LIST(workspaceSlug as string)); + + setToastAlert({ + title: "Success!", + type: "success", + message: "Project features updated successfully.", + }); + }) + .catch((err) => { + console.error(err); + }); + }; + + return ( + + + + + } + > +
+
+

Project Features

+
+
+
+
+

Use cycles

+

+ Cycles are enabled for all the projects in this workspace. Access it from the + navigation bar. +

+
+
+ +
+
+
+
+

Use modules

+

+ Modules are enabled for all the projects in this workspace. Access it from the + navigation bar. +

+
+
+ +
+
+ +
+
+
+ ); +}; + +export const getServerSideProps = async (ctx: NextPageContext) => { + const projectId = ctx.query.projectId as string; + const workspaceSlug = ctx.query.workspaceSlug as string; + + const memberDetail = await requiredAdmin(workspaceSlug, projectId, ctx.req?.headers.cookie); + + return { + props: { + isOwner: memberDetail?.role === 20, + isMember: memberDetail?.role === 15, + isViewer: memberDetail?.role === 10, + isGuest: memberDetail?.role === 5, + }, + }; +}; + +export default FeaturesSettings; diff --git a/apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/index.tsx b/apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/index.tsx index 1e9cc6e16..e85000f11 100644 --- a/apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/index.tsx +++ b/apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/index.tsx @@ -6,11 +6,11 @@ import useSWR, { mutate } from "swr"; // react-hook-form import { Controller, useForm } from "react-hook-form"; -import { IProject, IWorkspace } from "types"; +import { IProject, IWorkspace, UserAuth } from "types"; // lib import { requiredAdmin } from "lib/auth"; // layouts -import SettingsLayout from "layouts/settings-layout"; +import AppLayout from "layouts/app-layout"; // services import projectService from "services/project.service"; import workspaceService from "services/workspace.service"; @@ -24,13 +24,13 @@ import { Button, Input, TextArea, Loader, CustomSelect } from "components/ui"; import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs"; import OutlineButton from "components/ui/outline-button"; // helpers -import { debounce } from "helpers/functions.helper"; +import { debounce } from "helpers/common.helper"; // types import type { NextPage, NextPageContext } from "next"; // fetch-keys import { PROJECTS_LIST, PROJECT_DETAILS, WORKSPACE_DETAILS } from "constants/fetch-keys"; // constants -import { NETWORK_CHOICES } from "constants/"; +import { NETWORK_CHOICES } from "constants/project"; const defaultValues: Partial = { name: "", @@ -39,14 +39,7 @@ const defaultValues: Partial = { network: 0, }; -type TGeneralSettingsProps = { - isMember: boolean; - isOwner: boolean; - isViewer: boolean; - isGuest: boolean; -}; - -const GeneralSettings: NextPage = (props) => { +const GeneralSettings: NextPage = (props) => { const { isMember, isOwner, isViewer, isGuest } = props; const [selectProject, setSelectedProject] = useState(null); @@ -100,6 +93,7 @@ const GeneralSettings: NextPage = (props) => { const onSubmit = async (formData: IProject) => { if (!activeWorkspace || !projectDetails) return; + const payload: Partial = { name: formData.name, network: formData.network, @@ -109,6 +103,7 @@ const GeneralSettings: NextPage = (props) => { project_lead: formData.project_lead, icon: formData.icon, }; + await projectService .updateProject(activeWorkspace.slug, projectDetails.id, payload) .then((res) => { @@ -130,9 +125,9 @@ const GeneralSettings: NextPage = (props) => { }; return ( - = (props) => { - + ); }; diff --git a/apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/labels.tsx b/apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/labels.tsx index 568f62392..b82f76d9e 100644 --- a/apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/labels.tsx +++ b/apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/labels.tsx @@ -1,11 +1,15 @@ import React, { useState } from "react"; + import { useRouter } from "next/router"; + import useSWR from "swr"; + +// react-hook-form import { Controller, SubmitHandler, useForm } from "react-hook-form"; -import { PlusIcon } from "@heroicons/react/24/outline"; -import { Popover, Transition } from "@headlessui/react"; +// react-color import { TwitterPicker } from "react-color"; -import type { NextPageContext, NextPage } from "next"; +// headless ui +import { Popover, Transition } from "@headlessui/react"; // services import projectService from "services/project.service"; import workspaceService from "services/workspace.service"; @@ -13,20 +17,23 @@ import issuesService from "services/issues.service"; // lib import { requiredAdmin } from "lib/auth"; // layouts -import SettingsLayout from "layouts/settings-layout"; +import AppLayout from "layouts/app-layout"; // components import SingleLabel from "components/project/settings/single-label"; // ui import { Button, Input, Loader } from "components/ui"; import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs"; -// fetch-keys -import { PROJECT_DETAILS, PROJECT_ISSUE_LABELS, WORKSPACE_DETAILS } from "constants/fetch-keys"; +// icons +import { PlusIcon } from "@heroicons/react/24/outline"; // types import { IIssueLabels } from "types"; +import type { NextPageContext, NextPage } from "next"; +// fetch-keys +import { PROJECT_DETAILS, PROJECT_ISSUE_LABELS, WORKSPACE_DETAILS } from "constants/fetch-keys"; const defaultValues: Partial = { name: "", - colour: "#ff0000", + color: "#ff0000", }; type TLabelSettingsProps = { @@ -52,7 +59,7 @@ const LabelsSettings: NextPage = (props) => { () => (workspaceSlug ? workspaceService.getWorkspace(workspaceSlug as string) : null) ); - const { data: activeProject } = useSWR( + const { data: projectDetails } = useSWR( workspaceSlug && projectId ? PROJECT_DETAILS(projectId as string) : null, workspaceSlug && projectId ? () => projectService.getProject(workspaceSlug as string, projectId as string) @@ -77,9 +84,9 @@ const LabelsSettings: NextPage = (props) => { ); const handleNewLabel: SubmitHandler = async (formData) => { - if (!activeWorkspace || !activeProject || isSubmitting) return; + if (!activeWorkspace || !projectDetails || isSubmitting) return; await issuesService - .createIssueLabel(activeWorkspace.slug, activeProject.id, formData) + .createIssueLabel(activeWorkspace.slug, projectDetails.id, formData) .then((res) => { reset(defaultValues); mutate((prevData) => [...(prevData ?? []), res], false); @@ -89,16 +96,17 @@ const LabelsSettings: NextPage = (props) => { const editLabel = (label: IIssueLabels) => { setNewLabelForm(true); - setValue("colour", label.colour); + setValue("color", label.color); setValue("name", label.name); setIsUpdating(true); setLabelIdForUpdate(label.id); }; const handleLabelUpdate: SubmitHandler = async (formData) => { - if (!activeWorkspace || !activeProject || isSubmitting) return; + if (!activeWorkspace || !projectDetails || isSubmitting) return; + await issuesService - .patchIssueLabel(activeWorkspace.slug, activeProject.id, labelIdForUpdate ?? "", formData) + .patchIssueLabel(activeWorkspace.slug, projectDetails.id, labelIdForUpdate ?? "", formData) .then((res) => { console.log(res); reset(defaultValues); @@ -112,10 +120,10 @@ const LabelsSettings: NextPage = (props) => { }; const handleLabelDelete = (labelId: string) => { - if (activeWorkspace && activeProject) { + if (activeWorkspace && projectDetails) { mutate((prevData) => prevData?.filter((p) => p.id !== labelId), false); issuesService - .deleteIssueLabel(activeWorkspace.slug, activeProject.id, labelId) + .deleteIssueLabel(activeWorkspace.slug, projectDetails.id, labelId) .then((res) => { console.log(res); }) @@ -126,14 +134,14 @@ const LabelsSettings: NextPage = (props) => { }; return ( - @@ -170,13 +178,13 @@ const LabelsSettings: NextPage = (props) => { open ? "text-gray-900" : "text-gray-500" }`} > - {watch("colour") && watch("colour") !== "" && ( + {watch("color") && watch("color") !== "" && ( + /> )} @@ -191,7 +199,7 @@ const LabelsSettings: NextPage = (props) => { > ( = (props) => { - + ); }; diff --git a/apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/members.tsx b/apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/members.tsx index 0c9e90029..f8510b73a 100644 --- a/apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/members.tsx +++ b/apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/members.tsx @@ -2,9 +2,8 @@ import { useState } from "react"; import Image from "next/image"; import { useRouter } from "next/router"; + import useSWR from "swr"; -import { PlusIcon } from "@heroicons/react/24/outline"; -import type { NextPage, NextPageContext } from "next"; // services import projectService from "services/project.service"; @@ -13,10 +12,8 @@ import workspaceService from "services/workspace.service"; import { requiredAdmin } from "lib/auth"; // hooks import useToast from "hooks/use-toast"; -// constants -import { ROLE } from "constants/"; // layouts -import SettingsLayout from "layouts/settings-layout"; +import AppLayout from "layouts/app-layout"; // components import ConfirmProjectMemberRemove from "components/project/confirm-project-member-remove"; import SendProjectInvitationModal from "components/project/send-project-invitation-modal"; @@ -24,6 +21,9 @@ import SendProjectInvitationModal from "components/project/send-project-invitati import { Button, CustomListbox, CustomMenu, Loader } from "components/ui"; import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs"; // icons +import { PlusIcon } from "@heroicons/react/24/outline"; +// types +import type { NextPage, NextPageContext } from "next"; // fetch-keys import { PROJECT_DETAILS, @@ -31,6 +31,8 @@ import { PROJECT_MEMBERS, WORKSPACE_DETAILS, } from "constants/fetch-keys"; +// constants +import { ROLE } from "constants/workspace"; type TMemberSettingsProps = { isMember: boolean; @@ -58,7 +60,7 @@ const MembersSettings: NextPage = (props) => { () => (workspaceSlug ? workspaceService.getWorkspace(workspaceSlug as string) : null) ); - const { data: activeProject } = useSWR( + const { data: projectDetails } = useSWR( workspaceSlug && projectId ? PROJECT_DETAILS(projectId as string) : null, workspaceSlug && projectId ? () => projectService.getProject(workspaceSlug as string, projectId as string) @@ -120,11 +122,11 @@ const MembersSettings: NextPage = (props) => { (item) => item.id === selectedRemoveMember || item.id === selectedInviteRemoveMember )} handleDelete={async () => { - if (!activeWorkspace || !activeProject) return; + if (!activeWorkspace || !projectDetails) return; if (selectedRemoveMember) { await projectService.deleteProjectMember( activeWorkspace.slug, - activeProject.id, + projectDetails.id, selectedRemoveMember ); mutateMembers( @@ -135,7 +137,7 @@ const MembersSettings: NextPage = (props) => { if (selectedInviteRemoveMember) { await projectService.deleteProjectInvitation( activeWorkspace.slug, - activeProject.id, + projectDetails.id, selectedInviteRemoveMember ); mutateInvitations( @@ -155,14 +157,14 @@ const MembersSettings: NextPage = (props) => { setIsOpen={setInviteModal} members={members} /> - @@ -235,11 +237,11 @@ const MembersSettings: NextPage = (props) => { title={ROLE[member.role as keyof typeof ROLE] ?? "Select Role"} value={member.role} onChange={(value) => { - if (!activeWorkspace || !activeProject) return; + if (!activeWorkspace || !projectDetails) return; projectService .updateProjectMember( activeWorkspace.slug, - activeProject.id, + projectDetails.id, member.id, { role: value, @@ -306,7 +308,7 @@ const MembersSettings: NextPage = (props) => { )} - + ); }; diff --git a/apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/states.tsx b/apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/states.tsx index 34549b0d5..52a095b2a 100644 --- a/apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/states.tsx +++ b/apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/states.tsx @@ -11,7 +11,7 @@ import projectService from "services/project.service"; // lib import { requiredAdmin } from "lib/auth"; // layouts -import SettingsLayout from "layouts/settings-layout"; +import AppLayout from "layouts/app-layout"; // components import { CreateUpdateStateInline, DeleteStateModal, StateGroup } from "components/states"; // ui @@ -43,7 +43,7 @@ const StatesSettings: NextPage = (props) => { query: { workspaceSlug, projectId }, } = useRouter(); - const { data: activeProject } = useSWR( + const { data: projectDetails } = useSWR( workspaceSlug && projectId ? PROJECT_DETAILS(projectId as string) : null, workspaceSlug && projectId ? () => projectService.getProject(workspaceSlug as string, projectId as string) @@ -68,14 +68,14 @@ const StatesSettings: NextPage = (props) => { data={states?.find((state) => state.id === selectDeleteState) ?? null} onClose={() => setSelectDeleteState(null)} /> - @@ -87,7 +87,7 @@ const StatesSettings: NextPage = (props) => {

Manage the state of this project.

- {states && activeProject ? ( + {states && projectDetails ? ( Object.keys(groupedStates).map((key) => (
@@ -104,7 +104,7 @@ const StatesSettings: NextPage = (props) => {
{key === activeGroup && ( { setActiveGroup(null); setSelectedState(null); @@ -143,7 +143,7 @@ const StatesSettings: NextPage = (props) => { ) : (
{ setActiveGroup(null); setSelectedState(null); @@ -168,7 +168,7 @@ const StatesSettings: NextPage = (props) => { )}
- + ); }; diff --git a/apps/app/pages/[workspaceSlug]/settings/billing.tsx b/apps/app/pages/[workspaceSlug]/settings/billing.tsx index b1af24365..38758ffdc 100644 --- a/apps/app/pages/[workspaceSlug]/settings/billing.tsx +++ b/apps/app/pages/[workspaceSlug]/settings/billing.tsx @@ -1,19 +1,21 @@ import React from "react"; import { useRouter } from "next/router"; + import useSWR from "swr"; // lib -import type { NextPage, GetServerSideProps } from "next"; import { requiredWorkspaceAdmin } from "lib/auth"; -// constants // services import workspaceService from "services/workspace.service"; // layouts -import SettingsLayout from "layouts/settings-layout"; +import AppLayout from "layouts/app-layout"; // ui import { Button } from "components/ui"; import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs"; +// types +import type { NextPage, GetServerSideProps } from "next"; +// fetch-keys import { WORKSPACE_DETAILS } from "constants/fetch-keys"; type TBillingSettingsProps = { @@ -35,9 +37,9 @@ const BillingSettings: NextPage = (props) => { return ( <> - = (props) => {
- + ); }; diff --git a/apps/app/pages/[workspaceSlug]/settings/features.tsx b/apps/app/pages/[workspaceSlug]/settings/features.tsx deleted file mode 100644 index a5deede27..000000000 --- a/apps/app/pages/[workspaceSlug]/settings/features.tsx +++ /dev/null @@ -1,173 +0,0 @@ -import React from "react"; - -import { useRouter } from "next/router"; -import useSWR from "swr"; - -// lib -import type { GetServerSideProps, NextPage } from "next"; -import { requiredWorkspaceAdmin } from "lib/auth"; -// constants -// services -import workspaceService from "services/workspace.service"; -// layouts -import SettingsLayout from "layouts/settings-layout"; -// ui -import { Button } from "components/ui"; -import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs"; -import { WORKSPACE_DETAILS } from "constants/fetch-keys"; - -type TFeatureSettingsProps = { - isOwner: boolean; - isMember: boolean; - isViewer: boolean; - isGuest: boolean; -}; - -const FeaturesSettings: NextPage = (props) => { - const { - query: { workspaceSlug }, - } = useRouter(); - - const { data: activeWorkspace } = useSWR( - workspaceSlug ? WORKSPACE_DETAILS(workspaceSlug as string) : null, - () => (workspaceSlug ? workspaceService.getWorkspace(workspaceSlug as string) : null) - ); - - return ( - <> - - - - - } - > -
-
-

Workspace Features

-
-
-
-
-

Use modules

-

- Modules are enabled for all the projects in this workspace. Access it from the - navigation bar. -

-
-
- {/* Disabled- bg-gray-200, translate-x-0 */} - -
-
-
-
-

Use cycles

-

- Cycles are enabled for all the projects in this workspace. Access it from the - navigation bar. -

-
-
- {/* Disabled- bg-gray-200, translate-x-0 */} - -
-
-
-
-

Use backlogs

-

- Backlog are enabled for all the projects in this workspace. Access it from the - navigation bar. -

-
-
- {/* Disabled- bg-gray-200, translate-x-0 */} - -
-
- -
-
-
- - ); -}; - -export const getServerSideProps: GetServerSideProps = async (ctx) => { - const workspaceSlug = ctx.params?.workspaceSlug as string; - - const memberDetail = await requiredWorkspaceAdmin(workspaceSlug, ctx.req.headers.cookie); - - if (memberDetail === null) { - return { - redirect: { - destination: "/", - permanent: false, - }, - }; - } - - return { - props: { - isOwner: memberDetail?.role === 20, - isMember: memberDetail?.role === 15, - isViewer: memberDetail?.role === 10, - isGuest: memberDetail?.role === 5, - }, - }; -}; - -export default FeaturesSettings; diff --git a/apps/app/pages/[workspaceSlug]/settings/index.tsx b/apps/app/pages/[workspaceSlug]/settings/index.tsx index 1de6ee9fa..5ee704bce 100644 --- a/apps/app/pages/[workspaceSlug]/settings/index.tsx +++ b/apps/app/pages/[workspaceSlug]/settings/index.tsx @@ -17,7 +17,7 @@ import { requiredWorkspaceAdmin } from "lib/auth"; import workspaceService from "services/workspace.service"; import fileServices from "services/file.service"; // layouts -import SettingsLayout from "layouts/settings-layout"; +import AppLayout from "layouts/app-layout"; // hooks import useToast from "hooks/use-toast"; // components @@ -35,7 +35,7 @@ import type { GetServerSideProps, NextPage } from "next"; // fetch-keys import { WORKSPACE_DETAILS, USER_WORKSPACES } from "constants/fetch-keys"; // constants -import { companySize } from "constants/"; +import { COMPANY_SIZE } from "constants/workspace"; const defaultValues: Partial = { name: "", @@ -85,11 +85,13 @@ const WorkspaceSettings: NextPage = (props) => { const onSubmit = async (formData: IWorkspace) => { if (!activeWorkspace) return; + const payload: Partial = { logo: formData.logo, name: formData.name, company_size: formData.company_size, }; + await workspaceService .updateWorkspace(activeWorkspace.slug, payload) .then((res) => { @@ -106,9 +108,9 @@ const WorkspaceSettings: NextPage = (props) => { }; return ( - = (props) => { label={value ? value.toString() : "Select company size"} input > - {companySize?.map((item) => ( + {COMPANY_SIZE?.map((item) => ( {item.label} @@ -315,7 +317,7 @@ const WorkspaceSettings: NextPage = (props) => {
)} -
+ ); }; diff --git a/apps/app/pages/[workspaceSlug]/settings/members.tsx b/apps/app/pages/[workspaceSlug]/settings/members.tsx index a4e8c9166..e3bbcd2fc 100644 --- a/apps/app/pages/[workspaceSlug]/settings/members.tsx +++ b/apps/app/pages/[workspaceSlug]/settings/members.tsx @@ -2,29 +2,31 @@ import { useState } from "react"; import Image from "next/image"; import { useRouter } from "next/router"; + import useSWR from "swr"; -import { PlusIcon } from "@heroicons/react/24/outline"; // lib -import type { GetServerSideProps, NextPage } from "next"; import { requiredWorkspaceAdmin } from "lib/auth"; // hooks import useToast from "hooks/use-toast"; // services import workspaceService from "services/workspace.service"; -// constants // layouts -import SettingsLayout from "layouts/settings-layout"; +import AppLayout from "layouts/app-layout"; // components import ConfirmWorkspaceMemberRemove from "components/workspace/confirm-workspace-member-remove"; import SendWorkspaceInvitationModal from "components/workspace/send-workspace-invitation-modal"; // ui import { Button, CustomListbox, CustomMenu, Loader } from "components/ui"; import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs"; -import { ROLE } from "constants/"; // icons +import { PlusIcon } from "@heroicons/react/24/outline"; +// types +import type { GetServerSideProps, NextPage } from "next"; // fetch-keys import { WORKSPACE_DETAILS, WORKSPACE_INVITATIONS, WORKSPACE_MEMBERS } from "constants/fetch-keys"; +// constants +import { ROLE } from "constants/workspace"; type TMembersSettingsProps = { isOwner: boolean; @@ -135,11 +137,9 @@ const MembersSettings: NextPage = (props) => { workspace_slug={workspaceSlug as string} members={members} /> - = (props) => { )} - + ); }; diff --git a/apps/app/pages/create-workspace.tsx b/apps/app/pages/create-workspace.tsx index fcacbcedf..2c4b1a6a4 100644 --- a/apps/app/pages/create-workspace.tsx +++ b/apps/app/pages/create-workspace.tsx @@ -25,7 +25,7 @@ import type { NextPage, NextPageContext } from "next"; // fetch-keys import { USER_WORKSPACES } from "constants/fetch-keys"; // constants -import { companySize } from "constants/"; +import { COMPANY_SIZE } from "constants/workspace"; const defaultValues = { name: "", @@ -145,7 +145,7 @@ const CreateWorkspace: NextPage = () => { label={value ? value.toString() : "Select company size"} input > - {companySize?.map((item) => ( + {COMPANY_SIZE?.map((item) => ( {item.label} diff --git a/apps/app/pages/error.tsx b/apps/app/pages/error.tsx index fd41671d9..3909a1268 100644 --- a/apps/app/pages/error.tsx +++ b/apps/app/pages/error.tsx @@ -1,21 +1,21 @@ import React from "react"; -import type { NextPage } from "next"; - // layouts import DefaultLayout from "layouts/default-layout"; +// types +import type { NextPage } from "next"; const ErrorPage: NextPage = () => ( - -
-

Error!

-
-
- ); + +
+

Error!

+
+
+); export default ErrorPage; diff --git a/apps/app/pages/magic-sign-in/index.tsx b/apps/app/pages/magic-sign-in/index.tsx index ccfc13268..521373685 100644 --- a/apps/app/pages/magic-sign-in/index.tsx +++ b/apps/app/pages/magic-sign-in/index.tsx @@ -4,15 +4,16 @@ import { useRouter } from "next/router"; import { mutate } from "swr"; +// layouts +import DefaultLayout from "layouts/default-layout"; // services -import type { NextPage } from "next"; import authenticationService from "services/authentication.service"; -// constants // hooks import useUser from "hooks/use-user"; import useToast from "hooks/use-toast"; -// layouts -import DefaultLayout from "layouts/default-layout"; +// types +import type { NextPage } from "next"; +// constants import { USER_WORKSPACES } from "constants/fetch-keys"; const MagicSignIn: NextPage = () => { diff --git a/apps/app/pages/onboarding/index.tsx b/apps/app/pages/onboarding/index.tsx index 68d8f70f9..48f01462b 100644 --- a/apps/app/pages/onboarding/index.tsx +++ b/apps/app/pages/onboarding/index.tsx @@ -2,11 +2,13 @@ import { useState } from "react"; import Image from "next/image"; import { useRouter } from "next/router"; -// hooks -import type { NextPage, NextPageContext } from "next"; -import useUser from "hooks/use-user"; + // lib import { requiredAuth } from "lib/auth"; +// services +import userService from "services/user.service"; +// hooks +import useUser from "hooks/use-user"; // layouts import DefaultLayout from "layouts/default-layout"; // components @@ -20,7 +22,8 @@ import InviteMembers from "components/onboarding/invite-members"; import CommandMenu from "components/onboarding/command-menu"; // images import Logo from "public/onboarding/logo.svg"; -import userService from "services/user.service"; +// types +import type { NextPage, NextPageContext } from "next"; const Onboarding: NextPage = () => { const [step, setStep] = useState(1); diff --git a/apps/app/pages/workspace-member-invitation/[invitationId].tsx b/apps/app/pages/workspace-member-invitation/[invitationId].tsx index 7afe4c7e7..cbbb2fd41 100644 --- a/apps/app/pages/workspace-member-invitation/[invitationId].tsx +++ b/apps/app/pages/workspace-member-invitation/[invitationId].tsx @@ -13,7 +13,6 @@ import { } from "@heroicons/react/24/outline"; // swr // services -import type { NextPage } from "next"; import workspaceService from "services/workspace.service"; // hooks import useUser from "hooks/use-user"; @@ -23,6 +22,8 @@ import DefaultLayout from "layouts/default-layout"; import { Spinner } from "components/ui"; // icons import { EmptySpace, EmptySpaceItem } from "components/ui/empty-space"; +// types +import type { NextPage } from "next"; // constants import { WORKSPACE_INVITATION } from "constants/fetch-keys"; diff --git a/apps/app/types/issues.d.ts b/apps/app/types/issues.d.ts index 4ac7ef9c4..3dcb8c918 100644 --- a/apps/app/types/issues.d.ts +++ b/apps/app/types/issues.d.ts @@ -171,7 +171,7 @@ export interface IIssueLabels { updated_at: Date; name: string; description: string; - colour: string; + color: string; created_by: string; updated_by: string; project: string; diff --git a/apps/app/types/projects.d.ts b/apps/app/types/projects.d.ts index 4a83b90ba..603b8a527 100644 --- a/apps/app/types/projects.d.ts +++ b/apps/app/types/projects.d.ts @@ -1,20 +1,22 @@ import type { IUserLite, IWorkspace } from "./"; export interface IProject { - id: string; - workspace: IWorkspace | string; - default_assignee: IUser | string | null; - project_lead: IUser | string | null; created_at: Date; - updated_at: Date; - name: string; - description: string; - network: number; - identifier: string; - slug: string; created_by: string; - updated_by: string; + cycle_view: boolean; + default_assignee: IUser | string | null; + description: string; icon: string; + id: string; + identifier: string; + module_view: boolean; + name: string; + network: number; + project_lead: IUser | string | null; + slug: string; + updated_at: Date; + updated_by: string; + workspace: IWorkspace | string; } type ProjectViewTheme = {