Skip to content
This repository has been archived by the owner on Aug 3, 2024. It is now read-only.

Commit

Permalink
repositoryfilters hook
Browse files Browse the repository at this point in the history
  • Loading branch information
sametcn99 committed Feb 5, 2024
1 parent f34c9f0 commit 1d79cee
Show file tree
Hide file tree
Showing 5 changed files with 304 additions and 215 deletions.
122 changes: 26 additions & 96 deletions components/repositories/Repositories.tsx
Original file line number Diff line number Diff line change
@@ -1,35 +1,31 @@
"use client";
import { useContext, useMemo, useState } from "react";
import { useContext, useMemo } from "react";
import { GithubContext } from "@/app/context/GithubContext";
import { Box } from "@radix-ui/themes";
import { sortByKeyAscending, sortByKeyDescending } from "@/lib/utils/sort";
import FilterBar from "./FilterBar";
import ReposCard from "./ReposCard";
import { VList } from "virtua";
import Loading from "@/app/loading";

type SetSelectedFunction = (value: string) => void;
import { useRepositoryFilters } from "@/hooks/useRepositoryFilters";
import { extractUniqueValues } from "@/lib/utils";

export default function Repositories() {
const { repos, loading } = useContext(GithubContext);
const [sort, setSort] = useState("Stars Descending");
const [filterValue, setFilterValue] = useState("");
const [selectedTopic, setSelectedTopic] = useState("");
const [selectedLanguage, setSelectedLanguage] = useState("");
const [selectedFilter, setSelectedFilter] = useState("All");
const [selectedLicense, setSelectedLicense] = useState("");

const handleFilterClick = (
value: string,
setSelectedFunction: SetSelectedFunction,
selectedValue: string,
): void => {
setSelectedFunction(value);
// Reset filter if the same value is clicked again
if (value === selectedValue) {
setSelectedFunction("");
}
};
const {
sort,
setSort,
setFilterValue,
selectedTopic,
setSelectedTopic,
selectedLanguage,
setSelectedLanguage,
selectedFilter,
setSelectedFilter,
selectedLicense,
setSelectedLicense,
handleFilterClick,
filteredAndSortedRepos,
} = useRepositoryFilters(repos);

const handleTopicClick = (topic: string): void => {
handleFilterClick(topic, setSelectedTopic, selectedTopic);
Expand All @@ -43,81 +39,15 @@ export default function Repositories() {
handleFilterClick(license, setSelectedLicense, selectedLicense);
};

const filteredAndSortedRepos = useMemo(() => {
const filteredRepos = repos
? repos.filter((repo: any) => {
if (selectedTopic) {
return repo.topics.includes(selectedTopic);
}
if (selectedLanguage) {
return repo.language === selectedLanguage;
}
if (selectedLicense) {
return repo.license?.spdx_id === selectedLicense;
}

const nameMatches = repo.name
.toLowerCase()
.includes(filterValue.toLowerCase());
const isForked = repo.fork;
const isNotForked = !repo.fork;

switch (selectedFilter) {
case "All":
return nameMatches;
case "Forked":
return nameMatches && isForked;
case "Not Forked":
return nameMatches && isNotForked;
default:
return nameMatches;
}
})
: [];

switch (sort) {
case "Created Ascending":
return sortByKeyAscending(filteredRepos, "created_at");
case "Created Descending":
return sortByKeyDescending(filteredRepos, "created_at");
case "Updated Ascending":
return sortByKeyAscending(filteredRepos, "pushed_at");
case "Updated Descending":
return sortByKeyDescending(filteredRepos, "pushed_at");
case "Stars Ascending":
return sortByKeyAscending(filteredRepos, "stargazers_count");
default:
return sortByKeyDescending(filteredRepos, "stargazers_count");
}
}, [
repos,
sort,
selectedTopic,
selectedLanguage,
selectedLicense,
filterValue,
selectedFilter,
]);

const uniqueLanguages = useMemo(() => {
const languagesSet = new Set<string>();
filteredAndSortedRepos.forEach((repo: GitHubRepo) => {
if (repo.language) {
languagesSet.add(repo.language);
}
});
return Array.from(languagesSet);
}, [filteredAndSortedRepos]);
const uniqueLanguages = useMemo(
() => extractUniqueValues(filteredAndSortedRepos, "language"),
[filteredAndSortedRepos],
);

const uniqueLicenses = useMemo(() => {
const licenseSet = new Set<string>();
filteredAndSortedRepos.forEach((repo: GitHubRepo) => {
if (repo.license?.spdx_id) {
licenseSet.add(repo.license.spdx_id);
}
});
return Array.from(licenseSet);
}, [filteredAndSortedRepos]);
const uniqueLicenses = useMemo(
() => extractUniqueValues(filteredAndSortedRepos, "license", "spdx_id"),
[filteredAndSortedRepos],
);

const uniqueTopics = useMemo(() => {
const topicSet = new Set<string>();
Expand Down
98 changes: 98 additions & 0 deletions hooks/useRepositoryFilters.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
// hooks/useRepositoryFilters.ts
import { useState, useMemo } from "react";
import { sortByKeyAscending, sortByKeyDescending } from "@/lib/utils/sort";

type SetSelectedFunction = (value: string) => void;

export const useRepositoryFilters = (repos: GitHubRepo[]) => {
const [sort, setSort] = useState("Stars Descending");
const [filterValue, setFilterValue] = useState("");
const [selectedTopic, setSelectedTopic] = useState("");
const [selectedLanguage, setSelectedLanguage] = useState("");
const [selectedFilter, setSelectedFilter] = useState("All");
const [selectedLicense, setSelectedLicense] = useState("");

const handleFilterClick = (
value: string,
setSelectedFunction: SetSelectedFunction,
selectedValue: string,
): void => {
setSelectedFunction(value);
if (value === selectedValue) {
setSelectedFunction("");
}
};

const filteredAndSortedRepos = useMemo(() => {
const filteredRepos = repos
? repos.filter((repo: any) => {
if (selectedTopic) {
return repo.topics.includes(selectedTopic);
}
if (selectedLanguage) {
return repo.language === selectedLanguage;
}
if (selectedLicense) {
return repo.license?.spdx_id === selectedLicense;
}

const nameMatches = repo.name
.toLowerCase()
.includes(filterValue.toLowerCase());
const isForked = repo.fork;
const isNotForked = !repo.fork;

switch (selectedFilter) {
case "All":
return nameMatches;
case "Forked":
return nameMatches && isForked;
case "Not Forked":
return nameMatches && isNotForked;
default:
return nameMatches;
}
})
: [];

switch (sort) {
case "Created Ascending":
return sortByKeyAscending(filteredRepos, "created_at");
case "Created Descending":
return sortByKeyDescending(filteredRepos, "created_at");
case "Updated Ascending":
return sortByKeyAscending(filteredRepos, "pushed_at");
case "Updated Descending":
return sortByKeyDescending(filteredRepos, "pushed_at");
case "Stars Ascending":
return sortByKeyAscending(filteredRepos, "stargazers_count");
default:
return sortByKeyDescending(filteredRepos, "stargazers_count");
}
}, [
repos,
sort,
selectedTopic,
selectedLanguage,
selectedLicense,
filterValue,
selectedFilter,
]);

return {
sort,
setSort,
filterValue,
setFilterValue,
selectedTopic,
setSelectedTopic,
selectedLanguage,
setSelectedLanguage,
selectedFilter,
setSelectedFilter,
selectedLicense,
setSelectedLicense,
handleFilterClick,
filteredAndSortedRepos,
};
};
19 changes: 19 additions & 0 deletions lib/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,3 +97,22 @@ export function formatNumber(number: number) {
return number;
}
}

export const extractUniqueValues = <T, K extends keyof T>(
items: T[],
key: K,
subKey?: Extract<keyof T[K], string>,
): string[] => {
const uniqueSet = new Set<string>();
items.forEach((item) => {
const value = item[key];
if (typeof value === "object" && value !== null && subKey !== undefined) {
if (typeof subKey === "string" && subKey in value) {
uniqueSet.add(String(value[subKey]));
}
} else if (typeof value === "string") {
uniqueSet.add(value);
}
});
return Array.from(uniqueSet);
};
Loading

1 comment on commit 1d79cee

@vercel
Copy link

@vercel vercel bot commented on 1d79cee Feb 5, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.