From 69e4e4eba324b1b1f7a50163b79dca41a11a7790 Mon Sep 17 00:00:00 2001 From: Abdullah Shahid <90593598+nxabdullah@users.noreply.github.com> Date: Sun, 10 Nov 2024 00:00:46 -0500 Subject: [PATCH 1/4] [Tech debt] Remove blog (#105) --- api/schema.ts | 10 -- components/Blogs/BlogHighlightSection.tsx | 105 ------------------ components/Blogs/BlogListSection.tsx | 74 ------------ components/Common/NavBar.tsx | 12 +- components/Events/EventHighlightSection.tsx | 2 - components/Events/EventListSection.tsx | 1 - components/Home/BlogsSection.tsx | 103 ----------------- components/Home/EventSection.tsx | 1 - .../Sponsors/SponsorHighlightSection.tsx | 1 - components/Sponsors/SponsorListSection.tsx | 3 +- hooks/useBlogs.ts | 7 -- pages/Blogs/[pid].tsx | 91 --------------- pages/Blogs/index.tsx | 80 ------------- pages/Sponsors/[pid].tsx | 3 +- pages/Sponsors/index.tsx | 2 +- pages/index.tsx | 3 - scss/components/_BlogHighlightSection.scss | 85 -------------- scss/components/_BlogListSection.scss | 25 ----- scss/components/_BlogsSection.scss | 26 ----- scss/index.scss | 3 - store/blogSlice.ts | 101 ----------------- store/store.ts | 2 - types/Blogs/index.ts | 25 ----- 23 files changed, 4 insertions(+), 761 deletions(-) delete mode 100644 components/Blogs/BlogHighlightSection.tsx delete mode 100644 components/Blogs/BlogListSection.tsx delete mode 100644 components/Home/BlogsSection.tsx delete mode 100644 hooks/useBlogs.ts delete mode 100644 pages/Blogs/[pid].tsx delete mode 100644 pages/Blogs/index.tsx delete mode 100644 scss/components/_BlogHighlightSection.scss delete mode 100644 scss/components/_BlogListSection.scss delete mode 100644 scss/components/_BlogsSection.scss delete mode 100644 store/blogSlice.ts delete mode 100644 types/Blogs/index.ts diff --git a/api/schema.ts b/api/schema.ts index 325c2db..75e64c9 100644 --- a/api/schema.ts +++ b/api/schema.ts @@ -1,19 +1,10 @@ import { CategoryResponse, DataAttributes } from '../types'; -import { APIResponseBlog } from '../types/Blogs'; import { APIResponseEvent } from '../types/Events'; import { MemberResponse } from '../types/Members'; import { APIResponseSponsor } from '../types/Sponsors'; import { CustomFetch } from './useFetch'; -const blogs = (customFetch: CustomFetch) => - ({ - blogsList: async () => { - const res = await customFetch('CMS', 'blogs?populate=*'); - return res.data as APIResponseBlog; - }, - } as const); - const events = (customFetch: CustomFetch) => ({ eventsList: async () => { @@ -39,7 +30,6 @@ const sponsors = (customFetch: CustomFetch) => const config = (customFetch: CustomFetch) => ({ - ...blogs(customFetch), ...events(customFetch), ...members(customFetch), ...sponsors(customFetch), diff --git a/components/Blogs/BlogHighlightSection.tsx b/components/Blogs/BlogHighlightSection.tsx deleted file mode 100644 index c0780da..0000000 --- a/components/Blogs/BlogHighlightSection.tsx +++ /dev/null @@ -1,105 +0,0 @@ -import { FC } from 'react'; - -import Button from '@mui/material/Button'; - -import MaterialCard from '@components/Common/MaterialCard'; -import MediaQueryContainer from '@components/Common/MediaQueryContainer'; -import Slider from '@components/Common/Slider'; -import Tag from '@components/Common/Tag'; -import { useAppSelector } from '@store/hooks'; -import { formatDate } from '@utils/helper'; -import Image from 'next/image'; -import { useRouter } from 'next/router'; - -const BlogHighlightSection: FC = () => { - const { blogs } = useAppSelector((state) => state.blogs); - const router = useRouter(); - - const blogCardInfos = Object.entries(blogs) - .filter(([, { featured }]) => featured) - .slice(0, 3) - .map(([id, { title, author, updatedDatetime, coverImageUrl, tags, description }]) => ({ - id, - title, - author, - updatedDatetime: formatDate(updatedDatetime, { - month: 'short', - day: 'numeric', - year: 'numeric', - hour: 'numeric', - minute: 'numeric', - }), - coverImageUrl, - tags: tags.map((t) => t.Tag), - description, - })); - - return ( -
- - - {blogCardInfos.map(({ id, coverImageUrl, author, title, description, tags }) => ( -
- router.push(`Blogs/${id}`)} - > - -
- -
-
-

{`By: ${author}`}

-

{title}

-

{description}

-
-
-
- ))} -
-
- -
- {blogCardInfos.map(({ id, title, updatedDatetime, coverImageUrl, tags, author }) => ( - router.push(`Blogs/${id}`)} - > - -
-
- -
-
-
-

Last Updated

-

{updatedDatetime}

- {author &&

Creator

} -

{author}

-
-
-
-

{title}

-
-
- -
-
-
-
-
- ))} -
-
-
- ); -}; - -export default BlogHighlightSection; diff --git a/components/Blogs/BlogListSection.tsx b/components/Blogs/BlogListSection.tsx deleted file mode 100644 index 372b151..0000000 --- a/components/Blogs/BlogListSection.tsx +++ /dev/null @@ -1,74 +0,0 @@ -import { FC } from 'react'; - -import MaterialCard from '@components/Common/MaterialCard'; -import Tag from '@components/Common/Tag'; -import { useAppSelector } from '@store/hooks'; -import { formatDate } from '@utils/helper'; -import classNames from 'classnames'; -import Image from 'next/image'; -import { useRouter } from 'next/router'; -import _ from 'underscore'; - -interface IProps { - selectedCategories: string[]; -} - -const BlogListSection: FC = ({ selectedCategories }) => { - const { blogs } = useAppSelector((state) => state.blogs); - const router = useRouter(); - const blogCardInfos = Object.entries(blogs) - .filter( - ([, { tags }]) => - selectedCategories.includes('All') || - !_.isEmpty(tags.filter((category) => selectedCategories.includes(category.Tag))) - ) - .map(([id, { title, author, updatedDatetime, coverImageUrl, tags, description }]) => ({ - id, - title, - author, - updatedDatetime: formatDate(updatedDatetime, { - month: 'short', - day: 'numeric', - year: 'numeric', - hour: 'numeric', - minute: 'numeric', - }), - coverImageUrl, - tags: tags.map((t) => t.Tag), - description, - })); - - return ( -
-
- {blogCardInfos.map(({ id, title, author, description, coverImageUrl, tags }) => ( -
selectedCategories.includes(category))), - })} - key={id} - > - router.push(`Blogs/${id}`)} - > - -
- -
-
- {author &&

{`By: ${author}`}

} -

