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,5 +1,4 @@
import * as React from "react";
import { FC } from "react";
import { useRouter } from "next/router";
import Link from "next/link";
import { Plus } from "lucide-react";
@ -7,16 +6,18 @@ import { Plus } from "lucide-react";
import { Breadcrumbs, BreadcrumbItem, Button } from "@plane/ui";
// helpers
import { truncateText } from "helpers/string.helper";
// hooks
import { useMobxStore } from "lib/mobx/store-provider";
export interface ICyclesHeader {}
export interface ICyclesHeader {
name: string | undefined;
}
export const CyclesHeader: React.FC<ICyclesHeader> = (props) => {
const { name } = props;
export const CyclesHeader: FC<ICyclesHeader> = (props) => {
const {} = props;
// router
const router = useRouter();
const { workspaceSlug } = router.query;
// store
const { project: projectStore } = useMobxStore();
const { currentProjectDetails } = projectStore;
return (
<div
@ -34,7 +35,7 @@ export const CyclesHeader: React.FC<ICyclesHeader> = (props) => {
</Link>
}
/>
<BreadcrumbItem title={`${truncateText(name ?? "Project", 32)} Cycles`} />
<BreadcrumbItem title={`${truncateText(currentProjectDetails?.name ?? "Project Title", 32)} Cycles`} />
</Breadcrumbs>
</div>
</div>

View File

@ -1,4 +1,4 @@
import React, { Fragment, useEffect } from "react";
import React, { Fragment, useEffect, ReactElement } from "react";
import { useRouter } from "next/router";
import { observer } from "mobx-react-lite";
import { Tab } from "@headlessui/react";
@ -18,10 +18,12 @@ import { Plus } from "lucide-react";
import emptyAnalytics from "public/empty-state/analytics.svg";
// constants
import { ANALYTICS_TABS } from "constants/analytics";
// type
import { NextPageWithLayout } from "types/app";
const trackEventService = new TrackEventService();
const AnalyticsPage = observer(() => {
const AnalyticsPage: NextPageWithLayout = observer(() => {
// router
const router = useRouter();
const { workspaceSlug } = router.query;
@ -110,4 +112,8 @@ const AnalyticsPage = observer(() => {
);
});
AnalyticsPage.getLayout = function getLayout(page: ReactElement) {
return <AppLayout header={<WorkspaceAnalyticsHeader />}>{page}</AppLayout>;
};
export default AnalyticsPage;

View File

@ -1,14 +1,16 @@
import type { NextPage } from "next";
import { ReactElement } from "react";
// layouts
import { AppLayout } from "layouts/app-layout";
// components
import { WorkspaceDashboardView } from "components/views";
import { WorkspaceDashboardHeader } from "components/headers/workspace-dashboard";
// types
import { NextPageWithLayout } from "types/app";
const WorkspacePage: NextPage = () => (
<AppLayout header={<WorkspaceDashboardHeader />}>
<WorkspaceDashboardView />
</AppLayout>
);
const WorkspacePage: NextPageWithLayout = () => <WorkspaceDashboardView />;
WorkspacePage.getLayout = function getLayout(page: ReactElement) {
return <AppLayout header={<WorkspaceDashboardHeader />}>{page}</AppLayout>;
};
export default WorkspacePage;

View File

@ -1,3 +1,4 @@
import { ReactElement } from "react";
import useSWR from "swr";
import { useRouter } from "next/router";
import Link from "next/link";
@ -18,10 +19,12 @@ import { ExternalLinkIcon, Loader } from "@plane/ui";
import { USER_ACTIVITY } from "constants/fetch-keys";
// helper
import { timeAgo } from "helpers/date-time.helper";
// type
import { NextPageWithLayout } from "types/app";
const userService = new UserService();
const ProfileActivity = () => {
const ProfileActivityPage: NextPageWithLayout = () => {
const router = useRouter();
const { workspaceSlug } = router.query;
@ -31,8 +34,7 @@ const ProfileActivity = () => {
);
return (
<AppLayout header={<WorkspaceSettingHeader title="My Profile Activity" />}>
<WorkspaceSettingLayout>
<>
{userActivity ? (
<section className="pr-9 py-8 w-full overflow-y-auto">
<div className="flex items-center py-3.5 border-b border-custom-border-200">
@ -132,8 +134,7 @@ const ProfileActivity = () => {
) : (
<ActivityIcon activity={activityItem} />
)
) : activityItem.actor_detail.avatar &&
activityItem.actor_detail.avatar !== "" ? (
) : activityItem.actor_detail.avatar && activityItem.actor_detail.avatar !== "" ? (
<img
src={activityItem.actor_detail.avatar}
alt={activityItem.actor_detail.display_name}
@ -165,8 +166,7 @@ const ProfileActivity = () => {
<a className="text-gray font-medium">{activityItem.actor_detail.display_name}</a>
</Link>
)}{" "}
{message}{" "}
<span className="whitespace-nowrap">{timeAgo(activityItem.created_at)}</span>
{message} <span className="whitespace-nowrap">{timeAgo(activityItem.created_at)}</span>
</div>
</div>
</>
@ -187,9 +187,16 @@ const ProfileActivity = () => {
<Loader.Item height="40px" />
</Loader>
)}
</WorkspaceSettingLayout>
</>
);
};
ProfileActivityPage.getLayout = function getLayout(page: ReactElement) {
return (
<AppLayout header={<WorkspaceSettingHeader title="My Profile Activity" />}>
<WorkspaceSettingLayout>{page}</WorkspaceSettingLayout>
</AppLayout>
);
};
export default ProfileActivity;
export default ProfileActivityPage;

View File

@ -1,4 +1,4 @@
import React, { useEffect, useState } from "react";
import React, { useEffect, useState, ReactElement } from "react";
import { useRouter } from "next/router";
import Link from "next/link";
import { Controller, useForm } from "react-hook-form";
@ -19,8 +19,8 @@ import { Button, CustomSelect, CustomSearchSelect, Input, Spinner } from "@plane
// icons
import { User2, UserCircle2 } from "lucide-react";
// types
import type { NextPage } from "next";
import type { IUser } from "types";
import type { NextPageWithLayout } from "types/app";
// constants
import { USER_ROLES } from "constants/workspace";
import { TIME_ZONES } from "constants/timezones";
@ -38,7 +38,7 @@ const defaultValues: Partial<IUser> = {
const fileService = new FileService();
const userService = new UserService();
const Profile: NextPage = () => {
const ProfilePage: NextPageWithLayout = () => {
const [isRemoving, setIsRemoving] = useState(false);
const [isImageUploadModalOpen, setIsImageUploadModalOpen] = useState(false);
// router
@ -144,8 +144,7 @@ const Profile: NextPage = () => {
}));
return (
<AppLayout header={<WorkspaceSettingHeader title="My Profile" />}>
<WorkspaceSettingLayout>
<>
<ImageUploadModal
isOpen={isImageUploadModalOpen}
onClose={() => setIsImageUploadModalOpen(false)}
@ -390,9 +389,16 @@ const Profile: NextPage = () => {
<Spinner />
</div>
)}
</WorkspaceSettingLayout>
</>
);
};
ProfilePage.getLayout = function getLayout(page: ReactElement) {
return (
<AppLayout header={<WorkspaceSettingHeader title="My Profile" />}>
<WorkspaceSettingLayout>{page}</WorkspaceSettingLayout>
</AppLayout>
);
};
export default Profile;
export default ProfilePage;

View File

@ -1,4 +1,4 @@
import { useEffect, useState } from "react";
import { useEffect, useState, ReactElement } from "react";
import { observer } from "mobx-react-lite";
import { useTheme } from "next-themes";
// hooks
@ -14,8 +14,10 @@ import { WorkspaceSettingHeader } from "components/headers";
import { Spinner } from "@plane/ui";
// constants
import { I_THEME_OPTION, THEME_OPTIONS } from "constants/themes";
// type
import { NextPageWithLayout } from "types/app";
const ProfilePreferencesPage = observer(() => {
const ProfilePreferencesPage: NextPageWithLayout = observer(() => {
const { user: userStore } = useMobxStore();
// states
const [currentTheme, setCurrentTheme] = useState<I_THEME_OPTION | null>(null);
@ -45,8 +47,7 @@ const ProfilePreferencesPage = observer(() => {
};
return (
<AppLayout header={<WorkspaceSettingHeader title="My Profile Preferences" />}>
<WorkspaceSettingLayout>
<>
{userStore.currentUser ? (
<div className="pr-9 py-8 w-full overflow-y-auto">
<div className="flex items-center py-3.5 border-b border-custom-border-200">
@ -68,9 +69,16 @@ const ProfilePreferencesPage = observer(() => {
<Spinner />
</div>
)}
</WorkspaceSettingLayout>
</AppLayout>
</>
);
});
ProfilePreferencesPage.getLayout = function getLayout(page: ReactElement) {
return (
<AppLayout header={<WorkspaceSettingHeader title="My Profile Preferences" />}>
<WorkspaceSettingLayout>{page}</WorkspaceSettingLayout>
</AppLayout>
);
};
export default ProfilePreferencesPage;

View File

@ -1,5 +1,4 @@
import React from "react";
import type { NextPage } from "next";
import React, { ReactElement } from "react";
import { useRouter } from "next/router";
import useSWR from "swr";
import { observer } from "mobx-react-lite";
@ -13,10 +12,10 @@ import { ProfileIssuesKanBanLayout } from "components/issues/issue-layouts/kanba
// hooks
import { useMobxStore } from "lib/mobx/store-provider";
import { RootStore } from "store/root";
// types
import { NextPageWithLayout } from "types/app";
const ProfileAssignedIssues: NextPage = observer(() => {
const ProfileAssignedIssuesPage: NextPageWithLayout = observer(() => {
const {
workspace: workspaceStore,
project: projectStore,
@ -45,8 +44,7 @@ const ProfileAssignedIssues: NextPage = observer(() => {
const activeLayout = profileIssueFiltersStore.userDisplayFilters.layout;
return (
<AppLayout header={<UserProfileHeader />}>
<ProfileAuthWrapper showProfileIssuesFilter>
<>
{isLoading ? (
<div>Loading...</div>
) : (
@ -58,9 +56,16 @@ const ProfileAssignedIssues: NextPage = observer(() => {
) : null}
</div>
)}
</ProfileAuthWrapper>
</AppLayout>
</>
);
});
export default ProfileAssignedIssues;
ProfileAssignedIssuesPage.getLayout = function getLayout(page: ReactElement) {
return (
<AppLayout header={<UserProfileHeader />}>
<ProfileAuthWrapper showProfileIssuesFilter>{page}</ProfileAuthWrapper>
</AppLayout>
);
};
export default ProfileAssignedIssuesPage;

View File

@ -1,4 +1,4 @@
import React from "react";
import { ReactElement } from "react";
import { useRouter } from "next/router";
import useSWR from "swr";
// store
@ -12,9 +12,9 @@ import { UserProfileHeader } from "components/headers";
import { ProfileIssuesListLayout } from "components/issues/issue-layouts/list/roots/profile-issues-root";
import { ProfileIssuesKanBanLayout } from "components/issues/issue-layouts/kanban/roots/profile-issues-root";
// types
import type { NextPage } from "next";
import { NextPageWithLayout } from "types/app";
const ProfileCreatedIssues: NextPage = () => {
const ProfileCreatedIssuesPage: NextPageWithLayout = () => {
const {
workspace: workspaceStore,
project: projectStore,
@ -40,8 +40,7 @@ const ProfileCreatedIssues: NextPage = () => {
const activeLayout = profileIssueFiltersStore.userDisplayFilters.layout;
return (
<AppLayout header={<UserProfileHeader />}>
<ProfileAuthWrapper showProfileIssuesFilter>
<>
{isLoading ? (
<div>Loading...</div>
) : (
@ -53,9 +52,16 @@ const ProfileCreatedIssues: NextPage = () => {
) : null}
</div>
)}
</ProfileAuthWrapper>
</>
);
};
ProfileCreatedIssuesPage.getLayout = function getLayout(page: ReactElement) {
return (
<AppLayout header={<UserProfileHeader />}>
<ProfileAuthWrapper showProfileIssuesFilter>{page}</ProfileAuthWrapper>
</AppLayout>
);
};
export default observer(ProfileCreatedIssues);
export default observer(ProfileCreatedIssuesPage);

View File

@ -1,9 +1,6 @@
import React from "react";
import { ReactElement } from "react";
import { useRouter } from "next/router";
import useSWR from "swr";
// services
import { UserService } from "services/user.service";
// layouts
@ -19,8 +16,8 @@ import {
ProfileWorkload,
} from "components/profile";
// types
import type { NextPage } from "next";
import { IUserStateDistribution, TStateGroups } from "types";
import { NextPageWithLayout } from "types/app";
// constants
import { USER_PROFILE_DATA } from "constants/fetch-keys";
import { GROUP_CHOICES } from "constants/project";
@ -28,7 +25,7 @@ import { GROUP_CHOICES } from "constants/project";
// services
const userService = new UserService();
const ProfileOverview: NextPage = () => {
const ProfileOverviewPage: NextPageWithLayout = () => {
const router = useRouter();
const { workspaceSlug, userId } = router.query;
@ -45,8 +42,6 @@ const ProfileOverview: NextPage = () => {
});
return (
<AppLayout header={<UserProfileHeader />}>
<ProfileAuthWrapper>
<div className="h-full w-full px-5 md:px-9 py-5 space-y-7 overflow-y-auto">
<ProfileStats userProfile={userProfile} />
<ProfileWorkload stateDistribution={stateDistribution} />
@ -56,9 +51,15 @@ const ProfileOverview: NextPage = () => {
</div>
<ProfileActivity />
</div>
</ProfileAuthWrapper>
);
};
ProfileOverviewPage.getLayout = function getLayout(page: ReactElement) {
return (
<AppLayout header={<UserProfileHeader />}>
<ProfileAuthWrapper>{page}</ProfileAuthWrapper>
</AppLayout>
);
};
export default ProfileOverview;
export default ProfileOverviewPage;

View File

@ -1,4 +1,4 @@
import React from "react";
import { ReactElement } from "react";
import { useRouter } from "next/router";
import useSWR from "swr";
// store
@ -12,9 +12,9 @@ import { UserProfileHeader } from "components/headers";
import { ProfileIssuesListLayout } from "components/issues/issue-layouts/list/roots/profile-issues-root";
import { ProfileIssuesKanBanLayout } from "components/issues/issue-layouts/kanban/roots/profile-issues-root";
// types
import type { NextPage } from "next";
import { NextPageWithLayout } from "types/app";
const ProfileSubscribedIssues: NextPage = () => {
const ProfileSubscribedIssuesPage: NextPageWithLayout = () => {
const {
workspace: workspaceStore,
project: projectStore,
@ -58,4 +58,12 @@ const ProfileSubscribedIssues: NextPage = () => {
);
};
export default observer(ProfileSubscribedIssues);
ProfileSubscribedIssuesPage.getLayout = function getLayout(page: ReactElement) {
return (
<AppLayout header={<UserProfileHeader />}>
<ProfileAuthWrapper showProfileIssuesFilter>{page}</ProfileAuthWrapper>
</AppLayout>
);
};
export default observer(ProfileSubscribedIssuesPage);

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,15 +10,13 @@ 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 (
<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
@ -28,15 +26,22 @@ const ProjectArchivedIssues: NextPage = () => {
>
<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>
{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,15 +9,13 @@ 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 (
<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
@ -31,9 +30,17 @@ const ProjectDraftIssues: NextPage = () => {
</button>
</div>
</div>
);
};
ProjectDraftIssuesPage.getLayout = function getLayout(page: ReactElement) {
return (
<IssueViewContextProvider>
<AppLayout header={<ProjectDraftIssueHeader />} withProjectWrapper>
{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,7 +25,6 @@ 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">
@ -34,8 +34,15 @@ const ProjectInbox: NextPage = () => {
</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>
const ProjectIssuesPage: NextPageWithLayout = () => (
<div className="h-full w-full">
<ProjectLayoutRoot />
</div>
</AppLayout>
);
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,7 +77,6 @@ const ModuleIssuesPage: NextPage = () => {
return (
<>
<AppLayout header={<ModuleIssuesHeader />} withProjectWrapper>
{/* TODO: Update logic to bulk add issues to a cycle */}
<ExistingIssuesListModal
isOpen={moduleIssuesListModal}
@ -114,9 +112,16 @@ const ModuleIssuesPage: NextPage = () => {
)}
</div>
)}
</AppLayout>
</>
);
};
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 = () => (
const ProjectModulesPage: NextPageWithLayout = () => <ModulesListView />;
ProjectModulesPage.getLayout = function getLayout(page: ReactElement) {
return (
<AppLayout header={<ModulesListHeader />} withProjectWrapper>
<ModulesListView />
{page}
</AppLayout>
);
};
export default ProjectModules;
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;
@ -71,8 +68,6 @@ const AutomationsSettings: NextPage = () => {
const isAdmin = memberDetails?.role === 20;
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>
@ -80,9 +75,15 @@ const AutomationsSettings: NextPage = () => {
<AutoArchiveAutomation projectDetails={projectDetails} handleChange={handleChange} disabled={!isAdmin} />
<AutoCloseAutomation projectDetails={projectDetails} handleChange={handleChange} disabled={!isAdmin} />
</section>
</ProjectSettingLayout>
);
};
AutomationSettingsPage.getLayout = function getLayout(page: ReactElement) {
return (
<AppLayout header={<ProjectSettingHeader title="Automations Settings" />} withProjectWrapper>
<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>
const EstimatesSettingsPage: NextPageWithLayout = () => (
<div className="pr-9 py-8 w-full overflow-y-auto">
<EstimatesList />
</div>
</ProjectSettingLayout>
</AppLayout>
);
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 (
<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>
);
};
FeaturesSettingsPage.getLayout = function getLayout(page: ReactElement) {
return (
<AppLayout header={<ProjectSettingHeader title="Features Settings" />} withProjectWrapper>
<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,8 +41,7 @@ const GeneralSettings: NextPage = observer(() => {
const isAdmin = currentProjectDetails?.member_role === 20;
return (
<AppLayout header={<ProjectSettingHeader title="General Settings" />} withProjectWrapper>
<ProjectSettingLayout>
<>
{currentProjectDetails && (
<DeleteProjectModal
project={currentProjectDetails}
@ -70,9 +68,16 @@ const GeneralSettings: NextPage = observer(() => {
/>
)}
</div>
</ProjectSettingLayout>
</AppLayout>
</>
);
});
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,8 +42,6 @@ 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>
@ -79,9 +74,15 @@ const ProjectIntegrations: NextPage = () => {
</Loader>
)}
</div>
</ProjectSettingLayout>
);
};
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>
const LabelsSettingsPage: NextPageWithLayout = () => (
<div className="pr-9 py-8 gap-10 w-full overflow-y-auto">
<ProjectSettingsLabelList />
</div>
</ProjectSettingLayout>
</AppLayout>
);
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>
const MembersSettingsPage: NextPageWithLayout = () => (
<section className={`pr-9 py-8 w-full overflow-y-auto`}>
<ProjectSettingsMemberDefaults />
<ProjectMemberList />
</section>
</ProjectSettingLayout>
</AppLayout>
);
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>
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>
</ProjectSettingLayout>
</AppLayout>
);
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;

View File

@ -1,21 +1,23 @@
import { ReactElement } from "react";
import { useRouter } from "next/router";
import type { NextPage } from "next";
// components
import { ProjectCardList } from "components/project";
import { ProjectsHeader } from "components/headers";
// layouts
import { AppLayout } from "layouts/app-layout";
// type
import { NextPageWithLayout } from "types/app";
const ProjectsPage: NextPage = () => {
const ProjectsPage: NextPageWithLayout = () => {
// router
const router = useRouter();
const { workspaceSlug } = router.query;
return (
<AppLayout header={<ProjectsHeader />}>
<>{workspaceSlug && <ProjectCardList workspaceSlug={workspaceSlug.toString()} />}</>
</AppLayout>
);
return <>{workspaceSlug && <ProjectCardList workspaceSlug={workspaceSlug.toString()} />}</>;
};
ProjectsPage.getLayout = function getLayout(page: ReactElement) {
return <AppLayout header={<ProjectsHeader />}>{page}</AppLayout>;
};
export default ProjectsPage;

View File

@ -1,4 +1,4 @@
import React from "react";
import { ReactElement } from "react";
// layouts
import { AppLayout } from "layouts/app-layout";
import { WorkspaceSettingLayout } from "layouts/settings-layout";
@ -7,11 +7,9 @@ import { WorkspaceSettingHeader } from "components/headers";
// ui
import { Button } from "@plane/ui";
// types
import type { NextPage } from "next";
import { NextPageWithLayout } from "types/app";
const BillingSettings: NextPage = () => (
<AppLayout header={<WorkspaceSettingHeader title="Billing & Plans Settings" />}>
<WorkspaceSettingLayout>
const BillingSettingsPage: NextPageWithLayout = () => (
<section className="pr-9 py-8 w-full overflow-y-auto">
<div>
<div className="flex items-center py-3.5 border-b border-custom-border-200">
@ -28,8 +26,14 @@ const BillingSettings: NextPage = () => (
</div>
</div>
</section>
</WorkspaceSettingLayout>
</AppLayout>
);
export default BillingSettings;
BillingSettingsPage.getLayout = function getLayout(page: ReactElement) {
return (
<AppLayout header={<WorkspaceSettingHeader title="Billing & Plans Settings" />}>
<WorkspaceSettingLayout>{page}</WorkspaceSettingLayout>
</AppLayout>
);
};
export default BillingSettingsPage;

View File

@ -1,3 +1,4 @@
import { ReactElement } from "react";
// layout
import { AppLayout } from "layouts/app-layout";
import { WorkspaceSettingLayout } from "layouts/settings-layout";
@ -5,10 +6,9 @@ import { WorkspaceSettingLayout } from "layouts/settings-layout";
import { WorkspaceSettingHeader } from "components/headers";
import ExportGuide from "components/exporter/guide";
// types
import type { NextPage } from "next";
// helper
import { NextPageWithLayout } from "types/app";
const ImportExport: NextPage = () => (
const ExportsPage: NextPageWithLayout = () => (
<AppLayout header={<WorkspaceSettingHeader title="Export Settings" />}>
<WorkspaceSettingLayout>
<div className="pr-9 py-8 w-full overflow-y-auto">
@ -21,4 +21,12 @@ const ImportExport: NextPage = () => (
</AppLayout>
);
export default ImportExport;
ExportsPage.getLayout = function getLayout(page: ReactElement) {
return (
<AppLayout header={<WorkspaceSettingHeader title="Export Settings" />}>
<WorkspaceSettingLayout>{page}</WorkspaceSettingLayout>
</AppLayout>
);
};
export default ExportsPage;

View File

@ -1,23 +1,28 @@
import { ReactElement } from "react";
// layouts
import { WorkspaceSettingLayout } from "layouts/settings-layout";
// components
import { AppLayout } from "layouts/app-layout";
// components
import IntegrationGuide from "components/integration/guide";
import { WorkspaceSettingHeader } from "components/headers";
// types
import type { NextPage } from "next";
import { NextPageWithLayout } from "types/app";
const ImportExport: NextPage = () => (
<AppLayout header={<WorkspaceSettingHeader title="Import Settings" />}>
<WorkspaceSettingLayout>
const ImportsPage: NextPageWithLayout = () => (
<section className="pr-9 py-8 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">Imports</h3>
</div>
<IntegrationGuide />
</section>
</WorkspaceSettingLayout>
</AppLayout>
);
export default ImportExport;
ImportsPage.getLayout = function getLayout(page: ReactElement) {
return (
<AppLayout header={<WorkspaceSettingHeader title="Import Settings" />}>
<WorkspaceSettingLayout>{page}</WorkspaceSettingLayout>
</AppLayout>
);
};
export default ImportsPage;

View File

@ -1,3 +1,4 @@
import { ReactElement } from "react";
// layouts
import { AppLayout } from "layouts/app-layout";
import { WorkspaceSettingLayout } from "layouts/settings-layout";
@ -5,14 +6,16 @@ import { WorkspaceSettingLayout } from "layouts/settings-layout";
import { WorkspaceSettingHeader } from "components/headers";
import { WorkspaceDetails } from "components/workspace";
// types
import type { NextPage } from "next";
import { NextPageWithLayout } from "types/app";
const WorkspaceSettings: NextPage = () => (
const WorkspaceSettingsPage: NextPageWithLayout = () => <WorkspaceDetails />;
WorkspaceSettingsPage.getLayout = function getLayout(page: ReactElement) {
return (
<AppLayout header={<WorkspaceSettingHeader title="General Settings" />}>
<WorkspaceSettingLayout>
<WorkspaceDetails />
</WorkspaceSettingLayout>
<WorkspaceSettingLayout>{page}</WorkspaceSettingLayout>
</AppLayout>
);
};
export default WorkspaceSettings;
export default WorkspaceSettingsPage;

View File

@ -1,9 +1,6 @@
import React from "react";
import { ReactElement } from "react";
import { useRouter } from "next/router";
import useSWR from "swr";
// services
import { IntegrationService } from "services/integrations";
// layouts
@ -12,19 +9,18 @@ import { WorkspaceSettingLayout } from "layouts/settings-layout";
// components
import { SingleIntegrationCard } from "components/integration";
import { WorkspaceSettingHeader } from "components/headers";
import { Loader } from "@plane/ui";
// ui
import { IntegrationAndImportExportBanner } from "components/ui";
import { Loader } from "@plane/ui";
// types
import type { NextPage } from "next";
import { NextPageWithLayout } from "types/app";
// fetch-keys
import { APP_INTEGRATIONS } from "constants/fetch-keys";
// helper
// services
const integrationService = new IntegrationService();
const WorkspaceIntegrations: NextPage = () => {
const WorkspaceIntegrationsPage: NextPageWithLayout = () => {
const router = useRouter();
const { workspaceSlug } = router.query;
@ -33,15 +29,11 @@ const WorkspaceIntegrations: NextPage = () => {
);
return (
<AppLayout header={<WorkspaceSettingHeader title="Export Settings" />}>
<WorkspaceSettingLayout>
<section className="pr-9 py-8 w-full overflow-y-auto">
<IntegrationAndImportExportBanner bannerName="Integrations" />
<div>
{appIntegrations ? (
appIntegrations.map((integration) => (
<SingleIntegrationCard key={integration.id} integration={integration} />
))
appIntegrations.map((integration) => <SingleIntegrationCard key={integration.id} integration={integration} />)
) : (
<Loader className="space-y-2.5 mt-4">
<Loader.Item height="89px" />
@ -50,9 +42,15 @@ const WorkspaceIntegrations: NextPage = () => {
)}
</div>
</section>
</WorkspaceSettingLayout>
);
};
WorkspaceIntegrationsPage.getLayout = function getLayout(page: ReactElement) {
return (
<AppLayout header={<WorkspaceSettingHeader title="Export Settings" />}>
<WorkspaceSettingLayout>{page}</WorkspaceSettingLayout>
</AppLayout>
);
};
export default WorkspaceIntegrations;
export default WorkspaceIntegrationsPage;

View File

@ -1,4 +1,4 @@
import { useState } from "react";
import { useState, ReactElement } from "react";
import { useRouter } from "next/router";
// hooks
import useUser from "hooks/use-user";
@ -10,22 +10,22 @@ import { WorkspaceSettingHeader } from "components/headers";
import { SendWorkspaceInvitationModal, WorkspaceMembersList } from "components/workspace";
// ui
import { Button } from "@plane/ui";
// types
import type { NextPage } from "next";
// icons
import { Search } from "lucide-react";
// types
import { NextPageWithLayout } from "types/app";
const MembersSettings: NextPage = () => {
const [inviteModal, setInviteModal] = useState(false);
const [searchQuery, setSearchQuery] = useState<string>("");
const WorkspaceMembersSettingsPage: NextPageWithLayout = () => {
const router = useRouter();
const { workspaceSlug } = router.query;
// states
const [inviteModal, setInviteModal] = useState(false);
const [searchQuery, setSearchQuery] = useState<string>("");
// hooks
const { user } = useUser();
return (
<AppLayout header={<WorkspaceSettingHeader title="Members Settings" />}>
<WorkspaceSettingLayout>
<>
{workspaceSlug && (
<SendWorkspaceInvitationModal
isOpen={inviteModal}
@ -53,9 +53,16 @@ const MembersSettings: NextPage = () => {
</div>
<WorkspaceMembersList searchQuery={searchQuery} />
</section>
</WorkspaceSettingLayout>
</>
);
};
WorkspaceMembersSettingsPage.getLayout = function getLayout(page: ReactElement) {
return (
<AppLayout header={<WorkspaceSettingHeader title="Members Settings" />}>
<WorkspaceSettingLayout>{page}</WorkspaceSettingLayout>
</AppLayout>
);
};
export default MembersSettings;
export default WorkspaceMembersSettingsPage;

View File

@ -1,6 +1,6 @@
import { ReactElement } from "react";
import { useRouter } from "next/router";
import useSWR from "swr";
// mobx store
import { useMobxStore } from "lib/mobx/store-provider";
// layouts
@ -10,31 +10,35 @@ import { GlobalViewsHeader } from "components/workspace";
import { GlobalViewLayoutRoot } from "components/issues";
import { GlobalIssuesHeader } from "components/headers";
// types
import { NextPage } from "next";
import { NextPageWithLayout } from "types/app";
const GlobalViewIssues: NextPage = () => {
const GlobalViewIssuesPage: NextPageWithLayout = () => {
const router = useRouter();
const { workspaceSlug, globalViewId } = router.query;
const { globalViews: globalViewsStore } = useMobxStore();
const {
globalViews: { fetchGlobalViewDetails },
} = useMobxStore();
useSWR(
workspaceSlug && globalViewId ? `GLOBAL_VIEW_DETAILS_${globalViewId.toString()}` : null,
workspaceSlug && globalViewId
? () => globalViewsStore.fetchGlobalViewDetails(workspaceSlug.toString(), globalViewId.toString())
? () => fetchGlobalViewDetails(workspaceSlug.toString(), globalViewId.toString())
: null
);
return (
<AppLayout header={<GlobalIssuesHeader activeLayout="spreadsheet" />}>
<div className="h-full overflow-hidden bg-custom-background-100">
<div className="h-full w-full flex flex-col border-b border-custom-border-300">
<GlobalViewsHeader />
<GlobalViewLayoutRoot />
</div>
</div>
</AppLayout>
);
};
export default GlobalViewIssues;
GlobalViewIssuesPage.getLayout = function getLayout(page: ReactElement) {
return <AppLayout header={<GlobalIssuesHeader activeLayout="spreadsheet" />}>{page}</AppLayout>;
};
export default GlobalViewIssuesPage;

View File

@ -1,3 +1,4 @@
import { ReactElement } from "react";
// components
import { GlobalViewsHeader } from "components/workspace";
import { GlobalIssuesHeader } from "components/headers";
@ -5,17 +6,19 @@ import { GlobalViewLayoutRoot } from "components/issues";
// layouts
import { AppLayout } from "layouts/app-layout";
// types
import { NextPage } from "next";
import { NextPageWithLayout } from "types/app";
const GlobalViewAllIssues: NextPage = () => (
<AppLayout header={<GlobalIssuesHeader activeLayout="spreadsheet" />}>
const GlobalViewAllIssuesPage: NextPageWithLayout = () => (
<div className="h-full overflow-hidden bg-custom-background-100">
<div className="h-full w-full flex flex-col border-b border-custom-border-300">
<GlobalViewsHeader />
<GlobalViewLayoutRoot type="all-issues" />
</div>
</div>
</AppLayout>
);
export default GlobalViewAllIssues;
GlobalViewAllIssuesPage.getLayout = function getLayout(page: ReactElement) {
return <AppLayout header={<GlobalIssuesHeader activeLayout="spreadsheet" />}>{page}</AppLayout>;
};
export default GlobalViewAllIssuesPage;

View File

@ -1,3 +1,4 @@
import { ReactElement } from "react";
// components
import { GlobalViewsHeader } from "components/workspace";
import { GlobalIssuesHeader } from "components/headers";
@ -5,17 +6,19 @@ import { GlobalViewLayoutRoot } from "components/issues";
// layouts
import { AppLayout } from "layouts/app-layout";
// types
import { NextPage } from "next";
import { NextPageWithLayout } from "types/app";
const GlobalViewAssignedIssues: NextPage = () => (
<AppLayout header={<GlobalIssuesHeader activeLayout="spreadsheet" />}>
const GlobalViewAssignedIssuesPage: NextPageWithLayout = () => (
<div className="h-full overflow-hidden bg-custom-background-100">
<div className="h-full w-full flex flex-col border-b border-custom-border-300">
<GlobalViewsHeader />
<GlobalViewLayoutRoot type="assigned" />
</div>
</div>
</AppLayout>
);
export default GlobalViewAssignedIssues;
GlobalViewAssignedIssuesPage.getLayout = function getLayout(page: ReactElement) {
return <AppLayout header={<GlobalIssuesHeader activeLayout="spreadsheet" />}>{page}</AppLayout>;
};
export default GlobalViewAssignedIssuesPage;

View File

@ -1,3 +1,4 @@
import { ReactElement } from "react";
// components
import { GlobalViewsHeader } from "components/workspace";
import { GlobalIssuesHeader } from "components/headers";
@ -5,17 +6,19 @@ import { GlobalViewLayoutRoot } from "components/issues";
// layouts
import { AppLayout } from "layouts/app-layout";
// types
import { NextPage } from "next";
import { NextPageWithLayout } from "types/app";
const GlobalViewCreatedIssues: NextPage = () => (
<AppLayout header={<GlobalIssuesHeader activeLayout="spreadsheet" />}>
const GlobalViewCreatedIssuesPage: NextPageWithLayout = () => (
<div className="h-full overflow-hidden bg-custom-background-100">
<div className="h-full w-full flex flex-col border-b border-custom-border-300">
<GlobalViewsHeader />
<GlobalViewLayoutRoot type="created" />
</div>
</div>
</AppLayout>
);
export default GlobalViewCreatedIssues;
GlobalViewCreatedIssuesPage.getLayout = function getLayout(page: ReactElement) {
return <AppLayout header={<GlobalIssuesHeader activeLayout="spreadsheet" />}>{page}</AppLayout>;
};
export default GlobalViewCreatedIssuesPage;

View File

@ -1,4 +1,4 @@
import React, { useState } from "react";
import React, { useState, ReactElement } from "react";
// layouts
import { AppLayout } from "layouts/app-layout";
// components
@ -9,15 +9,14 @@ import { Input } from "@plane/ui";
// icons
import { Search } from "lucide-react";
// types
import type { NextPage } from "next";
import { NextPageWithLayout } from "types/app";
// constants
import { DEFAULT_GLOBAL_VIEWS_LIST } from "constants/workspace";
const WorkspaceViews: NextPage = () => {
const WorkspaceViewsPage: NextPageWithLayout = () => {
const [query, setQuery] = useState("");
return (
<AppLayout header={<GlobalIssuesHeader activeLayout="list" />}>
<div className="flex flex-col">
<div className="h-full w-full flex flex-col overflow-hidden">
<div className="flex items-center gap-2.5 w-full px-5 py-3 border-b border-custom-border-200">
@ -36,8 +35,11 @@ const WorkspaceViews: NextPage = () => {
))}
<GlobalViewsList searchQuery={query} />
</div>
</AppLayout>
);
};
export default WorkspaceViews;
WorkspaceViewsPage.getLayout = function getLayout(page: ReactElement) {
return <AppLayout header={<GlobalIssuesHeader activeLayout="list" />}>{page}</AppLayout>;
};
export default WorkspaceViewsPage;

View File

@ -1,3 +1,4 @@
import { ReactElement } from "react";
// layouts
import { AppLayout } from "layouts/app-layout";
// components
@ -5,17 +6,19 @@ import { GlobalViewsHeader } from "components/workspace";
import { GlobalIssuesHeader } from "components/headers";
import { GlobalViewLayoutRoot } from "components/issues";
// types
import { NextPage } from "next";
import { NextPageWithLayout } from "types/app";
const GlobalViewSubscribedIssues: NextPage = () => (
<AppLayout header={<GlobalIssuesHeader activeLayout="spreadsheet" />}>
const GlobalViewSubscribedIssuesPage: NextPageWithLayout = () => (
<div className="h-full overflow-hidden bg-custom-background-100">
<div className="h-full w-full flex flex-col border-b border-custom-border-300">
<GlobalViewsHeader />
<GlobalViewLayoutRoot type="subscribed" />
</div>
</div>
</AppLayout>
);
export default GlobalViewSubscribedIssues;
GlobalViewSubscribedIssuesPage.getLayout = function getLayout(page: ReactElement) {
return <AppLayout header={<GlobalIssuesHeader activeLayout="spreadsheet" />}>{page}</AppLayout>;
};
export default GlobalViewSubscribedIssuesPage;

View File

@ -1,6 +1,8 @@
import { ReactElement } from "react";
import Head from "next/head";
import dynamic from "next/dynamic";
import Router from "next/router";
import { AppProps } from "next/app";
import { ThemeProvider } from "next-themes";
import NProgress from "nprogress";
// styles
@ -11,15 +13,14 @@ import "styles/nprogress.css";
import "styles/react-datepicker.css";
// contexts
import { ToastContextProvider } from "contexts/toast.context";
// types
import type { AppProps } from "next/app";
// constants
import { THEMES } from "constants/themes";
// constants
import { SITE_TITLE } from "constants/seo-variables";
// mobx store provider
import { MobxStoreProvider } from "lib/mobx/store-provider";
import MobxStoreInit from "lib/mobx/store-init";
// types
import { NextPageWithLayout } from "types/app";
const CrispWithNoSSR = dynamic(() => import("constants/crisp"), { ssr: false });
@ -29,7 +30,14 @@ Router.events.on("routeChangeStart", NProgress.start);
Router.events.on("routeChangeError", NProgress.done);
Router.events.on("routeChangeComplete", NProgress.done);
function MyApp({ Component, pageProps }: AppProps) {
type AppPropsWithLayout = AppProps & {
Component: NextPageWithLayout;
};
function MyApp({ Component, pageProps }: AppPropsWithLayout) {
// Use the layout defined at the page level, if available
const getLayout = Component.getLayout ?? ((page: ReactElement) => page);
return (
<>
<Head>
@ -40,7 +48,7 @@ function MyApp({ Component, pageProps }: AppProps) {
<ToastContextProvider>
<CrispWithNoSSR />
<MobxStoreInit />
<Component {...pageProps} />
{getLayout(<Component {...pageProps} />)}
</ToastContextProvider>
</ThemeProvider>
</MobxStoreProvider>

View File

@ -1,4 +1,4 @@
import { NextPage } from "next";
import { ReactElement } from "react";
import Image from "next/image";
// components
import { EmailForgotPasswordForm, EmailForgotPasswordFormValues } from "components/account";
@ -10,10 +10,12 @@ import { UserService } from "services/user.service";
import useToast from "hooks/use-toast";
// images
import BluePlaneLogoWithoutText from "public/plane-logos/blue-without-text.png";
// types
import { NextPageWithLayout } from "types/app";
const userService = new UserService();
const ForgotPasswordPage: NextPage = () => {
const ForgotPasswordPage: NextPageWithLayout = () => {
// toast
const { setToastAlert } = useToast();
@ -47,7 +49,6 @@ const ForgotPasswordPage: NextPage = () => {
});
};
return (
<DefaultLayout>
<>
<div className="hidden sm:block sm:fixed border-r-[0.5px] border-custom-border-200 h-screen w-[0.5px] top-0 left-20 lg:left-32" />
<div className="fixed grid place-items-center bg-custom-background-100 sm:py-5 top-11 sm:top-12 left-7 sm:left-16 lg:left-28">
@ -57,15 +58,18 @@ const ForgotPasswordPage: NextPage = () => {
</div>
</div>
</div>
</>
<div className="grid place-items-center h-full overflow-y-auto py-6 px-7">
<div>
<h1 className="text-center text-2xl sm:text-2.5xl font-semibold text-custom-text-100">Forgot Password</h1>
<EmailForgotPasswordForm onSubmit={handleForgotPassword} />
</div>
</div>
</DefaultLayout>
</>
);
};
ForgotPasswordPage.getLayout = function getLayout(page: ReactElement) {
return <DefaultLayout>{page}</DefaultLayout>;
};
export default ForgotPasswordPage;

View File

@ -1,8 +1,5 @@
import React, { useState, useEffect } from "react";
import { useState, useEffect, ReactElement } from "react";
import { useRouter } from "next/router";
// next-themes
import { useTheme } from "next-themes";
// layouts
import DefaultLayout from "layouts/default-layout";
@ -12,11 +9,11 @@ import { AuthService } from "services/auth.service";
import useUserAuth from "hooks/use-user-auth";
import useToast from "hooks/use-toast";
// types
import type { NextPage } from "next";
import { NextPageWithLayout } from "types/app";
const authService = new AuthService();
const MagicSignIn: NextPage = () => {
const MagicSignInPage: NextPageWithLayout = () => {
const router = useRouter();
const { password, key } = router.query;
@ -55,14 +52,11 @@ const MagicSignIn: NextPage = () => {
}, [password, key, mutateUser, router]);
return (
<DefaultLayout>
<div className="h-screen w-full overflow-auto bg-custom-background-90">
{isSigningIn ? (
<div className="flex h-full w-full flex-col items-center justify-center gap-3">
<h2 className="text-4xl font-medium">Signing you in...</h2>
<p className="text-sm font-medium text-custom-text-200">
Please wait while we are preparing your take off.
</p>
<p className="text-sm font-medium text-custom-text-200">Please wait while we are preparing your take off.</p>
</div>
) : errorSigningIn ? (
<div className="flex h-full w-full flex-col items-center justify-center gap-3">
@ -101,8 +95,11 @@ const MagicSignIn: NextPage = () => {
</div>
)}
</div>
</DefaultLayout>
);
};
export default MagicSignIn;
MagicSignInPage.getLayout = function getLayout(page: ReactElement) {
return <DefaultLayout>{page}</DefaultLayout>;
};
export default MagicSignInPage;

View File

@ -1,11 +1,7 @@
import React, { useEffect, useState } from "react";
import React, { useEffect, useState, ReactElement } from "react";
import { useRouter } from "next/router";
import Image from "next/image";
// next-themes
import { useTheme } from "next-themes";
// react-hook-form
import { Controller, useForm } from "react-hook-form";
// hooks
import useToast from "hooks/use-toast";
@ -18,7 +14,7 @@ import { Button, Input, Spinner } from "@plane/ui";
// images
import BluePlaneLogoWithoutText from "public/plane-logos/blue-without-text.png";
// types
import type { NextPage } from "next";
import { NextPageWithLayout } from "types/app";
type FormData = {
password: string;
@ -28,7 +24,7 @@ type FormData = {
// services
const userService = new UserService();
const ResetPasswordPage: NextPage = () => {
const ResetPasswordPage: NextPageWithLayout = () => {
const [isLoading, setIsLoading] = useState(true);
const router = useRouter();
@ -98,7 +94,6 @@ const ResetPasswordPage: NextPage = () => {
);
return (
<DefaultLayout>
<>
<div className="hidden sm:block sm:fixed border-r-[0.5px] border-custom-border-200 h-screen w-[0.5px] top-0 left-20 lg:left-32" />
<div className="fixed grid place-items-center bg-custom-background-100 sm:py-5 top-11 sm:top-12 left-7 sm:left-16 lg:left-28">
@ -108,11 +103,9 @@ const ResetPasswordPage: NextPage = () => {
</div>
</div>
</div>
</>
<div className="grid place-items-center h-full w-full overflow-y-auto py-5 px-7">
<div className="w-full">
<h1 className="text-center text-2xl sm:text-2.5xl font-semibold text-custom-text-100">Reset your password</h1>
<form className="space-y-4 mt-10 w-full sm:w-[360px] mx-auto" onSubmit={handleSubmit(onSubmit)}>
<div className="space-y-1">
<Controller
@ -164,8 +157,12 @@ const ResetPasswordPage: NextPage = () => {
</form>
</div>
</div>
</DefaultLayout>
</>
);
};
ResetPasswordPage.getLayout = function getLayout(page: ReactElement) {
return <DefaultLayout>{page}</DefaultLayout>;
};
export default ResetPasswordPage;

View File

@ -1,4 +1,4 @@
import React, { useEffect } from "react";
import React, { useEffect, ReactElement } from "react";
import Image from "next/image";
import { useRouter } from "next/router";
// next-themes
@ -15,7 +15,8 @@ import { EmailSignUpForm } from "components/account";
// images
import BluePlaneLogoWithoutText from "public/plane-logos/blue-without-text.png";
// types
import type { NextPage } from "next";
import { NextPageWithLayout } from "types/app";
type EmailPasswordFormValues = {
email: string;
password?: string;
@ -25,7 +26,7 @@ type EmailPasswordFormValues = {
// services
const authService = new AuthService();
const SignUp: NextPage = () => {
const SignUpPage: NextPageWithLayout = () => {
const router = useRouter();
const { setToastAlert } = useToast();
@ -66,7 +67,6 @@ const SignUp: NextPage = () => {
}, [setTheme]);
return (
<DefaultLayout>
<>
<div className="hidden sm:block sm:fixed border-r-[0.5px] border-custom-border-200 h-screen w-[0.5px] top-0 left-20 lg:left-32" />
<div className="fixed grid place-items-center bg-custom-background-100 sm:py-5 top-11 sm:top-12 left-7 sm:left-16 lg:left-28">
@ -76,15 +76,18 @@ const SignUp: NextPage = () => {
</div>
</div>
</div>
</>
<div className="grid place-items-center h-full w-full overflow-y-auto py-5 px-7">
<div>
<h1 className="text-2xl text-center font-">SignUp on Plane</h1>
<EmailSignUpForm onSubmit={handleSignUp} />
</div>
</div>
</DefaultLayout>
</>
);
};
export default SignUp;
SignUpPage.getLayout = function getLayout(page: ReactElement) {
return <DefaultLayout>{page}</DefaultLayout>;
};
export default SignUpPage;

View File

@ -1,4 +1,4 @@
import React, { useState } from "react";
import React, { useState, ReactElement } from "react";
import { useRouter } from "next/router";
import Image from "next/image";
import { useTheme } from "next-themes";
@ -15,9 +15,9 @@ import BlackHorizontalLogo from "public/plane-logos/black-horizontal-with-blue-l
import WhiteHorizontalLogo from "public/plane-logos/white-horizontal-with-blue-logo.svg";
// types
import { IWorkspace } from "types";
import type { NextPage } from "next";
import { NextPageWithLayout } from "types/app";
const CreateWorkspace: NextPage = observer(() => {
const CreateWorkspacePage: NextPageWithLayout = observer(() => {
const [defaultValues, setDefaultValues] = useState({
name: "",
slug: "",
@ -38,8 +38,6 @@ const CreateWorkspace: NextPage = observer(() => {
};
return (
<UserAuthWrapper>
<DefaultLayout>
<div className="flex h-full flex-col gap-y-2 sm:gap-y-0 sm:flex-row overflow-hidden">
<div className="relative h-1/6 flex-shrink-0 sm:w-2/12 md:w-3/12 lg:w-1/5">
<div className="absolute border-b-[0.5px] sm:border-r-[0.5px] border-custom-border-200 h-[0.5px] w-full top-1/2 left-0 -translate-y-1/2 sm:h-screen sm:w-[0.5px] sm:top-0 sm:left-1/2 md:left-1/3 sm:-translate-x-1/2 sm:translate-y-0" />
@ -72,9 +70,15 @@ const CreateWorkspace: NextPage = observer(() => {
</div>
</div>
</div>
</DefaultLayout>
</UserAuthWrapper>
);
});
export default CreateWorkspace;
CreateWorkspacePage.getLayout = function getLayout(page: ReactElement) {
return (
<UserAuthWrapper>
<DefaultLayout>{page} </DefaultLayout>
</UserAuthWrapper>
);
};
export default CreateWorkspacePage;

View File

@ -1,13 +1,15 @@
import type { NextPage } from "next";
import { ReactElement } from "react";
// layouts
import DefaultLayout from "layouts/default-layout";
// components
import { SignInView } from "components/page-views";
// type
import { NextPageWithLayout } from "types/app";
const HomePage: NextPage = () => (
<DefaultLayout>
<SignInView />
</DefaultLayout>
);
const HomePage: NextPageWithLayout = () => <SignInView />;
HomePage.getLayout = function getLayout(page: ReactElement) {
return <DefaultLayout>{page}</DefaultLayout>;
};
export default HomePage;

View File

@ -1,16 +1,16 @@
import React, { useEffect } from "react";
import React, { useEffect, ReactElement } from "react";
import { useRouter } from "next/router";
// services
import { AppInstallationService } from "services/app_installation.service";
// ui
import { Spinner } from "@plane/ui";
// types
import { NextPageWithLayout } from "types/app";
// services
const appInstallationService = new AppInstallationService();
const AppPostInstallation = () => {
const AppPostInstallation: NextPageWithLayout = () => {
const router = useRouter();
const { installation_id, setup_action, state, provider, code } = router.query;
@ -85,4 +85,8 @@ const AppPostInstallation = () => {
);
};
AppPostInstallation.getLayout = function getLayout(page: ReactElement) {
return <div>{page}</div>;
};
export default AppPostInstallation;

View File

@ -1,4 +1,4 @@
import React, { useState } from "react";
import React, { useState, ReactElement } from "react";
import Link from "next/link";
import Image from "next/image";
import { useRouter } from "next/router";
@ -24,7 +24,7 @@ import emptyInvitation from "public/empty-state/invitation.svg";
// helpers
import { truncateText } from "helpers/string.helper";
// types
import type { NextPage } from "next";
import { NextPageWithLayout } from "types/app";
import type { IWorkspaceMemberInvitation } from "types";
// constants
import { ROLE } from "constants/workspace";
@ -35,7 +35,7 @@ import { EmptyState } from "components/common";
const workspaceService = new WorkspaceService();
const userService = new UserService();
const UserInvitationsPage: NextPage = () => {
const UserInvitationsPage: NextPageWithLayout = () => {
const [invitationsRespond, setInvitationsRespond] = useState<string[]>([]);
const [isJoiningWorkspaces, setIsJoiningWorkspaces] = useState(false);
@ -103,8 +103,6 @@ const UserInvitationsPage: NextPage = () => {
};
return (
<UserAuthWrapper>
<DefaultLayout>
<div className="flex h-full flex-col gap-y-2 sm:gap-y-0 sm:flex-row overflow-hidden">
<div className="relative h-1/6 flex-shrink-0 sm:w-2/12 md:w-3/12 lg:w-1/5">
<div className="absolute border-b-[0.5px] sm:border-r-[0.5px] border-custom-border-200 h-[0.5px] w-full top-1/2 left-0 -translate-y-1/2 sm:h-screen sm:w-[0.5px] sm:top-0 sm:left-1/2 md:left-1/3 sm:-translate-x-1/2 sm:translate-y-0" />
@ -163,9 +161,7 @@ const UserInvitationsPage: NextPage = () => {
<p className="text-xs text-custom-text-200">{ROLE[invitation.role]}</p>
</div>
<span
className={`flex-shrink-0 ${
isSelected ? "text-custom-primary-100" : "text-custom-text-200"
}`}
className={`flex-shrink-0 ${isSelected ? "text-custom-primary-100" : "text-custom-text-200"}`}
>
<CheckCircle2 className="h-5 w-5" />
</span>
@ -209,7 +205,13 @@ const UserInvitationsPage: NextPage = () => {
)
) : null}
</div>
</DefaultLayout>
);
};
UserInvitationsPage.getLayout = function getLayout(page: ReactElement) {
return (
<UserAuthWrapper>
<DefaultLayout>{page}</DefaultLayout>
</UserAuthWrapper>
);
};

View File

@ -1,4 +1,4 @@
import { useEffect, useState } from "react";
import { useEffect, useState, ReactElement } from "react";
import Image from "next/image";
import { observer } from "mobx-react-lite";
import useSWR from "swr";
@ -22,12 +22,12 @@ import BlackHorizontalLogo from "public/plane-logos/black-horizontal-with-blue-l
import WhiteHorizontalLogo from "public/plane-logos/white-horizontal-with-blue-logo.svg";
// types
import { IUser, TOnboardingSteps } from "types";
import type { NextPage } from "next";
import { NextPageWithLayout } from "types/app";
// services
const workspaceService = new WorkspaceService();
const Onboarding: NextPage = observer(() => {
const OnboardingPage: NextPageWithLayout = observer(() => {
const [step, setStep] = useState<number | null>(null);
const { user: userStore, workspace: workspaceStore } = useMobxStore();
@ -105,9 +105,8 @@ const Onboarding: NextPage = observer(() => {
}, [user, invitations, step]);
return (
<UserAuthWrapper>
<>
{user && step !== null ? (
<DefaultLayout>
<div className="flex h-full w-full flex-col gap-y-2 sm:gap-y-0 sm:flex-row overflow-hidden">
<div className="relative h-1/6 flex-shrink-0 sm:w-2/12 md:w-3/12 lg:w-1/5">
<div className="absolute border-b-[0.5px] sm:border-r-[0.5px] border-custom-border-200 h-[0.5px] w-full top-1/2 left-0 -translate-y-1/2 sm:h-screen sm:w-[0.5px] sm:top-0 sm:left-1/2 md:left-1/3 sm:-translate-x-1/2 sm:translate-y-0 z-10" />
@ -176,14 +175,21 @@ const Onboarding: NextPage = observer(() => {
</div>
)}
</div>
</DefaultLayout>
) : (
<div className="h-screen w-full grid place-items-center">
<Spinner />
</div>
)}
</UserAuthWrapper>
</>
);
});
export default Onboarding;
OnboardingPage.getLayout = function getLayout(page: ReactElement) {
return (
<UserAuthWrapper>
<DefaultLayout>{page}</DefaultLayout>
</UserAuthWrapper>
);
};
export default OnboardingPage;

View File

@ -1,6 +1,4 @@
import React from "react";
// next
import React, { ReactElement } from "react";
import { useRouter } from "next/router";
import useSWR from "swr";
// swr
@ -16,14 +14,14 @@ import { Spinner } from "@plane/ui";
// icons
import { EmptySpace, EmptySpaceItem } from "components/ui/empty-space";
// types
import type { NextPage } from "next";
import { NextPageWithLayout } from "types/app";
// constants
import { WORKSPACE_INVITATION } from "constants/fetch-keys";
// services
const workspaceService = new WorkspaceService();
const WorkspaceInvitation: NextPage = () => {
const WorkspaceInvitationPage: NextPageWithLayout = () => {
const router = useRouter();
const { invitation_id, email } = router.query;
@ -58,7 +56,6 @@ const WorkspaceInvitation: NextPage = () => {
};
return (
<DefaultLayout>
<div className="flex h-full w-full flex-col items-center justify-center px-3">
{invitationDetail ? (
<>
@ -139,8 +136,11 @@ const WorkspaceInvitation: NextPage = () => {
</div>
)}
</div>
</DefaultLayout>
);
};
export default WorkspaceInvitation;
WorkspaceInvitationPage.getLayout = function getLayout(page: ReactElement) {
return <DefaultLayout>{page}</DefaultLayout>;
};
export default WorkspaceInvitationPage;

3
web/types/app.d.ts vendored Normal file
View File

@ -0,0 +1,3 @@
export type NextPageWithLayout<P = {}, IP = P> = NextPage<P, IP> & {
getLayout?: (page: ReactElement) => ReactNode;
};