From fc1a84f3bbfe6e58f7b3e3f2aa8bd7a70fd8b5c5 Mon Sep 17 00:00:00 2001 From: MTG2000 Date: Thu, 20 Oct 2022 17:31:30 +0300 Subject: [PATCH] feat: add more filters, refactor filters state logic --- .../ProjectCardMini/ProjectCardMini.tsx | 4 +- .../pages/ExplorePage/ExplorePage.tsx | 64 ++++++--- .../ExplorePage/Filters/FiltersModal.tsx | 135 ++++++++++++++---- .../ProjectDetailsCard/ProjectDetails.graphql | 2 +- .../ProjectDetailsCard/ProjectDetailsCard.tsx | 47 +++--- src/graphql/index.tsx | 4 +- 6 files changed, 177 insertions(+), 79 deletions(-) diff --git a/src/features/Projects/Components/ProjectCardMini/ProjectCardMini.tsx b/src/features/Projects/Components/ProjectCardMini/ProjectCardMini.tsx index b4044db..cd6e200 100644 --- a/src/features/Projects/Components/ProjectCardMini/ProjectCardMini.tsx +++ b/src/features/Projects/Components/ProjectCardMini/ProjectCardMini.tsx @@ -12,7 +12,7 @@ export default function ProjectCardMini({ project, onClick }: Props) { return (
{ e.key !== 'Enter' || onClick(project?.id!) }} @@ -20,7 +20,7 @@ export default function ProjectCardMini({ project, onClick }: Props) { tabIndex={0} role='button' > - {project?.title + {project?.title

{project?.title}

diff --git a/src/features/Projects/pages/ExplorePage/ExplorePage.tsx b/src/features/Projects/pages/ExplorePage/ExplorePage.tsx index a3bfad3..9a9c1fe 100644 --- a/src/features/Projects/pages/ExplorePage/ExplorePage.tsx +++ b/src/features/Projects/pages/ExplorePage/ExplorePage.tsx @@ -1,7 +1,6 @@ -import { useParams, Navigate } from 'react-router-dom' + import ErrorMessage from 'src/Components/Errors/ErrorMessage/ErrorMessage'; import { useExplorePageQuery } from 'src/graphql'; -import HeaderImage from './Header/Header'; import ProjectsGrid from './ProjectsGrid/ProjectsGrid'; import { Helmet } from "react-helmet"; import Categories, { Category } from '../../Components/Categories/Categories'; @@ -13,36 +12,53 @@ import { openModal } from 'src/redux/features/modals.slice'; import { createAction } from '@reduxjs/toolkit'; import { useReduxEffect } from 'src/utils/hooks/useReduxEffect'; import { NetworkStatus } from '@apollo/client'; -import { GoSettings } from 'react-icons/go' import { FiSliders } from 'react-icons/fi'; import { ProjectsFilters } from './Filters/FiltersModal'; -const UPDATE_FILTERS_ACTION = createAction<{ categoriesIds?: string[], tagsIds?: string[], yearFounded?: string }>('PROJECTS_FILTERS_UPDATED')({}) +const UPDATE_FILTERS_ACTION = createAction>('PROJECTS_FILTERS_UPDATED')({}) + +type QueryFilter = Partial<{ + categoryId: string[] | null + tags: string[] | null + yearFounded: number | null + dead: boolean | null + license: string | null +}> export default function ExplorePage() { const dispatch = useAppDispatch(); - const [filters, setFilters] = useState>() + const [filters, setFilters] = useState | null>(null) const [selectedCategory, setSelectedCategory] = useState(null) const queryFilters = useMemo(() => { - let filter: any = {} + let filter: QueryFilter = {} if (!filters) return null; if (filters.categoriesIds && filters.categoriesIds?.length > 0) - filter['categoryId'] = filters.categoriesIds + filter.categoryId = filters.categoriesIds; + + if (selectedCategory?.id) filter.categoryId = [selectedCategory?.id] if (filters.tagsIds && filters.tagsIds?.length > 0) - filter['tags'] = filters.tagsIds + filter.tags = filters.tagsIds - if (filters.yearFounded && filters.yearFounded !== "Any") - filter['yearFounded'] = Number(filters.yearFounded) + if (filters.yearFounded && filters.yearFounded !== 'any') + filter.yearFounded = Number(filters.yearFounded) - if (Object.keys(filter).length === 0) return null + if (filters.projectStatus && filters.projectStatus !== 'any') + filter.dead = filters.projectStatus === 'alive' ? false : true; + + + if (filters.projectLicense && filters.projectLicense !== 'any') + filter.license = filters.projectLicense + + if (Object.keys(filter).length === 0) + return null return filter; - }, [filters]) + }, [filters, selectedCategory?.id]) const { data, networkStatus, error } = useExplorePageQuery({ variables: { @@ -55,11 +71,12 @@ export default function ExplorePage() { - - const onFiltersUpdated = useCallback(({ payload }: typeof UPDATE_FILTERS_ACTION) => { setSelectedCategory(null) - setFilters(payload); + if (Object.keys(payload).length === 0) + setFilters(null); + else + setFilters(payload); }, []) useReduxEffect(onFiltersUpdated, UPDATE_FILTERS_ACTION.type) @@ -83,13 +100,8 @@ export default function ExplorePage() { })) } - const selectCategoryTab = (category?: Category | null) => { - if (!category?.id) - return; + const selectCategoryTab = (category: Category | null) => { setSelectedCategory(category); - setFilters({ - categoriesIds: [category.id] - }) } if (error) { @@ -98,7 +110,6 @@ export default function ExplorePage() {
} - console.log(networkStatus, NetworkStatus.loading, NetworkStatus.refetch, NetworkStatus.setVariables); const isLoading = networkStatus === NetworkStatus.loading || networkStatus === NetworkStatus.refetch || networkStatus === NetworkStatus.setVariables; @@ -115,7 +126,14 @@ export default function ExplorePage() { />
selectCategoryTab(v)} />
- +
(initFilters?.categoriesIds ?? []); const [tagsFilter, setTagsFilter] = useState(initFilters?.tagsIds ?? []); - const [yearFoundedFilter, setYearFoundedFilter] = useState(initFilters?.yearFounded ?? yearsFounded[0]); + const [yearFoundedFilter, setYearFoundedFilter] = useState(initFilters?.yearFounded ?? "any"); + const [projectStatusFilter, setProjectStatusFilter] = useState(initFilters?.projectStatus ?? "any"); + const [projectLicenseFilter, setProjectLicenseFilter] = useState(initFilters?.projectLicense ?? "any"); const clickCategory = (id: string) => { if (categoriesFilter.includes(id)) - setCategoriesFilter(categoriesFilter.filter(v => v !== id)); + setCategoriesFilter([]); else - setCategoriesFilter([...categoriesFilter, id]); + setCategoriesFilter([id]); } @@ -58,16 +57,30 @@ export default function FiltersModal({ onClose, direction, initFilters, callback setTagsFilter([...tagsFilter, id]); } - const clearFilters = () => { - setCategoriesFilter([]); - setTagsFilter([]); - setYearFoundedFilter(yearsFounded[0]); + const createActionPayload = (filters: Partial) => { + const action = Object.assign({}, callbackAction); + let payload: any = {}; + for (const [key, value] of Object.entries(filters)) { + if (filters[(key as keyof typeof filters)] != null) payload[key] = value; + } + action.payload = payload; + return action } const applyFilters = () => { - const action = Object.assign({}, callbackAction); - action.payload = { categoriesIds: categoriesFilter, tagsIds: tagsFilter, yearFounded: yearFoundedFilter } - dispatch(action) + dispatch(createActionPayload({ + categoriesIds: categoriesFilter, + tagsIds: tagsFilter, + yearFounded: yearFoundedFilter, + projectStatus: projectStatusFilter, + projectLicense: projectLicenseFilter + })) + onClose?.(); + } + + + const clearFilters = () => { + dispatch(dispatch(createActionPayload({ categoriesIds: [], tagsIds: [], yearFounded: 'any', projectStatus: 'any', projectLicense: "any" }))) onClose?.(); } @@ -155,20 +168,57 @@ export default function FiltersModal({ onClose, direction, initFilters, callback

📆 Founded

Select the year you wish to see companies founded in.

-
- {yearsFounded.map(year => -
+
+ {yearsFoundedOptions.map(year => +
)} + {year.text} + )} +
+
+ +
+
+

💙 Project status

+

Select an option from below.

+
+ {projectStatusOptions.map(status => + )} +
+
+ + +
+
+

💻 License type

+

What type of license does this open source project have?

+
+ {licensesOptions.map(license => + )}
@@ -184,3 +234,34 @@ export default function FiltersModal({ onClose, direction, initFilters, callback ) } + + +const yearsFoundedOptions = [ + { value: "any", text: "Any" }, + { value: "2016", text: "2016" }, + { value: "2017", text: "2017" }, + { value: "2018", text: "2018" }, + { value: "2019", text: "2019" }, + { value: "2020", text: "2020" }, + { value: "2021", text: "2021" }, + { value: "2022", text: "2022" }, +] as const + +const projectStatusOptions = [ + { value: "any", text: "Any" }, + { value: 'alive', text: "Alive 🌱" }, + { value: 'dead', text: "RIP 💀" }, +] as const + +const licensesOptions = [ + { value: "any", text: "Any" }, + { value: 'MIT License', text: "MIT License" }, + { value: 'ISC License', text: "ISC License" }, + { value: 'Public domain', text: "Public domain" }, + { value: 'Apache License 2.0', text: "Apache License 2.0" }, + { value: 'GNU General Public License v2.0', text: "GNU General Public License v2.0" }, + { value: 'GNU General Public License v3.0', text: "GNU General Public License v3.0" }, + { value: 'Creative Commons Zero v1.0 Universal', text: "Creative Commons Zero v1.0 Universal" }, + { value: 'GNU Affero General Public License v3.0', text: "GNU Affero General Public License v3.0" }, + { value: 'Other', text: "Other" }, +] as const \ No newline at end of file diff --git a/src/features/Projects/pages/ProjectPage/ProjectDetailsCard/ProjectDetails.graphql b/src/features/Projects/pages/ProjectPage/ProjectDetailsCard/ProjectDetails.graphql index 1da9b45..f24f1e8 100644 --- a/src/features/Projects/pages/ProjectPage/ProjectDetailsCard/ProjectDetails.graphql +++ b/src/features/Projects/pages/ProjectPage/ProjectDetailsCard/ProjectDetails.graphql @@ -1,5 +1,5 @@ query ProjectDetails($projectsId: String) { - projects(id: $projectsId) { + getProject: projects(id: $projectsId) { id title dead diff --git a/src/features/Projects/pages/ProjectPage/ProjectDetailsCard/ProjectDetailsCard.tsx b/src/features/Projects/pages/ProjectPage/ProjectDetailsCard/ProjectDetailsCard.tsx index 899d3ec..6fbc327 100644 --- a/src/features/Projects/pages/ProjectPage/ProjectDetailsCard/ProjectDetailsCard.tsx +++ b/src/features/Projects/pages/ProjectPage/ProjectDetailsCard/ProjectDetailsCard.tsx @@ -42,12 +42,14 @@ export default function ProjectDetailsCard({ direction, projectId, ...props }: P projectsId: projectId!, }, onCompleted: data => { - dispatch(setProject((data.projects?.[0] as any) ?? null)) + dispatch(setProject((data.getProject?.[0] as any) ?? null)) }, onError: () => { dispatch(setProject(null)); }, - skip: !Boolean(projectId) + skip: !Boolean(projectId), + fetchPolicy: "no-cache" + }); @@ -72,7 +74,7 @@ export default function ProjectDetailsCard({ direction, projectId, ...props }: P return ; - const project = data?.projects?.[0]; + const project = data?.getProject?.[0]; if (!project) return

404

@@ -126,8 +128,8 @@ export default function ProjectDetailsCard({ direction, projectId, ...props }: P {/* Title & Basic Info */}
-
- +
+

{project?.title}

@@ -173,26 +175,23 @@ export default function ProjectDetailsCard({ direction, projectId, ...props }: P
-
-

DATA

-
- {project?.dead && {project.dead}} - {project?.createdAt && {project.createdAt}} - {project?.companyName && {project.companyName}} - {project?.endDate && {project.endDate}} - {project?.updatedAt && {project.updatedAt}} - {project?.watchers && {project.watchers}} - {project?.yearFounded && {project.yearFounded}} - {project?.subcategory && {project.subcategory}} - {project?.stars && {project.stars}} - {project?.repository && {project.repository}} - {project?.openSource && {project.openSource}} - {project?.linkedIn && {project.linkedIn}} - {project?.license && {project.license}} - {project?.language && {project.language}} - {project?.forks && {project.forks}} -
+
+

DATA

+
+ {project?.dead !== null && Dead} + {project?.createdAt !== null && Created at: {new Date(project.createdAt).toLocaleDateString()}} + {project?.companyName !== null && Company Name: {project.companyName}} + {project?.endDate !== null && End date: {new Date(project.endDate).toLocaleDateString()}} + {project?.repository !== null && Repository } + {project?.stars !== null && Stars: {project.stars}} + {project?.openSource !== null && Open source: {project.openSource}} + {project?.watchers !== null && Watchers: {project.watchers}} + {project?.forks !== null && Number of forks: {project.forks}} + {project?.license !== null && License: {project.license}} + {project?.language !== null && Language: {project.language}} + {project?.updatedAt !== null && Last updated at:{new Date(project.updatedAt).toLocaleDateString()}}
+

Want to suggest any changes to this project?

diff --git a/src/graphql/index.tsx b/src/graphql/index.tsx index ce44df6..7d014c7 100644 --- a/src/graphql/index.tsx +++ b/src/graphql/index.tsx @@ -425,7 +425,7 @@ export type ProjectDetailsQueryVariables = Exact<{ }>; -export type ProjectDetailsQuery = { __typename?: 'Query', projects: Array<{ __typename?: 'projects', id: string | null, title: string | null, dead: boolean | null, createdAt: string | null, companyName: string | null, category: string | null, description: string | null, discord: string | null, endDate: string | null, twitter: string | null, updatedAt: string | null, watchers: number | null, website: string | null, yearFounded: number | null, telegram: string | null, stars: number | null, repository: string | null, openSource: string | null, logo: Array | null, linkedIn: string | null, license: string | null, language: string | null, forks: number | null, categoryList: Array<{ __typename?: 'categoryList', name: string | null } | null> | null, tags: Array<{ __typename?: 'tags', id: string | null, name: string | null, icon: string | null } | null> | null } | null> | null }; +export type ProjectDetailsQuery = { __typename?: 'Query', getProject: Array<{ __typename?: 'projects', id: string | null, title: string | null, dead: boolean | null, createdAt: string | null, companyName: string | null, category: string | null, description: string | null, discord: string | null, endDate: string | null, twitter: string | null, updatedAt: string | null, watchers: number | null, website: string | null, yearFounded: number | null, telegram: string | null, stars: number | null, repository: string | null, openSource: string | null, logo: Array | null, linkedIn: string | null, license: string | null, language: string | null, forks: number | null, categoryList: Array<{ __typename?: 'categoryList', name: string | null } | null> | null, tags: Array<{ __typename?: 'tags', id: string | null, name: string | null, icon: string | null } | null> | null } | null> | null }; export const AllCategoriesDocument = gql` @@ -570,7 +570,7 @@ export type ExplorePageLazyQueryHookResult = ReturnType; export const ProjectDetailsDocument = gql` query ProjectDetails($projectsId: String) { - projects(id: $projectsId) { + getProject: projects(id: $projectsId) { id title dead