From a1598e731032d1a60a9765fa08a8add62c3c53b0 Mon Sep 17 00:00:00 2001 From: Dakshesh Jain Date: Thu, 8 Dec 2022 20:29:12 +0530 Subject: [PATCH 1/3] fix: mutation of project detail, removed two identifier validation and added default value for deep checking --- .../components/project/CreateProjectModal.tsx | 32 +++------- apps/app/constants/api-routes.ts | 2 + apps/app/constants/fetch-keys.ts | 2 +- apps/app/constants/index.ts | 2 + apps/app/constants/theme.context.constants.ts | 2 + apps/app/contexts/theme.context.tsx | 62 ++++++++++++++++--- apps/app/lib/hooks/useIssuesFilter.tsx | 62 ++++++++++--------- apps/app/lib/services/project.service.ts | 18 ++++++ apps/app/pages/create-workspace.tsx | 4 +- apps/app/pages/invitations.tsx | 4 +- apps/app/pages/me/my-issues.tsx | 4 +- apps/app/pages/me/profile.tsx | 4 +- .../app/pages/projects/[projectId]/cycles.tsx | 4 +- .../projects/[projectId]/issues/[issueId].tsx | 4 +- .../pages/projects/[projectId]/members.tsx | 4 +- .../pages/projects/[projectId]/settings.tsx | 21 ++++--- apps/app/pages/projects/index.tsx | 4 +- apps/app/pages/workspace/settings.tsx | 5 +- apps/app/types/projects.d.ts | 8 +++ 19 files changed, 170 insertions(+), 78 deletions(-) diff --git a/apps/app/components/project/CreateProjectModal.tsx b/apps/app/components/project/CreateProjectModal.tsx index 6402829dc..fe4047acb 100644 --- a/apps/app/components/project/CreateProjectModal.tsx +++ b/apps/app/components/project/CreateProjectModal.tsx @@ -8,6 +8,8 @@ import { Dialog, Transition } from "@headlessui/react"; // services import projectServices from "lib/services/project.service"; import workspaceService from "lib/services/workspace.service"; +// constants +import { NETWORK_CHOICES } from "constants/"; // fetch keys import { PROJECTS_LIST, WORKSPACE_MEMBERS } from "constants/fetch-keys"; // hooks @@ -15,8 +17,6 @@ import useUser from "lib/hooks/useUser"; import useToast from "lib/hooks/useToast"; // ui import { Button, Input, TextArea, Select } from "ui"; -// common -import { debounce } from "constants/common"; // types import { IProject, WorkspaceMember } from "types"; @@ -25,11 +25,11 @@ type Props = { setIsOpen: React.Dispatch>; }; -const NETWORK_CHOICES = { "0": "Secret", "2": "Public" }; - const defaultValues: Partial = { name: "", + identifier: "", description: "", + network: 0, }; const IsGuestCondition: React.FC<{ @@ -62,7 +62,10 @@ const CreateProjectModal: React.FC = ({ isOpen, setIsOpen }) => { const { data: workspaceMembers } = useSWR( activeWorkspace ? WORKSPACE_MEMBERS(activeWorkspace.slug) : null, - activeWorkspace ? () => workspaceService.workspaceMembers(activeWorkspace.slug) : null + activeWorkspace ? () => workspaceService.workspaceMembers(activeWorkspace.slug) : null, + { + shouldRetryOnError: false, + } ); const { setToastAlert } = useToast(); @@ -79,8 +82,6 @@ const CreateProjectModal: React.FC = ({ isOpen, setIsOpen }) => { setValue, } = useForm({ defaultValues, - reValidateMode: "onChange", - mode: "all", }); const onSubmit = async (formData: IProject) => { @@ -111,6 +112,7 @@ const CreateProjectModal: React.FC = ({ isOpen, setIsOpen }) => { handleClose(); return; } + err = err.data; Object.keys(err).map((key) => { const errorMessages = err[key]; setError(key as keyof IProject, { @@ -123,16 +125,6 @@ const CreateProjectModal: React.FC = ({ isOpen, setIsOpen }) => { const projectName = watch("name") ?? ""; const projectIdentifier = watch("identifier") ?? ""; - const checkIdentifier = (slug: string, value: string) => { - projectServices.checkProjectIdentifierAvailability(slug, value).then((response) => { - console.log(response); - if (response.exists) setError("identifier", { message: "Identifier already exists" }); - }); - }; - - // eslint-disable-next-line react-hooks/exhaustive-deps - const checkIdentifierAvailability = useCallback(debounce(checkIdentifier, 1500), []); - useEffect(() => { if (projectName && isChangeIdentifierRequired) { setValue("identifier", projectName.replace(/ /g, "-").toUpperCase().substring(0, 3)); @@ -234,11 +226,7 @@ const CreateProjectModal: React.FC = ({ isOpen, setIsOpen }) => { placeholder="Enter Project Identifier" error={errors.identifier} register={register} - onChange={(e: any) => { - setIsChangeIdentifierRequired(false); - if (!activeWorkspace || !e.target.value) return; - checkIdentifierAvailability(activeWorkspace.slug, e.target.value); - }} + onChange={() => setIsChangeIdentifierRequired(false)} validations={{ required: "Identifier is required", minLength: { diff --git a/apps/app/constants/api-routes.ts b/apps/app/constants/api-routes.ts index cafd0fb05..fdf3d0bc7 100644 --- a/apps/app/constants/api-routes.ts +++ b/apps/app/constants/api-routes.ts @@ -65,6 +65,8 @@ export const PROJECT_MEMBERS = (workspaceSlug: string, projectId: string) => `/api/workspaces/${workspaceSlug}/projects/${projectId}/members/`; export const PROJECT_MEMBER_DETAIL = (workspaceSlug: string, projectId: string, memberId: string) => `/api/workspaces/${workspaceSlug}/projects/${projectId}/members/${memberId}/`; +export const PROJECT_VIEW_ENDPOINT = (workspaceSlug: string, projectId: string) => + `/api/workspaces/${workspaceSlug}/projects/${projectId}/project-views/`; export const PROJECT_INVITATIONS = (workspaceSlug: string, projectId: string) => `/api/workspaces/${workspaceSlug}/projects/${projectId}/invitations/`; diff --git a/apps/app/constants/fetch-keys.ts b/apps/app/constants/fetch-keys.ts index b8dfa5618..9e3611024 100644 --- a/apps/app/constants/fetch-keys.ts +++ b/apps/app/constants/fetch-keys.ts @@ -7,7 +7,7 @@ export const WORKSPACE_INVITATIONS = "WORKSPACE_INVITATIONS"; export const WORKSPACE_INVITATION = "WORKSPACE_INVITATION"; export const PROJECTS_LIST = (workspaceSlug: string) => `PROJECTS_LIST_${workspaceSlug}`; -export const PROJECT_DETAILS = "PROJECT_DETAILS"; +export const PROJECT_DETAILS = (projectId: string) => `PROJECT_DETAILS_${projectId}`; export const PROJECT_MEMBERS = (projectId: string) => `PROJECT_MEMBERS_${projectId}`; export const PROJECT_INVITATIONS = "PROJECT_INVITATIONS"; diff --git a/apps/app/constants/index.ts b/apps/app/constants/index.ts index 9e319009d..603652e9f 100644 --- a/apps/app/constants/index.ts +++ b/apps/app/constants/index.ts @@ -6,3 +6,5 @@ export const ROLE = { 15: "Member", 20: "Admin", }; + +export const NETWORK_CHOICES = { "0": "Secret", "2": "Public" }; diff --git a/apps/app/constants/theme.context.constants.ts b/apps/app/constants/theme.context.constants.ts index d40e8138e..f170511ed 100644 --- a/apps/app/constants/theme.context.constants.ts +++ b/apps/app/constants/theme.context.constants.ts @@ -2,3 +2,5 @@ export const TOGGLE_SIDEBAR = "TOGGLE_SIDEBAR"; export const REHYDRATE_THEME = "REHYDRATE_THEME"; export const SET_ISSUE_VIEW = "SET_ISSUE_VIEW"; export const SET_GROUP_BY_PROPERTY = "SET_GROUP_BY_PROPERTY"; +export const SET_ORDER_BY_PROPERTY = "SET_ORDER_BY_PROPERTY"; +export const SET_FILTER_ISSUES = "SET_FILTER_ISSUES"; diff --git a/apps/app/contexts/theme.context.tsx b/apps/app/contexts/theme.context.tsx index 6df316ac7..bece44540 100644 --- a/apps/app/contexts/theme.context.tsx +++ b/apps/app/contexts/theme.context.tsx @@ -5,6 +5,8 @@ import { REHYDRATE_THEME, SET_ISSUE_VIEW, SET_GROUP_BY_PROPERTY, + SET_ORDER_BY_PROPERTY, + SET_FILTER_ISSUES, } from "constants/theme.context.constants"; // components import ToastAlert from "components/toast-alert"; @@ -12,30 +14,30 @@ import ToastAlert from "components/toast-alert"; export const themeContext = createContext({} as ContextType); // types -import type { IIssue, NestedKeyOf } from "types"; - -type Theme = { - collapsed: boolean; - issueView: "list" | "kanban" | null; - groupByProperty: NestedKeyOf | null; -}; +import type { IIssue, NestedKeyOf, ProjectViewTheme as Theme } from "types"; type ReducerActionType = { type: | typeof TOGGLE_SIDEBAR | typeof REHYDRATE_THEME | typeof SET_ISSUE_VIEW + | typeof SET_ORDER_BY_PROPERTY + | typeof SET_FILTER_ISSUES | typeof SET_GROUP_BY_PROPERTY; payload?: Partial; }; type ContextType = { collapsed: boolean; + orderBy: NestedKeyOf | null; issueView: "list" | "kanban" | null; groupByProperty: NestedKeyOf | null; + filterIssue: "activeIssue" | "backlogIssue" | null; toggleCollapsed: () => void; setIssueView: (display: "list" | "kanban") => void; setGroupByProperty: (property: NestedKeyOf | null) => void; + setOrderBy: (property: NestedKeyOf | null) => void; + setFilterIssue: (property: "activeIssue" | "backlogIssue" | null) => void; }; type StateType = Theme; @@ -45,6 +47,8 @@ export const initialState: StateType = { collapsed: false, issueView: "list", groupByProperty: null, + orderBy: null, + filterIssue: null, }; export const reducer: ReducerFunctionType = (state, action) => { @@ -87,6 +91,28 @@ export const reducer: ReducerFunctionType = (state, action) => { ...newState, }; } + case SET_ORDER_BY_PROPERTY: { + const newState = { + ...state, + orderBy: payload?.orderBy || null, + }; + localStorage.setItem("theme", JSON.stringify(newState)); + return { + ...state, + ...newState, + }; + } + case SET_FILTER_ISSUES: { + const newState = { + ...state, + filterIssue: payload?.filterIssue || null, + }; + localStorage.setItem("theme", JSON.stringify(newState)); + return { + ...state, + ...newState, + }; + } default: { return state; } @@ -120,6 +146,24 @@ export const ThemeContextProvider: React.FC<{ children: React.ReactNode }> = ({ }); }, []); + const setOrderBy = useCallback((property: NestedKeyOf | null) => { + dispatch({ + type: SET_ORDER_BY_PROPERTY, + payload: { + orderBy: property, + }, + }); + }, []); + + const setFilterIssue = useCallback((property: "activeIssue" | "backlogIssue" | null) => { + dispatch({ + type: SET_FILTER_ISSUES, + payload: { + filterIssue: property, + }, + }); + }, []); + useEffect(() => { dispatch({ type: REHYDRATE_THEME, @@ -135,6 +179,10 @@ export const ThemeContextProvider: React.FC<{ children: React.ReactNode }> = ({ setIssueView, groupByProperty: state.groupByProperty, setGroupByProperty, + orderBy: state.orderBy, + setOrderBy, + filterIssue: state.filterIssue, + setFilterIssue, }} > diff --git a/apps/app/lib/hooks/useIssuesFilter.tsx b/apps/app/lib/hooks/useIssuesFilter.tsx index 3ebf1a2c7..c598691fe 100644 --- a/apps/app/lib/hooks/useIssuesFilter.tsx +++ b/apps/app/lib/hooks/useIssuesFilter.tsx @@ -1,4 +1,3 @@ -import { useState } from "react"; // hooks import useTheme from "./useTheme"; import useUser from "./useUser"; @@ -7,14 +6,19 @@ import { groupBy, orderArrayBy } from "constants/common"; // constants import { PRIORITIES } from "constants/"; // types -import type { IssueResponse, IIssue, NestedKeyOf } from "types"; +import type { IssueResponse, IIssue } from "types"; const useIssuesFilter = (projectIssues?: IssueResponse) => { - const { issueView, setIssueView, groupByProperty, setGroupByProperty } = useTheme(); - - const [orderBy, setOrderBy] = useState | null>(null); - - const [filterIssue, setFilterIssue] = useState<"activeIssue" | "backlogIssue" | null>(null); + const { + issueView, + setIssueView, + groupByProperty, + setGroupByProperty, + orderBy, + setOrderBy, + filterIssue, + setFilterIssue, + } = useTheme(); const { states } = useUser(); @@ -52,29 +56,29 @@ const useIssuesFilter = (projectIssues?: IssueResponse) => { if (filterIssue !== null) { if (filterIssue === "activeIssue") { - groupedByIssues = Object.keys(groupedByIssues).reduce((acc, key) => { - const value = groupedByIssues[key]; - const filteredValue = value.filter( - (issue) => - issue.state_detail.group === "started" || issue.state_detail.group === "unstarted" - ); - if (filteredValue.length > 0) { - acc[key] = filteredValue; - } - return acc; - }, {} as typeof groupedByIssues); + const filteredStates = states?.filter( + (state) => state.group === "started" || state.group === "unstarted" + ); + groupedByIssues = Object.fromEntries( + filteredStates + ?.sort((a, b) => a.sequence - b.sequence) + ?.map((state) => [ + state.name, + projectIssues?.results.filter((issue) => issue.state === state.id) ?? [], + ]) ?? [] + ); } else if (filterIssue === "backlogIssue") { - groupedByIssues = Object.keys(groupedByIssues).reduce((acc, key) => { - const value = groupedByIssues[key]; - const filteredValue = value.filter( - (issue) => - issue.state_detail.group === "backlog" || issue.state_detail.group === "cancelled" - ); - if (filteredValue.length > 0) { - acc[key] = filteredValue; - } - return acc; - }, {} as typeof groupedByIssues); + const filteredStates = states?.filter( + (state) => state.group === "backlog" || state.group === "cancelled" + ); + groupedByIssues = Object.fromEntries( + filteredStates + ?.sort((a, b) => a.sequence - b.sequence) + ?.map((state) => [ + state.name, + projectIssues?.results.filter((issue) => issue.state === state.id) ?? [], + ]) ?? [] + ); } } diff --git a/apps/app/lib/services/project.service.ts b/apps/app/lib/services/project.service.ts index 9d0ab3d04..b7b4fe318 100644 --- a/apps/app/lib/services/project.service.ts +++ b/apps/app/lib/services/project.service.ts @@ -10,9 +10,12 @@ import { PROJECT_MEMBERS, PROJECT_MEMBER_DETAIL, USER_PROJECT_INVITATIONS, + PROJECT_VIEW_ENDPOINT, } from "constants/api-routes"; // services import APIService from "lib/services/api.service"; +// types +import type { ProjectViewTheme } from "types"; const { NEXT_PUBLIC_API_BASE_URL } = process.env; @@ -177,6 +180,7 @@ class ProjectServices extends APIService { throw error?.response?.data; }); } + async deleteProjectInvitation( workspace_slug: string, project_id: string, @@ -190,6 +194,20 @@ class ProjectServices extends APIService { throw error?.response?.data; }); } + + async setProjectView( + workspace_slug: string, + project_id: string, + data: ProjectViewTheme + ): Promise { + await this.patch(PROJECT_VIEW_ENDPOINT(workspace_slug, project_id), data) + .then((response) => { + return response?.data; + }) + .catch((error) => { + throw error?.response?.data; + }); + } } export default new ProjectServices(); diff --git a/apps/app/pages/create-workspace.tsx b/apps/app/pages/create-workspace.tsx index 1c5e8dc3e..e996372b6 100644 --- a/apps/app/pages/create-workspace.tsx +++ b/apps/app/pages/create-workspace.tsx @@ -8,6 +8,8 @@ import { useForm } from "react-hook-form"; import workspaceService from "lib/services/workspace.service"; // hooks import useUser from "lib/hooks/useUser"; +// hoc +import withAuth from "lib/hoc/withAuthWrapper"; // layouts import DefaultLayout from "layouts/DefaultLayout"; // ui @@ -144,4 +146,4 @@ const CreateWorkspace: NextPage = () => { ); }; -export default CreateWorkspace; +export default withAuth(CreateWorkspace); diff --git a/apps/app/pages/invitations.tsx b/apps/app/pages/invitations.tsx index 25bb7d324..155128770 100644 --- a/apps/app/pages/invitations.tsx +++ b/apps/app/pages/invitations.tsx @@ -11,6 +11,8 @@ import userService from "lib/services/user.service"; import useUser from "lib/hooks/useUser"; // constants import { USER_WORKSPACE_INVITATIONS } from "constants/api-routes"; +// hoc +import withAuth from "lib/hoc/withAuthWrapper"; // layouts import DefaultLayout from "layouts/DefaultLayout"; // components @@ -204,4 +206,4 @@ const OnBoard: NextPage = () => { ); }; -export default OnBoard; +export default withAuth(OnBoard); diff --git a/apps/app/pages/me/my-issues.tsx b/apps/app/pages/me/my-issues.tsx index 3f3620c66..ee58a0016 100644 --- a/apps/app/pages/me/my-issues.tsx +++ b/apps/app/pages/me/my-issues.tsx @@ -19,6 +19,8 @@ import { classNames } from "constants/common"; // services import userService from "lib/services/user.service"; import issuesServices from "lib/services/issues.services"; +// hoc +import withAuth from "lib/hoc/withAuthWrapper"; // components import ChangeStateDropdown from "components/project/issues/my-issues/ChangeStateDropdown"; // icons @@ -278,4 +280,4 @@ const MyIssues: NextPage = () => { ); }; -export default MyIssues; +export default withAuth(MyIssues); diff --git a/apps/app/pages/me/profile.tsx b/apps/app/pages/me/profile.tsx index 3c3350044..15850d050 100644 --- a/apps/app/pages/me/profile.tsx +++ b/apps/app/pages/me/profile.tsx @@ -8,6 +8,8 @@ import { useForm } from "react-hook-form"; import Dropzone, { useDropzone } from "react-dropzone"; // hooks import useUser from "lib/hooks/useUser"; +// hoc +import withAuth from "lib/hoc/withAuthWrapper"; // layouts import AdminLayout from "layouts/AdminLayout"; // services @@ -307,4 +309,4 @@ const Profile: NextPage = () => { ); }; -export default Profile; +export default withAuth(Profile); diff --git a/apps/app/pages/projects/[projectId]/cycles.tsx b/apps/app/pages/projects/[projectId]/cycles.tsx index 4dd67f129..8aae6f8fa 100644 --- a/apps/app/pages/projects/[projectId]/cycles.tsx +++ b/apps/app/pages/projects/[projectId]/cycles.tsx @@ -11,6 +11,8 @@ import sprintService from "lib/services/cycles.services"; import useUser from "lib/hooks/useUser"; // fetching keys import { CYCLE_ISSUES, CYCLE_LIST } from "constants/fetch-keys"; +// hoc +import withAuth from "lib/hoc/withAuthWrapper"; // layouts import AdminLayout from "layouts/AdminLayout"; // components @@ -258,4 +260,4 @@ const ProjectSprints: NextPage = () => { ); }; -export default ProjectSprints; +export default withAuth(ProjectSprints); diff --git a/apps/app/pages/projects/[projectId]/issues/[issueId].tsx b/apps/app/pages/projects/[projectId]/issues/[issueId].tsx index ef5a6945b..feee4131a 100644 --- a/apps/app/pages/projects/[projectId]/issues/[issueId].tsx +++ b/apps/app/pages/projects/[projectId]/issues/[issueId].tsx @@ -22,6 +22,8 @@ import { } from "constants/fetch-keys"; // hooks import useUser from "lib/hooks/useUser"; +// hoc +import withAuth from "lib/hoc/withAuthWrapper"; // layouts import AdminLayout from "layouts/AdminLayout"; // components @@ -606,4 +608,4 @@ const IssueDetail: NextPage = () => { ); }; -export default IssueDetail; +export default withAuth(IssueDetail); diff --git a/apps/app/pages/projects/[projectId]/members.tsx b/apps/app/pages/projects/[projectId]/members.tsx index f6d0ec9b4..101e3b9f8 100644 --- a/apps/app/pages/projects/[projectId]/members.tsx +++ b/apps/app/pages/projects/[projectId]/members.tsx @@ -14,6 +14,8 @@ import useUser from "lib/hooks/useUser"; import useToast from "lib/hooks/useToast"; // fetching keys import { PROJECT_MEMBERS, PROJECT_INVITATIONS } from "constants/fetch-keys"; +// hoc +import withAuth from "lib/hoc/withAuthWrapper"; // layouts import AdminLayout from "layouts/AdminLayout"; // components @@ -313,4 +315,4 @@ const ProjectMembers: NextPage = () => { ); }; -export default ProjectMembers; +export default withAuth(ProjectMembers); diff --git a/apps/app/pages/projects/[projectId]/settings.tsx b/apps/app/pages/projects/[projectId]/settings.tsx index 264ec1b3a..88645b458 100644 --- a/apps/app/pages/projects/[projectId]/settings.tsx +++ b/apps/app/pages/projects/[projectId]/settings.tsx @@ -10,6 +10,8 @@ import useSWR from "swr"; import { useForm, Controller } from "react-hook-form"; // headless ui import { Listbox, Tab, Transition } from "@headlessui/react"; +// hoc +import withAuth from "lib/hoc/withAuthWrapper"; // layouts import AdminLayout from "layouts/AdminLayout"; // service @@ -20,6 +22,8 @@ import useUser from "lib/hooks/useUser"; import useToast from "lib/hooks/useToast"; // fetch keys import { PROJECT_DETAILS, PROJECTS_LIST, WORKSPACE_MEMBERS } from "constants/fetch-keys"; +// constants +import { NETWORK_CHOICES } from "constants/"; // commons import { addSpaceIfCamelCase, debounce } from "constants/common"; // components @@ -44,8 +48,6 @@ const defaultValues: Partial = { description: "", }; -const NETWORK_CHOICES = { "0": "Secret", "2": "Public" }; - const ProjectSettings: NextPage = () => { const { register, @@ -71,7 +73,7 @@ const ProjectSettings: NextPage = () => { const { setToastAlert } = useToast(); const { data: projectDetails } = useSWR( - activeWorkspace && projectId ? PROJECT_DETAILS : null, + activeWorkspace && projectId ? PROJECT_DETAILS(projectId as string) : null, activeWorkspace ? () => projectServices.getProject(activeWorkspace.slug, projectId as string) : null @@ -99,7 +101,7 @@ const ProjectSettings: NextPage = () => { }, [projectDetails, reset]); const onSubmit = async (formData: IProject) => { - if (!activeWorkspace) return; + if (!activeWorkspace || !projectId) return; const payload: Partial = { name: formData.name, network: formData.network, @@ -111,7 +113,11 @@ const ProjectSettings: NextPage = () => { await projectServices .updateProject(activeWorkspace.slug, projectId as string, payload) .then((res) => { - mutate(PROJECT_DETAILS, (prevData) => ({ ...prevData, ...res }), false); + mutate( + PROJECT_DETAILS(projectId as string), + (prevData) => ({ ...prevData, ...res }), + false + ); mutate( PROJECTS_LIST(activeWorkspace.slug), (prevData) => { @@ -253,9 +259,6 @@ const ProjectSettings: NextPage = () => { register={register} label="Description" placeholder="Enter project description" - validations={{ - required: "Description is required", - }} />
@@ -547,4 +550,4 @@ const ProjectSettings: NextPage = () => { ); }; -export default ProjectSettings; +export default withAuth(ProjectSettings); diff --git a/apps/app/pages/projects/index.tsx b/apps/app/pages/projects/index.tsx index f55b07abb..39cc8d360 100644 --- a/apps/app/pages/projects/index.tsx +++ b/apps/app/pages/projects/index.tsx @@ -3,6 +3,8 @@ import React, { useEffect, useState } from "react"; import type { NextPage } from "next"; // hooks import useUser from "lib/hooks/useUser"; +// hoc +import withAuth from "lib/hoc/withAuthWrapper"; // layouts import AdminLayout from "layouts/AdminLayout"; // components @@ -129,4 +131,4 @@ const Projects: NextPage = () => { ); }; -export default Projects; +export default withAuth(Projects); diff --git a/apps/app/pages/workspace/settings.tsx b/apps/app/pages/workspace/settings.tsx index eaa20d1c9..478d87f65 100644 --- a/apps/app/pages/workspace/settings.tsx +++ b/apps/app/pages/workspace/settings.tsx @@ -8,9 +8,10 @@ import Dropzone from "react-dropzone"; // services import workspaceService from "lib/services/workspace.service"; import fileServices from "lib/services/file.services"; +// hoc +import withAuth from "lib/hoc/withAuthWrapper"; // layouts import AdminLayout from "layouts/AdminLayout"; - // hooks import useUser from "lib/hooks/useUser"; import useToast from "lib/hooks/useToast"; @@ -232,4 +233,4 @@ const WorkspaceSettings = () => { ); }; -export default WorkspaceSettings; +export default withAuth(WorkspaceSettings); diff --git a/apps/app/types/projects.d.ts b/apps/app/types/projects.d.ts index da80eec29..6b421b010 100644 --- a/apps/app/types/projects.d.ts +++ b/apps/app/types/projects.d.ts @@ -15,3 +15,11 @@ export interface IProject { created_by: string; updated_by: string; } + +type ProjectViewTheme = { + collapsed: boolean; + issueView: "list" | "kanban" | null; + groupByProperty: NestedKeyOf | null; + filterIssue: "activeIssue" | "backlogIssue" | null; + orderBy: NestedKeyOf | null; +}; From fe7284b9b060be7dba646c1ea0f0cae90e45f78e Mon Sep 17 00:00:00 2001 From: Dakshesh Jain Date: Mon, 12 Dec 2022 10:19:52 +0530 Subject: [PATCH 2/3] refractor: added types to workspace and project services, naming convention --- apps/app/.env.example | 4 + .../command-palette/addAsSubIssue.tsx | 2 +- apps/app/components/command-palette/index.tsx | 4 +- .../project/SendProjectInvitationModal.tsx | 9 +- ...jectModal.tsx => create-project-modal.tsx} | 62 ++++++++++++-- .../project/cycles/ConfirmCycleDeletion.tsx | 2 +- .../cycles/CreateUpdateCyclesModal.tsx | 2 +- .../project/cycles/CycleIssuesListModal.tsx | 2 +- .../components/project/cycles/CycleView.tsx | 4 +- .../project/issues/BoardView/index.tsx | 8 +- .../BoardView/state/ConfirmStateDeletion.tsx | 13 ++- .../state/CreateUpdateStateModal.tsx | 2 +- .../project/issues/ConfirmIssueDeletion.tsx | 2 +- .../CreateUpdateIssueModal/SelectAssignee.tsx | 4 +- .../CreateUpdateIssueModal/SelectLabels.tsx | 2 +- .../issues/CreateUpdateIssueModal/index.tsx | 2 +- .../project/issues/ListView/index.tsx | 6 +- .../issue-detail/IssueDetailSidebar.tsx | 15 +--- .../comment/IssueCommentSection.tsx | 2 +- .../issues/my-issues/ChangeStateDropdown.tsx | 2 +- .../project/settings/ControlSettings.tsx | 4 +- .../project/settings/LabelsSettings.tsx | 2 +- .../SendWorkspaceInvitationModal.tsx | 6 +- .../components/workspace/SingleInvitation.tsx | 4 +- apps/app/constants/common.ts | 9 ++ apps/app/contexts/user.context.tsx | 6 +- apps/app/layouts/AppLayout.tsx | 2 +- apps/app/layouts/Navbar/Sidebar.tsx | 12 +-- apps/app/lib/hooks/useIssuesProperties.tsx | 2 +- .../{cycles.services.ts => cycles.service.ts} | 0 .../{file.services.ts => file.service.ts} | 0 .../{issues.services.ts => issues.service.ts} | 0 apps/app/lib/services/project.service.ts | 83 ++++++++++--------- .../{state.services.ts => state.service.ts} | 0 apps/app/lib/services/workspace.service.ts | 77 ++++++++++------- apps/app/pages/invitations.tsx | 9 +- apps/app/pages/me/my-issues.tsx | 2 +- apps/app/pages/me/profile.tsx | 9 +- .../app/pages/projects/[projectId]/cycles.tsx | 4 +- .../projects/[projectId]/issues/[issueId].tsx | 2 +- .../projects/[projectId]/issues/index.tsx | 4 +- .../pages/projects/[projectId]/members.tsx | 6 +- apps/app/pages/projects/index.tsx | 2 +- .../[invitationId].tsx | 6 +- apps/app/pages/workspace/settings.tsx | 2 +- apps/app/types/invitation.d.ts | 16 ---- apps/app/types/projects.d.ts | 35 +++++++- apps/app/types/users.d.ts | 8 ++ apps/app/types/workspace.d.ts | 30 +++---- 49 files changed, 294 insertions(+), 197 deletions(-) create mode 100644 apps/app/.env.example rename apps/app/components/project/{CreateProjectModal.tsx => create-project-modal.tsx} (80%) rename apps/app/lib/services/{cycles.services.ts => cycles.service.ts} (100%) rename apps/app/lib/services/{file.services.ts => file.service.ts} (100%) rename apps/app/lib/services/{issues.services.ts => issues.service.ts} (100%) rename apps/app/lib/services/{state.services.ts => state.service.ts} (100%) delete mode 100644 apps/app/types/invitation.d.ts diff --git a/apps/app/.env.example b/apps/app/.env.example new file mode 100644 index 000000000..aff5c6c31 --- /dev/null +++ b/apps/app/.env.example @@ -0,0 +1,4 @@ +NEXT_PUBLIC_API_BASE_URL = "<-- endpoint goes here -->" +NEXT_PUBLIC_GOOGLE_CLIENTID = "<-- google client id goes here -->" +NEXT_PUBLIC_GITHUB_ID = "<-- github id goes here -->" +NEXT_PUBLIC_APP_ENVIRONMENT=development \ No newline at end of file diff --git a/apps/app/components/command-palette/addAsSubIssue.tsx b/apps/app/components/command-palette/addAsSubIssue.tsx index e8c585e45..aadc04574 100644 --- a/apps/app/components/command-palette/addAsSubIssue.tsx +++ b/apps/app/components/command-palette/addAsSubIssue.tsx @@ -7,7 +7,7 @@ import { useForm } from "react-hook-form"; // headless ui import { Combobox, Dialog, Transition } from "@headlessui/react"; // services -import issuesServices from "lib/services/issues.services"; +import issuesServices from "lib/services/issues.service"; // hooks import useUser from "lib/hooks/useUser"; // icons diff --git a/apps/app/components/command-palette/index.tsx b/apps/app/components/command-palette/index.tsx index 63490c97d..32f71a3db 100644 --- a/apps/app/components/command-palette/index.tsx +++ b/apps/app/components/command-palette/index.tsx @@ -8,7 +8,7 @@ import { SubmitHandler, useForm } from "react-hook-form"; // headless ui import { Combobox, Dialog, Transition } from "@headlessui/react"; // services -import issuesServices from "lib/services/issues.services"; +import issuesServices from "lib/services/issues.service"; // hooks import useUser from "lib/hooks/useUser"; import useTheme from "lib/hooks/useTheme"; @@ -22,7 +22,7 @@ import { } from "@heroicons/react/24/outline"; // components import ShortcutsModal from "components/command-palette/shortcuts"; -import CreateProjectModal from "components/project/CreateProjectModal"; +import CreateProjectModal from "components/project/create-project-modal"; import CreateUpdateIssuesModal from "components/project/issues/CreateUpdateIssueModal"; import CreateUpdateCycleModal from "components/project/cycles/CreateUpdateCyclesModal"; // ui diff --git a/apps/app/components/project/SendProjectInvitationModal.tsx b/apps/app/components/project/SendProjectInvitationModal.tsx index 0c0485803..6227c569f 100644 --- a/apps/app/components/project/SendProjectInvitationModal.tsx +++ b/apps/app/components/project/SendProjectInvitationModal.tsx @@ -20,7 +20,7 @@ import { Button, Select, TextArea } from "ui"; import { ChevronDownIcon, CheckIcon } from "@heroicons/react/20/solid"; // types -import { ProjectMember, WorkspaceMember } from "types"; +import { IProjectMemberInvitation } from "types"; type Props = { isOpen: boolean; @@ -28,6 +28,11 @@ type Props = { members: any[]; }; +type ProjectMember = IProjectMemberInvitation & { + member_id: string; + user_id: string; +}; + const defaultValues: Partial = { email: "", message: "", @@ -49,7 +54,7 @@ const SendProjectInvitationModal: React.FC = ({ isOpen, setIsOpen, member const { setToastAlert } = useToast(); - const { data: people } = useSWR( + const { data: people } = useSWR( activeWorkspace ? WORKSPACE_MEMBERS(activeWorkspace.slug) : null, activeWorkspace ? () => workspaceService.workspaceMembers(activeWorkspace.slug) : null, { diff --git a/apps/app/components/project/CreateProjectModal.tsx b/apps/app/components/project/create-project-modal.tsx similarity index 80% rename from apps/app/components/project/CreateProjectModal.tsx rename to apps/app/components/project/create-project-modal.tsx index b3fb53ee3..f6ad48a78 100644 --- a/apps/app/components/project/CreateProjectModal.tsx +++ b/apps/app/components/project/create-project-modal.tsx @@ -1,4 +1,4 @@ -import React, { useState, useEffect, useCallback } from "react"; +import React, { useState, useEffect } from "react"; // swr import useSWR, { mutate } from "swr"; // react hook form @@ -8,6 +8,8 @@ import { Dialog, Transition } from "@headlessui/react"; // services import projectServices from "lib/services/project.service"; import workspaceService from "lib/services/workspace.service"; +// common +import { createSimilarString } from "constants/common"; // constants import { NETWORK_CHOICES } from "constants/"; // fetch keys @@ -18,7 +20,7 @@ import useToast from "lib/hooks/useToast"; // ui import { Button, Input, TextArea, Select } from "ui"; // types -import { IProject, WorkspaceMember } from "types"; +import { IProject } from "types"; type Props = { isOpen: boolean; @@ -60,7 +62,7 @@ const CreateProjectModal: React.FC = ({ isOpen, setIsOpen }) => { const { activeWorkspace, user } = useUser(); - const { data: workspaceMembers } = useSWR( + const { data: workspaceMembers } = useSWR( activeWorkspace ? WORKSPACE_MEMBERS(activeWorkspace.slug) : null, activeWorkspace ? () => workspaceService.workspaceMembers(activeWorkspace.slug) : null, { @@ -68,6 +70,8 @@ const CreateProjectModal: React.FC = ({ isOpen, setIsOpen }) => { } ); + const [recommendedIdentifier, setRecommendedIdentifier] = useState([]); + const { setToastAlert } = useToast(); const [isChangeIdentifierRequired, setIsChangeIdentifierRequired] = useState(true); @@ -78,6 +82,7 @@ const CreateProjectModal: React.FC = ({ isOpen, setIsOpen }) => { handleSubmit, reset, setError, + clearErrors, watch, setValue, } = useForm({ @@ -125,12 +130,6 @@ const CreateProjectModal: React.FC = ({ isOpen, setIsOpen }) => { const projectName = watch("name") ?? ""; const projectIdentifier = watch("identifier") ?? ""; - useEffect(() => { - if (projectName && isChangeIdentifierRequired) { - setValue("identifier", projectName.replace(/ /g, "-").toUpperCase().substring(0, 3)); - } - }, [projectName, projectIdentifier, setValue, isChangeIdentifierRequired]); - if (workspaceMembers) { const isMember = workspaceMembers.find((member) => member.member.id === user?.id); const isGuest = workspaceMembers.find( @@ -140,6 +139,30 @@ const CreateProjectModal: React.FC = ({ isOpen, setIsOpen }) => { if ((!isMember || isGuest) && isOpen) return ; } + useEffect(() => { + if (projectName && isChangeIdentifierRequired) { + setValue("identifier", projectName.replace(/ /g, "").toUpperCase().substring(0, 3)); + } + }, [projectName, projectIdentifier, setValue, isChangeIdentifierRequired]); + + useEffect(() => { + if (!projectName) return; + const suggestedIdentifier = createSimilarString( + projectName.replace(/ /g, "").toUpperCase().substring(0, 3) + ); + + setRecommendedIdentifier([ + suggestedIdentifier + Math.floor(Math.random() * 101), + suggestedIdentifier + Math.floor(Math.random() * 101), + projectIdentifier.toUpperCase().substring(0, 3) + Math.floor(Math.random() * 101), + projectIdentifier.toUpperCase().substring(0, 3) + Math.floor(Math.random() * 101), + ]); + }, [errors.identifier]); + + useEffect(() => { + return () => setIsChangeIdentifierRequired(true); + }, [isOpen]); + return ( @@ -239,6 +262,27 @@ const CreateProjectModal: React.FC = ({ isOpen, setIsOpen }) => { }, }} /> + {errors.identifier && ( +
+

