feat: add urls to project modals, update filters in URL structure, hide isHidden=true categories

This commit is contained in:
MTG2000
2022-11-02 10:53:18 +02:00
parent cfb54120c2
commit b248bc1c89
10 changed files with 1078 additions and 306 deletions

1245
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -59,6 +59,7 @@
"lodash.debounce": "^4.0.8",
"lodash.throttle": "^4.1.1",
"marked": "^4.0.14",
"next": "^13.0.1",
"nexus": "^1.3.0",
"node-sass": "^7.0.1",
"nostr-tools": "^0.23.4",
@@ -89,6 +90,7 @@
"react-toastify": "^9.0.8",
"react-tooltip": "^4.2.21",
"react-topbar-progress-indicator": "^4.1.1",
"react-url-modal": "^0.4.3",
"remirror": "^1.0.77",
"serverless-http": "^3.0.1",
"stream": "npm:stream-browserify",

View File

@@ -10,7 +10,10 @@ import ProtectedRoute from "./Components/ProtectedRoute/ProtectedRoute";
import { Helmet } from "react-helmet";
import { NavbarLayout } from "./utils/routing/layouts";
import { Loadable, PAGES_ROUTES } from "./utils/routing";
import { URLModal } from "react-url-modal";
import ProjectDetailsCard from 'src/features/Projects/pages/ProjectPage/ProjectDetailsCard/ProjectDetailsCard';
import Modal from "./Components/Modals/Modal/Modal";
import ReactModal from "react-modal";
// Pages
// const FeedPage = Loadable(React.lazy(() => import( /* webpackChunkName: "feed_page" */ "./features/Posts/pages/FeedPage/FeedPage")))
@@ -33,6 +36,27 @@ import { Loadable, PAGES_ROUTES } from "./utils/routing";
const ExplorePage = Loadable(React.lazy(() => import( /* webpackChunkName: "explore_page" */ "src/features/Projects/pages/ExplorePage/ExplorePage")))
const ModalWrapper = ({ children, onClose, visible }: any) => {
return <ReactModal
isOpen={visible}
onRequestClose={onClose}
overlayClassName='fixed w-full inset-0 overflow-x-hidden z-[2020] no-scrollbar'
className=' '
closeTimeoutMS={1000}
contentElement={(_props, children) => <div {..._props} className={`
${_props.className}
w-screen min-h-screen relative flex flex-col justify-center items-center inset-0
`}>
<div
onClick={onClose}
className={`absolute w-full h-full top-0 left-0 bg-gray-300 bg-opacity-50`}
></div>
{children}
</div>}
>
{children}
</ReactModal>
}
function App() {
@@ -89,6 +113,13 @@ function App() {
/>
</Helmet>
<URLModal
adapter={null}
Wrapper={ModalWrapper}
modals={{
projectDetails: ProjectDetailsCard,
}}
/>
<Suspense fallback={<LoadingPage />}>
<Routes>
{/* <Route path={PAGES_ROUTES.blog.writeStory} element={<ProtectedRoute><CreatePostPage initType="story" /></ProtectedRoute>} /> */}

View File

@@ -1,5 +1,5 @@
query AllCategories($filter: JSON) {
categoryList(_filter: $filter) {
categoryList(isHidden: false, _filter: $filter) {
projectsCount
id
name

View File

@@ -42,22 +42,26 @@ export default function Header(props: Props) {
absolute top-24 left-24 md:top-1/2 md:left-40 md:-translate-y-1/2
rounded-full text-center flex justify-center items-center">
<FiArrowLeft className=' inline-block text-body2 lg:text-body1' /></Link> */}
<h1
className='text-primary-500 text-h1 font-medium'
>{title}</h1>
{subtitle &&
<p className="text-gray-600 font-medium text-body1">{subtitle}</p>
}
{onSearchPage && <div className=" ">
<p className="text-gray-500 font-medium text-body4 mb-24 text-center">filtered by</p>
<div className="flex gap-8 flex-wrap">
{filters?.yearFounded && <Badge size='sm'>📆 Founded in <span className='font-bold text-gray-700'>{filters.yearFounded}</span> <button onClick={() => removeFilter("yearFounded")} className='ml-4 text-gray-600 hover:scale-125'><MdClose /></button> </Badge>}
{filters?.projectStatus && <Badge size='sm'>🌱 Status: <span className='font-bold text-gray-700'>{filters?.projectStatus}</span> <button onClick={() => removeFilter("projectStatus")} className='ml-4 text-gray-600 hover:scale-125'><MdClose /></button> </Badge>}
{filters?.projectLicense && <Badge size='sm'>💻 License: <span className='font-bold text-gray-700'>{filters.projectLicense}</span> <button onClick={() => removeFilter("projectLicense")} className='ml-4 text-gray-600 hover:scale-125'><MdClose /></button> </Badge>}
{filters?.categories && filters.categories.length > 0 && <Badge size='sm'>Category: <span className='font-bold text-gray-700'>{filters.categories[0].label}</span> <button onClick={() => removeFilter("categories")} className='ml-4 text-gray-600 hover:scale-125'><MdClose /></button> </Badge>}
{filters?.tags && filters.tags.length > 0 && <Badge size='sm'>Tags: <span className='font-bold text-gray-700'>{filters.tags.map(t => t.label).join(', ')}</span> <button onClick={() => removeFilter("tags")} className='ml-4 text-gray-600 hover:scale-125'><MdClose /></button> </Badge>}
<div className="content-container">
<div className="flex flex-col justify-center items-center gap-8">
<h1
className='text-primary-500 text-h1 font-medium'
>{title}</h1>
{subtitle &&
<p className="text-gray-600 font-medium text-body1">{subtitle}</p>
}
{!filtersEmpty && <div className=" ">
<p className="text-gray-500 font-medium text-body4 mb-8 mt-8 text-center">filtered by</p>
<div className="flex gap-8 flex-wrap">
{filters?.yearFounded && <Badge size='sm'>📆 Founded in <span className='font-bold text-gray-700'>{filters.yearFounded}</span> <button onClick={() => removeFilter("yearFounded")} className='ml-4 text-gray-600 hover:scale-125'><MdClose /></button> </Badge>}
{filters?.projectStatus && <Badge size='sm'>🌱 Status: <span className='font-bold text-gray-700'>{filters?.projectStatus}</span> <button onClick={() => removeFilter("projectStatus")} className='ml-4 text-gray-600 hover:scale-125'><MdClose /></button> </Badge>}
{filters?.projectLicense && <Badge size='sm'>💻 License: <span className='font-bold text-gray-700'>{filters.projectLicense}</span> <button onClick={() => removeFilter("projectLicense")} className='ml-4 text-gray-600 hover:scale-125'><MdClose /></button> </Badge>}
{filters?.categories && filters.categories.length > 0 && <Badge size='sm'>Category: <span className='font-bold text-gray-700'>{filters.categories[0].label}</span> <button onClick={() => removeFilter("categories")} className='ml-4 text-gray-600 hover:scale-125'><MdClose /></button> </Badge>}
{filters?.tags && filters.tags.length > 0 && <Badge size='sm'>Tags: <span className='font-bold text-gray-700'>{filters.tags.map(t => t.label).join(', ')}</span> <button onClick={() => removeFilter("tags")} className='ml-4 text-gray-600 hover:scale-125'><MdClose /></button> </Badge>}
</div>
</div>}
</div>
</div>}
</div>
</div>
)
}

View File

@@ -1,7 +1,8 @@
import { openModal } from "react-url-modal";
import ProjectCardMini from "src/features/Projects/Components/ProjectCardMini/ProjectCardMini";
import ProjectCardMiniSkeleton from 'src/features/Projects/Components/ProjectCardMini/ProjectCardMini.Skeleton';
import { openModal } from 'src/redux/features/modals.slice';
// import { openModal } from 'src/redux/features/modals.slice';
import { useAppDispatch } from 'src/utils/hooks';
import { ProjectCard } from 'src/utils/interfaces';
@@ -16,13 +17,19 @@ export default function ProjectsGrid({ isLoading, isLoadingMore, projects }: Pro
const dispatch = useAppDispatch();
const handleClick = (projectId: string) => {
dispatch(openModal({
Modal: "ProjectDetailsCard",
isPageModal: true,
props: {
// dispatch(openModal({
// Modal: "ProjectDetailsCard",
// isPageModal: true,
// props: {
// projectId
// }
// }))
openModal({
name: "projectDetails",
params: {
projectId
}
}))
})
}
return (

View File

@@ -31,6 +31,18 @@ export function removeEmptyFitlers(filters: Partial<ProjectsFilters>): Partial<P
return res;
}
const extractNonFiltersParams = (params?: Record<string, any> & Partial<ProjectsFilters>) => {
const filtersKeys: (keyof ProjectsFilters)[] = ['categories', 'projectLicense', 'tags', 'projectStatus', 'yearFounded'];
if (!params) return {};
let res: Record<string, any> = {};
for (const [key, value] of Object.entries(params)) {
if (filtersKeys.includes(key as any)) continue;
res[key] = value;
}
console.log(res);
return res;
}
export const useUpdateUrlWithFilters = (state?: Partial<ProjectsFilters> | null) => {
const location = useLocation()
@@ -38,14 +50,21 @@ export const useUpdateUrlWithFilters = (state?: Partial<ProjectsFilters> | null)
useEffect(() => {
const allParams = qs.parse(window.location.search.slice(1))
console.log(allParams);
const nonFiltersParams = extractNonFiltersParams(allParams);
const filtersParams = removeEmptyFitlers({ ...state } ?? {});
const queryString = qs.stringify(
removeEmptyFitlers(state ?? {}),
{ ...filtersParams, ...nonFiltersParams },
{ skipNulls: true }
)
navigate(`${location.pathname}?${queryString}`, { replace: true });
navigate(`${window.location.pathname}?${queryString}`, { replace: true });
}, [location.pathname, location.search, navigate, state]);
}, [navigate, state]);
}

View File

@@ -2,7 +2,7 @@ import { useEffect, useState } from 'react'
import { MdLocalFireDepartment } from 'react-icons/md';
import { ModalCard } from 'src/Components/Modals/ModalsContainer/ModalsContainer';
import { useAppDispatch, useAppSelector, useMediaQuery } from 'src/utils/hooks';
import { openModal, scheduleModal } from 'src/redux/features/modals.slice';
import { Direction, openModal, scheduleModal } from 'src/redux/features/modals.slice';
import { setProject } from 'src/redux/features/project.slice';
import Button from 'src/Components/Button/Button';
import ProjectCardSkeleton from './ProjectDetailsCard.Skeleton'
@@ -24,10 +24,13 @@ import { CgGitFork } from 'react-icons/cg';
interface Props extends ModalCard {
projectId: string;
params: {
projectId: string;
}
}
export default function ProjectDetailsCard({ direction, projectId, ...props }: Props) {
export default function ProjectDetailsCard({ params: { projectId }, ...props }: Props) {
const dispatch = useAppDispatch();
const [screenshotsOpen, setScreenshotsOpen] = useState(-1);
@@ -64,7 +67,7 @@ export default function ProjectDetailsCard({ direction, projectId, ...props }: P
if (error)
return <div
className={`modal-card max-w-[768px] ${props.isPageModal && !isMdScreen && 'rounded-0 w-full min-h-screen'}`}
className={`modal-card max-w-[768px] ${!isMdScreen && 'rounded-0 w-full min-h-screen'}`}
>
<div className="p-64">
<ErrorMessage type='fetching' message='Something Wrong happened while fetching project details, please try refreshing the page' />
@@ -72,7 +75,7 @@ export default function ProjectDetailsCard({ direction, projectId, ...props }: P
</div>
if (loading)
return <ProjectCardSkeleton onClose={closeModal} direction={direction} isPageModal={props.isPageModal} />;
return <ProjectCardSkeleton onClose={closeModal} isPageModal={true} />;
const project = data?.getProject?.[0];
@@ -113,7 +116,7 @@ export default function ProjectDetailsCard({ direction, projectId, ...props }: P
return (
<div
className={`modal-card max-w-[676px] ${(props.isPageModal && !isMdScreen) && '!rounded-0 w-full min-h-screen'}`}
className={`modal-card max-w-[676px] ${(!isMdScreen) && '!rounded-0 w-full min-h-screen'}`}
>
{/* Cover Image */}
<div className="relative h-[120px] lg:h-[80px] bg-gray-400">
@@ -132,7 +135,7 @@ export default function ProjectDetailsCard({ direction, projectId, ...props }: P
{/* Title & Basic Info */}
<div className="flex flex-col mt-[-80px] md:flex-row md:mt-0 gap-24 md:items-center relative">
<div className="flex-shrink-0 w-[108px] h-[108px]">
<img className="w-full h-full object-cover border-2 border-gray-200 rounded-24" src={logo} alt="" />
<img className="w-full h-full object-cover border-2 bg-white border-gray-200 rounded-24" src={logo} alt="" />
</div>
<div className='flex flex-col gap-8 items-start justify-between'>
<a href={project?.website!} target='_blank' rel="noreferrer"><h3 className="text-body1 font-bold">{project?.title}</h3></a>

View File

@@ -133,6 +133,7 @@ export type QueryCategoryListArgs = {
description: InputMaybe<Scalars['String']>;
icon: InputMaybe<Scalars['String']>;
id: InputMaybe<Scalars['String']>;
isHidden: InputMaybe<Scalars['Boolean']>;
name: InputMaybe<Scalars['String']>;
projectFromData: InputMaybe<Array<InputMaybe<Scalars['String']>>>;
projectsCount: InputMaybe<Scalars['String']>;
@@ -318,6 +319,7 @@ export type CategoryList = {
description: Maybe<Scalars['String']>;
icon: Maybe<Scalars['String']>;
id: Maybe<Scalars['String']>;
isHidden: Maybe<Scalars['Boolean']>;
name: Maybe<Scalars['String']>;
projectFromData: Maybe<Array<Maybe<Scalars['String']>>>;
projectsCount: Maybe<Scalars['String']>;
@@ -430,7 +432,7 @@ export type ProjectDetailsQuery = { __typename?: 'Query', getProject: Array<{ __
export const AllCategoriesDocument = gql`
query AllCategories($filter: JSON) {
categoryList(_filter: $filter) {
categoryList(isHidden: false, _filter: $filter) {
projectsCount
id
name

View File

@@ -9,13 +9,13 @@ import { setIsMobileScreen } from 'src/redux/features/ui.slice';
import { isMobileScreen } from './helperFunctions';
import ReactTooltip from 'react-tooltip';
import { ToastContainer } from 'react-toastify';
import 'react-toastify/dist/ReactToastify.css';
import 'react-loading-skeleton/dist/skeleton.css'
import THEME from './theme';
import { NotificationsService } from 'src/services';
import ErrorPage from 'src/Components/Errors/ErrorPage/ErrorPage';
import { ErrorBoundary } from 'react-error-boundary';
THEME.injectStyles();
let basename = '/';
@@ -41,7 +41,6 @@ export const useWrapperSetup = () => {
useResizeListener(resizeListener)
}
export default function Wrapper(props: any) {
return (