Skip to content

Commit

Permalink
feat: Controlled filters from labels picking
Browse files Browse the repository at this point in the history
  • Loading branch information
ipapandinas committed Jan 17, 2024
1 parent bf7b634 commit be2a91e
Show file tree
Hide file tree
Showing 6 changed files with 91 additions and 19 deletions.
24 changes: 10 additions & 14 deletions app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import ContributionsTable from "@/components/contributions-table/table";
import Toolbar from "@/components/filters/toolbar";
import ControlledTable from "@/components/controlled-table";
import CtaBanner from "@/components/cta-banner";
import { title } from "@/components/primitives";
import { queryDatabase } from "@/lib/notion";
import { containerStyle } from "@/styles";
import { PaginatedCustomDataResponse } from "@/types";
import { Contribution } from "@/types/contribution";
import { SearchParams } from "@/types/filters";
import {
processNotionFilters,
Expand All @@ -21,7 +22,7 @@ export default async function Home({ searchParams }: IHomeProps) {
filter,
});
const contributions = transformNotionDataToContributions(data);
const items = {
const items: PaginatedCustomDataResponse<Contribution> = {
data: contributions,
hasMore: data.has_more,
nextCursor: data.next_cursor ?? undefined,
Expand All @@ -38,17 +39,12 @@ export default async function Home({ searchParams }: IHomeProps) {
<section className={containerStyle}>
<CtaBanner />
</section>
<div className="flex flex-col pt-10">
<Toolbar searchParams={searchParams} />
<section className={containerStyle}>
<ContributionsTable
items={items}
queries={{
page_size: 10,
filter,
}}
/>
</section>
<div className="pt-10">
<ControlledTable
filter={filter}
items={items}
searchParams={searchParams}
/>
</div>
</>
);
Expand Down
6 changes: 5 additions & 1 deletion components/contributions-table/row.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { useState, useRef, useEffect, useMemo } from "react";
import { usePathname, useSearchParams, useRouter } from "next/navigation";
import { Chip } from "@nextui-org/chip";
import { Link } from "@nextui-org/link";
import { Tooltip } from "@nextui-org/tooltip";
import Emoji from "@/components/emoji";
import MyImage from "@/components/ui/image";
import { useFilters } from "@/contexts/filters";
import { formatDate } from "@/utils/date";
import { useState, useRef, useEffect, useMemo } from "react";
import { getProjectUrls } from "@/utils/github";
import {
findInterestsByProject,
Expand Down Expand Up @@ -145,6 +146,8 @@ export const Labels = ({
const pathname = usePathname();
const params = useSearchParams();

const { updateFilter } = useFilters();

const [visibleLabelCount, setVisibleLabelCount] = useState(1);
const containerRef = useRef<HTMLDivElement>(null);
const indicatorRef = useRef<HTMLDivElement>(null);
Expand All @@ -163,6 +166,7 @@ export const Labels = ({

const handleClick = (label: { type: string; value: string }) => {
const paramKey = label.type;
updateFilter(paramKey, label.value);
const newUrl = createUrl(paramKey, label.value, pathname, params);
router.replace(newUrl, { scroll: false });
};
Expand Down
38 changes: 38 additions & 0 deletions components/controlled-table.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import React from "react";
import ContributionsTable from "@/components/contributions-table/table";
import Toolbar from "@/components/filters/toolbar";
import { FiltersProvider } from "@/contexts/filters";
import { containerStyle } from "@/styles";
import { PaginatedCustomDataResponse } from "@/types";
import { Contribution } from "@/types/contribution";
import { SearchParams } from "@/types/filters";

interface IControlledTableProps {
filter: any;
items: PaginatedCustomDataResponse<Contribution>;
searchParams: SearchParams;
}
const ControlledTable = ({
filter,
items,
searchParams,
}: IControlledTableProps) => {
return (
<FiltersProvider initialParams={searchParams}>
<div className="flex flex-col">
<Toolbar searchParams={searchParams} />
<section className={containerStyle}>
<ContributionsTable
items={items}
queries={{
page_size: 10,
filter,
}}
/>
</section>
</div>
</FiltersProvider>
);
};

export default ControlledTable;
6 changes: 2 additions & 4 deletions components/filters/toolbar.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
"use client";
import { useRef } from "react";
import { useFilters } from "@/contexts/filters";
import {
LANGUAGES_OPTIONS,
INTERESTS_OPTIONS,
Expand All @@ -9,7 +10,6 @@ import {
LANGUAGES_KEY,
PROJECTS_KEY,
} from "@/data/filters";
import { useFilters } from "@/hooks/useFilters";
import useSticky from "@/hooks/useSticky";
import { containerStyle } from "@/styles";
import { SearchParams } from "@/types/filters";
Expand All @@ -24,9 +24,7 @@ const Toolbar = ({ searchParams }: IToolbarProps) => {
const toolbarRef = useRef<HTMLDivElement>(null);
const isToolbarSticky = useSticky(toolbarRef);

const { filters, updateFilter, clearFilter, clearAllFilters } = useFilters({
initialParams: searchParams,
});
const { filters, updateFilter, clearFilter, clearAllFilters } = useFilters();

const handleSelect = (paramKey: string) => (value: string | null) => {
if (value) {
Expand Down
13 changes: 13 additions & 0 deletions contexts/filters.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
"use client";

import {
IConfigProps,
IFiltersContext,
useFilters as filtersHook,
} from "@/hooks/useFilters";
import { provideContext } from "@/utils/providers";

export const [FiltersProvider, useFilters] = provideContext<
IConfigProps,
IFiltersContext
>(filtersHook);
23 changes: 23 additions & 0 deletions utils/providers.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import type { FC, ReactNode } from "react";
import { createContext, useContext } from "react";

// This utility generates a context provider from a react hook passed as argument
// Returns an array containing the provider and the consumer hook
export const provideContext = <P, T>(useProviderContext: (props: P) => T) => {
// automatic typing based on our hook's return type
type ContextType = ReturnType<typeof useProviderContext>;
type ProviderProps = P & { children?: ReactNode };
type ProviderType = FC<ProviderProps>;

const Context = createContext({} as ContextType);

const Provider: ProviderType = ({ children, ...props }: ProviderProps) => {
const ctx = useProviderContext(props as P);

return <Context.Provider value={ctx}>{children}</Context.Provider>;
};

const useProvidedContext = () => useContext(Context);

return [Provider, useProvidedContext] as [ProviderType, () => ContextType];
};

0 comments on commit be2a91e

Please sign in to comment.