Skip to content

Commit

Permalink
feat: implemented swiping for suggestions
Browse files Browse the repository at this point in the history
  • Loading branch information
wzarek committed Jun 23, 2024
1 parent f90973a commit ee7d8cd
Show file tree
Hide file tree
Showing 9 changed files with 320 additions and 15 deletions.
141 changes: 141 additions & 0 deletions Client/reasn-client/apps/web/app/events/suggestions/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
"use client";

import { Card, CardVariant } from "@reasn/ui/src/components/shared";
import { Add, Dismiss, Question } from "@reasn/ui/src/icons";
import clsx from "clsx";
import React, { MouseEvent, useState } from "react";

const EventsSuggestionsPage = () => {
const [events, setEvents] = useState<number[]>([
0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
]);
const currentCardRef = React.useRef<HTMLDivElement>(null);
const nextCardRef = React.useRef<HTMLDivElement>(null);
const [isAnimating, setIsAnimating] = useState(false);
const [action, setAction] = useState<"like" | "dislike" | "participate" | "">(
"",
);

const handleDismissEvent = (e: MouseEvent<HTMLElement>) => {
currentCardRef.current?.classList.add("animate-fadeOutLeft");
setIsAnimating(true);
setAction("dislike");
setTimeout(() => {
currentCardRef.current?.classList.remove("animate-fadeOutLeft");
setEvents((prev) => prev.slice(1));
setIsAnimating(false);
setAction("");
}, 500);
e.stopPropagation();
};

const handleLikeEvent = (e: MouseEvent<HTMLElement>) => {
currentCardRef.current?.classList.add("animate-fadeOutDown");
setIsAnimating(true);
setAction("like");
setTimeout(() => {
currentCardRef.current?.classList.remove("animate-fadeOutDown");
setEvents((prev) => prev.slice(1));
setIsAnimating(false);
setAction("");
}, 500);
e.stopPropagation();
};

const handleParticipateInEvent = (e: MouseEvent<HTMLElement>) => {
currentCardRef.current?.classList.add("animate-fadeOutRight");
setIsAnimating(true);
setAction("participate");
setTimeout(() => {
currentCardRef.current?.classList.remove("animate-fadeOutRight");
setEvents((prev) => prev.slice(1));
setIsAnimating(false);
setAction("");
}, 500);
e.stopPropagation();
};

return (
<div className="relative flex w-full flex-col items-center justify-center">
<div
className={clsx(
"absolute right-[-50%] top-[-25%] z-0 h-[50%] w-[200%] rounded-full blur-3xl",
"bg-blue-400 duration-1000",
{ "opacity-30": action === "like" },
{ "opacity-10": action !== "like" },
)}
></div>
<div
className={clsx(
"absolute left-[-50%] top-[-25%] z-0 h-[100%] w-[100%] rounded-full blur-3xl",
"bg-red-400 duration-1000",
{ "opacity-30": action === "dislike" },
{ "opacity-10": action !== "dislike" },
)}
></div>
<div
className={clsx(
"absolute right-[-50%] top-[-25%] z-0 h-[100%] w-[100%] rounded-full blur-3xl",
"bg-green-400 duration-1000",
{ "opacity-30": action === "participate" },
{ "opacity-10": action !== "participate" },
)}
></div>
<div className="relative h-[60vh] w-full items-center justify-center">
{events.map((val, idx) => (
<div
key={val + idx}
className={clsx(
"absolute left-1/2 duration-500",
{ "pointer-events-none": idx !== 0 },
{ "opacity-5 blur-sm": idx > 1 || (idx === 1 && !isAnimating) },
{ "opacity-1 blur-none": idx === 1 && isAnimating },
{ "opacity-1 pointer-events-auto": idx === 0 },
)}
style={{
transform: `translate(-50%, ${idx * 1.5}%)`,
zIndex: `${11 - idx}`,
}}
ref={idx === 0 ? currentCardRef : idx === 1 ? nextCardRef : null}
>
<Card variant={CardVariant.Swiping} event="Abc" />
</div>
))}
</div>
<div className="flex w-full items-center justify-center gap-10 lg:gap-24">
<div
onClick={handleDismissEvent}
className={clsx(
"flex h-12 w-28 cursor-pointer items-center justify-center rounded-full",
"bg-red-500 bg-opacity-40 p-2 text-2xl font-semibold",
"group duration-300 hover:bg-red-700",
)}
>
<Dismiss className="h-5 w-5 fill-red-500 duration-300 group-hover:fill-black" />
</div>
<div
onClick={handleLikeEvent}
className={clsx(
"flex h-12 w-16 cursor-pointer items-center justify-center rounded-full",
"bg-blue-400 bg-opacity-40 p-2 text-2xl font-semibold",
"group duration-300 hover:bg-blue-700",
)}
>
<Question className="h-5 w-5 fill-blue-400 duration-300 group-hover:fill-black" />
</div>
<div
onClick={handleParticipateInEvent}
className={clsx(
"flex h-12 w-28 cursor-pointer items-center justify-center rounded-full",
"bg-green-500 bg-opacity-40 p-2 text-2xl font-semibold",
"group duration-300 hover:bg-green-700",
)}
>
<Add className="h-5 w-5 fill-green-500 duration-300 group-hover:fill-black" />
</div>
</div>
</div>
);
};

