Skip to content

Commit

Permalink
Merge pull request #30 from kudos-ink/feat/checkbox-filter-good-first…
Browse files Browse the repository at this point in the history
…-issue

Feat/checkbox filter good first issue
ipapandinas authored Jan 17, 2024
2 parents d566916 + 6b15a6a commit 3083ec4
Showing 10 changed files with 108 additions and 33 deletions.
44 changes: 44 additions & 0 deletions components/filters/checkbox-filter.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
"use client";
import React from "react";
import { usePathname, useRouter, useSearchParams } from "next/navigation";
import { Checkbox } from "@nextui-org/checkbox";
import { createUrl } from "@/utils/url";

interface ICheckboxFilterProps {
paramKey: string;
placeholder: string;
isSelected?: boolean;
onSelect: (value: string | null) => void;
}
export const CheckboxFilter = ({
paramKey,
placeholder,
isSelected,
onSelect,
}: ICheckboxFilterProps) => {
const router = useRouter();
const pathname = usePathname();
const params = useSearchParams();

const handleValueChange = (value: boolean) => {
const newValue = value ? value.toString() : null;
onSelect(newValue);
const newUrl = createUrl(paramKey, newValue, pathname, params);
router.replace(newUrl, { scroll: false });
};

return (
<Checkbox
classNames={{
wrapper: "before:border-default-200 before:border-medium",
label: "whitespace-nowrap",
}}
isSelected={isSelected}
onValueChange={handleValueChange}
>
{placeholder}
</Checkbox>
);
};

