Skip to content

Commit

Permalink
style: responsive analytics (#3604)
Browse files Browse the repository at this point in the history
  • Loading branch information
rameshkumarchandra authored Feb 9, 2024
1 parent 2e12968 commit 3a14f19
Show file tree
Hide file tree
Showing 11 changed files with 118 additions and 64 deletions.
28 changes: 19 additions & 9 deletions web/components/analytics/custom-analytics/custom-analytics.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import { CustomAnalyticsSelectBar, CustomAnalyticsMainContent, CustomAnalyticsSi
import { IAnalyticsParams } from "@plane/types";
// fetch-keys
import { ANALYTICS } from "constants/fetch-keys";
import { cn } from "helpers/common.helper";
import { useApplication } from "hooks/store";

type Props = {
additionalParams?: Partial<IAnalyticsParams>;
Expand Down Expand Up @@ -46,11 +48,13 @@ export const CustomAnalytics: React.FC<Props> = observer((props) => {
workspaceSlug ? () => analyticsService.getAnalytics(workspaceSlug.toString(), params) : null
);

const { theme: themeStore } = useApplication();

const isProjectLevel = projectId ? true : false;

return (
<div className={`flex flex-col-reverse overflow-hidden ${fullScreen ? "md:grid md:h-full md:grid-cols-4" : ""}`}>
<div className="col-span-3 flex h-full flex-col overflow-hidden">
<div className={cn("relative w-full h-full flex overflow-hidden", isProjectLevel ? "flex-col-reverse" : "")}>
<div className="w-full flex h-full flex-col overflow-hidden">
<CustomAnalyticsSelectBar
control={control}
setValue={setValue}
Expand All @@ -61,16 +65,22 @@ export const CustomAnalytics: React.FC<Props> = observer((props) => {
<CustomAnalyticsMainContent
analytics={analytics}
error={analyticsError}
fullScreen={fullScreen}
params={params}
fullScreen={fullScreen}
/>
</div>
<CustomAnalyticsSidebar
analytics={analytics}
params={params}
fullScreen={fullScreen}
isProjectLevel={isProjectLevel}
/>

<div
className={cn(
"border-l border-custom-border-200 transition-all",
!isProjectLevel
? "absolute right-0 top-0 bottom-0 md:relative flex-shrink-0 h-full max-w-[250px] sm:max-w-full"
: ""
)}
style={themeStore.workspaceAnalyticsSidebarCollapsed ? { right: `-${window?.innerWidth || 0}px` } : {}}
>
<CustomAnalyticsSidebar analytics={analytics} params={params} isProjectLevel={isProjectLevel} />
</div>
</div>
);
});
5 changes: 2 additions & 3 deletions web/components/analytics/custom-analytics/select-bar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,8 @@ export const CustomAnalyticsSelectBar: React.FC<Props> = observer((props) => {

return (
<div
className={`grid items-center gap-4 px-5 py-2.5 ${isProjectLevel ? "grid-cols-3" : "grid-cols-2"} ${
fullScreen ? "md:py-5 lg:grid-cols-4" : ""
}`}
className={`grid items-center gap-4 px-5 py-2.5 ${isProjectLevel ? "grid-cols-1 sm:grid-cols-3" : "grid-cols-2"} ${fullScreen ? "md:py-5 lg:grid-cols-4" : ""
}`}
>
{!isProjectLevel && (
<div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ export const CustomAnalyticsSidebarProjectsList: React.FC<Props> = observer((pro
const { getProjectById } = useProject();

return (
<div className="hidden h-full overflow-hidden md:flex md:flex-col">
<div className="relative flex flex-col gap-4 h-full">
<h4 className="font-medium">Selected Projects</h4>
<div className="mt-4 h-full space-y-6 overflow-y-auto">
<div className="relative space-y-6 overflow-hidden overflow-y-auto">
{projectIds.map((projectId) => {
const project = getProjectById(projectId);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export const CustomAnalyticsSidebarHeader = observer(() => {
<>
{projectId ? (
cycleDetails ? (
<div className="hidden h-full overflow-y-auto md:block">
<div className="h-full overflow-y-auto">
<h4 className="break-words font-medium">Analytics for {cycleDetails.name}</h4>
<div className="mt-4 space-y-4">
<div className="flex items-center gap-2 text-xs">
Expand All @@ -52,7 +52,7 @@ export const CustomAnalyticsSidebarHeader = observer(() => {
</div>
</div>
) : moduleDetails ? (
<div className="hidden h-full overflow-y-auto md:block">
<div className="h-full overflow-y-auto">
<h4 className="break-words font-medium">Analytics for {moduleDetails.name}</h4>
<div className="mt-4 space-y-4">
<div className="flex items-center gap-2 text-xs">
Expand All @@ -78,7 +78,7 @@ export const CustomAnalyticsSidebarHeader = observer(() => {
</div>
</div>
) : (
<div className="hidden h-full overflow-y-auto md:flex md:flex-col">
<div className="h-full overflow-y-auto">
<div className="flex items-center gap-1">
{projectDetails?.emoji ? (
<div className="grid h-6 w-6 flex-shrink-0 place-items-center">{renderEmoji(projectDetails.emoji)}</div>
Expand Down
46 changes: 21 additions & 25 deletions web/components/analytics/custom-analytics/sidebar/sidebar.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useEffect } from "react";
import { useEffect, } from "react";
import { useRouter } from "next/router";
import { observer } from "mobx-react-lite";
import { mutate } from "swr";
Expand All @@ -19,18 +19,18 @@ import { renderFormattedDate } from "helpers/date-time.helper";
import { IAnalyticsParams, IAnalyticsResponse, IExportAnalyticsFormData, IWorkspace } from "@plane/types";
// fetch-keys
import { ANALYTICS } from "constants/fetch-keys";
import { cn } from "helpers/common.helper";

type Props = {
analytics: IAnalyticsResponse | undefined;
params: IAnalyticsParams;
fullScreen: boolean;
isProjectLevel: boolean;
};

const analyticsService = new AnalyticsService();

export const CustomAnalyticsSidebar: React.FC<Props> = observer((props) => {
const { analytics, params, fullScreen, isProjectLevel = false } = props;
const { analytics, params, isProjectLevel = false } = props;
// router
const router = useRouter();
const { workspaceSlug, projectId, cycleId, moduleId } = router.query;
Expand Down Expand Up @@ -138,18 +138,14 @@ export const CustomAnalyticsSidebar: React.FC<Props> = observer((props) => {

const selectedProjects = params.project && params.project.length > 0 ? params.project : workspaceProjectIds;


return (
<div
className={`flex items-center justify-between space-y-2 px-5 py-2.5 ${
fullScreen
? "overflow-hidden border-l border-custom-border-200 md:h-full md:flex-col md:items-start md:space-y-4 md:border-l md:border-custom-border-200 md:py-5"
: ""
}`}
<div className={cn("relative h-full flex w-full gap-2 justify-between items-start px-5 py-4 bg-custom-sidebar-background-100", !isProjectLevel ? "flex-col" : "")}
>
<div className="flex flex-wrap items-center gap-2">
<div className="flex items-center gap-1 rounded-md bg-custom-background-80 px-3 py-1 text-xs text-custom-text-200">
<LayersIcon height={14} width={14} />
{analytics ? analytics.total : "..."} Issues
{analytics ? analytics.total : "..."} <div className={cn(isProjectLevel ? "hidden md:block" : "")}>Issues</div>
</div>
{isProjectLevel && (
<div className="flex items-center gap-1 rounded-md bg-custom-background-80 px-3 py-1 text-xs text-custom-text-200">
Expand All @@ -158,36 +154,36 @@ export const CustomAnalyticsSidebar: React.FC<Props> = observer((props) => {
(cycleId
? cycleDetails?.created_at
: moduleId
? moduleDetails?.created_at
: projectDetails?.created_at) ?? ""
? moduleDetails?.created_at
: projectDetails?.created_at) ?? ""
)}
</div>
)}
</div>
<div className="h-full w-full overflow-hidden">
{fullScreen ? (
<>
{!isProjectLevel && selectedProjects && selectedProjects.length > 0 && (
<CustomAnalyticsSidebarProjectsList projectIds={selectedProjects} />
)}
<CustomAnalyticsSidebarHeader />
</>
) : null}

<div className={cn("h-full w-full overflow-hidden", isProjectLevel ? "hidden" : "block")}>
<>
{!isProjectLevel && selectedProjects && selectedProjects.length > 0 && (
<CustomAnalyticsSidebarProjectsList projectIds={selectedProjects} />
)}
<CustomAnalyticsSidebarHeader />
</>
</div>
<div className="flex flex-wrap items-center gap-2 justify-self-end">

<div className="flex flex-wrap items-center gap-2 justify-end">
<Button
variant="neutral-primary"
prependIcon={<RefreshCw className="h-3.5 w-3.5" />}
prependIcon={<RefreshCw className="h-3 md:h-3.5 w-3 md:w-3.5" />}
onClick={() => {
if (!workspaceSlug) return;

mutate(ANALYTICS(workspaceSlug.toString(), params));
}}
>
Refresh
<div className={cn(isProjectLevel ? "hidden md:block" : "")}>Refresh</div>
</Button>
<Button variant="primary" prependIcon={<Download className="h-3.5 w-3.5" />} onClick={exportAnalytics}>
Export as CSV
<div className={cn(isProjectLevel ? "hidden md:block" : "")}>Export as CSV</div>
</Button>
</div>
</div>
Expand Down
7 changes: 3 additions & 4 deletions web/components/analytics/project-modal/main-content.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,15 @@ export const ProjectAnalyticsModalMainContent: React.FC<Props> = observer((props

return (
<Tab.Group as={React.Fragment}>
<Tab.List as="div" className="space-x-2 border-b border-custom-border-200 p-5 pt-0">
<Tab.List as="div" className="flex space-x-2 border-b border-custom-border-200 px-0 md:px-5 py-0 md:py-3">
{ANALYTICS_TABS.map((tab) => (
<Tab
key={tab.key}
className={({ selected }) =>
`rounded-3xl border border-custom-border-200 px-4 py-2 text-xs hover:bg-custom-background-80 ${
selected ? "bg-custom-background-80" : ""
`rounded-0 w-full md:w-max md:rounded-3xl border-b md:border border-custom-border-200 focus:outline-none px-0 md:px-4 py-2 text-xs hover:bg-custom-background-80 ${selected ? "border-custom-primary-100 text-custom-primary-100 md:bg-custom-background-80 md:text-custom-text-200 md:border-custom-border-200" : "border-transparent"
}`
}
onClick={() => {}}
onClick={() => { }}
>
{tab.title}
</Tab>
Expand Down
2 changes: 1 addition & 1 deletion web/components/headers/user-profile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ export const UserProfileHeader: FC<TUserProfileHeader> = observer((props) => {
</CustomMenu.MenuItem>
))}
</CustomMenu>
<button className="transition-all block md:hidden" onClick={() => { themStore.toggleProfileSidebar(); console.log(themStore.profileSidebarCollapsed) }}>
<button className="transition-all block md:hidden" onClick={() => { themStore.toggleProfileSidebar() }}>
<PanelRight className={
cn("w-4 h-4 block md:hidden", !themStore.profileSidebarCollapsed ? "text-[#3E63DD]" : "text-custom-text-200")
} />
Expand Down
35 changes: 31 additions & 4 deletions web/components/headers/workspace-analytics.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,35 @@
import { useRouter } from "next/router";
import { ArrowLeft, BarChart2 } from "lucide-react";
import { BarChart2, PanelRight } from "lucide-react";
// ui
import { Breadcrumbs } from "@plane/ui";
// components
import { SidebarHamburgerToggle } from "components/core/sidebar/sidebar-menu-hamburger-toggle";
import { BreadcrumbLink } from "components/common";
import { useApplication } from "hooks/store";
import { observer } from "mobx-react";
import { cn } from "helpers/common.helper";
import { useEffect } from "react";

export const WorkspaceAnalyticsHeader = () => {
export const WorkspaceAnalyticsHeader = observer(() => {
const router = useRouter();
const { analytics_tab } = router.query;

const { theme: themeStore } = useApplication();

useEffect(() => {
const handleToggleWorkspaceAnalyticsSidebar = () => {
if (window && window.innerWidth < 768) {
themeStore.toggleWorkspaceAnalyticsSidebar(true);
}
if (window && themeStore.workspaceAnalyticsSidebarCollapsed && window.innerWidth >= 768) {
themeStore.toggleWorkspaceAnalyticsSidebar(false);
}
};

window.addEventListener("resize", handleToggleWorkspaceAnalyticsSidebar);
handleToggleWorkspaceAnalyticsSidebar();
return () => window.removeEventListener("resize", handleToggleWorkspaceAnalyticsSidebar);
}, [themeStore]);

return (
<>
Expand All @@ -16,7 +38,7 @@ export const WorkspaceAnalyticsHeader = () => {
>
<div className="flex w-full flex-grow items-center gap-2 overflow-ellipsis whitespace-nowrap">
<SidebarHamburgerToggle />
<div>
<div className="flex items-center justify-between w-full">
<Breadcrumbs>
<Breadcrumbs.BreadcrumbItem
type="text"
Expand All @@ -25,9 +47,14 @@ export const WorkspaceAnalyticsHeader = () => {
}
/>
</Breadcrumbs>
{analytics_tab === 'custom' &&
<button className="block md:hidden" onClick={() => { themeStore.toggleWorkspaceAnalyticsSidebar() }}>
<PanelRight className={cn("w-4 h-4 block md:hidden", !themeStore.workspaceAnalyticsSidebarCollapsed ? "text-custom-primary-100" : "text-custom-text-200")} />
</button>
}
</div>
</div>
</div>
</>
);
};
});
16 changes: 8 additions & 8 deletions web/components/profile/sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export const ProfileSidebar = observer(() => {
const { workspaceSlug, userId } = router.query;
// store hooks
const { currentUser } = useUser();
const { theme: themStore } = useApplication();
const { theme: themeStore } = useApplication();
const ref = useRef<HTMLDivElement>(null);

const { data: userProjectsData } = useSWR(
Expand All @@ -41,9 +41,9 @@ export const ProfileSidebar = observer(() => {
);

useOutsideClickDetector(ref, () => {
if (themStore.profileSidebarCollapsed === false) {
if (themeStore.profileSidebarCollapsed === false) {
if (window.innerWidth < 768) {
themStore.toggleProfileSidebar();
themeStore.toggleProfileSidebar();
}
}
});
Expand All @@ -62,22 +62,22 @@ export const ProfileSidebar = observer(() => {
useEffect(() => {
const handleToggleProfileSidebar = () => {
if (window && window.innerWidth < 768) {
themStore.toggleProfileSidebar(true);
themeStore.toggleProfileSidebar(true);
}
if (window && themStore.profileSidebarCollapsed && window.innerWidth >= 768) {
themStore.toggleProfileSidebar(false);
if (window && themeStore.profileSidebarCollapsed && window.innerWidth >= 768) {
themeStore.toggleProfileSidebar(false);
}
};

window.addEventListener("resize", handleToggleProfileSidebar);
handleToggleProfileSidebar();
return () => window.removeEventListener("resize", handleToggleProfileSidebar);
}, [themStore]);
}, [themeStore]);

return (
<div
className={`flex-shrink-0 overflow-hidden overflow-y-auto shadow-custom-shadow-sm border-l border-custom-border-100 bg-custom-sidebar-background-100 h-full z-[5] fixed md:relative transition-all w-full md:w-[300px]`}
style={themStore.profileSidebarCollapsed ? { marginLeft: `${window?.innerWidth || 0}px` } : {}}
style={themeStore.profileSidebarCollapsed ? { marginLeft: `${window?.innerWidth || 0}px` } : {}}
>
{userProjectsData ? (
<>
Expand Down
15 changes: 10 additions & 5 deletions web/pages/[workspaceSlug]/analytics.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,11 @@ import { ANALYTICS_TABS } from "constants/analytics";
import { EUserWorkspaceRoles } from "constants/workspace";
// type
import { NextPageWithLayout } from "lib/types";
import { useRouter } from "next/router";

const AnalyticsPage: NextPageWithLayout = observer(() => {
const router = useRouter()
const { analytics_tab } = router.query
// theme
const { resolvedTheme } = useTheme();
// store hooks
Expand All @@ -38,17 +41,19 @@ const AnalyticsPage: NextPageWithLayout = observer(() => {
<>
{workspaceProjectIds && workspaceProjectIds.length > 0 ? (
<div className="flex h-full flex-col overflow-hidden bg-custom-background-100">
<Tab.Group as={Fragment}>
<Tab.List as="div" className="space-x-2 border-b border-custom-border-200 px-5 py-3">
<Tab.Group as={Fragment} defaultIndex={analytics_tab === 'custom' ? 1 : 0}>
<Tab.List as="div" className="flex space-x-2 border-b border-custom-border-200 px-0 md:px-5 py-0 md:py-3">
{ANALYTICS_TABS.map((tab) => (
<Tab
key={tab.key}
className={({ selected }) =>
`rounded-3xl border border-custom-border-200 px-4 py-2 text-xs hover:bg-custom-background-80 ${
selected ? "bg-custom-background-80" : ""
`rounded-0 w-full md:w-max md:rounded-3xl border-b md:border border-custom-border-200 focus:outline-none px-0 md:px-4 py-2 text-xs hover:bg-custom-background-80 ${selected ? "border-custom-primary-100 text-custom-primary-100 md:bg-custom-background-80 md:text-custom-text-200 md:border-custom-border-200" : "border-transparent"
}`
}
onClick={() => {}}
onClick={() => {
router.query.analytics_tab = tab.key
router.push(router)
}}
>
{tab.title}
</Tab>
Expand Down
Loading

0 comments on commit 3a14f19

Please sign in to comment.