mirror of
https://github.com/makeplane/plane
synced 2024-06-14 14:31:34 +00:00
fix: layout fixes
This commit is contained in:
parent
b1448c947e
commit
41fd9ce6e8
@ -1,7 +1,7 @@
|
||||
import React, { useCallback, useEffect, useState } from "react";
|
||||
|
||||
import { useRouter } from "next/router";
|
||||
import useSWR from "swr";
|
||||
import { observer } from "mobx-react-lite";
|
||||
// hooks
|
||||
import useToast from "hooks/use-toast";
|
||||
import useUser from "hooks/use-user";
|
||||
@ -18,13 +18,10 @@ import { CreateUpdatePageModal } from "components/pages";
|
||||
import { copyTextToClipboard } from "helpers/string.helper";
|
||||
// services
|
||||
import issuesService from "services/issue.service";
|
||||
import inboxService from "services/inbox.service";
|
||||
// fetch keys
|
||||
import { INBOX_LIST, ISSUE_DETAILS } from "constants/fetch-keys";
|
||||
import { ISSUE_DETAILS } from "constants/fetch-keys";
|
||||
// mobx store
|
||||
import { useMobxStore } from "lib/mobx/store-provider";
|
||||
import { observable } from "mobx";
|
||||
import { observer } from "mobx-react-lite";
|
||||
|
||||
export const CommandPalette: React.FC = observer(() => {
|
||||
const store: any = useMobxStore();
|
||||
@ -75,7 +72,7 @@ export const CommandPalette: React.FC = observer(() => {
|
||||
|
||||
const handleKeyDown = useCallback(
|
||||
(e: KeyboardEvent) => {
|
||||
const { key, ctrlKey, metaKey, altKey, shiftKey } = e;
|
||||
const { key, ctrlKey, metaKey, altKey } = e;
|
||||
if (!key) return;
|
||||
|
||||
const keyPressed = key.toLowerCase();
|
||||
|
@ -34,12 +34,12 @@ export const ProjectSidebarList: FC = observer(() => {
|
||||
// states
|
||||
const [isFavoriteProjectCreate, setIsFavoriteProjectCreate] = useState(false);
|
||||
const [isProjectModalOpen, setIsProjectModalOpen] = useState(false);
|
||||
|
||||
const [isScrolled, setIsScrolled] = useState(false); // scroll animation state
|
||||
|
||||
// refs
|
||||
const containerRef = useRef<HTMLDivElement | null>(null);
|
||||
|
||||
// user
|
||||
const { user } = useUserAuth();
|
||||
// toast
|
||||
const { setToastAlert } = useToast();
|
||||
|
||||
const joinedProjects = workspaceSlug && projectStore.joinedProjects;
|
||||
|
@ -1,11 +1,7 @@
|
||||
import React, { useRef, useState } from "react";
|
||||
|
||||
import Link from "next/link";
|
||||
|
||||
// headless ui
|
||||
import { Transition } from "@headlessui/react";
|
||||
// hooks
|
||||
import useTheme from "hooks/use-theme";
|
||||
import useOutsideClickDetector from "hooks/use-outside-click-detector";
|
||||
// icons
|
||||
import { Bolt, HelpOutlineOutlined, WestOutlined } from "@mui/icons-material";
|
||||
@ -13,6 +9,7 @@ import { ChatBubbleOvalLeftEllipsisIcon } from "@heroicons/react/24/outline";
|
||||
import { DocumentIcon, DiscordIcon, GithubIcon } from "components/icons";
|
||||
// mobx store
|
||||
import { useMobxStore } from "lib/mobx/store-provider";
|
||||
import { observer } from "mobx-react-lite";
|
||||
|
||||
const helpOptions = [
|
||||
{
|
||||
@ -38,15 +35,14 @@ const helpOptions = [
|
||||
},
|
||||
];
|
||||
|
||||
export interface WorkspaceHelpSectionProps {
|
||||
setSidebarActive: React.Dispatch<React.SetStateAction<boolean>>;
|
||||
}
|
||||
|
||||
export const WorkspaceHelpSection: React.FC<WorkspaceHelpSectionProps> = ({ setSidebarActive }) => {
|
||||
const store: any = useMobxStore();
|
||||
export interface WorkspaceHelpSectionProps {}
|
||||
|
||||
export const WorkspaceHelpSection: React.FC<WorkspaceHelpSectionProps> = observer(() => {
|
||||
// store
|
||||
const { theme: themeStore } = useMobxStore();
|
||||
// states
|
||||
const [isNeedHelpOpen, setIsNeedHelpOpen] = useState(false);
|
||||
|
||||
// refs
|
||||
const helpOptionsRef = useRef<HTMLDivElement | null>(null);
|
||||
|
||||
useOutsideClickDetector(helpOptionsRef, () => setIsNeedHelpOpen(false));
|
||||
@ -55,23 +51,23 @@ export const WorkspaceHelpSection: React.FC<WorkspaceHelpSectionProps> = ({ setS
|
||||
<>
|
||||
<div
|
||||
className={`flex w-full items-center justify-between gap-1 self-baseline border-t border-custom-border-200 bg-custom-sidebar-background-100 py-2 px-4 ${
|
||||
store?.theme?.sidebarCollapsed ? "flex-col" : ""
|
||||
themeStore?.sidebarCollapsed ? "flex-col" : ""
|
||||
}`}
|
||||
>
|
||||
{!store?.theme?.sidebarCollapsed && (
|
||||
{!themeStore?.sidebarCollapsed && (
|
||||
<div className="w-1/2 text-center cursor-default rounded-md px-2.5 py-1.5 font-medium outline-none text-sm bg-green-500/10 text-green-500">
|
||||
Free Plan
|
||||
</div>
|
||||
)}
|
||||
<div
|
||||
className={`flex items-center gap-1 ${
|
||||
store?.theme?.sidebarCollapsed ? "flex-col justify-center" : "justify-evenly w-1/2"
|
||||
themeStore?.sidebarCollapsed ? "flex-col justify-center" : "justify-evenly w-1/2"
|
||||
}`}
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
className={`grid place-items-center rounded-md p-1.5 text-custom-text-200 hover:text-custom-text-100 hover:bg-custom-background-90 outline-none ${
|
||||
store?.theme?.sidebarCollapsed ? "w-full" : ""
|
||||
themeStore?.sidebarCollapsed ? "w-full" : ""
|
||||
}`}
|
||||
onClick={() => {
|
||||
const e = new KeyboardEvent("keydown", {
|
||||
@ -85,7 +81,7 @@ export const WorkspaceHelpSection: React.FC<WorkspaceHelpSectionProps> = ({ setS
|
||||
<button
|
||||
type="button"
|
||||
className={`grid place-items-center rounded-md p-1.5 text-custom-text-200 hover:text-custom-text-100 hover:bg-custom-background-90 outline-none ${
|
||||
store?.theme?.sidebarCollapsed ? "w-full" : ""
|
||||
themeStore?.sidebarCollapsed ? "w-full" : ""
|
||||
}`}
|
||||
onClick={() => setIsNeedHelpOpen((prev) => !prev)}
|
||||
>
|
||||
@ -94,20 +90,20 @@ export const WorkspaceHelpSection: React.FC<WorkspaceHelpSectionProps> = ({ setS
|
||||
<button
|
||||
type="button"
|
||||
className="grid place-items-center rounded-md p-1.5 text-custom-text-200 hover:text-custom-text-100 hover:bg-custom-background-90 outline-none md:hidden"
|
||||
onClick={() => setSidebarActive(false)}
|
||||
onClick={() => themeStore.setSidebarCollapsed(!themeStore?.sidebarCollapsed)}
|
||||
>
|
||||
<WestOutlined fontSize="small" />
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className={`hidden md:grid place-items-center rounded-md p-1.5 text-custom-text-200 hover:text-custom-text-100 hover:bg-custom-background-90 outline-none ${
|
||||
store?.theme?.sidebarCollapsed ? "w-full" : ""
|
||||
themeStore?.sidebarCollapsed ? "w-full" : ""
|
||||
}`}
|
||||
onClick={() => store.theme.setSidebarCollapsed(!store?.theme?.sidebarCollapsed)}
|
||||
onClick={() => themeStore.setSidebarCollapsed(!themeStore?.sidebarCollapsed)}
|
||||
>
|
||||
<WestOutlined
|
||||
fontSize="small"
|
||||
className={`duration-300 ${store?.theme?.sidebarCollapsed ? "rotate-180" : ""}`}
|
||||
className={`duration-300 ${themeStore?.sidebarCollapsed ? "rotate-180" : ""}`}
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
@ -124,7 +120,7 @@ export const WorkspaceHelpSection: React.FC<WorkspaceHelpSectionProps> = ({ setS
|
||||
>
|
||||
<div
|
||||
className={`absolute bottom-2 ${
|
||||
store?.theme?.sidebarCollapsed ? "left-full" : "left-[-75px]"
|
||||
themeStore?.sidebarCollapsed ? "left-full" : "left-[-75px]"
|
||||
} space-y-2 rounded-sm bg-custom-background-80 p-1 shadow-md`}
|
||||
ref={helpOptionsRef}
|
||||
>
|
||||
@ -160,4 +156,4 @@ export const WorkspaceHelpSection: React.FC<WorkspaceHelpSectionProps> = ({ setS
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
});
|
||||
|
@ -7,14 +7,10 @@ import useTheme from "hooks/use-theme";
|
||||
import { NotificationPopover } from "components/notifications";
|
||||
import { Tooltip } from "components/ui";
|
||||
// icons
|
||||
import {
|
||||
BarChartRounded,
|
||||
GridViewOutlined,
|
||||
TaskAltOutlined,
|
||||
WorkOutlineOutlined,
|
||||
} from "@mui/icons-material";
|
||||
import { BarChartRounded, GridViewOutlined, TaskAltOutlined, WorkOutlineOutlined } from "@mui/icons-material";
|
||||
// mobx store
|
||||
import { useMobxStore } from "lib/mobx/store-provider";
|
||||
import { observer } from "mobx-react-lite";
|
||||
|
||||
const workspaceLinks = (workspaceSlug: string) => [
|
||||
{
|
||||
@ -39,21 +35,16 @@ const workspaceLinks = (workspaceSlug: string) => [
|
||||
},
|
||||
];
|
||||
|
||||
export const WorkspaceSidebarMenu = () => {
|
||||
const store: any = useMobxStore();
|
||||
|
||||
export const WorkspaceSidebarMenu = observer(() => {
|
||||
const { theme: themeStore } = useMobxStore();
|
||||
// router
|
||||
const router = useRouter();
|
||||
const { workspaceSlug } = router.query;
|
||||
|
||||
const { collapsed: sidebarCollapse } = useTheme();
|
||||
|
||||
return (
|
||||
<div className="w-full cursor-pointer space-y-1 p-4">
|
||||
{workspaceLinks(workspaceSlug as string).map((link, index) => {
|
||||
const isActive =
|
||||
link.name === "Settings"
|
||||
? router.asPath.includes(link.href)
|
||||
: router.asPath === link.href;
|
||||
const isActive = link.name === "Settings" ? router.asPath.includes(link.href) : router.asPath === link.href;
|
||||
|
||||
return (
|
||||
<Link key={index} href={link.href}>
|
||||
@ -62,17 +53,17 @@ export const WorkspaceSidebarMenu = () => {
|
||||
tooltipContent={link.name}
|
||||
position="right"
|
||||
className="ml-2"
|
||||
disabled={!store?.theme?.sidebarCollapsed}
|
||||
disabled={!themeStore?.sidebarCollapsed}
|
||||
>
|
||||
<div
|
||||
className={`group flex w-full items-center gap-2.5 rounded-md px-3 py-2 text-sm font-medium outline-none ${
|
||||
isActive
|
||||
? "bg-custom-primary-100/10 text-custom-primary-100"
|
||||
: "text-custom-sidebar-text-200 hover:bg-custom-sidebar-background-80 focus:bg-custom-sidebar-background-80"
|
||||
} ${store?.theme?.sidebarCollapsed ? "justify-center" : ""}`}
|
||||
} ${themeStore?.sidebarCollapsed ? "justify-center" : ""}`}
|
||||
>
|
||||
{<link.Icon fontSize="small" />}
|
||||
{!store?.theme?.sidebarCollapsed && link.name}
|
||||
{!themeStore?.sidebarCollapsed && link.name}
|
||||
</div>
|
||||
</Tooltip>
|
||||
</a>
|
||||
@ -83,4 +74,4 @@ export const WorkspaceSidebarMenu = () => {
|
||||
<NotificationPopover />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
});
|
||||
|
0
web/layouts/app-layout-legacy/layout.tsx
Normal file
0
web/layouts/app-layout-legacy/layout.tsx
Normal file
0
web/layouts/app-layout/header.tsx
Normal file
0
web/layouts/app-layout/header.tsx
Normal file
3
web/layouts/app-layout/index.ts
Normal file
3
web/layouts/app-layout/index.ts
Normal file
@ -0,0 +1,3 @@
|
||||
export * from "./layout";
|
||||
export * from "./sidebar";
|
||||
export * from "./header";
|
@ -0,0 +1,42 @@
|
||||
import { FC, ReactNode } from "react";
|
||||
// layouts
|
||||
import { UserAuthWrapper, WorkspaceAuthWrapper } from "layouts/auth-layout";
|
||||
// components
|
||||
import { CommandPalette } from "components/command-palette";
|
||||
import { AppSidebar } from "./sidebar";
|
||||
|
||||
export interface IAppLayout {
|
||||
bg: string;
|
||||
children: ReactNode;
|
||||
}
|
||||
|
||||
export const AppLayout: FC<IAppLayout> = (props) => {
|
||||
const { bg = "primary", children } = props;
|
||||
return (
|
||||
<div>
|
||||
<CommandPalette />
|
||||
<UserAuthWrapper>
|
||||
<WorkspaceAuthWrapper>
|
||||
<div>
|
||||
<AppSidebar />
|
||||
<div className="relative flex h-screen w-full overflow-hidden">
|
||||
<main
|
||||
className={`relative flex h-full w-full flex-col overflow-hidden ${
|
||||
bg === "primary"
|
||||
? "bg-custom-background-100"
|
||||
: bg === "secondary"
|
||||
? "bg-custom-background-90"
|
||||
: "bg-custom-background-80"
|
||||
}`}
|
||||
>
|
||||
<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>
|
||||
</div>
|
||||
</div>
|
||||
</WorkspaceAuthWrapper>
|
||||
</UserAuthWrapper>
|
||||
</div>
|
||||
);
|
||||
};
|
36
web/layouts/app-layout/sidebar.tsx
Normal file
36
web/layouts/app-layout/sidebar.tsx
Normal file
@ -0,0 +1,36 @@
|
||||
import { FC } from "react";
|
||||
import { observer } from "mobx-react-lite";
|
||||
// components
|
||||
import {
|
||||
WorkspaceHelpSection,
|
||||
WorkspaceSidebarDropdown,
|
||||
WorkspaceSidebarMenu,
|
||||
WorkspaceSidebarQuickAction,
|
||||
} from "components/workspace";
|
||||
import { ProjectSidebarList } from "components/project";
|
||||
// mobx store
|
||||
import { useMobxStore } from "lib/mobx/store-provider";
|
||||
|
||||
export interface IAppSidebar {}
|
||||
|
||||
export const AppSidebar: FC<IAppSidebar> = observer(() => {
|
||||
// store
|
||||
const { theme: themStore } = useMobxStore();
|
||||
|
||||
return (
|
||||
<div
|
||||
id="app-sidebar"
|
||||
className={`fixed md:relative inset-y-0 flex flex-col bg-custom-sidebar-background-100 h-full flex-shrink-0 flex-grow-0 border-r border-custom-sidebar-border-200 z-20 duration-300 ${
|
||||
themStore?.sidebarCollapsed ? "" : "md:w-[280px]"
|
||||
} ${themStore?.sidebarCollapsed ? "left-0" : "-left-full md:left-0"}`}
|
||||
>
|
||||
<div className="flex h-full w-full flex-1 flex-col">
|
||||
<WorkspaceSidebarDropdown />
|
||||
<WorkspaceSidebarQuickAction />
|
||||
<WorkspaceSidebarMenu />
|
||||
<ProjectSidebarList />
|
||||
<WorkspaceHelpSection />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
});
|
3
web/layouts/auth-layout-legacy/index.ts
Normal file
3
web/layouts/auth-layout-legacy/index.ts
Normal file
@ -0,0 +1,3 @@
|
||||
export * from "./project-authorization-wrapper";
|
||||
export * from "./workspace-authorization-wrapper";
|
||||
export * from "./user-authorization-wrapper";
|
@ -6,8 +6,8 @@ import { useRouter } from "next/router";
|
||||
// contexts
|
||||
import { useProjectMyMembership, ProjectMemberProvider } from "contexts/project-member.context";
|
||||
// layouts
|
||||
import AppHeader from "layouts/app-layout/app-header";
|
||||
import AppSidebar from "layouts/app-layout/app-sidebar";
|
||||
import AppHeader from "layouts/app-layout-legacy/app-header";
|
||||
import AppSidebar from "layouts/app-layout-legacy/app-sidebar";
|
||||
// components
|
||||
import { NotAuthorizedView, JoinProject } from "components/auth-screens";
|
||||
import { CommandPalette } from "components/command-palette";
|
@ -22,7 +22,6 @@ export const UserAuthorizationLayout: React.FC<Props> = ({ children }) => {
|
||||
return (
|
||||
<div className="h-screen grid place-items-center p-4">
|
||||
<div className="flex flex-col items-center gap-3 text-center">
|
||||
<h3 className="text-xl">Loading your profile...</h3>
|
||||
<Spinner />
|
||||
</div>
|
||||
</div>
|
@ -10,8 +10,8 @@ import workspaceServices from "services/workspace.service";
|
||||
// contexts
|
||||
import { WorkspaceMemberProvider } from "contexts/workspace-member.context";
|
||||
// layouts
|
||||
import AppSidebar from "layouts/app-layout/app-sidebar";
|
||||
import AppHeader from "layouts/app-layout/app-header";
|
||||
import AppSidebar from "layouts/app-layout-legacy/app-sidebar";
|
||||
import AppHeader from "layouts/app-layout-legacy/app-header";
|
||||
import { UserAuthorizationLayout } from "./user-authorization-wrapper";
|
||||
// components
|
||||
import { NotAuthorizedView, NotAWorkspaceMember } from "components/auth-screens";
|
@ -1,2 +1,2 @@
|
||||
export * from "./project-authorization-wrapper";
|
||||
export * from "./workspace-authorization-wrapper";
|
||||
export * from "./user-wrapper";
|
||||
export * from "./workspace-wrapper";
|
||||
|
39
web/layouts/auth-layout/user-wrapper.tsx
Normal file
39
web/layouts/auth-layout/user-wrapper.tsx
Normal file
@ -0,0 +1,39 @@
|
||||
import { FC, ReactNode } from "react";
|
||||
import { useRouter } from "next/router";
|
||||
import useSWR from "swr";
|
||||
// services
|
||||
import userService from "services/user.service";
|
||||
// ui
|
||||
import { Spinner } from "components/ui";
|
||||
// fetch-keys
|
||||
import { CURRENT_USER } from "constants/fetch-keys";
|
||||
|
||||
export interface IUserAuthWrapper {
|
||||
children: ReactNode;
|
||||
}
|
||||
|
||||
export const UserAuthWrapper: FC<IUserAuthWrapper> = (props) => {
|
||||
const { children } = props;
|
||||
// router
|
||||
const router = useRouter();
|
||||
// fetching user information
|
||||
const { data: currentUser, error } = useSWR(CURRENT_USER, () => userService.currentUser());
|
||||
|
||||
if (!currentUser && !error) {
|
||||
return (
|
||||
<div className="h-screen grid place-items-center p-4">
|
||||
<div className="flex flex-col items-center gap-3 text-center">
|
||||
<Spinner />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (error) {
|
||||
const redirectTo = router.asPath;
|
||||
router.push(`/?next=${redirectTo}`);
|
||||
return null;
|
||||
}
|
||||
|
||||
return <>{children}</>;
|
||||
};
|
73
web/layouts/auth-layout/workspace-wrapper.tsx
Normal file
73
web/layouts/auth-layout/workspace-wrapper.tsx
Normal file
@ -0,0 +1,73 @@
|
||||
import { FC, ReactNode } from "react";
|
||||
import { useRouter } from "next/router";
|
||||
import Link from "next/link";
|
||||
import useSWR from "swr";
|
||||
// services
|
||||
import workspaceServices from "services/workspace.service";
|
||||
// icons
|
||||
import { Spinner, PrimaryButton, SecondaryButton } from "components/ui";
|
||||
// fetch-keys
|
||||
import { WORKSPACE_MEMBERS_ME } from "constants/fetch-keys";
|
||||
|
||||
export interface IWorkspaceAuthWrapper {
|
||||
children: ReactNode;
|
||||
noHeader?: boolean;
|
||||
bg?: "primary" | "secondary";
|
||||
breadcrumbs?: JSX.Element;
|
||||
left?: JSX.Element;
|
||||
right?: JSX.Element;
|
||||
}
|
||||
|
||||
export const WorkspaceAuthWrapper: FC<IWorkspaceAuthWrapper> = (props) => {
|
||||
const { children } = props;
|
||||
// router
|
||||
const router = useRouter();
|
||||
const { workspaceSlug } = router.query;
|
||||
// fetching user workspace information
|
||||
const { data: workspaceMemberMe, error } = useSWR(
|
||||
workspaceSlug ? WORKSPACE_MEMBERS_ME(workspaceSlug as string) : null,
|
||||
workspaceSlug ? () => workspaceServices.workspaceMemberMe(workspaceSlug.toString()) : null
|
||||
);
|
||||
// while data is being loaded
|
||||
if (!workspaceMemberMe && !error) {
|
||||
return (
|
||||
<div className="grid h-screen place-items-center p-4 bg-custom-background-100">
|
||||
<div className="flex flex-col items-center gap-3 text-center">
|
||||
<Spinner />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
// while user does not have access to view that workspace
|
||||
if (error?.status === 401 || error?.status === 403) {
|
||||
return (
|
||||
<div className={`h-screen w-full overflow-hidden bg-custom-background-100`}>
|
||||
<div className="grid h-full place-items-center p-4">
|
||||
<div className="space-y-8 text-center">
|
||||
<div className="space-y-2">
|
||||
<h3 className="text-lg font-semibold">Not Authorized!</h3>
|
||||
<p className="mx-auto w-1/2 text-sm text-custom-text-200">
|
||||
You{"'"}re not a member of this workspace. Please contact the workspace admin to get an invitation or
|
||||
check your pending invitations.
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex items-center justify-center gap-2">
|
||||
<Link href="/invitations">
|
||||
<a>
|
||||
<SecondaryButton>Check pending invites</SecondaryButton>
|
||||
</a>
|
||||
</Link>
|
||||
<Link href="/create-workspace">
|
||||
<a>
|
||||
<PrimaryButton>Create new workspace</PrimaryButton>
|
||||
</a>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return <>{children}</>;
|
||||
};
|
@ -1,7 +1,7 @@
|
||||
// hooks
|
||||
import { useWorkspaceMyMembership } from "contexts/workspace-member.context";
|
||||
// layouts
|
||||
import { WorkspaceAuthorizationLayout } from "layouts/auth-layout";
|
||||
import { WorkspaceAuthorizationLayout } from "layouts/auth-layout-legacy";
|
||||
// components
|
||||
import { ProfileNavbar, ProfileSidebar } from "components/profile";
|
||||
// ui
|
||||
|
@ -15,7 +15,7 @@ import { Tab } from "@headlessui/react";
|
||||
import analyticsService from "services/analytics.service";
|
||||
import trackEventServices from "services/track_event.service";
|
||||
// layouts
|
||||
import { WorkspaceAuthorizationLayout } from "layouts/auth-layout";
|
||||
import { WorkspaceAuthorizationLayout } from "layouts/auth-layout-legacy";
|
||||
// components
|
||||
import { CustomAnalytics, ScopeAndDemand } from "components/analytics";
|
||||
// ui
|
||||
|
@ -9,19 +9,14 @@ import useSWR, { mutate } from "swr";
|
||||
// next-themes
|
||||
import { useTheme } from "next-themes";
|
||||
// layouts
|
||||
import { WorkspaceAuthorizationLayout } from "layouts/auth-layout";
|
||||
import { WorkspaceAuthorizationLayout } from "layouts/auth-layout-legacy";
|
||||
// services
|
||||
import userService from "services/user.service";
|
||||
// hooks
|
||||
import useUser from "hooks/use-user";
|
||||
import useProjects from "hooks/use-projects";
|
||||
// components
|
||||
import {
|
||||
CompletedIssuesGraph,
|
||||
IssuesList,
|
||||
IssuesPieChart,
|
||||
IssuesStats,
|
||||
} from "components/workspace";
|
||||
import { CompletedIssuesGraph, IssuesList, IssuesPieChart, IssuesStats } from "components/workspace";
|
||||
import { TourRoot } from "components/onboarding";
|
||||
// ui
|
||||
import { PrimaryButton, ProductUpdatesModal } from "components/ui";
|
||||
@ -59,8 +54,7 @@ const WorkspacePage: NextPage = () => {
|
||||
);
|
||||
|
||||
const today = new Date();
|
||||
const greeting =
|
||||
today.getHours() < 12 ? "morning" : today.getHours() < 18 ? "afternoon" : "evening";
|
||||
const greeting = today.getHours() < 12 ? "morning" : today.getHours() < 18 ? "afternoon" : "evening";
|
||||
|
||||
useEffect(() => {
|
||||
if (!workspaceSlug) return;
|
||||
@ -100,10 +94,7 @@ const WorkspacePage: NextPage = () => {
|
||||
}
|
||||
>
|
||||
{isProductUpdatesModalOpen && (
|
||||
<ProductUpdatesModal
|
||||
isOpen={isProductUpdatesModalOpen}
|
||||
setIsOpen={setIsProductUpdatesModalOpen}
|
||||
/>
|
||||
<ProductUpdatesModal isOpen={isProductUpdatesModalOpen} setIsOpen={setIsProductUpdatesModalOpen} />
|
||||
)}
|
||||
{user && !user.is_tour_completed && (
|
||||
<div className="fixed top-0 left-0 h-full w-full bg-custom-backdrop bg-opacity-50 transition-opacity z-20 grid place-items-center">
|
||||
@ -156,9 +147,7 @@ const WorkspacePage: NextPage = () => {
|
||||
<div className="mt-7 bg-custom-primary-100/5 flex justify-between gap-5 md:gap-8">
|
||||
<div className="p-5 md:p-8 pr-0">
|
||||
<h5 className="text-xl font-semibold">Create a project</h5>
|
||||
<p className="mt-2 mb-5">
|
||||
Manage your projects by creating issues, cycles, modules, views and pages.
|
||||
</p>
|
||||
<p className="mt-2 mb-5">Manage your projects by creating issues, cycles, modules, views and pages.</p>
|
||||
<PrimaryButton
|
||||
onClick={() => {
|
||||
const e = new KeyboardEvent("keydown", {
|
||||
|
@ -5,7 +5,7 @@ import { useRouter } from "next/router";
|
||||
// icons
|
||||
import { PlusIcon } from "@heroicons/react/24/outline";
|
||||
// layouts
|
||||
import { WorkspaceAuthorizationLayout } from "layouts/auth-layout";
|
||||
import { WorkspaceAuthorizationLayout } from "layouts/auth-layout-legacy";
|
||||
// hooks
|
||||
import useMyIssuesFilters from "hooks/my-issues/use-my-issues-filter";
|
||||
// components
|
||||
@ -107,9 +107,7 @@ const MyIssuesPage: NextPage = () => {
|
||||
type="button"
|
||||
onClick={tab.onClick}
|
||||
className={`border-b-2 p-4 text-sm font-medium outline-none whitespace-nowrap ${
|
||||
tab.selected
|
||||
? "border-custom-primary-100 text-custom-primary-100"
|
||||
: "border-transparent"
|
||||
tab.selected ? "border-custom-primary-100 text-custom-primary-100" : "border-transparent"
|
||||
}`}
|
||||
>
|
||||
{tab.label}
|
||||
|
@ -6,7 +6,7 @@ import Link from "next/link";
|
||||
// services
|
||||
import userService from "services/user.service";
|
||||
// layouts
|
||||
import { WorkspaceAuthorizationLayout } from "layouts/auth-layout";
|
||||
import { WorkspaceAuthorizationLayout } from "layouts/auth-layout-legacy";
|
||||
// components
|
||||
import { ActivityIcon, ActivityMessage } from "components/core";
|
||||
import { TipTapEditor } from "components/tiptap";
|
||||
@ -60,8 +60,7 @@ const ProfileActivity = () => {
|
||||
activityItem.new_value === "restore" && (
|
||||
<Icon iconName="history" className="text-sm text-custom-text-200" />
|
||||
)
|
||||
) : 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}
|
||||
@ -98,11 +97,7 @@ const ProfileActivity = () => {
|
||||
<div className="issue-comments-section p-0">
|
||||
<TipTapEditor
|
||||
workspaceSlug={workspaceSlug as string}
|
||||
value={
|
||||
activityItem?.new_value !== ""
|
||||
? activityItem.new_value
|
||||
: activityItem.old_value
|
||||
}
|
||||
value={activityItem?.new_value !== "" ? activityItem.new_value : activityItem.old_value}
|
||||
customClassName="text-xs border border-custom-border-200 bg-custom-background-100"
|
||||
noBorder
|
||||
borderOnFocus={false}
|
||||
@ -124,9 +119,7 @@ const ProfileActivity = () => {
|
||||
activityItem.field !== "estimate" ? (
|
||||
<span className="text-custom-text-200">
|
||||
created{" "}
|
||||
<Link
|
||||
href={`/${workspaceSlug}/projects/${activityItem.project}/issues/${activityItem.issue}`}
|
||||
>
|
||||
<Link href={`/${workspaceSlug}/projects/${activityItem.project}/issues/${activityItem.issue}`}>
|
||||
<a className="inline-flex items-center hover:underline">
|
||||
this issue. <ArrowTopRightOnSquareIcon className="ml-1 h-3.5 w-3.5" />
|
||||
</a>
|
||||
@ -150,10 +143,7 @@ const ProfileActivity = () => {
|
||||
<div className="flex h-6 w-6 items-center justify-center">
|
||||
{activityItem.field ? (
|
||||
activityItem.new_value === "restore" ? (
|
||||
<Icon
|
||||
iconName="history"
|
||||
className="!text-2xl text-custom-text-200"
|
||||
/>
|
||||
<Icon iconName="history" className="!text-2xl text-custom-text-200" />
|
||||
) : (
|
||||
<ActivityIcon activity={activityItem} />
|
||||
)
|
||||
@ -179,26 +169,19 @@ const ProfileActivity = () => {
|
||||
</div>
|
||||
<div className="min-w-0 flex-1 py-4 border-b border-custom-border-200">
|
||||
<div className="text-sm text-custom-text-200 break-words">
|
||||
{activityItem.field === "archived_at" &&
|
||||
activityItem.new_value !== "restore" ? (
|
||||
{activityItem.field === "archived_at" && activityItem.new_value !== "restore" ? (
|
||||
<span className="text-gray font-medium">Plane</span>
|
||||
) : activityItem.actor_detail.is_bot ? (
|
||||
<span className="text-gray font-medium">
|
||||
{activityItem.actor_detail.first_name} Bot
|
||||
</span>
|
||||
) : (
|
||||
<Link
|
||||
href={`/${workspaceSlug}/profile/${activityItem.actor_detail.id}`}
|
||||
>
|
||||
<a className="text-gray font-medium">
|
||||
{activityItem.actor_detail.display_name}
|
||||
</a>
|
||||
<Link href={`/${workspaceSlug}/profile/${activityItem.actor_detail.id}`}>
|
||||
<a className="text-gray font-medium">{activityItem.actor_detail.display_name}</a>
|
||||
</Link>
|
||||
)}{" "}
|
||||
{message}{" "}
|
||||
<span className="whitespace-nowrap">
|
||||
{timeAgo(activityItem.created_at)}
|
||||
</span>
|
||||
<span className="whitespace-nowrap">{timeAgo(activityItem.created_at)}</span>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
|
@ -11,7 +11,7 @@ import userService from "services/user.service";
|
||||
import useUserAuth from "hooks/use-user-auth";
|
||||
import useToast from "hooks/use-toast";
|
||||
// layouts
|
||||
import { WorkspaceAuthorizationLayout } from "layouts/auth-layout";
|
||||
import { WorkspaceAuthorizationLayout } from "layouts/auth-layout-legacy";
|
||||
// components
|
||||
import { ImagePickerPopover, ImageUploadModal } from "components/core";
|
||||
import { SettingsSidebar } from "components/project";
|
||||
@ -174,10 +174,7 @@ const Profile: NextPage = () => {
|
||||
<div className={`flex flex-col gap-8 pr-9 py-9 w-full overflow-y-auto`}>
|
||||
<div className="relative h-44 w-full mt-6">
|
||||
<img
|
||||
src={
|
||||
watch("cover_image") ??
|
||||
"https://images.unsplash.com/photo-1506383796573-caf02b4a79ab"
|
||||
}
|
||||
src={watch("cover_image") ?? "https://images.unsplash.com/photo-1506383796573-caf02b4a79ab"}
|
||||
className="h-44 w-full rounded-lg object-cover"
|
||||
alt={myProfile?.name ?? "Cover image"}
|
||||
/>
|
||||
@ -214,10 +211,7 @@ const Profile: NextPage = () => {
|
||||
onChange={(imageUrl) => {
|
||||
setValue("cover_image", imageUrl);
|
||||
}}
|
||||
value={
|
||||
watch("cover_image") ??
|
||||
"https://images.unsplash.com/photo-1506383796573-caf02b4a79ab"
|
||||
}
|
||||
value={watch("cover_image") ?? "https://images.unsplash.com/photo-1506383796573-caf02b4a79ab"}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
@ -307,9 +301,7 @@ const Profile: NextPage = () => {
|
||||
</CustomSelect>
|
||||
)}
|
||||
/>
|
||||
{errors.role && (
|
||||
<span className="text-xs text-red-500">Please select a role</span>
|
||||
)}
|
||||
{errors.role && <span className="text-xs text-red-500">Please select a role</span>}
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col gap-1">
|
||||
@ -328,8 +320,7 @@ const Profile: NextPage = () => {
|
||||
validate: (value) => {
|
||||
if (value.trim().length < 1) return "Display name can't be empty.";
|
||||
|
||||
if (value.split(" ").length > 1)
|
||||
return "Display name can't have two consecutive spaces.";
|
||||
if (value.split(" ").length > 1) return "Display name can't have two consecutive spaces.";
|
||||
|
||||
if (value.replace(/\s/g, "").length < 1)
|
||||
return "Display name must be at least 1 characters long.";
|
||||
@ -353,11 +344,7 @@ const Profile: NextPage = () => {
|
||||
render={({ field: { value, onChange } }) => (
|
||||
<CustomSearchSelect
|
||||
value={value}
|
||||
label={
|
||||
value
|
||||
? TIME_ZONES.find((t) => t.value === value)?.label ?? value
|
||||
: "Select a timezone"
|
||||
}
|
||||
label={value ? TIME_ZONES.find((t) => t.value === value)?.label ?? value : "Select a timezone"}
|
||||
options={timeZoneOptions}
|
||||
onChange={onChange}
|
||||
verticalPosition="top"
|
||||
@ -366,9 +353,7 @@ const Profile: NextPage = () => {
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
{errors.role && (
|
||||
<span className="text-xs text-red-500">Please select a role</span>
|
||||
)}
|
||||
{errors.role && <span className="text-xs text-red-500">Please select a role</span>}
|
||||
</div>
|
||||
|
||||
<div className="flex items-center justify-between py-2">
|
||||
|
@ -2,7 +2,7 @@ import { useEffect, useState } from "react";
|
||||
// hooks
|
||||
import useUserAuth from "hooks/use-user-auth";
|
||||
// layouts
|
||||
import { WorkspaceAuthorizationLayout } from "layouts/auth-layout";
|
||||
import { WorkspaceAuthorizationLayout } from "layouts/auth-layout-legacy";
|
||||
// components
|
||||
import { CustomThemeSelector, ThemeSwitch } from "components/core";
|
||||
// ui
|
||||
@ -36,14 +36,10 @@ const ProfilePreferences = observer(() => {
|
||||
background: currentTheme.background !== "" ? currentTheme.background : "#0d101b",
|
||||
text: currentTheme.text !== "" ? currentTheme.text : "#c5c5c5",
|
||||
primary: currentTheme.primary !== "" ? currentTheme.primary : "#3f76ff",
|
||||
sidebarBackground:
|
||||
currentTheme.sidebarBackground !== "" ? currentTheme.sidebarBackground : "#0d101b",
|
||||
sidebarBackground: currentTheme.sidebarBackground !== "" ? currentTheme.sidebarBackground : "#0d101b",
|
||||
sidebarText: currentTheme.sidebarText !== "" ? currentTheme.sidebarText : "#c5c5c5",
|
||||
darkPalette: false,
|
||||
palette:
|
||||
currentTheme.palette !== ",,,,"
|
||||
? currentTheme.palette
|
||||
: "#0d101b,#c5c5c5,#3f76ff,#0d101b,#c5c5c5",
|
||||
palette: currentTheme.palette !== ",,,," ? currentTheme.palette : "#0d101b,#c5c5c5,#3f76ff,#0d101b,#c5c5c5",
|
||||
theme: "custom",
|
||||
});
|
||||
setCustomThemeSelectorOptions((prevData) => true);
|
||||
@ -71,9 +67,7 @@ const ProfilePreferences = observer(() => {
|
||||
<div className="grid grid-cols-12 gap-4 sm:gap-16 py-6">
|
||||
<div className="col-span-12 sm:col-span-6">
|
||||
<h4 className="text-lg font-semibold text-custom-text-100">Theme</h4>
|
||||
<p className="text-sm text-custom-text-200">
|
||||
Select or customize your interface color scheme.
|
||||
</p>
|
||||
<p className="text-sm text-custom-text-200">Select or customize your interface color scheme.</p>
|
||||
</div>
|
||||
<div className="col-span-12 sm:col-span-6">
|
||||
<ThemeSwitch
|
||||
|
@ -12,7 +12,7 @@ import issuesService from "services/issue.service";
|
||||
import useUserAuth from "hooks/use-user-auth";
|
||||
import useToast from "hooks/use-toast";
|
||||
// layouts
|
||||
import { ProjectAuthorizationWrapper } from "layouts/auth-layout";
|
||||
import { ProjectAuthorizationWrapper } from "layouts/auth-layout-legacy";
|
||||
// components
|
||||
import { IssueDetailsSidebar, IssueMainContent } from "components/issues";
|
||||
// ui
|
||||
|
@ -5,7 +5,7 @@ import useSWR from "swr";
|
||||
// services
|
||||
import projectService from "services/project.service";
|
||||
// layouts
|
||||
import { ProjectAuthorizationWrapper } from "layouts/auth-layout";
|
||||
import { ProjectAuthorizationWrapper } from "layouts/auth-layout-legacy";
|
||||
// contexts
|
||||
import { IssueViewContextProvider } from "contexts/issue-view.context";
|
||||
// helper
|
||||
@ -28,9 +28,7 @@ const ProjectArchivedIssues: NextPage = () => {
|
||||
|
||||
const { data: projectDetails } = useSWR(
|
||||
workspaceSlug && projectId ? PROJECT_DETAILS(projectId as string) : null,
|
||||
workspaceSlug && projectId
|
||||
? () => projectService.getProject(workspaceSlug as string, projectId as string)
|
||||
: null
|
||||
workspaceSlug && projectId ? () => projectService.getProject(workspaceSlug as string, projectId as string) : null
|
||||
);
|
||||
|
||||
return (
|
||||
@ -39,9 +37,7 @@ const ProjectArchivedIssues: NextPage = () => {
|
||||
breadcrumbs={
|
||||
<Breadcrumbs>
|
||||
<BreadcrumbItem title="Projects" link={`/${workspaceSlug}/projects`} />
|
||||
<BreadcrumbItem
|
||||
title={`${truncateText(projectDetails?.name ?? "Project", 32)} Archived Issues`}
|
||||
/>
|
||||
<BreadcrumbItem title={`${truncateText(projectDetails?.name ?? "Project", 32)} Archived Issues`} />
|
||||
</Breadcrumbs>
|
||||
}
|
||||
right={
|
||||
|
@ -7,7 +7,7 @@ import useSWR from "swr";
|
||||
import { ArrowLeftIcon } from "@heroicons/react/24/outline";
|
||||
import { CyclesIcon } from "components/icons";
|
||||
// layouts
|
||||
import { ProjectAuthorizationWrapper } from "layouts/auth-layout";
|
||||
import { ProjectAuthorizationWrapper } from "layouts/auth-layout-legacy";
|
||||
// contexts
|
||||
import { IssueViewContextProvider } from "contexts/issue-view.context";
|
||||
// components
|
||||
|
@ -6,7 +6,7 @@ import useSWR from "swr";
|
||||
import useLocalStorage from "hooks/use-local-storage";
|
||||
import useUserAuth from "hooks/use-user-auth";
|
||||
// layouts
|
||||
import { ProjectAuthorizationWrapper } from "layouts/auth-layout";
|
||||
import { ProjectAuthorizationWrapper } from "layouts/auth-layout-legacy";
|
||||
// components
|
||||
import { CyclesView, ActiveCycleDetails, CreateUpdateCycleModal } from "components/cycles";
|
||||
// ui
|
||||
|
@ -5,7 +5,7 @@ import useSWR from "swr";
|
||||
// services
|
||||
import projectService from "services/project.service";
|
||||
// layouts
|
||||
import { ProjectAuthorizationWrapper } from "layouts/auth-layout";
|
||||
import { ProjectAuthorizationWrapper } from "layouts/auth-layout-legacy";
|
||||
// contexts
|
||||
import { IssueViewContextProvider } from "contexts/issue-view.context";
|
||||
// helper
|
||||
@ -28,9 +28,7 @@ const ProjectDraftIssues: NextPage = () => {
|
||||
|
||||
const { data: projectDetails } = useSWR(
|
||||
workspaceSlug && projectId ? PROJECT_DETAILS(projectId as string) : null,
|
||||
workspaceSlug && projectId
|
||||
? () => projectService.getProject(workspaceSlug as string, projectId as string)
|
||||
: null
|
||||
workspaceSlug && projectId ? () => projectService.getProject(workspaceSlug as string, projectId as string) : null
|
||||
);
|
||||
|
||||
return (
|
||||
@ -39,9 +37,7 @@ const ProjectDraftIssues: NextPage = () => {
|
||||
breadcrumbs={
|
||||
<Breadcrumbs>
|
||||
<BreadcrumbItem title="Projects" link={`/${workspaceSlug}/projects`} />
|
||||
<BreadcrumbItem
|
||||
title={`${truncateText(projectDetails?.name ?? "Project", 32)} Draft Issues`}
|
||||
/>
|
||||
<BreadcrumbItem title={`${truncateText(projectDetails?.name ?? "Project", 32)} Draft Issues`} />
|
||||
</Breadcrumbs>
|
||||
}
|
||||
right={
|
||||
|
@ -3,7 +3,7 @@ import { useRouter } from "next/router";
|
||||
// hooks
|
||||
import useProjectDetails from "hooks/use-project-details";
|
||||
// layouts
|
||||
import { ProjectAuthorizationWrapper } from "layouts/auth-layout";
|
||||
import { ProjectAuthorizationWrapper } from "layouts/auth-layout-legacy";
|
||||
// contexts
|
||||
import { InboxViewContextProvider } from "contexts/inbox-view-context";
|
||||
// components
|
||||
@ -30,9 +30,7 @@ const ProjectInbox: NextPage = () => {
|
||||
breadcrumbs={
|
||||
<Breadcrumbs>
|
||||
<BreadcrumbItem title="Projects" link={`/${workspaceSlug}/projects`} />
|
||||
<BreadcrumbItem
|
||||
title={`${truncateText(projectDetails?.name ?? "Project", 32)} Inbox`}
|
||||
/>
|
||||
<BreadcrumbItem title={`${truncateText(projectDetails?.name ?? "Project", 32)} Inbox`} />
|
||||
</Breadcrumbs>
|
||||
}
|
||||
right={
|
||||
|
@ -11,7 +11,7 @@ import issuesService from "services/issue.service";
|
||||
// hooks
|
||||
import useUserAuth from "hooks/use-user-auth";
|
||||
// layouts
|
||||
import { ProjectAuthorizationWrapper } from "layouts/auth-layout";
|
||||
import { ProjectAuthorizationWrapper } from "layouts/auth-layout-legacy";
|
||||
// components
|
||||
import { IssueDetailsSidebar, IssueMainContent } from "components/issues";
|
||||
// ui
|
||||
|
@ -10,7 +10,7 @@ import { useMobxStore } from "lib/mobx/store-provider";
|
||||
import projectService from "services/project.service";
|
||||
import inboxService from "services/inbox.service";
|
||||
// layouts
|
||||
import { ProjectAuthorizationWrapper } from "layouts/auth-layout";
|
||||
import { ProjectAuthorizationWrapper } from "layouts/auth-layout-legacy";
|
||||
// helper
|
||||
import { truncateText } from "helpers/string.helper";
|
||||
// components
|
||||
|
@ -12,7 +12,7 @@ import modulesService from "services/modules.service";
|
||||
import useToast from "hooks/use-toast";
|
||||
import useUserAuth from "hooks/use-user-auth";
|
||||
// layouts
|
||||
import { ProjectAuthorizationWrapper } from "layouts/auth-layout";
|
||||
import { ProjectAuthorizationWrapper } from "layouts/auth-layout-legacy";
|
||||
// contexts
|
||||
import { IssueViewContextProvider } from "contexts/issue-view.context";
|
||||
// components
|
||||
@ -45,32 +45,20 @@ const SingleModule: React.FC = () => {
|
||||
|
||||
const { data: modules } = useSWR(
|
||||
workspaceSlug && projectId ? MODULE_LIST(projectId as string) : null,
|
||||
workspaceSlug && projectId
|
||||
? () => modulesService.getModules(workspaceSlug as string, projectId as string)
|
||||
: null
|
||||
workspaceSlug && projectId ? () => modulesService.getModules(workspaceSlug as string, projectId as string) : null
|
||||
);
|
||||
|
||||
const { data: moduleIssues } = useSWR(
|
||||
workspaceSlug && projectId && moduleId ? MODULE_ISSUES(moduleId as string) : null,
|
||||
workspaceSlug && projectId && moduleId
|
||||
? () =>
|
||||
modulesService.getModuleIssues(
|
||||
workspaceSlug as string,
|
||||
projectId as string,
|
||||
moduleId as string
|
||||
)
|
||||
? () => modulesService.getModuleIssues(workspaceSlug as string, projectId as string, moduleId as string)
|
||||
: null
|
||||
);
|
||||
|
||||
const { data: moduleDetails, error } = useSWR(
|
||||
moduleId ? MODULE_DETAILS(moduleId as string) : null,
|
||||
workspaceSlug && projectId
|
||||
? () =>
|
||||
modulesService.getModuleDetails(
|
||||
workspaceSlug as string,
|
||||
projectId as string,
|
||||
moduleId as string
|
||||
)
|
||||
? () => modulesService.getModuleDetails(workspaceSlug as string, projectId as string, moduleId as string)
|
||||
: null
|
||||
);
|
||||
|
||||
@ -82,13 +70,7 @@ const SingleModule: React.FC = () => {
|
||||
};
|
||||
|
||||
await modulesService
|
||||
.addIssuesToModule(
|
||||
workspaceSlug as string,
|
||||
projectId as string,
|
||||
moduleId as string,
|
||||
payload,
|
||||
user
|
||||
)
|
||||
.addIssuesToModule(workspaceSlug as string, projectId as string, moduleId as string, payload, user)
|
||||
.catch(() =>
|
||||
setToastAlert({
|
||||
type: "error",
|
||||
@ -176,10 +158,7 @@ const SingleModule: React.FC = () => {
|
||||
/>
|
||||
) : (
|
||||
<>
|
||||
<AnalyticsProjectModal
|
||||
isOpen={analyticsModal}
|
||||
onClose={() => setAnalyticsModal(false)}
|
||||
/>
|
||||
<AnalyticsProjectModal isOpen={analyticsModal} onClose={() => setAnalyticsModal(false)} />
|
||||
<div
|
||||
className={`h-full flex flex-col ${moduleSidebar ? "mr-[24rem]" : ""} ${
|
||||
analyticsModal ? "mr-[50%]" : ""
|
||||
|
@ -5,18 +5,14 @@ import { useRouter } from "next/router";
|
||||
import useSWR from "swr";
|
||||
|
||||
// layouts
|
||||
import { ProjectAuthorizationWrapper } from "layouts/auth-layout";
|
||||
import { ProjectAuthorizationWrapper } from "layouts/auth-layout-legacy";
|
||||
// hooks
|
||||
import useUserAuth from "hooks/use-user-auth";
|
||||
// services
|
||||
import projectService from "services/project.service";
|
||||
import modulesService from "services/modules.service";
|
||||
// components
|
||||
import {
|
||||
CreateUpdateModuleModal,
|
||||
ModulesListGanttChartView,
|
||||
SingleModuleCard,
|
||||
} from "components/modules";
|
||||
import { CreateUpdateModuleModal, ModulesListGanttChartView, SingleModuleCard } from "components/modules";
|
||||
// ui
|
||||
import { EmptyState, Icon, Loader, PrimaryButton, Tooltip } from "components/ui";
|
||||
import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs";
|
||||
@ -56,16 +52,12 @@ const ProjectModules: NextPage = () => {
|
||||
|
||||
const { data: activeProject } = useSWR(
|
||||
workspaceSlug && projectId ? PROJECT_DETAILS(projectId as string) : null,
|
||||
workspaceSlug && projectId
|
||||
? () => projectService.getProject(workspaceSlug as string, projectId as string)
|
||||
: null
|
||||
workspaceSlug && projectId ? () => projectService.getProject(workspaceSlug as string, projectId as string) : null
|
||||
);
|
||||
|
||||
const { data: modules, mutate: mutateModules } = useSWR(
|
||||
workspaceSlug && projectId ? MODULE_LIST(projectId as string) : null,
|
||||
workspaceSlug && projectId
|
||||
? () => modulesService.getModules(workspaceSlug as string, projectId as string)
|
||||
: null
|
||||
workspaceSlug && projectId ? () => modulesService.getModules(workspaceSlug as string, projectId as string) : null
|
||||
);
|
||||
|
||||
const handleEditModule = (module: IModule) => {
|
||||
@ -95,24 +87,17 @@ const ProjectModules: NextPage = () => {
|
||||
{moduleViewOptions.map((option) => (
|
||||
<Tooltip
|
||||
key={option.type}
|
||||
tooltipContent={
|
||||
<span className="capitalize">{replaceUnderscoreIfSnakeCase(option.type)} View</span>
|
||||
}
|
||||
tooltipContent={<span className="capitalize">{replaceUnderscoreIfSnakeCase(option.type)} View</span>}
|
||||
position="bottom"
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
className={`grid h-7 w-7 place-items-center rounded p-1 outline-none hover:bg-custom-sidebar-background-80 duration-300 ${
|
||||
modulesView === option.type
|
||||
? "bg-custom-sidebar-background-80"
|
||||
: "text-custom-sidebar-text-200"
|
||||
modulesView === option.type ? "bg-custom-sidebar-background-80" : "text-custom-sidebar-text-200"
|
||||
}`}
|
||||
onClick={() => setModulesView(option.type)}
|
||||
>
|
||||
<Icon
|
||||
iconName={option.icon}
|
||||
className={`!text-base ${option.type === "grid" ? "rotate-90" : ""}`}
|
||||
/>
|
||||
<Icon iconName={option.icon} className={`!text-base ${option.type === "grid" ? "rotate-90" : ""}`} />
|
||||
</button>
|
||||
</Tooltip>
|
||||
))}
|
||||
|
@ -21,7 +21,7 @@ import issuesService from "services/issue.service";
|
||||
import useToast from "hooks/use-toast";
|
||||
import useUser from "hooks/use-user";
|
||||
// layouts
|
||||
import { ProjectAuthorizationWrapper } from "layouts/auth-layout";
|
||||
import { ProjectAuthorizationWrapper } from "layouts/auth-layout-legacy";
|
||||
// components
|
||||
import { CreateUpdateBlockInline, SinglePageBlock } from "components/pages";
|
||||
import { CreateLabelModal } from "components/labels";
|
||||
|
@ -15,7 +15,7 @@ import useUserAuth from "hooks/use-user-auth";
|
||||
// icons
|
||||
import { PlusIcon } from "components/icons";
|
||||
// layouts
|
||||
import { ProjectAuthorizationWrapper } from "layouts/auth-layout";
|
||||
import { ProjectAuthorizationWrapper } from "layouts/auth-layout-legacy";
|
||||
// components
|
||||
import { RecentPagesList, CreateUpdatePageModal, TPagesListProps } from "components/pages";
|
||||
// ui
|
||||
@ -31,33 +31,21 @@ import { PROJECT_DETAILS } from "constants/fetch-keys";
|
||||
// helper
|
||||
import { truncateText } from "helpers/string.helper";
|
||||
|
||||
const AllPagesList = dynamic<TPagesListProps>(
|
||||
() => import("components/pages").then((a) => a.AllPagesList),
|
||||
{
|
||||
ssr: false,
|
||||
}
|
||||
);
|
||||
const AllPagesList = dynamic<TPagesListProps>(() => import("components/pages").then((a) => a.AllPagesList), {
|
||||
ssr: false,
|
||||
});
|
||||
|
||||
const FavoritePagesList = dynamic<TPagesListProps>(
|
||||
() => import("components/pages").then((a) => a.FavoritePagesList),
|
||||
{
|
||||
ssr: false,
|
||||
}
|
||||
);
|
||||
const FavoritePagesList = dynamic<TPagesListProps>(() => import("components/pages").then((a) => a.FavoritePagesList), {
|
||||
ssr: false,
|
||||
});
|
||||
|
||||
const MyPagesList = dynamic<TPagesListProps>(
|
||||
() => import("components/pages").then((a) => a.MyPagesList),
|
||||
{
|
||||
ssr: false,
|
||||
}
|
||||
);
|
||||
const MyPagesList = dynamic<TPagesListProps>(() => import("components/pages").then((a) => a.MyPagesList), {
|
||||
ssr: false,
|
||||
});
|
||||
|
||||
const OtherPagesList = dynamic<TPagesListProps>(
|
||||
() => import("components/pages").then((a) => a.OtherPagesList),
|
||||
{
|
||||
ssr: false,
|
||||
}
|
||||
);
|
||||
const OtherPagesList = dynamic<TPagesListProps>(() => import("components/pages").then((a) => a.OtherPagesList), {
|
||||
ssr: false,
|
||||
});
|
||||
|
||||
const tabsList = ["Recent", "All", "Favorites", "Created by me", "Created by others"];
|
||||
|
||||
@ -75,9 +63,7 @@ const ProjectPages: NextPage = () => {
|
||||
|
||||
const { data: projectDetails } = useSWR(
|
||||
workspaceSlug && projectId ? PROJECT_DETAILS(projectId as string) : null,
|
||||
workspaceSlug && projectId
|
||||
? () => projectService.getProject(workspaceSlug as string, projectId as string)
|
||||
: null
|
||||
workspaceSlug && projectId ? () => projectService.getProject(workspaceSlug as string, projectId as string) : null
|
||||
);
|
||||
|
||||
const currentTabValue = (tab: string | null) => {
|
||||
@ -109,9 +95,7 @@ const ProjectPages: NextPage = () => {
|
||||
breadcrumbs={
|
||||
<Breadcrumbs>
|
||||
<BreadcrumbItem title="Projects" link={`/${workspaceSlug}/projects`} />
|
||||
<BreadcrumbItem
|
||||
title={`${truncateText(projectDetails?.name ?? "Project", 32)} Pages`}
|
||||
/>
|
||||
<BreadcrumbItem title={`${truncateText(projectDetails?.name ?? "Project", 32)} Pages`} />
|
||||
</Breadcrumbs>
|
||||
}
|
||||
right={
|
||||
|
@ -7,7 +7,7 @@ import { mutate } from "swr";
|
||||
// services
|
||||
import projectService from "services/project.service";
|
||||
// layouts
|
||||
import { ProjectAuthorizationWrapper } from "layouts/auth-layout";
|
||||
import { ProjectAuthorizationWrapper } from "layouts/auth-layout-legacy";
|
||||
// hooks
|
||||
import useUserAuth from "hooks/use-user-auth";
|
||||
import useProjectDetails from "hooks/use-project-details";
|
||||
@ -45,8 +45,7 @@ const AutomationsSettings: NextPage = () => {
|
||||
|
||||
mutate<IProject[]>(
|
||||
PROJECTS_LIST(workspaceSlug as string, { is_favorite: "all" }),
|
||||
(prevData) =>
|
||||
(prevData ?? []).map((p) => (p.id === projectDetails.id ? { ...p, ...formData } : p)),
|
||||
(prevData) => (prevData ?? []).map((p) => (p.id === projectDetails.id ? { ...p, ...formData } : p)),
|
||||
false
|
||||
);
|
||||
|
||||
|
@ -10,7 +10,7 @@ import projectService from "services/project.service";
|
||||
// hooks
|
||||
import useProjectDetails from "hooks/use-project-details";
|
||||
// layouts
|
||||
import { ProjectAuthorizationWrapper } from "layouts/auth-layout";
|
||||
import { ProjectAuthorizationWrapper } from "layouts/auth-layout-legacy";
|
||||
// components
|
||||
import { CreateUpdateEstimateModal, SingleEstimate } from "components/estimates";
|
||||
import { SettingsSidebar } from "components/project";
|
||||
|
@ -8,7 +8,7 @@ import useSWR, { mutate } from "swr";
|
||||
import projectService from "services/project.service";
|
||||
import trackEventServices, { MiscellaneousEventType } from "services/track_event.service";
|
||||
// layouts
|
||||
import { ProjectAuthorizationWrapper } from "layouts/auth-layout";
|
||||
import { ProjectAuthorizationWrapper } from "layouts/auth-layout-legacy";
|
||||
// hooks
|
||||
import useToast from "hooks/use-toast";
|
||||
import useUserAuth from "hooks/use-user-auth";
|
||||
|
@ -3,7 +3,7 @@ import { useRouter } from "next/router";
|
||||
import useSWR from "swr";
|
||||
import { Disclosure, Transition } from "@headlessui/react";
|
||||
// layouts
|
||||
import { ProjectAuthorizationWrapper } from "layouts/auth-layout";
|
||||
import { ProjectAuthorizationWrapper } from "layouts/auth-layout-legacy";
|
||||
// services
|
||||
import projectService from "services/project.service";
|
||||
// components
|
||||
|
@ -5,7 +5,7 @@ import { useRouter } from "next/router";
|
||||
import useSWR from "swr";
|
||||
|
||||
// layouts
|
||||
import { ProjectAuthorizationWrapper } from "layouts/auth-layout";
|
||||
import { ProjectAuthorizationWrapper } from "layouts/auth-layout-legacy";
|
||||
// services
|
||||
import IntegrationService from "services/integration.service";
|
||||
import projectService from "services/project.service";
|
||||
|
@ -10,7 +10,7 @@ import useUserAuth from "hooks/use-user-auth";
|
||||
import projectService from "services/project.service";
|
||||
import issuesService from "services/issue.service";
|
||||
// layouts
|
||||
import { ProjectAuthorizationWrapper } from "layouts/auth-layout";
|
||||
import { ProjectAuthorizationWrapper } from "layouts/auth-layout-legacy";
|
||||
// components
|
||||
import {
|
||||
CreateUpdateLabelInline,
|
||||
|
@ -15,7 +15,7 @@ import useProjectMembers from "hooks/use-project-members";
|
||||
import useProjectDetails from "hooks/use-project-details";
|
||||
import { Controller, useForm } from "react-hook-form";
|
||||
// layouts
|
||||
import { ProjectAuthorizationWrapper } from "layouts/auth-layout";
|
||||
import { ProjectAuthorizationWrapper } from "layouts/auth-layout-legacy";
|
||||
// components
|
||||
import ConfirmProjectMemberRemove from "components/project/confirm-project-member-remove";
|
||||
import SendProjectInvitationModal from "components/project/send-project-invitation-modal";
|
||||
@ -80,9 +80,8 @@ const MembersSettings: NextPage = () => {
|
||||
formState: { isSubmitting },
|
||||
} = useForm<IProject>({ defaultValues });
|
||||
|
||||
const { data: activeWorkspace } = useSWR(
|
||||
workspaceSlug ? WORKSPACE_DETAILS(workspaceSlug as string) : null,
|
||||
() => (workspaceSlug ? workspaceService.getWorkspace(workspaceSlug as string) : null)
|
||||
const { data: activeWorkspace } = useSWR(workspaceSlug ? WORKSPACE_DETAILS(workspaceSlug as string) : null, () =>
|
||||
workspaceSlug ? workspaceService.getWorkspace(workspaceSlug as string) : null
|
||||
);
|
||||
|
||||
const { data: people } = useSWR(
|
||||
@ -93,21 +92,16 @@ const MembersSettings: NextPage = () => {
|
||||
);
|
||||
|
||||
const { data: projectMembers, mutate: mutateMembers } = useSWR(
|
||||
workspaceSlug && projectId
|
||||
? PROJECT_MEMBERS_WITH_EMAIL(workspaceSlug.toString(), projectId.toString())
|
||||
: null,
|
||||
workspaceSlug && projectId ? PROJECT_MEMBERS_WITH_EMAIL(workspaceSlug.toString(), projectId.toString()) : null,
|
||||
workspaceSlug && projectId
|
||||
? () => projectService.projectMembersWithEmail(workspaceSlug as string, projectId as string)
|
||||
: null
|
||||
);
|
||||
|
||||
const { data: projectInvitations, mutate: mutateInvitations } = useSWR(
|
||||
workspaceSlug && projectId ? PROJECT_INVITATIONS_WITH_EMAIL(workspaceSlug.toString(), projectId.toString()) : null,
|
||||
workspaceSlug && projectId
|
||||
? PROJECT_INVITATIONS_WITH_EMAIL(workspaceSlug.toString(), projectId.toString())
|
||||
: null,
|
||||
workspaceSlug && projectId
|
||||
? () =>
|
||||
projectService.projectInvitationsWithEmail(workspaceSlug as string, projectId as string)
|
||||
? () => projectService.projectInvitationsWithEmail(workspaceSlug as string, projectId as string)
|
||||
: null
|
||||
);
|
||||
|
||||
@ -231,21 +225,12 @@ const MembersSettings: NextPage = () => {
|
||||
setSelectedRemoveMember(null);
|
||||
setSelectedInviteRemoveMember(null);
|
||||
}}
|
||||
data={members.find(
|
||||
(item) => item.id === selectedRemoveMember || item.id === selectedInviteRemoveMember
|
||||
)}
|
||||
data={members.find((item) => item.id === selectedRemoveMember || item.id === selectedInviteRemoveMember)}
|
||||
handleDelete={async () => {
|
||||
if (!activeWorkspace || !projectDetails) return;
|
||||
if (selectedRemoveMember) {
|
||||
await projectService.deleteProjectMember(
|
||||
activeWorkspace.slug,
|
||||
projectDetails.id,
|
||||
selectedRemoveMember
|
||||
);
|
||||
mutateMembers(
|
||||
(prevData: any) => prevData?.filter((item: any) => item.id !== selectedRemoveMember),
|
||||
false
|
||||
);
|
||||
await projectService.deleteProjectMember(activeWorkspace.slug, projectDetails.id, selectedRemoveMember);
|
||||
mutateMembers((prevData: any) => prevData?.filter((item: any) => item.id !== selectedRemoveMember), false);
|
||||
}
|
||||
if (selectedInviteRemoveMember) {
|
||||
await projectService.deleteProjectInvitation(
|
||||
@ -254,8 +239,7 @@ const MembersSettings: NextPage = () => {
|
||||
selectedInviteRemoveMember
|
||||
);
|
||||
mutateInvitations(
|
||||
(prevData: any) =>
|
||||
prevData?.filter((item: any) => item.id !== selectedInviteRemoveMember),
|
||||
(prevData: any) => prevData?.filter((item: any) => item.id !== selectedInviteRemoveMember),
|
||||
false
|
||||
);
|
||||
}
|
||||
@ -348,10 +332,7 @@ const MembersSettings: NextPage = () => {
|
||||
<div className="divide-y divide-custom-border-200">
|
||||
{members.length > 0
|
||||
? members.map((member) => (
|
||||
<div
|
||||
key={member.id}
|
||||
className="flex items-center justify-between px-3.5 py-[18px]"
|
||||
>
|
||||
<div key={member.id} className="flex items-center justify-between px-3.5 py-[18px]">
|
||||
<div className="flex items-center gap-x-6 gap-y-2">
|
||||
{member.avatar && member.avatar !== "" ? (
|
||||
<div className="relative flex h-10 w-10 items-center justify-center rounded-lg p-4 capitalize text-white">
|
||||
@ -377,19 +358,13 @@ const MembersSettings: NextPage = () => {
|
||||
<span>
|
||||
{member.first_name} {member.last_name}
|
||||
</span>
|
||||
<span className="text-custom-text-300 text-sm ml-2">
|
||||
({member.display_name})
|
||||
</span>
|
||||
<span className="text-custom-text-300 text-sm ml-2">({member.display_name})</span>
|
||||
</a>
|
||||
</Link>
|
||||
) : (
|
||||
<h4 className="text-sm">{member.display_name || member.email}</h4>
|
||||
)}
|
||||
{isOwner && (
|
||||
<p className="mt-0.5 text-xs text-custom-sidebar-text-300">
|
||||
{member.email}
|
||||
</p>
|
||||
)}
|
||||
{isOwner && <p className="mt-0.5 text-xs text-custom-sidebar-text-300">{member.email}</p>}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-3 text-xs">
|
||||
@ -419,27 +394,19 @@ const MembersSettings: NextPage = () => {
|
||||
|
||||
mutateMembers(
|
||||
(prevData: any) =>
|
||||
prevData.map((m: any) =>
|
||||
m.id === member.id ? { ...m, role: value } : m
|
||||
),
|
||||
prevData.map((m: any) => (m.id === member.id ? { ...m, role: value } : m)),
|
||||
false
|
||||
);
|
||||
|
||||
projectService
|
||||
.updateProjectMember(
|
||||
activeWorkspace.slug,
|
||||
projectDetails.id,
|
||||
member.id,
|
||||
{
|
||||
role: value,
|
||||
}
|
||||
)
|
||||
.updateProjectMember(activeWorkspace.slug, projectDetails.id, member.id, {
|
||||
role: value,
|
||||
})
|
||||
.catch(() => {
|
||||
setToastAlert({
|
||||
type: "error",
|
||||
title: "Error!",
|
||||
message:
|
||||
"An error occurred while updating member role. Please try again.",
|
||||
message: "An error occurred while updating member role. Please try again.",
|
||||
});
|
||||
});
|
||||
}}
|
||||
@ -447,18 +414,11 @@ const MembersSettings: NextPage = () => {
|
||||
disabled={
|
||||
member.memberId === user?.id ||
|
||||
!member.member ||
|
||||
(currentUser &&
|
||||
currentUser.role !== 20 &&
|
||||
currentUser.role < member.role)
|
||||
(currentUser && currentUser.role !== 20 && currentUser.role < member.role)
|
||||
}
|
||||
>
|
||||
{Object.keys(ROLE).map((key) => {
|
||||
if (
|
||||
currentUser &&
|
||||
currentUser.role !== 20 &&
|
||||
currentUser.role < parseInt(key)
|
||||
)
|
||||
return null;
|
||||
if (currentUser && currentUser.role !== 20 && currentUser.role < parseInt(key)) return null;
|
||||
|
||||
return (
|
||||
<CustomSelect.Option key={key} value={key}>
|
||||
@ -477,10 +437,7 @@ const MembersSettings: NextPage = () => {
|
||||
<span className="flex items-center justify-start gap-2">
|
||||
<XMarkIcon className="h-4 w-4" />
|
||||
|
||||
<span>
|
||||
{" "}
|
||||
{member.memberId !== user?.id ? "Remove member" : "Leave project"}
|
||||
</span>
|
||||
<span> {member.memberId !== user?.id ? "Remove member" : "Leave project"}</span>
|
||||
</span>
|
||||
</CustomMenu.MenuItem>
|
||||
</CustomMenu>
|
||||
|
@ -10,7 +10,7 @@ import stateService from "services/project_state.service";
|
||||
import useProjectDetails from "hooks/use-project-details";
|
||||
import useUserAuth from "hooks/use-user-auth";
|
||||
// layouts
|
||||
import { ProjectAuthorizationWrapper } from "layouts/auth-layout";
|
||||
import { ProjectAuthorizationWrapper } from "layouts/auth-layout-legacy";
|
||||
// components
|
||||
import { CreateUpdateStateInline, DeleteStateModal, SingleState, StateGroup } from "components/states";
|
||||
import { SettingsSidebar } from "components/project";
|
||||
|
@ -6,7 +6,7 @@ import useSWR from "swr";
|
||||
import projectService from "services/project.service";
|
||||
import viewsService from "services/views.service";
|
||||
// layouts
|
||||
import { ProjectAuthorizationWrapper } from "layouts/auth-layout";
|
||||
import { ProjectAuthorizationWrapper } from "layouts/auth-layout-legacy";
|
||||
// contexts
|
||||
import { IssueViewContextProvider } from "contexts/issue-view.context";
|
||||
// components
|
||||
@ -30,27 +30,18 @@ const SingleView: React.FC = () => {
|
||||
|
||||
const { data: activeProject } = useSWR(
|
||||
workspaceSlug && projectId ? PROJECT_DETAILS(projectId as string) : null,
|
||||
workspaceSlug && projectId
|
||||
? () => projectService.getProject(workspaceSlug as string, projectId as string)
|
||||
: null
|
||||
workspaceSlug && projectId ? () => projectService.getProject(workspaceSlug as string, projectId as string) : null
|
||||
);
|
||||
|
||||
const { data: views } = useSWR(
|
||||
workspaceSlug && projectId ? VIEWS_LIST(projectId as string) : null,
|
||||
workspaceSlug && projectId
|
||||
? () => viewsService.getViews(workspaceSlug as string, projectId as string)
|
||||
: null
|
||||
workspaceSlug && projectId ? () => viewsService.getViews(workspaceSlug as string, projectId as string) : null
|
||||
);
|
||||
|
||||
const { data: viewDetails, error } = useSWR(
|
||||
workspaceSlug && projectId && viewId ? VIEW_DETAILS(viewId as string) : null,
|
||||
workspaceSlug && projectId && viewId
|
||||
? () =>
|
||||
viewsService.getViewDetails(
|
||||
workspaceSlug as string,
|
||||
projectId as string,
|
||||
viewId as string
|
||||
)
|
||||
? () => viewsService.getViewDetails(workspaceSlug as string, projectId as string, viewId as string)
|
||||
: null
|
||||
);
|
||||
|
||||
|
@ -10,7 +10,7 @@ import useUserAuth from "hooks/use-user-auth";
|
||||
import viewsService from "services/views.service";
|
||||
import projectService from "services/project.service";
|
||||
// layouts
|
||||
import { ProjectAuthorizationWrapper } from "layouts/auth-layout";
|
||||
import { ProjectAuthorizationWrapper } from "layouts/auth-layout-legacy";
|
||||
// ui
|
||||
import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs";
|
||||
//icons
|
||||
@ -40,16 +40,12 @@ const ProjectViews: NextPage = () => {
|
||||
|
||||
const { data: activeProject } = useSWR(
|
||||
workspaceSlug && projectId ? PROJECT_DETAILS(projectId as string) : null,
|
||||
workspaceSlug && projectId
|
||||
? () => projectService.getProject(workspaceSlug as string, projectId as string)
|
||||
: null
|
||||
workspaceSlug && projectId ? () => projectService.getProject(workspaceSlug as string, projectId as string) : null
|
||||
);
|
||||
|
||||
const { data: views } = useSWR(
|
||||
workspaceSlug && projectId ? VIEWS_LIST(projectId as string) : null,
|
||||
workspaceSlug && projectId
|
||||
? () => viewsService.getViews(workspaceSlug as string, projectId as string)
|
||||
: null
|
||||
workspaceSlug && projectId ? () => viewsService.getViews(workspaceSlug as string, projectId as string) : null
|
||||
);
|
||||
|
||||
const handleEditView = (view: IView) => {
|
||||
|
@ -9,7 +9,7 @@ import useProjects from "hooks/use-projects";
|
||||
import useWorkspaces from "hooks/use-workspaces";
|
||||
import useUserAuth from "hooks/use-user-auth";
|
||||
// layouts
|
||||
import { WorkspaceAuthorizationLayout } from "layouts/auth-layout";
|
||||
import { WorkspaceAuthorizationLayout } from "layouts/auth-layout-legacy";
|
||||
// ui
|
||||
import { Icon, PrimaryButton } from "components/ui";
|
||||
import { Breadcrumbs, BreadcrumbItem } from "components/breadcrumbs";
|
||||
|
@ -7,7 +7,7 @@ import useSWR from "swr";
|
||||
// services
|
||||
import workspaceService from "services/workspace.service";
|
||||
// layouts
|
||||
import { WorkspaceAuthorizationLayout } from "layouts/auth-layout";
|
||||
import { WorkspaceAuthorizationLayout } from "layouts/auth-layout-legacy";
|
||||
// component
|
||||
import { SettingsSidebar } from "components/project";
|
||||
// ui
|
||||
@ -25,9 +25,8 @@ const BillingSettings: NextPage = () => {
|
||||
query: { workspaceSlug },
|
||||
} = useRouter();
|
||||
|
||||
const { data: activeWorkspace } = useSWR(
|
||||
workspaceSlug ? WORKSPACE_DETAILS(workspaceSlug as string) : null,
|
||||
() => (workspaceSlug ? workspaceService.getWorkspace(workspaceSlug as string) : null)
|
||||
const { data: activeWorkspace } = useSWR(workspaceSlug ? WORKSPACE_DETAILS(workspaceSlug as string) : null, () =>
|
||||
workspaceSlug ? workspaceService.getWorkspace(workspaceSlug as string) : null
|
||||
);
|
||||
|
||||
return (
|
||||
@ -56,9 +55,7 @@ const BillingSettings: NextPage = () => {
|
||||
<div className="px-4 py-6">
|
||||
<div>
|
||||
<h4 className="text-md mb-1 leading-6">Current plan</h4>
|
||||
<p className="mb-3 text-sm text-custom-text-200">
|
||||
You are currently using the free plan
|
||||
</p>
|
||||
<p className="mb-3 text-sm text-custom-text-200">You are currently using the free plan</p>
|
||||
<a href="https://plane.so/pricing" target="_blank" rel="noreferrer">
|
||||
<SecondaryButton outline>View Plans</SecondaryButton>
|
||||
</a>
|
||||
|
@ -5,7 +5,7 @@ import useSWR from "swr";
|
||||
// services
|
||||
import workspaceService from "services/workspace.service";
|
||||
// layouts
|
||||
import { WorkspaceAuthorizationLayout } from "layouts/auth-layout";
|
||||
import { WorkspaceAuthorizationLayout } from "layouts/auth-layout-legacy";
|
||||
// components
|
||||
import ExportGuide from "components/exporter/guide";
|
||||
import { SettingsSidebar } from "components/project";
|
||||
@ -22,9 +22,8 @@ const ImportExport: NextPage = () => {
|
||||
const router = useRouter();
|
||||
const { workspaceSlug } = router.query;
|
||||
|
||||
const { data: activeWorkspace } = useSWR(
|
||||
workspaceSlug ? WORKSPACE_DETAILS(workspaceSlug as string) : null,
|
||||
() => (workspaceSlug ? workspaceService.getWorkspace(workspaceSlug as string) : null)
|
||||
const { data: activeWorkspace } = useSWR(workspaceSlug ? WORKSPACE_DETAILS(workspaceSlug as string) : null, () =>
|
||||
workspaceSlug ? workspaceService.getWorkspace(workspaceSlug as string) : null
|
||||
);
|
||||
|
||||
return (
|
||||
|
@ -5,7 +5,7 @@ import useSWR from "swr";
|
||||
// services
|
||||
import workspaceService from "services/workspace.service";
|
||||
// layouts
|
||||
import { WorkspaceAuthorizationLayout } from "layouts/auth-layout";
|
||||
import { WorkspaceAuthorizationLayout } from "layouts/auth-layout-legacy";
|
||||
// components
|
||||
import IntegrationGuide from "components/integration/guide";
|
||||
import { SettingsSidebar } from "components/project";
|
||||
@ -22,9 +22,8 @@ const ImportExport: NextPage = () => {
|
||||
const router = useRouter();
|
||||
const { workspaceSlug } = router.query;
|
||||
|
||||
const { data: activeWorkspace } = useSWR(
|
||||
workspaceSlug ? WORKSPACE_DETAILS(workspaceSlug as string) : null,
|
||||
() => (workspaceSlug ? workspaceService.getWorkspace(workspaceSlug as string) : null)
|
||||
const { data: activeWorkspace } = useSWR(workspaceSlug ? WORKSPACE_DETAILS(workspaceSlug as string) : null, () =>
|
||||
workspaceSlug ? workspaceService.getWorkspace(workspaceSlug as string) : null
|
||||
);
|
||||
|
||||
return (
|
||||
|
@ -13,7 +13,7 @@ import fileService from "services/file.service";
|
||||
import useToast from "hooks/use-toast";
|
||||
import useUserAuth from "hooks/use-user-auth";
|
||||
// layouts
|
||||
import { WorkspaceAuthorizationLayout } from "layouts/auth-layout";
|
||||
import { WorkspaceAuthorizationLayout } from "layouts/auth-layout-legacy";
|
||||
// components
|
||||
import { ImageUploadModal } from "components/core";
|
||||
import { DeleteWorkspaceModal } from "components/workspace";
|
||||
@ -59,9 +59,8 @@ const WorkspaceSettings: NextPage = () => {
|
||||
|
||||
const { setToastAlert } = useToast();
|
||||
|
||||
const { data: activeWorkspace } = useSWR(
|
||||
workspaceSlug ? WORKSPACE_DETAILS(workspaceSlug as string) : null,
|
||||
() => (workspaceSlug ? workspaceService.getWorkspace(workspaceSlug as string) : null)
|
||||
const { data: activeWorkspace } = useSWR(workspaceSlug ? WORKSPACE_DETAILS(workspaceSlug as string) : null, () =>
|
||||
workspaceSlug ? workspaceService.getWorkspace(workspaceSlug as string) : null
|
||||
);
|
||||
|
||||
const {
|
||||
@ -156,9 +155,7 @@ const WorkspaceSettings: NextPage = () => {
|
||||
<WorkspaceAuthorizationLayout
|
||||
breadcrumbs={
|
||||
<Breadcrumbs>
|
||||
<BreadcrumbItem
|
||||
title={`${truncateText(activeWorkspace?.name ?? "Workspace", 32)} Settings`}
|
||||
/>
|
||||
<BreadcrumbItem title={`${truncateText(activeWorkspace?.name ?? "Workspace", 32)} Settings`} />
|
||||
</Breadcrumbs>
|
||||
}
|
||||
>
|
||||
@ -191,11 +188,7 @@ const WorkspaceSettings: NextPage = () => {
|
||||
<div className={`pr-9 py-8 w-full overflow-y-auto ${isAdmin ? "" : "opacity-60"}`}>
|
||||
<div className="flex gap-5 items-center pb-7 border-b border-custom-border-200">
|
||||
<div className="flex flex-col gap-1">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setIsImageUploadModalOpen(true)}
|
||||
disabled={!isAdmin}
|
||||
>
|
||||
<button type="button" onClick={() => setIsImageUploadModalOpen(true)} disabled={!isAdmin}>
|
||||
{watch("logo") && watch("logo") !== null && watch("logo") !== "" ? (
|
||||
<div className="relative mx-auto flex h-14 w-14">
|
||||
<img
|
||||
@ -214,8 +207,7 @@ const WorkspaceSettings: NextPage = () => {
|
||||
<div className="flex flex-col gap-1">
|
||||
<h3 className="text-lg font-semibold leading-6">{watch("name")}</h3>
|
||||
<span className="text-sm tracking-tight">{`${
|
||||
typeof window !== "undefined" &&
|
||||
window.location.origin.replace("http://", "").replace("https://", "")
|
||||
typeof window !== "undefined" && window.location.origin.replace("http://", "").replace("https://", "")
|
||||
}/${activeWorkspace.slug}`}</span>
|
||||
<div className="flex item-center gap-2.5">
|
||||
<button
|
||||
@ -267,9 +259,7 @@ const WorkspaceSettings: NextPage = () => {
|
||||
<CustomSelect
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
label={
|
||||
ORGANIZATION_SIZE.find((c) => c === value) ?? "Select organization size"
|
||||
}
|
||||
label={ORGANIZATION_SIZE.find((c) => c === value) ?? "Select organization size"}
|
||||
width="w-full"
|
||||
input
|
||||
disabled={!isAdmin}
|
||||
@ -303,11 +293,7 @@ const WorkspaceSettings: NextPage = () => {
|
||||
</div>
|
||||
|
||||
<div className="flex items-center justify-between py-2">
|
||||
<PrimaryButton
|
||||
onClick={handleSubmit(onSubmit)}
|
||||
loading={isSubmitting}
|
||||
disabled={!isAdmin}
|
||||
>
|
||||
<PrimaryButton onClick={handleSubmit(onSubmit)} loading={isSubmitting} disabled={!isAdmin}>
|
||||
{isSubmitting ? "Updating..." : "Update Workspace"}
|
||||
</PrimaryButton>
|
||||
</div>
|
||||
@ -337,17 +323,12 @@ const WorkspaceSettings: NextPage = () => {
|
||||
<Disclosure.Panel>
|
||||
<div className="flex flex-col gap-8">
|
||||
<span className="text-sm tracking-tight">
|
||||
The danger zone of the project delete page is a critical area that
|
||||
requires careful consideration and attention. When deleting a project, all
|
||||
of the data and resources within that project will be permanently removed
|
||||
and cannot be recovered.
|
||||
The danger zone of the project delete page is a critical area that requires careful
|
||||
consideration and attention. When deleting a project, all of the data and resources within
|
||||
that project will be permanently removed and cannot be recovered.
|
||||
</span>
|
||||
<div>
|
||||
<DangerButton
|
||||
onClick={() => setIsOpen(true)}
|
||||
className="!text-sm"
|
||||
outline
|
||||
>
|
||||
<DangerButton onClick={() => setIsOpen(true)} className="!text-sm" outline>
|
||||
Delete my project
|
||||
</DangerButton>
|
||||
</div>
|
||||
|
@ -8,7 +8,7 @@ import useSWR from "swr";
|
||||
import workspaceService from "services/workspace.service";
|
||||
import IntegrationService from "services/integration.service";
|
||||
// layouts
|
||||
import { WorkspaceAuthorizationLayout } from "layouts/auth-layout";
|
||||
import { WorkspaceAuthorizationLayout } from "layouts/auth-layout-legacy";
|
||||
// components
|
||||
import { SingleIntegrationCard } from "components/integration";
|
||||
import { SettingsSidebar } from "components/project";
|
||||
|
@ -12,7 +12,7 @@ import useToast from "hooks/use-toast";
|
||||
import useUser from "hooks/use-user";
|
||||
import useWorkspaceMembers from "hooks/use-workspace-members";
|
||||
// layouts
|
||||
import { WorkspaceAuthorizationLayout } from "layouts/auth-layout";
|
||||
import { WorkspaceAuthorizationLayout } from "layouts/auth-layout-legacy";
|
||||
// components
|
||||
import ConfirmWorkspaceMemberRemove from "components/workspace/confirm-workspace-member-remove";
|
||||
import SendWorkspaceInvitationModal from "components/workspace/send-workspace-invitation-modal";
|
||||
@ -25,11 +25,7 @@ import { XMarkIcon } from "components/icons";
|
||||
// types
|
||||
import type { NextPage } from "next";
|
||||
// fetch-keys
|
||||
import {
|
||||
WORKSPACE_DETAILS,
|
||||
WORKSPACE_INVITATION_WITH_EMAIL,
|
||||
WORKSPACE_MEMBERS_WITH_EMAIL,
|
||||
} from "constants/fetch-keys";
|
||||
import { WORKSPACE_DETAILS, WORKSPACE_INVITATION_WITH_EMAIL, WORKSPACE_MEMBERS_WITH_EMAIL } from "constants/fetch-keys";
|
||||
// constants
|
||||
import { ROLE } from "constants/workspace";
|
||||
// helper
|
||||
@ -49,23 +45,18 @@ const MembersSettings: NextPage = () => {
|
||||
|
||||
const { isOwner } = useWorkspaceMembers(workspaceSlug?.toString(), Boolean(workspaceSlug));
|
||||
|
||||
const { data: activeWorkspace } = useSWR(
|
||||
workspaceSlug ? WORKSPACE_DETAILS(workspaceSlug.toString()) : null,
|
||||
() => (workspaceSlug ? workspaceService.getWorkspace(workspaceSlug.toString()) : null)
|
||||
const { data: activeWorkspace } = useSWR(workspaceSlug ? WORKSPACE_DETAILS(workspaceSlug.toString()) : null, () =>
|
||||
workspaceSlug ? workspaceService.getWorkspace(workspaceSlug.toString()) : null
|
||||
);
|
||||
|
||||
const { data: workspaceMembers, mutate: mutateMembers } = useSWR(
|
||||
workspaceSlug ? WORKSPACE_MEMBERS_WITH_EMAIL(workspaceSlug.toString()) : null,
|
||||
workspaceSlug
|
||||
? () => workspaceService.workspaceMembersWithEmail(workspaceSlug.toString())
|
||||
: null
|
||||
workspaceSlug ? () => workspaceService.workspaceMembersWithEmail(workspaceSlug.toString()) : null
|
||||
);
|
||||
|
||||
const { data: workspaceInvitations, mutate: mutateInvitations } = useSWR(
|
||||
workspaceSlug ? WORKSPACE_INVITATION_WITH_EMAIL(workspaceSlug.toString()) : null,
|
||||
workspaceSlug
|
||||
? () => workspaceService.workspaceInvitationsWithEmail(workspaceSlug.toString())
|
||||
: null
|
||||
workspaceSlug ? () => workspaceService.workspaceInvitationsWithEmail(workspaceSlug.toString()) : null
|
||||
);
|
||||
|
||||
const members = [
|
||||
@ -143,15 +134,12 @@ const MembersSettings: NextPage = () => {
|
||||
});
|
||||
})
|
||||
.finally(() => {
|
||||
mutateMembers((prevData: any) =>
|
||||
prevData?.filter((item: any) => item.id !== selectedRemoveMember)
|
||||
);
|
||||
mutateMembers((prevData: any) => prevData?.filter((item: any) => item.id !== selectedRemoveMember));
|
||||
});
|
||||
}
|
||||
if (selectedInviteRemoveMember) {
|
||||
mutateInvitations(
|
||||
(prevData: any) =>
|
||||
prevData?.filter((item: any) => item.id !== selectedInviteRemoveMember),
|
||||
(prevData: any) => prevData?.filter((item: any) => item.id !== selectedInviteRemoveMember),
|
||||
false
|
||||
);
|
||||
workspaceService
|
||||
@ -206,10 +194,7 @@ const MembersSettings: NextPage = () => {
|
||||
<div className="divide-y divide-custom-border-200">
|
||||
{members.length > 0
|
||||
? members.map((member) => (
|
||||
<div
|
||||
key={member.id}
|
||||
className="group flex items-center justify-between px-3.5 py-[18px]"
|
||||
>
|
||||
<div key={member.id} className="group flex items-center justify-between px-3.5 py-[18px]">
|
||||
<div className="flex items-center gap-x-8 gap-y-2">
|
||||
{member.avatar && member.avatar !== "" ? (
|
||||
<Link href={`/${workspaceSlug}/profile/${member.memberId}`}>
|
||||
@ -239,21 +224,13 @@ const MembersSettings: NextPage = () => {
|
||||
<span>
|
||||
{member.first_name} {member.last_name}
|
||||
</span>
|
||||
<span className="text-custom-text-300 text-sm ml-2">
|
||||
({member.display_name})
|
||||
</span>
|
||||
<span className="text-custom-text-300 text-sm ml-2">({member.display_name})</span>
|
||||
</a>
|
||||
</Link>
|
||||
) : (
|
||||
<h4 className="text-sm cursor-default">
|
||||
{member.display_name || member.email}
|
||||
</h4>
|
||||
)}
|
||||
{isOwner && (
|
||||
<p className="mt-0.5 text-xs text-custom-sidebar-text-300">
|
||||
{member.email}
|
||||
</p>
|
||||
<h4 className="text-sm cursor-default">{member.display_name || member.email}</h4>
|
||||
)}
|
||||
{isOwner && <p className="mt-0.5 text-xs text-custom-sidebar-text-300">{member.email}</p>}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-3 text-xs">
|
||||
@ -288,9 +265,7 @@ const MembersSettings: NextPage = () => {
|
||||
|
||||
mutateMembers(
|
||||
(prevData: any) =>
|
||||
prevData?.map((m: any) =>
|
||||
m.id === member.id ? { ...m, role: value } : m
|
||||
),
|
||||
prevData?.map((m: any) => (m.id === member.id ? { ...m, role: value } : m)),
|
||||
false
|
||||
);
|
||||
|
||||
@ -302,8 +277,7 @@ const MembersSettings: NextPage = () => {
|
||||
setToastAlert({
|
||||
type: "error",
|
||||
title: "Error!",
|
||||
message:
|
||||
"An error occurred while updating member role. Please try again.",
|
||||
message: "An error occurred while updating member role. Please try again.",
|
||||
});
|
||||
});
|
||||
}}
|
||||
@ -311,18 +285,11 @@ const MembersSettings: NextPage = () => {
|
||||
disabled={
|
||||
member.memberId === currentUser?.member.id ||
|
||||
!member.status ||
|
||||
(currentUser &&
|
||||
currentUser.role !== 20 &&
|
||||
currentUser.role < member.role)
|
||||
(currentUser && currentUser.role !== 20 && currentUser.role < member.role)
|
||||
}
|
||||
>
|
||||
{Object.keys(ROLE).map((key) => {
|
||||
if (
|
||||
currentUser &&
|
||||
currentUser.role !== 20 &&
|
||||
currentUser.role < parseInt(key)
|
||||
)
|
||||
return null;
|
||||
if (currentUser && currentUser.role !== 20 && currentUser.role < parseInt(key)) return null;
|
||||
|
||||
return (
|
||||
<CustomSelect.Option key={key} value={key}>
|
||||
@ -344,10 +311,7 @@ const MembersSettings: NextPage = () => {
|
||||
<span className="flex items-center justify-start gap-2">
|
||||
<XMarkIcon className="h-4 w-4" />
|
||||
|
||||
<span>
|
||||
{" "}
|
||||
{user?.id === member.memberId ? "Leave" : "Remove member"}
|
||||
</span>
|
||||
<span> {user?.id === member.memberId ? "Leave" : "Remove member"}</span>
|
||||
</span>
|
||||
</CustomMenu.MenuItem>
|
||||
</CustomMenu>
|
||||
|
@ -2,7 +2,7 @@ import React from "react";
|
||||
|
||||
// layouts
|
||||
import DefaultLayout from "layouts/default-layout";
|
||||
import { UserAuthorizationLayout } from "layouts/auth-layout/user-authorization-wrapper";
|
||||
import { UserAuthorizationLayout } from "layouts/auth-layout-legacy/user-authorization-wrapper";
|
||||
// components
|
||||
import { CalendarView } from "components/issues";
|
||||
// types
|
||||
|
@ -13,7 +13,7 @@ import userService from "services/user.service";
|
||||
import useUser from "hooks/use-user";
|
||||
// layouts
|
||||
import DefaultLayout from "layouts/default-layout";
|
||||
import { UserAuthorizationLayout } from "layouts/auth-layout/user-authorization-wrapper";
|
||||
import { UserAuthorizationLayout } from "layouts/auth-layout-legacy/user-authorization-wrapper";
|
||||
// components
|
||||
import { CreateWorkspaceForm } from "components/workspace";
|
||||
// images
|
||||
@ -59,9 +59,7 @@ const CreateWorkspace: NextPage = () => {
|
||||
false
|
||||
);
|
||||
|
||||
await userService
|
||||
.updateUser({ last_workspace_id: workspace.id })
|
||||
.then(() => router.push(`/${workspace.slug}`));
|
||||
await userService.updateUser({ last_workspace_id: workspace.id }).then(() => router.push(`/${workspace.slug}`));
|
||||
};
|
||||
|
||||
return (
|
||||
|
@ -15,7 +15,7 @@ import useUser from "hooks/use-user";
|
||||
import useToast from "hooks/use-toast";
|
||||
// layouts
|
||||
import DefaultLayout from "layouts/default-layout";
|
||||
import { UserAuthorizationLayout } from "layouts/auth-layout/user-authorization-wrapper";
|
||||
import { UserAuthorizationLayout } from "layouts/auth-layout-legacy/user-authorization-wrapper";
|
||||
// ui
|
||||
import { SecondaryButton, PrimaryButton, EmptyState } from "components/ui";
|
||||
// icons
|
||||
@ -51,16 +51,11 @@ const OnBoard: NextPage = () => {
|
||||
workspaceService.userWorkspaceInvitations()
|
||||
);
|
||||
|
||||
const handleInvitation = (
|
||||
workspace_invitation: IWorkspaceMemberInvitation,
|
||||
action: "accepted" | "withdraw"
|
||||
) => {
|
||||
const handleInvitation = (workspace_invitation: IWorkspaceMemberInvitation, action: "accepted" | "withdraw") => {
|
||||
if (action === "accepted") {
|
||||
setInvitationsRespond((prevData) => [...prevData, workspace_invitation.id]);
|
||||
} else if (action === "withdraw") {
|
||||
setInvitationsRespond((prevData) =>
|
||||
prevData.filter((item: string) => item !== workspace_invitation.id)
|
||||
);
|
||||
setInvitationsRespond((prevData) => prevData.filter((item: string) => item !== workspace_invitation.id));
|
||||
}
|
||||
};
|
||||
|
||||
@ -144,9 +139,7 @@ const OnBoard: NextPage = () => {
|
||||
? "border-custom-primary-100"
|
||||
: "border-custom-border-200 hover:bg-custom-background-80"
|
||||
}`}
|
||||
onClick={() =>
|
||||
handleInvitation(invitation, isSelected ? "withdraw" : "accepted")
|
||||
}
|
||||
onClick={() => handleInvitation(invitation, isSelected ? "withdraw" : "accepted")}
|
||||
>
|
||||
<div className="flex-shrink-0">
|
||||
<div className="grid place-items-center h-9 w-9 rounded">
|
||||
@ -166,9 +159,7 @@ const OnBoard: NextPage = () => {
|
||||
</div>
|
||||
</div>
|
||||
<div className="min-w-0 flex-1">
|
||||
<div className="text-sm font-medium">
|
||||
{truncateText(invitation.workspace.name, 30)}
|
||||
</div>
|
||||
<div className="text-sm font-medium">{truncateText(invitation.workspace.name, 30)}</div>
|
||||
<p className="text-xs text-custom-text-200">{ROLE[invitation.role]}</p>
|
||||
</div>
|
||||
<span
|
||||
|
@ -2,8 +2,6 @@
|
||||
import { action, observable, makeObservable } from "mobx";
|
||||
// helper
|
||||
import { applyTheme, unsetCustomCssVariables } from "helpers/theme.helper";
|
||||
// interfaces
|
||||
import { ICurrentUserSettings } from "types";
|
||||
|
||||
class ThemeStore {
|
||||
sidebarCollapsed: boolean | null = null;
|
||||
@ -14,8 +12,8 @@ class ThemeStore {
|
||||
constructor(_rootStore: any | null = null) {
|
||||
makeObservable(this, {
|
||||
// observable
|
||||
sidebarCollapsed: observable,
|
||||
theme: observable,
|
||||
sidebarCollapsed: observable.ref,
|
||||
theme: observable.ref,
|
||||
// action
|
||||
setSidebarCollapsed: action,
|
||||
setTheme: action,
|
||||
|
Loading…
Reference in New Issue
Block a user