Skip to content

Commit

Permalink
Merge pull request #234 from Trendyol/revert-233-revert-232-animated-…
Browse files Browse the repository at this point in the history
…sort

feat: add animated sort
  • Loading branch information
armagandalkiran authored Dec 25, 2024
2 parents eb126ed + 5f7413f commit a16a59f
Show file tree
Hide file tree
Showing 4 changed files with 137 additions and 79 deletions.
1 change: 1 addition & 0 deletions gurubu-client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"dependencies": {
"@tabler/icons-react": "^2.40.0",
"axios": "^1.6.0",
"framer-motion": "^11.15.0",
"marked": "^15.0.4",
"next": "14.0.0",
"react": "^18",
Expand Down
195 changes: 116 additions & 79 deletions gurubu-client/src/app/components/room/grooming-board-participants.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,101 +3,138 @@ import { IconCheck } from "@tabler/icons-react";
import { useGroomingRoom } from "@/contexts/GroomingRoomContext";
import Image from "next/image";
import { GroomingMode, PARTICIPANT_VOTES_COUNT } from "@/shared/enums";
import { useEffect, useState } from "react";
import { AnimatePresence, motion } from "framer-motion";

const GroomingBoardParticipants = () => {
const { groomingInfo } = useGroomingRoom();
const groomingInfoParticipants = Object.keys(groomingInfo.participants || {});
const [sortedParticipants, setSortedParticipants] = useState<string[]>([]);

useEffect(() => {
if (groomingInfo.isResultShown) {
const sorted = groomingInfoParticipants.sort((a, b) => {
const votesA = groomingInfo.participants[a].votes || {};
const votesB = groomingInfo.participants[b].votes || {};
return (
(Number(votesB["storyPoint"] || 0)) -
Number(votesA["storyPoint"] || 0)
);
});
setSortedParticipants([...sorted]);
} else {
setSortedParticipants([...groomingInfoParticipants]);
}
}, [
groomingInfo,
]);

return (
<ul className="grooming-board-participants">
{groomingInfoParticipants.map((participantKey) => {
const { isAdmin, sockets, votes, nickname } = groomingInfo.participants[participantKey];
const hasSockets = sockets.length > 0;
const hasMaxVotes = Object.keys(votes || {}).length === PARTICIPANT_VOTES_COUNT.MAX_VOTE;
const isResultShown = groomingInfo.isResultShown;
const isPlanningPokerMode = groomingInfo.mode === GroomingMode.PlanningPoker;
<AnimatePresence>
{sortedParticipants.map(participantKey => {
const { isAdmin, sockets, votes, nickname } =
groomingInfo.participants[participantKey];
const hasSockets = sockets.length > 0;
const hasMaxVotes =
Object.keys(votes || {}).length ===
PARTICIPANT_VOTES_COUNT.MAX_VOTE;
const isResultShown = groomingInfo.isResultShown;
const isPlanningPokerMode =
groomingInfo.mode === GroomingMode.PlanningPoker;

return (
<li key={participantKey}>
<div className="grooming-board-participants__nickname-container">
{isAdmin && (
<Image
src="/admin.svg"
width={16}
height={16}
alt="Admin Logo"
priority
/>
)}
{!hasSockets && (
<Image
src="/wifi-off.svg"
width={14.26}
height={12}
alt="Wifi Off Logo"
priority
/>
)}
{hasSockets && !isAdmin && !isPlanningPokerMode && (
<div
return (
<motion.li
layout
initial={{ opacity: 0, scale: 0.9 }}
animate={{ opacity: 1, scale: 1 }}
exit={{ opacity: 0, scale: 0.9 }}
transition={{ duration: 0.3, ease: "easeInOut" }}
key={participantKey}
>
<div className="grooming-board-participants__nickname-container">
{isAdmin && (
<Image
src="/admin.svg"
width={16}
height={16}
alt="Admin Logo"
priority
/>
)}
{!hasSockets && (
<Image
src="/wifi-off.svg"
width={14.26}
height={12}
alt="Wifi Off Logo"
priority
/>
)}
{hasSockets && !isAdmin && !isPlanningPokerMode && (
<div
className={classNames(
"grooming-board-participants__point-card",
{
"grooming-board-participants__all-metrics-voted":
hasMaxVotes,
}
)}
>
{hasMaxVotes && (
<div className="grooming-board-participants__check-icon-container">
<IconCheck width={13} color="white" />
</div>
)}
</div>
)}

<label
className={classNames(
"grooming-board-participants__point-card",
"grooming-board-participants__nickname",
{
"grooming-board-participants__all-metrics-voted":
hasMaxVotes,
"connection-lost": !hasSockets,
"additional-space":
hasSockets && isPlanningPokerMode && !isAdmin,
}
)}
>
{hasMaxVotes && (
<div className="grooming-board-participants__check-icon-container">
<IconCheck width={13} color="white" />
</div>
)}
</div>
)}

<label
className={classNames("grooming-board-participants__nickname", {
"connection-lost": !hasSockets,
"additional-space": hasSockets && isPlanningPokerMode && !isAdmin
})}
>
{nickname}
</label>
</div>
{nickname}
</label>
</div>

<div className="grooming-board-participants__point-cards-container">
{groomingInfo.metrics.map((metric) => {
const participantVote =
votes && votes[metric.name];
const hasParticipantVoted = !!participantVote;
<div className="grooming-board-participants__point-cards-container">
{groomingInfo.metrics.map((metric) => {
const participantVote = votes && votes[metric.name];
const hasParticipantVoted = !!participantVote;

return (
<div key={metric.id}>
<div
className={classNames(
"grooming-board-participants__point-card",
{
"grooming-board-participants__metric-voted":
hasParticipantVoted,
show: isResultShown,
}
)}
>
{!isResultShown && (
<div className="grooming-board-participants__check-icon-container">
<IconCheck width={16} color="white" />
</div>
)}
return (
<div key={metric.id}>
<div
className={classNames(
"grooming-board-participants__point-card",
{
"grooming-board-participants__metric-voted":
hasParticipantVoted,
show: isResultShown,
}
)}
>
{!isResultShown && (
<div className="grooming-board-participants__check-icon-container">
<IconCheck width={16} color="white" />
</div>
)}
</div>
{isResultShown && <p>{participantVote}</p>}
</div>
{isResultShown && <p>{participantVote}</p>}
</div>
);
})}
</div>
</li>
);
})}
);
})}
</div>
</motion.li>
);
})}
</AnimatePresence>
</ul>
);
};
Expand Down
1 change: 1 addition & 0 deletions gurubu-client/src/app/styles/room/grooming-board.scss
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@
border: 1px solid $gray-20;
padding: 0 12px 12px 12px;
max-height: max-content;
margin-bottom: 24px;
}
&__metrics {
display: flex;
Expand Down
19 changes: 19 additions & 0 deletions gurubu-client/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1134,6 +1134,15 @@ form-data@^4.0.0:
combined-stream "^1.0.8"
mime-types "^2.1.12"

framer-motion@^11.15.0:
version "11.15.0"
resolved "https://registry.yarnpkg.com/framer-motion/-/framer-motion-11.15.0.tgz#93e5d1839d500ba9cab1d617959a36142a61212b"
integrity sha512-MLk8IvZntxOMg7lDBLw2qgTHHv664bYoYmnFTmE0Gm/FW67aOJk0WM3ctMcG+Xhcv+vh5uyyXwxvxhSeJzSe+w==
dependencies:
motion-dom "^11.14.3"
motion-utils "^11.14.3"
tslib "^2.4.0"

fs.realpath@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
Expand Down Expand Up @@ -1702,6 +1711,16 @@ minimist@^1.2.0, minimist@^1.2.6:
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c"
integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==

motion-dom@^11.14.3:
version "11.14.3"
resolved "https://registry.yarnpkg.com/motion-dom/-/motion-dom-11.14.3.tgz#725c72c0f1d0b632e42fdd8d13b69ecf9fe202c0"
integrity sha512-lW+D2wBy5vxLJi6aCP0xyxTxlTfiu+b+zcpVbGVFUxotwThqhdpPRSmX8xztAgtZMPMeU0WGVn/k1w4I+TbPqA==

motion-utils@^11.14.3:
version "11.14.3"
resolved "https://registry.yarnpkg.com/motion-utils/-/motion-utils-11.14.3.tgz#cd4a413463739498411f82abb67b3dd58768b0f8"
integrity sha512-Xg+8xnqIJTpr0L/cidfTTBFkvRw26ZtGGuIhA94J9PQ2p4mEa06Xx7QVYZH0BP+EpMSaDlu+q0I0mmvwADPsaQ==

[email protected]:
version "2.1.2"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
Expand Down

0 comments on commit a16a59f

Please sign in to comment.