Skip to content

Commit

Permalink
feat: event page, sorted and formated accordion
Browse files Browse the repository at this point in the history
  • Loading branch information
alexandre-kakal-akarah committed Jun 19, 2024
1 parent 72c39fd commit 0dc23f4
Show file tree
Hide file tree
Showing 9 changed files with 332 additions and 5 deletions.
8 changes: 4 additions & 4 deletions next.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
const nextConfig = {
images: {
remotePatterns: [
// {
// protocol: "https",
// hostname: "via.assets.so",
// },
{
protocol: "https",
hostname: "picsum.photos",
},
],
},
};
Expand Down
62 changes: 62 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
"dependencies": {
"@hookform/resolvers": "^3.6.0",
"@prisma/client": "^5.15.1",
"@radix-ui/react-accordion": "^1.1.2",
"@radix-ui/react-label": "^2.0.2",
"@radix-ui/react-popover": "^1.0.7",
"@radix-ui/react-radio-group": "^1.1.3",
Expand Down
82 changes: 82 additions & 0 deletions src/app/(app)/evenements/[id]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import React from "react";
import ParallaxImage from "@/components/clients/ParallaxImage";
import Rating from "@/components/Rating";
import { Icons } from "@/components/Icons";

type Params = { id: string };

const EventDetail = ({ params }: { params: Params }) => {
// get journey by id
return (
<main className="flex min-h-screen flex-col bg-gray">
<ParallaxImage />
<div className="relative flex-1 -translate-y-4 rounded-t-2xl px-5 pb-40 pt-14">
<div className="absolute left-4 top-0 flex gap-[6px]">
<div className="flex items-center rounded-b-md bg-white px-2 py-[6px]">
<Icons.dumbbel />
<p className="text-sm font-semibold text-gray">Facile</p>
</div>
<div className="flex items-center gap-1 rounded-b-md bg-green px-2 py-[6px]">
<Icons.bulb />
<p className="text-sm font-semibold text-gray">Intermédiaire</p>
</div>
</div>
<h1 className="text-xl font-extrabold text-orange">
Sentier du biscuit sablé
</h1>
<div className="flex items-center gap-1 text-beige-600">
<Icons.mapPin fill="rgba(206, 192, 173, 60%)" />
<p className="text-sm font-medium">Normandie</p>
</div>
<p>TODO: Par Jean Blonblon, le 23/06/2024</p>

<p className="text-sm">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce
accumsan ligula tellus, a luctus eros lobortis eu. Fusce rhoncus
turpis in metus fermentum, nec hendrerit elit mattis. In ipsum diam,
pellentesque ut porttitor eu, laoreet et dolor. Sed bibendum nec nulla
eu fringilla. Aliquam erat volutpat. Nullam quis risus scelerisque,
aliquet sapien ultricies, vulputate urna. Aenean sed dolor a nisl
pellentesque venenatis at eget lectus. Vestibulum tempus at dui quis
faucibus.
</p>
<div className="mt-[18px] flex items-center justify-between text-lg font-semibold text-orange">
<h2>Accessibilité</h2>
<Icons.arrowLink />
</div>
<div className="mt-4 flex gap-6">
<div className="flex aspect-[1/1] flex-1 items-center justify-center rounded-lg border-2 border-cadetblue bg-cadetblue-600">
<Icons.pmr />
</div>
<div className="flex aspect-[1/1] flex-1 items-center justify-center rounded-lg border-2 border-cadetblue bg-cadetblue-600">
<Icons.partiallySighted />
</div>
<div className="flex aspect-[1/1] flex-1 items-center justify-center rounded-lg border-2 border-cadetblue bg-cadetblue-600">
<Icons.partiallyDeaf />
</div>
<div className="flex aspect-[1/1] flex-1 items-center justify-center rounded-lg border-2 border-cadetblue bg-cadetblue-600">
<Icons.cognitivelyImpaired />
</div>
</div>
<h2 className="mt-[18px] text-lg font-semibold text-orange">
Pré-requis
</h2>
<p>
Lorem ipsum dolor sit amet consectetur, adipisicing elit.
Necessitatibus facilis velit dolores consectetur ea, molestias autem
maiores dicta, laboriosam eaque, nesciunt esse accusamus libero
aperiam.
</p>

<h2 className="mt-[18px] text-lg font-semibold text-orange">
Commentaires
</h2>
<div className="flex gap-1">
<Rating rating={3.5} ratingCount={4} />
</div>
</div>
</main>
);
};

export default EventDetail;
22 changes: 22 additions & 0 deletions src/app/(app)/evenements/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import React from "react";
import AddButton from "@/components/AddButton";
import JourneyForm from "@/components/form/journey/JourneyForm";
import TopBar from "@/components/TopBar";
import EventsFeed from "@/components/EventsFeed";

const Event = () => {
return (
<>
<TopBar />
<main>
<section className="flex flex-col gap-7 px-5 pb-40">
<EventsFeed />
</section>
<JourneyForm />
<AddButton action="journey" />
</main>
</>
);
};

export default Event;
86 changes: 86 additions & 0 deletions src/components/EventAccordion.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
"use client";
import React, { useState } from "react";
import {
Accordion,
AccordionItem,
AccordionTrigger,
AccordionContent,
} from "./ui/accordion";
import { Event } from "@prisma/client";
import Image from "next/image";
import Link from "next/link";

interface EventAccordionProps {
events: Event[];
}

const EventAccordion: React.FC<EventAccordionProps> = ({ events }) => {
const groupedEvents = events.reduce(
(groups: Record<string, Event[]>, event) => {
const date = new Date(event.startAt).toISOString().split("T")[0];
if (!groups[date]) {
groups[date] = [];
}
groups[date].push(event);
return groups;
},
{},
);

const sortedDates = Object.keys(groupedEvents).sort();

const formattedDates = sortedDates.map((date) => ({
original: date,
formatted: new Date(date).toLocaleDateString("fr-FR", {
weekday: "long",
year: "numeric",
month: "long",
day: "numeric",
}),
}));

const [openItem, setOpenItem] = useState<string>(formattedDates[0].formatted);

const handleToggle = (date: string) => {
setOpenItem((prev) => (prev === date ? "" : date));
};

return (
<Accordion
type="single"
value={openItem}
onValueChange={handleToggle}
className="w-full"
>
{formattedDates.map(({ original, formatted }) => (
<AccordionItem key={original} value={formatted}>
<AccordionTrigger className="py-2 text-lg font-medium">
{formatted}
</AccordionTrigger>
<AccordionContent className="space-y-4">
{groupedEvents[original].map((event) => (
<div key={event.id} className=" rounded-lg border p-4 shadow">
<Link href={`/evenements/${event.id}`}>
<Image
src={`${event.image}200`}
alt={event.title}
className="mb-4 h-32 w-full rounded object-cover"
width={200}
height={200}
/>
<h3 className="text-xl font-bold">{event.title}</h3>
<p className="">{event.description}</p>
<p className="">
Participants: {event.numberPlayerMin} -{" "}
{event.numberPlayerMax}
</p>
</Link>
</div>
))}
</AccordionContent>
</AccordionItem>
))}
</Accordion>
);
};
export default EventAccordion;
16 changes: 16 additions & 0 deletions src/components/EventsFeed.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import EventAccordion from "./EventAccordion";
import { Suspense } from "react";

const EventsFeed = async () => {
const res = await fetch(`${process.env.BASE_URL}/api/events`, {
cache: "no-cache",
});
const events = await res.json();
return (
<Suspense fallback={<div>Loading...</div>}>
<EventAccordion events={events.data} />
</Suspense>
);
};

export default EventsFeed;
2 changes: 1 addition & 1 deletion src/components/MobileNav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ const MobileNav = () => {
const currentPath = usePathname();
const isMainPage = currentPath === "/" || currentPath === "";
return (
<nav className="fixed inset-x-5 bottom-5 flex items-end justify-center rounded-xl bg-background p-2">
<nav className="fixed inset-x-5 bottom-5 flex items-end justify-center rounded-xl border-2 border-orange bg-background p-2">
<Link
href="/parcours"
className="flex h-10 flex-1 items-center justify-center "
Expand Down
58 changes: 58 additions & 0 deletions src/components/ui/accordion.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
"use client";

import * as React from "react";
import * as AccordionPrimitive from "@radix-ui/react-accordion";
import { ChevronDown } from "lucide-react";

import { cn } from "@/lib/tailwindUtils";

const Accordion = AccordionPrimitive.Root;

const AccordionItem = React.forwardRef<
React.ElementRef<typeof AccordionPrimitive.Item>,
React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Item>
>(({ className, ...props }, ref) => (
<AccordionPrimitive.Item
ref={ref}
className={cn("border-b", className)}
{...props}
/>
));
AccordionItem.displayName = "AccordionItem";

const AccordionTrigger = React.forwardRef<
React.ElementRef<typeof AccordionPrimitive.Trigger>,
React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Trigger>
>(({ className, children, ...props }, ref) => (
<AccordionPrimitive.Header className="flex">
<AccordionPrimitive.Trigger
ref={ref}
className={cn(
"flex flex-1 items-center justify-between py-4 font-medium transition-all hover:underline [&[data-state=open]>svg]:rotate-180",
className,
)}
{...props}
>
{children}
<ChevronDown className="size-4 shrink-0 transition-transform duration-200" />
</AccordionPrimitive.Trigger>
</AccordionPrimitive.Header>
));
AccordionTrigger.displayName = AccordionPrimitive.Trigger.displayName;

const AccordionContent = React.forwardRef<
React.ElementRef<typeof AccordionPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Content>
>(({ className, children, ...props }, ref) => (
<AccordionPrimitive.Content
ref={ref}
className="overflow-hidden text-sm transition-all data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down"
{...props}
>
<div className={cn("pb-4 pt-0", className)}>{children}</div>
</AccordionPrimitive.Content>
));

AccordionContent.displayName = AccordionPrimitive.Content.displayName;

export { Accordion, AccordionItem, AccordionTrigger, AccordionContent };

0 comments on commit 0dc23f4

Please sign in to comment.