export default EventsSuggestionsPage;
2 changes: 1 addition & 1 deletion Client/reasn-client/apps/web/middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export const middleware = (req: NextRequest) => {

if (path.startsWith("/events") && session.user?.role === UserRole.USER) {
return NextResponse.redirect(new URL("/events", req.url));
}
}
};

export const config = {
Expand Down
22 changes: 22 additions & 0 deletions Client/reasn-client/apps/web/tailwind.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,28 @@ module.exports = {
screens: {
xs: "460px",
},
keyframes: {
fadeOutRight: {
"0%": { transform: "translateX(-50%) rotate(0deg)", opacity: 1 },
"100%": { transform: "translateX(100%) rotate(30deg)", opacity: 0 },
},
fadeOutLeft: {
"0%": { transform: "translateX(-50%) rotate(0deg)", opacity: 1 },
"100%": { transform: "translateX(-150%) rotate(-30deg)", opacity: 0 },
},
fadeOutDown: {
"0%": { transform: "translateX(-50%) translateY(0%)", opacity: 1 },
"100%": {
transform: "translateX(-50%) translateY(-100%)",
opacity: 0,
},
},
},
animation: {
fadeOutRight: "fadeOutRight 0.5s ease-in-out forwards",
fadeOutLeft: "fadeOutLeft 0.5s ease-in-out forwards",
fadeOutDown: "fadeOutDown 0.5s ease-in-out forwards",
},
},
},
plugins: [],
Expand Down
30 changes: 30 additions & 0 deletions Client/reasn-client/packages/ui/src/components/shared/Card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export enum CardVariant {
Big,
Tile,
List,
Swiping,
}

export interface CardProps {
Expand All @@ -31,6 +32,7 @@ export const Card = (props: Readonly<CardProps>) => {
{variant === CardVariant.Big && <CardBig event={event} />}
{variant === CardVariant.Tile && <CardTile event={event} />}
{variant === CardVariant.List && <CardList event={event} />}
{variant === CardVariant.Swiping && <CardSwiping event={event} />}
</div>
);
};
Expand Down Expand Up @@ -145,3 +147,31 @@ const CardList = ({ event }: { event: string }) => {
</div>
);
};

const CardSwiping = ({ event }: { event: string }) => {
return (
<div className="group relative h-[45vh] w-[20vw] min-w-[15em] cursor-pointer overflow-clip rounded-3xl md:h-[50vh] md:min-h-[10em] md:min-w-[20em] lg:min-h-[25em] lg:min-w-[25em]">
<img
src={MOCK_IMG_URL}
alt=""
className="absolute left-0 top-0 h-full object-cover"
/>
<div className="relative flex h-2/3 w-full flex-col gap-2 bg-[#232326ee] p-4 text-[#F7F8F8]">
<div className="flex flex-wrap gap-1 text-xs text-[#cacaca]">
<p className="rounded-md bg-[#4b4e52] px-[5px] py-[1px]">#abcd</p>
<p className="rounded-md bg-[#4b4e52] px-[5px] py-[1px]">#abcd</p>
<p className="rounded-md bg-[#4b4e52] px-[5px] py-[1px]">#abcd</p>
<p className="rounded-md bg-[#4b4e52] px-[5px] py-[1px]">#abcd</p>
</div>
<h2 className="w-4/5 break-words text-3xl font-semibold">
Koncert fagaty na PWR w C-16
</h2>
<p className="hidden text-base text-[#cacaca] md:block">
Lorem ipsum, dolor sit amet consectetur adipisicing elit. Unde
quisquam maiores doloremque molestiae ducimus, distinctio accusamus
sed voluptatem eius itaque.
</p>
</div>
</div>
);
};
17 changes: 3 additions & 14 deletions Client/reasn-client/packages/ui/src/components/shared/Comment.tsx
Original file line number Diff line number Diff line change
@@ -1,26 +1,15 @@
import React from "react";
import {
CommentDto,
CommentDtoMapper,
} from "@reasn/common/src/schemas/CommentDto";
import { ButtonBase, FloatingTextarea } from "./form";

interface CommentProps {
comment?: CommentDto;
comment?: string;
}

