refactor: using label store to get labels

This commit is contained in:
Dakshesh Jain 2023-08-16 17:49:51 +05:30
parent f8ab0aa72b
commit e9c3a0642e
9 changed files with 307 additions and 306 deletions

View File

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

View File

@ -1,18 +1,21 @@
import React from "react"; import React, { useEffect } from "react";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import useSWR from "swr"; import useSWR from "swr";
// mobx
import { observer } from "mobx-react-lite";
import { useMobxStore } from "lib/mobx/store-provider";
// services // services
import issuesService from "services/issues.service";
import projectService from "services/project.service"; import projectService from "services/project.service";
// hooks // hooks
import useProjects from "hooks/use-projects"; import useProjects from "hooks/use-projects";
// component // component
import { Avatar, Icon } from "components/ui"; import { Avatar, Icon } from "components/ui";
// icons // icons
import { ArrowsPointingInIcon, ArrowsPointingOutIcon, PlusIcon } from "@heroicons/react/24/outline"; import { PlusIcon } from "@heroicons/react/24/outline";
import { getPriorityIcon, getStateGroupIcon } from "components/icons"; import { getPriorityIcon, getStateGroupIcon } from "components/icons";
// helpers // helpers
import { addSpaceIfCamelCase } from "helpers/string.helper"; import { addSpaceIfCamelCase } from "helpers/string.helper";
@ -20,7 +23,7 @@ import { renderEmoji } from "helpers/emoji.helper";
// types // types
import { IIssueViewProps, IState } from "types"; import { IIssueViewProps, IState } from "types";
// fetch-keys // fetch-keys
import { PROJECT_ISSUE_LABELS, PROJECT_MEMBERS } from "constants/fetch-keys"; import { PROJECT_MEMBERS } from "constants/fetch-keys";
type Props = { type Props = {
currentState?: IState | null; currentState?: IState | null;
@ -32,7 +35,8 @@ type Props = {
viewProps: IIssueViewProps; viewProps: IIssueViewProps;
}; };
export const BoardHeader: React.FC<Props> = ({ export const BoardHeader: React.FC<Props> = observer(
({
currentState, currentState,
groupTitle, groupTitle,
addIssueToGroup, addIssueToGroup,
@ -40,20 +44,14 @@ export const BoardHeader: React.FC<Props> = ({
setIsCollapsed, setIsCollapsed,
disableUserActions, disableUserActions,
viewProps, viewProps,
}) => { }) => {
const router = useRouter(); const router = useRouter();
const { workspaceSlug, projectId } = router.query; const { workspaceSlug, projectId } = router.query;
const { groupedIssues, groupByProperty: selectedGroup } = viewProps; const { groupedIssues, groupByProperty: selectedGroup } = viewProps;
const { data: issueLabels } = useSWR( const { label: labelStore } = useMobxStore();
workspaceSlug && projectId && selectedGroup === "labels" const { labels, loadLabels } = labelStore;
? PROJECT_ISSUE_LABELS(projectId.toString())
: null,
workspaceSlug && projectId && selectedGroup === "labels"
? () => issuesService.getIssueLabels(workspaceSlug.toString(), projectId.toString())
: null
);
const { data: members } = useSWR( const { data: members } = useSWR(
workspaceSlug && projectId && selectedGroup === "created_by" workspaceSlug && projectId && selectedGroup === "created_by"
@ -66,6 +64,10 @@ export const BoardHeader: React.FC<Props> = ({
const { projects } = useProjects(); const { projects } = useProjects();
useEffect(() => {
if (workspaceSlug && projectId) loadLabels(workspaceSlug.toString(), projectId.toString());
}, [workspaceSlug, projectId, loadLabels]);
const getGroupTitle = () => { const getGroupTitle = () => {
let title = addSpaceIfCamelCase(groupTitle); let title = addSpaceIfCamelCase(groupTitle);
@ -74,7 +76,7 @@ export const BoardHeader: React.FC<Props> = ({
title = addSpaceIfCamelCase(currentState?.name ?? ""); title = addSpaceIfCamelCase(currentState?.name ?? "");
break; break;
case "labels": case "labels":
title = issueLabels?.find((label) => label.id === groupTitle)?.name ?? "None"; title = labels?.find((label) => label.id === groupTitle)?.name ?? "None";
break; break;
case "project": case "project":
title = projects?.find((p) => p.id === groupTitle)?.name ?? "None"; title = projects?.find((p) => p.id === groupTitle)?.name ?? "None";
@ -113,8 +115,7 @@ export const BoardHeader: React.FC<Props> = ({
: null); : null);
break; break;
case "labels": case "labels":
const labelColor = const labelColor = labels?.find((label) => label.id === groupTitle)?.color ?? "#000000";
issueLabels?.find((label) => label.id === groupTitle)?.color ?? "#000000";
icon = ( icon = (
<span <span
className="h-3.5 w-3.5 flex-shrink-0 rounded-full" className="h-3.5 w-3.5 flex-shrink-0 rounded-full"
@ -175,7 +176,10 @@ export const BoardHeader: React.FC<Props> = ({
className="text-base font-medium text-custom-text-900" className="text-base font-medium text-custom-text-900"
/> />
) : ( ) : (
<Icon iconName="open_in_full" className="text-base font-medium text-custom-text-900" /> <Icon
iconName="open_in_full"
className="text-base font-medium text-custom-text-900"
/>
)} )}
</button> </button>
{!disableUserActions && selectedGroup !== "created_by" && ( {!disableUserActions && selectedGroup !== "created_by" && (
@ -190,4 +194,5 @@ export const BoardHeader: React.FC<Props> = ({
</div> </div>
</div> </div>
); );
}; }
);

View File

@ -1,9 +1,13 @@
import { useCallback, useState } from "react"; import { useCallback, useState, useEffect } from "react";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import useSWR, { mutate } from "swr"; import useSWR, { mutate } from "swr";
// mobx
import { observer } from "mobx-react-lite";
import { useMobxStore } from "lib/mobx/store-provider";
// react-beautiful-dnd // react-beautiful-dnd
import { DropResult } from "react-beautiful-dnd"; import { DropResult } from "react-beautiful-dnd";
// services // services
@ -37,7 +41,6 @@ import {
MODULE_DETAILS, MODULE_DETAILS,
MODULE_ISSUES_WITH_PARAMS, MODULE_ISSUES_WITH_PARAMS,
PROJECT_ISSUES_LIST_WITH_PARAMS, PROJECT_ISSUES_LIST_WITH_PARAMS,
PROJECT_ISSUE_LABELS,
STATES_LIST, STATES_LIST,
} from "constants/fetch-keys"; } from "constants/fetch-keys";
@ -46,10 +49,8 @@ type Props = {
disableUserActions?: boolean; disableUserActions?: boolean;
}; };
export const IssuesView: React.FC<Props> = ({ export const IssuesView: React.FC<Props> = observer((props) => {
openIssuesListModal, const { openIssuesListModal, disableUserActions = false } = props;
disableUserActions = false,
}) => {
// create issue modal // create issue modal
const [createIssueModal, setCreateIssueModal] = useState(false); const [createIssueModal, setCreateIssueModal] = useState(false);
const [createViewModal, setCreateViewModal] = useState<any>(null); const [createViewModal, setCreateViewModal] = useState<any>(null);
@ -75,6 +76,9 @@ export const IssuesView: React.FC<Props> = ({
const { user } = useUserAuth(); const { user } = useUserAuth();
const { label: labelStore } = useMobxStore();
const { labels, loadLabels } = labelStore;
const { setToastAlert } = useToast(); const { setToastAlert } = useToast();
const { const {
@ -99,15 +103,12 @@ export const IssuesView: React.FC<Props> = ({
); );
const states = getStatesList(stateGroups); const states = getStatesList(stateGroups);
const { data: labels } = useSWR(
workspaceSlug && projectId ? PROJECT_ISSUE_LABELS(projectId.toString()) : null,
workspaceSlug && projectId
? () => issuesService.getIssueLabels(workspaceSlug.toString(), projectId.toString())
: null
);
const { members } = useProjectMembers(workspaceSlug?.toString(), projectId?.toString()); const { members } = useProjectMembers(workspaceSlug?.toString(), projectId?.toString());
useEffect(() => {
if (workspaceSlug && projectId) loadLabels(workspaceSlug as string, projectId as string);
}, [loadLabels, projectId, workspaceSlug]);
const handleDeleteIssue = useCallback( const handleDeleteIssue = useCallback(
(issue: IIssue) => { (issue: IIssue) => {
setDeleteIssueModal(true); setDeleteIssueModal(true);
@ -564,4 +565,4 @@ export const IssuesView: React.FC<Props> = ({
/> />
</> </>
); );
}; });

View File

@ -1,11 +1,16 @@
import { useEffect } from "react";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import useSWR from "swr"; import useSWR from "swr";
// mobx
import { observer } from "mobx-react-lite";
import { useMobxStore } from "lib/mobx/store-provider";
// headless ui // headless ui
import { Disclosure, Transition } from "@headlessui/react"; import { Disclosure, Transition } from "@headlessui/react";
// services // services
import issuesService from "services/issues.service";
import projectService from "services/project.service"; import projectService from "services/project.service";
// hooks // hooks
import useProjects from "hooks/use-projects"; import useProjects from "hooks/use-projects";
@ -20,16 +25,9 @@ import { getPriorityIcon, getStateGroupIcon } from "components/icons";
import { addSpaceIfCamelCase } from "helpers/string.helper"; import { addSpaceIfCamelCase } from "helpers/string.helper";
import { renderEmoji } from "helpers/emoji.helper"; import { renderEmoji } from "helpers/emoji.helper";
// types // types
import { import { ICurrentUserResponse, IIssue, IIssueViewProps, IState, UserAuth } from "types";
ICurrentUserResponse,
IIssue,
IIssueLabels,
IIssueViewProps,
IState,
UserAuth,
} from "types";
// fetch-keys // fetch-keys
import { PROJECT_ISSUE_LABELS, PROJECT_MEMBERS } from "constants/fetch-keys"; import { PROJECT_MEMBERS } from "constants/fetch-keys";
type Props = { type Props = {
currentState?: IState | null; currentState?: IState | null;
@ -44,7 +42,8 @@ type Props = {
viewProps: IIssueViewProps; viewProps: IIssueViewProps;
}; };
export const SingleList: React.FC<Props> = ({ export const SingleList: React.FC<Props> = observer((props) => {
const {
currentState, currentState,
groupTitle, groupTitle,
addIssueToGroup, addIssueToGroup,
@ -55,7 +54,8 @@ export const SingleList: React.FC<Props> = ({
user, user,
userAuth, userAuth,
viewProps, viewProps,
}) => { } = props;
const router = useRouter(); const router = useRouter();
const { workspaceSlug, projectId, cycleId, moduleId } = router.query; const { workspaceSlug, projectId, cycleId, moduleId } = router.query;
@ -65,12 +65,8 @@ export const SingleList: React.FC<Props> = ({
const { groupByProperty: selectedGroup, groupedIssues } = viewProps; const { groupByProperty: selectedGroup, groupedIssues } = viewProps;
const { data: issueLabels } = useSWR<IIssueLabels[]>( const { label: labelStore } = useMobxStore();
workspaceSlug && projectId ? PROJECT_ISSUE_LABELS(projectId as string) : null, const { labels, loadLabels } = labelStore;
workspaceSlug && projectId
? () => issuesService.getIssueLabels(workspaceSlug as string, projectId as string)
: null
);
const { data: members } = useSWR( const { data: members } = useSWR(
workspaceSlug && projectId ? PROJECT_MEMBERS(projectId as string) : null, workspaceSlug && projectId ? PROJECT_MEMBERS(projectId as string) : null,
@ -81,6 +77,10 @@ export const SingleList: React.FC<Props> = ({
const { projects } = useProjects(); const { projects } = useProjects();
useEffect(() => {
if (workspaceSlug && projectId) loadLabels(workspaceSlug.toString(), projectId.toString());
}, [workspaceSlug, projectId, loadLabels]);
const getGroupTitle = () => { const getGroupTitle = () => {
let title = addSpaceIfCamelCase(groupTitle); let title = addSpaceIfCamelCase(groupTitle);
@ -89,7 +89,7 @@ export const SingleList: React.FC<Props> = ({
title = addSpaceIfCamelCase(currentState?.name ?? ""); title = addSpaceIfCamelCase(currentState?.name ?? "");
break; break;
case "labels": case "labels":
title = issueLabels?.find((label) => label.id === groupTitle)?.name ?? "None"; title = labels?.find((label) => label.id === groupTitle)?.name ?? "None";
break; break;
case "project": case "project":
title = projects?.find((p) => p.id === groupTitle)?.name ?? "None"; title = projects?.find((p) => p.id === groupTitle)?.name ?? "None";
@ -128,8 +128,7 @@ export const SingleList: React.FC<Props> = ({
: null); : null);
break; break;
case "labels": case "labels":
const labelColor = const labelColor = labels?.find((label) => label.id === groupTitle)?.color ?? "#000000";
issueLabels?.find((label) => label.id === groupTitle)?.color ?? "#000000";
icon = ( icon = (
<span <span
className="h-3 w-3 flex-shrink-0 rounded-full" className="h-3 w-3 flex-shrink-0 rounded-full"
@ -252,4 +251,4 @@ export const SingleList: React.FC<Props> = ({
)} )}
</Disclosure> </Disclosure>
); );
}; });

View File

@ -2,7 +2,9 @@ import React, { useEffect, useState } from "react";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import useSWR from "swr"; // mobx
import { observer } from "mobx-react-lite";
import { useMobxStore } from "lib/mobx/store-provider";
// react-hook-form // react-hook-form
import { Controller, UseFormWatch, useForm } from "react-hook-form"; import { Controller, UseFormWatch, useForm } from "react-hook-form";
@ -10,8 +12,6 @@ import { Controller, UseFormWatch, useForm } from "react-hook-form";
import { TwitterPicker } from "react-color"; import { TwitterPicker } from "react-color";
// headless ui // headless ui
import { Listbox, Popover, Transition } from "@headlessui/react"; import { Listbox, Popover, Transition } from "@headlessui/react";
// services
import issuesService from "services/issues.service";
// hooks // hooks
import useUser from "hooks/use-user"; import useUser from "hooks/use-user";
// ui // ui
@ -25,9 +25,7 @@ import {
XMarkIcon, XMarkIcon,
} from "@heroicons/react/24/outline"; } from "@heroicons/react/24/outline";
// types // types
import { IIssue, IIssueLabels } from "types"; import { IIssue, LabelForm } from "types";
// fetch-keys
import { PROJECT_ISSUE_LABELS } from "constants/fetch-keys";
type Props = { type Props = {
issueDetails: IIssue | undefined; issueDetails: IIssue | undefined;
@ -38,19 +36,13 @@ type Props = {
uneditable: boolean; uneditable: boolean;
}; };
const defaultValues: Partial<IIssueLabels> = { const defaultValues: Partial<LabelForm> = {
name: "", name: "",
color: "#ff0000", color: "#ff0000",
}; };
export const SidebarLabelSelect: React.FC<Props> = ({ export const SidebarLabelSelect: React.FC<Props> = observer((props) => {
issueDetails, const { issueDetails, issueControl, watchIssue, submitChanges, isNotAllowed, uneditable } = props;
issueControl,
watchIssue,
submitChanges,
isNotAllowed,
uneditable,
}) => {
const [createLabelForm, setCreateLabelForm] = useState(false); const [createLabelForm, setCreateLabelForm] = useState(false);
const router = useRouter(); const router = useRouter();
@ -64,33 +56,38 @@ export const SidebarLabelSelect: React.FC<Props> = ({
watch, watch,
control: labelControl, control: labelControl,
setFocus, setFocus,
} = useForm<Partial<IIssueLabels>>({ } = useForm<LabelForm>({
defaultValues, defaultValues,
}); });
const { user } = useUser(); const { user } = useUser();
const { data: issueLabels, mutate: issueLabelMutate } = useSWR<IIssueLabels[]>( const { label: labelStore } = useMobxStore();
workspaceSlug && projectId ? PROJECT_ISSUE_LABELS(projectId as string) : null, const {
workspaceSlug && projectId labels,
? () => issuesService.getIssueLabels(workspaceSlug as string, projectId as string) loadLabels,
: null createLabel,
); getLabelById,
getLabelChildren,
isLabelsLoading: isLoading,
} = labelStore;
const handleNewLabel = async (formData: Partial<IIssueLabels>) => { useEffect(() => {
if (!workspaceSlug || !projectId || isSubmitting) return; if (workspaceSlug && projectId) loadLabels(workspaceSlug.toString(), projectId.toString());
}, [workspaceSlug, projectId, loadLabels]);
await issuesService const handleNewLabel = async (formData: LabelForm) => {
.createIssueLabel(workspaceSlug as string, projectId as string, formData, user) if (!workspaceSlug || !projectId || isSubmitting || !user) return;
.then((res) => {
await createLabel(workspaceSlug.toString(), projectId.toString(), formData, user).then(
(res: any) => {
reset(defaultValues); reset(defaultValues);
issueLabelMutate((prevData: any) => [...(prevData ?? []), res], false);
submitChanges({ labels_list: [...(issueDetails?.labels ?? []), res.id] }); submitChanges({ labels_list: [...(issueDetails?.labels ?? []), res.id] });
setCreateLabelForm(false); setCreateLabelForm(false);
}); }
);
}; };
useEffect(() => { useEffect(() => {
@ -110,7 +107,7 @@ export const SidebarLabelSelect: React.FC<Props> = ({
<div className="basis-1/2"> <div className="basis-1/2">
<div className="flex flex-wrap gap-1"> <div className="flex flex-wrap gap-1">
{watchIssue("labels_list")?.map((labelId) => { {watchIssue("labels_list")?.map((labelId) => {
const label = issueLabels?.find((l) => l.id === labelId); const label = getLabelById(labelId);
if (label) if (label)
return ( return (
@ -168,12 +165,10 @@ export const SidebarLabelSelect: React.FC<Props> = ({
> >
<Listbox.Options className="absolute right-0 z-10 mt-1 max-h-28 w-40 overflow-auto rounded-md bg-custom-background-80 py-1 text-xs shadow-lg border border-custom-border-100 focus:outline-none"> <Listbox.Options className="absolute right-0 z-10 mt-1 max-h-28 w-40 overflow-auto rounded-md bg-custom-background-80 py-1 text-xs shadow-lg border border-custom-border-100 focus:outline-none">
<div className="py-1"> <div className="py-1">
{issueLabels ? ( {!isLoading ? (
issueLabels.length > 0 ? ( labels.length > 0 ? (
issueLabels.map((label: IIssueLabels) => { labels.map((label) => {
const children = issueLabels?.filter( const children = getLabelChildren(label.id);
(l) => l.parent === label.id
);
if (children.length === 0) { if (children.length === 0) {
if (!label.parent) if (!label.parent)
@ -346,4 +341,4 @@ export const SidebarLabelSelect: React.FC<Props> = ({
)} )}
</div> </div>
); );
}; });

View File

@ -1,11 +1,11 @@
import React, { useState } from "react"; import React, { useEffect, useState } from "react";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import useSWR from "swr"; // mobx
import { observer } from "mobx-react-lite";
import { useMobxStore } from "lib/mobx/store-provider";
// services
import issuesService from "services/issues.service";
// component // component
import { CreateLabelModal } from "components/labels"; import { CreateLabelModal } from "components/labels";
// ui // ui
@ -13,9 +13,7 @@ import { CustomSearchSelect, Tooltip } from "components/ui";
// icons // icons
import { PlusIcon, TagIcon } from "@heroicons/react/24/outline"; import { PlusIcon, TagIcon } from "@heroicons/react/24/outline";
// types // types
import { ICurrentUserResponse, IIssue, IIssueLabels } from "types"; import { ICurrentUserResponse, IIssue } from "types";
// fetch-keys
import { PROJECT_ISSUE_LABELS } from "constants/fetch-keys";
type Props = { type Props = {
issue: IIssue; issue: IIssue;
@ -28,7 +26,8 @@ type Props = {
isNotAllowed: boolean; isNotAllowed: boolean;
}; };
export const ViewLabelSelect: React.FC<Props> = ({ export const ViewLabelSelect: React.FC<Props> = observer((props) => {
const {
issue, issue,
partialUpdateIssue, partialUpdateIssue,
position = "left", position = "left",
@ -37,20 +36,21 @@ export const ViewLabelSelect: React.FC<Props> = ({
user, user,
isNotAllowed, isNotAllowed,
customButton = false, customButton = false,
}) => { } = props;
const [labelModal, setLabelModal] = useState(false); const [labelModal, setLabelModal] = useState(false);
const router = useRouter(); const router = useRouter();
const { workspaceSlug, projectId } = router.query; const { workspaceSlug, projectId } = router.query;
const { data: issueLabels } = useSWR<IIssueLabels[]>( const { label: labelStore } = useMobxStore();
projectId ? PROJECT_ISSUE_LABELS(projectId.toString()) : null, const { labels, loadLabels, getLabelById } = labelStore;
workspaceSlug && projectId
? () => issuesService.getIssueLabels(workspaceSlug as string, projectId as string)
: null
);
const options = issueLabels?.map((label) => ({ useEffect(() => {
if (workspaceSlug && projectId) loadLabels(workspaceSlug.toString(), projectId.toString());
}, [workspaceSlug, projectId, loadLabels]);
const options = labels?.map((label) => ({
value: label.id, value: label.id,
query: label.name, query: label.name,
content: ( content: (
@ -74,7 +74,7 @@ export const ViewLabelSelect: React.FC<Props> = ({
issue.labels.length > 0 issue.labels.length > 0
? issue.labels ? issue.labels
.map((labelId) => { .map((labelId) => {
const label = issueLabels?.find((l) => l.id === labelId); const label = getLabelById(labelId);
return label?.name ?? ""; return label?.name ?? "";
}) })
@ -90,7 +90,7 @@ export const ViewLabelSelect: React.FC<Props> = ({
{issue.labels.length > 0 ? ( {issue.labels.length > 0 ? (
<> <>
{issue.labels.slice(0, 4).map((labelId, index) => { {issue.labels.slice(0, 4).map((labelId, index) => {
const label = issueLabels?.find((l) => l.id === labelId); const label = getLabelById(labelId);
return ( return (
<div className={`flex h-4 w-4 rounded-full ${index ? "-ml-3.5" : ""}`}> <div className={`flex h-4 w-4 rounded-full ${index ? "-ml-3.5" : ""}`}>
@ -154,4 +154,4 @@ export const ViewLabelSelect: React.FC<Props> = ({
/> />
</> </>
); );
}; });

View File

@ -4,6 +4,10 @@ import { useRouter } from "next/router";
import useSWR from "swr"; import useSWR from "swr";
// mobx
import { observer } from "mobx-react-lite";
import { useMobxStore } from "lib/mobx/store-provider";
// react-hook-form // react-hook-form
import { useForm } from "react-hook-form"; import { useForm } from "react-hook-form";
// services // services
@ -20,9 +24,8 @@ import { checkIfArraysHaveSameElements } from "helpers/array.helper";
import { getStatesList } from "helpers/state.helper"; import { getStatesList } from "helpers/state.helper";
// types // types
import { IQuery, IView } from "types"; import { IQuery, IView } from "types";
import issuesService from "services/issues.service";
// fetch-keys // fetch-keys
import { PROJECT_ISSUE_LABELS, STATES_LIST } from "constants/fetch-keys"; import { STATES_LIST } from "constants/fetch-keys";
type Props = { type Props = {
handleFormSubmit: (values: IView) => Promise<void>; handleFormSubmit: (values: IView) => Promise<void>;
@ -37,13 +40,9 @@ const defaultValues: Partial<IView> = {
description: "", description: "",
}; };
export const ViewForm: React.FC<Props> = ({ export const ViewForm: React.FC<Props> = observer((props) => {
handleFormSubmit, const { handleFormSubmit, handleClose, status, data, preLoadedData } = props;
handleClose,
status,
data,
preLoadedData,
}) => {
const router = useRouter(); const router = useRouter();
const { workspaceSlug, projectId } = router.query; const { workspaceSlug, projectId } = router.query;
@ -69,16 +68,16 @@ export const ViewForm: React.FC<Props> = ({
); );
const states = getStatesList(stateGroups); const states = getStatesList(stateGroups);
const { data: labels } = useSWR( const { label: labelStore } = useMobxStore();
workspaceSlug && projectId && (filters?.labels ?? []).length > 0 const { labels, loadLabels } = labelStore;
? PROJECT_ISSUE_LABELS(projectId.toString())
: null,
workspaceSlug && projectId && (filters?.labels ?? []).length > 0
? () => issuesService.getIssueLabels(workspaceSlug.toString(), projectId.toString())
: null
);
const { members } = useProjectMembers(workspaceSlug?.toString(), projectId?.toString()); const { members } = useProjectMembers(workspaceSlug?.toString(), projectId?.toString());
useEffect(() => {
if (workspaceSlug && projectId && (filters?.labels ?? []).length > 0)
loadLabels(workspaceSlug.toString(), projectId.toString());
}, [workspaceSlug, projectId, loadLabels, filters]);
const handleCreateUpdateView = async (formData: IView) => { const handleCreateUpdateView = async (formData: IView) => {
await handleFormSubmit(formData); await handleFormSubmit(formData);
@ -211,4 +210,4 @@ export const ViewForm: React.FC<Props> = ({
</div> </div>
</form> </form>
); );
}; });

View File

@ -1,13 +1,16 @@
import { useState } from "react"; import { useState, useEffect } from "react";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import useSWR from "swr"; import useSWR from "swr";
// mobx
import { observer } from "mobx-react-lite";
import { useMobxStore } from "lib/mobx/store-provider";
// services // services
import stateService from "services/state.service"; import stateService from "services/state.service";
import projectService from "services/project.service"; import projectService from "services/project.service";
import issuesService from "services/issues.service";
// components // components
import { DueDateFilterModal } from "components/core"; import { DueDateFilterModal } from "components/core";
// ui // ui
@ -20,7 +23,7 @@ import { checkIfArraysHaveSameElements } from "helpers/array.helper";
// types // types
import { IIssueFilterOptions, IQuery } from "types"; import { IIssueFilterOptions, IQuery } from "types";
// fetch-keys // fetch-keys
import { PROJECT_ISSUE_LABELS, PROJECT_MEMBERS, STATES_LIST } from "constants/fetch-keys"; import { PROJECT_MEMBERS, STATES_LIST } from "constants/fetch-keys";
// constants // constants
import { PRIORITIES } from "constants/project"; import { PRIORITIES } from "constants/project";
import { DUE_DATES } from "constants/due-dates"; import { DUE_DATES } from "constants/due-dates";
@ -32,17 +35,17 @@ type Props = {
height?: "sm" | "md" | "rg" | "lg"; height?: "sm" | "md" | "rg" | "lg";
}; };
export const SelectFilters: React.FC<Props> = ({ export const SelectFilters: React.FC<Props> = observer((props) => {
filters, const { filters, onSelect, direction = "right", height = "md" } = props;
onSelect,
direction = "right",
height = "md",
}) => {
const [isDueDateFilterModalOpen, setIsDueDateFilterModalOpen] = useState(false); const [isDueDateFilterModalOpen, setIsDueDateFilterModalOpen] = useState(false);
const router = useRouter(); const router = useRouter();
const { workspaceSlug, projectId } = router.query; const { workspaceSlug, projectId } = router.query;
const { label: labelStore } = useMobxStore();
const { labels, loadLabels } = labelStore;
const { data: states } = useSWR( const { data: states } = useSWR(
workspaceSlug && projectId ? STATES_LIST(projectId as string) : null, workspaceSlug && projectId ? STATES_LIST(projectId as string) : null,
workspaceSlug && projectId workspaceSlug && projectId
@ -58,12 +61,9 @@ export const SelectFilters: React.FC<Props> = ({
: null : null
); );
const { data: issueLabels } = useSWR( useEffect(() => {
projectId ? PROJECT_ISSUE_LABELS(projectId.toString()) : null, if (workspaceSlug && projectId) loadLabels(workspaceSlug.toString(), projectId.toString());
workspaceSlug && projectId }, [workspaceSlug, projectId, loadLabels]);
? () => issuesService.getIssueLabels(workspaceSlug as string, projectId.toString())
: null
);
return ( return (
<> <>
@ -160,9 +160,9 @@ export const SelectFilters: React.FC<Props> = ({
{ {
id: "labels", id: "labels",
label: "Labels", label: "Labels",
value: issueLabels, value: labels,
hasChildren: true, hasChildren: true,
children: issueLabels?.map((label) => ({ children: labels?.map((label) => ({
id: label.id, id: label.id,
label: ( label: (
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
@ -216,4 +216,4 @@ export const SelectFilters: React.FC<Props> = ({
/> />
</> </>
); );
}; });

View File

@ -4,6 +4,10 @@ import { useRouter } from "next/router";
import useSWR, { mutate } from "swr"; import useSWR, { mutate } from "swr";
// mobx
import { observer } from "mobx-react-lite";
import { useMobxStore } from "lib/mobx/store-provider";
// react-hook-form // react-hook-form
import { useForm } from "react-hook-form"; import { useForm } from "react-hook-form";
// headless ui // headless ui
@ -16,7 +20,6 @@ import StrictModeDroppable from "components/dnd/StrictModeDroppable";
// services // services
import projectService from "services/project.service"; import projectService from "services/project.service";
import pagesService from "services/pages.service"; import pagesService from "services/pages.service";
import issuesService from "services/issues.service";
// hooks // hooks
import useToast from "hooks/use-toast"; import useToast from "hooks/use-toast";
import useUser from "hooks/use-user"; import useUser from "hooks/use-user";
@ -56,13 +59,12 @@ import { copyTextToClipboard, truncateText } from "helpers/string.helper";
import { orderArrayBy } from "helpers/array.helper"; import { orderArrayBy } from "helpers/array.helper";
// types // types
import type { NextPage } from "next"; import type { NextPage } from "next";
import { IIssueLabels, IPage, IPageBlock, IProjectMember } from "types"; import { IPage, IPageBlock, IProjectMember } from "types";
// fetch-keys // fetch-keys
import { import {
PAGE_BLOCKS_LIST, PAGE_BLOCKS_LIST,
PAGE_DETAILS, PAGE_DETAILS,
PROJECT_DETAILS, PROJECT_DETAILS,
PROJECT_ISSUE_LABELS,
USER_PROJECT_VIEW, USER_PROJECT_VIEW,
} from "constants/fetch-keys"; } from "constants/fetch-keys";
@ -80,6 +82,9 @@ const SinglePage: NextPage = () => {
const { user } = useUser(); const { user } = useUser();
const { label: labelStore } = useMobxStore();
const { labels, loadLabels } = labelStore;
const { handleSubmit, reset, watch, setValue } = useForm<IPage>({ const { handleSubmit, reset, watch, setValue } = useForm<IPage>({
defaultValues: { name: "" }, defaultValues: { name: "" },
}); });
@ -115,13 +120,6 @@ const SinglePage: NextPage = () => {
: null : null
); );
const { data: labels } = useSWR<IIssueLabels[]>(
workspaceSlug && projectId ? PROJECT_ISSUE_LABELS(projectId as string) : null,
workspaceSlug && projectId
? () => issuesService.getIssueLabels(workspaceSlug as string, projectId as string)
: null
);
const { data: memberDetails } = useSWR( const { data: memberDetails } = useSWR(
workspaceSlug && projectId ? USER_PROJECT_VIEW(projectId.toString()) : null, workspaceSlug && projectId ? USER_PROJECT_VIEW(projectId.toString()) : null,
workspaceSlug && projectId workspaceSlug && projectId
@ -129,6 +127,10 @@ const SinglePage: NextPage = () => {
: null : null
); );
useEffect(() => {
if (workspaceSlug && projectId) loadLabels(workspaceSlug.toString(), projectId.toString());
}, [workspaceSlug, projectId, loadLabels]);
const updatePage = async (formData: IPage) => { const updatePage = async (formData: IPage) => {
if (!workspaceSlug || !projectId || !pageId) return; if (!workspaceSlug || !projectId || !pageId) return;
@ -691,4 +693,4 @@ const SinglePage: NextPage = () => {
); );
}; };
export default SinglePage; export default observer(SinglePage);