chore: app dir headers re-implementation (#4751)

* chore: header refactor.

* fix: core imports

* chore: refactor profile activity header and fix all other header imports.

* fix: import fixes

* chore: header refactor.

* fix: app dir header reimplementation

* fix: removing parllel headers

* fix: adding route groups to handle pages

* fix: disabling sentry for temp

* chore: update default exports in layouts & headers for consistency.

* fix: bugfixes

* fix: build errors

---------

Co-authored-by: sriram veeraghanta <veeraghanta.sriram@gmail.com>
This commit is contained in:
Prateek Shourya 2024-06-11 02:23:19 +05:30 committed by GitHub
parent 423bc15119
commit 05de4d83f3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
150 changed files with 887 additions and 648 deletions

View File

@ -10,6 +10,6 @@ export const metadata: Metadata = {
title: "Email Settings - God Mode",
};
const EmailLayout = ({ children }: EmailLayoutProps) => <AdminLayout>{children}</AdminLayout>;
export default EmailLayout;
export default function EmailLayout({ children }: EmailLayoutProps) {
return <AdminLayout>{children}</AdminLayout>;
}

View File

@ -10,6 +10,6 @@ export const metadata: Metadata = {
title: "Images Settings - God Mode",
};
const ImageLayout = ({ children }: ImageLayoutProps) => <AdminLayout>{children}</AdminLayout>;
export default ImageLayout;
export default function ImageLayout({ children }: ImageLayoutProps) {
return <AdminLayout>{children}</AdminLayout>;
}

View File

@ -16,7 +16,7 @@ import { UserProvider } from "@/lib/user-provider";
// styles
import "./globals.css";
function RootLayout({ children }: { children: ReactNode }) {
export default function RootLayout({ children }: { children: ReactNode }) {
// themes
const { resolvedTheme } = useTheme();
@ -44,5 +44,3 @@ function RootLayout({ children }: { children: ReactNode }) {
</html>
);
}
export default RootLayout;

View File

@ -0,0 +1,8 @@
export default function WorkspacePagesLayout({ children }: { children: React.ReactNode }) {
return (
<div>
<h1>WorkspacePages Layout </h1>
{children}
</div>
);
}

View File

@ -0,0 +1,3 @@
export default function WorkspacePagesPage() {
return <div>WorkspacePagesPage</div>;
}

View File

@ -7,7 +7,7 @@ import { Breadcrumbs, ContrastIcon } from "@plane/ui";
import { BreadcrumbLink } from "@/components/common";
// icons
const WorkspaceActiveCycleHeader = observer(() => (
export const WorkspaceActiveCycleHeader = observer(() => (
<div className="relative z-10 flex h-[3.75rem] w-full flex-shrink-0 flex-row items-center justify-between gap-x-2 gap-y-4 bg-custom-sidebar-background-100 p-4">
<div className="flex w-full flex-grow items-center gap-2 overflow-ellipsis whitespace-nowrap">
<div className="flex items-center gap-2">
@ -27,5 +27,3 @@ const WorkspaceActiveCycleHeader = observer(() => (
</div>
</div>
));
export default WorkspaceActiveCycleHeader;

View File

@ -0,0 +1,13 @@
"use client";
import { AppHeader, ContentWrapper } from "@/components/core";
import { WorkspaceActiveCycleHeader } from "./header";
export default function WorkspaceActiveCycleLayout({ children }: { children: React.ReactNode }) {
return (
<>
<AppHeader header={<WorkspaceActiveCycleHeader />} />
<ContentWrapper>{children}</ContentWrapper>
</>
);
}

View File

@ -20,4 +20,4 @@ const WorkspaceActiveCyclesPage = observer(() => {
);
});
export default WorkspaceActiveCyclesPage;
export default WorkspaceActiveCyclesPage;

View File

@ -14,7 +14,7 @@ import { cn } from "@/helpers/common.helper";
// hooks
import { useAppTheme } from "@/hooks/store";
const WorkspaceAnalyticsHeader = observer(() => {
export const WorkspaceAnalyticsHeader = observer(() => {
const searchParams = useSearchParams();
const analytics_tab = searchParams.get("analytics_tab");
// store hooks
@ -71,5 +71,3 @@ const WorkspaceAnalyticsHeader = observer(() => {
</>
);
});
export default WorkspaceAnalyticsHeader;

View File

@ -0,0 +1,13 @@
"use client";
import { AppHeader, ContentWrapper } from "@/components/core";
import { WorkspaceAnalyticsHeader } from "./header";
export default function WorkspaceAnalyticsLayout({ children }: { children: React.ReactNode }) {
return (
<>
<AppHeader header={<WorkspaceAnalyticsHeader />} />
<ContentWrapper>{children}</ContentWrapper>
</>
);
}

View File

@ -12,7 +12,7 @@ import { EmptyState } from "@/components/empty-state";
import { ANALYTICS_TABS } from "@/constants/analytics";
import { EmptyStateType } from "@/constants/empty-state";
// hooks
import { useCommandPalette, useEventTracker, useProject, useWorkspace } from "@/hooks/store";;
import { useCommandPalette, useEventTracker, useProject, useWorkspace } from "@/hooks/store";
const AnalyticsPage = observer(() => {
const searchParams = useSearchParams();
@ -36,8 +36,9 @@ const AnalyticsPage = observer(() => {
<Tab key={tab.key} as={Fragment}>
{({ selected }) => (
<button
className={`text-sm group relative flex items-center gap-1 h-[50px] px-3 cursor-pointer transition-all font-medium outline-none ${selected ? "text-custom-primary-100 " : "hover:text-custom-text-200"
}`}
className={`text-sm group relative flex items-center gap-1 h-[50px] px-3 cursor-pointer transition-all font-medium outline-none ${
selected ? "text-custom-primary-100 " : "hover:text-custom-text-200"
}`}
>
{tab.title}
<div
@ -71,4 +72,4 @@ const AnalyticsPage = observer(() => {
);
});
export default AnalyticsPage;
export default AnalyticsPage;

View File

@ -15,7 +15,7 @@ import { CHANGELOG_REDIRECTED, GITHUB_REDIRECTED } from "@/constants/event-track
// hooks
import { useEventTracker } from "@/hooks/store";
const WorkspaceDashboardHeader = () => {
export const WorkspaceDashboardHeader = () => {
// hooks
const { captureEvent } = useEventTracker();
const { resolvedTheme } = useTheme();
@ -72,5 +72,3 @@ const WorkspaceDashboardHeader = () => {
</>
);
};
export default WorkspaceDashboardHeader;

View File

@ -3,9 +3,9 @@
import { CommandPalette } from "@/components/command-palette";
import { WorkspaceAuthWrapper } from "@/layouts/auth-layout";
import { AuthenticationWrapper } from "@/lib/wrappers";
import AppSidebar from "./sidebar";
import { AppSidebar } from "./sidebar";
export default function WorkspaceLayout({ header, children }: { header: React.ReactNode; children: React.ReactNode }) {
export default function WorkspaceLayout({ children }: { children: React.ReactNode }) {
return (
<AuthenticationWrapper>
<CommandPalette />
@ -13,10 +13,7 @@ export default function WorkspaceLayout({ header, children }: { header: React.Re
<div className="relative flex h-screen w-full overflow-hidden">
<AppSidebar />
<main className="relative flex h-full w-full flex-col overflow-hidden bg-custom-background-100">
{header}
<div className="h-full w-full overflow-hidden">
<div className="relative h-full w-full overflow-x-hidden overflow-y-scroll">{children}</div>
</div>
{children}
</main>
</div>
</WorkspaceAuthWrapper>

View File

@ -0,0 +1,28 @@
"use client";
import { observer } from "mobx-react";
// components
import { PageHead, AppHeader, ContentWrapper } from "@/components/core";
import { WorkspaceDashboardView } from "@/components/page-views";
// hooks
import { useWorkspace } from "@/hooks/store";
// local components
import { WorkspaceDashboardHeader } from "./header";
const WorkspaceDashboardPage = observer(() => {
const { currentWorkspace } = useWorkspace();
// derived values
const pageTitle = currentWorkspace?.name ? `${currentWorkspace?.name} - Home` : undefined;
return (
<>
<AppHeader header={<WorkspaceDashboardHeader />} />
<ContentWrapper>
<PageHead title={pageTitle} />
<WorkspaceDashboardView />
</ContentWrapper>
</>
);
});
export default WorkspaceDashboardPage;

View File

@ -17,7 +17,7 @@ type TUserProfileHeader = {
type?: string | undefined;
};
const UserProfileHeader: FC<TUserProfileHeader> = observer((props) => {
export const UserProfileHeader: FC<TUserProfileHeader> = observer((props) => {
const { type = undefined } = props;
// router
const { workspaceSlug, userId } = useParams();
@ -90,5 +90,3 @@ const UserProfileHeader: FC<TUserProfileHeader> = observer((props) => {
</div>
);
});
export default UserProfileHeader;

View File

@ -0,0 +1,69 @@
"use client";
import { observer } from "mobx-react";
import { useParams, usePathname } from "next/navigation";
// components
import { AppHeader, ContentWrapper } from "@/components/core";
import { ProfileSidebar } from "@/components/profile";
// constants
import { PROFILE_ADMINS_TAB, PROFILE_VIEWER_TAB } from "@/constants/profile";
import { EUserWorkspaceRoles } from "@/constants/workspace";
// hooks
import { useUser } from "@/hooks/store";
// local components
import { UserProfileHeader } from "./header";
import { ProfileIssuesMobileHeader } from "./mobile-header";
import { ProfileNavbar } from "./navbar";
type Props = {
children: React.ReactNode;
};
const AUTHORIZED_ROLES = [EUserWorkspaceRoles.ADMIN, EUserWorkspaceRoles.MEMBER, EUserWorkspaceRoles.VIEWER];
const UseProfileLayout: React.FC<Props> = observer((props) => {
const { children } = props;
// router
const { workspaceSlug, userId } = useParams();
const pathname = usePathname();
// store hooks
const {
membership: { currentWorkspaceRole },
} = useUser();
// derived values
const isAuthorized = currentWorkspaceRole && AUTHORIZED_ROLES.includes(currentWorkspaceRole);
const isAuthorizedPath =
pathname.includes("assigned") || pathname.includes("created") || pathname.includes("subscribed");
const isIssuesTab = pathname.includes("assigned") || pathname.includes("created") || pathname.includes("subscribed");
const tabsList = isAuthorized ? [...PROFILE_VIEWER_TAB, ...PROFILE_ADMINS_TAB] : PROFILE_VIEWER_TAB;
const currentTab = tabsList.find((tab) => pathname === `/${workspaceSlug}/profile/${userId}${tab.selected}`);
return (
<>
{/* Passing the type prop from the current route value as we need the header as top most component.
TODO: We are depending on the route path to handle the mobile header type. If the path changes, this logic will break. */}
<AppHeader
header={<UserProfileHeader type={currentTab?.label} />}
mobileHeader={isIssuesTab && <ProfileIssuesMobileHeader />}
/>
<ContentWrapper>
<div className="h-full w-full flex md:overflow-hidden">
<div className="flex w-full flex-col md:h-full md:overflow-hidden">
<ProfileNavbar isAuthorized={!!isAuthorized} showProfileIssuesFilter={isIssuesTab} />
{isAuthorized || !isAuthorizedPath ? (
<div className={`w-full overflow-hidden md:h-full`}>{children}</div>
) : (
<div className="grid h-full w-full place-items-center text-custom-text-200">
You do not have the permission to access this page.
</div>
)}
</div>
<ProfileSidebar />
</div>
</ContentWrapper>
</>
);
});
export default UseProfileLayout;

View File

@ -24,7 +24,7 @@ import { calculateTotalFilters } from "@/helpers/filter.helper";
// hooks
import { useIssues, useLabel } from "@/hooks/store";
const ProfileIssuesMobileHeader = observer(() => {
export const ProfileIssuesMobileHeader = observer(() => {
// router
const { workspaceSlug, userId } = useParams();
// store hook
@ -187,5 +187,3 @@ const ProfileIssuesMobileHeader = observer(() => {
</div>
);
});
export default ProfileIssuesMobileHeader;

View File

@ -22,7 +22,7 @@ import { UserService } from "@/services/user.service";
// services
const userService = new UserService();
const ProfileOverviewPage = () => {
export default function ProfileOverviewPage() {
const { workspaceSlug, userId } = useParams();
const { data: userProfile } = useSWR(
@ -51,6 +51,4 @@ const ProfileOverviewPage = () => {
</div>
</>
);
};
export default ProfileOverviewPage;
}

View File

@ -0,0 +1,14 @@
"use client";
// components
import { AppHeader, ContentWrapper } from "@/components/core";
import { ProjectArchivesHeader } from "../header";
export default function ProjectArchiveCyclesLayout({ children }: { children: React.ReactNode }) {
return (
<>
<AppHeader header={<ProjectArchivesHeader />} />
<ContentWrapper>{children}</ContentWrapper>
</>
);
}

View File

@ -14,7 +14,7 @@ import { EIssuesStoreType } from "@/constants/issue";
import { useIssues, useProject } from "@/hooks/store";
import { usePlatformOS } from "@/hooks/use-platform-os";
const ProjectArchivesHeader: FC = observer(() => {
export const ProjectArchivesHeader: FC = observer(() => {
// router
const router = useRouter();
const { workspaceSlug, projectId } = useParams();
@ -96,5 +96,3 @@ const ProjectArchivesHeader: FC = observer(() => {
</div>
);
});
export default ProjectArchivesHeader;

View File

@ -1,6 +1,5 @@
"use client";
import { FC } from "react";
import { observer } from "mobx-react";
import { useParams } from "next/navigation";
import useSWR from "swr";
@ -17,7 +16,7 @@ import { IssueArchiveService } from "@/services/issue";
const issueArchiveService = new IssueArchiveService();
const ProjectArchivedIssueDetailsHeader: FC = observer(() => {
export const ProjectArchivedIssueDetailsHeader = observer(() => {
// router
const { workspaceSlug, projectId, archivedIssueId } = useParams();
// store hooks
@ -94,5 +93,3 @@ const ProjectArchivedIssueDetailsHeader: FC = observer(() => {
</div>
);
});
export default ProjectArchivedIssueDetailsHeader;

View File

@ -0,0 +1,14 @@
"use client";
// components
import { AppHeader, ContentWrapper } from "@/components/core";
import { ProjectArchivedIssueDetailsHeader } from "./header";
export default function ProjectArchivedIssueDetailLayout({ children }: { children: React.ReactNode }) {
return (
<>
<AppHeader header={<ProjectArchivedIssueDetailsHeader />} />
<ContentWrapper>{children}</ContentWrapper>
</>
);
}

View File

@ -0,0 +1,14 @@
"use client";
// components
import { AppHeader, ContentWrapper } from "@/components/core";
import { ProjectArchivesHeader } from "../../header";
export default function ProjectArchiveIssuesLayout({ children }: { children: React.ReactNode }) {
return (
<>
<AppHeader header={<ProjectArchivesHeader />} />
<ContentWrapper>{children}</ContentWrapper>
</>
);
}

View File

@ -0,0 +1,14 @@
"use client";
// components
import { AppHeader, ContentWrapper } from "@/components/core";
import { ProjectArchivesHeader } from "../header";
export default function ProjectArchiveModulesLayout({ children }: { children: React.ReactNode }) {
return (
<>
<AppHeader header={<ProjectArchivesHeader />} />
<ContentWrapper>{children}</ContentWrapper>
</>
);
}

View File

@ -57,7 +57,7 @@ const CycleDropdownOption: React.FC<{ cycleId: string }> = ({ cycleId }) => {
);
};
const CycleIssuesHeader: React.FC = observer(() => {
export const CycleIssuesHeader: React.FC = observer(() => {
// states
const [analyticsModal, setAnalyticsModal] = useState(false);
// router
@ -208,9 +208,8 @@ const CycleIssuesHeader: React.FC = observer(() => {
{issuesCount && issuesCount > 0 ? (
<Tooltip
isMobile={isMobile}
tooltipContent={`There are ${issuesCount} ${
issuesCount > 1 ? "issues" : "issue"
} in this cycle`}
tooltipContent={`There are ${issuesCount} ${issuesCount > 1 ? "issues" : "issue"
} in this cycle`}
position="bottom"
>
<span className="flex flex-shrink-0 cursor-default items-center justify-center rounded-xl bg-custom-primary-100/20 px-2 text-center text-xs font-semibold text-custom-primary-100">
@ -311,5 +310,3 @@ const CycleIssuesHeader: React.FC = observer(() => {
</>
);
});
export default CycleIssuesHeader;

View File

@ -0,0 +1,15 @@
"use client";
// components
import { AppHeader, ContentWrapper } from "@/components/core";
import { CycleIssuesHeader } from "./header";
import { CycleIssuesMobileHeader } from "./mobile-header";
export default function ProjectCycleIssuesLayout({ children }: { children: React.ReactNode }) {
return (
<>
<AppHeader header={<CycleIssuesHeader />} mobileHeader={<CycleIssuesMobileHeader />} />
<ContentWrapper>{children}</ContentWrapper>
</>
);
}

View File

@ -18,7 +18,7 @@ import { calculateTotalFilters } from "@/helpers/filter.helper";
// hooks
import { useIssues, useCycle, useProjectState, useLabel, useMember, useProject } from "@/hooks/store";
const CycleIssuesMobileHeader = () => {
export const CycleIssuesMobileHeader = () => {
const [analyticsModal, setAnalyticsModal] = useState(false);
const { getCycleById } = useCycle();
const layouts = [
@ -204,5 +204,3 @@ const CycleIssuesMobileHeader = () => {
</>
);
};
export default CycleIssuesMobileHeader;

View File

@ -13,7 +13,7 @@ import { EUserProjectRoles } from "@/constants/project";
// hooks
import { useCommandPalette, useEventTracker, useProject, useUser } from "@/hooks/store";
const CyclesHeader: FC = observer(() => {
export const CyclesListHeader: FC = observer(() => {
// router
const router = useRouter();
const { workspaceSlug } = useParams();
@ -74,5 +74,3 @@ const CyclesHeader: FC = observer(() => {
</div>
);
});
export default CyclesHeader;

View File

@ -0,0 +1,15 @@
"use client";
// components
import { AppHeader, ContentWrapper } from "@/components/core";
import { CyclesListHeader } from "./header";
import { CyclesListMobileHeader } from "./mobile-header";
export default function ProjectCyclesListLayout({ children }: { children: React.ReactNode }) {
return (
<>
<AppHeader header={<CyclesListHeader />} mobileHeader={<CyclesListMobileHeader />} />
<ContentWrapper>{children}</ContentWrapper>
</>
);
}

View File

@ -10,7 +10,7 @@ import { CYCLE_VIEW_LAYOUTS } from "@/constants/cycle";
// hooks
import { useCycleFilter, useProject } from "@/hooks/store";
const CyclesListMobileHeader = observer(() => {
export const CyclesListMobileHeader = observer(() => {
const { currentProjectDetails } = useProject();
// hooks
const { updateDisplayFilters } = useCycleFilter();
@ -50,5 +50,3 @@ const CyclesListMobileHeader = observer(() => {
</div>
);
});
export default CyclesListMobileHeader;

View File

@ -18,7 +18,7 @@ import { calculateTotalFilters } from "@/helpers/filter.helper";
import { useIssues, useLabel, useMember, useProject, useProjectState } from "@/hooks/store";
import { usePlatformOS } from "@/hooks/use-platform-os";
const ProjectDraftIssueHeader: FC = observer(() => {
export const ProjectDraftIssueHeader: FC = observer(() => {
// router
const { workspaceSlug, projectId } = useParams() as { workspaceSlug: string; projectId: string };
// store hooks
@ -169,5 +169,3 @@ const ProjectDraftIssueHeader: FC = observer(() => {
</div>
);
});
export default ProjectDraftIssueHeader;

View File

@ -0,0 +1,14 @@
"use client";
// components
import { AppHeader, ContentWrapper } from "@/components/core";
import { ProjectDraftIssueHeader } from "./header";
export default function ProjectDraftIssuesLayou({ children }: { children: React.ReactNode }) {
return (
<>
<AppHeader header={<ProjectDraftIssueHeader />} />
<ContentWrapper>{children}</ContentWrapper>
</>
);
}

View File

@ -12,7 +12,7 @@ import { InboxIssueCreateEditModalRoot } from "@/components/inbox";
// hooks
import { useProject, useProjectInbox } from "@/hooks/store";
const ProjectInboxHeader: FC = observer(() => {
export const ProjectInboxHeader: FC = observer(() => {
// states
const [createIssueModal, setCreateIssueModal] = useState(false);
// router
@ -76,5 +76,3 @@ const ProjectInboxHeader: FC = observer(() => {
</div>
);
});
export default ProjectInboxHeader;

View File

@ -0,0 +1,14 @@
"use client";
// components
import { AppHeader, ContentWrapper } from "@/components/core";
import { ProjectInboxHeader } from "./header";
export default function ProjectInboxIssuesLayout({ children }: { children: React.ReactNode }) {
return (
<>
<AppHeader header={<ProjectInboxHeader />} />
<ContentWrapper>{children}</ContentWrapper>
</>
);
}

View File

@ -1,6 +1,5 @@
"use client";
import { FC } from "react";
import { observer } from "mobx-react";
import { useParams, useRouter } from "next/navigation";
import { PanelRight } from "lucide-react";
@ -13,7 +12,7 @@ import { cn } from "@/helpers/common.helper";
// hooks
import { useAppTheme, useIssueDetail, useProject } from "@/hooks/store";
const ProjectIssueDetailsHeader: FC = observer(() => {
export const ProjectIssueDetailsHeader = observer(() => {
// router
const router = useRouter();
const { workspaceSlug, projectId, issueId } = useParams();
@ -83,5 +82,3 @@ const ProjectIssueDetailsHeader: FC = observer(() => {
</div>
);
});
export default ProjectIssueDetailsHeader;

View File

@ -0,0 +1,14 @@
"use client";
// components
import { AppHeader, ContentWrapper } from "@/components/core";
import { ProjectIssueDetailsHeader } from "./header";
export default function ProjectIssueDetailsLayout({ children }: { children: React.ReactNode }) {
return (
<>
<AppHeader header={<ProjectIssueDetailsHeader />} />
<ContentWrapper>{children}</ContentWrapper>
</>
);
}

View File

@ -32,7 +32,7 @@ import {
import { useIssues } from "@/hooks/store/use-issues";
import { usePlatformOS } from "@/hooks/use-platform-os";
const ProjectIssuesHeader: React.FC = observer(() => {
export const ProjectIssuesHeader = observer(() => {
// states
const [analyticsModal, setAnalyticsModal] = useState(false);
// router
@ -242,5 +242,3 @@ const ProjectIssuesHeader: React.FC = observer(() => {
</>
);
});
export default ProjectIssuesHeader;

View File

@ -0,0 +1,15 @@
"use client";
// components
import { AppHeader, ContentWrapper } from "@/components/core";
import { ProjectIssuesHeader } from "./header";
import { ProjectIssuesMobileHeader } from "./mobile-header";
export default function ProjectIssuesLayout({ children }: { children: React.ReactNode }) {
return (
<>
<AppHeader header={<ProjectIssuesHeader />} mobileHeader={<ProjectIssuesMobileHeader />} />
<ContentWrapper>{children}</ContentWrapper>
</>
);
}

View File

@ -19,7 +19,7 @@ import { calculateTotalFilters } from "@/helpers/filter.helper";
// hooks
import { useIssues, useLabel, useMember, useProject, useProjectState } from "@/hooks/store";
const ProjectIssuesMobileHeader = observer(() => {
export const ProjectIssuesMobileHeader = observer(() => {
const layouts = [
{ key: "list", title: "List", icon: List },
{ key: "kanban", title: "Kanban", icon: Kanban },
@ -182,5 +182,3 @@ const ProjectIssuesMobileHeader = observer(() => {
</>
);
});
export default ProjectIssuesMobileHeader;

View File

@ -60,7 +60,7 @@ const ModuleDropdownOption: React.FC<{ moduleId: string }> = ({ moduleId }) => {
);
};
const ModuleIssuesHeader: React.FC = observer(() => {
export const ModuleIssuesHeader: React.FC = observer(() => {
// states
const [analyticsModal, setAnalyticsModal] = useState(false);
// router
@ -317,5 +317,3 @@ const ModuleIssuesHeader: React.FC = observer(() => {
</>
);
});
export default ModuleIssuesHeader;

View File

@ -0,0 +1,15 @@
"use client";
// components
import { AppHeader, ContentWrapper } from "@/components/core";
import { ModuleIssuesHeader } from "./header";
import { ModuleIssuesMobileHeader } from "./mobile-header";
export default function ProjectModuleIssuesLayout({ children }: { children: React.ReactNode }) {
return (
<>
<AppHeader header={<ModuleIssuesHeader />} mobileHeader={<ModuleIssuesMobileHeader />} />
<ContentWrapper>{children}</ContentWrapper>
</>
);
}

View File

@ -19,7 +19,7 @@ import { calculateTotalFilters } from "@/helpers/filter.helper";
// hooks
import { useIssues, useLabel, useMember, useModule, useProject, useProjectState } from "@/hooks/store";
const ModuleIssuesMobileHeader = observer(() => {
export const ModuleIssuesMobileHeader = observer(() => {
const [analyticsModal, setAnalyticsModal] = useState(false);
const { currentProjectDetails } = useProject();
const { getModuleById } = useModule();
@ -185,5 +185,3 @@ const ModuleIssuesMobileHeader = observer(() => {
</div>
);
});
export default ModuleIssuesMobileHeader;

View File

@ -12,7 +12,7 @@ import { EUserProjectRoles } from "@/constants/project";
// hooks
import { useCommandPalette, useEventTracker, useProject, useUser } from "@/hooks/store";
const ModulesListHeader: React.FC = observer(() => {
export const ModulesListHeader: React.FC = observer(() => {
// router
const router = useRouter();
const { workspaceSlug } = useParams();
@ -74,5 +74,3 @@ const ModulesListHeader: React.FC = observer(() => {
</div>
);
});
export default ModulesListHeader;

View File

@ -0,0 +1,15 @@
"use client";
// components
import { AppHeader, ContentWrapper } from "@/components/core";
import { ModulesListHeader } from "./header";
import { ModulesListMobileHeader } from "./mobile-header";
export default function ProjectModulesListLayout({ children }: { children: React.ReactNode }) {
return (
<>
<AppHeader header={<ModulesListHeader />} mobileHeader={<ModulesListMobileHeader />} />
<ContentWrapper>{children}</ContentWrapper>
</>
);
}

View File

@ -5,7 +5,7 @@ import { CustomMenu } from "@plane/ui";
import { MODULE_VIEW_LAYOUTS } from "@/constants/module";
import { useModuleFilter, useProject } from "@/hooks/store";
const ModulesListMobileHeader = observer(() => {
export const ModulesListMobileHeader = observer(() => {
const { currentProjectDetails } = useProject();
const { updateDisplayFilters } = useModuleFilter();
@ -38,5 +38,3 @@ const ModulesListMobileHeader = observer(() => {
</div>
);
});
export default ModulesListMobileHeader;

View File

@ -20,7 +20,7 @@ export interface IPagesHeaderProps {
showButton?: boolean;
}
const PageDetailsHeader = observer(() => {
export const PageDetailsHeader = observer(() => {
// router
const { workspaceSlug, pageId } = useParams();
// state
@ -168,5 +168,3 @@ const PageDetailsHeader = observer(() => {
</div>
);
});
export default PageDetailsHeader;

View File

@ -0,0 +1,15 @@
"use client";
// component
import { AppHeader, ContentWrapper } from "@/components/core";
// local components
import { PageDetailsHeader } from "./header";
export default function ProjectPageDetailsLayout({ children }: { children: React.ReactNode }) {
return (
<>
<AppHeader header={<PageDetailsHeader />} />
<ContentWrapper>{children}</ContentWrapper>
</>
);
}

View File

@ -13,7 +13,7 @@ import { EUserProjectRoles } from "@/constants/project";
// hooks
import { useCommandPalette, useEventTracker, useProject, useUser } from "@/hooks/store";
const PagesHeader = observer(() => {
export const PagesListHeader = observer(() => {
// router
const { workspaceSlug } = useParams();
const searchParams = useSearchParams();
@ -77,5 +77,3 @@ const PagesHeader = observer(() => {
</div>
);
});
export default PagesHeader;

View File

@ -0,0 +1,16 @@
"use client";
import { ReactNode } from "react";
// components
import { ContentWrapper, AppHeader } from "@/components/core";
// local components
import { PagesListHeader } from "./header";
export default function ProjectPagesListLayout({ children }: { children: ReactNode }) {
return (
<>
<AppHeader header={<PagesListHeader />} />
<ContentWrapper>{children}</ContentWrapper>
</>
);
}

View File

@ -13,7 +13,7 @@ import { EUserProjectRoles, PROJECT_SETTINGS_LINKS } from "@/constants/project";
// hooks
import { useProject, useUser } from "@/hooks/store";
const ProjectSettingHeader: FC = observer(() => {
export const ProjectSettingHeader: FC = observer(() => {
// router
const router = useRouter();
const { workspaceSlug, projectId } = useParams();
@ -82,5 +82,3 @@ const ProjectSettingHeader: FC = observer(() => {
</div>
);
});
export default ProjectSettingHeader;

View File

@ -0,0 +1,68 @@
"use client";
import { FC, ReactNode } from "react";
import { observer } from "mobx-react";
import Link from "next/link";
import { useParams } from "next/navigation";
// ui
import { Button, LayersIcon } from "@plane/ui";
// components
import { NotAuthorizedView } from "@/components/auth-screens";
import { AppHeader, ContentWrapper } from "@/components/core";
// constants
import { EUserProjectRoles } from "@/constants/project";
// hooks
import { useUser } from "@/hooks/store";
// local components
import { ProjectSettingHeader } from "./header";
import { ProjectSettingsSidebar } from "./sidebar";
export interface IProjectSettingLayout {
children: ReactNode;
}
const ProjectSettingLayout: FC<IProjectSettingLayout> = observer((props) => {
const { children } = props;
// router
const { workspaceSlug, projectId } = useParams();
// store hooks
const {
membership: { currentProjectRole },
} = useUser();
const restrictViewSettings = currentProjectRole && currentProjectRole <= EUserProjectRoles.VIEWER;
if (restrictViewSettings) {
return (
<NotAuthorizedView
type="project"
actionButton={
//TODO: Create a new component called Button Link to handle such scenarios
<Link href={`/${workspaceSlug}/projects/${projectId}/issues`}>
<Button variant="primary" size="md" prependIcon={<LayersIcon />}>
Go to issues
</Button>
</Link>
}
/>
);
}
return (
<>
<AppHeader header={<ProjectSettingHeader />} />
<ContentWrapper>
<div className="inset-y-0 z-20 flex flex-grow-0 h-full w-full">
<div className="w-80 flex-shrink-0 overflow-y-hidden pt-8 sm:hidden hidden md:block lg:block">
<ProjectSettingsSidebar />
</div>
<div className="w-full pl-10 sm:pl-10 md:pl-0 lg:pl-0 overflow-x-hidden overflow-y-scroll vertical-scrollbar scrollbar-md">
{children}
</div>
</div>
</ContentWrapper>
</>
);
});
export default ProjectSettingLayout;

View File

@ -10,7 +10,7 @@ import { EUserProjectRoles, PROJECT_SETTINGS_LINKS } from "@/constants/project";
// hooks
import { useUser } from "@/hooks/store";
const ProjectSettingsSidebar = () => {
export const ProjectSettingsSidebar = () => {
const { workspaceSlug, projectId } = useParams();
const pathname = usePathname();
// mobx store
@ -61,5 +61,3 @@ const ProjectSettingsSidebar = () => {
</div>
);
};
export default ProjectSettingsSidebar;

View File

@ -1,4 +1,5 @@
"use client";
import { useCallback } from "react";
import { observer } from "mobx-react";
import Link from "next/link";
@ -29,7 +30,7 @@ import {
useUser,
} from "@/hooks/store";
const ProjectViewIssuesHeader: React.FC = observer(() => {
export const ProjectViewIssuesHeader: React.FC = observer(() => {
// router
const { workspaceSlug, projectId, viewId } = useParams();
// store hooks
@ -262,5 +263,3 @@ const ProjectViewIssuesHeader: React.FC = observer(() => {
</div>
);
});
export default ProjectViewIssuesHeader;

View File

@ -31,26 +31,24 @@ const ProjectViewIssuesPage = observer(() => {
: null
);
if (error) {
<EmptyState
image={emptyView}
title="View does not exist"
description="The view you are looking for does not exist or has been deleted."
primaryButton={{
text: "View other views",
onClick: () => router.push(`/${workspaceSlug}/projects/${projectId}/views`),
}}
/>;
}
return (
<>
{error ? (
<EmptyState
image={emptyView}
title="View does not exist"
description="The view you are looking for does not exist or has been deleted."
primaryButton={{
text: "View other views",
onClick: () => router.push(`/${workspaceSlug}/projects/${projectId}/views`),
}}
/>
) : (
<>
<PageHead title={pageTitle} />
<ProjectViewLayoutRoot />
</>
)}
<PageHead title={pageTitle} />
<ProjectViewLayoutRoot />
</>
);
});
export default ProjectViewIssuesPage;
export default ProjectViewIssuesPage;

View File

@ -0,0 +1,14 @@
"use client";
import { AppHeader, ContentWrapper } from "@/components/core";
// local components
import { ProjectViewIssuesHeader } from "./[viewId]/header";
export default function ProjectViewIssuesLayout({ children }: { children: React.ReactNode }) {
return (
<>
<AppHeader header={<ProjectViewIssuesHeader />} />
<ContentWrapper>{children}</ContentWrapper>
</>
);
}

View File

@ -12,7 +12,7 @@ import { EUserProjectRoles } from "@/constants/project";
// hooks
import { useCommandPalette, useProject, useUser } from "@/hooks/store";
const ProjectViewsHeader: React.FC = observer(() => {
export const ProjectViewsHeader = observer(() => {
// router
const { workspaceSlug } = useParams();
// store hooks
@ -70,5 +70,3 @@ const ProjectViewsHeader: React.FC = observer(() => {
</>
);
});
export default ProjectViewsHeader;

View File

@ -0,0 +1,14 @@
"use client";
import { AppHeader, ContentWrapper } from "@/components/core";
// local components
import { ProjectViewsHeader } from "./header";
export default function ProjectViewsListLayout({ children }: { children: React.ReactNode }) {
return (
<>
<AppHeader header={<ProjectViewsHeader />} />
<ContentWrapper>{children}</ContentWrapper>
</>
);
}

View File

@ -0,0 +1,11 @@
"use client";
import { ReactNode } from "react";
// layouts
import { ProjectAuthWrapper } from "@/layouts/auth-layout";
const ProjectDetailLayout = ({ children }: { children: ReactNode }) => (
<ProjectAuthWrapper>{children}</ProjectAuthWrapper>
);
export default ProjectDetailLayout;

View File

@ -20,7 +20,7 @@ import { calculateTotalFilters } from "@/helpers/filter.helper";
import { useAppRouter, useCommandPalette, useEventTracker, useMember, useProjectFilter, useUser } from "@/hooks/store";
import useOutsideClickDetector from "@/hooks/use-outside-click-detector";
const ProjectsHeader = observer(() => {
export const ProjectsListHeader = observer(() => {
// states
const [isSearchOpen, setIsSearchOpen] = useState(false);
// refs
@ -183,5 +183,3 @@ const ProjectsHeader = observer(() => {
</div>
);
});
export default ProjectsHeader;

View File

@ -0,0 +1,17 @@
"use client";
import { ReactNode } from "react";
// components
import { AppHeader, ContentWrapper } from "@/components/core";
// local components
import { ProjectsListHeader } from "./header";
import { ProjectsListMobileHeader } from "./mobile-header";
export default function ProjectListLayout({ children }: { children: ReactNode }) {
return (
<>
<AppHeader header={<ProjectsListHeader />} mobileHeader={<ProjectsListMobileHeader />} />
<ContentWrapper>{children}</ContentWrapper>
</>
);
}

View File

@ -12,7 +12,7 @@ import { calculateTotalFilters } from "@/helpers/filter.helper";
// hooks
import { useAppRouter, useMember, useProjectFilter } from "@/hooks/store";
const ProjectsMobileHeader = observer(() => {
export const ProjectsListMobileHeader = observer(() => {
const {
currentWorkspaceDisplayFilters: displayFilters,
currentWorkspaceFilters: filters,
@ -87,5 +87,3 @@ const ProjectsMobileHeader = observer(() => {
</div>
);
});
export default ProjectsMobileHeader;

View File

@ -61,23 +61,23 @@ const ProjectsPage = observer(() => {
<div className="flex h-full w-full flex-col">
{(calculateTotalFilters(currentWorkspaceFilters ?? {}) !== 0 ||
currentWorkspaceAppliedDisplayFilters?.length !== 0) && (
<div className="border-b border-custom-border-200 px-5 py-3">
<ProjectAppliedFiltersList
appliedFilters={currentWorkspaceFilters ?? {}}
appliedDisplayFilters={currentWorkspaceAppliedDisplayFilters ?? []}
handleClearAllFilters={handleClearAllFilters}
handleRemoveFilter={handleRemoveFilter}
handleRemoveDisplayFilter={handleRemoveDisplayFilter}
filteredProjects={filteredProjectIds?.length ?? 0}
totalProjects={totalProjectIds?.length ?? 0}
alwaysAllowEditing
/>
</div>
)}
<div className="border-b border-custom-border-200 px-5 py-3">
<ProjectAppliedFiltersList
appliedFilters={currentWorkspaceFilters ?? {}}
appliedDisplayFilters={currentWorkspaceAppliedDisplayFilters ?? []}
handleClearAllFilters={handleClearAllFilters}
handleRemoveFilter={handleRemoveFilter}
handleRemoveDisplayFilter={handleRemoveDisplayFilter}
filteredProjects={filteredProjectIds?.length ?? 0}
totalProjects={totalProjectIds?.length ?? 0}
alwaysAllowEditing
/>
</div>
)}
<ProjectCardList />
</div>
</>
);
});
export default ProjectsPage;
export default ProjectsPage;

View File

@ -1,7 +1,7 @@
"use client";
import { FC } from "react";
import { observer } from "mobx-react";;
import { observer } from "mobx-react";
import { Settings } from "lucide-react";
// ui
import { Breadcrumbs } from "@plane/ui";
@ -10,7 +10,7 @@ import { BreadcrumbLink } from "@/components/common";
// hooks
import { useWorkspace } from "@/hooks/store";
const WorkspaceSettingHeader: FC = observer(() => {
export const WorkspaceSettingHeader: FC = observer(() => {
const { currentWorkspace } = useWorkspace();
return (
@ -35,5 +35,3 @@ const WorkspaceSettingHeader: FC = observer(() => {
</div>
);
});
export default WorkspaceSettingHeader;

View File

@ -0,0 +1,36 @@
"use client";
import { ReactNode } from "react";
// components
import { AppHeader, ContentWrapper } from "@/components/core";
// local components
import { WorkspaceSettingHeader } from "./header";
import { MobileWorkspaceSettingsTabs } from "./mobile-header-tabs";
import { WorkspaceSettingsSidebar } from "./sidebar";
export interface IWorkspaceSettingLayout {
children: ReactNode;
}
export default function WorkspaceSettingLayout(props: IWorkspaceSettingLayout) {
const { children } = props;
return (
<>
<AppHeader header={<WorkspaceSettingHeader />} />
<ContentWrapper>
<div className="inset-y-0 z-20 flex h-full w-full gap-2">
<div className="w-80 flex-shrink-0 overflow-y-hidden pt-8 sm:hidden hidden md:block lg:block">
<WorkspaceSettingsSidebar />
</div>
<div className="flex flex-col relative w-full overflow-hidden">
<MobileWorkspaceSettingsTabs />
<div className="w-full pl-4 md:pl-0 md:py-8 py-2 overflow-x-hidden overflow-y-scroll vertical-scrollbar scrollbar-md">
{children}
</div>
</div>
</div>
</ContentWrapper>
</>
);
}

View File

@ -1,7 +1,7 @@
import { useParams, usePathname, useRouter } from "next/navigation";
import { WORKSPACE_SETTINGS_LINKS } from "@/constants/workspace";
const MobileWorkspaceSettingsTabs = () => {
export const MobileWorkspaceSettingsTabs = () => {
const router = useRouter();
const { workspaceSlug } = useParams();
const pathname = usePathname();
@ -9,11 +9,10 @@ const MobileWorkspaceSettingsTabs = () => {
<div className="flex-shrink-0 md:hidden sticky inset-0 flex overflow-x-auto bg-custom-background-100 z-10">
{WORKSPACE_SETTINGS_LINKS.map((item, index) => (
<div
className={`${
item.highlight(pathname, `/${workspaceSlug}`)
className={`${item.highlight(pathname, `/${workspaceSlug}`)
? "text-custom-primary-100 text-sm py-2 px-3 whitespace-nowrap flex flex-grow cursor-pointer justify-around border-b border-custom-primary-200"
: "text-custom-text-200 flex flex-grow cursor-pointer justify-around border-b border-custom-border-200 text-sm py-2 px-3 whitespace-nowrap"
}`}
}`}
key={index}
onClick={() => router.push(`/${workspaceSlug}${item.href}`)}
>
@ -23,5 +22,3 @@ const MobileWorkspaceSettingsTabs = () => {
</div>
);
};
export default MobileWorkspaceSettingsTabs;

View File

@ -14,7 +14,7 @@ import useOutsideClickDetector from "@/hooks/use-outside-click-detector";
export interface IAppSidebar { }
const AppSidebar: FC<IAppSidebar> = observer(() => {
export const AppSidebar: FC<IAppSidebar> = observer(() => {
// store hooks
const { toggleSidebar, sidebarCollapsed } = useAppTheme();
// refs
@ -48,5 +48,3 @@ const AppSidebar: FC<IAppSidebar> = observer(() => {
</div>
);
});
export default AppSidebar;

Some files were not shown because too many files have changed in this diff Show More