{title}

-

{description}

-
-
-
- ))} -
-
- ); -}; - -export default BlogListSection; diff --git a/components/Common/NavBar.tsx b/components/Common/NavBar.tsx index bdd7153..af91db1 100644 --- a/components/Common/NavBar.tsx +++ b/components/Common/NavBar.tsx @@ -10,7 +10,6 @@ import Tabs from '@mui/material/Tabs'; import Typography from '@mui/material/Typography'; import Logo from '@public/MCSS.svg'; -import { getAllBlogs } from '@store/blogSlice'; import { getAllEvents } from '@store/eventSlice'; import { useAppDispatch, useAppSelector } from '@store/hooks'; import { useIsMobile } from '@utils/hooks'; @@ -40,18 +39,15 @@ const NavBar: FC = () => { const [showDrawer, setShowDrawer] = useState(false); const router = useRouter(); const { events } = useAppSelector((state) => state.events); - const { blogs } = useAppSelector((state) => state.blogs); const { data: sponsors } = useSponsors(); const links = [ { label: 'Events', href: '/Events' }, - { label: 'Blogs', href: '/Blogs' }, { label: 'Sponsors', href: '/Sponsors' }, ]; - const searchBarWhiteList = ['/Events', '/Blogs', '/Sponsors']; + const searchBarWhiteList = ['/Events', '/Sponsors']; const partialRouteMatch = searchBarWhiteList.some((route) => router.pathname.includes(route)); const options = [ ...Object.entries(events).map(([id, { title }]) => ({ label: `Event: ${title}`, value: id })), - ...Object.entries(blogs).map(([id, { title }]) => ({ label: `Blog: ${title}`, value: id })), ...(sponsors?.data ? Object.entries(sponsors.data).map(([, { id, attributes }]) => ({ label: `Sponsors: ${attributes.title}`, @@ -64,10 +60,6 @@ const NavBar: FC = () => { if (_.isEmpty(events)) { dispatch(getAllEvents()); } - - if (_.isEmpty(blogs)) { - dispatch(getAllBlogs()); - } // eslint-disable-next-line react-hooks/exhaustive-deps }, []); @@ -114,8 +106,6 @@ const NavBar: FC = () => { setValue(selectedOption); if (selectedOption?.label.includes('Event:')) { router.push(`/Events/${selectedOption.value}`); - } else if (selectedOption?.label.includes('Blog:')) { - router.push(`/Blogs/${selectedOption.value}`); } else if (selectedOption?.label.includes('Sponsors:')) { router.push(`/Sponsors/${selectedOption.value}`); } diff --git a/components/Events/EventHighlightSection.tsx b/components/Events/EventHighlightSection.tsx index 2b76e86..e1a68b8 100644 --- a/components/Events/EventHighlightSection.tsx +++ b/components/Events/EventHighlightSection.tsx @@ -1,8 +1,6 @@ import { FC } from 'react'; import EventOutlinedIcon from '@mui/icons-material/EventOutlined'; -import PersonOutlineOutlinedIcon from '@mui/icons-material/PersonOutlineOutlined'; -import Button from '@mui/material/Button'; import MaterialCard from '@components/Common/MaterialCard'; import MediaQueryContainer from '@components/Common/MediaQueryContainer'; diff --git a/components/Events/EventListSection.tsx b/components/Events/EventListSection.tsx index f13004a..b8b372b 100644 --- a/components/Events/EventListSection.tsx +++ b/components/Events/EventListSection.tsx @@ -1,7 +1,6 @@ import { FC } from 'react'; import EventOutlinedIcon from '@mui/icons-material/EventOutlined'; -import PersonOutlineOutlinedIcon from '@mui/icons-material/PersonOutlineOutlined'; import MaterialCard from '@components/Common/MaterialCard'; import Tag from '@components/Common/Tag'; diff --git a/components/Home/BlogsSection.tsx b/components/Home/BlogsSection.tsx deleted file mode 100644 index 7abefa7..0000000 --- a/components/Home/BlogsSection.tsx +++ /dev/null @@ -1,103 +0,0 @@ -import { FC } from 'react'; - -import ArrowForwardIcon from '@mui/icons-material/ArrowForward'; -import Button from '@mui/material/Button'; - -import HorizontalSkeletonLoader from '@components/Common/HorizontalSkeletonLoader'; -import MaterialCard from '@components/Common/MaterialCard'; -import MediaQueryContainer from '@components/Common/MediaQueryContainer'; -import SectionWrapper from '@components/Common/SectionWrapper'; -import Slider from '@components/Common/Slider'; -import Tag from '@components/Common/Tag'; -import { useAppSelector } from '@store/hooks'; -import Image from 'next/image'; -import { useRouter } from 'next/router'; -import _ from 'underscore'; - -const BlogsSection: FC = () => { - const { blogs } = useAppSelector((state) => state.blogs); - const router = useRouter(); - - const blogCardInfos = Object.entries(blogs) - .filter(([, { featured }]) => featured) - .slice(0, 3) - .map(([id, { title, author, coverImageUrl, tags, description }]) => ({ - id, - title, - author, - coverImageUrl, - tags: tags.map((t) => t.Tag), - description, - })); - - return ( - - - {_.isEmpty(blogCardInfos) ? ( - - ) : ( - - {blogCardInfos.map(({ id, coverImageUrl, author, title, description, tags }) => ( -
- router.push(`Blogs/${id}`)} - > - -
- -
-
-

{`By: ${author}`}

-

{title}

-

{description}

-
-
-
- ))} -
- )} -
- - {_.isEmpty(blogCardInfos) ? ( - - ) : ( -
- {blogCardInfos.map(({ id, coverImageUrl, author, title, description, tags }) => ( - router.push(`Blogs/${id}`)} - > - -
- -
-
-

{`By: ${author}`}

-

{title}

-

{description}

-
-
- ))} -
- )} -
-
- -
-
- ); -}; - -export default BlogsSection; diff --git a/components/Home/EventSection.tsx b/components/Home/EventSection.tsx index ffde4f4..8db77c5 100644 --- a/components/Home/EventSection.tsx +++ b/components/Home/EventSection.tsx @@ -2,7 +2,6 @@ import { FC } from 'react'; import ArrowForwardIcon from '@mui/icons-material/ArrowForward'; import EventOutlinedIcon from '@mui/icons-material/EventOutlined'; -import PersonOutlineOutlinedIcon from '@mui/icons-material/PersonOutlineOutlined'; import Button from '@mui/material/Button'; import HorizontalSkeletonLoader from '@components/Common/HorizontalSkeletonLoader'; diff --git a/components/Sponsors/SponsorHighlightSection.tsx b/components/Sponsors/SponsorHighlightSection.tsx index bddb023..1e5c536 100644 --- a/components/Sponsors/SponsorHighlightSection.tsx +++ b/components/Sponsors/SponsorHighlightSection.tsx @@ -5,7 +5,6 @@ import Button from '@mui/material/Button'; import MaterialCard from '@components/Common/MaterialCard'; import MediaQueryContainer from '@components/Common/MediaQueryContainer'; import Slider from '@components/Common/Slider'; -import { formatDate } from '@utils/helper'; import useSponsors from 'hooks/useSponsors'; import Image from 'next/image'; import { useRouter } from 'next/router'; diff --git a/components/Sponsors/SponsorListSection.tsx b/components/Sponsors/SponsorListSection.tsx index c0167c3..4582363 100644 --- a/components/Sponsors/SponsorListSection.tsx +++ b/components/Sponsors/SponsorListSection.tsx @@ -1,7 +1,6 @@ -import { FC, useEffect, useState } from 'react'; +import { FC } from 'react'; import MaterialCard from '@components/Common/MaterialCard'; -import { formatDate } from '@utils/helper'; import classNames from 'classnames'; import useSponsors from 'hooks/useSponsors'; import Image from 'next/image'; diff --git a/hooks/useBlogs.ts b/hooks/useBlogs.ts deleted file mode 100644 index a36f855..0000000 --- a/hooks/useBlogs.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { useAPI } from '../contexts/useAPI'; - -export const useBlogs = () => { - return useAPI().useQuery(['blogsList', null]); -}; - -export default useBlogs; diff --git a/pages/Blogs/[pid].tsx b/pages/Blogs/[pid].tsx deleted file mode 100644 index 135f06c..0000000 --- a/pages/Blogs/[pid].tsx +++ /dev/null @@ -1,91 +0,0 @@ -import { FC, useEffect, useState } from 'react'; -import { HashLoader } from 'react-spinners'; - -import DetailPageContainer from '@components/Common/DetailPageContainer'; -import HeadingCard from '@components/Common/HeadingCard'; -import MarkdownDisplay from '@components/Common/MarkdownDisplay'; -import { getAllBlogs } from '@store/blogSlice'; -import { useAppDispatch, useAppSelector } from '@store/hooks'; -import { formatDate } from '@utils/helper'; -import Error from 'next/error'; -import { useRouter } from 'next/router'; -import _ from 'underscore'; - -const BlogDetail: FC = () => { - const router = useRouter(); - const dispatch = useAppDispatch(); - - const { blogs } = useAppSelector((state) => state.blogs); - const [loading, setLoading] = useState(_.isEmpty(blogs)); - const { pid } = router.query; - const currBlog = - _.isString(pid) && _.isNumber(parseInt(pid, 10)) ? blogs[parseInt(pid, 10)] : null; - - useEffect(() => { - (async () => { - if (_.isEmpty(blogs)) { - await dispatch(getAllBlogs()); - setLoading(false); - } - })(); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); - - if (loading) { - return ( -
- -
- ); - } - - if (_.isEmpty(blogs) || !currBlog) { - return ; - } - - const tagStrings = currBlog.tags.map((tagObject) => tagObject.Tag); - - const parsedCurrBlog = { - id: pid, - title: currBlog.title, - creator: currBlog.author, - lastUpdated: formatDate(currBlog.updatedDatetime, { - month: 'short', - day: 'numeric', - year: 'numeric', - hour: 'numeric', - minute: 'numeric', - }), - coverImageUrl: currBlog.coverImageUrl, - categories: tagStrings, - content: currBlog.content, - descr: currBlog.description, - }; - - return ( - - - {parsedCurrBlog.content && {parsedCurrBlog.content}} - - ); -}; - -export default BlogDetail; diff --git a/pages/Blogs/index.tsx b/pages/Blogs/index.tsx deleted file mode 100644 index e443568..0000000 --- a/pages/Blogs/index.tsx +++ /dev/null @@ -1,80 +0,0 @@ -import { FC, useEffect, useState } from 'react'; - -import BlogHighlightSection from '@components/Blogs/BlogHighlightSection'; -import BlogListSection from '@components/Blogs/BlogListSection'; -import Filter from '@components/Common/Filter'; -import { getAllBlogs } from '@store/blogSlice'; -import { useAppDispatch, useAppSelector } from '@store/hooks'; -import { removeElement } from '@utils/helper'; -import Head from 'next/head'; -import _ from 'underscore'; - -const Blogs: FC = () => { - const dispatch = useAppDispatch(); - const { tags, blogs } = useAppSelector((state) => state.blogs); - const optionNames = ['All', ...tags, 'Other']; - const [selectedCategories, setSelectedCategories] = useState(['All']); - - interface IOption { - name: string; - onClick: () => void; - } - - const options = optionNames.reduce( - (accOptions, currOptionName) => [ - ...accOptions, - { - name: currOptionName, - onClick: () => { - let newSelectedCategories = selectedCategories.includes(currOptionName) - ? removeElement(selectedCategories, currOptionName) - : [...selectedCategories, currOptionName]; - - /** - * Case 1: Nothing is selected, then we should select 'All' - * Case 2: Something other than 'All' is selected, then we should de-select 'All' - * Case 3: If 'All' is selected, then we should de-select everything other than 'All' - */ - if (_.isEmpty(newSelectedCategories)) { - newSelectedCategories = ['All']; - } else if ( - newSelectedCategories.length > 1 && - currOptionName !== 'All' && - newSelectedCategories.includes('All') - ) { - newSelectedCategories = removeElement(newSelectedCategories, 'All'); - } else if (currOptionName === 'All') { - newSelectedCategories = ['All']; - } - - setSelectedCategories(newSelectedCategories); - }, - }, - ], - [] - ); - - useEffect(() => { - if (_.isEmpty(blogs)) { - dispatch(getAllBlogs()); - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); - - return ( - <> - - UTM MCSS | Blogs - -
-

Featured

- -

Blogs

- - -
- - ); -}; - -export default Blogs; diff --git a/pages/Sponsors/[pid].tsx b/pages/Sponsors/[pid].tsx index 71dcdbd..ce45071 100644 --- a/pages/Sponsors/[pid].tsx +++ b/pages/Sponsors/[pid].tsx @@ -1,10 +1,9 @@ -import { FC, useEffect, useState } from 'react'; +import { FC } from 'react'; import { HashLoader } from 'react-spinners'; import DetailPageContainer from '@components/Common/DetailPageContainer'; import HeadingCard from '@components/Common/HeadingCard'; import MarkdownDisplay from '@components/Common/MarkdownDisplay'; -import { formatDate } from '@utils/helper'; import useSponsors from 'hooks/useSponsors'; import Error from 'next/error'; import { useRouter } from 'next/router'; diff --git a/pages/Sponsors/index.tsx b/pages/Sponsors/index.tsx index efc2095..835df17 100644 --- a/pages/Sponsors/index.tsx +++ b/pages/Sponsors/index.tsx @@ -1,4 +1,4 @@ -import { FC, useEffect, useState } from 'react'; +import { FC, useState } from 'react'; import Filter from '@components/Common/Filter'; import SponsorHighlightSection from '@components/Sponsors/SponsorHighlightSection'; diff --git a/pages/index.tsx b/pages/index.tsx index 2c206c1..b8d7b82 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -3,11 +3,9 @@ import { useEffect } from 'react'; import Container from '@mui/material/Container'; import AboutUsSection from '@components/Home/AboutUsSection'; -import BlogsSection from '@components/Home/BlogsSection'; import HomeIntroSection from '@components/Home/HomeIntroSection'; import TeamMemberSection from '@components/Home/TeamMemberSection'; import WhatWeDoSection from '@components/Home/WhatWeDoSection'; -import { getAllBlogs } from '@store/blogSlice'; import { getAllEvents } from '@store/eventSlice'; import { useAppDispatch } from '@store/hooks'; import { getAllMembers } from '@store/memberSlice'; @@ -18,7 +16,6 @@ const Home = () => { useEffect(() => { dispatch(getAllEvents()); - dispatch(getAllBlogs()); dispatch(getAllMembers()); // eslint-disable-next-line react-hooks/exhaustive-deps }, []); diff --git a/scss/components/_BlogHighlightSection.scss b/scss/components/_BlogHighlightSection.scss deleted file mode 100644 index 5979834..0000000 --- a/scss/components/_BlogHighlightSection.scss +++ /dev/null @@ -1,85 +0,0 @@ -.blog-highlight-section { - overflow-x: scroll; - overflow-y: hidden; - white-space: nowrap; - margin: 10px 50px; - - // custom scrollbar - &::-webkit-scrollbar { - height: 8px; - } - - &::-webkit-scrollbar-track { - background: none; /* color of the tracking area */ - } - - &::-webkit-scrollbar-thumb { - background-color: #c1c1c1; /* color of the scroll thumb */ - border-radius: 20px; /* roundness of the scroll thumb */ - &:hover { - background-color: #b1b1b1; - } - } - - .blog-card { - display: inline-block; - margin: 10px; - - .tag { - position: absolute; - padding: 10px 15px; - z-index: 2000; - top: 0px; - left: 0px; - right: 50%; - color: white; - @apply bg-purple-600; - background: rgba(124, 58, 237, 0.8); - border-top-left-radius: 0.5rem; - } - - .title { - display: -webkit-box; - -webkit-line-clamp: 3; - -webkit-box-orient: vertical; - overflow: hidden; - word-break: word; - white-space: normal; - } - - .image-container { - position: relative; - - img { - @apply rounded-l-lg; - } - } - } -} -.mobile-blog-card { - .image-container { - position: relative; - img { - @apply rounded-t-lg; - } - } - .tag { - position: absolute; - padding: 2px 15px; - z-index: 1000; - top: 177px; - right: 5px; - color: white; - @apply bg-purple-600; - @apply rounded-full; - } - - .title { - display: -webkit-box; - -webkit-line-clamp: 3; - -webkit-box-orient: vertical; - overflow: hidden; - word-break: word; - white-space: normal; - } -} diff --git a/scss/components/_BlogListSection.scss b/scss/components/_BlogListSection.scss deleted file mode 100644 index 9c1c36b..0000000 --- a/scss/components/_BlogListSection.scss +++ /dev/null @@ -1,25 +0,0 @@ -.blog-list-page { - .image-container { - position: relative; - img { - @apply rounded-t-lg; - } - } - .tag { - position: absolute; - padding: 2px 15px; - z-index: 1000; - top: 177px; - right: 5px; - color: white; - @apply bg-purple-600; - @apply rounded-full; - } - - .title { - display: -webkit-box; - -webkit-line-clamp: 3; - -webkit-box-orient: vertical; - overflow: hidden; - } -} diff --git a/scss/components/_BlogsSection.scss b/scss/components/_BlogsSection.scss deleted file mode 100644 index 0e18618..0000000 --- a/scss/components/_BlogsSection.scss +++ /dev/null @@ -1,26 +0,0 @@ -.blogs-section { - .image-container { - position: relative; - img { - @apply rounded-t-lg; - } - } - - .tag { - position: absolute; - padding: 2px 15px; - z-index: 1000; - top: 177px; - right: 5px; - color: white; - @apply bg-purple-600; - @apply rounded-full; - } - - .description { - display: -webkit-box; - -webkit-line-clamp: 3; - -webkit-box-orient: vertical; - overflow: hidden; - } -} diff --git a/scss/index.scss b/scss/index.scss index 787779d..8085bd6 100644 --- a/scss/index.scss +++ b/scss/index.scss @@ -8,13 +8,10 @@ @import './components/EventSections.scss'; @import './components/MaterialCard'; @import './components/WhatWeDo'; -@import './components/BlogsSection'; @import './components/AboutUsSection'; @import './components/NavMenu'; @import './components/EventListPage'; @import './components/EventHighlightSection'; -@import './components/BlogHighlightSection'; -@import './components/BlogListSection'; @import './components/Footer'; @import './components/SponsorListSection'; @import './components/SponsorHighlightSection'; diff --git a/store/blogSlice.ts b/store/blogSlice.ts deleted file mode 100644 index 806365d..0000000 --- a/store/blogSlice.ts +++ /dev/null @@ -1,101 +0,0 @@ -/* eslint-disable @typescript-eslint/indent */ -/* eslint-disable no-param-reassign */ -import { createAsyncThunk, createSlice } from '@reduxjs/toolkit'; -import type { DataAttribute, DataAttributes } from '@store/storeTypes'; -import { getAPI } from '@utils/helper'; -import _ from 'underscore'; - -import type { RootState } from './store'; - -// Define a type for the slice state -interface Blog { - title: string; - coverImageUrl: string; - featured: boolean; - updatedDatetime: string; - author?: string; - content?: string; - description?: string; - tags: { - id: number; - Tag: string; - }[]; -} -interface BlogState { - blogs: Record; - tags: string[]; -} - -const uniqueTags: string[] = []; - -export const getAllBlogs = createAsyncThunk< - Record, - /** no args for this async dispatch */ - void, - { - state: RootState; - } ->('blogs/fetchAllBlogs', async () => { - interface BlogResponse extends Blog { - updatedAt: string; - cover: DataAttribute<{ url: string }>; - } - - interface APIResponse { - data: { - id: number; - attributes: BlogResponse; - }[]; - } - - const parsedBlogs: Record = {}; - const response: APIResponse = await getAPI('/blogs?populate=*'); - - if (response?.data) { - response.data.forEach( - ({ - id, - attributes: { title, cover, featured, updatedAt, author, content, description, tags }, - }) => { - tags.forEach((t) => { - if (!uniqueTags.includes(t.Tag)) { - uniqueTags.push(t.Tag); - } - }); - parsedBlogs[id] = { - title, - coverImageUrl: `${process.env.NEXT_PUBLIC_API_URL}${cover.data.attributes.url}`, - featured, - updatedDatetime: updatedAt, - author, - content: content?.replaceAll('/uploads/', `${process.env.NEXT_PUBLIC_API_URL}/uploads/`), - description, - tags, - }; - } - ); - } - return parsedBlogs; -}); - -// Define the initial state using that type -const initialState: BlogState = { - blogs: [], - tags: [], -}; - -const blogSlice = createSlice({ - name: 'blogs', - initialState, - reducers: {}, - extraReducers: (builder) => { - builder.addCase(getAllBlogs.fulfilled, (state, action) => { - // load all blogs - state.blogs = action.payload; - // load all blog categories - state.tags = uniqueTags; - }); - }, -}); - -export default blogSlice.reducer; diff --git a/store/store.ts b/store/store.ts index 0042e8d..88057ef 100644 --- a/store/store.ts +++ b/store/store.ts @@ -1,13 +1,11 @@ import { configureStore } from '@reduxjs/toolkit'; -import blogSlice from './blogSlice'; import eventSlice from './eventSlice'; import memberSlice from './memberSlice'; export const store = configureStore({ reducer: { events: eventSlice, - blogs: blogSlice, members: memberSlice, }, }); diff --git a/types/Blogs/index.ts b/types/Blogs/index.ts deleted file mode 100644 index 7309349..0000000 --- a/types/Blogs/index.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { DataAttribute, DataAttributes } from '../index'; - -export interface Blog { - title: string; - creator: string; - updatedDatetime: string; - coverImageUrl: string; - content: string; - categories: string[]; - featured: boolean; - description: string; -} - -interface BlogResponse extends Omit { - updatedAt: string; - categories: DataAttributes<{ type: string }>; - cover_image: DataAttribute<{ url: string }>; -} - -export interface APIResponseBlog { - data: { - id: number; - attributes: BlogResponse; - }[]; -} From 803fed2a2a6541dce446783a7e341dba30c95672 Mon Sep 17 00:00:00 2001 From: Abdullah Shahid <90593598+nxabdullah@users.noreply.github.com> Date: Sun, 10 Nov 2024 00:22:21 -0500 Subject: [PATCH 2/4] [revamp-2024] Reduce codebase down to a bare minimum & remove unused dependencies --- .github/pull_request_template.md | 11 +- .vscode/settings.json | 11 +- api/client.ts | 52 - api/schema.ts | 38 - api/types.ts | 39 - api/useFetch.ts | 67 - components/Common/Card.tsx | 15 - components/Common/DetailPageContainer.tsx | 18 - components/Common/Filter.tsx | 33 - components/Common/Footer.tsx | 148 - components/Common/HeadingCard.tsx | 69 - components/Common/HeroNotificationBox.tsx | 29 - .../Common/HorizontalSkeletonLoader.tsx | 27 - components/Common/MarkdownDisplay.tsx | 28 - components/Common/MaterialCard.tsx | 26 - components/Common/MediaQueryContainer.tsx | 23 - components/Common/NavBar.tsx | 242 - components/Common/ScrollingAvatars/Avatar.tsx | 43 - .../ScrollingAvatars/ScrollingAvatars.tsx | 106 - .../ScrollingAvatarsContainer.tsx | 60 - components/Common/SectionWrapper.tsx | 19 - components/Common/Slider.tsx | 16 - components/Common/Tag.tsx | 24 - components/Events/EventHighlightSection.tsx | 101 - components/Events/EventListSection.tsx | 66 - components/Home/AboutUsSection.tsx | 46 +- components/Home/EventSection.tsx | 116 - components/Home/HomeIntroSection.tsx | 59 +- components/Home/JoinUsSections.tsx | 67 - components/Home/TeamMemberSection.tsx | 23 - components/Home/WhatWeDoSection.tsx | 56 - .../Sponsors/SponsorHighlightSection.tsx | 98 - components/Sponsors/SponsorListSection.tsx | 58 - contexts/useAPI/index.tsx | 30 - hooks/useEvents.ts | 7 - hooks/useMembers.ts | 7 - hooks/useSponsors.ts | 7 - package.json | 31 +- pages/Events/[pid].tsx | 98 - pages/Events/index.tsx | 80 - pages/Sponsors/[pid].tsx | 64 - pages/Sponsors/index.tsx | 61 - pages/_app.tsx | 50 +- pages/index.tsx | 25 +- public/MCSS.svg | 1 - public/MCSS_Sponsorship_Package.pdf | Bin 3190665 -> 0 bytes public/chef.jpg | Bin 10189652 -> 0 bytes public/deerfield.png | Bin 846703 -> 0 bytes public/discord.svg | 1 - public/hero.png | Bin 97907 -> 0 bytes public/pattern.svg | 151 - public/profileplaceholder.png | Bin 57597 -> 0 bytes public/vercel.svg | 4 - scss/_HeroNotificationBox.scss | 15 - scss/components/_AboutUsSection.scss | 16 - scss/components/_AcademicsDetail.scss | 46 - .../_AcademicsHighlightSection.scss | 86 - scss/components/_AcademicsListSection.scss | 26 - scss/components/_AcademicsSection.scss | 27 - scss/components/_EventHighlightSection.scss | 85 - scss/components/_EventListPage.scss | 25 - scss/components/_EventSections.scss | 25 - scss/components/_Footer.scss | 12 - scss/components/_MaterialCard.scss | 3 - scss/components/_NavMenu.scss | 5 - scss/components/_ScrollingAvatars.scss | 73 - .../_ScrollingAvatarsContainer.scss | 23 - scss/components/_SponsorHighlightSection.scss | 85 - scss/components/_SponsorListSection.scss | 25 - scss/components/_WhatWeDo.scss | 5 - scss/index.scss | 27 - scss/theme/_colors.scss | 6 - store/eventSlice.ts | 114 - store/hooks.ts | 7 - store/memberSlice.ts | 80 - store/store.ts | 15 - store/storeTypes.d.ts | 12 - style/colors.ts | 12 - style/theme.ts | 167 - types/Academics/index.ts | 25 - types/Events/index.ts | 29 - types/Members/index.ts | 16 - types/Partners/index.ts | 26 - types/Sponsors/index.ts | 24 - types/index.ts | 15 - utils/helper.ts | 47 - utils/hooks.ts | 24 - yarn.lock | 4365 ++++++----------- 88 files changed, 1569 insertions(+), 6475 deletions(-) delete mode 100644 api/client.ts delete mode 100644 api/schema.ts delete mode 100644 api/types.ts delete mode 100644 api/useFetch.ts delete mode 100644 components/Common/Card.tsx delete mode 100644 components/Common/DetailPageContainer.tsx delete mode 100644 components/Common/Filter.tsx delete mode 100644 components/Common/Footer.tsx delete mode 100644 components/Common/HeadingCard.tsx delete mode 100644 components/Common/HeroNotificationBox.tsx delete mode 100644 components/Common/HorizontalSkeletonLoader.tsx delete mode 100644 components/Common/MarkdownDisplay.tsx delete mode 100644 components/Common/MaterialCard.tsx delete mode 100644 components/Common/MediaQueryContainer.tsx delete mode 100644 components/Common/NavBar.tsx delete mode 100644 components/Common/ScrollingAvatars/Avatar.tsx delete mode 100644 components/Common/ScrollingAvatars/ScrollingAvatars.tsx delete mode 100644 components/Common/ScrollingAvatars/ScrollingAvatarsContainer.tsx delete mode 100644 components/Common/SectionWrapper.tsx delete mode 100644 components/Common/Slider.tsx delete mode 100644 components/Common/Tag.tsx delete mode 100644 components/Events/EventHighlightSection.tsx delete mode 100644 components/Events/EventListSection.tsx delete mode 100644 components/Home/EventSection.tsx delete mode 100644 components/Home/JoinUsSections.tsx delete mode 100644 components/Home/TeamMemberSection.tsx delete mode 100644 components/Home/WhatWeDoSection.tsx delete mode 100644 components/Sponsors/SponsorHighlightSection.tsx delete mode 100644 components/Sponsors/SponsorListSection.tsx delete mode 100644 contexts/useAPI/index.tsx delete mode 100644 hooks/useEvents.ts delete mode 100644 hooks/useMembers.ts delete mode 100644 hooks/useSponsors.ts delete mode 100644 pages/Events/[pid].tsx delete mode 100644 pages/Events/index.tsx delete mode 100644 pages/Sponsors/[pid].tsx delete mode 100644 pages/Sponsors/index.tsx delete mode 100644 public/MCSS.svg delete mode 100644 public/MCSS_Sponsorship_Package.pdf delete mode 100644 public/chef.jpg delete mode 100644 public/deerfield.png delete mode 100644 public/discord.svg delete mode 100644 public/hero.png delete mode 100644 public/pattern.svg delete mode 100644 public/profileplaceholder.png delete mode 100644 public/vercel.svg delete mode 100644 scss/_HeroNotificationBox.scss delete mode 100644 scss/components/_AboutUsSection.scss delete mode 100644 scss/components/_AcademicsDetail.scss delete mode 100644 scss/components/_AcademicsHighlightSection.scss delete mode 100644 scss/components/_AcademicsListSection.scss delete mode 100644 scss/components/_AcademicsSection.scss delete mode 100644 scss/components/_EventHighlightSection.scss delete mode 100644 scss/components/_EventListPage.scss delete mode 100644 scss/components/_EventSections.scss delete mode 100644 scss/components/_Footer.scss delete mode 100644 scss/components/_MaterialCard.scss delete mode 100644 scss/components/_NavMenu.scss delete mode 100644 scss/components/_ScrollingAvatars.scss delete mode 100644 scss/components/_ScrollingAvatarsContainer.scss delete mode 100644 scss/components/_SponsorHighlightSection.scss delete mode 100644 scss/components/_SponsorListSection.scss delete mode 100644 scss/components/_WhatWeDo.scss delete mode 100644 scss/index.scss delete mode 100644 scss/theme/_colors.scss delete mode 100644 store/eventSlice.ts delete mode 100644 store/hooks.ts delete mode 100644 store/memberSlice.ts delete mode 100644 store/store.ts delete mode 100644 store/storeTypes.d.ts delete mode 100644 style/colors.ts delete mode 100644 style/theme.ts delete mode 100644 types/Academics/index.ts delete mode 100644 types/Events/index.ts delete mode 100644 types/Members/index.ts delete mode 100644 types/Partners/index.ts delete mode 100644 types/Sponsors/index.ts delete mode 100644 types/index.ts delete mode 100644 utils/helper.ts delete mode 100644 utils/hooks.ts diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index e9893e5..7c5e555 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -1,9 +1,12 @@ -# What's Inside +# Description -- [ ] Placeholder 1 -- [ ] Placeholder 2 +- Describe what changes you made -... full details of acceptance criteria documented in the linked GitHub issue +- Link the ticket here + +## Screenshot(s) + +- If applicable, provide screenshots of your change [//]: <> 'Self Checklist When Opening a Pull Request' diff --git a/.vscode/settings.json b/.vscode/settings.json index 1756547..3b60d31 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,23 +1,17 @@ { - // Spell checker "cSpell.words": ["Deerfield", "Esports", "linebreak", "Mailchimp", "MCSS", "rehype"], "cSpell.language": "en", - // Use prettier for code formatting "editor.defaultFormatter": "esbenp.prettier-vscode", - // Fix all autofixable errors on file save "editor.codeActionsOnSave": { - "source.fixAll": true + "source.fixAll": "explicit" }, - // Fix formatting issues on file save - "editor.formatOnSave": true, + "editor.formatOnSave": false, "eslint.format.enable": true, - // Enable code suggestions "editor.quickSuggestions": { "comments": "on", "strings": "on", "other": "on" }, - // Auto save files after TS refactoring "files.refactoring.autoSave": true, "typescript.tsdk": "node_modules/typescript/lib", "typescript.validate.enable": true, @@ -26,7 +20,6 @@ "typescript.suggest.completeJSDocs": true, "javascript.validate.enable": true, "typescript.preferences.importModuleSpecifier": "non-relative", - // Exclude files from watcher "files.watcherExclude": { "**/.git/objects/**": true, "**/.git/subtree-cache/**": true, diff --git a/api/client.ts b/api/client.ts deleted file mode 100644 index a64773f..0000000 --- a/api/client.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { - InvalidateOptions, - InvalidateQueryFilters, - QueryClient, - QueryKey, - useQuery as __useQuery, - UseQueryOptions, -} from '@tanstack/react-query'; - -import { APITemplate, ClientQueries, InferHandlerInput, QueryPaths } from './types'; - -const validateApiError = () => { - return (apiError: any) => { - throw new Error(apiError.toString()); - }; -}; - -export default class API { - public queryClient: QueryClient; - - private contract: APISchema; - - constructor(contract: APISchema) { - this.queryClient = new QueryClient(); - this.contract = contract; - } - - public useQuery< - TPath extends QueryPaths & string, - TQueryOutput extends ClientQueries[TPath]['awaitedResponse'], - TQueryInput extends InferHandlerInput - >(pathAndInput: [path: TPath, args: TQueryInput], opts?: UseQueryOptions) { - const [path, args] = pathAndInput; - const endpoint = this.contract[path]; - - return __useQuery( - pathAndInput as QueryKey, - () => endpoint(args).catch(validateApiError()), - opts - ); - } - - public invalidateQueries< - TPath extends QueryPaths & string, - TQueryInput extends InferHandlerInput - >( - filters: InvalidateQueryFilters & { queryKey: [path: TPath, args: Partial] }, - options?: InvalidateOptions - ) { - return this.queryClient.invalidateQueries(filters, options); - } -} diff --git a/api/schema.ts b/api/schema.ts deleted file mode 100644 index 75e64c9..0000000 --- a/api/schema.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { CategoryResponse, DataAttributes } from '../types'; -import { APIResponseEvent } from '../types/Events'; -import { MemberResponse } from '../types/Members'; -import { APIResponseSponsor } from '../types/Sponsors'; - -import { CustomFetch } from './useFetch'; - -const events = (customFetch: CustomFetch) => - ({ - eventsList: async () => { - const res = await customFetch('CMS', 'events?populate=*'); - return res.data as APIResponseEvent; - }, - } as const); - -const members = (customFetch: CustomFetch) => ({ - membersList: async () => { - const res = await customFetch('CMS', 'team-members?populate=*'); - return res.data as DataAttributes; - }, -}); - -const sponsors = (customFetch: CustomFetch) => - ({ - sponsorsList: async () => { - const res = await customFetch('CMS', 'sponsors?populate=*'); - return res.data as APIResponseSponsor; - }, - } as const); - -const config = (customFetch: CustomFetch) => - ({ - ...events(customFetch), - ...members(customFetch), - ...sponsors(customFetch), - } as const); - -export default config; diff --git a/api/types.ts b/api/types.ts deleted file mode 100644 index 96f9597..0000000 --- a/api/types.ts +++ /dev/null @@ -1,39 +0,0 @@ -/** template all api in schema should follow */ -export interface APITemplate { - [methodName: string]: (...args: any) => Promise -} - -const querySuffixes = ['Get', 'List'] as const; -type QuerySuffix = (typeof querySuffixes)[number]; - -/** api paths that are queries (end in querySuffixes) */ -export type QueryPaths = { - [QueryName in keyof Contract]-?: QueryName extends `${string}${QuerySuffix}` - ? Contract[QueryName] extends Function - ? QueryName - : never - : never -}[keyof Contract]; - -export type Awaited = T extends PromiseLike ? Awaited : T; - -/** api query paths mapped to args, response, and whatever awaitedResponse is */ -export type ClientQueries = { - [Query in QueryPaths]: { - args: Parameters[0] - response: ReturnType - awaitedResponse: Awaited> - } -}; - -/** args to send with provided api path */ -export type InferHandlerInput = TProcedure extends ( - args: infer TInput, - headers?: any -) => Promise - ? undefined extends TInput // ? is input optional - ? unknown extends TInput // ? is input unset - ? null | undefined // -> there is no input - : TInput | null | undefined // -> there is optional input - : TInput // -> input is required - : undefined | null;// -> there is no input diff --git a/api/useFetch.ts b/api/useFetch.ts deleted file mode 100644 index 45c6c79..0000000 --- a/api/useFetch.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { useCallback } from 'react'; - -const baseURLKeys = ['CMS', 'CUSTOM'] as const; -type BaseURL = (typeof baseURLKeys)[number]; - -const CMS_BASE_URL = process.env.NEXT_PUBLIC_API_URL; - -type Props = { - base: BaseURL; - url: string; -}; - -const fetchHelper = async (props: Props): Promise<{ data: any; error: any; statusCode: any }> => { - const { base, url } = props; - - const api = () => { - switch (base) { - case 'CMS': - return `${CMS_BASE_URL}/api/${url}`; - default: - return url; - } - }; - - const req = { - method: 'GET', - headers: { - 'Content-Type': 'application/json', - }, - }; - - const resp = await fetch(api(), req); - - const response: { error: any; data: unknown; statusCode: any } = { - error: { data: undefined }, - data: undefined, - statusCode: resp.status, - }; - - if (resp.status !== 200) { - const error = await resp.json(); - response.error.data = error; - } else { - const data = await resp.json(); - response.data = data; - } - return response; -}; - -/** DO NOT use this directly, use useAPI */ -const useFetch = () => { - return useCallback(async (base: BaseURL, url: string) => { - try { - return await fetchHelper({ - base, - url, - }); - } catch (error) { - console.log(error); - throw error; - } - }, []); -}; - -export type CustomFetch = ReturnType; - -export default useFetch; diff --git a/components/Common/Card.tsx b/components/Common/Card.tsx deleted file mode 100644 index b8d5dfe..0000000 --- a/components/Common/Card.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import { FC } from 'react'; - -type CardProps = { - children: React.ReactNode; - className?: string; -}; - -/** @deprecated - * use MaterialCard instead - */ -const Card: FC = ({ children, className }) => ( -
{children}
-); - -export default Card; diff --git a/components/Common/DetailPageContainer.tsx b/components/Common/DetailPageContainer.tsx deleted file mode 100644 index dcbb9bc..0000000 --- a/components/Common/DetailPageContainer.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import { ReactNode } from 'react'; - -import Container from '@mui/material/Container'; - -type Props = { - children: ReactNode; -}; - -const DetailPageContainer = (props: Props) => { - const { children } = props; - return ( - - {children} - - ); -}; - -export default DetailPageContainer; diff --git a/components/Common/Filter.tsx b/components/Common/Filter.tsx deleted file mode 100644 index 858cd16..0000000 --- a/components/Common/Filter.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import { FC } from 'react'; - -interface FilterProps { - options: Omit[]; - selectedOptions: string[]; -} - -interface Option { - name: string; - onClick: () => void; - clicked: boolean; -} - -const OptionButton: FC