From 0a1a53e0bcf132a86c5b5014f850e7bae04a3a09 Mon Sep 17 00:00:00 2001
From: Nabarun Gogoi <nabarun@deepstacksoft.com>
Date: Thu, 21 Dec 2023 16:42:06 +0530
Subject: [PATCH] Add chips to display different kinds of information (#20)

* Add chip for showing deployment status

* Add chip to display projects count

* Display label if project search is not matching

* Add chip to display domain is not connected

* Fix text size in chips for deployment domain

* Add chip to display if repository is private

---------

Co-authored-by: neeraj <neeraj.rtly@gmail.com>
---
 packages/frontend/src/assets/deployments.json |  6 +-
 packages/frontend/src/assets/projects.json    | 18 +++--
 .../frontend/src/assets/repositories.json     | 20 +++---
 .../src/components/projects/ProjectCard.tsx   |  2 +-
 .../src/components/projects/ProjectSearch.tsx | 65 +++++++++++--------
 .../projects/create/ProjectRepoCard.tsx       | 21 ++++--
 .../projects/project/ActivityCard.tsx         |  9 ++-
 .../projects/project/DeploymentsTabPanel.tsx  |  8 ++-
 .../projects/project/OverviewTabPanel.tsx     | 36 +++++++---
 .../deployments/DeploymentDetailsCard.tsx     | 31 +++++++--
 packages/frontend/src/pages/Projects.tsx      | 14 ++--
 packages/frontend/src/types/project.ts        |  1 +
 12 files changed, 153 insertions(+), 78 deletions(-)

diff --git a/packages/frontend/src/assets/deployments.json b/packages/frontend/src/assets/deployments.json
index 6034e7e2..c2805124 100644
--- a/packages/frontend/src/assets/deployments.json
+++ b/packages/frontend/src/assets/deployments.json
@@ -1,6 +1,6 @@
 [
   {
-    "title": "nextjs-bolerplate-9t44zbky4dg-bygideon-projects",
+    "title": "nextjs-boilerplate-9t44zbky4dg-bygideon-projects",
     "status": "Building",
     "environment": "Production",
     "branch": "prod",
@@ -12,7 +12,7 @@
     "updatedAt": "2023-12-11T04:20:00"
   },
   {
-    "title": "nextjs-bolerplate-9232dwky4dg-bygideon-projects",
+    "title": "nextjs-boilerplate-9232dwky4dg-bygideon-projects",
     "status": "Ready",
     "environment": "Preview",
     "branch": "prod",
@@ -24,7 +24,7 @@
     "updatedAt": "2023-12-11T04:20:00"
   },
   {
-    "title": "nextjs-bolerplate-9saa22y4dg-bygideon-projects",
+    "title": "nextjs-boilerplate-9saa22y4dg-bygideon-projects",
     "status": "Error",
     "environment": "Production",
     "branch": "main",
diff --git a/packages/frontend/src/assets/projects.json b/packages/frontend/src/assets/projects.json
index 584aeb9e..c9f9e419 100644
--- a/packages/frontend/src/assets/projects.json
+++ b/packages/frontend/src/assets/projects.json
@@ -4,8 +4,9 @@
     "icon": "^",
     "name": "iglotools",
     "title": "Iglotools",
+    "domain": "",
     "organization": "Airfoil",
-    "domain": "iglotools.co",
+    "url": "iglotools.co",
     "createdAt": "2023-12-07T04:20:00",
     "createdBy": "Alice",
     "deployment": "iglotools.snowballtools.co",
@@ -21,8 +22,9 @@
     "icon": "^",
     "name": "snowball-starter-kit",
     "title": "Snowball Starter Kit",
+    "domain": "",
     "organization": "Snowball",
-    "domain": "starterkit.snowballtools.com",
+    "url": "starterkit.snowballtools.com",
     "createdAt": "2023-12-04T04:20:00",
     "createdBy": "Bob",
     "deployment": "deploy.snowballtools.com",
@@ -38,8 +40,9 @@
     "icon": "^",
     "name": "web3-android",
     "title": "Web3 Android",
+    "domain": "",
     "organization": "Personal",
-    "domain": "web3fordroids.com",
+    "url": "web3fordroids.com",
     "createdAt": "2023-12-01T04:20:00",
     "createdBy": "Charlie",
     "deployment": "deploy.web3fordroids.com",
@@ -55,8 +58,9 @@
     "icon": "^",
     "name": "passkeys-demo",
     "title": "Passkeys Demo",
+    "domain": "",
     "organization": "Airfoil",
-    "domain": "passkeys.iglootools.xyz",
+    "url": "passkeys.iglootools.xyz",
     "createdAt": "2023-12-01T04:20:00",
     "createdBy": "David",
     "deployment": "demo.passkeys.xyz",
@@ -72,8 +76,9 @@
     "icon": "^",
     "name": "iglootools",
     "title": "Iglootools",
+    "domain": "",
     "organization": "Airfoil",
-    "domain": "iglotools.xyz",
+    "url": "iglotools.xyz",
     "createdAt": "2023-12-11T04:20:00",
     "createdBy": "Erin",
     "deployment": "staging.snowballtools.com",
@@ -89,8 +94,9 @@
     "icon": "^",
     "name": "iglootools",
     "title": "Iglootools",
+    "domain": "",
     "organization": "Airfoil",
-    "domain": "iglotools.xyz",
+    "url": "iglotools.xyz",
     "createdAt": "2023-12-11T04:20:00",
     "createdBy": "Frank",
     "deployment": "iglotools.snowballtools.com",
diff --git a/packages/frontend/src/assets/repositories.json b/packages/frontend/src/assets/repositories.json
index f9364789..04a1cff1 100644
--- a/packages/frontend/src/assets/repositories.json
+++ b/packages/frontend/src/assets/repositories.json
@@ -2,31 +2,31 @@
   {
     "title": "project-101",
     "updatedAt": "2023-12-21T08:30:00",
-    "user": "bob"
+    "user": "bob",
+    "private": false
   },
   {
     "title": "project-102",
     "updatedAt": "2023-12-21T08:30:00",
-    "user": "alice"
+    "user": "alice",
+    "private": true
   },
   {
     "title": "project-103",
     "updatedAt": "2023-12-21T04:20:00",
-    "user": "charlie"
+    "user": "charlie",
+    "private": false
   },
   {
     "title": "project-104",
     "updatedAt": "2023-12-21T04:27:00",
-    "user": "alice"
+    "user": "alice",
+    "private": false
   },
   {
     "title": "project-105",
     "updatedAt": "2023-12-21T04:41:00",
-    "user": "ivan"
-  },
-  {
-    "title": "project-106",
-    "updatedAt": "2023-12-21T04:32:00",
-    "user": "david"
+    "user": "ivan",
+    "private": false
   }
 ]
diff --git a/packages/frontend/src/components/projects/ProjectCard.tsx b/packages/frontend/src/components/projects/ProjectCard.tsx
index 25125700..afa24369 100644
--- a/packages/frontend/src/components/projects/ProjectCard.tsx
+++ b/packages/frontend/src/components/projects/ProjectCard.tsx
@@ -25,7 +25,7 @@ const ProjectCard: React.FC<ProjectCardProps> = ({ project }) => {
           <Link to={`projects/${project.id}`}>
             <Typography>{project.name}</Typography>
             <Typography color="gray" variant="small">
-              {project.domain}
+              {project.url}
             </Typography>
           </Link>
         </div>
diff --git a/packages/frontend/src/components/projects/ProjectSearch.tsx b/packages/frontend/src/components/projects/ProjectSearch.tsx
index baf37937..e5037431 100644
--- a/packages/frontend/src/components/projects/ProjectSearch.tsx
+++ b/packages/frontend/src/components/projects/ProjectSearch.tsx
@@ -27,6 +27,7 @@ const ProjectSearch = ({ onChange }: ProjectsSearchProps) => {
     getInputProps,
     getItemProps,
     highlightedIndex,
+    inputValue,
   } = useCombobox({
     onInputValueChange({ inputValue }) {
       setItems(
@@ -57,39 +58,47 @@ const ProjectSearch = ({ onChange }: ProjectsSearchProps) => {
     <div className="relative">
       <SearchBar {...getInputProps()} />
       <Card
-        className={`absolute w-1/2 max-h-100 -mt-1 overflow-y-scroll ${
-          !(isOpen && items.length) && 'hidden'
+        className={`absolute w-1/2 max-h-52 -mt-1 overflow-y-auto ${
+          (!inputValue || !isOpen) && 'hidden'
         }`}
       >
         <List {...getMenuProps()}>
-          <div className="p-3">
-            <Typography variant="small" color="gray">
-              Suggestions
-            </Typography>
-          </div>
-          {items.map((item, index) => (
-            <ListItem
-              selected={highlightedIndex === index || selectedItem === item}
-              key={item.id}
-              {...getItemProps({ item, index })}
-            >
-              <ListItemPrefix>
-                <i>^</i>
-              </ListItemPrefix>
-              <div>
-                <Typography variant="h6" color="blue-gray">
-                  {item.title}
-                </Typography>
-                <Typography
-                  variant="small"
-                  color="gray"
-                  className="font-normal"
-                >
-                  {item.organization}
+          {items.length ? (
+            <>
+              <div className="p-3">
+                <Typography variant="small" color="gray">
+                  Suggestions
                 </Typography>
               </div>
-            </ListItem>
-          ))}
+              {items.map((item, index) => (
+                <ListItem
+                  selected={highlightedIndex === index || selectedItem === item}
+                  key={item.id}
+                  {...getItemProps({ item, index })}
+                >
+                  <ListItemPrefix>
+                    <i>^</i>
+                  </ListItemPrefix>
+                  <div>
+                    <Typography variant="h6" color="blue-gray">
+                      {item.title}
+                    </Typography>
+                    <Typography
+                      variant="small"
+                      color="gray"
+                      className="font-normal"
+                    >
+                      {item.organization}
+                    </Typography>
+                  </div>
+                </ListItem>
+              ))}
+            </>
+          ) : (
+            <div className="p-3">
+              <Typography>^ No projects matching this name</Typography>
+            </div>
+          )}
         </List>
       </Card>
     </div>
diff --git a/packages/frontend/src/components/projects/create/ProjectRepoCard.tsx b/packages/frontend/src/components/projects/create/ProjectRepoCard.tsx
index 67703f86..158de6bc 100644
--- a/packages/frontend/src/components/projects/create/ProjectRepoCard.tsx
+++ b/packages/frontend/src/components/projects/create/ProjectRepoCard.tsx
@@ -1,6 +1,6 @@
 import React from 'react';
 
-import { IconButton } from '@material-tailwind/react';
+import { Chip, IconButton } from '@material-tailwind/react';
 
 import { relativeTime } from '../../../utils/time';
 
@@ -8,6 +8,7 @@ interface RepositoryDetails {
   title: string;
   updatedAt: string;
   user: string;
+  private: boolean;
 }
 
 interface ProjectRepoCardProps {
@@ -19,9 +20,21 @@ const ProjectRepoCard: React.FC<ProjectRepoCardProps> = ({ repository }) => {
     <div className="group flex items-center gap-4 text-gray-500 text-xs hover:bg-gray-100 p-2 cursor-pointer">
       <div>^</div>
       <div className="grow">
-        <p className="text-black">
-          {repository.user}/{repository.title}
-        </p>
+        <div>
+          <span className="text-black">
+            {repository.user}/{repository.title}
+          </span>
+          {repository.private ? (
+            <Chip
+              className="normal-case inline ml-6 bg-[#FED7AA] text-[#EA580C] font-normal"
+              size="sm"
+              value="Private"
+              icon={'^'}
+            />
+          ) : (
+            ''
+          )}
+        </div>
         <p>{relativeTime(repository.updatedAt)}</p>
       </div>
       <div className="hidden group-hover:block">
diff --git a/packages/frontend/src/components/projects/project/ActivityCard.tsx b/packages/frontend/src/components/projects/project/ActivityCard.tsx
index 4d2b8497..9a8f473a 100644
--- a/packages/frontend/src/components/projects/project/ActivityCard.tsx
+++ b/packages/frontend/src/components/projects/project/ActivityCard.tsx
@@ -1,6 +1,6 @@
 import React from 'react';
 
-import { Typography } from '@material-tailwind/react';
+import { Typography, IconButton } from '@material-tailwind/react';
 
 import { relativeTime } from '../../../utils/time';
 
@@ -18,7 +18,7 @@ interface ActivityCardProps {
 
 const ActivityCard = ({ activity }: ActivityCardProps) => {
   return (
-    <div className="flex hover:bg-gray-200 rounded mt-1">
+    <div className="group flex hover:bg-gray-200 rounded mt-1">
       <div className="w-4">{activity.authorAvatar}</div>
 
       <div className="grow">
@@ -30,6 +30,11 @@ const ActivityCard = ({ activity }: ActivityCardProps) => {
           {activity.message}
         </Typography>
       </div>
+      <div className="mr-2 self-center hidden group-hover:block">
+        <IconButton size="sm" className="rounded-full bg-gray-600">
+          {'>'}
+        </IconButton>
+      </div>
     </div>
   );
 };
diff --git a/packages/frontend/src/components/projects/project/DeploymentsTabPanel.tsx b/packages/frontend/src/components/projects/project/DeploymentsTabPanel.tsx
index 64d1715b..ae21894b 100644
--- a/packages/frontend/src/components/projects/project/DeploymentsTabPanel.tsx
+++ b/packages/frontend/src/components/projects/project/DeploymentsTabPanel.tsx
@@ -3,7 +3,9 @@ import React, { useCallback, useMemo, useState } from 'react';
 import { Button, Typography } from '@material-tailwind/react';
 
 import deploymentData from '../../../assets/deployments.json';
-import DeployDetailsCard from './deployments/DeploymentDetailsCard';
+import DeployDetailsCard, {
+  DeploymentDetails,
+} from './deployments/DeploymentDetailsCard';
 import FilterForm, {
   FilterValue,
   StatusOptions,
@@ -17,7 +19,7 @@ const DEFAULT_FILTER_VALUE: FilterValue = {
 const DeploymentsTabPanel = () => {
   const [filterValue, setFilterValue] = useState(DEFAULT_FILTER_VALUE);
 
-  const filteredDeployments = useMemo(() => {
+  const filteredDeployments = useMemo<DeploymentDetails[]>(() => {
     return deploymentData.filter((deployment) => {
       // Searched branch filter
       const branchMatch =
@@ -37,7 +39,7 @@ const DeploymentsTabPanel = () => {
           new Date(deployment.updatedAt) <= filterValue.updateAtRange!.to!);
 
       return branchMatch && statusMatch && dateMatch;
-    });
+    }) as DeploymentDetails[];
   }, [filterValue]);
 
   const handleResetFilters = useCallback(() => {
diff --git a/packages/frontend/src/components/projects/project/OverviewTabPanel.tsx b/packages/frontend/src/components/projects/project/OverviewTabPanel.tsx
index 65a133c5..1d49843d 100644
--- a/packages/frontend/src/components/projects/project/OverviewTabPanel.tsx
+++ b/packages/frontend/src/components/projects/project/OverviewTabPanel.tsx
@@ -1,6 +1,6 @@
 import React from 'react';
 
-import { Typography } from '@material-tailwind/react';
+import { Typography, Button, Chip } from '@material-tailwind/react';
 
 import ActivityCard from './ActivityCard';
 import activityDetails from '../../../assets/activities.json';
@@ -19,24 +19,40 @@ const OverviewTabPanel = ({ project }: OverviewProps) => (
         <div className="grow">
           <Typography>{project.name}</Typography>
           <Typography variant="small" color="gray">
-            {project.domain}
+            {project.url}
           </Typography>
         </div>
       </div>
-      <div className="flex justify-between p-2 text-sm">
-        <p>Domain</p>
-        {project.domain ? <p>{project.domain}</p> : <button>Set up</button>}
+      <div className="flex justify-between p-2 text-sm items-center">
+        <div>
+          ^ Domain
+          {!project.domain && (
+            <Chip
+              className="normal-case ml-6 bg-[#FED7AA] text-[#EA580C] inline font-normal"
+              size="sm"
+              value="Not connected"
+              icon="^"
+            />
+          )}
+        </div>
+        {project.domain ? (
+          <p>{project.domain}</p>
+        ) : (
+          <Button className="normal-case rounded-full" color="blue" size="sm">
+            Setup
+          </Button>
+        )}
       </div>
       <div className="flex justify-between p-2 text-sm">
-        <p>Source</p>
-        <p>^ {project.source}</p>
+        <p>^ Source</p>
+        <p>{project.source}</p>
       </div>
       <div className="flex justify-between p-2 text-sm">
-        <p>deployment</p>
-        <p>{project.deployment} ^</p>
+        <p>^ Deployment</p>
+        <p className="text-blue-600">{project.deployment}</p>
       </div>
       <div className="flex justify-between p-2 text-sm">
-        <p>Created</p>
+        <p>^ Created</p>
         <p>
           {relativeTime(project.createdAt)} by ^ {project.createdBy}
         </p>
diff --git a/packages/frontend/src/components/projects/project/deployments/DeploymentDetailsCard.tsx b/packages/frontend/src/components/projects/project/deployments/DeploymentDetailsCard.tsx
index cd87c0d2..0a1bab92 100644
--- a/packages/frontend/src/components/projects/project/deployments/DeploymentDetailsCard.tsx
+++ b/packages/frontend/src/components/projects/project/deployments/DeploymentDetailsCard.tsx
@@ -6,13 +6,21 @@ import {
   MenuList,
   MenuItem,
   Typography,
+  Chip,
+  ChipProps,
 } from '@material-tailwind/react';
 
 import { relativeTime } from '../../../../utils/time';
 
-interface DeploymentDetails {
+export enum Status {
+  BUILDING = 'Building',
+  READY = 'Ready',
+  ERROR = 'Error',
+}
+
+export interface DeploymentDetails {
   title: string;
-  status: string;
+  status: Status;
   environment: string;
   branch: string;
   commit: {
@@ -27,15 +35,24 @@ interface DeployDetailsCardProps {
   deployment: DeploymentDetails;
 }
 
+const STATUS_COLORS: { [key in Status]: ChipProps['color'] } = {
+  [Status.BUILDING]: 'blue',
+  [Status.READY]: 'green',
+  [Status.ERROR]: 'red',
+};
+
 const DeployDetailsCard = ({ deployment }: DeployDetailsCardProps) => {
   return (
-    <div className="grid grid-cols-4 gap-2 border-b border-gray-300">
+    <div className="grid grid-cols-4 gap-2 border-b border-gray-300 p-3 my-2">
       <div className="col-span-2">
         <div className="flex">
-          <Typography className=" basis-2/3">{deployment.title}</Typography>
-          <Typography color="gray" className="basis-1/3">
-            {deployment.status}
-          </Typography>
+          <Typography className=" basis-3/4">{deployment.title}</Typography>
+          <Chip
+            value={deployment.status}
+            color={STATUS_COLORS[deployment.status] ?? 'gray'}
+            variant="ghost"
+            icon={<i>^</i>}
+          />
         </div>
         <Typography color="gray">{deployment.environment}</Typography>
       </div>
diff --git a/packages/frontend/src/pages/Projects.tsx b/packages/frontend/src/pages/Projects.tsx
index f7c4fa08..daafcd5e 100644
--- a/packages/frontend/src/pages/Projects.tsx
+++ b/packages/frontend/src/pages/Projects.tsx
@@ -1,7 +1,7 @@
 import React from 'react';
 import { Link } from 'react-router-dom';
 
-import { Button, IconButton, Typography } from '@material-tailwind/react';
+import { Button, IconButton, Typography, Chip } from '@material-tailwind/react';
 
 import ProjectCard from '../components/projects/ProjectCard';
 import HorizontalLine from '../components/HorizontalLine';
@@ -26,12 +26,18 @@ const Projects = () => {
         </div>
       </div>
       <HorizontalLine />
-      <div className="flex p-4">
+      <div className="flex p-5">
         <div className="grow">
-          <Typography variant="h4">Projects</Typography>
+          <div className="flex gap-2 items-center">
+            <Typography variant="h4">Projects</Typography>
+            <Chip
+              className="bg-gray-300 rounded-full static"
+              value={projectsDetail.length}
+              size="sm"
+            />
+          </div>
         </div>
         <div>
-          {/* TODO: Create button component */}
           <Link to="/projects/create">
             <Button className="rounded-full" color="blue">
               Create project
diff --git a/packages/frontend/src/types/project.ts b/packages/frontend/src/types/project.ts
index 602a53e6..1e8c6a7f 100644
--- a/packages/frontend/src/types/project.ts
+++ b/packages/frontend/src/types/project.ts
@@ -3,6 +3,7 @@ export interface ProjectDetails {
   name: string;
   title: string;
   organization: string;
+  url: string;
   domain: string;
   id: number;
   createdAt: string;