Skip to content

Commit

Permalink
dynamic filters
Browse files Browse the repository at this point in the history
  • Loading branch information
ipapandinas committed Nov 3, 2024
1 parent 5837706 commit 87005af
Show file tree
Hide file tree
Showing 29 changed files with 282 additions and 272 deletions.
18 changes: 17 additions & 1 deletion api/core/_client.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,21 @@
import { sanitizeUrl } from "@/utils/url";
import { prepareUrl, sanitizeUrl } from "@/utils/url";
import APIClient from "@/api/client";

const CORE_API_URL = sanitizeUrl(process.env.NEXT_PUBLIC_API_URL || "");

export async function fetchFromApi<T>(
endpoint: string,
queryParams: Record<string, any>,
tag?: string,
): Promise<T> {
try {
const url = prepareUrl(endpoint, queryParams);
const config = tag ? { tag } : { noStoreCache: true };
return await coreApiClient.get<T>(url, config);
} catch (error) {
console.error(`Error fetching data from ${endpoint}:`, error);
throw error;
}
}

export const coreApiClient = new APIClient(CORE_API_URL);
51 changes: 31 additions & 20 deletions api/core/_transformers.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
import { GOOD_FIRST_ISSUE_LABELS, KUDOS_ISSUE_LABELS } from "@/data/filters";
import { TRACKED_LABELS } from "@/data/filters";
import {
Issue,
IssueDto,
IssueQueryParamsWithPagination,
IssueQueryParamsDto,
} from "@/types/issue";
import { Project, ProjectDto } from "@/types/project";
import {
Project,
ProjectDto,
ProjectQueryParams,
ProjectQueryParamsDto,
} from "@/types/project";
import {
LanguageQueryParams,
LanguageQueryParamsDto,
Expand Down Expand Up @@ -45,7 +50,7 @@ export function dtoToProject(dto: ProjectDto): Project {
name: dto.name,
slug: dto.slug,
avatar: dto.avatar ?? null,
categories: dto.categories ?? [],
types: dto.types ?? [],
purposes: dto.purposes ?? [],
stack_levels: dto.stack_levels ?? [],
technologies: dto.technologies ?? [],
Expand All @@ -56,7 +61,7 @@ export function issueQueryParamsToDto(
query: IssueQueryParamsWithPagination,
allLanguages: string[],
): IssueQueryParamsDto {
const { technologies = [], labels, kudos } = query;
const { technologies = [], labels } = query;

const languageSlugs = technologies.filter((tech) =>
allLanguages.includes(tech),
Expand All @@ -65,17 +70,13 @@ export function issueQueryParamsToDto(
(tech) => !allLanguages.includes(tech),
);

const combinedLabels =
labels === undefined
? kudos
? KUDOS_ISSUE_LABELS
: [...GOOD_FIRST_ISSUE_LABELS, ...KUDOS_ISSUE_LABELS]
: labels;
const combinedLabels = labels === undefined ? TRACKED_LABELS : labels;

return {
slugs: query.projects,
certified: query.certified,
purposes: query.purposes,
types: query.types,
stack_levels: query.stackLevels,
labels: combinedLabels.length > 0 ? combinedLabels : undefined,
open: query.open,
Expand All @@ -91,20 +92,30 @@ export function issueQueryParamsToDto(
export function languageQueryParamsToDto(
query?: LanguageQueryParams,
): LanguageQueryParamsDto {
const labels = query?.labels ?? [];

const combinedLabels = [
...labels,
...GOOD_FIRST_ISSUE_LABELS,
...KUDOS_ISSUE_LABELS,
];

return {
open: query?.open,
slugs: query?.projects,
certified: query?.certified,
labels: combinedLabels.length > 0 ? combinedLabels : undefined,
labels: query?.labels,
with_technologies: query?.withTechnologies,
certified_or_labels: combinedLabels.length > 0 && query?.certified,
certified_or_labels:
query?.labels && query.labels.length > 0 && query?.certified,
};
}

export function projectQueryParamsToDto(
query: ProjectQueryParams,
): ProjectQueryParamsDto {
return {
purposes: query.purposes,
stack_levels: query.stackLevels,
technologies: query.technologies,
open: query.open,
slugs: query.slugs,
certified: query.certified,
rewards: query.withRewards,
labels: query.labels,
certified_or_labels:
query?.labels && query.labels.length > 0 && query.certified,
};
}
30 changes: 17 additions & 13 deletions api/core/issues.ts
Original file line number Diff line number Diff line change
@@ -1,31 +1,35 @@
import { DEFAULT_QUERY } from "@/data/fetch";
import { DEFAULT_QUERY_FILTERS, DEFAULT_PAGINATION } from "@/data/fetch";
import { IssueQueryParams, IssueDto, Issue } from "@/types/issue";
import {
PaginationQueryParams,
PaginatedCustomResponse,
PaginatedCustomResponseDto,
} from "@/types/pagination";
import { prepareUrl } from "@/utils/url";
import { coreApiClient } from "./_client";
import { mergeWithDefaultFilters } from "@/utils/url";
import { fetchFromApi } from "./_client";
import { dtoToIssue, issueQueryParamsToDto } from "./_transformers";
import { getAllLanguages } from "./languages";

const ISSUES_PATH = "/issues";

export async function getIssues(
query: IssueQueryParams & PaginationQueryParams = DEFAULT_QUERY,
query: IssueQueryParams & PaginationQueryParams = DEFAULT_PAGINATION,
tag?: string,
): Promise<PaginatedCustomResponse<Issue>> {
let allLanguages: string[] = [];
if (query?.technologies?.length) {
allLanguages = await getAllLanguages({ labels: query.labels });
}
const mergedQuery = mergeWithDefaultFilters(query, {
...DEFAULT_PAGINATION,
...DEFAULT_QUERY_FILTERS,
});

const queryDto = issueQueryParamsToDto(query, allLanguages);
const url = prepareUrl(`${ISSUES_PATH}`, queryDto);
const res = await coreApiClient.get<PaginatedCustomResponseDto<IssueDto>>(
url,
tag ? { tag } : { noStoreCache: true },
const allLanguages = mergedQuery.technologies?.length
? await getAllLanguages({ labels: mergedQuery.labels })
: [];
const queryDto = issueQueryParamsToDto(mergedQuery, allLanguages);

const res = await fetchFromApi<PaginatedCustomResponseDto<IssueDto>>(
ISSUES_PATH,
queryDto,
tag,
);

return {
Expand Down
24 changes: 12 additions & 12 deletions api/core/languages.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
import { LanguageQueryParams } from "@/types/repository";
import tags from "@/utils/tags";
import { prepareUrl } from "@/utils/url";
import { coreApiClient } from "./_client";
import { mergeWithDefaultFilters } from "@/utils/url";
import { fetchFromApi } from "./_client";
import { languageQueryParamsToDto } from "./_transformers";
import { DEFAULT_QUERY_FILTERS } from "@/data/fetch";

const LANGUAGES_PATH = "/languages";

export async function getAllLanguages(query?: LanguageQueryParams) {
const queryDto = languageQueryParamsToDto(query);
const url = prepareUrl(`${LANGUAGES_PATH}`, queryDto);
export async function getAllLanguages(query: LanguageQueryParams) {
const mergedQuery = mergeWithDefaultFilters(query, DEFAULT_QUERY_FILTERS);
const queryDto = languageQueryParamsToDto(mergedQuery);

const response = await coreApiClient.get<string[]>(url, {
tag: tags.languages,
});

const uniqueLanguages = Array.from(
const response = await fetchFromApi<string[]>(
LANGUAGES_PATH,
queryDto,
tags.languages,
);
return Array.from(
new Set(response.map((language) => language.toLowerCase())),
);

return uniqueLanguages;
}

export default { getAllLanguages };
47 changes: 33 additions & 14 deletions api/core/projects.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,34 @@
import { DEFAULT_QUERY } from "@/data/fetch";
import { DEFAULT_PAGINATION, DEFAULT_QUERY_FILTERS } from "@/data/fetch";
import {
PaginatedCustomResponse,
PaginatedCustomResponseDto,
PaginationQueryParams,
} from "@/types/pagination";
import { ProjectDto, ProjectQueryParams } from "@/types/project";
import {
Project,
ProjectDto,
ProjectOptions,
ProjectQueryParams,
} from "@/types/project";
import tags from "@/utils/tags";
import { prepareUrl } from "@/utils/url";
import { coreApiClient } from "./_client";
import { dtoToProject } from "./_transformers";
import { mergeWithDefaultFilters } from "@/utils/url";
import { fetchFromApi } from "./_client";
import { dtoToProject, projectQueryParamsToDto } from "./_transformers";

const PROJECTS_PATH = "/projects";
const PROJECT_OPTIONS_PATH = "/projects/options";

export async function getProjects(
query: ProjectQueryParams & PaginationQueryParams = DEFAULT_QUERY,
query: ProjectQueryParams & PaginationQueryParams = DEFAULT_PAGINATION,
tag?: string,
) {
const url = prepareUrl(PROJECTS_PATH, query);
): Promise<PaginatedCustomResponse<Project>> {
const nextTag = tag ?? tags.projects(query.slugs?.join("-") || "");
const mergedQuery = mergeWithDefaultFilters(query, DEFAULT_PAGINATION);

const res = await coreApiClient.get<PaginatedCustomResponseDto<ProjectDto>>(
url,
{
tag: nextTag,
},
const res = await fetchFromApi<PaginatedCustomResponseDto<ProjectDto>>(
PROJECTS_PATH,
mergedQuery,
nextTag,
);

return {
Expand All @@ -33,4 +39,17 @@ export async function getProjects(
};
}

export default { getProjects };
export async function getProjectOptions(
query: ProjectQueryParams,
): Promise<ProjectOptions> {
const mergedQuery = mergeWithDefaultFilters(query, DEFAULT_QUERY_FILTERS);
const queryDto = projectQueryParamsToDto(mergedQuery);

return await fetchFromApi<ProjectOptions>(
PROJECT_OPTIONS_PATH,
queryDto,
tags.projectOptions,
);
}

export default { getProjects, getProjectOptions };
35 changes: 0 additions & 35 deletions api/core/repositories.ts

This file was deleted.

40 changes: 10 additions & 30 deletions app/carnival/page.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,20 @@
import { Button } from "@nextui-org/button";
import { Link } from "@nextui-org/link";
import { IconSocial, IconWeb } from "@/assets/icons";
import IssuesApi from "@/api/core/issues";
import ProjectsApi from "@/api/core/projects";
import Toolbar from "@/components/filters/toolbar";
import { Project, ProjectQueryParams } from "@/types/project";
import { container } from "@/components/primitives";
import PaginatedTable from "@/components/table/paginated-table";
import { FiltersProvider } from "@/contexts/filters";
import { SITE_CONFIG } from "@/data/config";
import { DEFAULT_PAGINATED_RESPONSE, DEFAULT_QUERY } from "@/data/fetch";
import { DEFAULT_PAGINATION } from "@/data/fetch";
import { getFilterOptions } from "@/lib/filters";
import { initFilters } from "@/utils/filters";
import { FilterOptions } from "@/types/filters";
import { Issue, IssueQueryParams } from "@/types/issue";
import { IssueQueryParams } from "@/types/issue";
import { Leaderboard } from "@/types/leaderboard";
import { PaginatedCustomResponse } from "@/types/pagination";
import EventBanner from "./_components/EventBanner";
import { fetchIssues } from "@/lib/api/issues";
import { fetchProjects } from "@/lib/api/projects";

const MOCKED_WEEKLY_LEADERBOARD: Leaderboard[] = [
{
Expand Down Expand Up @@ -147,31 +145,14 @@ export default async function SingleEventPage() {
return {} as FilterOptions;
});

const query: IssueQueryParams = {
certified: true,
open: true,
const issuesQuery: IssueQueryParams = {
labels: [],
};

const projectQuery: ProjectQueryParams = {
const issues = await fetchIssues(issuesQuery);
const projects = await fetchProjects({
certified: true,
};

const issues = (await IssuesApi.getIssues({
...DEFAULT_QUERY,
...query,
}).catch((error) => {
console.error(`Error fetching Kudos Carnival issues:`, error);
return DEFAULT_PAGINATED_RESPONSE;
})) as PaginatedCustomResponse<Issue>;

const projects = (await ProjectsApi.getProjects({
...DEFAULT_QUERY,
...projectQuery,
}).catch((error) => {
console.error(`Error fetching Kudos Carnival projects:`, error);
return DEFAULT_PAGINATED_RESPONSE;
})) as PaginatedCustomResponse<Project>;
});

return (
<>
Expand Down Expand Up @@ -345,9 +326,8 @@ export default async function SingleEventPage() {
/>
<section className={container()}>
<PaginatedTable
initialItems={issues}
query={query}
pagination={DEFAULT_QUERY}
query={issuesQuery}
pagination={DEFAULT_PAGINATION}
emptyContent="Label your issues with 'kudos' to have them featured in the backlog"
/>
</section>
Expand Down
Loading

0 comments on commit 87005af

Please sign in to comment.