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