fix: implementing layouts using _app.tsx get layout method. (#2620)

* fix: implementing layouts in all pages

* fix: layout fixes, implemting using standard nextjs parctice
This commit is contained in:
sriram veeraghanta 2023-11-02 23:57:44 +05:30 committed by GitHub
parent a582021f2c
commit 3c884fd46e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
57 changed files with 1653 additions and 1423 deletions

View file

@ -1,10 +1,6 @@
import React, { useCallback, useEffect, useState } from "react";
import { useCallback, useEffect, useState, ReactElement } from "react";
import { useRouter } from "next/router";
import useSWR, { mutate } from "swr";
// react-hook-form
import { useForm } from "react-hook-form";
// services
import { IssueService, IssueArchiveService } from "services/issue";
@ -22,7 +18,7 @@ import { ArchiveIcon, Loader } from "@plane/ui";
import { History } from "lucide-react";
// types
import { IIssue } from "types";
import type { NextPage } from "next";
import { NextPageWithLayout } from "types/app";
// fetch-keys
import { PROJECT_ISSUES_ACTIVITY, ISSUE_DETAILS } from "constants/fetch-keys";
@ -42,12 +38,13 @@ const defaultValues: Partial<IIssue> = {
const issueService = new IssueService();
const issueArchiveService = new IssueArchiveService();
const ArchivedIssueDetailsPage: NextPage = () => {
const [isRestoring, setIsRestoring] = useState(false);
const ArchivedIssueDetailsPage: NextPageWithLayout = () => {
// router
const router = useRouter();
const { workspaceSlug, projectId, archivedIssueId } = router.query;
// states
const [isRestoring, setIsRestoring] = useState(false);
// hooks
const { user } = useUserAuth();
const { setToastAlert } = useToast();
@ -136,7 +133,7 @@ const ArchivedIssueDetailsPage: NextPage = () => {
};
return (
<AppLayout header={<ProjectArchivedIssueDetailsHeader />} withProjectWrapper>
<>
{issueDetails && projectId ? (
<div className="flex h-full overflow-hidden">
<div className="w-2/3 h-full overflow-y-auto space-y-2 divide-y-2 divide-custom-border-300 p-5">
@ -187,6 +184,14 @@ const ArchivedIssueDetailsPage: NextPage = () => {
</div>
</Loader>
)}
</>
);
};
ArchivedIssueDetailsPage.getLayout = function getLayout(page: ReactElement) {
return (
<AppLayout header={<ProjectArchivedIssueDetailsHeader />} withProjectWrapper>
{page}
</AppLayout>
);
};

View file

@ -1,5 +1,5 @@
import { ReactElement } from "react";
import { useRouter } from "next/router";
// layouts
import { AppLayout } from "layouts/app-layout";
// contexts
@ -10,33 +10,38 @@ import { ProjectArchivedIssuesHeader } from "components/headers";
// icons
import { X } from "lucide-react";
// types
import type { NextPage } from "next";
import { NextPageWithLayout } from "types/app";
const ProjectArchivedIssues: NextPage = () => {
const ProjectArchivedIssuesPage: NextPageWithLayout = () => {
const router = useRouter();
const { workspaceSlug, projectId } = router.query;
return (
<div className="h-full w-full flex flex-col">
<div className="flex items-center ga-1 px-4 py-2.5 shadow-sm border-b border-custom-border-200">
<button
type="button"
onClick={() => router.push(`/${workspaceSlug}/projects/${projectId}/issues/`)}
className="flex items-center gap-1.5 rounded-full border border-custom-border-200 px-3 py-1.5 text-xs"
>
<ArchiveIcon className="h-4 w-4" />
<span>Archived Issues</span>
<X className="h-3 w-3" />
</button>
</div>
{/* <IssuesView /> */}
</div>
);
};
ProjectArchivedIssuesPage.getLayout = function getLayout(page: ReactElement) {
return (
<IssueViewContextProvider>
<AppLayout header={<ProjectArchivedIssuesHeader />} withProjectWrapper>
<div className="h-full w-full flex flex-col">
<div className="flex items-center ga-1 px-4 py-2.5 shadow-sm border-b border-custom-border-200">
<button
type="button"
onClick={() => router.push(`/${workspaceSlug}/projects/${projectId}/issues/`)}
className="flex items-center gap-1.5 rounded-full border border-custom-border-200 px-3 py-1.5 text-xs"
>
<ArchiveIcon className="h-4 w-4" />
<span>Archived Issues</span>
<X className="h-3 w-3" />
</button>
</div>
{/* <IssuesView /> */}
</div>
{page}
</AppLayout>
</IssueViewContextProvider>
);
};
export default ProjectArchivedIssues;
export default ProjectArchivedIssuesPage;

View file

@ -1,4 +1,4 @@
import React, { useState } from "react";
import { useState, ReactElement } from "react";
import { useRouter } from "next/router";
import useSWR from "swr";
// mobx store
@ -22,10 +22,11 @@ import { EmptyState } from "components/common";
import emptyCycle from "public/empty-state/cycle.svg";
// types
import { ISearchIssueResponse } from "types";
import { NextPageWithLayout } from "types/app";
const issueService = new IssueService();
const SingleCycle: React.FC = () => {
const CycleDetailPage: NextPageWithLayout = () => {
const [cycleIssuesListModal, setCycleIssuesListModal] = useState(false);
const router = useRouter();
@ -75,7 +76,7 @@ const SingleCycle: React.FC = () => {
};
return (
<AppLayout header={<CycleIssuesHeader />} withProjectWrapper>
<>
{/* TODO: Update logic to bulk add issues to a cycle */}
<ExistingIssuesListModal
isOpen={cycleIssuesListModal}
@ -113,8 +114,16 @@ const SingleCycle: React.FC = () => {
</div>
</>
)}
</>
);
};
CycleDetailPage.getLayout = function getLayout(page: ReactElement) {
return (
<AppLayout header={<CycleIssuesHeader />} withProjectWrapper>
{page}
</AppLayout>
);
};
export default SingleCycle;
export default CycleDetailPage;

View file

@ -1,4 +1,4 @@
import { Fragment, useCallback, useEffect, useState } from "react";
import { Fragment, useCallback, useEffect, useState, ReactElement } from "react";
import { useRouter } from "next/router";
import { Tab } from "@headlessui/react";
import useSWR from "swr";
@ -13,19 +13,20 @@ import { CyclesHeader } from "components/headers";
import { CyclesView, ActiveCycleDetails, CycleCreateUpdateModal } from "components/cycles";
// ui
import { EmptyState } from "components/common";
import { Tooltip } from "@plane/ui";
// images
import emptyCycle from "public/empty-state/cycle.svg";
// types
import { TCycleView, TCycleLayout } from "types";
import type { NextPage } from "next";
import { NextPageWithLayout } from "types/app";
// constants
import { CYCLE_TAB_LIST, CYCLE_VIEWS } from "constants/cycle";
// lib cookie
import { setLocalStorage, getLocalStorage } from "lib/local-storage";
import { Tooltip } from "@plane/ui";
// helpers
import { replaceUnderscoreIfSnakeCase } from "helpers/string.helper";
const ProjectCyclesPage: NextPage = observer(() => {
const ProjectCyclesPage: NextPageWithLayout = observer(() => {
const [createModal, setCreateModal] = useState(false);
// store
const { project: projectStore, cycle: cycleStore } = useMobxStore();
@ -85,7 +86,7 @@ const ProjectCyclesPage: NextPage = observer(() => {
const cycleLayout = cycleStore?.cycleLayout;
return (
<AppLayout header={<CyclesHeader name={currentProjectDetails?.name} />} withProjectWrapper>
<>
<CycleCreateUpdateModal
workspaceSlug={workspaceSlug}
projectId={projectId}
@ -217,8 +218,16 @@ const ProjectCyclesPage: NextPage = observer(() => {
</Tab.Panels>
</Tab.Group>
)}
</AppLayout>
</>
);
});
ProjectCyclesPage.getLayout = function getLayout(page: ReactElement) {
return (
<AppLayout header={<CyclesHeader />} withProjectWrapper>
{page}
</AppLayout>
);
};
export default ProjectCyclesPage;

View file

@ -1,3 +1,4 @@
import { ReactElement } from "react";
import { useRouter } from "next/router";
// layouts
import { AppLayout } from "layouts/app-layout";
@ -8,32 +9,38 @@ import { ProjectDraftIssueHeader } from "components/headers";
// icons
import { X, PenSquare } from "lucide-react";
// types
import type { NextPage } from "next";
import { NextPageWithLayout } from "types/app";
const ProjectDraftIssues: NextPage = () => {
const ProjectDraftIssuesPage: NextPageWithLayout = () => {
const router = useRouter();
const { workspaceSlug, projectId } = router.query;
return (
<div className="h-full w-full flex flex-col">
<div className="flex items-center ga-1 px-4 py-2.5 shadow-sm border-b border-custom-border-200">
<button
type="button"
onClick={() => router.push(`/${workspaceSlug}/projects/${projectId}/issues/`)}
className="flex items-center gap-1.5 rounded border border-custom-border-200 px-3 py-1.5 text-xs"
>
<PenSquare className="h-3 w-3 text-custom-text-300" />
<span>Draft Issues</span>
<X className="h-3 w-3" />
</button>
</div>
</div>
);
};
ProjectDraftIssuesPage.getLayout = function getLayout(page: ReactElement) {
return (
<IssueViewContextProvider>
<AppLayout header={<ProjectDraftIssueHeader />} withProjectWrapper>
<div className="h-full w-full flex flex-col">
<div className="flex items-center ga-1 px-4 py-2.5 shadow-sm border-b border-custom-border-200">
<button
type="button"
onClick={() => router.push(`/${workspaceSlug}/projects/${projectId}/issues/`)}
className="flex items-center gap-1.5 rounded border border-custom-border-200 px-3 py-1.5 text-xs"
>
<PenSquare className="h-3 w-3 text-custom-text-300" />
<span>Draft Issues</span>
<X className="h-3 w-3" />
</button>
</div>
</div>
{page}
</AppLayout>
</IssueViewContextProvider>
);
};
export default ProjectDraftIssues;
export default ProjectDraftIssuesPage;

View file

@ -1,6 +1,5 @@
import { ReactElement } from "react";
import { useRouter } from "next/router";
import { NextPage } from "next";
import useSWR from "swr";
// hooks
import { useMobxStore } from "lib/mobx/store-provider";
@ -9,8 +8,10 @@ import { AppLayout } from "layouts/app-layout";
// components
import { InboxActionsHeader, InboxMainContent, InboxIssuesListSidebar } from "components/inbox";
import { ProjectInboxHeader } from "components/headers";
// types
import { NextPageWithLayout } from "types/app";
const ProjectInbox: NextPage = () => {
const ProjectInboxPage: NextPageWithLayout = () => {
const router = useRouter();
const { workspaceSlug, projectId, inboxId } = router.query;
@ -24,18 +25,24 @@ const ProjectInbox: NextPage = () => {
);
return (
<AppLayout header={<ProjectInboxHeader />} withProjectWrapper>
<div className="flex flex-col h-full">
<InboxActionsHeader />
<div className="grid grid-cols-4 flex-1 divide-x divide-custom-border-200 overflow-hidden">
<InboxIssuesListSidebar />
<div className="col-span-3 h-full overflow-auto">
<InboxMainContent />
</div>
<div className="flex flex-col h-full">
<InboxActionsHeader />
<div className="grid grid-cols-4 flex-1 divide-x divide-custom-border-200 overflow-hidden">
<InboxIssuesListSidebar />
<div className="col-span-3 h-full overflow-auto">
<InboxMainContent />
</div>
</div>
</div>
);
};
ProjectInboxPage.getLayout = function getLayout(page: ReactElement) {
return (
<AppLayout header={<ProjectInboxHeader />} withProjectWrapper>
{page}
</AppLayout>
);
};
export default ProjectInbox;
export default ProjectInboxPage;

View file

@ -1,9 +1,6 @@
import React, { useCallback, useEffect } from "react";
import React, { useCallback, useEffect, ReactElement } from "react";
import { useRouter } from "next/router";
import useSWR, { mutate } from "swr";
// react-hook-form
import { useForm } from "react-hook-form";
// services
import { IssueService } from "services/issue";
@ -21,10 +18,9 @@ import { Loader } from "@plane/ui";
import emptyIssue from "public/empty-state/issue.svg";
// types
import { IIssue } from "types";
import type { NextPage } from "next";
import { NextPageWithLayout } from "types/app";
// fetch-keys
import { PROJECT_ISSUES_ACTIVITY, ISSUE_DETAILS } from "constants/fetch-keys";
// helper
const defaultValues: Partial<IIssue> = {
description: "",
@ -42,10 +38,10 @@ const defaultValues: Partial<IIssue> = {
// services
const issueService = new IssueService();
const IssueDetailsPage: NextPage = () => {
const IssueDetailsPage: NextPageWithLayout = () => {
// router
const router = useRouter();
const { workspaceSlug, projectId, issueId } = router.query;
// console.log(workspaceSlug, "workspaceSlug")
const { user } = useUserAuth();
@ -111,7 +107,8 @@ const IssueDetailsPage: NextPage = () => {
}, [issueDetails, reset, issueId]);
return (
<AppLayout header={<ProjectIssueDetailsHeader />} withProjectWrapper>
<>
{" "}
{error ? (
<EmptyState
image={emptyIssue}
@ -152,6 +149,14 @@ const IssueDetailsPage: NextPage = () => {
</div>
</Loader>
)}
</>
);
};
IssueDetailsPage.getLayout = function getLayout(page: ReactElement) {
return (
<AppLayout header={<ProjectIssueDetailsHeader />} withProjectWrapper>
{page}
</AppLayout>
);
};

View file

@ -1,17 +1,24 @@
import { ReactElement } from "react";
// components
import { ProjectLayoutRoot } from "components/issues";
import { ProjectIssuesHeader } from "components/headers";
// types
import type { NextPage } from "next";
import { NextPageWithLayout } from "types/app";
// layouts
import { AppLayout } from "layouts/app-layout";
const ProjectIssues: NextPage = () => (
<AppLayout header={<ProjectIssuesHeader />} withProjectWrapper>
<div className="h-full w-full">
<ProjectLayoutRoot />
</div>
</AppLayout>
const ProjectIssuesPage: NextPageWithLayout = () => (
<div className="h-full w-full">
<ProjectLayoutRoot />
</div>
);
export default ProjectIssues;
ProjectIssuesPage.getLayout = function getLayout(page: ReactElement) {
return (
<AppLayout header={<ProjectIssuesHeader />} withProjectWrapper>
{page}
</AppLayout>
);
};
export default ProjectIssuesPage;

View file

@ -1,9 +1,8 @@
import React, { useState } from "react";
import { useState, ReactElement } from "react";
import { useRouter } from "next/router";
import useSWR from "swr";
// mobx store
import { useMobxStore } from "lib/mobx/store-provider";
// services
import { ModuleService } from "services/module.service";
// hooks
@ -22,23 +21,23 @@ import { EmptyState } from "components/common";
// assets
import emptyModule from "public/empty-state/module.svg";
// types
import { NextPage } from "next";
import { NextPageWithLayout } from "types/app";
import { ISearchIssueResponse } from "types";
const moduleService = new ModuleService();
const ModuleIssuesPage: NextPage = () => {
const ModuleIssuesPage: NextPageWithLayout = () => {
// states
const [moduleIssuesListModal, setModuleIssuesListModal] = useState(false);
// router
const router = useRouter();
const { workspaceSlug, projectId, moduleId } = router.query;
// store
const { module: moduleStore } = useMobxStore();
// hooks
const { user } = useUser();
const { setToastAlert } = useToast();
// local storage
const { setValue, storedValue } = useLocalStorage("module_sidebar_collapsed", "false");
const isSidebarCollapsed = storedValue ? (storedValue === "true" ? true : false) : false;
@ -78,45 +77,51 @@ const ModuleIssuesPage: NextPage = () => {
return (
<>
<AppLayout header={<ModuleIssuesHeader />} withProjectWrapper>
{/* TODO: Update logic to bulk add issues to a cycle */}
<ExistingIssuesListModal
isOpen={moduleIssuesListModal}
handleClose={() => setModuleIssuesListModal(false)}
searchParams={{ module: true }}
handleOnSubmit={handleAddIssuesToModule}
{/* TODO: Update logic to bulk add issues to a cycle */}
<ExistingIssuesListModal
isOpen={moduleIssuesListModal}
handleClose={() => setModuleIssuesListModal(false)}
searchParams={{ module: true }}
handleOnSubmit={handleAddIssuesToModule}
/>
{error ? (
<EmptyState
image={emptyModule}
title="Module does not exist"
description="The module you are looking for does not exist or has been deleted."
primaryButton={{
text: "View other modules",
onClick: () => router.push(`/${workspaceSlug}/projects/${projectId}/modules`),
}}
/>
{error ? (
<EmptyState
image={emptyModule}
title="Module does not exist"
description="The module you are looking for does not exist or has been deleted."
primaryButton={{
text: "View other modules",
onClick: () => router.push(`/${workspaceSlug}/projects/${projectId}/modules`),
}}
/>
) : (
<div className="flex h-full w-full">
<div className="h-full w-full overflow-hidden">
<ModuleLayoutRoot openIssuesListModal={openIssuesListModal} />
</div>
{moduleId && !isSidebarCollapsed && (
<div
className="flex flex-col gap-3.5 h-full w-[24rem] z-10 overflow-y-auto border-l border-custom-border-100 bg-custom-sidebar-background-100 px-6 py-3.5 duration-300 flex-shrink-0"
style={{
boxShadow:
"0px 1px 4px 0px rgba(0, 0, 0, 0.06), 0px 2px 4px 0px rgba(16, 24, 40, 0.06), 0px 1px 8px -1px rgba(16, 24, 40, 0.06)",
}}
>
<ModuleDetailsSidebar moduleId={moduleId.toString()} handleClose={toggleSidebar} />
</div>
)}
) : (
<div className="flex h-full w-full">
<div className="h-full w-full overflow-hidden">
<ModuleLayoutRoot openIssuesListModal={openIssuesListModal} />
</div>
)}
</AppLayout>
{moduleId && !isSidebarCollapsed && (
<div
className="flex flex-col gap-3.5 h-full w-[24rem] z-10 overflow-y-auto border-l border-custom-border-100 bg-custom-sidebar-background-100 px-6 py-3.5 duration-300 flex-shrink-0"
style={{
boxShadow:
"0px 1px 4px 0px rgba(0, 0, 0, 0.06), 0px 2px 4px 0px rgba(16, 24, 40, 0.06), 0px 1px 8px -1px rgba(16, 24, 40, 0.06)",
}}
>
<ModuleDetailsSidebar moduleId={moduleId.toString()} handleClose={toggleSidebar} />
</div>
)}
</div>
)}
</>
);
};
ModuleIssuesPage.getLayout = function getLayout(page: ReactElement) {
return (
<AppLayout header={<ModuleIssuesHeader />} withProjectWrapper>
{page}
</AppLayout>
);
};
export default ModuleIssuesPage;

View file

@ -1,15 +1,20 @@
import React from "react";
import { NextPage } from "next";
import { ReactElement } from "react";
// layouts
import { AppLayout } from "layouts/app-layout";
// components
import { ModulesListView } from "components/modules";
import { ModulesListHeader } from "components/headers";
// types
import { NextPageWithLayout } from "types/app";
const ProjectModules: NextPage = () => (
<AppLayout header={<ModulesListHeader />} withProjectWrapper>
<ModulesListView />
</AppLayout>
);
const ProjectModulesPage: NextPageWithLayout = () => <ModulesListView />;
export default ProjectModules;
ProjectModulesPage.getLayout = function getLayout(page: ReactElement) {
return (
<AppLayout header={<ModulesListHeader />} withProjectWrapper>
{page}
</AppLayout>
);
};
export default ProjectModulesPage;

View file

@ -1,18 +1,10 @@
import React, { useEffect, useRef, useState } from "react";
import React, { useEffect, useRef, useState, ReactElement } from "react";
import { useRouter } from "next/router";
import useSWR, { mutate } from "swr";
// react-hook-form
import { Controller, useForm } from "react-hook-form";
// headless ui
import { Popover, Transition } from "@headlessui/react";
// react-color
import { TwitterPicker } from "react-color";
// react-beautiful-dnd
import { DragDropContext, DropResult } from "react-beautiful-dnd";
import StrictModeDroppable from "components/dnd/StrictModeDroppable";
// services
import { ProjectService } from "services/project";
import { PageService } from "services/page.service";
@ -23,6 +15,7 @@ import useUser from "hooks/use-user";
// layouts
import { AppLayout } from "layouts/app-layout";
// components
import StrictModeDroppable from "components/dnd/StrictModeDroppable";
import { CreateUpdateBlockInline, SinglePageBlock } from "components/pages";
import { CreateLabelModal } from "components/labels";
import { CreateBlock } from "components/pages/create-block";
@ -39,7 +32,7 @@ import { render24HourFormatTime, renderShortDate } from "helpers/date-time.helpe
import { copyTextToClipboard } from "helpers/string.helper";
import { orderArrayBy } from "helpers/array.helper";
// types
import type { NextPage } from "next";
import { NextPageWithLayout } from "types/app";
import { IIssueLabels, IPage, IPageBlock, IProjectMember } from "types";
// fetch-keys
import {
@ -55,7 +48,7 @@ const projectService = new ProjectService();
const pageService = new PageService();
const issueLabelService = new IssueLabelService();
const SinglePage: NextPage = () => {
const PageDetailsPage: NextPageWithLayout = () => {
const [createBlockForm, setCreateBlockForm] = useState(false);
const [labelModal, setLabelModal] = useState(false);
const [showBlock, setShowBlock] = useState(false);
@ -302,7 +295,7 @@ const SinglePage: NextPage = () => {
}, [memberDetails]);
return (
<AppLayout header={<PagesHeader />} withProjectWrapper>
<>
{error ? (
<EmptyState
image={emptyPage}
@ -330,7 +323,7 @@ const SinglePage: NextPage = () => {
<Controller
name="name"
control={control}
render={({ field: { value, onChange } }) => (
render={() => (
<TextArea
id="name"
name="name"
@ -627,8 +620,16 @@ const SinglePage: NextPage = () => {
<Loader.Item height="200px" />
</Loader>
)}
</>
);
};
PageDetailsPage.getLayout = function getLayout(page: ReactElement) {
return (
<AppLayout header={<PagesHeader />} withProjectWrapper>
{page}
</AppLayout>
);
};
export default SinglePage;
export default PageDetailsPage;

View file

@ -1,9 +1,6 @@
import { useState, Fragment } from "react";
import { useState, Fragment, ReactElement } from "react";
import { useRouter } from "next/router";
import dynamic from "next/dynamic";
// headless ui
import { Tab } from "@headlessui/react";
// hooks
import useLocalStorage from "hooks/use-local-storage";
@ -17,8 +14,7 @@ import { RecentPagesList, CreateUpdatePageModal, TPagesListProps } from "compone
import { PagesHeader } from "components/headers";
// types
import { TPageViewProps } from "types";
import type { NextPage } from "next";
// fetch-keys
import { NextPageWithLayout } from "types/app";
const AllPagesList = dynamic<TPagesListProps>(() => import("components/pages").then((a) => a.AllPagesList), {
ssr: false,
@ -38,7 +34,7 @@ const OtherPagesList = dynamic<TPagesListProps>(() => import("components/pages")
const tabsList = ["Recent", "All", "Favorites", "Created by me", "Created by others"];
const ProjectPages: NextPage = () => {
const ProjectPagesPage: NextPageWithLayout = () => {
const router = useRouter();
const { workspaceSlug, projectId } = router.query;
// states
@ -68,7 +64,7 @@ const ProjectPages: NextPage = () => {
};
return (
<AppLayout header={<PagesHeader showButton />} withProjectWrapper>
<>
{workspaceSlug && projectId && (
<CreateUpdatePageModal
isOpen={createUpdatePageModal}
@ -160,8 +156,16 @@ const ProjectPages: NextPage = () => {
</Tab.Panels>
</Tab.Group>
</div>
</>
);
};
ProjectPagesPage.getLayout = function getLayout(page: ReactElement) {
return (
<AppLayout header={<PagesHeader showButton />} withProjectWrapper>
{page}
</AppLayout>
);
};
export default ProjectPages;
export default ProjectPagesPage;

View file

@ -1,9 +1,6 @@
import React from "react";
import React, { ReactElement } from "react";
import { useRouter } from "next/router";
import useSWR, { mutate } from "swr";
// services
import { ProjectService } from "services/project";
// layouts
@ -17,7 +14,7 @@ import useToast from "hooks/use-toast";
import { AutoArchiveAutomation, AutoCloseAutomation } from "components/automation";
import { ProjectSettingHeader } from "components/headers";
// types
import type { NextPage } from "next";
import { NextPageWithLayout } from "types/app";
import { IProject } from "types";
// constant
import { PROJECTS_LIST, PROJECT_DETAILS, USER_PROJECT_VIEW } from "constants/fetch-keys";
@ -25,7 +22,7 @@ import { PROJECTS_LIST, PROJECT_DETAILS, USER_PROJECT_VIEW } from "constants/fet
// services
const projectService = new ProjectService();
const AutomationsSettings: NextPage = () => {
const AutomationSettingsPage: NextPageWithLayout = () => {
const router = useRouter();
const { workspaceSlug, projectId } = router.query;
@ -70,19 +67,23 @@ const AutomationsSettings: NextPage = () => {
const isAdmin = memberDetails?.role === 20;
return (
<section className={`pr-9 py-8 w-full overflow-y-auto ${isAdmin ? "" : "opacity-60"}`}>
<div className="flex items-center py-3.5 border-b border-custom-border-200">
<h3 className="text-xl font-medium">Automations</h3>
</div>
<AutoArchiveAutomation projectDetails={projectDetails} handleChange={handleChange} disabled={!isAdmin} />
<AutoCloseAutomation projectDetails={projectDetails} handleChange={handleChange} disabled={!isAdmin} />
</section>
);
};
AutomationSettingsPage.getLayout = function getLayout(page: ReactElement) {
return (
<AppLayout header={<ProjectSettingHeader title="Automations Settings" />} withProjectWrapper>
<ProjectSettingLayout>
<section className={`pr-9 py-8 w-full overflow-y-auto ${isAdmin ? "" : "opacity-60"}`}>
<div className="flex items-center py-3.5 border-b border-custom-border-200">
<h3 className="text-xl font-medium">Automations</h3>
</div>
<AutoArchiveAutomation projectDetails={projectDetails} handleChange={handleChange} disabled={!isAdmin} />
<AutoCloseAutomation projectDetails={projectDetails} handleChange={handleChange} disabled={!isAdmin} />
</section>
</ProjectSettingLayout>
<ProjectSettingLayout>{page}</ProjectSettingLayout>
</AppLayout>
);
};
export default AutomationsSettings;
export default AutomationSettingsPage;

View file

@ -1,4 +1,4 @@
import React from "react";
import { ReactElement } from "react";
// layouts
import { AppLayout } from "layouts/app-layout";
import { ProjectSettingLayout } from "layouts/settings-layout";
@ -6,16 +6,20 @@ import { ProjectSettingLayout } from "layouts/settings-layout";
import { ProjectSettingHeader } from "components/headers";
import { EstimatesList } from "components/estimates/estimate-list";
// types
import type { NextPage } from "next";
import { NextPageWithLayout } from "types/app";
const EstimatesSettings: NextPage = () => (
<AppLayout header={<ProjectSettingHeader title="Estimates Settings" />} withProjectWrapper>
<ProjectSettingLayout>
<div className="pr-9 py-8 w-full overflow-y-auto">
<EstimatesList />
</div>
</ProjectSettingLayout>
</AppLayout>
const EstimatesSettingsPage: NextPageWithLayout = () => (
<div className="pr-9 py-8 w-full overflow-y-auto">
<EstimatesList />
</div>
);
export default EstimatesSettings;
EstimatesSettingsPage.getLayout = function getLayout(page: ReactElement) {
return (
<AppLayout header={<ProjectSettingHeader title="Estimates Settings" />} withProjectWrapper>
<ProjectSettingLayout>{page}; </ProjectSettingLayout>
</AppLayout>
);
};
export default EstimatesSettingsPage;

View file

@ -1,4 +1,4 @@
import React from "react";
import { ReactElement } from "react";
import { useRouter } from "next/router";
import useSWR from "swr";
// mobx store
@ -6,43 +6,43 @@ import { useMobxStore } from "lib/mobx/store-provider";
// layouts
import { AppLayout } from "layouts/app-layout";
import { ProjectSettingLayout } from "layouts/settings-layout";
// hooks
import useUserAuth from "hooks/use-user-auth";
// components
import { ProjectSettingHeader } from "components/headers";
import { ProjectFeaturesList } from "components/project";
// types
import type { NextPage } from "next";
import { NextPageWithLayout } from "types/app";
const FeaturesSettings: NextPage = () => {
const FeaturesSettingsPage: NextPageWithLayout = () => {
const router = useRouter();
const { workspaceSlug, projectId } = router.query;
const {} = useUserAuth();
const { user: userStore } = useMobxStore();
// store
const {
user: { fetchUserProjectInfo },
} = useMobxStore();
const { data: memberDetails } = useSWR(
workspaceSlug && projectId ? `PROJECT_MEMBERS_ME_${workspaceSlug}_${projectId}` : null,
workspaceSlug && projectId
? () => userStore.fetchUserProjectInfo(workspaceSlug.toString(), projectId.toString())
: null
workspaceSlug && projectId ? () => fetchUserProjectInfo(workspaceSlug.toString(), projectId.toString()) : null
);
const isAdmin = memberDetails?.role === 20;
return (
<section className={`pr-9 py-8 w-full overflow-y-auto ${isAdmin ? "" : "opacity-60"}`}>
<div className="flex items-center py-3.5 border-b border-custom-border-200">
<h3 className="text-xl font-medium">Features</h3>
</div>
<ProjectFeaturesList />
</section>
);
};
FeaturesSettingsPage.getLayout = function getLayout(page: ReactElement) {
return (
<AppLayout header={<ProjectSettingHeader title="Features Settings" />} withProjectWrapper>
<ProjectSettingLayout>
<section className={`pr-9 py-8 w-full overflow-y-auto ${isAdmin ? "" : "opacity-60"}`}>
<div className="flex items-center py-3.5 border-b border-custom-border-200">
<h3 className="text-xl font-medium">Features</h3>
</div>
<ProjectFeaturesList />
</section>
</ProjectSettingLayout>
<ProjectSettingLayout>{page}</ProjectSettingLayout>
</AppLayout>
);
};
export default FeaturesSettings;
export default FeaturesSettingsPage;

View file

@ -1,6 +1,5 @@
import { useState } from "react";
import { useState, ReactElement } from "react";
import { useRouter } from "next/router";
import useSWR from "swr";
// layouts
import { AppLayout } from "layouts/app-layout";
@ -14,12 +13,12 @@ import {
ProjectDetailsFormLoader,
} from "components/project";
// types
import type { NextPage } from "next";
import { NextPageWithLayout } from "types/app";
// fetch-keys
import { useMobxStore } from "lib/mobx/store-provider";
import { observer } from "mobx-react-lite";
const GeneralSettings: NextPage = observer(() => {
const GeneralSettingsPage: NextPageWithLayout = observer(() => {
// store
const { project: projectStore } = useMobxStore();
const { currentProjectDetails } = projectStore;
@ -42,37 +41,43 @@ const GeneralSettings: NextPage = observer(() => {
const isAdmin = currentProjectDetails?.member_role === 20;
return (
<AppLayout header={<ProjectSettingHeader title="General Settings" />} withProjectWrapper>
<ProjectSettingLayout>
{currentProjectDetails && (
<DeleteProjectModal
<>
{currentProjectDetails && (
<DeleteProjectModal
project={currentProjectDetails}
isOpen={Boolean(selectProject)}
onClose={() => setSelectedProject(null)}
/>
)}
<div className={`pr-9 py-8 w-full overflow-y-auto ${isAdmin ? "" : "opacity-60"}`}>
{currentProjectDetails && workspaceSlug ? (
<ProjectDetailsForm
project={currentProjectDetails}
isOpen={Boolean(selectProject)}
onClose={() => setSelectedProject(null)}
workspaceSlug={workspaceSlug.toString()}
isAdmin={isAdmin}
/>
) : (
<ProjectDetailsFormLoader />
)}
<div className={`pr-9 py-8 w-full overflow-y-auto ${isAdmin ? "" : "opacity-60"}`}>
{currentProjectDetails && workspaceSlug ? (
<ProjectDetailsForm
project={currentProjectDetails}
workspaceSlug={workspaceSlug.toString()}
isAdmin={isAdmin}
/>
) : (
<ProjectDetailsFormLoader />
)}
{isAdmin && (
<DeleteProjectSection
projectDetails={currentProjectDetails}
handleDelete={() => setSelectedProject(currentProjectDetails.id ?? null)}
/>
)}
</div>
</ProjectSettingLayout>
</AppLayout>
{isAdmin && (
<DeleteProjectSection
projectDetails={currentProjectDetails}
handleDelete={() => setSelectedProject(currentProjectDetails.id ?? null)}
/>
)}
</div>
</>
);
});
export default GeneralSettings;
GeneralSettingsPage.getLayout = function getLayout(page: ReactElement) {
return (
<AppLayout header={<ProjectSettingHeader title="General Settings" />} withProjectWrapper>
<ProjectSettingLayout>{page}</ProjectSettingLayout>
</AppLayout>
);
};
export default GeneralSettingsPage;

View file

@ -1,9 +1,6 @@
import React from "react";
import { ReactElement } from "react";
import { useRouter } from "next/router";
import useSWR from "swr";
// layouts
import { AppLayout } from "layouts/app-layout";
import { ProjectSettingLayout } from "layouts/settings-layout";
@ -20,7 +17,7 @@ import { Loader } from "@plane/ui";
import emptyIntegration from "public/empty-state/integration.svg";
// types
import { IProject } from "types";
import type { NextPage } from "next";
import { NextPageWithLayout } from "types/app";
// fetch-keys
import { PROJECT_DETAILS, WORKSPACE_INTEGRATIONS } from "constants/fetch-keys";
@ -28,7 +25,7 @@ import { PROJECT_DETAILS, WORKSPACE_INTEGRATIONS } from "constants/fetch-keys";
const integrationService = new IntegrationService();
const projectService = new ProjectService();
const ProjectIntegrations: NextPage = () => {
const ProjectIntegrationsPage: NextPageWithLayout = () => {
const router = useRouter();
const { workspaceSlug, projectId } = router.query;
@ -45,43 +42,47 @@ const ProjectIntegrations: NextPage = () => {
const isAdmin = projectDetails?.member_role === 20;
return (
<AppLayout withProjectWrapper header={<ProjectSettingHeader title="Integrations Settings" />}>
<ProjectSettingLayout>
<div className={`pr-9 py-8 gap-10 w-full overflow-y-auto ${isAdmin ? "" : "opacity-60"}`}>
<div className="flex items-center py-3.5 border-b border-custom-border-200">
<h3 className="text-xl font-medium">Integrations</h3>
<div className={`pr-9 py-8 gap-10 w-full overflow-y-auto ${isAdmin ? "" : "opacity-60"}`}>
<div className="flex items-center py-3.5 border-b border-custom-border-200">
<h3 className="text-xl font-medium">Integrations</h3>
</div>
{workspaceIntegrations ? (
workspaceIntegrations.length > 0 ? (
<div>
{workspaceIntegrations.map((integration) => (
<IntegrationCard key={integration.integration_detail.id} integration={integration} />
))}
</div>
{workspaceIntegrations ? (
workspaceIntegrations.length > 0 ? (
<div>
{workspaceIntegrations.map((integration) => (
<IntegrationCard key={integration.integration_detail.id} integration={integration} />
))}
</div>
) : (
<EmptyState
title="You haven't configured integrations"
description="Configure GitHub and other integrations to sync your project issues."
image={emptyIntegration}
primaryButton={{
text: "Configure now",
onClick: () => router.push(`/${workspaceSlug}/settings/integrations`),
}}
disabled={!isAdmin}
/>
)
) : (
<Loader className="space-y-5">
<Loader.Item height="40px" />
<Loader.Item height="40px" />
<Loader.Item height="40px" />
<Loader.Item height="40px" />
</Loader>
)}
</div>
</ProjectSettingLayout>
) : (
<EmptyState
title="You haven't configured integrations"
description="Configure GitHub and other integrations to sync your project issues."
image={emptyIntegration}
primaryButton={{
text: "Configure now",
onClick: () => router.push(`/${workspaceSlug}/settings/integrations`),
}}
disabled={!isAdmin}
/>
)
) : (
<Loader className="space-y-5">
<Loader.Item height="40px" />
<Loader.Item height="40px" />
<Loader.Item height="40px" />
<Loader.Item height="40px" />
</Loader>
)}
</div>
);
};
ProjectIntegrationsPage.getLayout = function getLayout(page: ReactElement) {
return (
<AppLayout withProjectWrapper header={<ProjectSettingHeader title="Integrations Settings" />}>
<ProjectSettingLayout>{page}</ProjectSettingLayout>
</AppLayout>
);
};
export default ProjectIntegrations;
export default ProjectIntegrationsPage;

View file

@ -1,5 +1,4 @@
import React from "react";
import { ReactElement } from "react";
// layouts
import { AppLayout } from "layouts/app-layout";
import { ProjectSettingLayout } from "layouts/settings-layout";
@ -7,16 +6,20 @@ import { ProjectSettingLayout } from "layouts/settings-layout";
import { ProjectSettingsLabelList } from "components/labels";
import { ProjectSettingHeader } from "components/headers";
// types
import type { NextPage } from "next";
import { NextPageWithLayout } from "types/app";
const LabelsSettings: NextPage = () => (
<AppLayout withProjectWrapper header={<ProjectSettingHeader title="Labels Settings" />}>
<ProjectSettingLayout>
<div className="pr-9 py-8 gap-10 w-full overflow-y-auto">
<ProjectSettingsLabelList />
</div>
</ProjectSettingLayout>
</AppLayout>
const LabelsSettingsPage: NextPageWithLayout = () => (
<div className="pr-9 py-8 gap-10 w-full overflow-y-auto">
<ProjectSettingsLabelList />
</div>
);
export default LabelsSettings;
LabelsSettingsPage.getLayout = function getLayout(page: ReactElement) {
return (
<AppLayout withProjectWrapper header={<ProjectSettingHeader title="Labels Settings" />}>
<ProjectSettingLayout>{page}</ProjectSettingLayout>
</AppLayout>
);
};
export default LabelsSettingsPage;

View file

@ -1,3 +1,4 @@
import { ReactElement } from "react";
// layouts
import { AppLayout } from "layouts/app-layout";
import { ProjectSettingLayout } from "layouts/settings-layout";
@ -5,17 +6,21 @@ import { ProjectSettingLayout } from "layouts/settings-layout";
import { ProjectSettingHeader } from "components/headers";
import { ProjectMemberList, ProjectSettingsMemberDefaults } from "components/project";
// types
import type { NextPage } from "next";
import { NextPageWithLayout } from "types/app";
const MembersSettings: NextPage = () => (
<AppLayout header={<ProjectSettingHeader title="Members Settings" />} withProjectWrapper>
<ProjectSettingLayout>
<section className={`pr-9 py-8 w-full overflow-y-auto`}>
<ProjectSettingsMemberDefaults />
<ProjectMemberList />
</section>
</ProjectSettingLayout>
</AppLayout>
const MembersSettingsPage: NextPageWithLayout = () => (
<section className={`pr-9 py-8 w-full overflow-y-auto`}>
<ProjectSettingsMemberDefaults />
<ProjectMemberList />
</section>
);
export default MembersSettings;
MembersSettingsPage.getLayout = function getLayout(page: ReactElement) {
return (
<AppLayout header={<ProjectSettingHeader title="Members Settings" />} withProjectWrapper>
<ProjectSettingLayout>{page}</ProjectSettingLayout>
</AppLayout>
);
};
export default MembersSettingsPage;

View file

@ -1,4 +1,4 @@
import React from "react";
import { ReactElement } from "react";
// layout
import { AppLayout } from "layouts/app-layout";
import { ProjectSettingLayout } from "layouts/settings-layout";
@ -6,20 +6,23 @@ import { ProjectSettingLayout } from "layouts/settings-layout";
import { ProjectSettingStateList } from "components/states";
import { ProjectSettingHeader } from "components/headers";
// types
import type { NextPage } from "next";
import { NextPageWithLayout } from "types/app";
const StatesSettings: NextPage = () => (
<AppLayout withProjectWrapper header={<ProjectSettingHeader title="States Settings" />}>
<ProjectSettingLayout>
<div className="pr-9 py-8 gap-10 w-full overflow-y-auto">
<div className="flex items-center py-3.5 border-b border-custom-border-200">
<h3 className="text-xl font-medium">States</h3>
</div>
<ProjectSettingStateList />
</div>
</ProjectSettingLayout>
</AppLayout>
const StatesSettingsPage: NextPageWithLayout = () => (
<div className="pr-9 py-8 gap-10 w-full overflow-y-auto">
<div className="flex items-center py-3.5 border-b border-custom-border-200">
<h3 className="text-xl font-medium">States</h3>
</div>
<ProjectSettingStateList />
</div>
);
export default StatesSettings;
StatesSettingsPage.getLayout = function getLayout(page: ReactElement) {
return (
<AppLayout withProjectWrapper header={<ProjectSettingHeader title="States Settings" />}>
<ProjectSettingLayout>{page}</ProjectSettingLayout>
</AppLayout>
);
};
export default StatesSettingsPage;

View file

@ -1,3 +1,4 @@
import { ReactElement } from "react";
import { useRouter } from "next/router";
import useSWR from "swr";
// mobx store
@ -12,9 +13,9 @@ import { EmptyState } from "components/common";
// assets
import emptyView from "public/empty-state/view.svg";
// types
import { NextPage } from "next";
import { NextPageWithLayout } from "types/app";
const ProjectViewIssues: NextPage = () => {
const ProjectViewIssuesPage: NextPageWithLayout = () => {
const router = useRouter();
const { workspaceSlug, projectId, viewId } = router.query;
@ -28,7 +29,7 @@ const ProjectViewIssues: NextPage = () => {
);
return (
<AppLayout header={<ProjectViewIssuesHeader />} withProjectWrapper>
<>
{error ? (
<EmptyState
image={emptyView}
@ -42,8 +43,16 @@ const ProjectViewIssues: NextPage = () => {
) : (
<ProjectViewLayoutRoot />
)}
</>
);
};
ProjectViewIssuesPage.getLayout = function getLayout(page: ReactElement) {
return (
<AppLayout header={<ProjectViewIssuesHeader />} withProjectWrapper>
{page}
</AppLayout>
);
};
export default ProjectViewIssues;
export default ProjectViewIssuesPage;

View file

@ -1,5 +1,4 @@
import React from "react";
import type { NextPage } from "next";
import { ReactElement } from "react";
import { useRouter } from "next/router";
import useSWR from "swr";
// mobx store
@ -9,25 +8,31 @@ import { ProjectViewsHeader } from "components/headers";
import { ProjectViewsList } from "components/views";
// layouts
import { AppLayout } from "layouts/app-layout";
// types
import { NextPageWithLayout } from "types/app";
const ProjectViews: NextPage = () => {
const ProjectViewsPage: NextPageWithLayout = () => {
const router = useRouter();
const { workspaceSlug, projectId } = router.query;
const { projectViews: projectViewsStore } = useMobxStore();
// store
const {
projectViews: { fetchAllViews },
} = useMobxStore();
useSWR(
workspaceSlug && projectId ? `PROJECT_VIEWS_LIST_${workspaceSlug.toString()}_${projectId.toString()}` : null,
workspaceSlug && projectId
? () => projectViewsStore.fetchAllViews(workspaceSlug.toString(), projectId.toString())
: null
workspaceSlug && projectId ? () => fetchAllViews(workspaceSlug.toString(), projectId.toString()) : null
);
return <ProjectViewsList />;
};
ProjectViewsPage.getLayout = function getLayout(page: ReactElement) {
return (
<AppLayout header={<ProjectViewsHeader />} withProjectWrapper>
<ProjectViewsList />
{page}
</AppLayout>
);
};
export default ProjectViews;
export default ProjectViewsPage;