Repository: open-sauced/app
Pull request #2418 (2024-01-04 19:36:31)

chore: release 1.81.0


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 364ee6b8..f26d5979 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,95 @@
 
 > All notable changes to this project will be documented in this file
 
+## [1.81.0-beta.8](https://github.com/open-sauced/insights/compare/v1.81.0-beta.7...v1.81.0-beta.8) (2024-01-04)
+
+
+### 🍕 Features
+
+* contributions treemap filtered by owners now ([#2391](https://github.com/open-sauced/insights/issues/2391)) ([3944293](https://github.com/open-sauced/insights/commit/39442930dcc13773cd9e3fb5702060c25816c823))
+
+## [1.81.0-beta.7](https://github.com/open-sauced/insights/compare/v1.81.0-beta.6...v1.81.0-beta.7) (2024-01-03)
+
+
+### 🐛 Bug Fixes
+
+* Added state for reactions dropdown on highlight cards. ([#2409](https://github.com/open-sauced/insights/issues/2409)) ([5f334f8](https://github.com/open-sauced/insights/commit/5f334f8fc9638b8d9c11a7957b8c31dcf69eedc2))
+
+## [1.81.0-beta.6](https://github.com/open-sauced/insights/compare/v1.81.0-beta.5...v1.81.0-beta.6) (2023-12-22)
+
+
+### 🍕 Features
+
+* now contributions treemap can resize ([#2401](https://github.com/open-sauced/insights/issues/2401)) ([d524fb0](https://github.com/open-sauced/insights/commit/d524fb0d94cf3c020afb9873e23f921d5d1c5c53))
+* replace contribution distribution chart with contributors table in list overview page ([#2385](https://github.com/open-sauced/insights/issues/2385)) ([a9db0dd](https://github.com/open-sauced/insights/commit/a9db0dd6253313b67ff80c8068a9f03cba5eef62))
+
+## [1.81.0-beta.5](https://github.com/open-sauced/insights/compare/v1.81.0-beta.4...v1.81.0-beta.5) (2023-12-22)
+
+
+### 🍕 Features
+
+* insights page are available to non logged in users ([#2226](https://github.com/open-sauced/insights/issues/2226)) ([23e19fa](https://github.com/open-sauced/insights/commit/23e19fa48dc0dd53bc8c962e8b532411ba549449))
+
+
+### 📝 Documentation
+
+* add sidebar component prototype to storybook ([#2377](https://github.com/open-sauced/insights/issues/2377)) ([9e15943](https://github.com/open-sauced/insights/commit/9e15943e77c75a86401b408648fa656f5f962825))
+
+
+### 🐛 Bug Fixes
+
+* now page limit dropdown filters works on repo table ([#2227](https://github.com/open-sauced/insights/issues/2227)) ([fdcc081](https://github.com/open-sauced/insights/commit/fdcc0814aad71834f2c5cc74e87549e7dbf1b1e5))
+* removed treemap prototype ([17cb4d8](https://github.com/open-sauced/insights/commit/17cb4d8783ce1e8ed1b95d790fa2a815262f3b1e))
+* removed treemap prototype ([#2392](https://github.com/open-sauced/insights/issues/2392)) ([04c7f29](https://github.com/open-sauced/insights/commit/04c7f2989f44a69add4e27fc8f6690b8f0292aa3))
+* Revert "fix: fixed releases breaking from SWC by turning it off ([#2394](https://github.com/open-sauced/insights/issues/2394))" ([#2397](https://github.com/open-sauced/insights/issues/2397)) ([0d2775d](https://github.com/open-sauced/insights/commit/0d2775d0a6738c087049e4530512599dc679ef46))
+
+## [1.81.0-beta.4](https://github.com/open-sauced/insights/compare/v1.81.0-beta.3...v1.81.0-beta.4) (2023-12-21)
+
+
+### 🐛 Bug Fixes
+
+* activity list contributions treemap nodes are keyboard navigable now ([60ac568](https://github.com/open-sauced/insights/commit/60ac56844210a213781577101809dcaca69b2a5e))
+* activity list contributions treemap nodes are keyboard navigable now ([#2388](https://github.com/open-sauced/insights/issues/2388)) ([bd2141c](https://github.com/open-sauced/insights/commit/bd2141c947de3c478917f8bc3d0bdabc10b50b94))
+
+## [1.81.0-beta.3](https://github.com/open-sauced/insights/compare/v1.81.0-beta.2...v1.81.0-beta.3) (2023-12-20)
+
+
+### 🐛 Bug Fixes
+
+* Hotfix to bust app-cache ([#2387](https://github.com/open-sauced/insights/issues/2387)) ([d1f35ed](https://github.com/open-sauced/insights/commit/d1f35ed48836c0a1d2be9bebc8935a7bb1d646ea))
+
+## [1.81.0-beta.2](https://github.com/open-sauced/insights/compare/v1.81.0-beta.1...v1.81.0-beta.2) (2023-12-20)
+
+
+### 🐛 Bug Fixes
+
+* added contributions treemap loading view ([e47e3b6](https://github.com/open-sauced/insights/commit/e47e3b67c167bcb3d520423e10c0731864343aa1))
+* added contributions treemap loading view ([#2383](https://github.com/open-sauced/insights/issues/2383)) ([c6c94b3](https://github.com/open-sauced/insights/commit/c6c94b38d882cfdf105af0c776df5d7f64486751))
+
+
+### 🍕 Features
+
+* Make insight pages more agnostic and use new v1/insight API functionality ([#2368](https://github.com/open-sauced/insights/issues/2368)) ([5813beb](https://github.com/open-sauced/insights/commit/5813beb3cca54ef9c11cbc1062f7d0c7e627ae2b))
+
+## [1.81.0-beta.1](https://github.com/open-sauced/insights/compare/v1.80.0...v1.81.0-beta.1) (2023-12-20)
+
+
+### 🍕 Features
+
+* add helper tooltip to dashboard highlight cards ([#2309](https://github.com/open-sauced/insights/issues/2309)) ([9429233](https://github.com/open-sauced/insights/commit/942923313e522e31614ee94512417851b9f99ef9))
+
+
+### 🐛 Bug Fixes
+
+* added a constant for our fallback empty data value ([7ea28e1](https://github.com/open-sauced/insights/commit/7ea28e110ff8cc126859c555831e7caaab57c94f))
+* added a constant for our fallback empty data value ([#2374](https://github.com/open-sauced/insights/issues/2374)) ([48cf2c4](https://github.com/open-sauced/insights/commit/48cf2c401690c0ac56fb43859eeaaa7118a1ebc2))
+* fix pagination logic ([#2361](https://github.com/open-sauced/insights/issues/2361)) ([073fb85](https://github.com/open-sauced/insights/commit/073fb85aab6f8fc9a7d2f10bd6e343304398e11d))
+* now interests are not fallbacks for most used languages ([6fc1273](https://github.com/open-sauced/insights/commit/6fc12733e78a8d9c03fdf76aa3b564d7678a38b5))
+* now interests are not fallbacks for most used languages ([e2ff7fd](https://github.com/open-sauced/insights/commit/e2ff7fd33ff379936c1bffe6a61fb57be39b5bae))
+* now interests are not fallbacks for most used languages ([#2373](https://github.com/open-sauced/insights/issues/2373)) ([7e68217](https://github.com/open-sauced/insights/commit/7e68217646cd53e4025f07e00e55edf94ec20876))
+* now you can navigate back to the previous page from a user profile page ([9a4c538](https://github.com/open-sauced/insights/commit/9a4c538a7ff43dec90345750e1985346da547249))
+* now you can navigate back to the previous page from a user profile page ([#2382](https://github.com/open-sauced/insights/issues/2382)) ([7d15dca](https://github.com/open-sauced/insights/commit/7d15dcaf9bc8d7bc955c9340b22bbe20a9422e9c))
+
 ## [1.80.0](https://github.com/open-sauced/insights/compare/v1.79.2...v1.80.0) (2023-12-19)
 
 
diff --git a/components/Graphs/ContributionsTreemap/contributions-treemap.stories.tsx b/components/Graphs/ContributionsTreemap/contributions-treemap.stories.tsx
new file mode 100644
index 00000000..914b57a3
--- /dev/null
+++ b/components/Graphs/ContributionsTreemap/contributions-treemap.stories.tsx
@@ -0,0 +1,111 @@
+import { Meta, StoryObj } from "@storybook/react";
+import { getGraphColorPalette } from "lib/utils/color-utils";
+import { ContributionsTreemap } from "./contributions-treemap";
+
+type Story = StoryObj<typeof ContributionsTreemap>;
+
+const meta: Meta<typeof ContributionsTreemap> = {
+  title: "Components/Graphs/ContributionsTreemap",
+  component: ContributionsTreemap,
+};
+
+export default meta;
+
+export const Owners: Story = {
+  args: {
+    data: {
+      id: "root",
+      children: [
+        { id: "hono-js", value: 45 },
+        { id: "reduxjs", value: 12 },
+        { id: "nodejs", value: 76 },
+        { id: "reactjs", value: 89 },
+        { id: "angular", value: 33 },
+        { id: "babel", value: 52 },
+        { id: "expressjs", value: 64 },
+        { id: "webpack", value: 22 },
+        { id: "eslint", value: 17 },
+        { id: "jest", value: 91 },
+        { id: "vuejs", value: 41 },
+        { id: "nestjs", value: 55 },
+        { id: "axios", value: 8 },
+        { id: "lodash", value: 37 },
+        { id: "moment", value: 67 },
+        { id: "storybook", value: 14 },
+        { id: "graphql", value: 72 },
+        { id: "prisma", value: 5 },
+        { id: "mongodb", value: 29 },
+        { id: "redis", value: 83 },
+      ],
+    },
+    color: getGraphColorPalette(),
+    onDrillDown: () => {},
+    onDrillUp: () => {},
+    orgId: null,
+    projectId: null,
+    isLoading: false,
+  },
+};
+
+export const Repositories: Story = {
+  args: {
+    data: {
+      id: "root",
+      children: [
+        { id: "kubernetes", value: 42 },
+        { id: "minikube", value: 15 },
+        { id: "kops", value: 72 },
+        { id: "helm", value: 91 },
+        { id: "kubectl", value: 33 },
+        { id: "kube-proxy", value: 58 },
+        { id: "kubelet", value: 22 },
+        { id: "kube-scheduler", value: 67 },
+        { id: "kube-controller-manager", value: 8 },
+        { id: "etcd", value: 79 },
+        { id: "kube-dns", value: 11 },
+        { id: "coredns", value: 25 },
+        { id: "flannel", value: 63 },
+        { id: "calico", value: 41 },
+        { id: "istio", value: 37 },
+        { id: "prometheus", value: 54 },
+        { id: "grafana", value: 18 },
+        { id: "cni", value: 88 },
+        { id: "kubernetes-dashboard", value: 9 },
+        { id: "dashboard", value: 75 },
+      ],
+    },
+    color: getGraphColorPalette(),
+    onDrillDown: () => {},
+    onDrillUp: () => {},
+    orgId: "kubernetes",
+    projectId: null,
+    isLoading: false,
+  },
+};
+
+export const Contributors: Story = {
+  args: {
+    data: {
+      id: "root",
+      children: [
+        { id: "nickytonline", value: 10 },
+        { id: "brandonroberts", value: 97 },
+        { id: "BekahHW", value: 30 },
+        { id: "isabensusan", value: 41 },
+        { id: "bdougie", value: 52 },
+        { id: "jpmcb", value: 63 },
+        { id: "OgDev-01", value: 34 },
+      ],
+    },
+    color: getGraphColorPalette(),
+    onDrillDown: () => {},
+    onDrillUp: () => {},
+    orgId: "open-sauced",
+    projectId: "app",
+    isLoading: false,
+  },
+};
+
+export const Loading: Story = {
+  args: { isLoading: true },
+};
diff --git a/components/Graphs/ContributionsTreemap/contributions-treemap.tsx b/components/Graphs/ContributionsTreemap/contributions-treemap.tsx
new file mode 100644
index 00000000..4748ea75
--- /dev/null
+++ b/components/Graphs/ContributionsTreemap/contributions-treemap.tsx
@@ -0,0 +1,134 @@
+import { useSpring, animated } from "@react-spring/web";
+import dynamic from "next/dynamic";
+import { Datum } from "@nivo/line";
+import { ReactNode } from "react";
+import Card from "components/atoms/Card/card";
+import ClientOnly from "components/atoms/ClientOnly/client-only";
+import SkeletonWrapper from "components/atoms/SkeletonLoader/skeleton-wrapper";
+import Button from "components/atoms/Button/button";
+import { OnToggleResizeEventType, Resizer } from "components/Graphs/shared/graph-resizer";
+import type { NodeMouseEventHandler, NodeProps, TreeMapCommonProps } from "@nivo/treemap";
+import { SpecialNode } from "./special-node";
+import { ContributorNode } from "./contributor-node";
+
+interface ContributionsTreemapProps {
+  data: any;
+  color: TreeMapCommonProps<Datum>["colors"];
+  projectId: string | null;
+  orgId: string | null;
+  isLoading: boolean;
+  onDrillDown: NodeMouseEventHandler<object>;
+  onDrillUp: () => void;
+  onToggleResize: OnToggleResizeEventType;
+}
+
+function BreadCrumb({
+  isActive,
+  useSeparator = true,
+  children,
+}: {
+  isActive: boolean;
+  useSeparator?: boolean;
+  children: ReactNode;
+}) {
+  const separatorStyle = useSpring(isActive ? { opacity: 1 } : { opacity: 0 });
+  const textStyle = useSpring(isActive ? { opacity: 1, translateX: 0 } : { opacity: 0, translateX: 100 });
+
+  return (
+    <>
+      <animated.div style={textStyle} {...{ children }} />
+      {useSeparator ? (
+        <animated.div className={"px-1"} style={separatorStyle}>
+          {"/"}
+        </animated.div>
+      ) : null}
+    </>
+  );
+}
+
+const ResponsiveTreeMapHtml = dynamic(() => import("@nivo/treemap").then((module) => module.ResponsiveTreeMapHtml), {
+  ssr: false,
+});
+
+export const ContributionsTreemap = ({
+  projectId,
+  orgId,
+  data,
+  color,
+  isLoading,
+  onDrillDown: onDrilldown,
+  onDrillUp,
+  onToggleResize,
+}: ContributionsTreemapProps) => {
+  return (
+    <Card className="grid place-content-stretch">
+      <>
+        <Resizer onToggleResize={onToggleResize} />
+        <div className="grid">
+          {/* Label: Text */}
+          <h2 className="font-medium text-lg text-slate-900 mb-2 flex items-center justify-between">
+            All Contributions
+          </h2>
+          <div className="flex gap-2 items-center justify-between">
+            <div className="flex gap-2 mb-2">
+              {orgId ? (
+                <BreadCrumb isActive={true} useSeparator={projectId !== null}>
+                  {orgId}
+                </BreadCrumb>
+              ) : null}
+              {projectId ? (
+                <>
+                  <BreadCrumb isActive={true}>{projectId}</BreadCrumb>
+                  <BreadCrumb isActive={true} useSeparator={false}>
+                    Contributors
+                  </BreadCrumb>
+                </>
+              ) : null}
+            </div>
+            <div className="flex gap-2 mb-2">
+              <Button variant="outline" disabled={!orgId} onClick={orgId ? onDrillUp : undefined}>
+                <span className="sr-only">Drill up in the treemap of contributions</span>
+                <span className="not-sr-only">Back</span>
+              </Button>
+            </div>
+          </div>
+          <div className="rounded-md overflow-hidden grid place-content-stretch">
+            <div className="grid" style={{ gridArea: "1 / 1", minHeight: "29rem" }}>
+              <ClientOnly>
+                {isLoading ? (
+                  <SkeletonWrapper />
+                ) : (
+                  <ResponsiveTreeMapHtml
+                    data={data}
+                    tile="squarify"
+                    labelSkipSize={12}
+                    innerPadding={4}
+                    leavesOnly
+                    orientLabel={false}
+                    nodeComponent={
+                      projectId === null || orgId === null
+                        ? SpecialNode
+                        : // TODO: Sort this out later
+                          (ContributorNode as <Datum extends object>({
+                            node,
+                            animatedProps,
+                            borderWidth,
+                            enableLabel,
+                            labelSkipSize,
+                          }: NodeProps<Datum>) => JSX.Element)
+                    }
+                    colors={color}
+                    nodeOpacity={1}
+                    borderWidth={0}
+                    onClick={onDrilldown}
+                    motionConfig={"default"}
+                  />
+                )}
+              </ClientOnly>
+            </div>
+          </div>
+        </div>
+      </>
+    </Card>
+  );
+};
diff --git a/components/molecules/TreemapPrototype/contributor-node.tsx b/components/Graphs/ContributionsTreemap/contributor-node.tsx
similarity index 82%
rename from components/molecules/TreemapPrototype/contributor-node.tsx
rename to components/Graphs/ContributionsTreemap/contributor-node.tsx
index aded9786..afbecae5 100644
--- a/components/molecules/TreemapPrototype/contributor-node.tsx
+++ b/components/Graphs/ContributionsTreemap/contributor-node.tsx
@@ -18,7 +18,7 @@ const NonMemoizedContributorNode = <Datum extends { id: string; value?: number;
   const avatarURL = getAvatarByUsername(node.id);
 
   return (
-    <animated.div
+    <animated.button
       className="absolute grid overflow-hidden border-solid place-content-stretch"
       style={{
         top: 0,
@@ -52,7 +52,7 @@ const NonMemoizedContributorNode = <Datum extends { id: string; value?: number;
             placeItems: "flex-start",
           }}
         >
-          <div className="grid gap-x-2" style={{ gridTemplateColumns: "auto 1fr", gridTemplateRows: "auto auto" }}>
+          <div className="flex items-center gap-2">
             <Image
               className="col-span-1 col-start-1 row-span-2"
               src={avatarURL}
@@ -62,17 +62,19 @@ const NonMemoizedContributorNode = <Datum extends { id: string; value?: number;
               style={{ display: "block", borderRadius: "50%", border: "solid 2px white", flexShrink: 0, flexGrow: 0 }}
             />
 
-            <div style={{ gridColumnStart: "2", alignItems: "center", alignSelf: "center" }}>{node.id}</div>
-            <div
-              className="font-normal"
-              style={{ textOverflow: "ellipsis", gridColumnStart: "2", marginTop: "-0.5rem" }}
-            >
-              {node.formattedValue} Contributions
+            <div className="flex flex-col items-start gap-2">
+              <div>{node.id}</div>
+              <div
+                className="whitespace-nowrap overflow-hidden overflow-ellipsis"
+                style={{ gridColumnStart: "2", marginTop: "-0.5rem" }}
+              >
+                {node.formattedValue} Contributions
+              </div>
             </div>
           </div>
         </animated.div>
       )}
-    </animated.div>
+    </animated.button>
   );
 };
 
diff --git a/components/molecules/TreemapPrototype/special-node.tsx b/components/Graphs/ContributionsTreemap/special-node.tsx
similarity index 83%
rename from components/molecules/TreemapPrototype/special-node.tsx
rename to components/Graphs/ContributionsTreemap/special-node.tsx
index d393cfef..d1873e20 100644
--- a/components/molecules/TreemapPrototype/special-node.tsx
+++ b/components/Graphs/ContributionsTreemap/special-node.tsx
@@ -15,8 +15,8 @@ const NonMemoizedSpecialNode = <Datum extends object>({
   const [fullRepoName] = node.id.split(":");
 
   return (
-    <animated.div
-      className="absolute grid overflow-hidden border-solid cursor-pointer place-content-stretch"
+    <animated.button
+      className="absolute grid overflow-hidden border-solid place-content-stretch"
       style={{
         top: 0,
         left: 0,
@@ -26,6 +26,7 @@ const NonMemoizedSpecialNode = <Datum extends object>({
         borderWidth,
         borderColor: node.borderColor,
       }}
+      onClick={node.onClick}
     >
       <animated.div
         style={{
@@ -38,7 +39,6 @@ const NonMemoizedSpecialNode = <Datum extends object>({
         onMouseEnter={node.onMouseEnter}
         onMouseMove={node.onMouseMove}
         onMouseLeave={node.onMouseLeave}
-        onClick={node.onClick}
       />
       {showLabel && (
         <animated.div
@@ -50,15 +50,15 @@ const NonMemoizedSpecialNode = <Datum extends object>({
             placeItems: "flex-start",
           }}
         >
-          <div className="grid gap-2">
+          <div className="flex flex-col items-start">
             <div className="text-sm">{fullRepoName}</div>
-            <div className="text-xs font-normal" style={{ textOverflow: "ellipsis" }}>
-              {node.label}
+            <div className="text-xs whitespace-nowrap overflow-hidden overflow-ellipsis">
+              {node.label} contributions
             </div>
           </div>
         </animated.div>
       )}
-    </animated.div>
+    </animated.button>
   );
 };
 
diff --git a/components/Graphs/shared/graph-resizer.tsx b/components/Graphs/shared/graph-resizer.tsx
new file mode 100644
index 00000000..90ed37f5
--- /dev/null
+++ b/components/Graphs/shared/graph-resizer.tsx
@@ -0,0 +1,23 @@
+import { FiMaximize2 } from "react-icons/fi";
+
+export type OnToggleResizeEventType = (checked: boolean) => void;
+
+export const Resizer = ({ onToggleResize }: { onToggleResize: OnToggleResizeEventType }) => {
+  return (
+    <button
+      role="switch"
+      aria-checked="true"
+      onClick={(event) => {
+        const button = event.currentTarget;
+        const checked = button.ariaChecked === "true";
+        button.ariaChecked = checked ? "false" : "true";
+
+        onToggleResize(checked);
+      }}
+      className="border rounded border-transparent absolute top-0 right-0 p-2"
+    >
+      <span className="sr-only">Toggle graph size</span>
+      <FiMaximize2 className="w-4 h-4 hover:text-orange-500" />
+    </button>
+  );
+};
diff --git a/components/ListHeader/list-header.tsx b/components/ListHeader/list-header.tsx
index ece3fcf9..7c1c82c2 100644
--- a/components/ListHeader/list-header.tsx
+++ b/components/ListHeader/list-header.tsx
@@ -10,6 +10,7 @@ import ContextThumbnail from "components/atoms/ContextThumbnail/context-thumbnai
 
 import { truncateString } from "lib/utils/truncate-string";
 import { useToast } from "lib/hooks/useToast";
+import ClientOnly from "components/atoms/ClientOnly/client-only";
 
 interface ListHeaderProps {
   name: string;
@@ -50,7 +51,7 @@ const ListHeader = ({ name, isPublic, listId, isOwner, numberOfContributors }: L
             {<Badge isPublic={isPublic} />}
           </div>
           <div className="flex items-center gap-2 mt-4" id="contributorCount">
-            {numberOfContributors} Contributors
+            <ClientOnly>{numberOfContributors} Contributors </ClientOnly>
           </div>
         </div>
       </div>
diff --git a/components/Sidebar/sidebar-group-wrapper.stories.tsx b/components/Sidebar/sidebar-group-wrapper.stories.tsx
new file mode 100644
index 00000000..ede226e5
--- /dev/null
+++ b/components/Sidebar/sidebar-group-wrapper.stories.tsx
@@ -0,0 +1,36 @@
+import { StoryObj, Meta } from "@storybook/react";
+import SidebarGroupWrapper from "./sidebar-group-wrapper";
+import SidebarMenuItem from "./sidebar-menu-item";
+import SidebarMenuHeader from "./sidebar-menu-header";
+
+const meta: Meta<typeof SidebarGroupWrapper> = {
+  title: "Design System/Sidebar/SidebarGroupWrapper",
+  component: SidebarGroupWrapper,
+  argTypes: {
+    isLoading: {
+      control: { type: "boolean" },
+    },
+  },
+};
+
+export default meta;
+
+type Story = StoryObj<typeof SidebarGroupWrapper>;
+
+export const Default: Story = {
+  args: {
+    children: (
+      <>
+        <SidebarMenuHeader>Your insights</SidebarMenuHeader>
+        <SidebarMenuItem title="Dashboard" href="/dashboard" type="list" />
+        <SidebarMenuItem title="Repositories" href="/repositories" type="repo" isActive />
+      </>
+    ),
+  },
+};
+
+export const Loading: Story = {
+  args: {
+    isLoading: true,
+  },
+};
diff --git a/components/Sidebar/sidebar-group-wrapper.tsx b/components/Sidebar/sidebar-group-wrapper.tsx
new file mode 100644
index 00000000..e886b2fc
--- /dev/null
+++ b/components/Sidebar/sidebar-group-wrapper.tsx
@@ -0,0 +1,23 @@
+import React from "react";
+import SkeletonWrapper from "components/atoms/SkeletonLoader/skeleton-wrapper";
+
+interface SidebarGroupWrapperProps {
+  isLoading?: boolean;
+  children?: React.ReactNode;
+}
+const SidebarGroupWrapper = ({ isLoading, children }: SidebarGroupWrapperProps) => {
+  return (
+    <div className="w-full px-2 -mt-4">
+      {isLoading ? (
+        <>
+          <SkeletonWrapper height={20} radius={5} count={2} classNames="w-48" />
+          <SkeletonWrapper height={20} radius={5} count={1} classNames="w-28" />
+        </>
+      ) : (
+        children
+      )}
+    </div>
+  );
+};
+
+export default SidebarGroupWrapper;
diff --git a/components/Sidebar/sidebar-menu-header.stories.tsx b/components/Sidebar/sidebar-menu-header.stories.tsx
new file mode 100644
index 00000000..e82aa89e
--- /dev/null
+++ b/components/Sidebar/sidebar-menu-header.stories.tsx
@@ -0,0 +1,17 @@
+import { StoryObj, Meta } from "@storybook/react";
+import SidebarMenuHeader from "./sidebar-menu-header";
+
+const meta: Meta<typeof SidebarMenuHeader> = {
+  title: "Design System/Sidebar/SidebarMenuHeader",
+  component: SidebarMenuHeader,
+};
+
+export default meta;
+
+type Story = StoryObj<typeof SidebarMenuHeader>;
+
+export const Default: Story = {
+  args: {
+    children: "Your insights",
+  },
+};
diff --git a/components/Sidebar/sidebar-menu-header.tsx b/components/Sidebar/sidebar-menu-header.tsx
new file mode 100644
index 00000000..4185029a
--- /dev/null
+++ b/components/Sidebar/sidebar-menu-header.tsx
@@ -0,0 +1,15 @@
+import React from "react";
+import Title from "components/atoms/Typography/title";
+
+interface MenuHeaderProps {
+  children: React.ReactNode;
+}
+const SidebarMenuHeader = ({ children }: MenuHeaderProps) => {
+  return (
+    <Title className="text-gray-500 text-sm px-2" level={3}>
+      {children}
+    </Title>
+  );
+};
+
+export default SidebarMenuHeader;
diff --git a/components/Sidebar/sidebar-menu-item.stories.tsx b/components/Sidebar/sidebar-menu-item.stories.tsx
new file mode 100644
index 00000000..6bfaaf6f
--- /dev/null
+++ b/components/Sidebar/sidebar-menu-item.stories.tsx
@@ -0,0 +1,41 @@
+import { ComponentProps } from "react";
+import { Meta, StoryObj } from "@storybook/react";
+
+import { UsersIcon } from "@heroicons/react/24/solid";
+import SidebarMenuItem from "./sidebar-menu-item";
+
+const meta: Meta<typeof SidebarMenuItem> = {
+  title: "Design System/Sidebar/SidebarMenuItem",
+  component: SidebarMenuItem,
+  argTypes: {
+    type: {
+      options: ["repo", "list"],
+      control: { type: "radio" },
+    },
+  },
+};
+
+export default meta;
+
+type Story = StoryObj<typeof SidebarMenuItem>;
+
+const baseProps: ComponentProps<typeof SidebarMenuItem> = {
+  title: "My New List",
+  href: "/dashboard",
+};
+
+export const Default: Story = {
+  args: { ...baseProps, icon: <UsersIcon className="w-5 h-5 text-slate-400" /> },
+};
+
+export const Repo: Story = {
+  args: { ...baseProps, type: "repo" },
+};
+
+export const List: Story = {
+  args: { ...baseProps, type: "list" },
+};
+
+export const Active: Story = {
+  args: { ...baseProps, isActive: true, type: "list" },
+};
diff --git a/components/Sidebar/sidebar-menu-item.tsx b/components/Sidebar/sidebar-menu-item.tsx
new file mode 100644
index 00000000..650f49c9
--- /dev/null
+++ b/components/Sidebar/sidebar-menu-item.tsx
@@ -0,0 +1,34 @@
+import Link from "next/link";
+import React from "react";
+import { UsersIcon } from "@heroicons/react/24/solid";
+import { ChartBarSquareIcon } from "@heroicons/react/24/outline";
+import clsx from "clsx";
+
+interface MenuItemProps {
+  title: string;
+  icon?: React.ReactNode;
+  type?: "repo" | "list";
+  href: string;
+  isActive?: boolean;
+}
+const SidebarMenuItem = ({ title, icon, type, href, isActive }: MenuItemProps) => {
+  const getIcon = (type: "repo" | "list") => {
+    switch (type) {
+      case "list":
+        return <UsersIcon className={clsx("w-5 h-5 text-slate-400", isActive && "text-slate-700")} />;
+      case "repo":
+        return <ChartBarSquareIcon className={clsx("w-5 h-5 text-slate-400", isActive && "text-slate-700")} />;
+    }
+  };
+
+  return (
+    <li className={clsx("list-none py-2 px-3 rounded-md", isActive ? "bg-slate-100" : "")}>
+      <Link href={href} className=" flex gap-2 items-center">
+        {type && !icon ? getIcon(type) : icon}
+        <span className={clsx("text-slate-700 font-medium", isActive && "text-slate-800")}>{title}</span>
+      </Link>
+    </li>
+  );
+};
+
+export default SidebarMenuItem;
diff --git a/components/Sidebar/sidebar-wrapper.stories.tsx b/components/Sidebar/sidebar-wrapper.stories.tsx
new file mode 100644
index 00000000..3352d231
--- /dev/null
+++ b/components/Sidebar/sidebar-wrapper.stories.tsx
@@ -0,0 +1,77 @@
+import { StoryObj, Meta } from "@storybook/react";
+import SidebarWrapper from "./sidebar-wrapper";
+import SidebarMenuItem from "./sidebar-menu-item";
+import MenuHeader from "./sidebar-menu-header";
+import SidebarGroupWrapper from "./sidebar-group-wrapper";
+
+const meta: Meta<typeof SidebarWrapper> = {
+  title: "Design System/Sidebar/SidebarWrapper",
+  component: SidebarWrapper,
+};
+
+export default meta;
+
+type Story = StoryObj<typeof SidebarWrapper>;
+
+export const Default: Story = {
+  args: {
+    children: (
+      <>
+        <MenuHeader>Your insights</MenuHeader>
+        <SidebarGroupWrapper>
+          <SidebarMenuItem title="Dashboard" href="/dashboard" type="list" />
+          <SidebarMenuItem title="Repositories" href="/repositories" type="repo" />
+        </SidebarGroupWrapper>
+
+        <MenuHeader>Shared with you</MenuHeader>
+        <SidebarGroupWrapper>
+          <SidebarMenuItem title="Javascript frameworks" href="/community" type="repo" />
+          <SidebarMenuItem title="Staff Picks" href="/trending" type="repo" />
+          <SidebarMenuItem title="Potential Hires" href="/trending" type="repo" />
+        </SidebarGroupWrapper>
+      </>
+    ),
+  },
+};
+
+export const WithActiveItem: Story = {
+  args: {
+    children: (
+      <>
+        <MenuHeader>Your insights</MenuHeader>
+        <SidebarGroupWrapper>
+          <SidebarMenuItem title="Dashboard" href="/dashboard" type="list" isActive />
+          <SidebarMenuItem title="Repositories" href="/repositories" type="repo" />
+        </SidebarGroupWrapper>
+
+        <MenuHeader>Shared with you</MenuHeader>
+        <SidebarGroupWrapper>
+          <SidebarMenuItem title="Javascript frameworks" href="/community" type="repo" />
+          <SidebarMenuItem title="Staff Picks" href="/trending" type="repo" />
+          <SidebarMenuItem title="Potential Hires" href="/trending" type="repo" />
+        </SidebarGroupWrapper>
+      </>
+    ),
+  },
+};
+
+export const WithLoading: Story = {
+  args: {
+    children: (
+      <>
+        <MenuHeader>Your insights</MenuHeader>
+        <SidebarGroupWrapper>
+          <SidebarMenuItem title="Dashboard" href="/dashboard" type="list" />
+          <SidebarMenuItem title="Repositories" href="/repositories" type="repo" />
+        </SidebarGroupWrapper>
+
+        <MenuHeader>Shared with you</MenuHeader>
+        <SidebarGroupWrapper isLoading>
+          <SidebarMenuItem title="Javascript frameworks" href="/community" type="repo" />
+          <SidebarMenuItem title="Staff Picks" href="/trending" type="repo" />
+          <SidebarMenuItem title="Potential Hires" href="/trending" type="repo" />
+        </SidebarGroupWrapper>
+      </>
+    ),
+  },
+};
diff --git a/components/Sidebar/sidebar-wrapper.tsx b/components/Sidebar/sidebar-wrapper.tsx
new file mode 100644
index 00000000..8aa45091
--- /dev/null
+++ b/components/Sidebar/sidebar-wrapper.tsx
@@ -0,0 +1,26 @@
+import React from "react";
+
+import { LifebuoyIcon, Cog8ToothIcon } from "@heroicons/react/24/outline";
+import SidebarMenuItem from "./sidebar-menu-item";
+
+interface SidebarProps {
+  children: React.ReactNode;
+}
+
+const SidebarWrapper = ({ children }: SidebarProps) => {
+  return (
+    <div className="bg-white relative w-full md:w-1/5 px-3 py-4 flex flex-col gap-8 min-h-[calc(100vh-40px)]">
+      {children}
+      <div className="absolute flex flex-col bottom-0">
+        <SidebarMenuItem title="Support" href="/logout" icon={<LifebuoyIcon className="w-5 h-5 text-slate-400" />} />
+        <SidebarMenuItem
+          title="Settings"
+          href="/settings"
+          icon={<Cog8ToothIcon className="w-5 h-5 text-slate-400" />}
+        />
+      </div>
+    </div>
+  );
+};
+
+export default SidebarWrapper;
diff --git a/components/atoms/SkeletonLoader/skeleton-wrapper.tsx b/components/atoms/SkeletonLoader/skeleton-wrapper.tsx
index 5bbe384e..f5c12833 100644
--- a/components/atoms/SkeletonLoader/skeleton-wrapper.tsx
+++ b/components/atoms/SkeletonLoader/skeleton-wrapper.tsx
@@ -3,20 +3,24 @@ import Skeleton from "react-loading-skeleton";
 interface SkeletonWrapperProps {
   classNames?: string;
   count?: number;
-  height: number;
+  height?: number;
   width?: number;
   radius?: number;
 }
 
-const SkeletonWrapper = ({ classNames, count, width, height, radius }: SkeletonWrapperProps): JSX.Element => {
-  const skeletonArray = Array(count || 1).fill(true);
+const SkeletonWrapper = ({ classNames, count = 1, width, height, radius }: SkeletonWrapperProps): JSX.Element => {
+  const skeletonArray = Array(count).fill(true);
   return (
     <>
-      {skeletonArray.map((skeleton, index) => (
-        <div className={classNames || ""} key={index}>
-          <Skeleton height={height} width={width} borderRadius={radius} count={1} />
-        </div>
-      ))}
+      {skeletonArray.map((_, index) => {
+        return !height ? (
+          <div className="react-loading-skeleton" />
+        ) : (
+          <div className={classNames}>
+            <Skeleton height={height} width={width} borderRadius={radius} count={1} />
+          </div>
+        );
+      })}
     </>
   );
 };
diff --git a/components/molecules/ContributionsTreemap/contributions-treemap.tsx b/components/molecules/ContributionsTreemap/contributions-treemap.tsx
deleted file mode 100644
index fe923875..00000000
--- a/components/molecules/ContributionsTreemap/contributions-treemap.tsx
+++ /dev/null
@@ -1,82 +0,0 @@
-import { useSpring, animated } from "@react-spring/web";
-import dynamic from "next/dynamic";
-import { Datum } from "@nivo/line";
-import Card from "components/atoms/Card/card";
-import { SpecialNode } from "components/molecules/TreemapPrototype/special-node";
-import { ContributorNode } from "components/molecules/TreemapPrototype/contributor-node";
-import ClientOnly from "components/atoms/ClientOnly/client-only";
-import type { NodeMouseEventHandler, NodeProps, TreeMapCommonProps } from "@nivo/treemap";
-
-interface ContributionsTreemapProps {
-  data: any;
-  color: TreeMapCommonProps<Datum>["colors"];
-  onClick: NodeMouseEventHandler<object>;
-  repoId: number | null;
-  setRepoId: (repoId: number | null) => void;
-}
-
-function BreadCrumb({ isActive, ...rest }: any) {
-  const separatorStyle = useSpring(isActive ? { opacity: 1 } : { opacity: 0 });
-  const textStyle = useSpring(isActive ? { opacity: 1, translateX: 0 } : { opacity: 0, translateX: 100 });
-
-  return (
-    <>
-      <animated.div className={"px-1"} style={separatorStyle}>
-        {"/"}
-      </animated.div>
-      <animated.div style={textStyle} {...rest} />
-    </>
-  );
-}
-
-const ResponsiveTreeMapHtml = dynamic(() => import("@nivo/treemap").then((module) => module.ResponsiveTreeMapHtml), {
-  ssr: false,
-});
-
-export const ContributionsTreemap = ({ setRepoId, repoId, data, color, onClick }: ContributionsTreemapProps) => {
-  return (
-    <Card className="grid place-content-stretch">
-      <div className="grid">
-        {/* Label: Text */}
-        <h2 className="font-medium text-lg text-slate-900 mb-2 flex">
-          <button className="cursor-pointer" onClick={() => setRepoId(null)}>
-            Repos
-          </button>
-          <div> </div>
-          <BreadCrumb isActive={repoId !== null}>Contributors</BreadCrumb>
-        </h2>
-        <div className="rounded-md overflow-hidden grid place-content-stretch">
-          <div className="grid" style={{ gridArea: "1 / 1", minHeight: "29rem" }}>
-            <ClientOnly>
-              <ResponsiveTreeMapHtml
-                data={data}
-                tile="squarify"
-                labelSkipSize={12}
-                innerPadding={4}
-                leavesOnly
-                orientLabel={false}
-                nodeComponent={
-                  repoId === null
-                    ? SpecialNode
-                    : // TODO: Sort this out later
-                      (ContributorNode as <Datum extends object>({
-                        node,
-                        animatedProps,
-                        borderWidth,
-                        enableLabel,
-                        labelSkipSize,
-                      }: NodeProps<Datum>) => JSX.Element)
-                }
-                colors={color}
-                nodeOpacity={1}
-                borderWidth={0}
-                onClick={onClick}
-                motionConfig={"default"}
-              />
-            </ClientOnly>
-          </div>
-        </div>
-      </div>
-    </Card>
-  );
-};
diff --git a/components/molecules/ContributorHighlight/contributor-highlight-card.tsx b/components/molecules/ContributorHighlight/contributor-highlight-card.tsx
index 4dffd199..6f38d335 100644
--- a/components/molecules/ContributorHighlight/contributor-highlight-card.tsx
+++ b/components/molecules/ContributorHighlight/contributor-highlight-card.tsx
@@ -121,6 +121,7 @@ const ContributorHighlightCard = ({
   const [addTaggedRepoFormOpen, setAddTaggedRepoFormOpen] = useState(false);
   const [host, setHost] = useState("");
   const [dropdownOpen, setDropdownOpen] = useState(false);
+  const [emojiDropdownOpen, setEmojiDropdownOpen] = useState(false);
   const { follow, unFollow, isError } = useFollowUser(
     dropdownOpen && loggedInUser?.user_metadata.user_name !== user ? user : ""
   );
@@ -620,12 +621,18 @@ const ContributorHighlightCard = ({
       )}
 
       <div className="flex flex-wrap items-center gap-1">
-        <DropdownMenu modal={false}>
-          <DropdownMenuTrigger className="p-1   rounded-full data-[state=open]:bg-light-slate-7">
+        <DropdownMenu modal={false} open={emojiDropdownOpen}>
+          <DropdownMenuTrigger
+            className="p-1 rounded-full data-[state=open]:bg-light-slate-7"
+            onClick={() => setEmojiDropdownOpen(!emojiDropdownOpen)}
+          >
             <HiOutlineEmojiHappy className="w-5 h-5" />
           </DropdownMenuTrigger>
-
-          <DropdownMenuContent className="flex flex-row gap-1 rounded-3xl" side="right">
+          <DropdownMenuContent
+            className="flex flex-row gap-1 rounded-3xl"
+            side="right"
+            onClick={() => setEmojiDropdownOpen(false)}
+          >
             {emojis &&
               emojis.length > 0 &&
               emojis.map(({ id, name }) => (
diff --git a/components/molecules/ContributorListTableRow/contributor-list-table-row.tsx b/components/molecules/ContributorListTableRow/contributor-list-table-row.tsx
index f1bc9976..20fcf260 100644
--- a/components/molecules/ContributorListTableRow/contributor-list-table-row.tsx
+++ b/components/molecules/ContributorListTableRow/contributor-list-table-row.tsx
@@ -12,6 +12,7 @@ import useRepoList from "lib/hooks/useRepoList";
 import { useFetchUser } from "lib/hooks/useFetchUser";
 import Checkbox from "components/atoms/Checkbox/checkbox";
 import { getTopContributorLanguages } from "lib/utils/contributor-utils";
+import { DATA_FALLBACK_VALUE } from "lib/utils/fallback-values";
 import { getActivity } from "../RepoRow/repo-row";
 import DevProfile from "../DevProfile/dev-profile";
 
@@ -86,7 +87,7 @@ const ContributorListTableRow = ({
 
   const repoList = useRepoList(Array.from(new Set(data.map((prData) => prData.full_name))).join(","));
   const contributorLanguageList = user ? getTopContributorLanguages(user) : [];
-  const days = getPullRequestsToDays(data, Number(range || "30"));
+  const days = getPullRequestsToDays(data, Number(range ?? 30));
   const totalPrs = data.length;
   const last30days = [
     {
@@ -158,11 +159,13 @@ const ContributorListTableRow = ({
 
           <div className="flex items-center justify-between py-3 border-b">
             <div>Languages</div>
-            {contributorLanguageList && (
-              <p>
+            {contributorLanguageList.length > 0 ? (
+              <div>
                 {firstContributorLanguage && getLanguageAbbreviation(firstContributorLanguage)}
                 {secondContributorLanguage && `, ${getLanguageAbbreviation(secondContributorLanguage)}`}
-              </p>
+              </div>
+            ) : (
+              <div>{DATA_FALLBACK_VALUE}</div>
             )}
           </div>
           <div className="flex items-center justify-between py-3 border-b">
diff --git a/components/molecules/DevCard/dev-card.tsx b/components/molecules/DevCard/dev-card.tsx
index 455844f1..5b4f878d 100644
--- a/components/molecules/DevCard/dev-card.tsx
+++ b/components/molecules/DevCard/dev-card.tsx
@@ -14,6 +14,7 @@ import CardSauceBGSVG from "img/card-sauce-bg.svg";
 import openSaucedImg from "img/openSauced-icon.png";
 import PRIcon from "img/icons/pr-icon.svg";
 import { getRelativeDays } from "lib/utils/date-utils";
+import { DATA_FALLBACK_VALUE } from "lib/utils/fallback-values";
 
 export interface DevCardProps {
   username: string;
@@ -214,7 +215,7 @@ export default function DevCard(props: DevCardProps) {
                 {!props.isLoading ? (
                   <ActivityPill activity={activity} size="small" />
                 ) : (
-                  <div className="text-xs text-slate-300 font-extralight">-</div>
+                  <div className="text-xs text-slate-300 font-extralight">{DATA_FALLBACK_VALUE}</div>
                 )}
               </div>
               <Seperator />
@@ -222,7 +223,7 @@ export default function DevCard(props: DevCardProps) {
                 <div className="text-xs text-slate-300">PRs Velocity</div>
                 <div className="flex items-center ml-auto gap-1">
                   {!props.prVelocity || props.prMergePercentage == undefined ? (
-                    <div className="text-xs text-slate-300 font-extralight">-</div>
+                    <div className="text-xs text-slate-300 font-extralight">{DATA_FALLBACK_VALUE}</div>
                   ) : (
                     <>
                       <div className="text-xs text-slate-300 font-extralight">{getRelativeDays(props.prVelocity)}</div>
diff --git a/components/molecules/InsightHeader/insight-header.tsx b/components/molecules/InsightHeader/insight-header.tsx
index 724a9299..362ce07d 100644
--- a/components/molecules/InsightHeader/insight-header.tsx
+++ b/components/molecules/InsightHeader/insight-header.tsx
@@ -22,10 +22,10 @@ interface InsightHeaderProps {
   insight?: DbUserInsight;
   repositories?: number[];
   insightId: string;
-  isOwner: boolean;
+  canEdit: boolean | undefined;
 }
 
-const InsightHeader = ({ insight, repositories, insightId, isOwner }: InsightHeaderProps): JSX.Element => {
+const InsightHeader = ({ insight, repositories, insightId, canEdit }: InsightHeaderProps): JSX.Element => {
   const router = useRouter();
   const { range } = router.query;
   const { data: repoData, meta: repoMeta } = useRepositories(repositories);
@@ -81,7 +81,7 @@ const InsightHeader = ({ insight, repositories, insightId, isOwner }: InsightHea
         >
           <FiCopy className="mt-1 mr-2" /> Share
         </Button>
-        {isOwner && (
+        {canEdit && (
           <Link href={`/hub/insights/${insightId}/edit`}>
             <Button className="text-xs w-max" variant="primary">
               <FaEdit className="mr-2" /> Edit Page
diff --git a/components/molecules/InsightRow/insight-row.tsx b/components/molecules/InsightRow/insight-row.tsx
index 6f277893..dfe527e9 100644
--- a/components/molecules/InsightRow/insight-row.tsx
+++ b/components/molecules/InsightRow/insight-row.tsx
@@ -4,6 +4,7 @@ import { BsPencilFill } from "react-icons/bs";
 import { MdOutlineArrowForwardIos } from "react-icons/md";
 import { User } from "@supabase/supabase-js";
 
+import clsx from "clsx";
 import { getRelativeDays } from "lib/utils/date-utils";
 import useRepositories from "lib/hooks/api/useRepositories";
 import getRepoInsights from "lib/utils/get-repo-insights";
@@ -17,13 +18,18 @@ import CardRepoList from "../CardRepoList/card-repo-list";
 interface InsightRowProps {
   insight: DbUserInsight;
   user: User | null;
+  isEditable?: boolean;
 }
 
-const InsightRow = ({ insight, user }: InsightRowProps) => {
+const InsightRow = ({ insight, user, isEditable = true }: InsightRowProps) => {
   const repoIds = insight.repos.map((repo) => repo.repo_id);
   const { data: repoData, meta: repoMeta } = useRepositories(repoIds);
   const { open, merged, velocity, total, repoList } = getRepoInsights(repoData);
   const avgOpenPrs = repoData.length > 0 ? Math.round(open / repoData.length) : 0;
+
+  const membership = insight.members?.find((member) => member.user_id === Number(user?.id));
+  const canEdit = membership && ["edit", "admin"].includes(membership.access);
+
   return (
     <Card className="flex flex-col md:flex-row w-full rounded-lg px-4 lg:px-8 py-5 gap-4 lg:gap-2 bg-white items-center">
       <>
@@ -31,18 +37,30 @@ const InsightRow = ({ insight, user }: InsightRowProps) => {
           <div className="flex items-center lg:items-center gap-4 ">
             <div className="w-4 h-4 bg-light-orange-10 rounded-full"></div>
             <div className="text-xl text-light-slate-12 flex justify-between">
-              <Link href={`/pages/${user?.user_metadata.user_name}/${insight.id}/dashboard`}>{insight.name}</Link>
-            </div>
-            <div className="rounded-2xl border px-2 text-light-slate-11">
-              {!!insight.is_public ? "public" : "private"}
+              <Link href={`/pages/${user ? user?.user_metadata.user_name : "anonymous"}/${insight.id}/dashboard`}>
+                {isEditable ? insight.name : `Demo | ${insight.name}`}
+              </Link>
             </div>
-            <div className="flex-1 md:hidden">
-              <span className=" bg-light-slate-1 inline-block rounded-lg p-2.5 border mr-2">
-                <Link href={`/hub/insights/${insight.id}/edit`}>
-                  <BsPencilFill title="Edit Insight Page" className="text-light-slate-10 text-md cursor-pointer w-4" />
-                </Link>
-              </span>
+            <div
+              className={clsx(
+                "rounded-2xl border px-2 text-light-slate-11",
+                !isEditable ? "text-orange-700 bg-orange-50 border-orange-600" : ""
+              )}
+            >
+              {!isEditable ? "demo" : !!insight.is_public ? "public" : "private"}
             </div>
+            {isEditable ? (
+              <div className="flex-1 md:hidden">
+                <span className=" bg-light-slate-1 inline-block rounded-lg p-2.5 border mr-2">
+                  <Link href={`/hub/insights/${insight.id}/edit`}>
+                    <BsPencilFill
+                      title="Edit Insight Page"
+                      className="text-light-slate-10 text-md cursor-pointer w-4"
+                    />
+                  </Link>
+                </span>
+              </div>
+            ) : null}
           </div>
           <div className="w-full truncate">
             {insight.repos && insight.repos.length > 0 && (
@@ -77,7 +95,7 @@ const InsightRow = ({ insight, user }: InsightRowProps) => {
               </div>
             </div>
             <div className="flex-1 hidden md:flex  justify-end">
-              {(user?.user_metadata.sub && Number(user?.user_metadata.sub) === Number(insight.user_id)) ||
+              {canEdit ||
                 (!insight.is_featured && (
                   <Link href={`/hub/insights/${insight.id}/edit`}>
                     <span className=" bg-light-slate-1 inline-block rounded-lg p-2.5 border mr-2 cursor-pointer">
@@ -85,7 +103,7 @@ const InsightRow = ({ insight, user }: InsightRowProps) => {
                     </span>
                   </Link>
                 ))}
-              <Link href={`/pages/${user?.user_metadata.user_name}/${insight.id}/dashboard`}>
+              <Link href={`/pages/${user ? user?.user_metadata.user_name : "anonymous"}/${insight.id}/dashboard`}>
                 <span className=" bg-light-slate-1 inline-block rounded-lg p-2.5 border cursor-pointer">
                   <MdOutlineArrowForwardIos title="Go To Insight Page" className="text-light-slate-10 text-lg" />
                 </span>
diff --git a/components/molecules/ListCard/list-card.tsx b/components/molecules/ListCard/list-card.tsx
index ab10a60c..ffdc46e9 100644
--- a/components/molecules/ListCard/list-card.tsx
+++ b/components/molecules/ListCard/list-card.tsx
@@ -2,6 +2,7 @@ import React from "react";
 import Link from "next/link";
 import { MdOutlineArrowForwardIos } from "react-icons/md";
 import { RiDeleteBinLine } from "react-icons/ri";
+import clsx from "clsx";
 import Text from "components/atoms/Typography/text";
 import { useFetchListContributors } from "lib/hooks/useList";
 import Card from "components/atoms/Card/card";
@@ -9,7 +10,7 @@ import StackedAvatar, { Contributor } from "../StackedAvatar/stacked-avatar";
 
 interface ListCardProps {
   list: DbUserList;
-  handleOnDeleteClick: (listName: string, listId: string) => void;
+  handleOnDeleteClick?: (listName: string, listId: string) => void;
 }
 const ListCard = ({ list, handleOnDeleteClick }: ListCardProps) => {
   const { data: contributors, meta } = useFetchListContributors(list.id);
@@ -27,7 +28,14 @@ const ListCard = ({ list, handleOnDeleteClick }: ListCardProps) => {
             <div className="flex justify-between text-xl text-light-slate-12">
               <Link href={`/lists/${list.id}/overview`}>{list.name}</Link>
             </div>
-            <div className="px-2 border rounded-2xl text-light-slate-11">{!!list.is_public ? "public" : "private"}</div>
+            <div
+              className={clsx(
+                "px-2 border rounded-2xl text-light-slate-11",
+                !handleOnDeleteClick ? "text-orange-700 bg-orange-50 border-orange-600" : ""
+              )}
+            >
+              {handleOnDeleteClick ? (!!list.is_public ? "public" : "private") : "demo"}
+            </div>
           </div>
         </div>
         <div>
@@ -43,13 +51,15 @@ const ListCard = ({ list, handleOnDeleteClick }: ListCardProps) => {
             </div>
             <div className="justify-end flex-1 hidden md:flex">
               {/* Delete button */}
-              <button
-                onClick={() => handleOnDeleteClick(list.name, list.id)}
-                className="inline-block p-3 mr-2 border rounded-lg cursor-pointer bg-light-slate-1"
-                type="button"
-              >
-                <RiDeleteBinLine title="Delete List" className="text-lg text-light-slate-10" />
-              </button>
+              {handleOnDeleteClick && (
+                <button
+                  onClick={() => handleOnDeleteClick(list.name, list.id)}
+                  className="inline-block p-3 mr-2 border rounded-lg cursor-pointer bg-light-slate-1"
+                  type="button"
+                >
+                  <RiDeleteBinLine title="Delete List" className="text-lg text-light-slate-10" />
+                </button>
+              )}
               <Link
                 className="inline-block p-3 mr-2 border rounded-lg cursor-pointer bg-light-slate-1"
                 href={`/lists/${list.id}/overview`}
diff --git a/components/molecules/StackedAvatar/stacked-avatar.tsx b/components/molecules/StackedAvatar/stacked-avatar.tsx
index ffe8f730..f221e22b 100644
--- a/components/molecules/StackedAvatar/stacked-avatar.tsx
+++ b/components/molecules/StackedAvatar/stacked-avatar.tsx
@@ -4,6 +4,7 @@ import clsx from "clsx";
 import AvatarHoverCard from "components/atoms/Avatar/avatar-hover-card";
 
 import useInsight from "lib/hooks/useInsight";
+import { DATA_FALLBACK_VALUE } from "lib/utils/fallback-values";
 
 export type Contributor = { host_login: string };
 
@@ -23,7 +24,7 @@ const StackedAvatar = ({ contributors, visibleQuantity = 5, classNames }: Stacke
   if (isError) {
     // eslint-disable-next-line no-console
     console.log("Error fetching insight", isError);
-    return <div>-</div>;
+    return <div>{DATA_FALLBACK_VALUE}</div>;
   }
 
   return (
diff --git a/components/molecules/TableHeader/table-header.tsx b/components/molecules/TableHeader/table-header.tsx
index 03474c12..7d7e6b7a 100644
--- a/components/molecules/TableHeader/table-header.tsx
+++ b/components/molecules/TableHeader/table-header.tsx
@@ -8,6 +8,7 @@ import Title from "components/atoms/Typography/title";
 import LimitSelect, { LimitSelectMap } from "components/atoms/Select/limit-select";
 import LayoutToggle, { ToggleValue } from "components/atoms/LayoutToggle/layout-toggle";
 import { setQueryParams } from "lib/utils/query-params";
+import ClientOnly from "components/atoms/ClientOnly/client-only";
 import PaginationResult from "../PaginationResults/pagination-result";
 
 interface TableHeaderProps {
@@ -69,12 +70,14 @@ const TableHeader = ({ title, metaInfo, entity, onSearch, layout, onLayoutToggle
         ) : (
           ""
         )}
-        <PaginationResult
-          total={metaInfo.itemCount}
-          className="hidden !translate-y-[2px]  md:inline-flex"
-          metaInfo={metaInfo}
-          entity={entity}
-        />
+        <ClientOnly>
+          <PaginationResult
+            total={metaInfo.itemCount}
+            className="hidden !translate-y-[2px]  md:inline-flex"
+            metaInfo={metaInfo}
+            entity={entity}
+          />
+        </ClientOnly>
       </div>
       <div className="flex flex-col-reverse items-start gap-3 md:flex-row md:items-end ">
         {layout ? (
diff --git a/components/molecules/TreemapPrototype/data.ts b/components/molecules/TreemapPrototype/data.ts
deleted file mode 100644
index c443aa2a..00000000
--- a/components/molecules/TreemapPrototype/data.ts
+++ /dev/null
@@ -1,421 +0,0 @@
-export const data = {
-  name: "nivo",
-  color: "hsl(189, 70%, 50%)",
-  children: [
-    {
-      name: "viz",
-      color: "hsl(261, 70%, 50%)",
-      children: [
-        {
-          name: "stack",
-          color: "hsl(5, 70%, 50%)",
-          children: [
-            {
-              name: "cchart",
-              color: "hsl(138, 70%, 50%)",
-              loc: 112734,
-            },
-            {
-              name: "xAxis",
-              color: "hsl(239, 70%, 50%)",
-              loc: 71469,
-            },
-            {
-              name: "yAxis",
-              color: "hsl(286, 70%, 50%)",
-              loc: 47029,
-            },
-            {
-              name: "layers",
-              color: "hsl(345, 70%, 50%)",
-              loc: 154411,
-            },
-          ],
-        },
-        {
-          name: "ppie",
-          color: "hsl(72, 70%, 50%)",
-          children: [
-            {
-              name: "chart",
-              color: "hsl(337, 70%, 50%)",
-              children: [
-                {
-                  name: "pie",
-                  color: "hsl(228, 70%, 50%)",
-                  children: [
-                    {
-                      name: "outline",
-                      color: "hsl(195, 70%, 50%)",
-                      loc: 93291,
-                    },
-                    {
-                      name: "slices",
-                      color: "hsl(1, 70%, 50%)",
-                      loc: 74503,
-                    },
-                    {
-                      name: "bbox",
-                      color: "hsl(344, 70%, 50%)",
-                      loc: 93284,
-                    },
-                  ],
-                },
-                {
-                  name: "donut",
-                  color: "hsl(51, 70%, 50%)",
-                  loc: 148773,
-                },
-                {
-                  name: "gauge",
-                  color: "hsl(24, 70%, 50%)",
-                  loc: 172515,
-                },
-              ],
-            },
-            {
-              name: "legends",
-              color: "hsl(236, 70%, 50%)",
-              loc: 181781,
-            },
-          ],
-        },
-      ],
-    },
-    {
-      name: "colors",
-      color: "hsl(326, 70%, 50%)",
-      children: [
-        {
-          name: "rgb",
-          color: "hsl(11, 70%, 50%)",
-          loc: 199524,
-        },
-        {
-          name: "hsl",
-          color: "hsl(152, 70%, 50%)",
-          loc: 46649,
-        },
-      ],
-    },
-    {
-      name: "utils",
-      color: "hsl(205, 70%, 50%)",
-      children: [
-        {
-          name: "randomize",
-          color: "hsl(247, 70%, 50%)",
-          loc: 166728,
-        },
-        {
-          name: "resetClock",
-          color: "hsl(121, 70%, 50%)",
-          loc: 117624,
-        },
-        {
-          name: "noop",
-          color: "hsl(293, 70%, 50%)",
-          loc: 50104,
-        },
-        {
-          name: "tick",
-          color: "hsl(136, 70%, 50%)",
-          loc: 35188,
-        },
-        {
-          name: "forceGC",
-          color: "hsl(259, 70%, 50%)",
-          loc: 19014,
-        },
-        {
-          name: "stackTrace",
-          color: "hsl(296, 70%, 50%)",
-          loc: 152117,
-        },
-        {
-          name: "dbg",
-          color: "hsl(272, 70%, 50%)",
-          loc: 187021,
-        },
-      ],
-    },
-    {
-      name: "generators",
-      color: "hsl(105, 70%, 50%)",
-      children: [
-        {
-          name: "address",
-          color: "hsl(212, 70%, 50%)",
-          loc: 106084,
-        },
-        {
-          name: "city",
-          color: "hsl(86, 70%, 50%)",
-          loc: 97735,
-        },
-        {
-          name: "animal",
-          color: "hsl(228, 70%, 50%)",
-          loc: 129734,
-        },
-        {
-          name: "movie",
-          color: "hsl(128, 70%, 50%)",
-          loc: 115500,
-        },
-        {
-          name: "user",
-          color: "hsl(130, 70%, 50%)",
-          loc: 96608,
-        },
-      ],
-    },
-    {
-      name: "set",
-      color: "hsl(250, 70%, 50%)",
-      children: [
-        {
-          name: "clone",
-          color: "hsl(144, 70%, 50%)",
-          loc: 56957,
-        },
-        {
-          name: "intersect",
-          color: "hsl(119, 70%, 50%)",
-          loc: 116255,
-        },
-        {
-          name: "merge",
-          color: "hsl(329, 70%, 50%)",
-          loc: 132810,
-        },
-        {
-          name: "reverse",
-          color: "hsl(146, 70%, 50%)",
-          loc: 179227,
-        },
-        {
-          name: "toArray",
-          color: "hsl(153, 70%, 50%)",
-          loc: 82125,
-        },
-        {
-          name: "toObject",
-          color: "hsl(281, 70%, 50%)",
-          loc: 84641,
-        },
-        {
-          name: "fromCSV",
-          color: "hsl(198, 70%, 50%)",
-          loc: 137308,
-        },
-        {
-          name: "slice",
-          color: "hsl(255, 70%, 50%)",
-          loc: 148517,
-        },
-        {
-          name: "append",
-          color: "hsl(81, 70%, 50%)",
-          loc: 151057,
-        },
-        {
-          name: "prepend",
-          color: "hsl(298, 70%, 50%)",
-          loc: 33588,
-        },
-        {
-          name: "shuffle",
-          color: "hsl(69, 70%, 50%)",
-          loc: 113555,
-        },
-        {
-          name: "pick",
-          color: "hsl(19, 70%, 50%)",
-          loc: 125108,
-        },
-        {
-          name: "plouc",
-          color: "hsl(148, 70%, 50%)",
-          loc: 177573,
-        },
-      ],
-    },
-    {
-      name: "text",
-      color: "hsl(237, 70%, 50%)",
-      children: [
-        {
-          name: "trim",
-          color: "hsl(92, 70%, 50%)",
-          loc: 192414,
-        },
-        {
-          name: "slugify",
-          color: "hsl(313, 70%, 50%)",
-          loc: 98323,
-        },
-        {
-          name: "snakeCase",
-          color: "hsl(311, 70%, 50%)",
-          loc: 140702,
-        },
-        {
-          name: "camelCase",
-          color: "hsl(31, 70%, 50%)",
-          loc: 189412,
-        },
-        {
-          name: "repeat",
-          color: "hsl(42, 70%, 50%)",
-          loc: 177940,
-        },
-        {
-          name: "padLeft",
-          color: "hsl(70, 70%, 50%)",
-          loc: 94736,
-        },
-        {
-          name: "padRight",
-          color: "hsl(251, 70%, 50%)",
-          loc: 161758,
-        },
-        {
-          name: "sanitize",
-          color: "hsl(7, 70%, 50%)",
-          loc: 68324,
-        },
-        {
-          name: "ploucify",
-          color: "hsl(41, 70%, 50%)",
-          loc: 131979,
-        },
-      ],
-    },
-    {
-      name: "misc",
-      color: "hsl(40, 70%, 50%)",
-      children: [
-        {
-          name: "greetings",
-          color: "hsl(271, 70%, 50%)",
-          children: [
-            {
-              name: "hey",
-              color: "hsl(351, 70%, 50%)",
-              loc: 82305,
-            },
-            {
-              name: "HOWDY",
-              color: "hsl(43, 70%, 50%)",
-              loc: 157783,
-            },
-            {
-              name: "aloha",
-              color: "hsl(33, 70%, 50%)",
-              loc: 179847,
-            },
-            {
-              name: "AHOY",
-              color: "hsl(146, 70%, 50%)",
-              loc: 198481,
-            },
-          ],
-        },
-        {
-          name: "other",
-          color: "hsl(79, 70%, 50%)",
-          loc: 117383,
-        },
-        {
-          name: "path",
-          color: "hsl(137, 70%, 50%)",
-          children: [
-            {
-              name: "pathA",
-              color: "hsl(320, 70%, 50%)",
-              loc: 63674,
-            },
-            {
-              name: "pathB",
-              color: "hsl(37, 70%, 50%)",
-              children: [
-                {
-                  name: "pathB1",
-                  color: "hsl(89, 70%, 50%)",
-                  loc: 182356,
-                },
-                {
-                  name: "pathB2",
-                  color: "hsl(93, 70%, 50%)",
-                  loc: 97722,
-                },
-                {
-                  name: "pathB3",
-                  color: "hsl(73, 70%, 50%)",
-                  loc: 58316,
-                },
-                {
-                  name: "pathB4",
-                  color: "hsl(314, 70%, 50%)",
-                  loc: 182338,
-                },
-              ],
-            },
-            {
-              name: "pathC",
-              color: "hsl(302, 70%, 50%)",
-              children: [
-                {
-                  name: "pathC1",
-                  color: "hsl(146, 70%, 50%)",
-                  loc: 39231,
-                },
-                {
-                  name: "pathC2",
-                  color: "hsl(270, 70%, 50%)",
-                  loc: 192574,
-                },
-                {
-                  name: "pathC3",
-                  color: "hsl(312, 70%, 50%)",
-                  loc: 63845,
-                },
-                {
-                  name: "pathC4",
-                  color: "hsl(304, 70%, 50%)",
-                  loc: 61593,
-                },
-                {
-                  name: "pathC5",
-                  color: "hsl(146, 70%, 50%)",
-                  loc: 138936,
-                },
-                {
-                  name: "pathC6",
-                  color: "hsl(279, 70%, 50%)",
-                  loc: 93730,
-                },
-                {
-                  name: "pathC7",
-                  color: "hsl(302, 70%, 50%)",
-                  loc: 10242,
-                },
-                {
-                  name: "pathC8",
-                  color: "hsl(25, 70%, 50%)",
-                  loc: 79281,
-                },
-                {
-                  name: "pathC9",
-                  color: "hsl(135, 70%, 50%)",
-                  loc: 198445,
-                },
-              ],
-            },
-          ],
-        },
-      ],
-    },
-  ],
-};
diff --git a/components/molecules/TreemapPrototype/treemap-prototype.stories.tsx b/components/molecules/TreemapPrototype/treemap-prototype.stories.tsx
deleted file mode 100644
index d54a1d91..00000000
--- a/components/molecules/TreemapPrototype/treemap-prototype.stories.tsx
+++ /dev/null
@@ -1,217 +0,0 @@
-import { ResponsiveTreeMapHtml, NodeMouseEventHandler } from "@nivo/treemap";
-import { useState } from "react";
-import { animated, useSpring } from "@react-spring/web";
-import { ContributorNode } from "components/molecules/TreemapPrototype/contributor-node";
-import Card from "components/atoms/Card/card";
-import { SpecialNode } from "components/molecules/TreemapPrototype/special-node";
-import type { Meta, StoryObj } from "@storybook/react";
-
-const meta = {
-  title: "Design System/Prototypes/Treemap",
-  parameters: {
-    layout: "fullscreen",
-  },
-  decorators: [
-    (Story) => (
-      <div className="grid p-4 bg-slate-50 w-screen h-screen">
-        <Story />
-      </div>
-    ),
-  ],
-} satisfies Meta;
-
-export default meta;
-
-type Story = StoryObj;
-
-const color = "hsla(21, 90%, 48%, 1)";
-const repos = [
-  {
-    id: "/insights",
-    value: 340,
-  },
-  {
-    id: "/hot",
-    value: 120,
-  },
-  {
-    id: "/ai",
-    value: 120,
-  },
-  {
-    id: "/pizza-cli",
-    value: 100,
-  },
-  {
-    id: "/super-secret-special-sauce",
-    value: 84,
-  },
-];
-const contributors = [
-  {
-    id: "foxyblocks",
-    value: 68,
-    color: color,
-  },
-  {
-    id: "codebytere",
-    value: 166,
-    color: color,
-  },
-  {
-    id: "miniak",
-    value: 163,
-    color: color,
-  },
-  {
-    id: "ckerr",
-    value: 115,
-    color: color,
-  },
-  {
-    id: "JeanMeche",
-    value: 84,
-    color: color,
-  },
-  {
-    id: "annacmc",
-    value: 90,
-    color: color,
-  },
-];
-
-export const Repos: Story = {
-  render: () => {
-    const data = {
-      id: "root",
-      color: color,
-      children: repos,
-    };
-    return (
-      <Card className="grid place-content-stretch">
-        <div className="grid">
-          {/* Label: Text */}
-          <div className="text-lg text-slate-900 mb-2">Organizations / Repos</div>
-          <div className="rounded-md overflow-hidden">
-            <ResponsiveTreeMapHtml
-              data={data}
-              tile="squarify"
-              labelSkipSize={12}
-              innerPadding={4}
-              leavesOnly
-              orientLabel={false}
-              nodeOpacity={1}
-              borderWidth={0}
-              colors={color}
-              nodeComponent={SpecialNode}
-              label={(node) => `${node.formattedValue} Contributors`}
-            />
-          </div>
-        </div>
-      </Card>
-    );
-  },
-};
-export const Contributors: Story = {
-  render: () => {
-    const color = "hsla(21, 90%, 48%, 1)";
-    const data = {
-      id: "root",
-      color: color,
-      children: contributors,
-    };
-    return (
-      <Card className="grid place-content-stretch">
-        <div className="grid">
-          {/* Label: Text */}
-          <div className="text-lg text-slate-900 mb-2">Organizations / Repos / Contributors</div>
-          <div className="rounded-md overflow-hidden">
-            <ResponsiveTreeMapHtml
-              data={data}
-              tile="squarify"
-              labelSkipSize={12}
-              innerPadding={4}
-              leavesOnly
-              orientLabel={false}
-              nodeComponent={ContributorNode}
-              colors={color}
-              nodeOpacity={1}
-              borderWidth={0}
-            />
-          </div>
-        </div>
-      </Card>
-    );
-  },
-};
-
-function BreadCrumb({ isActive, ...rest }: any) {
-  const separatorStyle = useSpring(isActive ? { opacity: 1 } : { opacity: 0 });
-  const textStyle = useSpring(isActive ? { opacity: 1, translateX: 0 } : { opacity: 0, translateX: 100 });
-  return (
-    <>
-      <animated.div className={"px-1"} style={separatorStyle}>
-        {"/"}
-      </animated.div>
-      <animated.div style={textStyle} {...rest} />
-    </>
-  );
-}
-
-function TreeTransitionExample() {
-  const [currentLevel, setCurrentLevel] = useState(0);
-
-  const data = {
-    id: "root",
-    color: color,
-    children: repos,
-  };
-  const data2 = {
-    id: "root",
-    color: color,
-    children: contributors,
-  };
-
-  const handleClick: NodeMouseEventHandler<object> = (node, event) => {
-    setCurrentLevel((prev) => prev + 1);
-  };
-
-  return (
-    <Card className="grid place-content-stretch">
-      <div className="grid">
-        {/* Label: Text */}
-        <div className="text-lg text-slate-900 mb-2 flex">
-          <div className="cursor-pointer" onClick={() => setCurrentLevel(0)}>
-            Repos
-          </div>
-          <div> </div>
-          <BreadCrumb isActive={currentLevel > 0}>Contributors</BreadCrumb>
-        </div>
-        <div className="rounded-md overflow-hidden grid place-content-stretch">
-          <div className="grid" style={{ gridArea: "1 / 1" }}>
-            <ResponsiveTreeMapHtml
-              data={currentLevel === 0 ? data : data2}
-              tile="squarify"
-              labelSkipSize={12}
-              innerPadding={4}
-              leavesOnly
-              orientLabel={false}
-              nodeComponent={currentLevel === 0 ? SpecialNode : ContributorNode}
-              colors={color}
-              nodeOpacity={1}
-              borderWidth={0}
-              onClick={handleClick}
-              motionConfig={"default"}
-            />
-          </div>
-        </div>
-      </div>
-    </Card>
-  );
-}
-
-export const TransitionBetweenLevels: Story = {
-  render: () => {
-    return <TreeTransitionExample />;
-  },
-};
diff --git a/components/organisms/ContributorProfilePage/contributor-profile-page.tsx b/components/organisms/ContributorProfilePage/contributor-profile-page.tsx
index d2023146..0eb34adc 100644
--- a/components/organisms/ContributorProfilePage/contributor-profile-page.tsx
+++ b/components/organisms/ContributorProfilePage/contributor-profile-page.tsx
@@ -15,6 +15,7 @@ import ContributorProfileInfo from "components/molecules/ContributorProfileInfo/
 import ProfileLanguageChart from "components/molecules/ProfileLanguageChart/profile-language-chart";
 import useFollowUser from "lib/hooks/useFollowUser";
 import useSupabaseAuth from "lib/hooks/useSupabaseAuth";
+import { DATA_FALLBACK_VALUE } from "lib/utils/fallback-values";
 import ContributorProfileTab from "../ContributorProfileTab/contributor-profile-tab";
 import { ContributorObject } from "../ContributorCard/contributor-card";
 
@@ -181,7 +182,7 @@ const ContributorProfilePage = ({
                             </Text>
                           </div>
                         ) : (
-                          <div className="flex items-end justify-center mt-1"> - </div>
+                          <div className="flex items-end justify-center mt-1">{DATA_FALLBACK_VALUE}</div>
                         )}
                       </div>
                       <div>
@@ -195,7 +196,7 @@ const ContributorProfilePage = ({
                             <Pill color="purple" text={`${prsMergedPercentage}%`} />
                           </div>
                         ) : (
-                          <div className="flex items-end justify-center mt-1"> - </div>
+                          <div className="flex items-end justify-center mt-1">{DATA_FALLBACK_VALUE}</div>
                         )}
                       </div>
                       <div>
@@ -207,7 +208,7 @@ const ContributorProfilePage = ({
                             </Text>
                           </div>
                         ) : (
-                          <div className="flex items-end justify-center mt-1"> - </div>
+                          <div className="flex items-end justify-center mt-1">{DATA_FALLBACK_VALUE}</div>
                         )}
                       </div>
                     </div>
diff --git a/components/organisms/ContributorProfileTab/contributor-profile-tab.tsx b/components/organisms/ContributorProfileTab/contributor-profile-tab.tsx
index dd2401d5..21abac2f 100644
--- a/components/organisms/ContributorProfileTab/contributor-profile-tab.tsx
+++ b/components/organisms/ContributorProfileTab/contributor-profile-tab.tsx
@@ -1,6 +1,6 @@
 import Link from "next/link";
 import Image from "next/image";
-import { useState, useEffect } from "react";
+import { useState } from "react";
 import { useRouter } from "next/router";
 import clsx from "clsx";
 import formatDistanceToNowStrict from "date-fns/formatDistanceToNowStrict";
@@ -33,6 +33,7 @@ import Pagination from "components/molecules/Pagination/pagination";
 import DashContainer from "components/atoms/DashedContainer/DashContainer";
 import SkeletonWrapper from "components/atoms/SkeletonLoader/skeleton-wrapper";
 import { useToast } from "lib/hooks/useToast";
+import { DATA_FALLBACK_VALUE } from "lib/utils/fallback-values";
 import ConnectionRequestsWrapper from "../ConnectionRequestWrapper/connection-requests-wrapper";
 import UserRepositoryRecommendations from "../UserRepositoryRecommendations/user-repository-recommendations";
 
@@ -93,32 +94,16 @@ const ContributorProfileTab = ({
   const { data: emojis } = useFetchAllEmojis();
 
   const router = useRouter();
-  const { tab } = router.query;
+  const { tab = "highlights" } = router.query as { tab: TabKey };
 
   const hasHighlights = highlights ? highlights.length > 0 : false;
   const [inputVisible, setInputVisible] = useState(false);
 
-  const currentTab = (
-    (Object.keys(tabs).includes(tab as string) && tab) || hasHighlights ? "highlights" : "contributions"
-  ) as TabKey;
   function onTabChange(value: string) {
     const tabValue = value as TabKey;
     setQueryParams({ tab: tabValue } satisfies QueryParams);
   }
 
-  useEffect(() => {
-    // Setting the query param "tab" if none exists
-    if (
-      !tab ||
-      !Object.keys(tabs).includes(tab as string) ||
-      (tab === "recommendations" && user_name !== login) ||
-      (tab === "connections" && !receive_collaboration) ||
-      (tab === "connections" && user_name !== login)
-    ) {
-      setQueryParams({ tab: currentTab } satisfies QueryParams);
-    }
-  }, [tab, currentTab]);
-
   const getTabTriggerClassName = (tab: TabKey): string => {
     return clsx(
       "data-[state=active]:border-sauced-orange shrink-0 data-[state=active]:border-b-2 text-lg",
@@ -190,7 +175,7 @@ const ContributorProfileTab = ({
   };
 
   return (
-    <Tabs value={String(router.query.tab)} onValueChange={onTabChange}>
+    <Tabs value={tab} onValueChange={onTabChange}>
       <TabsList className="justify-start w-full overflow-x-auto border-b">
         {(Object.keys(tabs) as TabKey[]).map((tab) => (
           <TabsTrigger key={tab} className={getTabTriggerClassName(tab)} value={tab}>
@@ -381,7 +366,7 @@ const ContributorProfileTab = ({
                     <Text className="!text-lg md:!text-xl lg:!text-2xl !text-black !leading-none">{openPrs} PRs</Text>
                   </div>
                 ) : (
-                  <div className="flex items-end justify-center mt-1"> - </div>
+                  <div className="flex items-end justify-center mt-1">{DATA_FALLBACK_VALUE}</div>
                 )}
               </div>
               <div>
@@ -395,7 +380,7 @@ const ContributorProfileTab = ({
                     <Pill color="purple" text={`${prsMergedPercentage}%`} />
                   </div>
                 ) : (
-                  <div className="flex items-end justify-center mt-1"> - </div>
+                  <div className="flex items-end justify-center mt-1">{DATA_FALLBACK_VALUE}</div>
                 )}
               </div>
               <div>
@@ -407,7 +392,7 @@ const ContributorProfileTab = ({
                     </Text>
                   </div>
                 ) : (
-                  <div className="flex items-end justify-center mt-1"> - </div>
+                  <div className="flex items-end justify-center mt-1">{DATA_FALLBACK_VALUE}</div>
                 )}
               </div>
             </div>
diff --git a/components/organisms/Contributors/contributors.tsx b/components/organisms/Contributors/contributors.tsx
index 170c5a87..cfd66d2d 100644
--- a/components/organisms/Contributors/contributors.tsx
+++ b/components/organisms/Contributors/contributors.tsx
@@ -10,7 +10,7 @@ import TableHeader from "components/molecules/TableHeader/table-header";
 import { calcDistanceFromToday } from "lib/utils/date-utils";
 
 import SkeletonWrapper from "components/atoms/SkeletonLoader/skeleton-wrapper";
-import LimitSelect from "components/atoms/Select/limit-select";
+import LimitSelect, { LimitSelectMap } from "components/atoms/Select/limit-select";
 
 import useContributors from "lib/hooks/api/useContributors";
 import { getAvatarByUsername } from "lib/utils/github";
@@ -23,6 +23,7 @@ import { Command, CommandGroup, CommandInput, CommandItem } from "components/ato
 import { useToast } from "lib/hooks/useToast";
 
 import ClientOnly from "components/atoms/ClientOnly/client-only";
+import { setQueryParams } from "lib/utils/query-params";
 import ContributorCard from "../ContributorCard/contributor-card";
 import ContributorTable from "../ContributorsTable/contributors-table";
 
@@ -32,9 +33,10 @@ interface ContributorProps {
 
 const Contributors = ({ repositories }: ContributorProps): JSX.Element => {
   const router = useRouter();
+  const limit = router.query.limit as string;
   const topic = router.query.pageId as string;
 
-  const { data, meta, setPage, setLimit, isError, isLoading } = useContributors(10, repositories);
+  const { data, meta, setPage, isError, isLoading } = useContributors(Number(limit ?? 10), repositories);
   const { toast } = useToast();
   const [layout, setLayout] = useState<ToggleValue>("list");
   const [selectedContributors, setSelectedContributors] = useState<DbPRContributor[]>([]);
@@ -238,8 +240,9 @@ const Contributors = ({ repositories }: ContributorProps): JSX.Element => {
             { name: "50 per page", value: "50" },
           ]}
           className="!w-36 ml-auto md:hidden overflow-x-hidden"
+          defaultValue={String(limit ?? 10) as LimitSelectMap}
           onChange={function (limit: string): void {
-            setLimit(Number(limit));
+            setQueryParams({ limit });
           }}
         />
 
diff --git a/components/organisms/ContributorsList/contributors-list.tsx b/components/organisms/ContributorsList/contributors-list.tsx
index 80e43bcd..27ae3a7a 100644
--- a/components/organisms/ContributorsList/contributors-list.tsx
+++ b/components/organisms/ContributorsList/contributors-list.tsx
@@ -60,6 +60,7 @@ const ContributorsList = ({ contributors, isLoading, meta, setPage, range }: Con
         layout={layout}
         onLayoutToggle={setLayout}
       />
+
       <ClientOnly>
         {layout !== "grid" ? (
           <>
@@ -70,13 +71,13 @@ const ContributorsList = ({ contributors, isLoading, meta, setPage, range }: Con
           <ContributorCardList contributors={contributors} topic={"*"} range={range ?? 30} />
         )}
       </ClientOnly>
+
       <div className="flex items-center justify-between w-full py-1 md:py-4 md:mt-5">
-        <div>
+        <ClientOnly>
           <div>
             <PaginationResults metaInfo={meta} total={meta.itemCount} entity={"contributors"} />
           </div>
-        </div>
-        <div>
+
           <div className="flex flex-col gap-4">
             <Pagination
               pages={[]}
@@ -91,7 +92,7 @@ const ContributorsList = ({ contributors, isLoading, meta, setPage, range }: Con
               goToPage
             />
           </div>
-        </div>
+        </ClientOnly>
       </div>
     </>
   );
diff --git a/components/organisms/Dashboard/dashboard.tsx b/components/organisms/Dashboard/dashboard.tsx
index f9fc8a97..4a64e468 100644
--- a/components/organisms/Dashboard/dashboard.tsx
+++ b/components/organisms/Dashboard/dashboard.tsx
@@ -71,6 +71,7 @@ const Dashboard = ({ repositories }: DashboardProps): JSX.Element => {
           isLoading={isLoading}
         />
       </section>
+
       <section className="flex flex-col max-w-full gap-4 my-6">
         <Repositories repositories={repositories} />
       </section>
diff --git a/components/organisms/InsightPage/InsightPage.tsx b/components/organisms/InsightPage/InsightPage.tsx
index 7be31ff2..f52aa3ed 100644
--- a/components/organisms/InsightPage/InsightPage.tsx
+++ b/components/organisms/InsightPage/InsightPage.tsx
@@ -21,7 +21,6 @@ import useStore from "lib/store";
 import Error from "components/atoms/Error/Error";
 import Search from "components/atoms/Search/search";
 import { useToast } from "lib/hooks/useToast";
-import { TeamMemberData } from "components/molecules/TeamMembersConfig/team-members-config";
 import useInsightMembers from "lib/hooks/useInsightMembers";
 import { useFetchInsightRecommendedRepositories } from "lib/hooks/useFetchOrgRecommendations";
 import { RepoCardProfileProps } from "components/molecules/RepoCardProfile/repo-card-profile";
@@ -103,16 +102,6 @@ const InsightPage = ({ edit, insight, pageRepos }: InsightPageProps) => {
       avatarUrl: !!member.user_id ? getAvatarById(String(member.user_id)) : "",
     }));
 
-  const insightOwner: TeamMemberData = {
-    insight_id: Number(insight?.id),
-    email: String(insight?.user.email),
-    id: String(insight?.user.id),
-
-    name: String(insight?.user.name || insight?.user.login),
-    avatarUrl: getAvatarByUsername(String(insight?.user.login)),
-    access: "owner",
-  };
-
   // Loading States
   const [deleteLoading, setDeleteLoading] = useState(false);
   const [createLoading, setCreateLoading] = useState(false);
@@ -616,7 +605,7 @@ const InsightPage = ({ edit, insight, pageRepos }: InsightPageProps) => {
               onUpdateMember={(id, access) => updateMember(id, access)}
               onDeleteMember={deleteMember}
               onAddMember={addMember}
-              members={[insightOwner, ...members]}
+              members={[...members]}
             />
           </div>
         )}
diff --git a/components/organisms/Repositories/repositories.tsx b/components/organisms/Repositories/repositories.tsx
index 2727b0c5..681b776d 100644
--- a/components/organisms/Repositories/repositories.tsx
+++ b/components/organisms/Repositories/repositories.tsx
@@ -25,7 +25,7 @@ interface RepositoriesProps {
 const Repositories = ({ repositories }: RepositoriesProps): JSX.Element => {
   const { user, signIn } = useSupabaseAuth();
   const router = useRouter();
-  const { pageId, toolName, selectedFilter, userOrg, range, limit } = router.query;
+  const { pageId, toolName, selectedFilter, userOrg, range = 30, limit = 10 } = router.query;
   const username = userOrg ? user?.user_metadata.user_name : undefined;
   const topic = pageId as string;
 
@@ -130,7 +130,7 @@ const Repositories = ({ repositories }: RepositoriesProps): JSX.Element => {
               <TableTitle>Contributors</TableTitle>
             </div>
             <div className={clsx(classNames.cols.last30days, "hidden xl:flex")}>
-              <TableTitle>Last 30 Days</TableTitle>
+              <TableTitle>Last {range} Days</TableTitle>
             </div>
           </div>
 
diff --git a/components/organisms/TopNav/top-nav.tsx b/components/organisms/TopNav/top-nav.tsx
index 4cc7d440..e26aaddc 100644
--- a/components/organisms/TopNav/top-nav.tsx
+++ b/components/organisms/TopNav/top-nav.tsx
@@ -57,13 +57,11 @@ const Nav = ({ className, name = "Main" }: { className?: string; name?: string }
   return (
     <nav className={className} aria-label={name}>
       <ul className="flex gap-3 md:gap-8 mb-1 ml-2 sm:m-0 w-full sm:w-auto">
-        {!!user && onboarded && (
-          <li>
-            <Link className={`text-sm ${getActiveStyle(router.asPath === "/hub/insights")}`} href={"/hub/insights"}>
-              Insights
-            </Link>
-          </li>
-        )}
+        <li>
+          <Link className={`text-sm ${getActiveStyle(router.asPath === "/hub/insights")}`} href={"/hub/insights"}>
+            Insights
+          </Link>
+        </li>
         <li>
           <Link
             className={`text-sm ${getActiveStyle(router.asPath === `/${userInterest}/dashboard/filter/recent`)}`}
diff --git a/layouts/hub-page.tsx b/layouts/hub-page.tsx
index dc1e77fa..0bb895ed 100644
--- a/layouts/hub-page.tsx
+++ b/layouts/hub-page.tsx
@@ -1,4 +1,4 @@
-import React, { useEffect } from "react";
+import React from "react";
 import { useRouter } from "next/router";
 
 import Footer from "components/organisms/Footer/footer";
@@ -11,8 +11,6 @@ import useNav from "lib/hooks/useNav";
 import useInsight from "lib/hooks/useInsight";
 import useSupabaseAuth from "lib/hooks/useSupabaseAuth";
 import SkeletonWrapper from "components/atoms/SkeletonLoader/skeleton-wrapper";
-import { setQueryParams } from "lib/utils/query-params";
-
 const HubPageLayout = ({ children }: { children: React.ReactNode }) => {
   const router = useRouter();
   const { userId } = useSupabaseAuth();
@@ -21,15 +19,10 @@ const HubPageLayout = ({ children }: { children: React.ReactNode }) => {
   const { data: insight, isLoading, isError } = useInsight(insightId);
   const repositories = insight?.repos.map((repo) => repo.repo_id);
 
-  useEffect(() => {
-    if (router.isReady && !range) {
-      setQueryParams({ range: "30" });
-    }
-  }, [range, router.isReady]);
-
   const { toolList, selectedTool, selectedFilter, userOrg } = useNav(repositories);
 
-  let isOwner = !!(userId && insight && `${userId}` === `${insight.user.id}`);
+  const membership = insight?.members?.find((member) => member.user_id === Number(userId));
+  const canEdit = membership && ["edit", "admin"].includes(membership.access);
 
   return (
     <div className="flex flex-col min-h-screen">
@@ -38,7 +31,7 @@ const HubPageLayout = ({ children }: { children: React.ReactNode }) => {
         <div className="info-container container w-full min-h-[100px]">
           <Header>
             {insight ? (
-              <InsightHeader insight={insight} repositories={repositories} insightId={insightId} isOwner={isOwner} />
+              <InsightHeader insight={insight} repositories={repositories} insightId={insightId} canEdit={canEdit} />
             ) : isLoading ? (
               <div className="flex justify-between w-full h-46">
                 <div className="flex items-center gap-3">
diff --git a/layouts/hub.tsx b/layouts/hub.tsx
index 4e86062e..7a62a478 100644
--- a/layouts/hub.tsx
+++ b/layouts/hub.tsx
@@ -1,27 +1,28 @@
-import React, { useEffect } from "react";
+import React from "react";
 
 import { useRouter } from "next/router";
 import Link from "next/link";
 import clsx from "clsx";
 
-import useSession from "lib/hooks/useSession";
+import Text from "components/atoms/Typography/text";
 import useSupabaseAuth from "lib/hooks/useSupabaseAuth";
-import { supabase } from "lib/utils/supabase";
+import GitHubIcon from "img/icons/github-icon.svg";
 
 import Title from "components/atoms/Typography/title";
 import Search from "components/atoms/Search/search";
 import Button from "components/atoms/Button/button";
+import Icon from "components/atoms/Icon/icon";
 import Footer from "../components/organisms/Footer/footer";
 import TopNav from "../components/organisms/TopNav/top-nav";
 
 const HubLayout = ({ children }: { children: React.ReactNode }) => {
-  const { onboarded } = useSession();
-  const { user } = useSupabaseAuth();
+  const { user, signIn } = useSupabaseAuth();
   const navLinks = [
     { name: "Insights", href: "/hub/insights" },
     { name: "Lists", href: "/hub/lists" },
   ];
   const router = useRouter();
+  const { pathname } = router;
 
   const validatePath = (path: string) => {
     const PATHREGEX = /^\/hub\/(insights|lists)?$/;
@@ -29,25 +30,8 @@ const HubLayout = ({ children }: { children: React.ReactNode }) => {
     return PATHREGEX.test(path);
   };
 
-  useEffect(() => {
-    async function getUser() {
-      try {
-        const currentUser = await supabase.auth.getSession();
-
-        if (!currentUser?.data?.session) {
-          await router.push("/feed");
-        }
-      } catch (e: unknown) {
-        router.push("/feed");
-      }
-    }
-
-    // eslint-disable-next-line no-console
-    getUser().catch(console.error);
-  }, [router, onboarded]);
-
   const getActiveLinkClassNames = (href: string) => {
-    return router.pathname === href ? "text-light-slate-12" : "text-slate-300";
+    return pathname === href ? "text-light-slate-12" : "text-slate-300";
   };
 
   return (
@@ -58,7 +42,7 @@ const HubLayout = ({ children }: { children: React.ReactNode }) => {
           {user ? (
             <>
               <div className="container px-2 mx-auto md:px-16">
-                {validatePath(router.pathname) ? (
+                {validatePath(pathname) ? (
                   <div className="container flex flex-col w-full gap-4 py-2">
                     <Title className="-mb-6 text-base text-sauced-orange">Your pages</Title>
 
@@ -81,7 +65,7 @@ const HubLayout = ({ children }: { children: React.ReactNode }) => {
                         <div className="hidden w-58">
                           <Search placeholder="Search repositories" className="max-w-full" name={"query"} />
                         </div>
-                        {router.pathname.split("/")[2] === "insights" ? (
+                        {pathname.split("/")[2] === "insights" ? (
                           <Button href="/hub/insights/new" variant="primary">
                             New Insight
                           </Button>
@@ -99,7 +83,45 @@ const HubLayout = ({ children }: { children: React.ReactNode }) => {
               </div>
             </>
           ) : (
-            <></>
+            <>
+              {validatePath(pathname) ? (
+                <nav className="flex items-center w-full container px-2 mx-auto md:px-16  gap-4">
+                  <ul className="flex items-center gap-3">
+                    {navLinks.map((link, index) => (
+                      <li key={`hub-nav-${index}-${link.name}`}>
+                        <Link
+                          className={clsx("text-3xl leading-none mx-0", getActiveLinkClassNames(link.href))}
+                          href={link.href}
+                        >
+                          {link.name}
+                        </Link>
+                      </li>
+                    ))}
+                  </ul>
+                </nav>
+              ) : null}
+              <div className="container px-2 mx-auto md:px-16">{children}</div>
+              <div className="flex flex-col items-center justify-center w-full mt-10 gap-4">
+                <Text className="text-2xl font-semibold text-center">
+                  Sign in to create your own {pathname.split("/")[2] === "insights" ? "Insight" : "List"} Pages
+                </Text>
+                <Button
+                  onClick={() => {
+                    signIn({
+                      provider: "github",
+                      options: {
+                        redirectTo: pathname === "/hub/insights" ? "/hub/insights/new" : "/hub/lists/new",
+                      },
+                    });
+                  }}
+                  variant="primary"
+                  className="px-8"
+                >
+                  Connect <span className="hidden sm:inline-block ml-1">with GitHub</span>
+                  <Icon IconImage={GitHubIcon} className="ml-2" />
+                </Button>
+              </div>
+            </>
           )}
         </main>
       </div>
diff --git a/layouts/lists.tsx b/layouts/lists.tsx
index cccfeea5..39450be5 100644
--- a/layouts/lists.tsx
+++ b/layouts/lists.tsx
@@ -27,7 +27,7 @@ const ListPageLayout = ({
   const paths = router.asPath.split("/");
   const selectedTab = paths[3] ?? "overview";
 
-  const tabList = [{ name: "Overview" }, { name: "Activity" }, { name: "Contributors" }];
+  const tabList = [{ name: "Overview" }, { name: "Activity" }];
 
   return (
     <div className="flex flex-col min-h-screen">
diff --git a/lib/hooks/api/useContributionsByProject.ts b/lib/hooks/api/useContributionsByProject.ts
index de0f75ee..abfc725b 100644
--- a/lib/hooks/api/useContributionsByProject.ts
+++ b/lib/hooks/api/useContributionsByProject.ts
@@ -10,7 +10,7 @@ export const useContributionsByProject = ({
   range: number;
   initialData?: DbProjectContributions[];
 }) => {
-  const { data, error } = useSWR<DbProjectContributions[]>(
+  const { data, error, isLoading } = useSWR<DbProjectContributions[]>(
     listId ? `lists/${listId}/stats/contributions-by-project?range=${range}` : null,
     publicApiFetcher as Fetcher<DbProjectContributions[], Error>,
     {
@@ -21,5 +21,6 @@ export const useContributionsByProject = ({
   return {
     data,
     error,
+    isLoading,
   };
 };
diff --git a/lib/hooks/api/useContributors.ts b/lib/hooks/api/useContributors.ts
index 73e63525..e7abae5f 100644
--- a/lib/hooks/api/useContributors.ts
+++ b/lib/hooks/api/useContributors.ts
@@ -18,10 +18,10 @@ interface PaginatedResponse {
  * @param range
  * @returns
  */
-const useContributors = (intialLimit = 10, repoIds: number[] = []) => {
+const useContributors = (limit = 10, repoIds: number[] = []) => {
   const router = useRouter();
   const [page, setPage] = useState(1);
-  const [limit, setLimit] = useState(intialLimit);
+
   const { pageId, selectedFilter, range } = router.query;
   const topic = pageId as string;
   const filterQuery = getFilterQuery(selectedFilter);
@@ -66,7 +66,6 @@ const useContributors = (intialLimit = 10, repoIds: number[] = []) => {
     mutate,
     page,
     setPage,
-    setLimit,
   };
 };
 
diff --git a/lib/hooks/api/useContributorsByProject.ts b/lib/hooks/api/useContributorsByProject.ts
index 9ae0b782..1e8c25a7 100644
--- a/lib/hooks/api/useContributorsByProject.ts
+++ b/lib/hooks/api/useContributorsByProject.ts
@@ -15,7 +15,7 @@ export const useContributorsByProject = (listId: string, range = 30) => {
   const baseEndpoint = `lists/${listId}/stats/top-project-contributions-by-contributor`;
 
   const endpointString = `${baseEndpoint}?${query.toString()}`;
-  const { data, error } = useSWR<DBProjectContributor[]>(
+  const { data, error, isLoading } = useSWR<DBProjectContributor[]>(
     listId && repoId ? endpointString : null,
     publicApiFetcher as Fetcher<DBProjectContributor[], Error>
   );
@@ -25,5 +25,6 @@ export const useContributorsByProject = (listId: string, range = 30) => {
     error,
     setRepoId,
     repoId,
+    isLoading,
   };
 };
diff --git a/lib/hooks/useFetchFeaturedInsights.ts b/lib/hooks/useFetchFeaturedInsights.ts
new file mode 100644
index 00000000..babb484b
--- /dev/null
+++ b/lib/hooks/useFetchFeaturedInsights.ts
@@ -0,0 +1,24 @@
+import useSWR, { Fetcher } from "swr";
+import publicApiFetcher from "lib/utils/public-api-fetcher";
+
+export interface PaginatedInsightsResponse {
+  readonly data: DbUserInsight[];
+  readonly meta: Meta;
+}
+
+const useFetchFeaturedInsights = (shouldFetch = true) => {
+  const { data, error, mutate } = useSWR<PaginatedInsightsResponse, Error>(
+    shouldFetch ? "insights/featured" : null,
+    publicApiFetcher as Fetcher<PaginatedInsightsResponse, Error>
+  );
+
+  return {
+    data: data?.data ?? [],
+    meta: data?.meta ?? { itemCount: 0, limit: 0, page: 0, hasNextPage: false, hasPreviousPage: false, pageCount: 0 },
+    isLoading: !error && !data,
+    isError: !!error && Object.keys(error).length > 0,
+    mutate,
+  };
+};
+
+export default useFetchFeaturedInsights;
diff --git a/lib/hooks/useFetchFeaturedLists.ts b/lib/hooks/useFetchFeaturedLists.ts
new file mode 100644
index 00000000..d3f8cc47
--- /dev/null
+++ b/lib/hooks/useFetchFeaturedLists.ts
@@ -0,0 +1,26 @@
+import useSWR, { Fetcher } from "swr";
+import publicApiFetcher from "lib/utils/public-api-fetcher";
+
+interface PaginatedListResponse {
+  data: DbUserList[];
+  meta: Meta;
+}
+
+const useFetchFeaturedLists = (shouldFetch = true) => {
+  const endpointString = "lists/featured";
+
+  const { data, error, mutate } = useSWR<PaginatedListResponse, Error>(
+    shouldFetch ? endpointString : null,
+    publicApiFetcher as Fetcher<PaginatedListResponse, Error>
+  );
+
+  return {
+    data: data?.data ?? [],
+    isLoading: !error && !data,
+    isError: !!error,
+    meta: data?.meta ?? { itemCount: 0, limit: 0, page: 0, hasNextPage: false, hasPreviousPage: false, pageCount: 0 },
+    mutate,
+  };
+};
+
+export default useFetchFeaturedLists;
diff --git a/lib/hooks/useList.ts b/lib/hooks/useList.ts
index b505d142..1a8713cc 100644
--- a/lib/hooks/useList.ts
+++ b/lib/hooks/useList.ts
@@ -14,7 +14,7 @@ interface PaginatedListContributorsResponse {
   meta: Meta;
 }
 
-const useFetchAllLists = (range = 30) => {
+const useFetchAllLists = (range = 30, shouldFetch = true) => {
   const [page, setPage] = useState(1);
   const [limit, setLimit] = useState(10);
 
@@ -28,7 +28,7 @@ const useFetchAllLists = (range = 30) => {
   const endpointString = `${baseEndpoint}`;
 
   const { data, error, mutate } = useSWR<PaginatedListResponse, Error>(
-    endpointString,
+    shouldFetch ? endpointString : null,
     publicApiFetcher as Fetcher<PaginatedListResponse, Error>
   );
 
diff --git a/lib/hooks/useUserInsights.ts b/lib/hooks/useUserInsights.ts
index c9fb2307..be8fb62e 100644
--- a/lib/hooks/useUserInsights.ts
+++ b/lib/hooks/useUserInsights.ts
@@ -2,12 +2,12 @@ import { useState } from "react";
 import useSWR, { Fetcher } from "swr";
 import publicApiFetcher from "lib/utils/public-api-fetcher";
 
-interface PaginatedInsightsResponse {
+export interface PaginatedInsightsResponse {
   readonly data: DbUserInsight[];
   readonly meta: Meta;
 }
 
-const useUserInsights = () => {
+const useUserInsights = (fetch = true) => {
   const [page, setPage] = useState(1);
   const [limit, setLimit] = useState(10);
 
@@ -18,7 +18,7 @@ const useUserInsights = () => {
   const endpointString = `${baseEndpoint}?${pageQuery}${limitQuery}`;
 
   const { data, error, mutate } = useSWR<PaginatedInsightsResponse, Error>(
-    endpointString,
+    fetch ? endpointString : null,
     publicApiFetcher as Fetcher<PaginatedInsightsResponse, Error>
   );
 
diff --git a/lib/store/index.ts b/lib/store/index.ts
index 9b8a0d71..09226ca6 100644
--- a/lib/store/index.ts
+++ b/lib/store/index.ts
@@ -11,7 +11,6 @@ const initialState: GlobalStateInterface = {
   userId: null,
   hasReports: false,
   openSearch: false,
-  dismissFeaturedInsights: false,
 };
 
 interface AppStore extends GlobalStateInterface {
@@ -32,7 +31,6 @@ interface AppStore extends GlobalStateInterface {
   setUserId: (userId?: number | null) => void;
   setHasReports: (hasReports: boolean) => void;
   setOpenSearch: (openSearch: boolean) => void;
-  setDismissFeaturedInsights: () => void;
 }
 
 const store = create<AppStore>()((set) => ({
@@ -54,7 +52,6 @@ const store = create<AppStore>()((set) => ({
   setUserId: (userId?: number | null) => set((state) => ({ ...state, userId })),
   setHasReports: (hasReports: boolean) => set((state) => ({ ...state, hasReports })),
   setOpenSearch: (openSearch: boolean) => set((state) => ({ ...state, openSearch: openSearch })),
-  setDismissFeaturedInsights: () => set((state) => ({ ...state, dismissFeaturedInsights: true })),
 }));
 
 export default store;
diff --git a/lib/utils/contributor-utils.ts b/lib/utils/contributor-utils.ts
index 3ce64b77..91a5f29d 100644
--- a/lib/utils/contributor-utils.ts
+++ b/lib/utils/contributor-utils.ts
@@ -1,10 +1,6 @@
 export function getTopContributorLanguages(contributor: DbUser) {
-  // some contributors will have empty language objects so we will pull their popular language from the interests field instead of defaulting to nothing
-  const entries = Object.entries<string>(contributor.languages);
-  const languages =
-    entries.length > 0
-      ? entries.map(([language]) => language)
-      : contributor.interests.split(",").filter((interest) => interest !== "");
+  // Note that it's possible for a user to have no languages
+  const languages = Object.entries(contributor.languages).map(([language]) => language);
 
   return languages.sort((a, b) => (a < b ? -1 : 1)).slice(0, 2);
 }
diff --git a/lib/utils/fallback-values.ts b/lib/utils/fallback-values.ts
new file mode 100644
index 00000000..887af435
--- /dev/null
+++ b/lib/utils/fallback-values.ts
@@ -0,0 +1,1 @@
+export const DATA_FALLBACK_VALUE = "-";
diff --git a/lib/utils/get-insight-team-member.ts b/lib/utils/get-insight-team-member.ts
index 87c105a9..c5569e26 100644
--- a/lib/utils/get-insight-team-member.ts
+++ b/lib/utils/get-insight-team-member.ts
@@ -1,4 +1,10 @@
-const isInsightTeamMember = async (insightId: number, bearerToken: string, userId: string) => {
+import { MemberAccess } from "components/molecules/TeamMembersConfig/team-members-config";
+
+const getInsightTeamMemberAccess = async (
+  insightId: number,
+  bearerToken: string,
+  userId: string
+): Promise<MemberAccess | null> => {
   try {
     const teamMembersResponse = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/user/insights/${insightId}/members`, {
       headers: {
@@ -9,13 +15,19 @@ const isInsightTeamMember = async (insightId: number, bearerToken: string, userI
 
     if (teamMembersResponse.ok) {
       const teamMembers: DbInsightMember[] = (await teamMembersResponse.json()).data;
-      return !!teamMembers.find((teamMember) => teamMember.user_id === Number(userId));
+      const teamMember = teamMembers.find((teamMember) => teamMember.user_id === Number(userId));
+
+      if (!teamMember) {
+        return null;
+      }
+
+      return teamMember.access;
     } else {
-      return false;
+      return null;
     }
   } catch (e: unknown) {
-    return false;
+    return null;
   }
 };
 
-export default isInsightTeamMember;
+export default getInsightTeamMemberAccess;
diff --git a/middleware.ts b/middleware.ts
index 7746d5de..c854ddc2 100644
--- a/middleware.ts
+++ b/middleware.ts
@@ -9,7 +9,6 @@ import { pathToRegexp } from "path-to-regexp";
 // prettier-ignore
 const pathsToMatch = [
   "/",
-  "/hub/insights/:path*",
   "/feed/",
   "/user/notifications",
   "/user/settings",
diff --git a/next-types.d.ts b/next-types.d.ts
index 1f1412da..ca935f42 100644
--- a/next-types.d.ts
+++ b/next-types.d.ts
@@ -185,8 +185,6 @@ interface DbInsightMember {
 }
 interface DbUserInsight {
   readonly id: number;
-  readonly user_id: number;
-  readonly user: DbUser;
   readonly name: string;
   readonly is_public: boolean;
   readonly is_favorite: boolean;
@@ -195,6 +193,7 @@ interface DbUserInsight {
   readonly created_at: string;
   readonly updated_at: string;
   readonly repos: DbUserInsightRepo[];
+  readonly members: DbInsightMember[];
 }
 
 interface DbUserInsightRepo {
diff --git a/next.config.js b/next.config.js
index ec8d3be0..d6942db5 100644
--- a/next.config.js
+++ b/next.config.js
@@ -37,6 +37,11 @@ module.exports = {
         destination: "/lists/:listId/overview",
         permanent: true,
       },
+      {
+        source: "/lists/:listId/contributors",
+        destination: "/lists/:listId/overview",
+        permanent: true,
+      },
     ];
   },
 };
diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json
index e6348c1f..42b33c5f 100644
--- a/npm-shrinkwrap.json
+++ b/npm-shrinkwrap.json
@@ -1,12 +1,12 @@
 {
   "name": "@open-sauced/insights",
-  "version": "1.80.0",
+  "version": "1.81.0-beta.8",
   "lockfileVersion": 3,
   "requires": true,
   "packages": {
     "": {
       "name": "@open-sauced/insights",
-      "version": "1.80.0",
+      "version": "1.81.0-beta.8",
       "hasInstallScript": true,
       "license": "Apache 2.0",
       "dependencies": {
diff --git a/package.json b/package.json
index 9fc78a4e..0eaaa79e 100644
--- a/package.json
+++ b/package.json
@@ -2,7 +2,7 @@
   "name": "@open-sauced/insights",
   "description": "🍕The dashboard for open source discovery.",
   "keywords": [],
-  "version": "1.80.0",
+  "version": "1.81.0-beta.8",
   "author": "Brian Douglas <brian@opensauced.pizza>",
   "private": true,
   "license": "Apache 2.0",
diff --git a/pages/_app.tsx b/pages/_app.tsx
index 1a8da782..37fa07c4 100644
--- a/pages/_app.tsx
+++ b/pages/_app.tsx
@@ -104,13 +104,13 @@ function MyApp({ Component, pageProps }: ComponentWithPageLayout) {
       console.log("You are on the browser");
 
       // When initializing, we restore the data from `localStorage` into a map.
-      const map: Map<string, string> = new Map(JSON.parse(localStorage.getItem("app-cache") || "[]"));
+      const map: Map<string, string> = new Map(JSON.parse(localStorage.getItem("app-cache-blue") || "[]"));
 
       // Before unloading the app, we write back all the data into `localStorage`.
       window.addEventListener("beforeunload", () => {
         const appCache = JSON.stringify(Array.from(map.entries()));
         try {
-          localStorage.setItem("app-cache", appCache);
+          localStorage.setItem("app-cache-blue", appCache);
         } catch (error) {
           if (error instanceof Error && error.name === "QuotaExceededError")
             // eslint-disable-next-line no-console
diff --git a/pages/hub/insights/[insightId]/edit.tsx b/pages/hub/insights/[insightId]/edit.tsx
index 4c7f6a53..74570996 100644
--- a/pages/hub/insights/[insightId]/edit.tsx
+++ b/pages/hub/insights/[insightId]/edit.tsx
@@ -27,8 +27,7 @@ const EditInsightPage: WithPageLayout = () => {
     return <>Error</>;
   }
 
-  // if the user is not the owner and they aren't part of the team
-  if (insight && Number(insight.user.id) !== Number(user?.user_metadata.sub) && insightTeamMembersError) {
+  if (insightTeamMembersError) {
     return <>Unauthorized</>;
   }
 
diff --git a/pages/hub/insights/index.tsx b/pages/hub/insights/index.tsx
index a3c97732..e6ae8e44 100644
--- a/pages/hub/insights/index.tsx
+++ b/pages/hub/insights/index.tsx
@@ -11,19 +11,24 @@ import HubLayout from "layouts/hub";
 import { WithPageLayout } from "interfaces/with-page-layout";
 import useUserInsights from "lib/hooks/useUserInsights";
 import useSupabaseAuth from "lib/hooks/useSupabaseAuth";
-import useStore from "lib/store";
 import useSession from "lib/hooks/useSession";
 import { useToast } from "lib/hooks/useToast";
 import Text from "components/atoms/Typography/text";
+import useFetchFeaturedInsights from "lib/hooks/useFetchFeaturedInsights";
+import ClientOnly from "components/atoms/ClientOnly/client-only";
 
 const InsightsHub: WithPageLayout = () => {
   const router = useRouter();
   const { user } = useSupabaseAuth();
-  const store = useStore();
-  const dismissFeaturedInsights = useStore((store) => store.dismissFeaturedInsights);
+
   const { toast } = useToast();
   const { session } = useSession(true);
-  const { data, meta, isError, isLoading, setPage } = useUserInsights();
+  const { data, meta, isError, isLoading, setPage } = useUserInsights(!!user);
+  const {
+    data: featuredInsightsData,
+    isError: featuredInsightsError,
+    isLoading: featuredInsightsLoading,
+  } = useFetchFeaturedInsights(user ? false : true);
 
   function handleView() {
     const insight = data.slice(0, 1).shift();
@@ -34,12 +39,14 @@ const InsightsHub: WithPageLayout = () => {
     const toaster = toast({
       description: "Welcome to your Insights Hub!",
       variant: "success",
+      duration: 10000,
       action: (
         <div className="flex flex-col">
           <div className="flex align-middle">
             <Text>
-              We&apos;ve included a featured Insight Page for you to test out. You can also create your own to get
-              insights on repositories.
+              {user
+                ? "We've included a featured Insight Page for you to test out. You can also create your own to get insights on repositories."
+                : "Try out our Demo Insight page or sign up to create your own"}
             </Text>
           </div>
           <div className="flex flex-start">
@@ -50,40 +57,61 @@ const InsightsHub: WithPageLayout = () => {
             >
               <Text className="pr-2 cursor-pointer">Dismiss</Text>
             </button>
-            <button
-              onClick={() => {
-                toaster && toaster.dismiss();
-                handleView();
-              }}
-            >
-              <Text className="text-orange-500 cursor-pointer">Open Insight Page</Text>
-            </button>
+            {session ? (
+              <button
+                onClick={() => {
+                  toaster && toaster.dismiss();
+                  handleView();
+                }}
+              >
+                <Text className="text-orange-500 cursor-pointer">Open Insight Page</Text>
+              </button>
+            ) : null}
           </div>
         </div>
       ),
     });
 
-    store.setDismissFeaturedInsights();
+    localStorage.setItem("dismissFeaturedInsights", "true");
   }
 
   useEffect(() => {
-    if (session && session.insights_count === 0 && !dismissFeaturedInsights) {
+    if (
+      (session && session.insights_count === 0 && !localStorage.getItem("dismissFeaturedInsights")) ||
+      (!session && !localStorage.getItem("dismissFeaturedInsights"))
+    ) {
       openInsightToast();
     }
-  }, [session, user]);
+  }, [session]);
 
   return (
     <>
-      <section className="flex flex-col gap-4">
-        {isLoading ? (
-          <SkeletonWrapper count={3} classNames="w-full" height={95} radius={10} />
-        ) : isError ? (
-          "Error..."
-        ) : (
-          data.map((insight) => {
-            return <InsightRow key={`insights_${insight.id}`} user={user} insight={insight} />;
-          })
-        )}
+      <section className="flex flex-col gap-4 pt-4">
+        {user ? (
+          <>
+            {session && isLoading ? (
+              <SkeletonWrapper count={3} classNames="w-full" height={95} radius={10} />
+            ) : isError ? (
+              "Error..."
+            ) : (
+              data.map((insight) => {
+                return <InsightRow key={`insights_${insight.id}`} user={user} insight={insight} />;
+              })
+            )}
+          </>
+        ) : null}
+
+        <ClientOnly>
+          {!session && featuredInsightsLoading ? (
+            <SkeletonWrapper count={1} classNames="w-full" height={95} radius={10} />
+          ) : featuredInsightsError ? (
+            "Error..."
+          ) : (
+            featuredInsightsData.map((insight) => {
+              return <InsightRow key={`insights_${insight.id}`} user={user} insight={insight} isEditable={false} />;
+            })
+          )}
+        </ClientOnly>
       </section>
 
       <div
@@ -110,7 +138,6 @@ const InsightsHub: WithPageLayout = () => {
 };
 
 InsightsHub.PageLayout = HubLayout;
-InsightsHub.isPrivateRoute = true;
 InsightsHub.SEO = {
   title: "Insights Hub | Open Sauced Insights",
 };
diff --git a/pages/hub/lists/index.tsx b/pages/hub/lists/index.tsx
index f0089118..9ed2c6e8 100644
--- a/pages/hub/lists/index.tsx
+++ b/pages/hub/lists/index.tsx
@@ -17,11 +17,15 @@ import { useToast } from "lib/hooks/useToast";
 
 import { useFetchAllLists } from "lib/hooks/useList";
 import useSupabaseAuth from "lib/hooks/useSupabaseAuth";
+import useFetchFeaturedLists from "lib/hooks/useFetchFeaturedLists";
 
 const ListsHub: WithPageLayout = () => {
-  const { data, isLoading, meta, setPage, mutate } = useFetchAllLists();
-  const { toast } = useToast();
   const { sessionToken } = useSupabaseAuth();
+  const { data, isLoading, meta, setPage, mutate } = useFetchAllLists(30, !!sessionToken);
+  const { data: featuredListsData, isLoading: featuredListsLoading } = useFetchFeaturedLists(
+    sessionToken ? false : true
+  );
+  const { toast } = useToast();
   const [isDeleteOpen, setIsDeleteOpen] = useState(false);
   const [disabled, setDisabled] = useState(true);
   const [deleteLoading, setDeleteLoading] = useState(false);
@@ -87,11 +91,28 @@ const ListsHub: WithPageLayout = () => {
           ))
         ) : (
           <div className="flex flex-col items-center justify-center w-full gap-4 ">
-            {!isLoading && <Title className="text-2xl">You currently have no lists</Title>}
+            {!isLoading && sessionToken ? <Title className="text-2xl">You currently have no lists</Title> : null}
           </div>
         )}
 
-        {isLoading && <SkeletonWrapper count={3} classNames="w-full" height={95} radius={10} />}
+        {sessionToken && isLoading ? <SkeletonWrapper count={3} classNames="w-full" height={95} radius={10} /> : null}
+
+        {!sessionToken && featuredListsLoading ? (
+          <SkeletonWrapper count={1} classNames="w-full" height={95} radius={10} />
+        ) : null}
+        {featuredListsData.map((list, i) => (
+          <ListCard
+            key={`featured_list_${i}`}
+            list={{
+              id: list.id,
+              user: { login: "bdougie", id: 1, name: "Brian Douglas" },
+              name: `Demo | ${list.name}`,
+              created_at: " ",
+              updated_at: "",
+              is_public: list.is_public,
+            }}
+          />
+        ))}
       </section>
       <div
         className={clsx("py-1 md:py-4 flex w-full md:mt-5 justify-between items-center", {
diff --git a/pages/lists/[listId]/activity.tsx b/pages/lists/[listId]/activity.tsx
index ca821560..1faedbfb 100644
--- a/pages/lists/[listId]/activity.tsx
+++ b/pages/lists/[listId]/activity.tsx
@@ -1,13 +1,15 @@
 import { createPagesServerClient } from "@supabase/auth-helpers-nextjs";
 import { GetServerSidePropsContext } from "next";
-import { NodeMouseEventHandler } from "@nivo/treemap";
 import { useRouter } from "next/router";
+import { useState } from "react";
+import { NodeMouseEventHandler } from "@nivo/treemap";
+import { useRef } from "react";
 import Error from "components/atoms/Error/Error";
 import { fetchApiData, validateListPath } from "helpers/fetchApiData";
 import ListPageLayout from "layouts/lists";
 import MostActiveContributorsCard from "components/molecules/MostActiveContributorsCard/most-active-contributors-card";
 import useMostActiveContributors from "lib/hooks/api/useMostActiveContributors";
-import { ContributionsTreemap } from "components/molecules/ContributionsTreemap/contributions-treemap";
+import { ContributionsTreemap } from "components/Graphs/ContributionsTreemap/contributions-treemap";
 import { useContributorsByProject } from "lib/hooks/api/useContributorsByProject";
 import { useContributionsByProject } from "lib/hooks/api/useContributionsByProject";
 import { getGraphColorPalette } from "lib/utils/color-utils";
@@ -15,6 +17,7 @@ import ContributionsEvolutionByType from "components/molecules/ContributionsEvol
 import useContributionsEvolutionByType from "lib/hooks/api/useContributionsByEvolutionType";
 import { FeatureFlagged } from "components/shared/feature-flagged";
 import { FeatureFlag, getAllFeatureFlags } from "lib/utils/server/feature-flags";
+import { OnToggleResizeEventType } from "components/Graphs/shared/graph-resizer";
 
 interface ContributorListPageProps {
   list?: DBList;
@@ -70,6 +73,63 @@ export const getServerSideProps = async (ctx: GetServerSidePropsContext) => {
   };
 };
 
+// if no repoId is set,  want the id
+
+const getTreemapData = ({
+  orgId,
+  repoId,
+  projectData = [],
+  projectContributionsByUser = [],
+}: {
+  orgId: string | null;
+  repoId: number | null;
+  projectData: DbProjectContributions[];
+  projectContributionsByUser: DBProjectContributor[] | undefined;
+}) => {
+  let children;
+
+  switch (true) {
+    case orgId === null:
+      children = Object.values(
+        projectData.reduce((acc, { org_id, contributions }) => {
+          if (!acc[org_id]) {
+            acc[org_id] = { id: org_id, value: 0, orgId: org_id };
+          }
+          acc[org_id].value += contributions;
+          return acc;
+        }, {} as any)
+      );
+      break;
+    case orgId !== null && repoId === null:
+      children = projectData
+        .filter(({ org_id }) => org_id === orgId)
+        .map(({ org_id, project_id, repo_id, contributions }) => {
+          return {
+            id: project_id,
+            value: contributions,
+            repoId: `${repo_id}`,
+          };
+        });
+      break;
+
+    case repoId !== null:
+      children = projectContributionsByUser.map(
+        ({ login, commits, prs_created, prs_reviewed, issues_created, comments }) => {
+          return {
+            id: login,
+            value: commits + prs_created, // Coming soon + prs_reviewed + issues_created + comments,
+          };
+        }
+      );
+      break;
+  }
+
+  return {
+    id: "root",
+    children,
+  };
+};
+
 const ListActivityPage = ({ list, numberOfContributors, isError, isOwner, featureFlags }: ContributorListPageProps) => {
   const router = useRouter();
   const range = router.query.range as string;
@@ -80,47 +140,73 @@ const ListActivityPage = ({ list, numberOfContributors, isError, isOwner, featur
     setContributorType,
     contributorType,
   } = useMostActiveContributors({ listId: list!.id });
-
+  const [orgId, setOrgId] = useState<string | null>(null);
   const {
     setRepoId,
     error,
     data: projectContributionsByUser,
     repoId,
+    isLoading: isLoadingProjectContributionsByUser,
   } = useContributorsByProject(list!.id, Number(range ?? "30"));
+  const [projectId, setProjectId] = useState<string | null>(null);
 
-  const { data: projectData, error: projectDataError } = useContributionsByProject({
+  const {
+    data: projectData = [],
+    error: projectDataError,
+    isLoading: isTreemapLoading,
+  } = useContributionsByProject({
     listId: list!.id,
     range: Number(range ?? "30"),
   });
 
-  const onHandleClick: NodeMouseEventHandler<object> = (node) => {
-    // @ts-ignore TODO: fix this
-    setRepoId(Number(node.data.repoId));
+  const onDrillDown: NodeMouseEventHandler<{ orgId: null; repoId: null; id: string | null }> = (node) => {
+    if (orgId === null) {
+      setOrgId(node.data.orgId);
+      return;
+    } else {
+      setRepoId(Number(node.data.repoId));
+      setProjectId(node.data.id);
+    }
   };
-  const treemapData = {
-    id: "root",
-    children:
-      repoId === null
-        ? (projectData ?? []).map(({ org_id, project_id, repo_id, contributions }) => {
-            return {
-              id: `${org_id}/${project_id}`,
-              value: contributions,
-              repoId: `${repo_id}`,
-            };
-          })
-        : projectContributionsByUser?.map(({ login, commits, prs_created, prs_reviewed, issues_created, comments }) => {
-            return {
-              id: login,
-              value: commits + prs_created, // Coming soon + prs_reviewed + issues_created + comments,
-            };
-          }),
+
+  const onDrillUp = () => {
+    if (repoId !== null) {
+      setRepoId(null);
+      setProjectId(null);
+    } else {
+      setOrgId(null);
+    }
   };
 
+  const treemapData = getTreemapData({ orgId, repoId, projectData, projectContributionsByUser });
+
   const {
     data: evolutionData,
     isError: evolutionError,
     isLoading: isLoadingEvolution,
   } = useContributionsEvolutionByType({ listId: list!.id, range: Number(range ?? "30") });
+  const treemapRef = useRef<HTMLSpanElement>(null);
+  const mostActiveRef = useRef<HTMLSpanElement>(null);
+  const graphResizerLookup = new Map();
+
+  if (treemapRef.current) {
+    graphResizerLookup.set(treemapRef.current, true);
+  }
+
+  if (mostActiveRef.current) {
+    graphResizerLookup.set(mostActiveRef.current, true);
+  }
+
+  const onToggleResize: OnToggleResizeEventType = (checked) => {
+    const treemap = treemapRef.current;
+
+    if (!treemap) {
+      return;
+    }
+
+    treemap.style.gridColumn = checked ? "1 / span 2" : "";
+    treemap.style.gridRow = checked ? "1 / span 2" : "";
+  };
 
   return (
     <ListPageLayout list={list} numberOfContributors={numberOfContributors} isOwner={isOwner}>
@@ -136,13 +222,18 @@ const ListActivityPage = ({ list, numberOfContributors, isError, isOwner, featur
             contributorType={contributorType}
             isLoading={isLoading}
           />
-          <ContributionsTreemap
-            setRepoId={setRepoId}
-            repoId={repoId}
-            onClick={onHandleClick}
-            data={treemapData}
-            color={getGraphColorPalette()}
-          />
+          <span ref={treemapRef} className="relative">
+            <ContributionsTreemap
+              projectId={projectId}
+              orgId={orgId}
+              onDrillDown={onDrillDown as NodeMouseEventHandler<object>}
+              onDrillUp={onDrillUp}
+              data={treemapData}
+              color={getGraphColorPalette()}
+              isLoading={isLoadingProjectContributionsByUser || isTreemapLoading}
+              onToggleResize={onToggleResize}
+            />
+          </span>
           <FeatureFlagged flag="contributions_evolution_by_type" featureFlags={featureFlags}>
             <ContributionsEvolutionByType data={evolutionData} isLoading={isLoadingEvolution} />
           </FeatureFlagged>
diff --git a/pages/lists/[listId]/contributors.tsx b/pages/lists/[listId]/contributors.tsx
deleted file mode 100644
index 3166fbdb..00000000
--- a/pages/lists/[listId]/contributors.tsx
+++ /dev/null
@@ -1,87 +0,0 @@
-import { GetServerSidePropsContext } from "next";
-import { createPagesServerClient } from "@supabase/auth-helpers-nextjs";
-import { useRouter } from "next/router";
-
-import { ErrorBoundary } from "react-error-boundary";
-import ListPageLayout from "layouts/lists";
-import { fetchApiData, validateListPath } from "helpers/fetchApiData";
-import Error from "components/atoms/Error/Error";
-import { useContributorsList } from "lib/hooks/api/useContributorList";
-import ContributorsList from "components/organisms/ContributorsList/contributors-list";
-import { FilterParams } from "./activity";
-
-export const getServerSideProps = async (ctx: GetServerSidePropsContext) => {
-  const supabase = createPagesServerClient(ctx);
-
-  const {
-    data: { session },
-  } = await supabase.auth.getSession();
-  const bearerToken = session ? session.access_token : "";
-
-  const { listId } = ctx.params as FilterParams;
-
-  const { data: list, error } = await fetchApiData<DBList>({
-    path: `lists/${listId}`,
-    bearerToken,
-    pathValidator: validateListPath,
-  });
-
-  if (error?.status === 404) {
-    return {
-      notFound: true,
-    };
-  }
-
-  const userId = Number(session?.user.user_metadata.sub);
-
-  return {
-    props: {
-      list,
-      isError: error,
-      isOwner: list && list.user_id === userId,
-    },
-  };
-};
-
-interface ContributorListPageProps {
-  list?: DBList;
-  isError: boolean;
-  isOwner: boolean;
-}
-
-const ContributorsListPage = ({ list, isError, isOwner }: ContributorListPageProps) => {
-  const router = useRouter();
-  const { range, limit } = router.query;
-
-  const {
-    isLoading,
-    setPage,
-    data: { data: contributors, meta },
-  } = useContributorsList({
-    listId: list?.id,
-    defaultRange: range ? (range as string) : "30",
-    defaultLimit: limit ? (limit as unknown as number) : 10,
-  });
-
-  return (
-    <ListPageLayout list={list} numberOfContributors={meta.itemCount} isOwner={isOwner}>
-      {isError ? (
-        <Error errorMessage="Unable to load list of contributors" />
-      ) : (
-        <ErrorBoundary
-          fallback={<div className="grid place-content-center">Error loading the list of contributors</div>}
-        >
-          <ContributorsList
-            contributors={contributors}
-            meta={meta}
-            isLoading={isLoading}
-            setPage={setPage}
-            range={String(range) ?? "30"}
-          />
-        </ErrorBoundary>
-      )}
-    </ListPageLayout>
-  );
-};
-
-export default ContributorsListPage;
diff --git a/pages/lists/[listId]/overview.tsx b/pages/lists/[listId]/overview.tsx
index e66df84d..78d00649 100644
--- a/pages/lists/[listId]/overview.tsx
+++ b/pages/lists/[listId]/overview.tsx
@@ -1,28 +1,22 @@
-import { useState } from "react";
 import { useRouter } from "next/router";
+import { ErrorBoundary } from "react-error-boundary";
 import { createPagesServerClient } from "@supabase/auth-helpers-nextjs";
 import { GetServerSidePropsContext } from "next";
 import ListPageLayout from "layouts/lists";
 
-import Card from "components/atoms/Card/card";
-import NivoScatterPlot from "components/molecules/NivoScatterChart/nivo-scatter-chart";
-import { ScatterChartDataItems } from "components/molecules/NivoScatterChart/nivo-scatter-chart";
-
-import { useMediaQuery } from "lib/hooks/useMediaQuery";
-import { calcDaysFromToday } from "lib/utils/date-utils";
-import { getAvatarByUsername } from "lib/utils/github";
-import useListContributions from "lib/hooks/useListContributions";
+import Error from "components/atoms/Error/Error";
 import useListStats from "lib/hooks/useListStats";
 import HighlightCard from "components/molecules/HighlightCard/highlight-card";
 import { fetchApiData, validateListPath } from "helpers/fetchApiData";
 import ClientOnly from "components/atoms/ClientOnly/client-only";
-
-type ContributorPrMap = { [contributor: string]: DbRepoPR };
+import { useContributorsList } from "lib/hooks/api/useContributorList";
+import ContributorsList from "components/organisms/ContributorsList/contributors-list";
 
 interface ListsOverviewProps {
   list: DBList;
   numberOfContributors: number;
   isOwner: boolean;
+  isError: boolean;
 }
 
 export const getServerSideProps = async (ctx: GetServerSidePropsContext) => {
@@ -57,14 +51,24 @@ export const getServerSideProps = async (ctx: GetServerSidePropsContext) => {
       list,
       numberOfContributors: data?.meta.itemCount || 0,
       isOwner: list && list.user_id === userId,
+      isError: error || contributorListError,
     },
   };
 };
 
-const ListsOverview = ({ list, numberOfContributors, isOwner }: ListsOverviewProps): JSX.Element => {
+const ListsOverview = ({ list, numberOfContributors, isOwner, isError }: ListsOverviewProps): JSX.Element => {
   const router = useRouter();
-  const { listId } = router.query;
-  const { data: prData, isError: prError } = useListContributions(listId as string);
+  const { listId, range, limit } = router.query;
+
+  const {
+    isLoading,
+    setPage,
+    data: { data: contributors, meta },
+  } = useContributorsList({
+    listId: list?.id,
+    defaultRange: range ? (range as string) : "30",
+    defaultLimit: limit ? (limit as unknown as number) : 10,
+  });
 
   const {
     data: prevAllContributorStats,
@@ -96,55 +100,6 @@ const ListsOverview = ({ list, numberOfContributors, isOwner }: ListsOverviewPro
 
   const allContributorCommits = allContributorStats?.reduce((acc, curr) => acc + curr.commits, 0) || 0;
   const prevAllContributorCommits = prevAllContributorStats?.reduce((acc, curr) => acc + curr.commits, 0) || 0;
-  const [showBots, setShowBots] = useState(false);
-  const isMobile = useMediaQuery("(max-width:720px)");
-
-  let scatterChartData: ScatterChartDataItems[] = [];
-
-  const uniqueContributors: ContributorPrMap = prData.reduce((prs, curr) => {
-    if (prs[curr.author_login]) {
-      prs[curr.author_login].linesCount += Math.abs(curr.additions - curr.deletions);
-    } else {
-      prs[curr.author_login] = { ...curr };
-      prs[curr.author_login].linesCount = Math.abs(curr.additions - curr.deletions);
-    }
-
-    return prs;
-  }, {} as ContributorPrMap);
-
-  const prs = Object.keys(uniqueContributors)
-    .filter((key) => {
-      if (showBots) {
-        return true;
-      }
-
-      return !key.includes("[bot]");
-    })
-    .map((key) => uniqueContributors[key]);
-
-  if (prError) {
-    scatterChartData = [];
-  } else {
-    scatterChartData = prs.map(({ updated_at, linesCount, author_login }) => {
-      const author_image = author_login.includes("[bot]") ? "octocat" : author_login;
-
-      const data = {
-        x: calcDaysFromToday(new Date(updated_at)),
-        y: linesCount,
-        contributor: author_login,
-        image: getAvatarByUsername(author_image, 40),
-      };
-      return data;
-    });
-  }
-
-  const maxFilesModified = scatterChartData.reduce((max, curr) => {
-    const { y } = curr;
-    if (Number(y) > max) {
-      return y as number;
-    }
-    return max;
-  }, 0);
 
   return (
     <ListPageLayout list={list} numberOfContributors={numberOfContributors} isOwner={isOwner} showRangeFilter={false}>
@@ -189,16 +144,21 @@ const ListsOverview = ({ list, numberOfContributors, isOwner }: ListsOverviewPro
           </section>
           <section className="flex flex-col max-w-full gap-4 mb-6 lg:flex-row">
             <div className="flex flex-col w-full">
-              <Card className="w-full">
-                <NivoScatterPlot
-                  title="Contributor Distribution"
-                  showBots={showBots}
-                  setShowBots={setShowBots}
-                  data={[{ id: "Contributors", data: scatterChartData }]}
-                  maxFilesModified={maxFilesModified}
-                  isMobile={isMobile}
-                />
-              </Card>
+              {isError ? (
+                <Error errorMessage="Unable to load list of contributors" />
+              ) : (
+                <ErrorBoundary
+                  fallback={<div className="grid place-content-center">Error loading the list of contributors</div>}
+                >
+                  <ContributorsList
+                    contributors={contributors}
+                    meta={meta}
+                    isLoading={isLoading}
+                    setPage={setPage}
+                    range={String(range ?? "30")}
+                  />
+                </ErrorBoundary>
+              )}
             </div>
           </section>
         </ClientOnly>
diff --git a/pages/pages/[userOrg]/[pageId]/[toolName].tsx b/pages/pages/[userOrg]/[pageId]/[toolName].tsx
index 8057a6bc..c87e8aac 100644
--- a/pages/pages/[userOrg]/[pageId]/[toolName].tsx
+++ b/pages/pages/[userOrg]/[pageId]/[toolName].tsx
@@ -9,7 +9,8 @@ import { WithPageLayout } from "interfaces/with-page-layout";
 import changeCapitalization from "lib/utils/change-capitalization";
 import SEO from "layouts/SEO/SEO";
 import fetchSocialCard from "lib/utils/fetch-social-card";
-import getInsightTeamMember from "lib/utils/get-insight-team-member";
+import getInsightTeamMemberAccess from "lib/utils/get-insight-team-member";
+import { MemberAccess } from "components/molecules/TeamMembersConfig/team-members-config";
 
 interface InsightPageProps {
   insight: DbUserInsight;
@@ -81,15 +82,14 @@ export const getServerSideProps = async (ctx: GetServerSidePropsContext) => {
     };
   }
   const userId = session?.user?.user_metadata.sub as string;
-  const isOwner = !!(userId && insight && `${userId}` === `${insight.user?.id}`);
-  let isTeamMember = false;
+  let teamMemberAccess: MemberAccess | null = null;
 
-  if (!insight.is_public && !isOwner) {
+  if (!insight.is_public) {
     // check if user is insight page team member
-    isTeamMember = await getInsightTeamMember(Number(insightId), bearerToken, userId);
+    teamMemberAccess = await getInsightTeamMemberAccess(Number(insightId), bearerToken, userId);
   }
 
-  if (!insight.is_public && !isOwner && !isTeamMember) {
+  if (!insight.is_public && (!teamMemberAccess || teamMemberAccess === "pending")) {
     return {
       redirect: {
         destination: "/",
diff --git a/pages/pages/[userOrg]/[pageId]/[toolName]/filter/[...selectedFilter].tsx b/pages/pages/[userOrg]/[pageId]/[toolName]/filter/[...selectedFilter].tsx
index 12a72544..62e04264 100644
--- a/pages/pages/[userOrg]/[pageId]/[toolName]/filter/[...selectedFilter].tsx
+++ b/pages/pages/[userOrg]/[pageId]/[toolName]/filter/[...selectedFilter].tsx
@@ -7,7 +7,8 @@ import Tool from "components/organisms/ToolsDisplay/tools-display";
 import HubPageLayout from "layouts/hub-page";
 import { WithPageLayout } from "interfaces/with-page-layout";
 import changeCapitalization from "lib/utils/change-capitalization";
-import getInsightTeamMember from "lib/utils/get-insight-team-member";
+import getInsightTeamMemberAccess from "lib/utils/get-insight-team-member";
+import { MemberAccess } from "components/molecules/TeamMembersConfig/team-members-config";
 
 interface InsightFilterPageProps {
   insight: DbUserInsight;
@@ -49,15 +50,14 @@ export const getServerSideProps = async (ctx: GetServerSidePropsContext) => {
   }
 
   const userId = session?.user?.user_metadata.sub as string;
-  const isOwner = userId && insight && `${userId}` === `${insight.user?.id}` ? true : false;
-  let isTeamMember = false;
+  let teamMemberAccess: MemberAccess | null = null;
 
-  if (!insight.is_public && !isOwner) {
+  if (!insight.is_public) {
     // check if user is insight page team member
-    isTeamMember = await getInsightTeamMember(Number(insightId), bearerToken, userId);
+    teamMemberAccess = await getInsightTeamMemberAccess(Number(insightId), bearerToken, userId);
   }
 
-  if (!insight.is_public && !isOwner && !isTeamMember) {
+  if (!insight.is_public && (!teamMemberAccess || teamMemberAccess === "pending")) {
     return {
       redirect: {
         destination: "/",


Test patch:
diff --git a/lib/utils/contributor-utils.test.ts b/lib/utils/contributor-utils.test.ts
index 4f644614..20f5ffcb 100644
--- a/lib/utils/contributor-utils.test.ts
+++ b/lib/utils/contributor-utils.test.ts
@@ -36,6 +36,7 @@ describe("contributor utilities", () => {
       is_maintainer: true,
       coupon_code: "DBUSER10",
       receive_product_updates: true,
+      interests: "Ultimate Frisbee, Hiking, Biking, C++",
     });
 
     it("should get the top two languages in alpabetical order", () => {
@@ -47,25 +48,14 @@ describe("contributor utilities", () => {
           rust: 4,
           go: 5,
         },
-        interests: "logo,c++,assembly",
       }) satisfies DbUser;
 
       expect(getTopContributorLanguages(user)).toEqual(["go", "javascript"]);
     });
 
-    it("should get the top two languages in alpabetical order as the top two interests when there are no languages", () => {
+    it("should get no languages when there are no languages", () => {
       const user = Object.assign({}, baseUser, {
         languages: {},
-        interests: "logo,c++,assembly",
-      }) satisfies DbUser;
-
-      expect(getTopContributorLanguages(user)).toEqual(["assembly", "c++"]);
-    });
-
-    it("should get no languages when there are no languages or interests", () => {
-      const user = Object.assign({}, baseUser, {
-        languages: {},
-        interests: "",
       }) satisfies DbUser;
 
       expect(getTopContributorLanguages(user)).toEqual([]);