refactor: only using runInAction for assignment

refactor: - using single types instead of lite version, - isLoading logic for label store
This commit is contained in:
Dakshesh Jain 2023-08-17 13:57:21 +05:30
parent 37df8684d7
commit 963eeb0a8c
13 changed files with 111 additions and 108 deletions

View File

@ -10,7 +10,7 @@ import { replaceUnderscoreIfSnakeCase } from "helpers/string.helper";
// helpers
import { renderShortDateWithYearFormat } from "helpers/date-time.helper";
// types
import { IIssueFilterOptions, IState, IUserLite, TStateGroups, LabelLite } from "types";
import { IIssueFilterOptions, IState, IUserLite, TStateGroups, IIssueLabels } from "types";
// constants
import { STATE_GROUP_COLORS } from "constants/state";
@ -18,7 +18,7 @@ type Props = {
filters: Partial<IIssueFilterOptions>;
setFilters: (updatedFilter: Partial<IIssueFilterOptions>) => void;
clearAllFilters: (...args: any) => void;
labels: LabelLite[] | undefined;
labels: IIssueLabels[] | undefined;
members: IUserLite[] | undefined;
states: IState[] | undefined;
};

View File

@ -18,7 +18,7 @@ import {
TagIcon,
} from "@heroicons/react/24/outline";
// types
import type { LabelLite } from "types";
import type { IIssueLabels } from "types";
type Props = {
setIsOpen: React.Dispatch<React.SetStateAction<boolean>>;
@ -42,7 +42,7 @@ export const IssueLabelSelect: React.FC<Props> = observer(
if (workspaceSlug && projectId) loadLabels(workspaceSlug.toString(), projectId);
}, [workspaceSlug, projectId, loadLabels]);
const filteredOptions: LabelLite[] = labels?.filter((l) =>
const filteredOptions: IIssueLabels[] = labels?.filter((l) =>
l.name.toLowerCase().includes(query.toLowerCase())
);

View File

@ -19,7 +19,7 @@ import { Input, PrimaryButton, SecondaryButton } from "components/ui";
// icons
import { ChevronDownIcon } from "@heroicons/react/24/outline";
// types
import { IIssueLabels, LabelLite } from "types";
import { IIssueLabels } from "types";
// fetch-keys
import { getRandomLabelColor, LABEL_COLOR_OPTIONS } from "constants/label";
@ -27,7 +27,7 @@ type Props = {
labelForm: boolean;
setLabelForm: React.Dispatch<React.SetStateAction<boolean>>;
isUpdating: boolean;
labelToUpdate: LabelLite | null;
labelToUpdate: IIssueLabels | null;
onClose?: () => void;
};

View File

@ -15,12 +15,12 @@ import useToast from "hooks/use-toast";
// ui
import { DangerButton, SecondaryButton } from "components/ui";
// types
import type { ICurrentUserResponse, LabelLite } from "types";
import type { ICurrentUserResponse, IIssueLabels } from "types";
type Props = {
isOpen: boolean;
onClose: () => void;
data: LabelLite | null;
data: IIssueLabels | null;
user: ICurrentUserResponse | undefined;
};

View File

@ -11,12 +11,12 @@ import { Combobox, Dialog, Transition } from "@headlessui/react";
// icons
import { RectangleStackIcon, MagnifyingGlassIcon } from "@heroicons/react/24/outline";
// types
import { ICurrentUserResponse, LabelLite } from "types";
import { ICurrentUserResponse, IIssueLabels } from "types";
type Props = {
isOpen: boolean;
handleClose: () => void;
parent: LabelLite | undefined;
parent: IIssueLabels | undefined;
user: ICurrentUserResponse | undefined;
};
@ -37,7 +37,7 @@ export const LabelsListModal: React.FC<Props> = observer(
setQuery("");
};
const addChildLabel = async (label: LabelLite) => {
const addChildLabel = async (label: IIssueLabels) => {
if (!workspaceSlug || !projectId || !user) return;
updateLabel(

View File

@ -20,14 +20,14 @@ import {
TrashIcon,
} from "@heroicons/react/24/outline";
// types
import { ICurrentUserResponse, LabelLite } from "types";
import { ICurrentUserResponse, IIssueLabels } from "types";
type Props = {
label: LabelLite;
labelChildren: LabelLite[];
addLabelToGroup: (parentLabel: LabelLite) => void;
editLabel: (label: LabelLite) => void;
handleLabelDelete: (label: LabelLite) => void;
label: IIssueLabels;
labelChildren: IIssueLabels[];
addLabelToGroup: (parentLabel: IIssueLabels) => void;
editLabel: (label: IIssueLabels) => void;
handleLabelDelete: (label: IIssueLabels) => void;
user: ICurrentUserResponse | undefined;
};
@ -39,7 +39,7 @@ export const SingleLabelGroup: React.FC<Props> = observer(
const { label: labelStore } = useMobxStore();
const { updateLabel } = labelStore;
const removeFromGroup = (label: LabelLite) => {
const removeFromGroup = (label: IIssueLabels) => {
if (!workspaceSlug || !projectId || !user) return;
updateLabel(

View File

@ -3,14 +3,14 @@ import React from "react";
// ui
import { CustomMenu } from "components/ui";
// types
import { LabelLite } from "types";
import { IIssueLabels } from "types";
//icons
import { RectangleGroupIcon, PencilIcon, TrashIcon } from "@heroicons/react/24/outline";
type Props = {
label: LabelLite;
addLabelToGroup: (parentLabel: LabelLite) => void;
editLabel: (label: LabelLite) => void;
label: IIssueLabels;
addLabelToGroup: (parentLabel: IIssueLabels) => void;
editLabel: (label: IIssueLabels) => void;
handleLabelDelete: () => void;
};

View File

@ -19,32 +19,32 @@ export const EditorBubbleMenu: FC<EditorBubbleMenuProps> = (props) => {
const items: BubbleMenuItem[] = [
{
name: "bold",
isActive: () => props.editor.isActive("bold"),
command: () => props.editor.chain().focus().toggleBold().run(),
isActive: () => props?.editor?.isActive("bold")!,
command: () => props?.editor?.chain().focus().toggleBold().run()!,
icon: BoldIcon,
},
{
name: "italic",
isActive: () => props.editor.isActive("italic"),
command: () => props.editor.chain().focus().toggleItalic().run(),
isActive: () => props?.editor?.isActive("italic")!,
command: () => props?.editor?.chain().focus().toggleItalic().run()!,
icon: ItalicIcon,
},
{
name: "underline",
isActive: () => props.editor.isActive("underline"),
command: () => props.editor.chain().focus().toggleUnderline().run(),
isActive: () => props?.editor?.isActive("underline")!,
command: () => props?.editor?.chain().focus().toggleUnderline().run()!,
icon: UnderlineIcon,
},
{
name: "strike",
isActive: () => props.editor.isActive("strike"),
command: () => props.editor.chain().focus().toggleStrike().run(),
isActive: () => props?.editor?.isActive("strike")!,
command: () => props?.editor?.chain().focus().toggleStrike().run()!,
icon: StrikethroughIcon,
},
{
name: "code",
isActive: () => props.editor.isActive("code"),
command: () => props.editor.chain().focus().toggleCode().run(),
isActive: () => props?.editor?.isActive("code")!,
command: () => props?.editor?.chain().focus().toggleCode().run()!,
icon: CodeIcon,
},
];
@ -78,7 +78,7 @@ export const EditorBubbleMenu: FC<EditorBubbleMenuProps> = (props) => {
className="flex w-fit divide-x divide-custom-border-300 rounded border border-custom-border-300 bg-custom-background-100 shadow-xl"
>
<NodeSelector
editor={props.editor}
editor={props?.editor!}
isOpen={isNodeSelectorOpen}
setIsOpen={() => {
setIsNodeSelectorOpen(!isNodeSelectorOpen);
@ -86,7 +86,7 @@ export const EditorBubbleMenu: FC<EditorBubbleMenuProps> = (props) => {
}}
/>
<LinkSelector
editor={props.editor}
editor={props?.editor!}
isOpen={isLinkSelectorOpen}
setIsOpen={() => {
setIsLinkSelectorOpen(!isLinkSelectorOpen);

View File

@ -31,7 +31,7 @@ import { PlusIcon } from "@heroicons/react/24/outline";
// images
import emptyLabel from "public/empty-state/label.svg";
// types
import { LabelLite } from "types";
import { IIssueLabels } from "types";
import type { NextPage } from "next";
// fetch-keys
import { PROJECT_DETAILS } from "constants/fetch-keys";
@ -44,14 +44,14 @@ const LabelsSettings: NextPage = () => {
// edit label
const [isUpdating, setIsUpdating] = useState(false);
const [labelToUpdate, setLabelToUpdate] = useState<LabelLite | null>(null);
const [labelToUpdate, setLabelToUpdate] = useState<IIssueLabels | null>(null);
// labels list modal
const [labelsListModal, setLabelsListModal] = useState(false);
const [parentLabel, setParentLabel] = useState<LabelLite | undefined>(undefined);
const [parentLabel, setParentLabel] = useState<IIssueLabels | undefined>(undefined);
// delete label
const [selectDeleteLabel, setSelectDeleteLabel] = useState<LabelLite | null>(null);
const [selectDeleteLabel, setSelectDeleteLabel] = useState<IIssueLabels | null>(null);
const router = useRouter();
const { workspaceSlug, projectId } = router.query;
@ -79,12 +79,12 @@ const LabelsSettings: NextPage = () => {
setLabelForm(true);
};
const addLabelToGroup = (parentLabel: LabelLite) => {
const addLabelToGroup = (parentLabel: IIssueLabels) => {
setLabelsListModal(true);
setParentLabel(parentLabel);
};
const editLabel = (label: LabelLite) => {
const editLabel = (label: IIssueLabels) => {
setLabelForm(true);
setIsUpdating(true);
setLabelToUpdate(label);

View File

@ -5,10 +5,10 @@ import { action, observable, runInAction, makeAutoObservable } from "mobx";
import issueService from "services/issues.service";
// types
import type { IIssueLabels, LabelLite, ICurrentUserResponse, LabelForm } from "types";
import type { IIssueLabels, ICurrentUserResponse, LabelForm } from "types";
class LabelStore {
labels: LabelLite[] = [];
labels: IIssueLabels[] = [];
isLabelsLoading: boolean = false;
rootStore: any | null = null;
@ -30,24 +30,29 @@ class LabelStore {
*/
loadLabels = async (workspaceSlug: string, projectId: string) => {
this.isLabelsLoading = true;
this.isLabelsLoading = this.labels.length === 0;
try {
const labelsResponse: IIssueLabels[] = await issueService.getIssueLabels(
workspaceSlug,
projectId
);
const _labels = [...(labelsResponse || [])].map((label) => ({
id: label.id,
name: label.name,
description: label.description,
color: label.color,
parent: label.parent,
}));
runInAction(() => {
this.labels = labelsResponse.map((label) => ({
id: label.id,
name: label.name,
description: label.description,
color: label.color,
parent: label.parent,
}));
this.labels = _labels;
this.isLabelsLoading = false;
});
} catch (error) {
this.isLabelsLoading = false;
runInAction(() => {
this.isLabelsLoading = false;
});
console.error("Fetching labels error", error);
}
};
@ -59,11 +64,11 @@ class LabelStore {
/**
* For provided query, this function returns all labels that contain query in their name from the labels store.
* @param query - query string
* @returns {LabelLite[]} array of labels that contain query in their name
* @returns {IIssueLabels[]} array of labels that contain query in their name
* @example
* getFilteredLabels("labe") // [{ id: "1", name: "label1", description: "", color: "", parent: null }]
*/
getFilteredLabels = (query: string): LabelLite[] =>
getFilteredLabels = (query: string): IIssueLabels[] =>
this.labels.filter((label) => label.name.includes(query));
createLabel = async (
@ -80,18 +85,19 @@ class LabelStore {
user
);
const _label = [
...this.labels,
{
id: labelResponse.id,
name: labelResponse.name,
description: labelResponse.description,
color: labelResponse.color,
parent: labelResponse.parent,
},
].sort((a, b) => a.name.localeCompare(b.name));
runInAction(() => {
this.labels = [
...this.labels,
{
id: labelResponse.id,
name: labelResponse.name,
description: labelResponse.description,
color: labelResponse.color,
parent: labelResponse.parent,
},
];
this.labels.sort((a, b) => a.name.localeCompare(b.name));
this.labels = _label;
});
return labelResponse;
} catch (error) {
@ -116,18 +122,20 @@ class LabelStore {
user
);
const _labels = [...this.labels].map((label) => {
if (label.id === labelId) {
return {
id: labelResponse.id,
name: labelResponse.name,
description: labelResponse.description,
color: labelResponse.color,
parent: labelResponse.parent,
};
}
return label;
});
const _labels = [...this.labels]
.map((label) => {
if (label.id === labelId) {
return {
id: labelResponse.id,
name: labelResponse.name,
description: labelResponse.description,
color: labelResponse.color,
parent: labelResponse.parent,
};
}
return label;
})
.sort((a, b) => a.name.localeCompare(b.name));
runInAction(() => {
this.labels = _labels;
@ -146,8 +154,11 @@ class LabelStore {
) => {
try {
issueService.deleteIssueLabel(workspaceSlug, projectId, labelId, user);
const _labels = [...this.labels].filter((label) => label.id !== labelId);
runInAction(() => {
this.labels = this.labels.filter((label) => label.id !== labelId);
this.labels = _labels;
});
} catch (error) {
console.error("Deleting label error", error);

View File

@ -18,7 +18,7 @@ export * from "./calendar";
export * from "./notifications";
export * from "./waitlist";
export * from "./reaction";
export * from "./labels";
export type NestedKeyOf<ObjectType extends object> = {
[Key in keyof ObjectType & (string | number)]: ObjectType[Key] extends object

View File

@ -148,36 +148,6 @@ export type IssuePriorities = {
user: string;
};
export interface IIssueLabels {
id: string;
created_at: Date;
updated_at: Date;
name: string;
description: string;
color: string;
created_by: string;
updated_by: string;
project: string;
project_detail: IProjectLite;
workspace: string;
workspace_detail: IWorkspaceLite;
parent: string | null;
}
export interface LabelForm {
name: string;
description: string;
color: string;
parent: string | null;
}
/**
* @description Issue label's lite version
*/
export interface LabelLite extends LabelForm {
id: string;
}
export interface IIssueActivity {
actor: string;
actor_detail: IUserLite;

22
apps/app/types/labels.d.ts vendored Normal file
View File

@ -0,0 +1,22 @@
export interface IIssueLabels {
id: string;
created_at?: Date;
updated_at?: Date;
name: string;
description: string;
color: string;
created_by?: string;
updated_by?: string;
project?: string;
project_detail?: IProjectLite;
workspace?: string;
workspace_detail?: IWorkspaceLite;
parent: string | null;
}
export interface LabelForm {
name: string;
description: string;
color: string;
parent: string | null;
}