Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

perf: search improvements #8

Merged
merged 3 commits into from
Oct 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions src/pkg/github/context/SearchContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,6 @@ export function GitHubSearchProvider({ children }: PropsWithChildren) {
const [archived, setArchived] = useState<GitHubEnumArchived>(
defaults.archived
)
const [total, setTotal] = useState<number>(0)
const [params, setParams] = useState<GitHubSearchParams>(defaults)

useEffect(() => {
Expand Down Expand Up @@ -90,7 +89,6 @@ export function GitHubSearchProvider({ children }: PropsWithChildren) {
per_page,
visibility,
archived,
total,
queryParams: params,
setKeyword,
setOwner,
Expand All @@ -100,7 +98,6 @@ export function GitHubSearchProvider({ children }: PropsWithChildren) {
setPerPage,
setVisibility,
setArchived,
setTotal,
}}>
{children}
</GitHubSearchContext.Provider>
Expand Down
4 changes: 3 additions & 1 deletion src/pkg/github/hooks/search.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ import { renderHook, waitFor } from '@testing-library/react'
import fetchMock from 'fetch-mock'
import { describe, expect, it } from 'vitest'
import useSearchRepos from './search'
import { wrapper } from 'test/queryClientWrapper'
import { createReactQueryWrapper } from 'test/wrapper'
import { GitHubSearchProvider } from '../context/SearchContext'

const wrapper = createReactQueryWrapper([GitHubSearchProvider])
describe('useSearchRepos()', () => {
it('should search repos', async () => {
const expected = { hello: 'world' }
Expand Down
2 changes: 0 additions & 2 deletions src/pkg/github/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ export type GitHubSearchParams = {
}

export type GitHubSearchContextProps = {
total: number
queryParams: GitHubSearchParams
setKeyword: (newVal: string) => void
setOwner: (newVal: string) => void
Expand All @@ -55,7 +54,6 @@ export type GitHubSearchContextProps = {
setPage: (newVal: number) => void
setVisibility: (newVal: GitHubEnumVisibility) => void
setArchived: (newVal: GitHubEnumArchived) => void
setTotal: (newVal: number) => void
} & GitHubSearchParams

export type GitHubDeleteRepoResponse =
Expand Down
24 changes: 4 additions & 20 deletions src/pkg/github/views/Search.tsx
Original file line number Diff line number Diff line change
@@ -1,34 +1,18 @@
'use client'

import { useEffect, useState } from 'react'
import { useThemeContext } from '@/pkg/ui/contexts/ThemeContext'
import { GitHubSearchItems } from '../types'
import SearchToolbar from './SearchToolbar'
import { useGitHubSearchContext } from '../context/SearchContext'
import RepoList from './repo/RepoList'
import useSearchRepos from '../hooks/search'

export default function Search() {
const { setLoading } = useThemeContext()
const { data: response, isLoading } = useSearchRepos()
const { setTotal } = useGitHubSearchContext()
const [repositories, setRepositories] = useState<GitHubSearchItems>([])

useEffect(() => {
setLoading(isLoading)
}, [isLoading, setLoading])

useEffect(() => {
if (response) {
setRepositories(response.data.items)
setTotal(response.data.total_count)
}
}, [response, setTotal])
const repositories = response ? response.data.items : []
const total = response ? response.data.total_count : 0

return (
<div className="flex flex-col w-screen gap-4">
<SearchToolbar />
<RepoList repositories={repositories} />
<SearchToolbar loading={isLoading} total={total} />
<RepoList loading={isLoading} repositories={repositories} />
</div>
)
}
155 changes: 64 additions & 91 deletions src/pkg/github/views/SearchToolbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,27 @@

import { useGitHubSearchContext } from '../context/SearchContext'
import Pagination from '@/pkg/ui/views/Pagination'
import { useThemeContext } from '@/pkg/ui/contexts/ThemeContext'
import { useState } from 'react'
import { MdSearch } from 'react-icons/md'
import { GitHubEnumArchived, GitHubEnumSortOrder, GitHubEnumVisibility } from '../types'
import {
GitHubEnumArchived,
GitHubEnumSortOrder,
GitHubEnumVisibility,
} from '../types'
import useSearchRepos from '../hooks/search'

export default function SearchToolbar() {
export default function SearchToolbar({
loading,
total,
}: {
loading: boolean
total: number
}) {
const { data: response } = useSearchRepos()
const {
setPage,
page,
per_page,
total,
keyword,
setKeyword,
visibility,
Expand All @@ -22,10 +32,9 @@ export default function SearchToolbar() {
sort,
setSort,
order,
setOrder
setOrder,
} = useGitHubSearchContext()

const { loading } = useThemeContext()
const [search, setSearch] = useState(keyword)

const onPageChanged = (newPage: number) => {
Expand All @@ -38,146 +47,110 @@ export default function SearchToolbar() {
}

const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
if(e.key == 'Enter'){
if (e.key == 'Enter') {
handleSearch()
}
}

const handleChange = (key:string, newValue: string) => {
if(key==='visibility') setVisibility(newValue as GitHubEnumVisibility)
if(key==='archived') setArchived(newValue as GitHubEnumArchived)
if(key==='sort') setSort(newValue)
if(key==='order') setOrder(newValue as GitHubEnumSortOrder)
const handleChange = (key: string, newValue: string) => {
if (key === 'visibility') setVisibility(newValue as GitHubEnumVisibility)
if (key === 'archived') setArchived(newValue as GitHubEnumArchived)
if (key === 'sort') setSort(newValue)
if (key === 'order') setOrder(newValue as GitHubEnumSortOrder)

setPage(1)
}

return (
<div className='flex flex-col bg-white p-2 rounded-lg drop-shadow-lg gap-2'>
<div className="flex flex-col bg-white p-2 rounded-lg drop-shadow-lg gap-2">
{/* filters */}
<div className='flex gap-2'>

<div className="flex flex-wrap gap-2">
{/* search */}
<div className='join'>
<div className="join">
<input
onChange={(e) => setSearch(e.target.value)}
type='text'
className='input input-bordered input-sm join-item focus:outline-none'
placeholder='type here to search'
accessKey='s'
type="text"
className="input input-bordered input-sm join-item focus:outline-none"
placeholder="type here to search"
accessKey="s"
onKeyDown={(e) => handleKeyDown(e)}
/>
<button
className='join-item btn btn-sm border-slate-400'
onClick={handleSearch}
>
<MdSearch/>
className="join-item btn btn-sm border-slate-400"
onClick={handleSearch}>
<MdSearch />
</button>
</div>

{/* visibility */}
<div className='form-control w-full max-w-xs'>
<div className="form-control w-full max-w-xs">
<select
id='visibility'
id="visibility"
onChange={(e) => handleChange('visibility', e.target.value)}
value={visibility}
className='select select-bordered select-sm focus:outline-none'
>
<option
value={GitHubEnumVisibility.undefined}
>
all
</option>
<option
value={GitHubEnumVisibility.public}
>
public
</option>
<option
value={GitHubEnumVisibility.private}
>
private
</option>
className="select select-bordered select-sm focus:outline-none">
<option value={GitHubEnumVisibility.undefined}>all</option>
<option value={GitHubEnumVisibility.public}>public</option>
<option value={GitHubEnumVisibility.private}>private</option>
</select>
<label className='label' htmlFor='visibility'>
<span className='label-text-alt text-sm'>
<label className="label" htmlFor="visibility">
<span className="label-text-alt text-sm">
filter repo visibility
</span>
</label>
</div>

{/* archived */}
<div className='form-control w-full max-w-xs'>
<div className="form-control w-full max-w-xs">
<select
id='archived'
id="archived"
onChange={(e) => handleChange('archived', e.target.value)}
value={archived}
className='select select-bordered select-sm focus:outline-none'
>
<option
value={GitHubEnumArchived.undefined}
>
all
</option>
<option
value={GitHubEnumArchived.true}
>
archived
</option>
<option
value={GitHubEnumArchived.false}
>
unarchived
</option>
className="select select-bordered select-sm focus:outline-none">
<option value={GitHubEnumArchived.undefined}>all</option>
<option value={GitHubEnumArchived.true}>archived</option>
<option value={GitHubEnumArchived.false}>unarchived</option>
</select>
<label className='label' htmlFor='archived'>
<span className='label-text-alt text-sm'>Filter archived/unarchived repo</span>
<label className="label" htmlFor="archived">
<span className="label-text-alt text-sm">
Filter archived/unarchived repo
</span>
</label>
</div>

{/* sort */}
<div className='form-control w-full max-w-xs'>
<div className="form-control w-full max-w-xs">
<select
id='sort'
id="sort"
onChange={(e) => handleChange('sort', e.target.value)}
value={sort}
className='select select-bordered select-sm focus:outline-none'
>
<option value='updated'>
updated
</option>
<option value='name'>
name
</option>
className="select select-bordered select-sm focus:outline-none">
<option value="updated">updated</option>
<option value="name">name</option>
</select>
<label className='label' htmlFor='sort'>
<span className='label-text-alt text-sm'>sort repository</span>
<label className="label" htmlFor="sort">
<span className="label-text-alt text-sm">sort repository</span>
</label>
</div>

{/* order */}
<div className='form-control w-full max-w-xs'>
<div className="form-control w-full max-w-xs">
<select
id='order'
id="order"
onChange={(e) => handleChange('order', e.target.value)}
value={order}
className='select select-bordered select-sm focus:outline-none'
>
<option value={GitHubEnumSortOrder.asc}>
Ascending
</option>
<option value={GitHubEnumSortOrder.desc}>
Descending
</option>
className="select select-bordered select-sm focus:outline-none">
<option value={GitHubEnumSortOrder.asc}>Ascending</option>
<option value={GitHubEnumSortOrder.desc}>Descending</option>
</select>
<label className='label' htmlFor='order'>
<span className='label-text-alt text-sm'>sort order</span>
<label className="label" htmlFor="order">
<span className="label-text-alt text-sm">sort order</span>
</label>
</div>
</div>

{/* navigation */}
<div className='flex'>
<div className="flex">
<Pagination
onPageChanged={onPageChanged}
perPage={per_page}
Expand Down
15 changes: 9 additions & 6 deletions src/pkg/github/views/repo/RepoList.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,22 @@
'use client'
import { useThemeContext } from '@/pkg/ui/contexts/ThemeContext'
import { GitHubSearchItems } from '../../types'
import RepoCard from './RepoCard'

type Props = {
repositories: GitHubSearchItems
loading: boolean
}

export default function RepoList({repositories}: Props) {
export default function RepoList({ repositories, loading }: Props) {
if (loading) {
return <></>
}

return (
<div className='flex flex-wrap gap-4 items-start justify-center'>
<div className="flex flex-wrap gap-4 items-start justify-center">
{repositories.map((repo) => (
<RepoCard
key={repo.id}
repo={repo}
/>
<RepoCard key={repo.id} repo={repo} />
))}
</div>
)
Expand Down
3 changes: 2 additions & 1 deletion src/pkg/ui/contexts/ThemeContext.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
'use client'

import { createContext, useContext, useState } from 'react'
import { createContext, useContext, useEffect, useState } from 'react'
import {
ThemeAction,
ThemeActionType,
Expand All @@ -27,6 +27,7 @@ function themeReducer(state: ThemeState, action: ThemeAction) {
const ThemeContext = createContext<ThemeContextProps | undefined>(undefined)
export default function ThemeProvider({ children }: PropsWithChildren) {
const [loading, setLoading] = useState(false)

return (
<ThemeContext.Provider
value={{
Expand Down
Loading