Ops! Identifier is already taken. Try one of the following:

+
+ {recommendedIdentifier.map((identifier) => ( + + ))} +
+
+ )}
diff --git a/apps/app/components/project/cycles/ConfirmCycleDeletion.tsx b/apps/app/components/project/cycles/ConfirmCycleDeletion.tsx index fb5cf565b..b3571831a 100644 --- a/apps/app/components/project/cycles/ConfirmCycleDeletion.tsx +++ b/apps/app/components/project/cycles/ConfirmCycleDeletion.tsx @@ -4,7 +4,7 @@ import { mutate } from "swr"; // headless ui import { Dialog, Transition } from "@headlessui/react"; // services -import cycleService from "lib/services/cycles.services"; +import cycleService from "lib/services/cycles.service"; // fetch api import { CYCLE_LIST } from "constants/fetch-keys"; // hooks diff --git a/apps/app/components/project/cycles/CreateUpdateCyclesModal.tsx b/apps/app/components/project/cycles/CreateUpdateCyclesModal.tsx index 0fd25f481..3f3127082 100644 --- a/apps/app/components/project/cycles/CreateUpdateCyclesModal.tsx +++ b/apps/app/components/project/cycles/CreateUpdateCyclesModal.tsx @@ -6,7 +6,7 @@ import { useForm } from "react-hook-form"; // headless import { Dialog, Transition } from "@headlessui/react"; // services -import cycleService from "lib/services/cycles.services"; +import cycleService from "lib/services/cycles.service"; // fetch keys import { CYCLE_LIST } from "constants/fetch-keys"; // hooks diff --git a/apps/app/components/project/cycles/CycleIssuesListModal.tsx b/apps/app/components/project/cycles/CycleIssuesListModal.tsx index 5f29a5bfd..d25d069df 100644 --- a/apps/app/components/project/cycles/CycleIssuesListModal.tsx +++ b/apps/app/components/project/cycles/CycleIssuesListModal.tsx @@ -7,7 +7,7 @@ import { Combobox, Dialog, Transition } from "@headlessui/react"; // ui import { Button } from "ui"; // services -import issuesServices from "lib/services/issues.services"; +import issuesServices from "lib/services/issues.service"; // hooks import useUser from "lib/hooks/useUser"; import useToast from "lib/hooks/useToast"; diff --git a/apps/app/components/project/cycles/CycleView.tsx b/apps/app/components/project/cycles/CycleView.tsx index f46079165..73a0d0af4 100644 --- a/apps/app/components/project/cycles/CycleView.tsx +++ b/apps/app/components/project/cycles/CycleView.tsx @@ -7,7 +7,7 @@ import useSWR, { mutate } from "swr"; // headless ui import { Disclosure, Transition, Menu } from "@headlessui/react"; // services -import cycleServices from "lib/services/cycles.services"; +import cycleServices from "lib/services/cycles.service"; // hooks import useUser from "lib/hooks/useUser"; // components @@ -22,7 +22,7 @@ import type { CycleViewProps as Props, CycleIssueResponse, IssueResponse } from import { CYCLE_ISSUES } from "constants/fetch-keys"; // constants import { renderShortNumericDateFormat } from "constants/common"; -import issuesServices from "lib/services/issues.services"; +import issuesServices from "lib/services/issues.service"; import StrictModeDroppable from "components/dnd/StrictModeDroppable"; import { Draggable } from "react-beautiful-dnd"; diff --git a/apps/app/components/project/issues/BoardView/index.tsx b/apps/app/components/project/issues/BoardView/index.tsx index fe69a091e..4881f22ed 100644 --- a/apps/app/components/project/issues/BoardView/index.tsx +++ b/apps/app/components/project/issues/BoardView/index.tsx @@ -7,8 +7,8 @@ import useSWR from "swr"; import type { DropResult } from "react-beautiful-dnd"; import { DragDropContext } from "react-beautiful-dnd"; // services -import stateServices from "lib/services/state.services"; -import issuesServices from "lib/services/issues.services"; +import stateServices from "lib/services/state.service"; +import issuesServices from "lib/services/issues.service"; // hooks import useUser from "lib/hooks/useUser"; // fetching keys @@ -20,7 +20,7 @@ import CreateUpdateIssuesModal from "components/project/issues/CreateUpdateIssue // ui import { Spinner } from "ui"; // types -import type { IState, IIssue, Properties, NestedKeyOf, ProjectMember } from "types"; +import type { IState, IIssue, Properties, NestedKeyOf, IProjectMember } from "types"; import ConfirmIssueDeletion from "../ConfirmIssueDeletion"; import { TrashIcon } from "@heroicons/react/24/outline"; @@ -30,7 +30,7 @@ type Props = { groupedByIssues: { [key: string]: IIssue[]; }; - members: ProjectMember[] | undefined; + members: IProjectMember[] | undefined; }; const BoardView: React.FC = ({ properties, selectedGroup, groupedByIssues, members }) => { diff --git a/apps/app/components/project/issues/BoardView/state/ConfirmStateDeletion.tsx b/apps/app/components/project/issues/BoardView/state/ConfirmStateDeletion.tsx index b8754437a..448c50acc 100644 --- a/apps/app/components/project/issues/BoardView/state/ConfirmStateDeletion.tsx +++ b/apps/app/components/project/issues/BoardView/state/ConfirmStateDeletion.tsx @@ -4,7 +4,7 @@ import { mutate } from "swr"; // headless ui import { Dialog, Transition } from "@headlessui/react"; // services -import stateServices from "lib/services/state.services"; +import stateServices from "lib/services/state.service"; // fetch api import { STATE_LIST } from "constants/fetch-keys"; // hooks @@ -43,7 +43,7 @@ const ConfirmStateDeletion: React.FC = ({ isOpen, setIsOpen, data }) => { mutate( STATE_LIST(data.project), (prevData) => prevData?.filter((state) => state.id !== data?.id), - false, + false ); handleClose(); }) @@ -98,18 +98,15 @@ const ConfirmStateDeletion: React.FC = ({ isOpen, setIsOpen, data }) => { />
- + Delete State

