import { useCallback, useState } from "react"; import { useRouter } from "next/router"; import useSWR, { mutate } from "swr"; // hook import useToast from "hooks/use-toast"; import useWorkspaceIssuesFilters from "hooks/use-worskpace-issue-filter"; import useProjects from "hooks/use-projects"; import useUser from "hooks/use-user"; import useWorkspaceMembers from "hooks/use-workspace-members"; // context import { useProjectMyMembership } from "contexts/project-member.context"; // services import workspaceService from "services/workspace.service"; import projectIssuesServices from "services/issues.service"; // layouts import { WorkspaceAuthorizationLayout } from "layouts/auth-layout"; // components import { FiltersList, SpreadsheetView } from "components/core"; import { WorkspaceViewsNavigation } from "components/workspace/views/workpace-view-navigation"; import { WorkspaceIssuesViewOptions } from "components/issues/workspace-views/workspace-issue-view-option"; import { CreateUpdateViewModal } from "components/views"; import { CreateUpdateIssueModal, DeleteIssueModal } from "components/issues"; // ui import { EmptyState, PrimaryButton } from "components/ui"; // icons import { PlusIcon } from "@heroicons/react/24/outline"; import { CheckCircle } from "lucide-react"; // images import emptyView from "public/empty-state/view.svg"; // fetch-keys import { WORKSPACE_LABELS, WORKSPACE_VIEWS_LIST, WORKSPACE_VIEW_DETAILS, WORKSPACE_VIEW_ISSUES, } from "constants/fetch-keys"; // constant import { STATE_GROUP } from "constants/project"; // types import { IIssue, IIssueFilterOptions, IView } from "types"; const WorkspaceView: React.FC = () => { const [createViewModal, setCreateViewModal] = useState(null); // create issue modal const [createIssueModal, setCreateIssueModal] = useState(false); const [preloadedData, setPreloadedData] = useState< (Partial & { actionType: "createIssue" | "edit" | "delete" }) | undefined >(undefined); // update issue modal const [editIssueModal, setEditIssueModal] = useState(false); const [issueToEdit, setIssueToEdit] = useState< (IIssue & { actionType: "edit" | "delete" }) | undefined >(undefined); // delete issue modal const [deleteIssueModal, setDeleteIssueModal] = useState(false); const [issueToDelete, setIssueToDelete] = useState(null); const router = useRouter(); const { workspaceSlug, workspaceViewId } = router.query; const { memberRole } = useProjectMyMembership(); const { user } = useUser(); const { setToastAlert } = useToast(); const { data: viewDetails, error } = useSWR( workspaceSlug && workspaceViewId ? WORKSPACE_VIEW_DETAILS(workspaceViewId.toString()) : null, workspaceSlug && workspaceViewId ? () => workspaceService.getViewDetails(workspaceSlug.toString(), workspaceViewId.toString()) : null ); const { params, filters, setFilters } = useWorkspaceIssuesFilters( workspaceSlug?.toString(), workspaceViewId?.toString() ); const { isGuest, isViewer } = useWorkspaceMembers( workspaceSlug?.toString(), Boolean(workspaceSlug) ); const { data: viewIssues, mutate: mutateIssues } = useSWR( workspaceSlug && viewDetails ? WORKSPACE_VIEW_ISSUES(workspaceSlug.toString(), params) : null, workspaceSlug && viewDetails ? () => workspaceService.getViewIssues(workspaceSlug.toString(), params) : null ); const { projects: allProjects } = useProjects(); const joinedProjects = allProjects?.filter((p) => p.is_member); const { data: workspaceLabels } = useSWR( workspaceSlug ? WORKSPACE_LABELS(workspaceSlug.toString()) : null, workspaceSlug ? () => projectIssuesServices.getWorkspaceLabels(workspaceSlug.toString()) : null ); const { workspaceMembers } = useWorkspaceMembers(workspaceSlug?.toString() ?? ""); const updateView = async (payload: IIssueFilterOptions) => { const payloadData = { query_data: payload, }; await workspaceService .updateView(workspaceSlug as string, workspaceViewId as string, payloadData) .then((res) => { mutate( WORKSPACE_VIEWS_LIST(workspaceSlug as string), (prevData) => prevData?.map((p) => { if (p.id === res.id) return { ...p, ...payloadData }; return p; }), false ); setToastAlert({ type: "success", title: "Success!", message: "View updated successfully.", }); }) .catch(() => { setToastAlert({ type: "error", title: "Error!", message: "View could not be updated. Please try again.", }); }); }; const makeIssueCopy = useCallback( (issue: IIssue) => { setCreateIssueModal(true); setPreloadedData({ ...issue, name: `${issue.name} (Copy)`, actionType: "createIssue" }); }, [setCreateIssueModal, setPreloadedData] ); const handleEditIssue = useCallback( (issue: IIssue) => { setEditIssueModal(true); setIssueToEdit({ ...issue, actionType: "edit", cycle: issue.issue_cycle ? issue.issue_cycle.cycle : null, module: issue.issue_module ? issue.issue_module.module : null, }); }, [setEditIssueModal, setIssueToEdit] ); const handleDeleteIssue = useCallback( (issue: IIssue) => { setDeleteIssueModal(true); setIssueToDelete(issue); }, [setDeleteIssueModal, setIssueToDelete] ); const handleIssueAction = useCallback( (issue: IIssue, action: "copy" | "edit" | "delete" | "updateDraft") => { if (action === "copy") makeIssueCopy(issue); else if (action === "edit") handleEditIssue(issue); else if (action === "delete") handleDeleteIssue(issue); }, [makeIssueCopy, handleEditIssue, handleDeleteIssue] ); const nullFilters = filters && Object.keys(filters).filter((key) => filters[key as keyof IIssueFilterOptions] === null); const areFiltersApplied = filters && Object.keys(filters).length > 0 && nullFilters.length !== Object.keys(filters).length; const isNotAllowed = isGuest || isViewer; return ( {viewDetails ? `${viewDetails.name} Issues` : "Workspace Issues"} } right={
{ const e = new KeyboardEvent("keydown", { key: "c" }); document.dispatchEvent(e); }} > Add Issue
} > setCreateIssueModal(false)} prePopulateData={{ ...preloadedData, }} onSubmit={async () => { mutateIssues(); }} /> setEditIssueModal(false)} data={issueToEdit} onSubmit={async () => { mutateIssues(); }} /> setDeleteIssueModal(false)} isOpen={deleteIssueModal} data={issueToDelete} user={user} onSubmit={async () => { mutateIssues(); }} /> setCreateViewModal(null)} viewType="workspace" preLoadedData={createViewModal} user={user} />
setCreateViewModal(true)} /> {error ? ( router.push(`/${workspaceSlug}/workspace-views`), }} /> ) : (
{areFiltersApplied && ( <>
setFilters(updatedFilter)} labels={workspaceLabels} members={workspaceMembers?.map((m) => m.member)} stateGroup={STATE_GROUP} project={joinedProjects} clearAllFilters={() => setFilters({ assignees: null, created_by: null, labels: null, priority: null, state_group: null, start_date: null, target_date: null, subscriber: null, project: null, }) } /> { if (workspaceViewId) { updateView(filters); } else setCreateViewModal({ query: filters, }); }} className="flex items-center gap-2 text-sm" > {!workspaceViewId && } {workspaceViewId ? "Update" : "Save"} view
{
} )}
)}
); }; export default WorkspaceView;