From 7a041fd753daa00cb9a17a3cacc9ca399ece6db4 Mon Sep 17 00:00:00 2001
From: ingawei <46611122+ingawei@users.noreply.github.com>
Date: Wed, 20 Jul 2022 22:45:53 -0700
Subject: [PATCH] Changing manalinks table UI (#665)
From table to card view
---
web/components/contract/contract-details.tsx | 9 +-
.../contract/contract-info-dialog.tsx | 2 +-
web/components/manalink-card.tsx | 262 +++++++++++++-----
.../manalinks/create-links-button.tsx | 5 +-
web/components/pagination.tsx | 9 +-
web/components/share-icon-button.tsx | 49 ++--
web/pages/link/[slug].tsx | 64 +++--
web/pages/links.tsx | 155 ++---------
8 files changed, 285 insertions(+), 270 deletions(-)
diff --git a/web/components/contract/contract-details.tsx b/web/components/contract/contract-details.tsx
index b4d67520..036311fe 100644
--- a/web/components/contract/contract-details.tsx
+++ b/web/components/contract/contract-details.tsx
@@ -11,6 +11,7 @@ import { UserLink } from '../user-page'
import {
Contract,
contractMetrics,
+ contractPath,
contractPool,
updateContract,
} from 'web/lib/firebase/contracts'
@@ -33,6 +34,7 @@ import { ShareIconButton } from 'web/components/share-icon-button'
import { useUser } from 'web/hooks/use-user'
import { Editor } from '@tiptap/react'
import { exhibitExts } from 'common/util/parse'
+import { ENV_CONFIG } from 'common/envs/constants'
export type ShowTime = 'resolve-date' | 'close-date'
@@ -222,9 +224,12 @@ export function ContractDetails(props: {
{volumeLabel}
{!disabled && }
diff --git a/web/components/contract/contract-info-dialog.tsx b/web/components/contract/contract-info-dialog.tsx
index a0c7fcc9..d976253f 100644
--- a/web/components/contract/contract-info-dialog.tsx
+++ b/web/components/contract/contract-info-dialog.tsx
@@ -19,7 +19,7 @@ import { InfoTooltip } from '../info-tooltip'
import { DuplicateContractButton } from '../copy-contract-button'
export const contractDetailsButtonClassName =
- 'group flex items-center rounded-md px-3 py-2 text-sm font-medium cursor-pointer hover:bg-gray-100 text-gray-400 hover:text-gray-500'
+ 'group flex items-center rounded-md px-3 py-2 text-sm font-medium cursor-pointer hover:bg-gray-100 text-gray-400 hover:text-gray-500'
export function ContractInfoDialog(props: { contract: Contract; bets: Bet[] }) {
const { contract, bets } = props
diff --git a/web/components/manalink-card.tsx b/web/components/manalink-card.tsx
index b5a79091..b49e1621 100644
--- a/web/components/manalink-card.tsx
+++ b/web/components/manalink-card.tsx
@@ -3,9 +3,13 @@ import { formatMoney } from 'common/util/format'
import { fromNow } from 'web/lib/util/time'
import { Col } from 'web/components/layout/col'
import { Row } from 'web/components/layout/row'
-import { User } from 'web/lib/firebase/users'
-import { Button } from './button'
-
+import { Claim, Manalink } from 'common/manalink'
+import { useState } from 'react'
+import { ShareIconButton } from './share-icon-button'
+import { DotsHorizontalIcon } from '@heroicons/react/solid'
+import { contractDetailsButtonClassName } from './contract/contract-info-dialog'
+import { useUserById } from 'web/hooks/use-user'
+import getManalinkUrl from 'web/get-manalink-url'
export type ManalinkInfo = {
expiresTime: number | null
maxUses: number | null
@@ -15,94 +19,202 @@ export type ManalinkInfo = {
}
export function ManalinkCard(props: {
- user: User | null | undefined
- className?: string
info: ManalinkInfo
- isClaiming: boolean
- onClaim?: () => void
+ className?: string
+ preview?: boolean
}) {
- const { user, className, isClaiming, info, onClaim } = props
+ const { className, info, preview = false } = props
const { expiresTime, maxUses, uses, amount, message } = info
return (
-
+
+
+
+ {maxUses != null
+ ? `${maxUses - uses}/${maxUses} uses left`
+ : `Unlimited use`}
+
+
+ {expiresTime != null
+ ? `Expires ${fromNow(expiresTime)}`
+ : 'Never expires'}
+
+
+
+
+
+
+
+ {formatMoney(amount)}
+
+ {message}
+
+
+
+
+ )
+}
+
+export function ManalinkCardFromView(props: {
+ className?: string
+ link: Manalink
+ highlightedSlug: string
+}) {
+ const { className, link, highlightedSlug } = props
+ const { message, amount, expiresTime, maxUses, claims } = link
+ const [details, setDetails] = useState(false)
+
+ return (
+
-
-
- {maxUses != null
- ? `${maxUses - uses}/${maxUses} uses left`
- : `Unlimited use`}
-
-
- {expiresTime != null
- ? `Expires ${fromNow(expiresTime)}`
- : 'Never expires'}
-
-
-
-
-
-
-
+
setDetails(!details)}
+ >
+ {details && (
+
+ )}
+
+
+ {maxUses != null
+ ? `${maxUses - claims.length}/${maxUses} uses left`
+ : `Unlimited use`}
+
+
+ {expiresTime != null
+ ? `Expires ${fromNow(expiresTime)}`
+ : 'Never expires'}
+
+
+
+
+
+
+
{formatMoney(amount)}
- {message}
-
-
-
-
-
-
-
+
+
+
+
{message || '\n\n'}
+
+
)
}
-export function ManalinkCardPreview(props: {
- className?: string
- info: ManalinkInfo
-}) {
- const { className, info } = props
- const { expiresTime, maxUses, uses, amount, message } = info
+function ClaimsList(props: { link: Manalink; className: string }) {
+ const { link, className } = props
return (
-
-
-
- {maxUses != null
- ? `${maxUses - uses}/${maxUses} uses left`
- : `Unlimited use`}
+ <>
+
+
+ Claimed by...
-
- {expiresTime != null
- ? `Expires ${fromNow(expiresTime)}`
- : 'Never expires'}
+
+ {link.claims.length > 0 ? (
+ <>
+ {link.claims.map((claim) => (
+
+
+
+ ))}
+ >
+ ) : (
+
+ No one has claimed this manalink yet! Share your manalink to start
+ spreading the wealth.
+
+ )}
-
-
-
-
- {formatMoney(amount)}
- {message}
-
-
-
+ >
)
}
+
+function Claim(props: { claim: Claim }) {
+ const { claim } = props
+ const who = useUserById(claim.toId)
+ return (
+
+ {who?.name || 'Loading...'}
+ {fromNow(claim.claimedTime)}
+
+ )
+}
+
+function getManalinkGradient(amount: number) {
+ if (amount < 20) {
+ return 'from-indigo-200 via-indigo-500 to-indigo-800'
+ } else if (amount >= 20 && amount < 50) {
+ return 'from-fuchsia-200 via-fuchsia-500 to-fuchsia-800'
+ } else if (amount >= 50 && amount < 100) {
+ return 'from-rose-100 via-rose-400 to-rose-700'
+ } else if (amount >= 100) {
+ return 'from-amber-200 via-amber-500 to-amber-700'
+ }
+}
+
+function getManalinkAmountColor(amount: number) {
+ if (amount < 20) {
+ return 'text-indigo-500'
+ } else if (amount >= 20 && amount < 50) {
+ return 'text-fuchsia-600'
+ } else if (amount >= 50 && amount < 100) {
+ return 'text-rose-600'
+ } else if (amount >= 100) {
+ return 'text-amber-600'
+ }
+}
diff --git a/web/components/manalinks/create-links-button.tsx b/web/components/manalinks/create-links-button.tsx
index 0d1d603e..25b51bb2 100644
--- a/web/components/manalinks/create-links-button.tsx
+++ b/web/components/manalinks/create-links-button.tsx
@@ -4,7 +4,7 @@ import { Col } from '../layout/col'
import { Row } from '../layout/row'
import { Title } from '../title'
import { User } from 'common/user'
-import { ManalinkCardPreview, ManalinkInfo } from 'web/components/manalink-card'
+import { ManalinkCard, ManalinkInfo } from 'web/components/manalink-card'
import { createManalink } from 'web/lib/firebase/manalinks'
import { Modal } from 'web/components/layout/modal'
import Textarea from 'react-expanding-textarea'
@@ -37,6 +37,7 @@ export function CreateLinksButton(props: {
message: newManalink.message,
})
setHighlightedSlug(slug || '')
+ setTimeout(() => setHighlightedSlug(''), 3700)
}}
/>
@@ -191,7 +192,7 @@ function CreateManalinkForm(props: {
{finishedCreating && (
<>
-
+
void
scrollToTop?: boolean
+ className?: string
nextTitle?: string
prevTitle?: string
}) {
@@ -15,13 +18,17 @@ export function Pagination(props: {
scrollToTop,
nextTitle,
prevTitle,
+ className,
} = props
const maxPage = Math.ceil(totalItems / itemsPerPage) - 1
return (