Are you sure you want to delete state - {`"`} {data?.name} - {`"`} ? All of the data related to the state will be - permanently removed. This action cannot be undone. + {`"`} ? All of the data related to the state will be permanently removed. + This action cannot be undone.

diff --git a/apps/app/components/project/issues/BoardView/state/CreateUpdateStateModal.tsx b/apps/app/components/project/issues/BoardView/state/CreateUpdateStateModal.tsx index 9f3b3951b..3ba149820 100644 --- a/apps/app/components/project/issues/BoardView/state/CreateUpdateStateModal.tsx +++ b/apps/app/components/project/issues/BoardView/state/CreateUpdateStateModal.tsx @@ -8,7 +8,7 @@ import { TwitterPicker } from "react-color"; // headless import { Dialog, Popover, Transition } from "@headlessui/react"; // services -import stateService from "lib/services/state.services"; +import stateService from "lib/services/state.service"; // fetch keys import { STATE_LIST } from "constants/fetch-keys"; // hooks diff --git a/apps/app/components/project/issues/ConfirmIssueDeletion.tsx b/apps/app/components/project/issues/ConfirmIssueDeletion.tsx index 3b161ae6c..f1476c682 100644 --- a/apps/app/components/project/issues/ConfirmIssueDeletion.tsx +++ b/apps/app/components/project/issues/ConfirmIssueDeletion.tsx @@ -6,7 +6,7 @@ import { Dialog, Transition } from "@headlessui/react"; // fetching keys import { PROJECT_ISSUES_LIST } from "constants/fetch-keys"; // services -import issueServices from "lib/services/issues.services"; +import issueServices from "lib/services/issues.service"; // hooks import useUser from "lib/hooks/useUser"; import useToast from "lib/hooks/useToast"; diff --git a/apps/app/components/project/issues/CreateUpdateIssueModal/SelectAssignee.tsx b/apps/app/components/project/issues/CreateUpdateIssueModal/SelectAssignee.tsx index 376ab65e6..dc5d2b741 100644 --- a/apps/app/components/project/issues/CreateUpdateIssueModal/SelectAssignee.tsx +++ b/apps/app/components/project/issues/CreateUpdateIssueModal/SelectAssignee.tsx @@ -11,7 +11,7 @@ import useUser from "lib/hooks/useUser"; import { PROJECT_MEMBERS } from "constants/fetch-keys"; // types import type { Control } from "react-hook-form"; -import type { IIssue, WorkspaceMember } from "types"; +import type { IIssue } from "types"; import { UserIcon } from "@heroicons/react/24/outline"; import { SearchListbox } from "ui"; @@ -23,7 +23,7 @@ type Props = { const SelectAssignee: React.FC = ({ control }) => { const { activeWorkspace, activeProject } = useUser(); - const { data: people } = useSWR( + const { data: people } = useSWR( activeWorkspace && activeProject ? PROJECT_MEMBERS(activeProject.id) : null, activeWorkspace && activeProject ? () => projectServices.projectMembers(activeWorkspace.slug, activeProject.id) diff --git a/apps/app/components/project/issues/CreateUpdateIssueModal/SelectLabels.tsx b/apps/app/components/project/issues/CreateUpdateIssueModal/SelectLabels.tsx index a7ef75203..6fad13a44 100644 --- a/apps/app/components/project/issues/CreateUpdateIssueModal/SelectLabels.tsx +++ b/apps/app/components/project/issues/CreateUpdateIssueModal/SelectLabels.tsx @@ -6,7 +6,7 @@ import { useForm, Controller } from "react-hook-form"; // headless ui import { Listbox, Transition } from "@headlessui/react"; // services -import issuesServices from "lib/services/issues.services"; +import issuesServices from "lib/services/issues.service"; // hooks import useUser from "lib/hooks/useUser"; // fetching keys diff --git a/apps/app/components/project/issues/CreateUpdateIssueModal/index.tsx b/apps/app/components/project/issues/CreateUpdateIssueModal/index.tsx index b7559d988..14032c6c6 100644 --- a/apps/app/components/project/issues/CreateUpdateIssueModal/index.tsx +++ b/apps/app/components/project/issues/CreateUpdateIssueModal/index.tsx @@ -16,7 +16,7 @@ import { // headless import { Dialog, Menu, Transition } from "@headlessui/react"; // services -import issuesServices from "lib/services/issues.services"; +import issuesServices from "lib/services/issues.service"; // hooks import useUser from "lib/hooks/useUser"; import useToast from "lib/hooks/useToast"; diff --git a/apps/app/components/project/issues/ListView/index.tsx b/apps/app/components/project/issues/ListView/index.tsx index c4a7e19f1..78d5ab68b 100644 --- a/apps/app/components/project/issues/ListView/index.tsx +++ b/apps/app/components/project/issues/ListView/index.tsx @@ -10,14 +10,14 @@ import { Listbox, Transition } from "@headlessui/react"; // icons import { PencilIcon, TrashIcon } from "@heroicons/react/24/outline"; // types -import { IIssue, IssueResponse, NestedKeyOf, Properties, WorkspaceMember } from "types"; +import { IIssue, IssueResponse, NestedKeyOf, Properties } from "types"; // hooks import useUser from "lib/hooks/useUser"; // fetch keys import { PRIORITIES } from "constants/"; import { PROJECT_ISSUES_LIST, WORKSPACE_MEMBERS } from "constants/fetch-keys"; // services -import issuesServices from "lib/services/issues.services"; +import issuesServices from "lib/services/issues.service"; import workspaceService from "lib/services/workspace.service"; // constants import { addSpaceIfCamelCase, classNames, renderShortNumericDateFormat } from "constants/common"; @@ -60,7 +60,7 @@ const ListView: React.FC = ({ }); }; - const { data: people } = useSWR( + const { data: people } = useSWR( activeWorkspace ? WORKSPACE_MEMBERS : null, activeWorkspace ? () => workspaceService.workspaceMembers(activeWorkspace.slug) : null ); diff --git a/apps/app/components/project/issues/issue-detail/IssueDetailSidebar.tsx b/apps/app/components/project/issues/issue-detail/IssueDetailSidebar.tsx index 12f0773f2..71c84a745 100644 --- a/apps/app/components/project/issues/issue-detail/IssueDetailSidebar.tsx +++ b/apps/app/components/project/issues/issue-detail/IssueDetailSidebar.tsx @@ -6,8 +6,8 @@ import { Listbox, Transition } from "@headlessui/react"; // react hook form import { useForm, Controller, UseFormWatch } from "react-hook-form"; // services -import stateServices from "lib/services/state.services"; -import issuesServices from "lib/services/issues.services"; +import stateServices from "lib/services/state.service"; +import issuesServices from "lib/services/issues.service"; import workspaceService from "lib/services/workspace.service"; // hooks import useUser from "lib/hooks/useUser"; @@ -40,14 +40,7 @@ import { } from "@heroicons/react/24/outline"; // types import type { Control } from "react-hook-form"; -import type { - IIssue, - IIssueLabels, - IssueResponse, - IState, - NestedKeyOf, - WorkspaceMember, -} from "types"; +import type { IIssue, IIssueLabels, IssueResponse, IState, NestedKeyOf } from "types"; import { TwitterPicker } from "react-color"; import IssuesListModal from "components/project/issues/IssuesListModal"; @@ -84,7 +77,7 @@ const IssueDetailSidebar: React.FC = ({ : null ); - const { data: people } = useSWR( + const { data: people } = useSWR( activeWorkspace ? WORKSPACE_MEMBERS(activeWorkspace.slug) : null, activeWorkspace ? () => workspaceService.workspaceMembers(activeWorkspace.slug) : null ); diff --git a/apps/app/components/project/issues/issue-detail/comment/IssueCommentSection.tsx b/apps/app/components/project/issues/issue-detail/comment/IssueCommentSection.tsx index 364381ce1..fe07421f1 100644 --- a/apps/app/components/project/issues/issue-detail/comment/IssueCommentSection.tsx +++ b/apps/app/components/project/issues/issue-detail/comment/IssueCommentSection.tsx @@ -4,7 +4,7 @@ import { mutate } from "swr"; // react hook form import { useForm } from "react-hook-form"; // services -import issuesServices from "lib/services/issues.services"; +import issuesServices from "lib/services/issues.service"; // fetch keys import { PROJECT_ISSUES_COMMENTS } from "constants/fetch-keys"; // components diff --git a/apps/app/components/project/issues/my-issues/ChangeStateDropdown.tsx b/apps/app/components/project/issues/my-issues/ChangeStateDropdown.tsx index 1b84fd937..9e90c0e8d 100644 --- a/apps/app/components/project/issues/my-issues/ChangeStateDropdown.tsx +++ b/apps/app/components/project/issues/my-issues/ChangeStateDropdown.tsx @@ -8,7 +8,7 @@ import useUser from "lib/hooks/useUser"; import { addSpaceIfCamelCase, classNames } from "constants/common"; import { STATE_LIST } from "constants/fetch-keys"; // services -import stateServices from "lib/services/state.services"; +import stateServices from "lib/services/state.service"; // ui import { Listbox, Transition } from "@headlessui/react"; // types diff --git a/apps/app/components/project/settings/ControlSettings.tsx b/apps/app/components/project/settings/ControlSettings.tsx index c60ec54f0..5ee4f58ec 100644 --- a/apps/app/components/project/settings/ControlSettings.tsx +++ b/apps/app/components/project/settings/ControlSettings.tsx @@ -15,7 +15,7 @@ import { Button } from "ui"; // icons import { CheckIcon, ChevronDownIcon } from "@heroicons/react/24/outline"; // types -import { IProject, WorkspaceMember } from "types"; +import { IProject } from "types"; // fetch-keys import { WORKSPACE_MEMBERS } from "constants/fetch-keys"; @@ -27,7 +27,7 @@ type Props = { const ControlSettings: React.FC = ({ control, isSubmitting }) => { const { activeWorkspace } = useUser(); - const { data: people } = useSWR( + const { data: people } = useSWR( activeWorkspace ? WORKSPACE_MEMBERS : null, activeWorkspace ? () => workspaceService.workspaceMembers(activeWorkspace.slug) : null ); diff --git a/apps/app/components/project/settings/LabelsSettings.tsx b/apps/app/components/project/settings/LabelsSettings.tsx index 139c005b6..f67ed1d8b 100644 --- a/apps/app/components/project/settings/LabelsSettings.tsx +++ b/apps/app/components/project/settings/LabelsSettings.tsx @@ -7,7 +7,7 @@ import { Controller, SubmitHandler, useForm } from "react-hook-form"; // react-color import { TwitterPicker } from "react-color"; // services -import issuesServices from "lib/services/issues.services"; +import issuesServices from "lib/services/issues.service"; // hooks import useUser from "lib/hooks/useUser"; // headless ui diff --git a/apps/app/components/workspace/SendWorkspaceInvitationModal.tsx b/apps/app/components/workspace/SendWorkspaceInvitationModal.tsx index 8b9e5d99f..5e40c3bce 100644 --- a/apps/app/components/workspace/SendWorkspaceInvitationModal.tsx +++ b/apps/app/components/workspace/SendWorkspaceInvitationModal.tsx @@ -14,7 +14,7 @@ import { Button, Input, TextArea, Select } from "ui"; // hooks import useToast from "lib/hooks/useToast"; // types -import { WorkspaceMember } from "types"; +import { IWorkspaceMemberInvitation } from "types"; type Props = { isOpen: boolean; @@ -30,7 +30,7 @@ const ROLE = { 20: "Admin", }; -const defaultValues: Partial = { +const defaultValues: Partial = { email: "", role: 5, message: "", @@ -57,7 +57,7 @@ const SendWorkspaceInvitationModal: React.FC = ({ formState: { errors, isSubmitting }, handleSubmit, reset, - } = useForm({ + } = useForm({ defaultValues, reValidateMode: "onChange", mode: "all", diff --git a/apps/app/components/workspace/SingleInvitation.tsx b/apps/app/components/workspace/SingleInvitation.tsx index 27614e984..da3483c8a 100644 --- a/apps/app/components/workspace/SingleInvitation.tsx +++ b/apps/app/components/workspace/SingleInvitation.tsx @@ -3,10 +3,10 @@ import Image from "next/image"; // react import { useState } from "react"; // types -import { IWorkspaceInvitation } from "types"; +import { IWorkspaceMemberInvitation } from "types"; type Props = { - invitation: IWorkspaceInvitation; + invitation: IWorkspaceMemberInvitation; invitationsRespond: string[]; handleInvitation: any; }; diff --git a/apps/app/constants/common.ts b/apps/app/constants/common.ts index 1937d65e3..dbc65ebcd 100644 --- a/apps/app/constants/common.ts +++ b/apps/app/constants/common.ts @@ -207,3 +207,12 @@ export const cosineSimilarity = (a: string, b: string) => { return dotProduct / Math.sqrt(magnitudeA * magnitudeB); }; + +export const createSimilarString = (str: string) => { + const shuffled = str + .split("") + .sort(() => Math.random() - 0.5) + .join(""); + + return shuffled; +}; diff --git a/apps/app/contexts/user.context.tsx b/apps/app/contexts/user.context.tsx index 6b52b0939..71f5a7ec8 100644 --- a/apps/app/contexts/user.context.tsx +++ b/apps/app/contexts/user.context.tsx @@ -6,9 +6,9 @@ import { useRouter } from "next/router"; import useSWR from "swr"; // services import userService from "lib/services/user.service"; -import issuesServices from "lib/services/issues.services"; -import stateServices from "lib/services/state.services"; -import sprintsServices from "lib/services/cycles.services"; +import issuesServices from "lib/services/issues.service"; +import stateServices from "lib/services/state.service"; +import sprintsServices from "lib/services/cycles.service"; import projectServices from "lib/services/project.service"; import workspaceService from "lib/services/workspace.service"; // constants diff --git a/apps/app/layouts/AppLayout.tsx b/apps/app/layouts/AppLayout.tsx index c8bd3daa5..dbdddf0a7 100644 --- a/apps/app/layouts/AppLayout.tsx +++ b/apps/app/layouts/AppLayout.tsx @@ -8,7 +8,7 @@ import useUser from "lib/hooks/useUser"; import Container from "layouts/Container"; import Sidebar from "layouts/Navbar/Sidebar"; // components -import CreateProjectModal from "components/project/CreateProjectModal"; +import CreateProjectModal from "components/project/create-project-modal"; // types import type { Props } from "./types"; diff --git a/apps/app/layouts/Navbar/Sidebar.tsx b/apps/app/layouts/Navbar/Sidebar.tsx index 70a510ec4..9f61f9ac8 100644 --- a/apps/app/layouts/Navbar/Sidebar.tsx +++ b/apps/app/layouts/Navbar/Sidebar.tsx @@ -10,8 +10,6 @@ import authenticationService from "lib/services/authentication.service"; import useUser from "lib/hooks/useUser"; import useTheme from "lib/hooks/useTheme"; import useToast from "lib/hooks/useToast"; -// components -import CreateProjectModal from "components/project/CreateProjectModal"; // headless ui import { Dialog, Disclosure, Menu, Transition } from "@headlessui/react"; // icons @@ -108,7 +106,6 @@ const userLinks = [ const Sidebar: React.FC = () => { const [sidebarOpen, setSidebarOpen] = useState(false); - const [isCreateProjectModal, setCreateProjectModal] = useState(false); const router = useRouter(); @@ -124,7 +121,6 @@ const Sidebar: React.FC = () => { return (