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

sorting issue #30 #38

Merged
merged 6 commits into from
Mar 5, 2024
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
1 change: 1 addition & 0 deletions .husky/pre-commit
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@
. "$(dirname -- "$0")/_/husky.sh"

pnpm lint
pnpm test
30 changes: 25 additions & 5 deletions components/Picker/SortPicker.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
import { RepositorySortOrder } from "@/types/types";
import { RepositorySortOrder, RepositorySortType } from "@/types/types";
import { faCaretDown, faCaretUp, faShuffle } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import classNames from "classnames";
import { SectionTitle } from "../SectionTitle";

type SortPickerProps = {
activeSort: RepositorySortOrder;
sortType: RepositorySortType;
sortOptions: RepositorySortOrder[];
onSortOrderSelect: (sortOrder: RepositorySortOrder) => void;
onSortOrderSelect: (sortOrder: RepositorySortOrder, sortType: RepositorySortType) => void;
};

export const SortPicker = ({ activeSort, sortOptions, onSortOrderSelect }: SortPickerProps) => {
export const SortPicker = ({
activeSort,
sortOptions,
onSortOrderSelect,
sortType
}: SortPickerProps) => {
return (
<div
className="flex flex-col justify-between pt-6 lg:flex-row lg:items-center lg:pt-0"
Expand All @@ -22,7 +29,7 @@ export const SortPicker = ({ activeSort, sortOptions, onSortOrderSelect }: SortP
return (
<button
key={sortOption}
onClick={() => onSortOrderSelect(sortOption)}
onClick={() => onSortOrderSelect(sortOption, sortType)}
className={classNames("group m-1 inline-block rounded-sm border px-2 py-1", {
["active-pill"]: activeSort === sortOption,
["border-silver-100 transition-all hover:border-primary hover:text-primary"]: !(
Expand All @@ -31,6 +38,19 @@ export const SortPicker = ({ activeSort, sortOptions, onSortOrderSelect }: SortP
})}
>
{sortOption}
{activeSort === sortOption && (
<>
{sortType === RepositorySortType.ASCENDING && (
<FontAwesomeIcon icon={faCaretUp} className="ms-1" />
)}
{sortType === RepositorySortType.DESCENDING && (
<FontAwesomeIcon icon={faCaretDown} className="ms-1" />
)}
{sortType === RepositorySortType.NONE && (
<FontAwesomeIcon icon={faShuffle} className="ms-1" />
)}
</>
)}
</button>
);
})}
Expand Down
2 changes: 2 additions & 0 deletions components/Repository/RepositoryList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export const RepositoryList = ({ languageId, categoryId, tagId }: RepositoryList
const [items, setItems] = useState(itemsPerScroll);
const {
repositories,
repositorySortType,
repositorySortOrder,
updateRepositorySortOrder,
filterRepositoriesByTag,
Expand Down Expand Up @@ -58,6 +59,7 @@ export const RepositoryList = ({ languageId, categoryId, tagId }: RepositoryList
activeSort={repositorySortOrder}
sortOptions={REPOSITORY_SORT_OPTIONS}
onSortOrderSelect={updateRepositorySortOrder}
sortType={repositorySortType}
/>
<SearchBar />
<InfiniteScroll
Expand Down
6 changes: 2 additions & 4 deletions constants.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import { RepositorySortOrder } from "./types/types";

export const REPOSITORY_SORT_OPTIONS = [
RepositorySortOrder.NEW_ISSUES,
RepositorySortOrder.ISSUE_AGE,
RepositorySortOrder.MOST_DOWNLOADS,
RepositorySortOrder.MOST_STARS,
RepositorySortOrder.NEWEST,
RepositorySortOrder.NONE
RepositorySortOrder.MOST_STARS
];
121 changes: 75 additions & 46 deletions context/AppDataContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ import {
CountableTag,
Issue,
Repository,
RepositorySortOrder
RepositorySortOrder,
RepositorySortType
} from "@/types/types";
import { getData } from "app/data-loader";
import React, { createContext, useEffect, useState } from "react";
Expand All @@ -16,13 +17,15 @@ type AppDataContextType = AppData & {
filterRepositoriesByQuery: (query: string) => void;
filterRepositoriesByLanguage: (languageId: string) => Repository[];
filterRepositoriesByCategory: (categoryId: string) => Repository[];
updateRepositorySortOrder: (sortOrder: RepositorySortOrder, sortType: RepositorySortType) => void;
};

const DEFAULT_VALUE: AppDataContextType = {
languages: [],
categories: [],
repositories: [],
repositorySortOrder: RepositorySortOrder.NONE,
repositorySortOrder: RepositorySortOrder.ISSUE_AGE,
repositorySortType: RepositorySortType.ASCENDING,
tags: [],
query: "",
updateRepositorySortOrder: () => {},
Expand Down Expand Up @@ -56,59 +59,85 @@ const AppDataProvider = ({ children }: { children: React.ReactNode }) => {
} = data;
const [repositories, setRepositories] = useState<Repository[]>(allRepositories);
const [repositorySortOrder, setRepositorySortOrder] = useState<RepositorySortOrder>(
RepositorySortOrder.NONE
RepositorySortOrder.ISSUE_AGE
);
const [repositorySortType, setRepositorySortType] = useState<RepositorySortType>(
RepositorySortType.NONE
);

useEffect(() => {
const { repositories } = data;
setRepositories(repositories);
}, [data]);

const updateRepositorySortOrder = (sortOrder: RepositorySortOrder) => {
const isSetToDefaultSort = sortOrder === RepositorySortOrder.NONE;
const shouldDeselect = !isSetToDefaultSort && sortOrder === repositorySortOrder;

const finalSortOrder = shouldDeselect ? RepositorySortOrder.NONE : sortOrder;

setRepositorySortOrder(finalSortOrder);
updateRepositoriesOnSortChange(finalSortOrder);
};

const updateRepositoriesOnSortChange = (sortOrder: RepositorySortOrder) => {
let updatedRepositories: Repository[] = [];

// Find and return the newest issue in a given repository
if (sortOrder === RepositorySortOrder.NEW_ISSUES) {
updatedRepositories = [...allRepositories].sort((a, b) => {
const newestIssueA = getNewestIssue(a).created_at;
const newestIssueB = getNewestIssue(b).created_at;
return new Date(newestIssueB).getTime() - new Date(newestIssueA).getTime();
});
}

// Sort by number of stars
if (sortOrder === RepositorySortOrder.MOST_STARS) {
updatedRepositories = [...allRepositories].sort((a, b) => b.stars - a.stars);
}

// Sort by number of monthly downloads
if (sortOrder === RepositorySortOrder.MOST_DOWNLOADS) {
updatedRepositories = [...allRepositories].sort(
(a, b) => b.monthly_downloads - a.monthly_downloads
);
}

// Sort by newest project
if (sortOrder === RepositorySortOrder.NEWEST) {
updatedRepositories = [...allRepositories].sort(
(a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime()
);
const updateRepositorySortOrder = (
sortOrder: RepositorySortOrder,
sortType: RepositorySortType
) => {
let nextSortType: RepositorySortType;
if (sortOrder === repositorySortOrder) {
switch (sortType) {
case RepositorySortType.NONE:
nextSortType = RepositorySortType.DESCENDING;
break;
case RepositorySortType.DESCENDING:
nextSortType = RepositorySortType.ASCENDING;
break;
case RepositorySortType.ASCENDING:
default:
nextSortType = RepositorySortType.NONE;
break;
}
} else {
nextSortType = RepositorySortType.DESCENDING;
}
setRepositorySortOrder(sortOrder);
setRepositorySortType(nextSortType);
updateRepositoriesOnSortChange(sortOrder, nextSortType);
};

if (sortOrder === RepositorySortOrder.NONE) {
updatedRepositories = allRepositories;
const updateRepositoriesOnSortChange = (sortOrder: RepositorySortOrder, order) => {
let updatedRepositories: Repository[] = [...allRepositories];

switch (sortOrder) {
case RepositorySortOrder.ISSUE_AGE:
updatedRepositories = updatedRepositories.sort((a, b) => {
const newestIssueA = getNewestIssue(a).created_at;
const newestIssueB = getNewestIssue(b).created_at;
if (order === "Descending") {
return new Date(newestIssueB).getTime() - new Date(newestIssueA).getTime();
} else if (order === "Ascending") {
return new Date(newestIssueA).getTime() - new Date(newestIssueB).getTime();
} else {
return 0;
}
});
break;
case RepositorySortOrder.MOST_STARS:
updatedRepositories = updatedRepositories.sort((a, b) => {
if (order === "Descending") {
return b.stars - a.stars;
} else if (order === "Ascending") {
return a.stars - b.stars;
} else {
return 0;
}
});
break;
case RepositorySortOrder.MOST_DOWNLOADS:
updatedRepositories = updatedRepositories.sort((a, b) => {
if (order === "Descending") {
return b.monthly_downloads - a.monthly_downloads;
} else if (order === "Ascending") {
return a.monthly_downloads - b.monthly_downloads;
} else {
return 0;
}
});
break;
default:
break;
}

setRepositories(updatedRepositories);
};

Expand Down Expand Up @@ -138,12 +167,12 @@ const AppDataProvider = ({ children }: { children: React.ReactNode }) => {
const filterRepositoriesByCategory = (categoryId: string) => {
return repositories.filter((repository) => repository.category.id === categoryId);
};

const value = {
languages: data.languages,
categories: data.categories,
repositories,
repositorySortOrder,
repositorySortType,
tags: data.tags,
query,
updateRepositorySortOrder,
Expand Down
40 changes: 30 additions & 10 deletions data/__tests__/test-data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,9 @@ export const dummyRepositories: Repository[] = [
{ display: "energy-data", id: "energy-data" },
{ display: "energy-flexibility", id: "energy-flexibility" },
{ display: "machine-learning", id: "machine-learning" }
]
],
monthly_downloads: 0,
created_at: ""
},
{
id: "64170",
Expand Down Expand Up @@ -226,7 +228,9 @@ export const dummyRepositories: Repository[] = [
{ display: "water", id: "water" },
{ display: "weather", id: "weather" },
{ display: "wind", id: "wind" }
]
],
monthly_downloads: 0,
created_at: ""
},
{
id: "64174",
Expand Down Expand Up @@ -305,7 +309,9 @@ export const dummyRepositories: Repository[] = [
url: "https://github.com/WFP-VAM/prism-app/issues/443"
}
],
tags: []
tags: [],
monthly_downloads: 0,
created_at: ""
},
{
id: "64148",
Expand Down Expand Up @@ -389,7 +395,9 @@ export const dummyRepositories: Repository[] = [
{ display: "electric-vehicle", id: "electric-vehicle" },
{ display: "hacktoberfest", id: "hacktoberfest" },
{ display: "map", id: "map" }
]
],
monthly_downloads: 0,
created_at: ""
},
{
id: "857",
Expand Down Expand Up @@ -440,7 +448,9 @@ export const dummyRepositories: Repository[] = [
{ display: "pathway-analysis", id: "pathway-analysis" },
{ display: "scenario", id: "scenario" },
{ display: "sr15", id: "sr15" }
]
],
monthly_downloads: 0,
created_at: ""
},
{
id: "76706",
Expand Down Expand Up @@ -492,7 +502,9 @@ export const dummyRepositories: Repository[] = [
{ display: "climate-model", id: "climate-model" },
{ display: "climate-solutions", id: "climate-solutions" },
{ display: "drawdown", id: "drawdown" }
]
],
monthly_downloads: 0,
created_at: ""
},
{
id: "64175",
Expand Down Expand Up @@ -604,7 +616,9 @@ export const dummyRepositories: Repository[] = [
{ display: "national-hydrography-dataset", id: "national-hydrography-dataset" },
{ display: "national-water-center", id: "national-water-center" },
{ display: "noaa", id: "noaa" }
]
],
monthly_downloads: 0,
created_at: ""
},
{
id: "64195",
Expand Down Expand Up @@ -706,7 +720,9 @@ export const dummyRepositories: Repository[] = [
{ display: "openscience", id: "openscience" },
{ display: "pangeo", id: "pangeo" },
{ display: "remote-sensing", id: "remote-sensing" }
]
],
monthly_downloads: 0,
created_at: ""
},
{
id: "25757",
Expand Down Expand Up @@ -748,7 +764,9 @@ export const dummyRepositories: Repository[] = [
url: "https://github.com/openclimatefix/metnet/issues/1"
}
],
tags: [{ display: "pytorch", id: "pytorch" }]
tags: [{ display: "pytorch", id: "pytorch" }],
monthly_downloads: 0,
created_at: ""
},
{
id: "64168",
Expand Down Expand Up @@ -803,6 +821,8 @@ export const dummyRepositories: Repository[] = [
tags: [
{ display: "manuscript", id: "manuscript" },
{ display: "python", id: "python" }
]
],
monthly_downloads: 0,
created_at: ""
}
];
4 changes: 2 additions & 2 deletions styles/globals.scss
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
.active-pill {
@apply border-primary font-semibold text-primary;

>span {
> span {
@apply text-primary;
}
}
Expand All @@ -34,4 +34,4 @@
@media (min-width: 1024px) {
max-width: 28rem;
}
}
}
Loading
Loading