Refactoring Phase 1 (#199)

* style: added cta at the bottom of sidebar, added missing icons as well, showing dynamic workspace member count on workspace dropdown

* refractor: running parallel request,

made create/edit label function to async function

* fix: sidebar dropdown content going below kanban items

outside click detection in need help dropdown

* refractor: making parallel api calls

fix: create state input comes at bottom, create state input gets on focus automatically, form is getting submitted on enter click

* refactoring file structure and signin page

* style: changed text and added spinner for signing in loading

* refractor: removed unused type

* fix: my issue cta in profile page sending to 404 page

* fix: added new s3 bucket url in next.config.js file

increased image modal height

* packaging UI components

* eslint config

* eslint fixes

* refactoring changes

* build fixes

* minor fixes

* adding todo comments for reference

* refactor: cleared unused imports and re ordered imports

* refactor: removed unused imports

* fix: added workspace argument to useissues hook

* refactor: removed api-routes file, unnecessary constants

* refactor: created helpers folder, removed unnecessary constants

* refactor: new context for issue view

* refactoring issues page

* build fixes

* refactoring

* refactor: create issue modal

* refactor: module ui

* fix: sub-issues mutation

* fix: create more option in create issue modal

* description form debounce issue

* refactor: global component for assignees list

* fix: link module interface

* fix: priority icons and sub-issues count added

* fix: cycle mutation in issue details page

* fix: remove issue from cycle mutation

* fix: create issue modal in home page

* fix: removed unnecessary props

* fix: updated create issue form status

* fix: settings auth breaking

* refactor: issue details page

Co-authored-by: Dakshesh Jain <dakshesh.jain14@gmail.com>
Co-authored-by: Dakshesh Jain <65905942+dakshesh14@users.noreply.github.com>
Co-authored-by: venkatesh-soulpage <venkatesh.marreboyina@soulpageit.com>
Co-authored-by: Aaryan Khandelwal <aaryankhandu123@gmail.com>
Co-authored-by: Anmol Singh Bhatia <anmolsinghbhatia1001@gmail.com>
This commit is contained in:
sriram veeraghanta 2023-01-26 23:42:20 +05:30 committed by GitHub
parent 9134b0c543
commit 9075f9441c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
322 changed files with 14149 additions and 21378 deletions

View file

@ -1,23 +1,24 @@
import React, { useEffect } from "react";
import { useRouter } from "next/router";
import type { NextPageContext, NextPage } from "next";
import Image from "next/image";
import useSWR, { mutate } from "swr";
import { Controller, useForm } from "react-hook-form";
import type { NextPageContext, NextPage } from "next";
// lib
import { requiredAdmin } from "lib/auth";
// layouts
import SettingsLayout from "layouts/settings-layout";
// services
import projectService from "lib/services/project.service";
import workspaceService from "lib/services/workspace.service";
import projectService from "services/project.service";
import workspaceService from "services/workspace.service";
// hooks
import useToast from "lib/hooks/useToast";
import useToast from "hooks/use-toast";
// ui
import { BreadcrumbItem, Breadcrumbs, Button, CustomSelect, Loader } from "ui";
import { Button, CustomSelect, Loader } from "components/ui";
import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs";
// types
import { IProject, IWorkspace } from "types";
// fetch-keys

View file

@ -1,43 +1,36 @@
import { useCallback, useEffect, useState } from "react";
import { useRouter } from "next/router";
import type { NextPage, NextPageContext } from "next";
import useSWR, { mutate } from "swr";
// react-hook-form
import { Controller, useForm } from "react-hook-form";
// fetch-keys
import { PROJECTS_LIST, PROJECT_DETAILS, WORKSPACE_DETAILS } from "constants/fetch-keys";
// common
import { debounce } from "constants/common";
// constants
import { NETWORK_CHOICES } from "constants/";
import { IProject, IWorkspace } from "types";
// lib
import { requiredAdmin } from "lib/auth";
// layouts
import SettingsLayout from "layouts/settings-layout";
// services
import projectService from "lib/services/project.service";
import workspaceService from "lib/services/workspace.service";
import projectService from "services/project.service";
import workspaceService from "services/workspace.service";
// components
import ConfirmProjectDeletion from "components/project/confirm-project-deletion";
import EmojiIconPicker from "components/emoji-icon-picker";
// hooks
import useToast from "lib/hooks/useToast";
import useToast from "hooks/use-toast";
// ui
import {
BreadcrumbItem,
Breadcrumbs,
Button,
EmojiIconPicker,
Input,
Select,
TextArea,
Loader,
CustomSelect,
} from "ui";
import OutlineButton from "ui/outline-button";
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";
// types
import { IProject, IWorkspace } from "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/";
const defaultValues: Partial<IProject> = {
name: "",
@ -124,19 +117,7 @@ const GeneralSettings: NextPage<TGeneralSettingsProps> = (props) => {
(prevData) => ({ ...prevData, ...res }),
false
);
mutate<IProject[]>(
PROJECTS_LIST(activeWorkspace.slug),
(prevData) => {
const newData = prevData?.map((item) => {
if (item.id === res.id) {
return res;
}
return item;
});
return newData;
},
false
);
mutate(PROJECTS_LIST(activeWorkspace.slug));
setToastAlert({
title: "Success",
type: "success",

View file

@ -1,32 +1,28 @@
import React, { useState } from "react";
import { useRouter } from "next/router";
import type { NextPageContext, NextPage } from "next";
import useSWR from "swr";
import { Controller, SubmitHandler, useForm } from "react-hook-form";
import { PlusIcon } from "@heroicons/react/24/outline";
import { Popover, Transition } from "@headlessui/react";
import { TwitterPicker } from "react-color";
import type { NextPageContext, NextPage } from "next";
// services
import projectService from "lib/services/project.service";
import workspaceService from "lib/services/workspace.service";
import issuesService from "lib/services/issues.service";
import projectService from "services/project.service";
import workspaceService from "services/workspace.service";
import issuesService from "services/issues.service";
// lib
import { requiredAdmin } from "lib/auth";
// layouts
import SettingsLayout from "layouts/settings-layout";
// components
import SingleLabel from "components/project/settings/single-label";
// headless ui
import { Popover, Transition } from "@headlessui/react";
// ui
import { BreadcrumbItem, Breadcrumbs, Button, Input, Loader } from "ui";
// icons
import { PlusIcon } from "@heroicons/react/24/outline";
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";
// types
import { IIssueLabels } from "types";
import { requiredAdmin } from "lib/auth";
const defaultValues: Partial<IIssueLabels> = {
name: "",
@ -57,9 +53,9 @@ const LabelsSettings: NextPage<TLabelSettingsProps> = (props) => {
);
const { data: activeProject } = useSWR(
activeWorkspace && projectId ? PROJECT_DETAILS(projectId as string) : null,
activeWorkspace && projectId
? () => projectService.getProject(activeWorkspace.slug, projectId as string)
workspaceSlug && projectId ? PROJECT_DETAILS(projectId as string) : null,
workspaceSlug && projectId
? () => projectService.getProject(workspaceSlug as string, projectId as string)
: null
);
@ -74,20 +70,21 @@ const LabelsSettings: NextPage<TLabelSettingsProps> = (props) => {
} = useForm<IIssueLabels>({ defaultValues });
const { data: issueLabels, mutate } = useSWR<IIssueLabels[]>(
activeProject && activeWorkspace ? PROJECT_ISSUE_LABELS(activeProject.id) : null,
activeProject && activeWorkspace
? () => issuesService.getIssueLabels(activeWorkspace.slug, activeProject.id)
workspaceSlug && projectId ? PROJECT_ISSUE_LABELS(projectId as string) : null,
workspaceSlug && projectId
? () => issuesService.getIssueLabels(workspaceSlug as string, projectId as string)
: null
);
const handleNewLabel: SubmitHandler<IIssueLabels> = (formData) => {
const handleNewLabel: SubmitHandler<IIssueLabels> = async (formData) => {
if (!activeWorkspace || !activeProject || isSubmitting) return;
issuesService.createIssueLabel(activeWorkspace.slug, activeProject.id, formData).then((res) => {
console.log(res);
reset(defaultValues);
mutate((prevData) => [...(prevData ?? []), res], false);
setNewLabelForm(false);
});
await issuesService
.createIssueLabel(activeWorkspace.slug, activeProject.id, formData)
.then((res) => {
reset(defaultValues);
mutate((prevData) => [...(prevData ?? []), res], false);
setNewLabelForm(false);
});
};
const editLabel = (label: IIssueLabels) => {
@ -98,9 +95,9 @@ const LabelsSettings: NextPage<TLabelSettingsProps> = (props) => {
setLabelIdForUpdate(label.id);
};
const handleLabelUpdate: SubmitHandler<IIssueLabels> = (formData) => {
const handleLabelUpdate: SubmitHandler<IIssueLabels> = async (formData) => {
if (!activeWorkspace || !activeProject || isSubmitting) return;
issuesService
await issuesService
.patchIssueLabel(activeWorkspace.slug, activeProject.id, labelIdForUpdate ?? "", formData)
.then((res) => {
console.log(res);
@ -179,7 +176,7 @@ const LabelsSettings: NextPage<TLabelSettingsProps> = (props) => {
style={{
backgroundColor: watch("colour") ?? "green",
}}
></span>
/>
)}
</Popover.Button>
@ -215,7 +212,7 @@ const LabelsSettings: NextPage<TLabelSettingsProps> = (props) => {
id="labelName"
name="name"
register={register}
placeholder="Lable title"
placeholder="Label title"
validations={{
required: "Label title is required",
}}
@ -252,10 +249,10 @@ const LabelsSettings: NextPage<TLabelSettingsProps> = (props) => {
))
) : (
<Loader className="space-y-5 md:w-2/3">
<Loader.Item height="40px"></Loader.Item>
<Loader.Item height="40px"></Loader.Item>
<Loader.Item height="40px"></Loader.Item>
<Loader.Item height="40px"></Loader.Item>
<Loader.Item height="40px" />
<Loader.Item height="40px" />
<Loader.Item height="40px" />
<Loader.Item height="40px" />
</Loader>
)}
</>

View file

@ -2,16 +2,17 @@ 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";
import useSWR from "swr";
// services
import projectService from "lib/services/project.service";
import workspaceService from "lib/services/workspace.service";
import projectService from "services/project.service";
import workspaceService from "services/workspace.service";
// lib
import { requiredAdmin } from "lib/auth";
// hooks
import useToast from "lib/hooks/useToast";
import useToast from "hooks/use-toast";
// constants
import { ROLE } from "constants/";
// layouts
@ -20,9 +21,9 @@ import SettingsLayout from "layouts/settings-layout";
import ConfirmProjectMemberRemove from "components/project/confirm-project-member-remove";
import SendProjectInvitationModal from "components/project/send-project-invitation-modal";
// ui
import { BreadcrumbItem, Breadcrumbs, Button, CustomListbox, CustomMenu, Loader } from "ui";
import { Button, CustomListbox, CustomMenu, Loader } from "components/ui";
import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs";
// icons
import { PlusIcon } from "@heroicons/react/24/outline";
// fetch-keys
import {
PROJECT_DETAILS,
@ -84,7 +85,7 @@ const MembersSettings: NextPage<TMemberSettingsProps> = (props) => {
: null
);
let members = [
const members = [
...(projectMembers?.map((item: any) => ({
id: item.id,
avatar: item.member?.avatar,
@ -174,10 +175,10 @@ const MembersSettings: NextPage<TMemberSettingsProps> = (props) => {
</div>
{!projectMembers || !projectInvitations ? (
<Loader className="space-y-5 md:w-2/3">
<Loader.Item height="40px"></Loader.Item>
<Loader.Item height="40px"></Loader.Item>
<Loader.Item height="40px"></Loader.Item>
<Loader.Item height="40px"></Loader.Item>
<Loader.Item height="40px" />
<Loader.Item height="40px" />
<Loader.Item height="40px" />
<Loader.Item height="40px" />
</Loader>
) : (
<div className="md:w-2/3">
@ -252,11 +253,11 @@ const MembersSettings: NextPage<TMemberSettingsProps> = (props) => {
});
mutateMembers(
(prevData: any) =>
prevData.map((m: any) => {
return m.id === selectedMember
prevData.map((m: any) =>
m.id === selectedMember
? { ...m, ...res, role: value }
: m;
}),
: m
),
false
);
setSelectedMember(null);

View file

@ -1,19 +1,17 @@
import React, { useState } from "react";
import { useRouter } from "next/router";
import type { NextPage, NextPageContext } from "next";
import useSWR from "swr";
import { PencilSquareIcon, PlusIcon, TrashIcon } from "@heroicons/react/24/outline";
import { PROJECT_DETAILS, STATE_LIST, WORKSPACE_DETAILS } from "constants/fetch-keys";
// types
import type { NextPage, NextPageContext } from "next";
import { IState } from "types";
// services
import stateService from "lib/services/state.service";
import projectService from "lib/services/project.service";
import workspaceService from "lib/services/workspace.service";
import stateService from "services/state.service";
import projectService from "services/project.service";
// lib
import { requiredAdmin } from "lib/auth";
// hooks
import useUser from "lib/hooks/useUser";
// layouts
import SettingsLayout from "layouts/settings-layout";
// components
@ -23,13 +21,13 @@ import {
StateGroup,
} from "components/project/issues/BoardView/state/create-update-state-inline";
// ui
import { BreadcrumbItem, Breadcrumbs, Loader } from "ui";
// icons
import { PencilSquareIcon, PlusIcon, TrashIcon } from "@heroicons/react/24/outline";
// types
import { IState } from "types";
// common
import { addSpaceIfCamelCase, groupBy } from "constants/common";
import { Loader } from "components/ui";
import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs";
// helpers
import { addSpaceIfCamelCase } from "helpers/string.helper";
import { groupBy } from "helpers/array.helper";
// fetch-keys
import { PROJECT_DETAILS, STATE_LIST } from "constants/fetch-keys";
type TStateSettingsProps = {
isMember: boolean;
@ -49,22 +47,17 @@ const StatesSettings: NextPage<TStateSettingsProps> = (props) => {
query: { workspaceSlug, projectId },
} = useRouter();
const { data: activeWorkspace } = useSWR(
workspaceSlug ? WORKSPACE_DETAILS(workspaceSlug as string) : null,
() => (workspaceSlug ? workspaceService.getWorkspace(workspaceSlug as string) : null)
);
const { data: activeProject } = useSWR(
activeWorkspace && projectId ? PROJECT_DETAILS(projectId as string) : null,
activeWorkspace && projectId
? () => projectService.getProject(activeWorkspace.slug, projectId as string)
workspaceSlug && projectId ? PROJECT_DETAILS(projectId as string) : null,
workspaceSlug && projectId
? () => projectService.getProject(workspaceSlug as string, projectId as string)
: null
);
const { data: states } = useSWR(
activeWorkspace && activeProject ? STATE_LIST(activeProject.id) : null,
activeWorkspace && activeProject
? () => stateService.getStates(activeWorkspace.slug, activeProject.id)
workspaceSlug && projectId ? STATE_LIST(projectId as string) : null,
workspaceSlug && projectId
? () => stateService.getStates(workspaceSlug as string, projectId as string)
: null
);
@ -113,18 +106,6 @@ const StatesSettings: NextPage<TStateSettingsProps> = (props) => {
</button>
</div>
<div className="space-y-1 rounded-xl border p-1 md:w-2/3">
{key === activeGroup && (
<CreateUpdateStateInline
projectId={activeProject.id}
onClose={() => {
setActiveGroup(null);
setSelectedState(null);
}}
workspaceSlug={activeWorkspace?.slug}
data={null}
selectedGroup={key as keyof StateGroup}
/>
)}
{groupedStates[key]?.map((state) =>
state.id !== selectedState ? (
<div
@ -139,7 +120,7 @@ const StatesSettings: NextPage<TStateSettingsProps> = (props) => {
style={{
backgroundColor: state.color,
}}
></div>
/>
<h6 className="text-sm">{addSpaceIfCamelCase(state.name)}</h6>
</div>
<div className="flex items-center gap-2">
@ -152,29 +133,41 @@ const StatesSettings: NextPage<TStateSettingsProps> = (props) => {
</div>
</div>
) : (
<div className={`border-b last:border-b-0`} key={state.id}>
<div className="border-b last:border-b-0" key={state.id}>
<CreateUpdateStateInline
projectId={activeProject.id}
onClose={() => {
setActiveGroup(null);
setSelectedState(null);
}}
workspaceSlug={activeWorkspace?.slug}
workspaceSlug={workspaceSlug as string}
data={states?.find((state) => state.id === selectedState) ?? null}
selectedGroup={key as keyof StateGroup}
/>
</div>
)
)}
{key === activeGroup && (
<CreateUpdateStateInline
projectId={activeProject.id}
onClose={() => {
setActiveGroup(null);
setSelectedState(null);
}}
workspaceSlug={workspaceSlug as string}
data={null}
selectedGroup={key as keyof StateGroup}
/>
)}
</div>
</div>
))
) : (
<Loader className="space-y-5 md:w-2/3">
<Loader.Item height="40px"></Loader.Item>
<Loader.Item height="40px"></Loader.Item>
<Loader.Item height="40px"></Loader.Item>
<Loader.Item height="40px"></Loader.Item>
<Loader.Item height="40px" />
<Loader.Item height="40px" />
<Loader.Item height="40px" />
<Loader.Item height="40px" />
</Loader>
)}
</div>