Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add a copy button to the vote modal for a proposal link #86

Merged
merged 1 commit into from
Nov 27, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 49 additions & 8 deletions components/groups/modals/voteDetailsModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
import CountdownTimer from '../components/CountdownTimer';
import { useFeeEstimation } from '@/hooks';

import { TrashIcon } from '@heroicons/react/24/outline';
import { ShareIcon, TrashIcon, CheckIcon } from '@heroicons/react/24/outline';
const Chart = dynamic(() => import('react-apexcharts'), {
ssr: false,
}) as any;
Expand Down Expand Up @@ -419,9 +419,18 @@
return { action: null, label: null };
}, [proposal, proposalClosed, userHasVoted, address]);

const [copied, setCopied] = useState(false);

const copyProposalLink = () => {
const url = `${window.location.origin}/groups?policyAddress=${proposal?.group_policy_address}&proposalId=${proposal?.id}`;
navigator.clipboard.writeText(url);
setCopied(true);

Check warning on line 427 in components/groups/modals/voteDetailsModal.tsx

View check run for this annotation

Codecov / codecov/patch

components/groups/modals/voteDetailsModal.tsx#L424-L427

Added lines #L424 - L427 were not covered by tests
setTimeout(() => setCopied(false), 2000);
};

return (
<dialog id={modalId} className="modal">
<div className="modal-box relative max-w-4xl min-h-96 max-h-[80vh] overflow-y-hidden flex flex-col md:flex-row md:ml-20 -mt-12 rounded-[24px] shadow-lg bg-secondary transition-all duration-300 z-[1000]">
<div className="modal-box relative max-w-4xl min-h-96 max-h-[80vh] overflow-y-auto flex flex-col md:flex-row md:ml-20 -mt-12 rounded-[24px] shadow-lg bg-secondary transition-all duration-300 z-[1000]">
<form method="dialog" onSubmit={onClose}>
<button className="btn btn-sm btn-circle text-black dark:text-white btn-ghost absolute right-2 top-2">
Expand Down Expand Up @@ -471,15 +480,17 @@
</span>
</div>
<div className="divider my-"></div>
<div className="w-full">
<p className="text-sm font-light text-gray-500 dark:text-gray-400 mb-2 ">SUMMARY</p>
<div className="bg-base-300 rounded-[12px] p-4">
<p className="text-sm text-primary-content">{proposal?.summary}</p>
{proposal?.summary && (
<div className="w-full">
<p className="text-sm font-light text-gray-500 dark:text-gray-400 mb-2 ">SUMMARY</p>
<div className="bg-base-300 rounded-[12px] p-4">
<p className="text-sm text-primary-content">{proposal?.summary}</p>
</div>
</div>
</div>
)}
<div className="w-full">
<p className="text-sm font-light text-gray-500 dark:text-gray-400 mb-2">MESSAGES</p>
<div className="bg-base-300 rounded-[12px] p-4 overflow-y-auto max-h-[20rem]">
<div className="bg-base-300 rounded-[12px] p-4 overflow-y-auto max-h-[17rem]">
{proposal?.messages?.map((message: any, index: number) => {
const messageType = message['@type'];
const fieldsToShow = importantFields[messageType] || defaultFields;
Expand All @@ -503,6 +514,21 @@
</p>
<CountdownTimer endTime={new Date(proposal?.voting_period_end)} />
</div>
<div className="flex-row gap-2 items-center hidden md:flex mb-2">
<button
onClick={copyProposalLink}
className="flex flex-row items-center gap-2 hover:bg-[#FFFFFFCC] dark:hover:bg-[#FFFFFF0F] p-2 rounded-full transition-colors duration-200"
>
{copied ? (
<CheckIcon className="w-4 h-4 text-green-500" />
) : (
<ShareIcon className="w-4 h-4" />
)}
<p className="text-sm font-light text-gray-500 dark:text-gray-400">
{copied ? 'Copied!' : 'Share this proposal'}
</p>
</button>
</div>
</div>
<div className="divider divider-horizontal"></div>
<div className="flex flex-col w-full relative flex-grow items-start justify-start p-6 space-y-6">
Expand Down Expand Up @@ -562,6 +588,21 @@
</p>
<CountdownTimer endTime={new Date(proposal.voting_period_end)} />
</div>
<div className="flex-row gap-2 items-center flex md:hidden mb-2">
<button
onClick={copyProposalLink}
className="flex flex-row items-center gap-2 hover:bg-[#FFFFFFCC] dark:hover:bg-[#FFFFFF0F] p-2 rounded-full transition-colors duration-200"
>
{copied ? (
<CheckIcon className="w-4 h-4 text-green-500" />
) : (
<ShareIcon className="w-4 h-4" />
)}
<p className="text-sm font-light text-gray-500 dark:text-gray-400">
{copied ? 'Copied!' : 'Share this proposal'}
</p>
</button>
</div>
Comment on lines +591 to +605
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

DRY: Consider extracting share button component

The share button implementation is duplicated between desktop and mobile views. Consider extracting it into a reusable component.

+ const ShareButton = ({ onClick, copied }) => (
+   <button
+     onClick={onClick}
+     aria-label={copied ? "Copied to clipboard" : "Share proposal"}
+     title="Copy proposal link"
+     className="flex flex-row items-center gap-2 hover:bg-[#FFFFFFCC] dark:hover:bg-[#FFFFFF0F] p-2 rounded-full transition-colors duration-200"
+   >
+     {copied ? (
+       <CheckIcon className="w-4 h-4 text-green-500" />
+     ) : (
+       <ShareIcon className="w-4 h-4" />
+     )}
+     <p className="text-sm font-light text-gray-500 dark:text-gray-400">
+       {copied ? 'Copied!' : 'Share this proposal'}
+     </p>
+   </button>
+ );

// Then use it in both places:
- <button onClick={copyProposalLink} className="...">
+ <ShareButton onClick={copyProposalLink} copied={copied} />

Committable suggestion skipped: line range outside the PR's diff.

<div className="w-full relative">
{getButtonState.action && (
<button
Expand Down