refractor: added types to workspace and project services, naming convention

This commit is contained in:
Dakshesh Jain 2022-12-12 10:19:52 +05:30
parent 9c33c3c87f
commit fe7284b9b0
49 changed files with 294 additions and 197 deletions

View file

@ -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<ProjectMember> = {
email: "",
message: "",
@ -49,7 +54,7 @@ const SendProjectInvitationModal: React.FC<Props> = ({ isOpen, setIsOpen, member
const { setToastAlert } = useToast();
const { data: people } = useSWR<WorkspaceMember[]>(
const { data: people } = useSWR(
activeWorkspace ? WORKSPACE_MEMBERS(activeWorkspace.slug) : null,
activeWorkspace ? () => workspaceService.workspaceMembers(activeWorkspace.slug) : null,
{

View file

@ -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<Props> = ({ isOpen, setIsOpen }) => {
const { activeWorkspace, user } = useUser();
const { data: workspaceMembers } = useSWR<WorkspaceMember[]>(
const { data: workspaceMembers } = useSWR(
activeWorkspace ? WORKSPACE_MEMBERS(activeWorkspace.slug) : null,
activeWorkspace ? () => workspaceService.workspaceMembers(activeWorkspace.slug) : null,
{
@ -68,6 +70,8 @@ const CreateProjectModal: React.FC<Props> = ({ isOpen, setIsOpen }) => {
}
);
const [recommendedIdentifier, setRecommendedIdentifier] = useState<string[]>([]);
const { setToastAlert } = useToast();
const [isChangeIdentifierRequired, setIsChangeIdentifierRequired] = useState(true);
@ -78,6 +82,7 @@ const CreateProjectModal: React.FC<Props> = ({ isOpen, setIsOpen }) => {
handleSubmit,
reset,
setError,
clearErrors,
watch,
setValue,
} = useForm<IProject>({
@ -125,12 +130,6 @@ const CreateProjectModal: React.FC<Props> = ({ 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<Props> = ({ isOpen, setIsOpen }) => {
if ((!isMember || isGuest) && isOpen) return <IsGuestCondition setIsOpen={setIsOpen} />;
}
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 (
<Transition.Root show={isOpen} as={React.Fragment}>
<Dialog as="div" className="relative z-10" onClose={handleClose}>
@ -239,6 +262,27 @@ const CreateProjectModal: React.FC<Props> = ({ isOpen, setIsOpen }) => {
},
}}
/>
{errors.identifier && (
<div className="mt-2">
<p>Ops! Identifier is already taken. Try one of the following:</p>
<div className="flex gap-x-2">
{recommendedIdentifier.map((identifier) => (
<button
key={identifier}
type="button"
className="text-sm text-gray-500 hover:text-gray-700 border p-2 py-0.5 rounded"
onClick={() => {
clearErrors("identifier");
setValue("identifier", identifier);
setIsChangeIdentifierRequired(false);
}}
>
{identifier}
</button>
))}
</div>
</div>
)}
</div>
</div>
</div>

View file

@ -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

View file

@ -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

View file

@ -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";

View file

@ -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";

View file

@ -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<Props> = ({ properties, selectedGroup, groupedByIssues, members }) => {

View file

@ -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<Props> = ({ isOpen, setIsOpen, data }) => {
mutate<IState[]>(
STATE_LIST(data.project),
(prevData) => prevData?.filter((state) => state.id !== data?.id),
false,
false
);
handleClose();
})
@ -98,18 +98,15 @@ const ConfirmStateDeletion: React.FC<Props> = ({ isOpen, setIsOpen, data }) => {
/>
</div>
<div className="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left">
<Dialog.Title
as="h3"
className="text-lg font-medium leading-6 text-gray-900"
>
<Dialog.Title as="h3" className="text-lg font-medium leading-6 text-gray-900">
Delete State
</Dialog.Title>
<div className="mt-2">
<p className="text-sm text-gray-500">
Are you sure you want to delete state - {`"`}
<span className="italic">{data?.name}</span>
{`"`} ? 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.
</p>
</div>
</div>

View file

@ -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

View file

@ -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";

View file

@ -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<Props> = ({ control }) => {
const { activeWorkspace, activeProject } = useUser();
const { data: people } = useSWR<WorkspaceMember[]>(
const { data: people } = useSWR(
activeWorkspace && activeProject ? PROJECT_MEMBERS(activeProject.id) : null,
activeWorkspace && activeProject
? () => projectServices.projectMembers(activeWorkspace.slug, activeProject.id)

View file

@ -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

View file

@ -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";

View file

@ -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<Props> = ({
});
};
const { data: people } = useSWR<WorkspaceMember[]>(
const { data: people } = useSWR(
activeWorkspace ? WORKSPACE_MEMBERS : null,
activeWorkspace ? () => workspaceService.workspaceMembers(activeWorkspace.slug) : null
);

View file

@ -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<Props> = ({
: null
);
const { data: people } = useSWR<WorkspaceMember[]>(
const { data: people } = useSWR(
activeWorkspace ? WORKSPACE_MEMBERS(activeWorkspace.slug) : null,
activeWorkspace ? () => workspaceService.workspaceMembers(activeWorkspace.slug) : null
);

View file

@ -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

View file

@ -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

View file

@ -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<Props> = ({ control, isSubmitting }) => {
const { activeWorkspace } = useUser();
const { data: people } = useSWR<WorkspaceMember[]>(
const { data: people } = useSWR(
activeWorkspace ? WORKSPACE_MEMBERS : null,
activeWorkspace ? () => workspaceService.workspaceMembers(activeWorkspace.slug) : null
);

View file

@ -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