From 8cc3e7f778de14ec03c255252ce44ff4de0b560c Mon Sep 17 00:00:00 2001 From: James Q Quick Date: Thu, 25 Jul 2024 14:51:36 -0500 Subject: [PATCH] Merge Staging to Main (#233) - accessibility - loading states for improved streaming performance - static pages for deal pages --- src/app/deals/[id]/loading.tsx | 6 +++ src/app/deals/[id]/page.tsx | 31 ++++++++++------ src/app/deals/category/[category]/page.tsx | 13 +++---- src/app/deals/page.tsx | 15 +++----- src/app/page.tsx | 7 +--- src/components/IconButton.tsx | 19 ++++++++++ src/components/Overlay.tsx | 37 +++++++++++-------- src/components/deals/ApprovedDeals.tsx | 9 +++++ .../deals/ApprovedDealsByCategory.tsx | 14 +++++++ src/components/deals/DealCard.tsx | 11 +----- .../{ => deals}/DealGradientPlaceholder.tsx | 6 --- src/components/deals/DealImage.tsx | 2 +- src/components/{ => deals}/DealPreview.tsx | 11 ++---- src/components/deals/DealsList.tsx | 3 ++ src/components/deals/FeaturedDeals.tsx | 7 ++++ .../FeaturedDealsSection.tsx} | 12 +++--- .../deals/loading/LoadingDealImage.tsx | 5 +++ .../deals/loading/LoadingDealsList.tsx | 20 ++++++++++ .../deals/loading/LoadingPreview.tsx | 11 ++++++ .../forms/add-a-deal/ReviewDeal.tsx | 2 +- src/components/search/GlobalSearch.tsx | 1 + src/components/search/SearchResults.tsx | 2 +- src/components/search/SearchedDeal.tsx | 2 +- 23 files changed, 166 insertions(+), 80 deletions(-) create mode 100644 src/app/deals/[id]/loading.tsx create mode 100644 src/components/IconButton.tsx create mode 100644 src/components/deals/ApprovedDeals.tsx create mode 100644 src/components/deals/ApprovedDealsByCategory.tsx rename src/components/{ => deals}/DealGradientPlaceholder.tsx (95%) rename src/components/{ => deals}/DealPreview.tsx (87%) create mode 100644 src/components/deals/FeaturedDeals.tsx rename src/components/{FeaturedDeals.tsx => deals/FeaturedDealsSection.tsx} (61%) create mode 100644 src/components/deals/loading/LoadingDealImage.tsx create mode 100644 src/components/deals/loading/LoadingDealsList.tsx create mode 100644 src/components/deals/loading/LoadingPreview.tsx diff --git a/src/app/deals/[id]/loading.tsx b/src/app/deals/[id]/loading.tsx new file mode 100644 index 0000000..c7eafcd --- /dev/null +++ b/src/app/deals/[id]/loading.tsx @@ -0,0 +1,6 @@ +import LoadingPreview from '@/components/deals/loading/LoadingPreview' +import React from 'react' + +export default function Loading() { + return +} diff --git a/src/app/deals/[id]/page.tsx b/src/app/deals/[id]/page.tsx index 00e967f..408fcc1 100644 --- a/src/app/deals/[id]/page.tsx +++ b/src/app/deals/[id]/page.tsx @@ -1,23 +1,25 @@ import { notFound } from 'next/navigation' -import { getDealById } from '@/lib/queries' -import DealPreview from '@/components/DealPreview' -import { Metadata, ResolvingMetadata } from 'next' +import { getApprovedDeals, getDealById } from '@/lib/queries' +import { Metadata } from 'next' +import DealPreview from '@/components/deals/DealPreview' export const revalidate = 120 type Props = { params: { id: string } - searchParams: { [key: string]: string | string[] | undefined } } -export async function generateMetadata( - { params, searchParams }: Props, - parent: ResolvingMetadata -): Promise { - // read route params - const id = params.id +export const dynamicParams = true - // fetch data +export async function generateStaticParams() { + const deals = await getApprovedDeals() + + return deals.map((deal) => ({ + id: deal.xata_id, + })) +} + +export async function generateMetadata({ params }: Props): Promise { const deal = await getDealById(params.id) if (!deal) { @@ -35,10 +37,15 @@ export async function generateMetadata( } } +//sleep function +function sleep(ms: number) { + return new Promise((resolve) => setTimeout(resolve, ms)) +} export default async function DealPage({ params }: { params: { id: string } }) { if (!params.id) { - //not found + notFound() } + const deal = await getDealById(params.id) if (!deal) { notFound() diff --git a/src/app/deals/category/[category]/page.tsx b/src/app/deals/category/[category]/page.tsx index 531b590..bc042e9 100644 --- a/src/app/deals/category/[category]/page.tsx +++ b/src/app/deals/category/[category]/page.tsx @@ -4,6 +4,9 @@ import { Category } from '@/types/Types' import { getApprovedDealsByCategory } from '@/lib/queries' import PageHeader from '@/components/PageHeader' import DealsList from '@/components/deals/DealsList' +import ApprovedDealsByCategory from '@/components/deals/ApprovedDealsByCategory' +import { Suspense } from 'react' +import LoadingDealsList from '@/components/deals/loading/LoadingDealsList' export const revalidate = 120 @@ -23,7 +26,6 @@ export default async function CategoryPage({ } //TODO move logic for converting deals to capitalized and singular to a helper function const category = categoryString as Category - const deals = await getApprovedDealsByCategory(category) let capitalizedCategory = category .split(' ') .map((word) => word.charAt(0).toUpperCase() + word.toLowerCase().slice(1)) @@ -39,12 +41,9 @@ export default async function CategoryPage({
- {deals.length === 0 && ( -
- No deals found for this category -
- )} - + }> + + ) } diff --git a/src/app/deals/page.tsx b/src/app/deals/page.tsx index f4def76..ec04f75 100644 --- a/src/app/deals/page.tsx +++ b/src/app/deals/page.tsx @@ -1,13 +1,13 @@ import CategoryOptions from '@/components/CategoryOptions' -import { getApprovedDeals } from '@/lib/queries' import NeverMissADeal from '@/components/NeverMissADeal' import PageHeader from '@/components/PageHeader' -import DealsList from '@/components/deals/DealsList' +import ApprovedDeals from '@/components/deals/ApprovedDeals' +import LoadingDealsList from '@/components/deals/loading/LoadingDealsList' +import { Suspense } from 'react' export const revalidate = 120 export default async function DealsPage() { - const deals = await getApprovedDeals(20) //TODO: handle error return (
@@ -17,12 +17,9 @@ export default async function DealsPage() {
- {deals.length === 0 && ( -
- No deals found for this category -
- )} - + }> + +
) diff --git a/src/app/page.tsx b/src/app/page.tsx index d57d723..247db36 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -1,19 +1,16 @@ +import FeaturedDealsSection from '@/components/deals/FeaturedDealsSection' import DevGiveaways from '@/components/DevGiveaways' -import FeaturedDeals from '@/components/FeaturedDeals' import Hero from '@/components/Hero' import NeverMissADeal from '@/components/NeverMissADeal' import Separator from '@/components/Separator' -import { getApprovedFeaturedDeals } from '@/lib/queries' export const revalidate = 120 export default async function Home() { - const deals = await getApprovedFeaturedDeals() return (
- - +
diff --git a/src/components/IconButton.tsx b/src/components/IconButton.tsx new file mode 100644 index 0000000..46e3428 --- /dev/null +++ b/src/components/IconButton.tsx @@ -0,0 +1,19 @@ +import React from 'react' + +export default function IconButton({ + handleClick, + children, +}: { + handleClick: () => void + children: React.ReactNode +}) { + return ( + + ) +} diff --git a/src/components/Overlay.tsx b/src/components/Overlay.tsx index 62fdb34..d3abc87 100644 --- a/src/components/Overlay.tsx +++ b/src/components/Overlay.tsx @@ -1,6 +1,6 @@ 'use client' -import { ReactNode } from 'react' +import { ReactNode, useEffect, useRef } from 'react' import { FaTimes } from 'react-icons/fa' const Overlay = ({ @@ -12,22 +12,29 @@ const Overlay = ({ onClose: () => void children: ReactNode }) => { + const dialogRef = useRef(null) + + useEffect(() => { + if (isOpen) { + dialogRef.current?.showModal() + } else { + dialogRef.current?.close() + } + }) return ( -
-
- - {children} -
-
+ + {children} + ) } diff --git a/src/components/deals/ApprovedDeals.tsx b/src/components/deals/ApprovedDeals.tsx new file mode 100644 index 0000000..b22d3a6 --- /dev/null +++ b/src/components/deals/ApprovedDeals.tsx @@ -0,0 +1,9 @@ +import { getApprovedDeals } from '@/lib/queries' +import React from 'react' +import DealsList from './DealsList' + +export default async function ApprovedDeals() { + const deals = await getApprovedDeals(20) + + return +} diff --git a/src/components/deals/ApprovedDealsByCategory.tsx b/src/components/deals/ApprovedDealsByCategory.tsx new file mode 100644 index 0000000..cd9cbcd --- /dev/null +++ b/src/components/deals/ApprovedDealsByCategory.tsx @@ -0,0 +1,14 @@ +import { getApprovedDealsByCategory } from '@/lib/queries' +import React from 'react' +import DealsList from './DealsList' +import { Category } from '@/types/Types' + +export default async function ApprovedDealsByCategory({ + category, +}: { + category: Category +}) { + const deals = await getApprovedDealsByCategory(category) + + return +} diff --git a/src/components/deals/DealCard.tsx b/src/components/deals/DealCard.tsx index d2490c0..7d38b95 100644 --- a/src/components/deals/DealCard.tsx +++ b/src/components/deals/DealCard.tsx @@ -1,17 +1,8 @@ import Link from 'next/link' -import { FaBeer, FaVideo, FaBook, FaCog, FaCalendar } from 'react-icons/fa' import { Category } from '@/types/Types' import { Deal } from '@prisma/client' import DealImage from './DealImage' -const categoryToIcon: { [key: string]: JSX.Element } = { - Misc: , - Ebook: , - Video: , - Tool: , - Conference: , -} - export default function DealCard({ deal }: { deal: Deal }) { return ( -

{deal.name}

+

{deal.name}

{deal.coupon && deal.couponPercent && (

{deal.couponPercent}% diff --git a/src/components/DealGradientPlaceholder.tsx b/src/components/deals/DealGradientPlaceholder.tsx similarity index 95% rename from src/components/DealGradientPlaceholder.tsx rename to src/components/deals/DealGradientPlaceholder.tsx index 9e6a71a..67a9db2 100644 --- a/src/components/DealGradientPlaceholder.tsx +++ b/src/components/deals/DealGradientPlaceholder.tsx @@ -1,19 +1,13 @@ import { Category } from '@/types/Types' import React from 'react' import { - FaBeer, FaBook, - FaCalendar, FaChair, FaCog, - FaCompactDisc, - FaDeskpro, FaDesktop, FaMicrophone, FaSchool, - FaTable, FaTag, - FaVideo, } from 'react-icons/fa' import { twMerge } from 'tailwind-merge' diff --git a/src/components/deals/DealImage.tsx b/src/components/deals/DealImage.tsx index 150bfbd..d2e01f0 100644 --- a/src/components/deals/DealImage.tsx +++ b/src/components/deals/DealImage.tsx @@ -1,7 +1,7 @@ import { Category } from '@/types/Types' import { Deal } from '@prisma/client' import React from 'react' -import DealGradientPlaceholder from '../DealGradientPlaceholder' +import DealGradientPlaceholder from './DealGradientPlaceholder' import Image from 'next/image' interface IDealImageProps { diff --git a/src/components/DealPreview.tsx b/src/components/deals/DealPreview.tsx similarity index 87% rename from src/components/DealPreview.tsx rename to src/components/deals/DealPreview.tsx index 3f9cd5f..1720f06 100644 --- a/src/components/DealPreview.tsx +++ b/src/components/deals/DealPreview.tsx @@ -1,10 +1,7 @@ import { format } from 'date-fns' -import React from 'react' -import DealGradientPlaceholder from './DealGradientPlaceholder' import { Category } from '@/types/Types' -import Image from 'next/image' -import ClickableCoupon from './ClickableCouponCode' -import DealImage from './deals/DealImage' +import DealImage from './DealImage' +import ClickableCoupon from '../ClickableCouponCode' export default function DealPreview({ link, @@ -35,8 +32,8 @@ export default function DealPreview({ category={category as Category} />

-
- {name} +
+

{name}

Website: + {deals.length === 0 && ( +
No deals found
+ )} {deals.length > 0 && (
<> diff --git a/src/components/deals/FeaturedDeals.tsx b/src/components/deals/FeaturedDeals.tsx new file mode 100644 index 0000000..112c89c --- /dev/null +++ b/src/components/deals/FeaturedDeals.tsx @@ -0,0 +1,7 @@ +import DealsList from './DealsList' +import { getApprovedFeaturedDeals } from '@/lib/queries' + +export default async function FeaturedDeals() { + const deals = await getApprovedFeaturedDeals() + return +} diff --git a/src/components/FeaturedDeals.tsx b/src/components/deals/FeaturedDealsSection.tsx similarity index 61% rename from src/components/FeaturedDeals.tsx rename to src/components/deals/FeaturedDealsSection.tsx index 427b0a9..a8c6f4a 100644 --- a/src/components/FeaturedDeals.tsx +++ b/src/components/deals/FeaturedDealsSection.tsx @@ -1,9 +1,9 @@ -import React from 'react' -import DealsList from './deals/DealsList' import Link from 'next/link' -import { Deal } from '@prisma/client' +import FeaturedDeals from './FeaturedDeals' +import { Suspense } from 'react' +import LoadingDealsList from './loading/LoadingDealsList' -export default function FeaturedDeals({ deals }: { deals: Deal[] }) { +export default function FeaturedDealsSection() { return (
@@ -18,7 +18,9 @@ export default function FeaturedDeals({ deals }: { deals: Deal[] }) { View all deals
- + }> + +
) } diff --git a/src/components/deals/loading/LoadingDealImage.tsx b/src/components/deals/loading/LoadingDealImage.tsx new file mode 100644 index 0000000..aa0e7e8 --- /dev/null +++ b/src/components/deals/loading/LoadingDealImage.tsx @@ -0,0 +1,5 @@ +export default function LoadingDealImage() { + return ( +
+ ) +} diff --git a/src/components/deals/loading/LoadingDealsList.tsx b/src/components/deals/loading/LoadingDealsList.tsx new file mode 100644 index 0000000..cc901a6 --- /dev/null +++ b/src/components/deals/loading/LoadingDealsList.tsx @@ -0,0 +1,20 @@ +import LoadingDealImage from './LoadingDealImage' + +export default function LoadingDealsList({ count }: { count: number }) { + const arr = Array.from(Array(count).keys()) + + return ( +
+
+ <> + {arr.map((num) => ( +
+ +
+
+ ))} + +
+
+ ) +} diff --git a/src/components/deals/loading/LoadingPreview.tsx b/src/components/deals/loading/LoadingPreview.tsx new file mode 100644 index 0000000..2e5ba6e --- /dev/null +++ b/src/components/deals/loading/LoadingPreview.tsx @@ -0,0 +1,11 @@ +import LoadingDealImage from './LoadingDealImage' + +export default function LoadingPreview() { + return ( +
+
+ +
+
+ ) +} diff --git a/src/components/forms/add-a-deal/ReviewDeal.tsx b/src/components/forms/add-a-deal/ReviewDeal.tsx index cc0fbfc..5071d73 100644 --- a/src/components/forms/add-a-deal/ReviewDeal.tsx +++ b/src/components/forms/add-a-deal/ReviewDeal.tsx @@ -2,10 +2,10 @@ import { useRouter } from 'next/navigation' import { useAddDealContext } from '@/context/AddDealContext' import toast from 'react-hot-toast' -import DealPreview from '@/components/DealPreview' import Loading from '@/components/Loading' import { submitDealAction } from '@/app/deals/add/actions' import { NewDealType } from '@/app/deals/add/schemas' +import DealPreview from '@/components/deals/DealPreview' export default function ReviewDeal() { const { newDealData, dataLoaded } = useAddDealContext() diff --git a/src/components/search/GlobalSearch.tsx b/src/components/search/GlobalSearch.tsx index 3ffeaa4..5325640 100644 --- a/src/components/search/GlobalSearch.tsx +++ b/src/components/search/GlobalSearch.tsx @@ -88,6 +88,7 @@ export default function GlobalSearch() { diff --git a/src/components/search/SearchResults.tsx b/src/components/search/SearchResults.tsx index ac313e2..d80e6c0 100644 --- a/src/components/search/SearchResults.tsx +++ b/src/components/search/SearchResults.tsx @@ -31,7 +31,7 @@ export default function SearchResults({ )} {!loading && deals && deals.length === 0 && ( -
+

No results for search{' '} {'"' + searchQuery + '"'} diff --git a/src/components/search/SearchedDeal.tsx b/src/components/search/SearchedDeal.tsx index de9502a..5219c00 100644 --- a/src/components/search/SearchedDeal.tsx +++ b/src/components/search/SearchedDeal.tsx @@ -1,6 +1,6 @@ import { Category } from '@/types/Types' import { Deal } from '@prisma/client' -import DealGradientPlaceholder from '../DealGradientPlaceholder' +import DealGradientPlaceholder from '../deals/DealGradientPlaceholder' import Image from 'next/image' import Link from 'next/link' import React from 'react'