export default CheckboxFilter;
11 changes: 5 additions & 6 deletions components/filters/clear-filters.tsx
Original file line number Diff line number Diff line change
@@ -14,19 +14,18 @@ interface IClearFilters {
export const ClearFilters = ({ param, value, onClear }: IClearFilters) => {
const router = useRouter();
const pathname = usePathname();
const searchParams = useSearchParams();
const params = useSearchParams();

const clearSearchParams = () => {
if (!!param) {
const optionNameLowerCase = param.toLowerCase();
const optionSearchParams = new URLSearchParams(searchParams.toString());
optionSearchParams.delete(optionNameLowerCase);
const optionUrl = createUrl(pathname, optionSearchParams);
router.replace(optionUrl);
const newUrl = createUrl(param, null, pathname, params);
router.replace(newUrl);
} else {
router.replace(pathname);
}
onClear();
};

return (
<div className="flex gap-4">
<Chip
13 changes: 3 additions & 10 deletions components/filters/select-filter.tsx
Original file line number Diff line number Diff line change
@@ -24,20 +24,13 @@ export const SelectFilter = ({
}: ISelectFilterProps) => {
const router = useRouter();
const pathname = usePathname();
const searchParams = useSearchParams();
const params = useSearchParams();

const handleSelectionChange = (selection: unknown) => {
const selectedValue = Array.from(selection as Iterable<string>)[0];
onSelect(selectedValue);
const optionNameLowerCase = placeholder.toLowerCase();
const optionSearchParams = new URLSearchParams(searchParams.toString());
if (selectedValue) {
optionSearchParams.set(optionNameLowerCase, selectedValue);
} else {
optionSearchParams.delete(optionNameLowerCase);
}
const optionUrl = createUrl(pathname, optionSearchParams);
router.replace(optionUrl, { scroll: false });
const newUrl = createUrl(placeholder, selectedValue, pathname, params);
router.replace(newUrl, { scroll: false });
};

const resetFilter = () => {
12 changes: 10 additions & 2 deletions components/filters/toolbar.tsx
Original file line number Diff line number Diff line change
@@ -3,10 +3,12 @@ import {
LANGUAGES_OPTIONS,
INTERESTS_OPTIONS,
PROJECTS_OPTIONS,
GOOD_FIRST_ISSUE_KEY,
} from "@/data/filters";
import { useFilters } from "@/hooks/useFilters";
import useSticky from "@/hooks/useSticky";
import { SearchParams } from "@/types/filters";
import CheckboxFilter from "./checkbox-filter";
import ClearFilters from "./clear-filters";
import SelectFilter from "./select-filter";
import { useRef } from "react";
@@ -22,7 +24,7 @@ const Toolbar = ({ searchParams }: IToolbarProps) => {
initialParams: searchParams,
});

const handleSelect = (paramKey: string) => (value: string) => {
const handleSelect = (paramKey: string) => (value: string | null) => {
if (value) {
updateFilter(paramKey, value);
} else {
@@ -40,7 +42,7 @@ const Toolbar = ({ searchParams }: IToolbarProps) => {
>
<div className="container mx-auto max-w-7xl px-6 pt-6 flex flex-col gap-4">
<div className="flex flex-col gap-4 items-start overflow-hidden lg:flex-row lg:items-center">
<div className="flex flex-nowrap overflow-x-auto gap-4 w-full sm:w-auto">
<div className="flex flex-nowrap overflow-x-auto overflow-y-hidden gap-4 w-full sm:w-auto xl:overflow-visible">
<SelectFilter
placeholder="Languages"
mainEmoji="🌐"
@@ -62,6 +64,12 @@ const Toolbar = ({ searchParams }: IToolbarProps) => {
selectedKey={filters.projects}
onSelect={handleSelect("projects")}
/>
<CheckboxFilter
paramKey={GOOD_FIRST_ISSUE_KEY}
placeholder="Good first issues Only"
isSelected={filters[GOOD_FIRST_ISSUE_KEY] === "true"}
onSelect={handleSelect(GOOD_FIRST_ISSUE_KEY)}
/>
</div>

{numberOfFilters > 1 && (
14 changes: 4 additions & 10 deletions components/search.tsx
Original file line number Diff line number Diff line change
@@ -24,7 +24,7 @@ const Search: FC<SearchProps> = ({

const router = useRouter();
const pathname = usePathname();
const searchParams = useSearchParams();
const params = useSearchParams();

useEffect(() => {
setValue(selectedValue || "");
@@ -34,16 +34,10 @@ const Search: FC<SearchProps> = ({
if (value === undefined || value === "") {
return;
}
const optionNameLowerCase = placeholder.toLowerCase();
const optionSearchParams = new URLSearchParams(searchParams.toString());
if (value !== null) {
optionSearchParams.set(optionNameLowerCase, value);
} else {
optionSearchParams.delete(optionNameLowerCase);
}
const optionUrl = createUrl(pathname, optionSearchParams);
router.replace(optionUrl, { scroll: false });
const newUrl = createUrl(placeholder, value, pathname, params);
router.replace(newUrl, { scroll: false });
}, [value]);

return (
<Autocomplete
placeholder={placeholder}
9 changes: 9 additions & 0 deletions data/filters.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
export const GOOD_FIRST_ISSUE_KEY = "good-first-issue";
export const GOOD_FIRST_ISSUE_LABELS = [
"good first issue",
"C-good-first-issue",
"good first issue :baby:",
"c1-mentor",
"d0-easy",
];

export const LANGUAGES_OPTIONS = [
{ value: "Rust", label: "Rust", emoji: "🦀" }, // Rust
{ value: "Ink", label: "Ink!", emoji: "🐙" }, // Ink
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -12,6 +12,7 @@
"dependencies": {
"@nextui-org/autocomplete": "^2.0.9",
"@nextui-org/button": "2.0.26",
"@nextui-org/checkbox": "^2.0.25",
"@nextui-org/chip": "^2.0.25",
"@nextui-org/dropdown": "^2.1.16",
"@nextui-org/image": "^2.0.24",
3 changes: 3 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

18 changes: 16 additions & 2 deletions utils/notion.ts
Original file line number Diff line number Diff line change
@@ -7,7 +7,11 @@ import { ValidRepositoryLink } from "@/lib/notion/types";
import projectLogosJson from "@/public/images/imageMap.json";
import { Contribution } from "@/types/contribution";
import { getImagePath } from "./github";
import { REPOSITORIES_BY_INTERESTS } from "@/data/filters";
import {
GOOD_FIRST_ISSUE_KEY,
GOOD_FIRST_ISSUE_LABELS,
REPOSITORIES_BY_INTERESTS,
} from "@/data/filters";

export function transformNotionDataToContributions(
notionData: QueryDatabaseResponse,
@@ -61,7 +65,6 @@ export function processNotionFilters(params?: {
REPO_LINK_TO_PAGE_ID_MAP[
params.projects as unknown as ValidRepositoryLink
];
console.log(repositories);
filters.push({
property: "Github Repo",
relation: {
@@ -86,6 +89,17 @@ export function processNotionFilters(params?: {
filters.push(interestsFilter);
}

if (params?.[GOOD_FIRST_ISSUE_KEY]) {
filters.push({
or: GOOD_FIRST_ISSUE_LABELS.map((label) => ({
property: "Issue Labels",
multi_select: {
contains: label,
},
})),
});
}

if (filters.length === 1) {
return filters[0];
} else if (filters.length > 1) {
16 changes: 13 additions & 3 deletions utils/url.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,21 @@
import { ReadonlyURLSearchParams } from "next/navigation";

export const createUrl = (
key: string,
value: string | null | undefined,
pathname: string,
params: URLSearchParams | ReadonlyURLSearchParams,
) => {
const paramsString = params.toString();
const queryString = `${paramsString.length ? "?" : ""}${paramsString}`;
const keyLowerCase = key.toLowerCase();
const searchParams = new URLSearchParams(params.toString());
if (value) {
searchParams.set(keyLowerCase, value.toString());
} else {
searchParams.delete(keyLowerCase);
}

return `${pathname}${queryString}`;
const newParams = searchParams.toString();
const queryString = `${newParams.length ? "?" : ""}${newParams}`;
const url = `${pathname}${queryString}`;
return url;
};

0 comments on commit 3083ec4

Please sign in to comment.