Filter deployments with status options (#15)

This commit is contained in:
Nabarun Gogoi 2023-12-20 16:43:27 +05:30 committed by GitHub
parent cfb299c79e
commit 318ebdfd26
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 114 additions and 54 deletions

View File

@ -1,16 +1,10 @@
import React, { ChangeEventHandler, forwardRef } from 'react';
import React, { forwardRef } from 'react';
import { Input } from '@material-tailwind/react';
interface SearchBarProps {
onChange?: ChangeEventHandler<HTMLInputElement>;
value?: string;
placeholder?: string;
}
import { Input, InputProps } from '@material-tailwind/react';
const SearchBar: React.ForwardRefRenderFunction<
HTMLInputElement,
SearchBarProps
InputProps
> = ({ value, onChange, placeholder = 'Search', ...props }, ref) => {
return (
<div className="relative flex w-full gap-2">
@ -28,8 +22,8 @@ const SearchBar: React.ForwardRefRenderFunction<
}}
// TODO: Debug issue: https://github.com/creativetimofficial/material-tailwind/issues/427
crossOrigin={undefined}
ref={ref}
{...props}
ref={ref}
/>
<div className="!absolute left-3 top-[13px]">
<i>^</i>

View File

@ -1,60 +1,47 @@
import React, { useCallback, useMemo, useState } from 'react';
import { Button } from '@material-tailwind/react';
import { Button, Typography } from '@material-tailwind/react';
import deploymentData from '../../../assets/deployments.json';
import DeployDetailsCard from './DeploymentDetailsCard';
import Dropdown from '../../Dropdown';
import SearchBar from '../../SearchBar';
import DeployDetailsCard from './deployments/DeploymentDetailsCard';
import FilterForm, { StatusOptions } from './deployments/FilterForm';
const STATUS_OPTIONS = [
{ value: 'building', label: 'Building' },
{ value: 'ready', label: 'Ready' },
{ value: 'error', label: 'Error' },
];
const DEFAULT_FILTER_VALUE = {
searchedBranch: '',
status: 'All status',
};
const DeploymentsTabPanel = () => {
const [searchedBranch, setSearchedBranch] = useState('');
const [filterValue, setFilterValue] = useState(DEFAULT_FILTER_VALUE);
const filteredDeployments = useMemo(() => {
if (searchedBranch) {
return deploymentData.filter((deployment) =>
deployment.branch.toLowerCase().includes(searchedBranch.toLowerCase()),
);
}
return deploymentData.filter((deployment) => {
// Searched branch filter
const branchMatch =
!filterValue.searchedBranch ||
deployment.branch
.toLowerCase()
.includes(filterValue.searchedBranch.toLowerCase());
return deploymentData;
}, [searchedBranch]);
// Status filter
const statusMatch =
filterValue.status === StatusOptions.ALL_STATUS ||
deployment.status === filterValue.status;
return branchMatch && statusMatch;
});
}, [filterValue]);
const handleResetFilters = useCallback(() => {
setSearchedBranch('');
setFilterValue(DEFAULT_FILTER_VALUE);
}, []);
return (
<div className="p-4">
<div className="grid grid-cols-4 gap-2 text-sm text-gray-600">
<div className="col-span-2">
<SearchBar
placeholder="Search branches"
value={searchedBranch}
onChange={(event) => setSearchedBranch(event.target.value)}
/>
</div>
<div className="col-span-1">
<input
type="text"
className="border border-gray-300 rounded p-2 w-full focus:border-blue-300 focus:outline-none focus:shadow-outline-blue"
placeholder="All time"
/>
</div>
<div className="col-span-1">
<Dropdown
placeholder="All status"
options={STATUS_OPTIONS}
onChange={() => {}}
/>
</div>
</div>
<FilterForm
value={filterValue}
onChange={(value) => setFilterValue(value)}
/>
<div className="mt-2">
{Boolean(filteredDeployments.length) ? (
filteredDeployments.map((deployment, key) => {
@ -63,8 +50,10 @@ const DeploymentsTabPanel = () => {
) : (
<div className="h-[50vh] bg-gray-100 flex rounded items-center justify-center">
<div className="text-center">
<h5 className="text-lg font-bold">No deployments found</h5>
<p>Please change your search query or filters</p>
<Typography variant="h5">No deployments found</Typography>
<Typography>
Please change your search query or filters
</Typography>
<Button
className="rounded-full mt-5"
color="white"

View File

@ -7,7 +7,7 @@ import {
MenuItem,
} from '@material-tailwind/react';
import { relativeTime } from '../../../utils/time';
import { relativeTime } from '../../../../utils/time';
interface DeploymentDetails {
title: string;

View File

@ -0,0 +1,77 @@
import React, { useEffect, useState } from 'react';
import { Option, Select } from '@material-tailwind/react';
import SearchBar from '../../../SearchBar';
export enum StatusOptions {
ALL_STATUS = 'All status',
BUILDING = 'Building',
READY = 'Ready',
ERROR = 'Error',
}
interface FilterValue {
searchedBranch: string;
status: string;
}
interface FilterFormProps {
value: FilterValue;
onChange: (value: FilterValue) => void;
}
const FilterForm = ({ value, onChange }: FilterFormProps) => {
const [searchedBranch, setSearchedBranch] = useState(value.searchedBranch);
const [selectedStatus, setSelectedStatus] = useState(value.status);
useEffect(() => {
onChange({
searchedBranch,
status: selectedStatus,
});
}, [searchedBranch, selectedStatus]);
useEffect(() => {
setSearchedBranch(value.searchedBranch);
setSelectedStatus(value.status);
}, [value]);
return (
<div className="grid grid-cols-4 gap-2 text-sm text-gray-600">
<div className="col-span-2">
<SearchBar
placeholder="Search branches"
value={searchedBranch}
onChange={(event) => setSearchedBranch(event.target.value)}
/>
</div>
<div className="col-span-1">
<input
type="text"
className="border border-gray-300 rounded p-2 w-full focus:border-blue-300 focus:outline-none focus:shadow-outline-blue"
placeholder="All time"
/>
</div>
<div className="col-span-1">
<Select
value={selectedStatus}
onChange={(value) => setSelectedStatus(value!)}
label="Select Version"
>
{Object.values(StatusOptions).map((status) => (
<Option
className={status === selectedStatus ? 'hidden' : ''}
key={status}
value={status}
>
^ {status}
</Option>
))}
</Select>
</div>
</div>
);
};
export default FilterForm;