Implement filtering repositories by name and account (#18)
* Filter repositories according to title * Add style to project repo card * Filter repositories through title and user * Update project repository card for user --------- Co-authored-by: neeraj <neeraj.rtly@gmail.com>
This commit is contained in:
parent
6590b8f6f5
commit
5c762f3583
@ -1,26 +1,32 @@
|
||||
[
|
||||
{
|
||||
"title": "Project-101",
|
||||
"updatedTime": "2023-05-15T08:30:00"
|
||||
"title": "project-101",
|
||||
"updatedAt": "2023-12-21T08:30:00",
|
||||
"user": "bob"
|
||||
},
|
||||
{
|
||||
"title": "Project-102",
|
||||
"updatedTime": "2023-05-15T08:30:00"
|
||||
"title": "project-102",
|
||||
"updatedAt": "2023-12-21T08:30:00",
|
||||
"user": "alice"
|
||||
},
|
||||
{
|
||||
"title": "Project-103",
|
||||
"updatedTime": "2023-12-11T04:20:00"
|
||||
"title": "project-103",
|
||||
"updatedAt": "2023-12-21T04:20:00",
|
||||
"user": "charlie"
|
||||
},
|
||||
{
|
||||
"title": "Project-104",
|
||||
"updatedTime": "2023-12-11T04:27:00"
|
||||
"title": "project-104",
|
||||
"updatedAt": "2023-12-21T04:27:00",
|
||||
"user": "alice"
|
||||
},
|
||||
{
|
||||
"title": "Project-105",
|
||||
"updatedTime": "2023-12-11T04:41:00"
|
||||
"title": "project-105",
|
||||
"updatedAt": "2023-12-21T04:41:00",
|
||||
"user": "ivan"
|
||||
},
|
||||
{
|
||||
"title": "Project-106",
|
||||
"updatedTime": "2023-12-11T04:32:00"
|
||||
"title": "project-106",
|
||||
"updatedAt": "2023-12-21T04:32:00",
|
||||
"user": "david"
|
||||
}
|
||||
]
|
||||
|
@ -1,10 +1,13 @@
|
||||
import React from 'react';
|
||||
|
||||
import { IconButton } from '@material-tailwind/react';
|
||||
|
||||
import { relativeTime } from '../../../utils/time';
|
||||
|
||||
interface RepositoryDetails {
|
||||
title: string;
|
||||
updatedTime: string;
|
||||
updatedAt: string;
|
||||
user: string;
|
||||
}
|
||||
|
||||
interface ProjectRepoCardProps {
|
||||
@ -13,11 +16,16 @@ interface ProjectRepoCardProps {
|
||||
|
||||
const ProjectRepoCard: React.FC<ProjectRepoCardProps> = ({ repository }) => {
|
||||
return (
|
||||
<div className="flex text-gray-500 text-xs bg-gray-100 m-2">
|
||||
<div className="group flex items-center gap-4 text-gray-500 text-xs hover:bg-gray-100 m-2">
|
||||
<div>^</div>
|
||||
<div className="grow">
|
||||
<p>{repository.title}</p>
|
||||
<p>{relativeTime(repository.updatedTime)}</p>
|
||||
<p className="text-black">
|
||||
{repository.user}/{repository.title}
|
||||
</p>
|
||||
<p>{relativeTime(repository.updatedAt)}</p>
|
||||
</div>
|
||||
<div className="hidden group-hover:block">
|
||||
<IconButton size="sm">{'>'}</IconButton>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
@ -1,34 +1,87 @@
|
||||
import React from 'react';
|
||||
import React, { useCallback, useMemo, useState } from 'react';
|
||||
|
||||
import { Button, Typography, Option, Select } from '@material-tailwind/react';
|
||||
|
||||
import SearchBar from '../../SearchBar';
|
||||
import ProjectRepoCard from './ProjectRepoCard';
|
||||
import repositoryDetails from '../../../assets/repositories.json';
|
||||
import Dropdown from '../../Dropdown';
|
||||
|
||||
const ACCOUNT_OPTIONS = [
|
||||
{ value: 'alice', label: 'Alice' },
|
||||
{ value: 'bob', label: 'Bob' },
|
||||
{ value: 'charlie', label: 'Charlie' },
|
||||
];
|
||||
const DEFAULT_SEARCHED_REPO = '';
|
||||
const DEFAULT_SELECTED_USER = 'All accounts';
|
||||
|
||||
const RepositoryList = () => {
|
||||
const [searchedRepo, setSearchedRepo] = useState(DEFAULT_SEARCHED_REPO);
|
||||
const [selectedUser, setSelectedUser] = useState(DEFAULT_SELECTED_USER);
|
||||
|
||||
const filteredRepos = useMemo(() => {
|
||||
return repositoryDetails.filter((repo) => {
|
||||
const titleMatch =
|
||||
!searchedRepo ||
|
||||
repo.title.toLowerCase().includes(searchedRepo.toLowerCase());
|
||||
const userMatch =
|
||||
selectedUser === DEFAULT_SELECTED_USER || selectedUser === repo.user;
|
||||
return titleMatch && userMatch;
|
||||
});
|
||||
}, [searchedRepo, selectedUser]);
|
||||
|
||||
const handleResetFilters = useCallback(() => {
|
||||
setSearchedRepo(DEFAULT_SEARCHED_REPO);
|
||||
setSelectedUser(DEFAULT_SELECTED_USER);
|
||||
}, []);
|
||||
|
||||
const users = useMemo(() => {
|
||||
return [
|
||||
DEFAULT_SELECTED_USER,
|
||||
...Array.from(new Set(repositoryDetails.map((repo) => repo.user))),
|
||||
];
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="p-4">
|
||||
<div className="flex">
|
||||
<div className="flex gap-2">
|
||||
<div className="basis-1/3">
|
||||
<Dropdown
|
||||
placeholder="All accounts"
|
||||
options={ACCOUNT_OPTIONS}
|
||||
onChange={() => {}}
|
||||
/>
|
||||
<Select
|
||||
value={selectedUser}
|
||||
onChange={(value) => setSelectedUser(value!)}
|
||||
>
|
||||
{users.map((user, key) => (
|
||||
<Option
|
||||
className={user === selectedUser ? 'hidden' : ''}
|
||||
key={key}
|
||||
value={user}
|
||||
>
|
||||
^ {user}
|
||||
</Option>
|
||||
))}
|
||||
</Select>
|
||||
</div>
|
||||
<div className="basis-2/3">
|
||||
<SearchBar onChange={() => {}} placeholder="Search for repository" />
|
||||
<SearchBar
|
||||
value={searchedRepo}
|
||||
onChange={(event) => setSearchedRepo(event.target.value)}
|
||||
placeholder="Search for repository"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{repositoryDetails.map((repo, key) => {
|
||||
return <ProjectRepoCard repository={repo} key={key} />;
|
||||
})}
|
||||
{Boolean(filteredRepos.length) ? (
|
||||
filteredRepos.map((repo, key) => {
|
||||
return <ProjectRepoCard repository={repo} key={key} />;
|
||||
})
|
||||
) : (
|
||||
<div className="mt-4 p-6 flex items-center justify-center">
|
||||
<div className="text-center">
|
||||
<Typography>No repository found</Typography>
|
||||
<Button
|
||||
className="rounded-full mt-5"
|
||||
color="white"
|
||||
size="sm"
|
||||
onClick={handleResetFilters}
|
||||
>
|
||||
^ Reset filters
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
@ -1,5 +1,7 @@
|
||||
import React from 'react';
|
||||
|
||||
import { IconButton } from '@material-tailwind/react';
|
||||
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
interface TemplateDetails {
|
||||
@ -12,15 +14,19 @@ interface TemplateCardProps {
|
||||
|
||||
const TemplateCard: React.FC<TemplateCardProps> = ({ framework }) => {
|
||||
return (
|
||||
<div className="group bg-gray-200 text-gray-500 text-xs border-gray-200 rounded-lg shadow p-4 flex items-center justify-between">
|
||||
<div>
|
||||
{framework.icon}
|
||||
{framework.framework}
|
||||
<Link to={'/projects/create/template'}>
|
||||
<div className="h-14 group bg-gray-200 text-gray-500 text-xs border-gray-200 rounded-lg shadow p-4 flex items-center justify-between">
|
||||
<div className="grow">
|
||||
{framework.icon}
|
||||
{framework.framework}
|
||||
</div>
|
||||
<div>
|
||||
<IconButton size="sm" className="hidden group-hover:block">
|
||||
{'>'}
|
||||
</IconButton>
|
||||
</div>
|
||||
</div>
|
||||
<Link to={'/projects/create/template'}>
|
||||
<button className="hidden group-hover:block">{'>'}</button>
|
||||
</Link>
|
||||
</div>
|
||||
</Link>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -57,7 +57,6 @@ const FilterForm = ({ value, onChange }: FilterFormProps) => {
|
||||
<Select
|
||||
value={selectedStatus}
|
||||
onChange={(value) => setSelectedStatus(value!)}
|
||||
label="Select Version"
|
||||
>
|
||||
{Object.values(StatusOptions).map((status) => (
|
||||
<Option
|
||||
|
Loading…
Reference in New Issue
Block a user