* chore: removed viewer role * chore: indentation * chore: remove viewer role * chore: handled user permissions in store * chore: updated the migration file * chore: updated user permissions store * chore: removed the owner key * chore: code refactor * chore: code refactor * chore: code refactor * chore: code refactor * chore: code refactor * fix: build error * chore: updated user permissions store and handled the permissions fetch in workspace and project wrappers * chore: package user enum updated * chore: user permission updated * chore: user permission updated * chore: resolved build errors * chore: resolved build error * chore: resolved build errors * chore: computedFn deep map issue resolved * chore: added back migration * chore: added new field in project table * chore: removed member store in users * chore: private project for admins * chore: workspace notification access validation updated * fix: workspace member edit option * fix: project intake permission validation updated * chore: workspace export settings permission updated * chore: guest_view_all_issues added * chore: guest_view_all_issues added * chore: key changed for guest access * chore: added validation for individual issues * chore: changed the dashboard issues count * chore: added new yarn file * chore: modified yarn file * chore: project page permission updated * chore: project page permission updated * chore: member setting ux updated * chore: build error * fix: yarn lock * fix: build error --------- Co-authored-by: gurusainath <gurusainath007@gmail.com> Co-authored-by: Anmol Singh Bhatia <anmolsinghbhatia@plane.so>
96 lines
3.9 KiB
TypeScript
96 lines
3.9 KiB
TypeScript
"use client";
|
|
|
|
import { observer } from "mobx-react";
|
|
import { useParams, usePathname } from "next/navigation";
|
|
import useSWR from "swr";
|
|
// components
|
|
import { AppHeader, ContentWrapper } from "@/components/core";
|
|
import { ProfileSidebar } from "@/components/profile";
|
|
// constants
|
|
import { USER_PROFILE_PROJECT_SEGREGATION } from "@/constants/fetch-keys";
|
|
import { PROFILE_ADMINS_TAB, PROFILE_VIEWER_TAB } from "@/constants/profile";
|
|
// hooks
|
|
import { useUserPermissions } from "@/hooks/store";
|
|
import useSize from "@/hooks/use-window-size";
|
|
import { EUserPermissions, EUserPermissionsLevel } from "@/plane-web/constants/user-permissions";
|
|
// local components
|
|
import { UserService } from "@/services/user.service";
|
|
import { UserProfileHeader } from "./header";
|
|
import { ProfileIssuesMobileHeader } from "./mobile-header";
|
|
import { ProfileNavbar } from "./navbar";
|
|
|
|
const userService = new UserService();
|
|
|
|
type Props = {
|
|
children: React.ReactNode;
|
|
};
|
|
|
|
const UseProfileLayout: React.FC<Props> = observer((props) => {
|
|
const { children } = props;
|
|
// router
|
|
const { workspaceSlug, userId } = useParams();
|
|
const pathname = usePathname();
|
|
// store hooks
|
|
const { allowPermissions } = useUserPermissions();
|
|
// derived values
|
|
const isAuthorized = allowPermissions(
|
|
[EUserPermissions.ADMIN, EUserPermissions.MEMBER],
|
|
EUserPermissionsLevel.WORKSPACE
|
|
);
|
|
|
|
const windowSize = useSize();
|
|
const isSmallerScreen = windowSize[0] >= 768;
|
|
|
|
const { data: userProjectsData } = useSWR(
|
|
workspaceSlug && userId ? USER_PROFILE_PROJECT_SEGREGATION(workspaceSlug.toString(), userId.toString()) : null,
|
|
workspaceSlug && userId
|
|
? () => userService.getUserProfileProjectsSegregation(workspaceSlug.toString(), userId.toString())
|
|
: null
|
|
);
|
|
// derived values
|
|
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. */}
|
|
<div className="h-full w-full flex flex-col md:flex-row overflow-hidden">
|
|
<div className="h-full w-full flex flex-col overflow-hidden">
|
|
<AppHeader
|
|
header={
|
|
<UserProfileHeader
|
|
type={currentTab?.label}
|
|
userProjectsData={userProjectsData}
|
|
showProfileIssuesFilter={isIssuesTab}
|
|
/>
|
|
}
|
|
mobileHeader={isIssuesTab && <ProfileIssuesMobileHeader />}
|
|
/>
|
|
<ContentWrapper>
|
|
<div className="h-full w-full flex flex-row md:flex-col md:overflow-hidden">
|
|
<div className="flex w-full flex-col md:h-full md:overflow-hidden">
|
|
<ProfileNavbar isAuthorized={!!isAuthorized} />
|
|
{isAuthorized || !isAuthorizedPath ? (
|
|
<div className={`w-full overflow-hidden 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>
|
|
{!isSmallerScreen && <ProfileSidebar userProjectsData={userProjectsData} />}
|
|
</div>
|
|
</ContentWrapper>
|
|
</div>
|
|
{isSmallerScreen && <ProfileSidebar userProjectsData={userProjectsData} />}
|
|
</div>
|
|
</>
|
|
);
|
|
});
|
|
|
|
export default UseProfileLayout;
|