diff --git a/web/components/cycles/cycle-mobile-header.tsx b/web/components/cycles/cycle-mobile-header.tsx index add78943c..9fbc96df3 100644 --- a/web/components/cycles/cycle-mobile-header.tsx +++ b/web/components/cycles/cycle-mobile-header.tsx @@ -109,7 +109,7 @@ export const CycleMobileHeader = () => { onClose={() => setAnalyticsModal(false)} cycleDetails={cycleDetails ?? undefined} /> -
+
{ + const { currentProjectDetails } = useProject(); + // hooks + const { updateDisplayFilters } = useCycleFilter(); + return ( +
+ + + Layout + + } + customButtonClassName="flex flex-grow justify-center items-center text-custom-text-200 text-sm" + closeOnSelect + > + {CYCLE_VIEW_LAYOUTS.map((layout) => { + if (layout.key == "gantt") return; + return ( + { + updateDisplayFilters(currentProjectDetails!.id, { + layout: layout.key, + }); + }} + className="flex items-center gap-2" + > + +
{layout.title}
+
+ ); + })} +
+
+ ); +}); + +export default CyclesListMobileHeader; diff --git a/web/components/headers/cycle-issues.tsx b/web/components/headers/cycle-issues.tsx index 8c5018ffb..a9dc3a8f4 100644 --- a/web/components/headers/cycle-issues.tsx +++ b/web/components/headers/cycle-issues.tsx @@ -9,8 +9,6 @@ import { ArrowRight, Plus, PanelRight } from "lucide-react"; import { Breadcrumbs, Button, ContrastIcon, CustomMenu, Tooltip } from "@plane/ui"; import { ProjectAnalyticsModal } from "components/analytics"; import { BreadcrumbLink } from "components/common"; -import { SidebarHamburgerToggle } from "components/core/sidebar/sidebar-menu-hamburger-toggle"; -import { CycleMobileHeader } from "components/cycles/cycle-mobile-header"; import { DisplayFiltersSelection, FiltersDropdown, FilterSelection, LayoutSelection } from "components/issues"; import { EIssueFilterType, EIssuesStoreType, ISSUE_DISPLAY_FILTERS_BY_LAYOUT } from "constants/issue"; import { EUserProjectRoles } from "constants/project"; @@ -159,9 +157,8 @@ export const CycleIssuesHeader: React.FC = observer(() => { cycleDetails={cycleDetails ?? undefined} />
-
+
- { {issueCount && issueCount > 0 ? ( 1 ? "issues" : "issue" - } in this cycle`} + tooltipContent={`There are ${issueCount} ${issueCount > 1 ? "issues" : "issue" + } in this cycle`} position="bottom" > @@ -299,9 +295,6 @@ export const CycleIssuesHeader: React.FC = observer(() => {
-
- -
); diff --git a/web/components/headers/cycles.tsx b/web/components/headers/cycles.tsx index 6f019f3bd..375a04a13 100644 --- a/web/components/headers/cycles.tsx +++ b/web/components/headers/cycles.tsx @@ -1,19 +1,15 @@ -import { FC, useCallback } from "react"; +import { FC } from "react"; import { observer } from "mobx-react-lite"; import { useRouter } from "next/router"; -import { List, Plus } from "lucide-react"; +import { Plus } from "lucide-react"; // hooks // ui -import { Breadcrumbs, Button, ContrastIcon, CustomMenu } from "@plane/ui"; +import { Breadcrumbs, Button, ContrastIcon } from "@plane/ui"; // helpers // components import { BreadcrumbLink } from "components/common"; -import { SidebarHamburgerToggle } from "components/core/sidebar/sidebar-menu-hamburger-toggle"; -import { CYCLE_VIEW_LAYOUTS } from "constants/cycle"; import { EUserProjectRoles } from "constants/project"; import { useApplication, useEventTracker, useProject, useUser } from "hooks/store"; -import useLocalStorage from "hooks/use-local-storage"; -import { TCycleLayoutOptions } from "@plane/types"; import { ProjectLogo } from "components/project"; export const CyclesHeader: FC = observer(() => { @@ -33,20 +29,11 @@ export const CyclesHeader: FC = observer(() => { const canUserCreateCycle = currentProjectRole && [EUserProjectRoles.ADMIN, EUserProjectRoles.MEMBER].includes(currentProjectRole); - const { setValue: setCycleLayout } = useLocalStorage("cycle_layout", "list"); - - const handleCurrentLayout = useCallback( - (_layout: TCycleLayoutOptions) => { - setCycleLayout(_layout); - }, - [setCycleLayout] - ); return (
-
+
-
{
)}
-
- - - Layout - - } - customButtonClassName="flex flex-grow justify-center items-center text-custom-text-200 text-sm" - closeOnSelect - > - {CYCLE_VIEW_LAYOUTS.map((layout) => ( - { - // handleLayoutChange(ISSUE_LAYOUTS[index].key); - handleCurrentLayout(layout.key as TCycleLayoutOptions); - }} - className="flex items-center gap-2" - > - -
{layout.title}
-
- ))} -
-
); }); diff --git a/web/components/headers/global-issues.tsx b/web/components/headers/global-issues.tsx index 13dccba41..cf44e389e 100644 --- a/web/components/headers/global-issues.tsx +++ b/web/components/headers/global-issues.tsx @@ -7,7 +7,6 @@ import { usePlatformOS } from "hooks/use-platform-os"; import { List, PlusIcon, Sheet } from "lucide-react"; import { Breadcrumbs, Button, LayersIcon, PhotoFilterIcon, Tooltip } from "@plane/ui"; import { BreadcrumbLink } from "components/common"; -import { SidebarHamburgerToggle } from "components/core/sidebar/sidebar-menu-hamburger-toggle"; import { DisplayFiltersSelection, FiltersDropdown, FilterSelection } from "components/issues"; // components import { CreateUpdateWorkspaceViewModal } from "components/workspace"; @@ -109,9 +108,8 @@ export const GlobalIssuesHeader: React.FC = observer((props) => { return ( <> setCreateViewModal(false)} /> -
+
- = observer((props) => {
{ moduleDetails={moduleDetails ?? undefined} />
-
+
- {

{moduleDetails?.name && moduleDetails.name}

{issueCount && issueCount > 0 ? ( 1 ? "issues" : "issue" - } in this module`} + isMobile={isMobile} + tooltipContent={`There are ${issueCount} ${issueCount > 1 ? "issues" : "issue" + } in this module`} position="bottom" > @@ -309,7 +305,6 @@ export const ModuleIssuesHeader: React.FC = observer(() => {
-
); diff --git a/web/components/headers/modules-list.tsx b/web/components/headers/modules-list.tsx index fcd26dd59..a6147cad3 100644 --- a/web/components/headers/modules-list.tsx +++ b/web/components/headers/modules-list.tsx @@ -1,13 +1,12 @@ import { useCallback, useRef, useState } from "react"; import { observer } from "mobx-react-lite"; import { useRouter } from "next/router"; -import { GanttChartSquare, LayoutGrid, List, ListFilter, Plus, Search, X } from "lucide-react"; +import { ListFilter, Plus, Search, X } from "lucide-react"; // hooks import { useApplication, useEventTracker, useMember, useModuleFilter, useProject, useUser } from "hooks/store"; import useOutsideClickDetector from "hooks/use-outside-click-detector"; // components import { BreadcrumbLink } from "components/common"; -import { SidebarHamburgerToggle } from "components/core/sidebar/sidebar-menu-hamburger-toggle"; import { ProjectLogo } from "components/project"; // constants import { MODULE_VIEW_LAYOUTS } from "constants/module"; @@ -17,7 +16,7 @@ import { usePlatformOS } from "hooks/use-platform-os"; import { ModuleFiltersSelection, ModuleOrderByDropdown } from "components/modules"; import { FiltersDropdown } from "components/issues"; // ui -import { Breadcrumbs, Button, Tooltip, DiceIcon, CustomMenu } from "@plane/ui"; +import { Breadcrumbs, Button, Tooltip, DiceIcon } from "@plane/ui"; // helpers import { cn } from "helpers/common.helper"; // types @@ -89,176 +88,138 @@ export const ModulesListHeader: React.FC = observer(() => { currentProjectRole && [EUserProjectRoles.ADMIN, EUserProjectRoles.MEMBER].includes(currentProjectRole); return ( -
-
-
- -
- - - - - ) - } - /> - } - /> - } />} - /> - -
-
-
-
- {!isSearchOpen && ( - - )} -
- - updateSearchQuery(e.target.value)} - onKeyDown={handleInputKeyDown} - /> - {isSearchOpen && ( - - )} -
-
-
- {MODULE_VIEW_LAYOUTS.map((layout) => ( - - - - ))} -
- { - if (!projectId || val === displayFilters?.order_by) return; - updateDisplayFilters(projectId.toString(), { - order_by: val, - }); - }} - /> - } title="Filters" placement="bottom-end"> - { - if (!projectId) return; - updateDisplayFilters(projectId.toString(), val); - }} - handleFiltersUpdate={handleFilters} - memberIds={workspaceMemberIds ?? undefined} +
+
+
+ + + + + ) + } + /> + } /> - - {canUserCreateModule && ( - - )} + } />} + /> +
-
- - {displayFilters?.layout === "gantt" ? ( - - ) : displayFilters?.layout === "board" ? ( - - ) : ( - - )} - Layout - - } - customButtonClassName="flex flex-grow justify-center items-center text-custom-text-200 text-sm" - closeOnSelect - > - {MODULE_VIEW_LAYOUTS.map((layout) => ( - +
+ {!isSearchOpen && ( + + )} +
+ + updateSearchQuery(e.target.value)} + onKeyDown={handleInputKeyDown} + /> + {isSearchOpen && ( + + )} +
+
+
+ {MODULE_VIEW_LAYOUTS.map((layout) => ( + + + ))} - +
+ { + if (!projectId || val === displayFilters?.order_by) return; + updateDisplayFilters(projectId.toString(), { + order_by: val, + }); + }} + /> + } title="Filters" placement="bottom-end"> + { + if (!projectId) return; + updateDisplayFilters(projectId.toString(), val); + }} + handleFiltersUpdate={handleFilters} + memberIds={workspaceMemberIds ?? undefined} + /> + + {canUserCreateModule && ( + + )}
); diff --git a/web/components/headers/page-details.tsx b/web/components/headers/page-details.tsx index 2c05d95fa..4404fc0f3 100644 --- a/web/components/headers/page-details.tsx +++ b/web/components/headers/page-details.tsx @@ -7,7 +7,6 @@ import { FileText, Plus } from "lucide-react"; import { Breadcrumbs, Button } from "@plane/ui"; // helpers import { BreadcrumbLink } from "components/common"; -import { SidebarHamburgerToggle } from "components/core/sidebar/sidebar-menu-hamburger-toggle"; // components import { useApplication, usePage, useProject } from "hooks/store"; import { ProjectLogo } from "components/project"; @@ -28,9 +27,8 @@ export const PageDetailsHeader: FC = observer((props) => { const pageDetails = usePage(pageId as string); return ( -
+
-
{ currentProjectRole && [EUserProjectRoles.ADMIN, EUserProjectRoles.MEMBER].includes(currentProjectRole); return ( -
+
-
{ ); return ( -
+
-
{ : undefined; return ( -
+
- -
- -
- + { : undefined; return ( -
+
-
{ const { currentProjectDetails } = useProject(); return ( -
+
-
{ const isSidebarCollapsed = themeStore.issueDetailSidebarCollapsed; return ( -
+
-
{ projectDetails={currentProjectDetails ?? undefined} />
-
+
-
router.back()}> { )}
-
- -
); diff --git a/web/components/headers/project-settings.tsx b/web/components/headers/project-settings.tsx index 817d842b4..831965fad 100644 --- a/web/components/headers/project-settings.tsx +++ b/web/components/headers/project-settings.tsx @@ -5,7 +5,6 @@ import { useRouter } from "next/router"; import { Breadcrumbs, CustomMenu } from "@plane/ui"; // helper import { BreadcrumbLink } from "components/common"; -import { SidebarHamburgerToggle } from "components/core/sidebar/sidebar-menu-hamburger-toggle"; import { EUserProjectRoles, PROJECT_SETTINGS_LINKS } from "constants/project"; // hooks import { useProject, useUser } from "hooks/store"; @@ -31,8 +30,7 @@ export const ProjectSettingHeader: FC = observer((props) if (currentProjectRole && currentProjectRole <= EUserProjectRoles.VIEWER) return null; return ( -
- +
diff --git a/web/components/headers/project-view-issues.tsx b/web/components/headers/project-view-issues.tsx index ab3959716..c59258463 100644 --- a/web/components/headers/project-view-issues.tsx +++ b/web/components/headers/project-view-issues.tsx @@ -8,7 +8,6 @@ import { Plus } from "lucide-react"; // ui import { Breadcrumbs, Button, CustomMenu, PhotoFilterIcon } from "@plane/ui"; import { BreadcrumbLink } from "components/common"; -import { SidebarHamburgerToggle } from "components/core/sidebar/sidebar-menu-hamburger-toggle"; import { DisplayFiltersSelection, FiltersDropdown, FilterSelection, LayoutSelection } from "components/issues"; // helpers // types @@ -128,9 +127,8 @@ export const ProjectViewIssuesHeader: React.FC = observer(() => { currentProjectRole && [EUserProjectRoles.ADMIN, EUserProjectRoles.MEMBER].includes(currentProjectRole); return ( -
+
- { return ( <> -
+
-
{ }; return ( -
+
-
= observer((props) => { const { theme: themStore } = useApplication(); return ( -
+
-
( -
+
-
{ return ( <>
-
{ return ( <> -
+
-
= observer((pro return (
-
{ +export const IssuesMobileHeader = observer(() => { const layouts = [ { key: "list", title: "List", icon: List }, { key: "kanban", title: "Kanban", icon: Kanban }, @@ -87,7 +88,7 @@ export const IssuesMobileHeader = () => { onClose={() => setAnalyticsModal(false)} projectDetails={currentProjectDetails ?? undefined} /> -
+
{
); -}; +}); diff --git a/web/components/modules/moduels-list-mobile-header.tsx b/web/components/modules/moduels-list-mobile-header.tsx new file mode 100644 index 000000000..90919a998 --- /dev/null +++ b/web/components/modules/moduels-list-mobile-header.tsx @@ -0,0 +1,40 @@ +import { CustomMenu } from "@plane/ui"; +import { MODULE_VIEW_LAYOUTS } from "constants/module"; +import { useModuleFilter, useProject } from "hooks/store"; +import { observer } from "mobx-react"; + +const ModulesListMobileHeader = observer(() => { + const { currentProjectDetails } = useProject(); + const { updateDisplayFilters } = useModuleFilter(); + + return ( +
+ Layout} + customButtonClassName="flex flex-grow justify-center items-center text-custom-text-200 text-sm" + closeOnSelect + > + {MODULE_VIEW_LAYOUTS.map((layout) => { + if (layout.key == "gantt") return; + return ( + { + updateDisplayFilters(currentProjectDetails!.id.toString(), { layout: layout.key }); + }} + className="flex items-center gap-2" + > + +
{layout.title}
+
+ ); + })} +
+
+ ); +}); + +export default ModulesListMobileHeader; diff --git a/web/components/modules/module-mobile-header.tsx b/web/components/modules/module-mobile-header.tsx index 4763639ed..ead9eb6c5 100644 --- a/web/components/modules/module-mobile-header.tsx +++ b/web/components/modules/module-mobile-header.tsx @@ -1,14 +1,21 @@ import { useCallback, useState } from "react"; +import { observer } from "mobx-react"; import router from "next/router"; +// icons import { Calendar, ChevronDown, Kanban, List } from "lucide-react"; +// ui import { CustomMenu } from "@plane/ui"; +// components import { ProjectAnalyticsModal } from "components/analytics"; import { DisplayFiltersSelection, FilterSelection, FiltersDropdown } from "components/issues"; -import { EIssueFilterType, EIssuesStoreType, ISSUE_DISPLAY_FILTERS_BY_LAYOUT, ISSUE_LAYOUTS } from "constants/issue"; +// hooks import { useIssues, useLabel, useMember, useModule, useProjectState } from "hooks/store"; +// types import { IIssueDisplayFilterOptions, IIssueDisplayProperties, IIssueFilterOptions, TIssueLayouts } from "@plane/types"; +// constants +import { EIssueFilterType, EIssuesStoreType, ISSUE_DISPLAY_FILTERS_BY_LAYOUT, ISSUE_LAYOUTS } from "constants/issue"; -export const ModuleMobileHeader = () => { +export const ModuleMobileHeader = observer(() => { const [analyticsModal, setAnalyticsModal] = useState(false); const { getModuleById } = useModule(); const layouts = [ @@ -83,7 +90,7 @@ export const ModuleMobileHeader = () => { onClose={() => setAnalyticsModal(false)} moduleDetails={moduleDetails ?? undefined} /> -
+
{
); -}; +}); diff --git a/web/layouts/app-layout/layout.tsx b/web/layouts/app-layout/layout.tsx index dd1df164f..b417a5dfc 100644 --- a/web/layouts/app-layout/layout.tsx +++ b/web/layouts/app-layout/layout.tsx @@ -1,22 +1,21 @@ import { FC, ReactNode } from "react"; // layouts import { observer } from "mobx-react-lite"; -import useSWR from "swr"; import { CommandPalette } from "components/command-palette"; -import { EIssuesStoreType } from "constants/issue"; -import { useIssues } from "hooks/store/use-issues"; import { UserAuthWrapper, WorkspaceAuthWrapper, ProjectAuthWrapper } from "layouts/auth-layout"; // components import { AppSidebar } from "./sidebar"; +import { SidebarHamburgerToggle } from "components/core/sidebar/sidebar-menu-hamburger-toggle"; export interface IAppLayout { children: ReactNode; header: ReactNode; withProjectWrapper?: boolean; + mobileHeader?: ReactNode; } export const AppLayout: FC = observer((props) => { - const { children, header, withProjectWrapper = false } = props; + const { children, header, withProjectWrapper = false, mobileHeader } = props; return ( <> @@ -26,7 +25,15 @@ export const AppLayout: FC = observer((props) => {
- {header} +
+
+
+ +
+
{header}
+
+ {mobileHeader && mobileHeader} +
{withProjectWrapper ? {children} : <>{children}} diff --git a/web/pages/[workspaceSlug]/projects/[projectId]/cycles/[cycleId].tsx b/web/pages/[workspaceSlug]/projects/[projectId]/cycles/[cycleId].tsx index 6cf76cd70..5f1c9de77 100644 --- a/web/pages/[workspaceSlug]/projects/[projectId]/cycles/[cycleId].tsx +++ b/web/pages/[workspaceSlug]/projects/[projectId]/cycles/[cycleId].tsx @@ -17,6 +17,7 @@ import { AppLayout } from "layouts/app-layout"; // assets import { NextPageWithLayout } from "lib/types"; import emptyCycle from "public/empty-state/cycle.svg"; +import { CycleMobileHeader } from "components/cycles/cycle-mobile-header"; // types const CycleDetailPage: NextPageWithLayout = observer(() => { @@ -85,7 +86,7 @@ const CycleDetailPage: NextPageWithLayout = observer(() => { CycleDetailPage.getLayout = function getLayout(page: ReactElement) { return ( - } withProjectWrapper> + } mobileHeader={} withProjectWrapper> {page} ); diff --git a/web/pages/[workspaceSlug]/projects/[projectId]/cycles/index.tsx b/web/pages/[workspaceSlug]/projects/[projectId]/cycles/index.tsx index 651d03898..391f69007 100644 --- a/web/pages/[workspaceSlug]/projects/[projectId]/cycles/index.tsx +++ b/web/pages/[workspaceSlug]/projects/[projectId]/cycles/index.tsx @@ -27,6 +27,7 @@ import { TCycleFilters } from "@plane/types"; // constants import { CYCLE_TABS_LIST } from "constants/cycle"; import { EmptyStateType } from "constants/empty-state"; +import CyclesListMobileHeader from "components/cycles/cycles-list-mobile-header"; const ProjectCyclesPage: NextPageWithLayout = observer(() => { // states @@ -137,7 +138,7 @@ const ProjectCyclesPage: NextPageWithLayout = observer(() => { ProjectCyclesPage.getLayout = function getLayout(page: ReactElement) { return ( - } withProjectWrapper> + } mobileHeader={} withProjectWrapper> {page} ); diff --git a/web/pages/[workspaceSlug]/projects/[projectId]/issues/index.tsx b/web/pages/[workspaceSlug]/projects/[projectId]/issues/index.tsx index 241af79c4..e79ef109d 100644 --- a/web/pages/[workspaceSlug]/projects/[projectId]/issues/index.tsx +++ b/web/pages/[workspaceSlug]/projects/[projectId]/issues/index.tsx @@ -10,6 +10,7 @@ import { ProjectLayoutRoot } from "components/issues"; import { useProject } from "hooks/store"; import { AppLayout } from "layouts/app-layout"; import { NextPageWithLayout } from "lib/types"; +import { IssuesMobileHeader } from "components/issues/issues-mobile-header"; // layouts // hooks @@ -42,7 +43,7 @@ const ProjectIssuesPage: NextPageWithLayout = observer(() => { ProjectIssuesPage.getLayout = function getLayout(page: ReactElement) { return ( - } withProjectWrapper> + } mobileHeader={} withProjectWrapper> {page} ); diff --git a/web/pages/[workspaceSlug]/projects/[projectId]/modules/[moduleId].tsx b/web/pages/[workspaceSlug]/projects/[projectId]/modules/[moduleId].tsx index c5f41d419..949731f3b 100644 --- a/web/pages/[workspaceSlug]/projects/[projectId]/modules/[moduleId].tsx +++ b/web/pages/[workspaceSlug]/projects/[projectId]/modules/[moduleId].tsx @@ -16,6 +16,7 @@ import { AppLayout } from "layouts/app-layout"; // assets import { NextPageWithLayout } from "lib/types"; import emptyModule from "public/empty-state/module.svg"; +import { ModuleMobileHeader } from "components/modules/module-mobile-header"; // types const ModuleIssuesPage: NextPageWithLayout = observer(() => { @@ -83,7 +84,7 @@ const ModuleIssuesPage: NextPageWithLayout = observer(() => { ModuleIssuesPage.getLayout = function getLayout(page: ReactElement) { return ( - } withProjectWrapper> + } mobileHeader={} withProjectWrapper> {page} ); diff --git a/web/pages/[workspaceSlug]/projects/[projectId]/modules/index.tsx b/web/pages/[workspaceSlug]/projects/[projectId]/modules/index.tsx index eb3c92044..44bce7da7 100644 --- a/web/pages/[workspaceSlug]/projects/[projectId]/modules/index.tsx +++ b/web/pages/[workspaceSlug]/projects/[projectId]/modules/index.tsx @@ -13,6 +13,7 @@ import { AppLayout } from "layouts/app-layout"; import { NextPageWithLayout } from "lib/types"; import { calculateTotalFilters } from "helpers/filter.helper"; import { TModuleFilters } from "@plane/types"; +import ModulesListMobileHeader from "components/modules/moduels-list-mobile-header"; const ProjectModulesPage: NextPageWithLayout = observer(() => { const router = useRouter(); @@ -59,7 +60,7 @@ const ProjectModulesPage: NextPageWithLayout = observer(() => { ProjectModulesPage.getLayout = function getLayout(page: ReactElement) { return ( - } withProjectWrapper> + } mobileHeader={} withProjectWrapper> {page} );