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", title: "Email Settings - God Mode",
}; };
const EmailLayout = ({ children }: EmailLayoutProps) => <AdminLayout>{children}</AdminLayout>; export default function EmailLayout({ children }: EmailLayoutProps) {
return <AdminLayout>{children}</AdminLayout>;
export default EmailLayout; }

View file

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

View file

@ -16,7 +16,7 @@ import { UserProvider } from "@/lib/user-provider";
// styles // styles
import "./globals.css"; import "./globals.css";
function RootLayout({ children }: { children: ReactNode }) { export default function RootLayout({ children }: { children: ReactNode }) {
// themes // themes
const { resolvedTheme } = useTheme(); const { resolvedTheme } = useTheme();
@ -44,5 +44,3 @@ function RootLayout({ children }: { children: ReactNode }) {
</html> </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"; import { BreadcrumbLink } from "@/components/common";
// icons // 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="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 w-full flex-grow items-center gap-2 overflow-ellipsis whitespace-nowrap">
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
@ -27,5 +27,3 @@ const WorkspaceActiveCycleHeader = observer(() => (
</div> </div>
</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 // hooks
import { useAppTheme } from "@/hooks/store"; import { useAppTheme } from "@/hooks/store";
const WorkspaceAnalyticsHeader = observer(() => { export const WorkspaceAnalyticsHeader = observer(() => {
const searchParams = useSearchParams(); const searchParams = useSearchParams();
const analytics_tab = searchParams.get("analytics_tab"); const analytics_tab = searchParams.get("analytics_tab");
// store hooks // 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 { ANALYTICS_TABS } from "@/constants/analytics";
import { EmptyStateType } from "@/constants/empty-state"; import { EmptyStateType } from "@/constants/empty-state";
// hooks // hooks
import { useCommandPalette, useEventTracker, useProject, useWorkspace } from "@/hooks/store";; import { useCommandPalette, useEventTracker, useProject, useWorkspace } from "@/hooks/store";
const AnalyticsPage = observer(() => { const AnalyticsPage = observer(() => {
const searchParams = useSearchParams(); const searchParams = useSearchParams();
@ -36,8 +36,9 @@ const AnalyticsPage = observer(() => {
<Tab key={tab.key} as={Fragment}> <Tab key={tab.key} as={Fragment}>
{({ selected }) => ( {({ selected }) => (
<button <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} {tab.title}
<div <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 // hooks
import { useEventTracker } from "@/hooks/store"; import { useEventTracker } from "@/hooks/store";
const WorkspaceDashboardHeader = () => { export const WorkspaceDashboardHeader = () => {
// hooks // hooks
const { captureEvent } = useEventTracker(); const { captureEvent } = useEventTracker();
const { resolvedTheme } = useTheme(); 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 { CommandPalette } from "@/components/command-palette";
import { WorkspaceAuthWrapper } from "@/layouts/auth-layout"; import { WorkspaceAuthWrapper } from "@/layouts/auth-layout";
import { AuthenticationWrapper } from "@/lib/wrappers"; 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 ( return (
<AuthenticationWrapper> <AuthenticationWrapper>
<CommandPalette /> <CommandPalette />
@ -13,10 +13,7 @@ export default function WorkspaceLayout({ header, children }: { header: React.Re
<div className="relative flex h-screen w-full overflow-hidden"> <div className="relative flex h-screen w-full overflow-hidden">
<AppSidebar /> <AppSidebar />
<main className="relative flex h-full w-full flex-col overflow-hidden bg-custom-background-100"> <main className="relative flex h-full w-full flex-col overflow-hidden bg-custom-background-100">
{header} {children}
<div className="h-full w-full overflow-hidden">
<div className="relative h-full w-full overflow-x-hidden overflow-y-scroll">{children}</div>
</div>
</main> </main>
</div> </div>
</WorkspaceAuthWrapper> </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; type?: string | undefined;
}; };
const UserProfileHeader: FC<TUserProfileHeader> = observer((props) => { export const UserProfileHeader: FC<TUserProfileHeader> = observer((props) => {
const { type = undefined } = props; const { type = undefined } = props;
// router // router
const { workspaceSlug, userId } = useParams(); const { workspaceSlug, userId } = useParams();
@ -90,5 +90,3 @@ const UserProfileHeader: FC<TUserProfileHeader> = observer((props) => {
</div> </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 // hooks
import { useIssues, useLabel } from "@/hooks/store"; import { useIssues, useLabel } from "@/hooks/store";
const ProfileIssuesMobileHeader = observer(() => { export const ProfileIssuesMobileHeader = observer(() => {
// router // router
const { workspaceSlug, userId } = useParams(); const { workspaceSlug, userId } = useParams();
// store hook // store hook
@ -187,5 +187,3 @@ const ProfileIssuesMobileHeader = observer(() => {
</div> </div>
); );
}); });
export default ProfileIssuesMobileHeader;

View file

@ -22,7 +22,7 @@ import { UserService } from "@/services/user.service";
// services // services
const userService = new UserService(); const userService = new UserService();
const ProfileOverviewPage = () => { export default function ProfileOverviewPage() {
const { workspaceSlug, userId } = useParams(); const { workspaceSlug, userId } = useParams();
const { data: userProfile } = useSWR( const { data: userProfile } = useSWR(
@ -51,6 +51,4 @@ const ProfileOverviewPage = () => {
</div> </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 { useIssues, useProject } from "@/hooks/store";
import { usePlatformOS } from "@/hooks/use-platform-os"; import { usePlatformOS } from "@/hooks/use-platform-os";
const ProjectArchivesHeader: FC = observer(() => { export const ProjectArchivesHeader: FC = observer(() => {
// router // router
const router = useRouter(); const router = useRouter();
const { workspaceSlug, projectId } = useParams(); const { workspaceSlug, projectId } = useParams();
@ -96,5 +96,3 @@ const ProjectArchivesHeader: FC = observer(() => {
</div> </div>
); );
}); });
export default ProjectArchivesHeader;

View file

@ -1,6 +1,5 @@
"use client"; "use client";
import { FC } from "react";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import { useParams } from "next/navigation"; import { useParams } from "next/navigation";
import useSWR from "swr"; import useSWR from "swr";
@ -17,7 +16,7 @@ import { IssueArchiveService } from "@/services/issue";
const issueArchiveService = new IssueArchiveService(); const issueArchiveService = new IssueArchiveService();
const ProjectArchivedIssueDetailsHeader: FC = observer(() => { export const ProjectArchivedIssueDetailsHeader = observer(() => {
// router // router
const { workspaceSlug, projectId, archivedIssueId } = useParams(); const { workspaceSlug, projectId, archivedIssueId } = useParams();
// store hooks // store hooks
@ -94,5 +93,3 @@ const ProjectArchivedIssueDetailsHeader: FC = observer(() => {
</div> </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 // states
const [analyticsModal, setAnalyticsModal] = useState(false); const [analyticsModal, setAnalyticsModal] = useState(false);
// router // router
@ -208,9 +208,8 @@ const CycleIssuesHeader: React.FC = observer(() => {
{issuesCount && issuesCount > 0 ? ( {issuesCount && issuesCount > 0 ? (
<Tooltip <Tooltip
isMobile={isMobile} isMobile={isMobile}
tooltipContent={`There are ${issuesCount} ${ tooltipContent={`There are ${issuesCount} ${issuesCount > 1 ? "issues" : "issue"
issuesCount > 1 ? "issues" : "issue" } in this cycle`}
} in this cycle`}
position="bottom" 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"> <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 // hooks
import { useIssues, useCycle, useProjectState, useLabel, useMember, useProject } from "@/hooks/store"; import { useIssues, useCycle, useProjectState, useLabel, useMember, useProject } from "@/hooks/store";
const CycleIssuesMobileHeader = () => { export const CycleIssuesMobileHeader = () => {
const [analyticsModal, setAnalyticsModal] = useState(false); const [analyticsModal, setAnalyticsModal] = useState(false);
const { getCycleById } = useCycle(); const { getCycleById } = useCycle();
const layouts = [ const layouts = [
@ -204,5 +204,3 @@ const CycleIssuesMobileHeader = () => {
</> </>
); );
}; };
export default CycleIssuesMobileHeader;

View file

@ -13,7 +13,7 @@ import { EUserProjectRoles } from "@/constants/project";
// hooks // hooks
import { useCommandPalette, useEventTracker, useProject, useUser } from "@/hooks/store"; import { useCommandPalette, useEventTracker, useProject, useUser } from "@/hooks/store";
const CyclesHeader: FC = observer(() => { export const CyclesListHeader: FC = observer(() => {
// router // router
const router = useRouter(); const router = useRouter();
const { workspaceSlug } = useParams(); const { workspaceSlug } = useParams();
@ -74,5 +74,3 @@ const CyclesHeader: FC = observer(() => {
</div> </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 // hooks
import { useCycleFilter, useProject } from "@/hooks/store"; import { useCycleFilter, useProject } from "@/hooks/store";
const CyclesListMobileHeader = observer(() => { export const CyclesListMobileHeader = observer(() => {
const { currentProjectDetails } = useProject(); const { currentProjectDetails } = useProject();
// hooks // hooks
const { updateDisplayFilters } = useCycleFilter(); const { updateDisplayFilters } = useCycleFilter();
@ -50,5 +50,3 @@ const CyclesListMobileHeader = observer(() => {
</div> </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 { useIssues, useLabel, useMember, useProject, useProjectState } from "@/hooks/store";
import { usePlatformOS } from "@/hooks/use-platform-os"; import { usePlatformOS } from "@/hooks/use-platform-os";
const ProjectDraftIssueHeader: FC = observer(() => { export const ProjectDraftIssueHeader: FC = observer(() => {
// router // router
const { workspaceSlug, projectId } = useParams() as { workspaceSlug: string; projectId: string }; const { workspaceSlug, projectId } = useParams() as { workspaceSlug: string; projectId: string };
// store hooks // store hooks
@ -169,5 +169,3 @@ const ProjectDraftIssueHeader: FC = observer(() => {
</div> </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 // hooks
import { useProject, useProjectInbox } from "@/hooks/store"; import { useProject, useProjectInbox } from "@/hooks/store";
const ProjectInboxHeader: FC = observer(() => { export const ProjectInboxHeader: FC = observer(() => {
// states // states
const [createIssueModal, setCreateIssueModal] = useState(false); const [createIssueModal, setCreateIssueModal] = useState(false);
// router // router
@ -76,5 +76,3 @@ const ProjectInboxHeader: FC = observer(() => {
</div> </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"; "use client";
import { FC } from "react";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import { useParams, useRouter } from "next/navigation"; import { useParams, useRouter } from "next/navigation";
import { PanelRight } from "lucide-react"; import { PanelRight } from "lucide-react";
@ -13,7 +12,7 @@ import { cn } from "@/helpers/common.helper";
// hooks // hooks
import { useAppTheme, useIssueDetail, useProject } from "@/hooks/store"; import { useAppTheme, useIssueDetail, useProject } from "@/hooks/store";
const ProjectIssueDetailsHeader: FC = observer(() => { export const ProjectIssueDetailsHeader = observer(() => {
// router // router
const router = useRouter(); const router = useRouter();
const { workspaceSlug, projectId, issueId } = useParams(); const { workspaceSlug, projectId, issueId } = useParams();
@ -83,5 +82,3 @@ const ProjectIssueDetailsHeader: FC = observer(() => {
</div> </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 { useIssues } from "@/hooks/store/use-issues";
import { usePlatformOS } from "@/hooks/use-platform-os"; import { usePlatformOS } from "@/hooks/use-platform-os";
const ProjectIssuesHeader: React.FC = observer(() => { export const ProjectIssuesHeader = observer(() => {
// states // states
const [analyticsModal, setAnalyticsModal] = useState(false); const [analyticsModal, setAnalyticsModal] = useState(false);
// router // 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 // hooks
import { useIssues, useLabel, useMember, useProject, useProjectState } from "@/hooks/store"; import { useIssues, useLabel, useMember, useProject, useProjectState } from "@/hooks/store";
const ProjectIssuesMobileHeader = observer(() => { export const ProjectIssuesMobileHeader = observer(() => {
const layouts = [ const layouts = [
{ key: "list", title: "List", icon: List }, { key: "list", title: "List", icon: List },
{ key: "kanban", title: "Kanban", icon: Kanban }, { 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 // states
const [analyticsModal, setAnalyticsModal] = useState(false); const [analyticsModal, setAnalyticsModal] = useState(false);
// router // 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 // hooks
import { useIssues, useLabel, useMember, useModule, useProject, useProjectState } from "@/hooks/store"; import { useIssues, useLabel, useMember, useModule, useProject, useProjectState } from "@/hooks/store";
const ModuleIssuesMobileHeader = observer(() => { export const ModuleIssuesMobileHeader = observer(() => {
const [analyticsModal, setAnalyticsModal] = useState(false); const [analyticsModal, setAnalyticsModal] = useState(false);
const { currentProjectDetails } = useProject(); const { currentProjectDetails } = useProject();
const { getModuleById } = useModule(); const { getModuleById } = useModule();
@ -185,5 +185,3 @@ const ModuleIssuesMobileHeader = observer(() => {
</div> </div>
); );
}); });
export default ModuleIssuesMobileHeader;

View file

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

View file

@ -20,7 +20,7 @@ export interface IPagesHeaderProps {
showButton?: boolean; showButton?: boolean;
} }
const PageDetailsHeader = observer(() => { export const PageDetailsHeader = observer(() => {
// router // router
const { workspaceSlug, pageId } = useParams(); const { workspaceSlug, pageId } = useParams();
// state // state
@ -168,5 +168,3 @@ const PageDetailsHeader = observer(() => {
</div> </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 // hooks
import { useCommandPalette, useEventTracker, useProject, useUser } from "@/hooks/store"; import { useCommandPalette, useEventTracker, useProject, useUser } from "@/hooks/store";
const PagesHeader = observer(() => { export const PagesListHeader = observer(() => {
// router // router
const { workspaceSlug } = useParams(); const { workspaceSlug } = useParams();
const searchParams = useSearchParams(); const searchParams = useSearchParams();
@ -77,5 +77,3 @@ const PagesHeader = observer(() => {
</div> </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 // hooks
import { useProject, useUser } from "@/hooks/store"; import { useProject, useUser } from "@/hooks/store";
const ProjectSettingHeader: FC = observer(() => { export const ProjectSettingHeader: FC = observer(() => {
// router // router
const router = useRouter(); const router = useRouter();
const { workspaceSlug, projectId } = useParams(); const { workspaceSlug, projectId } = useParams();
@ -82,5 +82,3 @@ const ProjectSettingHeader: FC = observer(() => {
</div> </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 // hooks
import { useUser } from "@/hooks/store"; import { useUser } from "@/hooks/store";
const ProjectSettingsSidebar = () => { export const ProjectSettingsSidebar = () => {
const { workspaceSlug, projectId } = useParams(); const { workspaceSlug, projectId } = useParams();
const pathname = usePathname(); const pathname = usePathname();
// mobx store // mobx store
@ -61,5 +61,3 @@ const ProjectSettingsSidebar = () => {
</div> </div>
); );
}; };
export default ProjectSettingsSidebar;

View file

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

View file

@ -31,26 +31,24 @@ const ProjectViewIssuesPage = observer(() => {
: null : 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 ( return (
<> <>
{error ? ( <PageHead title={pageTitle} />
<EmptyState <ProjectViewLayoutRoot />
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 />
</>
)}
</> </>
); );
}); });
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 // hooks
import { useCommandPalette, useProject, useUser } from "@/hooks/store"; import { useCommandPalette, useProject, useUser } from "@/hooks/store";
const ProjectViewsHeader: React.FC = observer(() => { export const ProjectViewsHeader = observer(() => {
// router // router
const { workspaceSlug } = useParams(); const { workspaceSlug } = useParams();
// store hooks // 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 { useAppRouter, useCommandPalette, useEventTracker, useMember, useProjectFilter, useUser } from "@/hooks/store";
import useOutsideClickDetector from "@/hooks/use-outside-click-detector"; import useOutsideClickDetector from "@/hooks/use-outside-click-detector";
const ProjectsHeader = observer(() => { export const ProjectsListHeader = observer(() => {
// states // states
const [isSearchOpen, setIsSearchOpen] = useState(false); const [isSearchOpen, setIsSearchOpen] = useState(false);
// refs // refs
@ -183,5 +183,3 @@ const ProjectsHeader = observer(() => {
</div> </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 // hooks
import { useAppRouter, useMember, useProjectFilter } from "@/hooks/store"; import { useAppRouter, useMember, useProjectFilter } from "@/hooks/store";
const ProjectsMobileHeader = observer(() => { export const ProjectsListMobileHeader = observer(() => {
const { const {
currentWorkspaceDisplayFilters: displayFilters, currentWorkspaceDisplayFilters: displayFilters,
currentWorkspaceFilters: filters, currentWorkspaceFilters: filters,
@ -87,5 +87,3 @@ const ProjectsMobileHeader = observer(() => {
</div> </div>
); );
}); });
export default ProjectsMobileHeader;

View file

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

View file

@ -1,7 +1,7 @@
"use client"; "use client";
import { FC } from "react"; import { FC } from "react";
import { observer } from "mobx-react";; import { observer } from "mobx-react";
import { Settings } from "lucide-react"; import { Settings } from "lucide-react";
// ui // ui
import { Breadcrumbs } from "@plane/ui"; import { Breadcrumbs } from "@plane/ui";
@ -10,7 +10,7 @@ import { BreadcrumbLink } from "@/components/common";
// hooks // hooks
import { useWorkspace } from "@/hooks/store"; import { useWorkspace } from "@/hooks/store";
const WorkspaceSettingHeader: FC = observer(() => { export const WorkspaceSettingHeader: FC = observer(() => {
const { currentWorkspace } = useWorkspace(); const { currentWorkspace } = useWorkspace();
return ( return (
@ -35,5 +35,3 @@ const WorkspaceSettingHeader: FC = observer(() => {
</div> </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 { useParams, usePathname, useRouter } from "next/navigation";
import { WORKSPACE_SETTINGS_LINKS } from "@/constants/workspace"; import { WORKSPACE_SETTINGS_LINKS } from "@/constants/workspace";
const MobileWorkspaceSettingsTabs = () => { export const MobileWorkspaceSettingsTabs = () => {
const router = useRouter(); const router = useRouter();
const { workspaceSlug } = useParams(); const { workspaceSlug } = useParams();
const pathname = usePathname(); 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"> <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) => ( {WORKSPACE_SETTINGS_LINKS.map((item, index) => (
<div <div
className={`${ className={`${item.highlight(pathname, `/${workspaceSlug}`)
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-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" : "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} key={index}
onClick={() => router.push(`/${workspaceSlug}${item.href}`)} onClick={() => router.push(`/${workspaceSlug}${item.href}`)}
> >
@ -23,5 +22,3 @@ const MobileWorkspaceSettingsTabs = () => {
</div> </div>
); );
}; };
export default MobileWorkspaceSettingsTabs;

View file

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

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