export const Comment = (props: CommentProps) => {
const comment = CommentDtoMapper.fromObject({
EventId: 1,
Content:
"Lorem ipsum dolor, sit amet consectetur adipisicing elit. Soluta quidem sapiente odit maxime. Officiis, error laborum. Voluptatem quibusdam mollitia possimus?",
CreatedAt: new Date(),
UserId: 1,
});

const { comment } = props;
return (
<div className="flex flex-col gap-4 rounded-md bg-[#4b4e526d] p-2">
<p className="font-thin">{comment.Content}</p>
<p className="font-thin">{comment}</p>
<div className="flex items-center gap-2">
<div className="relative rounded-full bg-gradient-to-r from-[#32346A] to-[#4E4F75] p-[2px]">
<img
Expand Down
40 changes: 40 additions & 0 deletions Client/reasn-client/packages/ui/src/icons/Add.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import React from "react";
import { IconProps } from "./IconProps";

export const Add = (props: IconProps) => {
const { className, colors, gradientTransform, onClick } = props;

return (
<svg
xmlns="http://www.w3.org/2000/svg"
width="16"
height="16"
className={className}
viewBox="0 0 24 24"
fill="url(#gradient1)"
onClick={onClick}
>
<defs>
<linearGradient
id="gradient1"
x1="0%"
y1="0%"
x2="100%"
y2="0%"
gradientTransform={gradientTransform}
>
{colors?.map((color, index) => (
<stop
key={index}
offset={`${
index + 1 < colors.length ? index * (100 / colors.length) : 100
}%`}
style={{ stopColor: color, stopOpacity: 1 }}
/>
))}
</linearGradient>
</defs>
<path d="M11.883 3.007 12 3a1 1 0 0 1 .993.883L13 4v7h7a1 1 0 0 1 .993.883L21 12a1 1 0 0 1-.883.993L20 13h-7v7a1 1 0 0 1-.883.993L12 21a1 1 0 0 1-.993-.883L11 20v-7H4a1 1 0 0 1-.993-.883L3 12a1 1 0 0 1 .883-.993L4 11h7V4a1 1 0 0 1 .883-.993L12 3l-.117.007Z" />
</svg>
);
};
40 changes: 40 additions & 0 deletions Client/reasn-client/packages/ui/src/icons/Dismiss.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import React from "react";
import { IconProps } from "./IconProps";

export const Dismiss = (props: IconProps) => {
const { className, colors, gradientTransform, onClick } = props;

return (
<svg
xmlns="http://www.w3.org/2000/svg"
width="16"
height="16"
className={className}
viewBox="0 0 24 24"
fill="url(#gradient1)"
onClick={onClick}
>
<defs>
<linearGradient
id="gradient1"
x1="0%"
y1="0%"
x2="100%"
y2="0%"
gradientTransform={gradientTransform}
>
{colors?.map((color, index) => (
<stop
key={index}
offset={`${
index + 1 < colors.length ? index * (100 / colors.length) : 100
}%`}
style={{ stopColor: color, stopOpacity: 1 }}
/>
))}
</linearGradient>
</defs>
<path d="m4.21 4.387.083-.094a1 1 0 0 1 1.32-.083l.094.083L12 10.585l6.293-6.292a1 1 0 1 1 1.414 1.414L13.415 12l6.292 6.293a1 1 0 0 1 .083 1.32l-.083.094a1 1 0 0 1-1.32.083l-.094-.083L12 13.415l-6.293 6.292a1 1 0 0 1-1.414-1.414L10.585 12 4.293 5.707a1 1 0 0 1-.083-1.32l.083-.094-.083.094Z" />
</svg>
);
};
40 changes: 40 additions & 0 deletions Client/reasn-client/packages/ui/src/icons/Question.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import React from "react";
import { IconProps } from "./IconProps";

export const Question = (props: IconProps) => {
const { className, colors, gradientTransform, onClick } = props;

return (
<svg
xmlns="http://www.w3.org/2000/svg"
width="16"
height="16"
className={className}
viewBox="0 0 24 24"
fill="url(#gradient1)"
onClick={onClick}
>
<defs>
<linearGradient
id="gradient1"
x1="0%"
y1="0%"
x2="100%"
y2="0%"
gradientTransform={gradientTransform}
>
{colors?.map((color, index) => (
<stop
key={index}
offset={`${
index + 1 < colors.length ? index * (100 / colors.length) : 100
}%`}
style={{ stopColor: color, stopOpacity: 1 }}
/>
))}
</linearGradient>
</defs>
<path d="M12 4C9.238 4 7 6.238 7 9a1 1 0 0 0 2 0c0-1.658 1.342-3 3-3s3 1.342 3 3c0 .816-.199 1.294-.438 1.629-.262.365-.625.638-1.128.985l-.116.078c-.447.306-1.023.699-1.469 1.247-.527.648-.849 1.467-.849 2.561v.5a1 1 0 1 0 2 0v-.5c0-.656.178-1.024.4-1.299.257-.314.603-.552 1.114-.903l.053-.037c.496-.34 1.133-.786 1.62-1.468C16.7 11.081 17 10.183 17 9c0-2.762-2.238-5-5-5ZM12 21.25a1.25 1.25 0 1 0 0-2.5 1.25 1.25 0 0 0 0 2.5Z" />
</svg>
);
};
3 changes: 3 additions & 0 deletions Client/reasn-client/packages/ui/src/icons/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,6 @@ export { ArrowRight } from "./ArrowRight";
export { Upload } from "./Upload";
export { CaretDown } from "./CaretDown";
export { CaretUp } from "./CaretUp";
export { Add } from "./Add";
export { Question } from "./Question";
export { Dismiss } from "./Dismiss";

0 comments on commit ee7d8cd

Please sign in to comment.