From a4e2cce4aab5232db21788175ed338ee7163a97c Mon Sep 17 00:00:00 2001
From: ingawei <46611122+ingawei@users.noreply.github.com>
Date: Wed, 13 Jul 2022 14:57:34 -0700
Subject: [PATCH] initial commit for manalinks UI improvements (#642)
* manalinks UI improvements
* made manalink look more like card
* changed new link to pulsing indigo instead of green
---
 web/components/button.tsx                     |  37 +++
 web/components/manalink-card.tsx              |  41 +++
 .../manalinks/create-links-button.tsx         | 197 +++++++++++++++
 web/components/subtitle.tsx                   |  15 ++
 web/get-manalink-url.ts                       |   3 +
 web/pages/links.tsx                           | 236 ++++--------------
 6 files changed, 340 insertions(+), 189 deletions(-)
 create mode 100644 web/components/button.tsx
 create mode 100644 web/components/manalinks/create-links-button.tsx
 create mode 100644 web/components/subtitle.tsx
 create mode 100644 web/get-manalink-url.ts
diff --git a/web/components/button.tsx b/web/components/button.tsx
new file mode 100644
index 00000000..3b59581b
--- /dev/null
+++ b/web/components/button.tsx
@@ -0,0 +1,37 @@
+import { ReactNode } from 'react'
+import clsx from 'clsx'
+
+export default function Button(props: {
+  className?: string
+  onClick?: () => void
+  color: 'green' | 'red' | 'blue' | 'indigo' | 'yellow' | 'gray'
+  children?: ReactNode
+  type?: 'button' | 'reset' | 'submit'
+}) {
+  const {
+    className,
+    onClick,
+    children,
+    color = 'indigo',
+    type = 'button',
+  } = props
+
+  return (
+    
+  )
+}
diff --git a/web/components/manalink-card.tsx b/web/components/manalink-card.tsx
index 97f5951c..fec05919 100644
--- a/web/components/manalink-card.tsx
+++ b/web/components/manalink-card.tsx
@@ -67,3 +67,44 @@ export function ManalinkCard(props: {
     
   )
 }
+
+export function ManalinkCardPreview(props: {
+  className?: string
+  info: ManalinkInfo
+  defaultMessage: string
+}) {
+  const { className, defaultMessage, info } = 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 || defaultMessage}
+        
+      
+    
 
+  )
+}
diff --git a/web/components/manalinks/create-links-button.tsx b/web/components/manalinks/create-links-button.tsx
new file mode 100644
index 00000000..d74980cf
--- /dev/null
+++ b/web/components/manalinks/create-links-button.tsx
@@ -0,0 +1,197 @@
+import clsx from 'clsx'
+import { useState } from 'react'
+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 { createManalink } from 'web/lib/firebase/manalinks'
+import { Modal } from 'web/components/layout/modal'
+import Textarea from 'react-expanding-textarea'
+import dayjs from 'dayjs'
+import Button from '../button'
+import { getManalinkUrl } from 'web/pages/links'
+import { DuplicateIcon } from '@heroicons/react/outline'
+
+export function CreateLinksButton(props: {
+  user: User
+  highlightedSlug: string
+  setHighlightedSlug: (slug: string) => void
+}) {
+  const { user, highlightedSlug, setHighlightedSlug } = props
+  const [open, setOpen] = useState(false)
+
+  return (
+    <>
+       setOpen(newOpen)}>
+        
+           {
+              const slug = await createManalink({
+                fromId: user.id,
+                amount: newManalink.amount,
+                expiresTime: newManalink.expiresTime,
+                maxUses: newManalink.maxUses,
+                message: newManalink.message,
+              })
+              setHighlightedSlug(slug || '')
+            }}
+          />
+        
+      
+
+      
+    >
+  )
+}
+
+function CreateManalinkForm(props: {
+  highlightedSlug: string
+  user: User
+  onCreate: (m: ManalinkInfo) => Promise
+}) {
+  const { user, onCreate, highlightedSlug } = props
+  const [isCreating, setIsCreating] = useState(false)
+  const [finishedCreating, setFinishedCreating] = useState(false)
+  const [copyPressed, setCopyPressed] = useState(false)
+  setTimeout(() => setCopyPressed(false), 300)
+
+  const [newManalink, setNewManalink] = useState({
+    expiresTime: null,
+    amount: 100,
+    maxUses: 1,
+    uses: 0,
+    message: '',
+  })
+
+  return (
+    <>
+      {!finishedCreating && (
+        
+      )}
+      {finishedCreating && (
+        <>
+          
+          
+          
+            
+              {getManalinkUrl(highlightedSlug)}
+            
+             {
+                navigator.clipboard.writeText(getManalinkUrl(highlightedSlug))
+                setCopyPressed(true)
+              }}
+              className="my-auto ml-2 h-5 w-5 cursor-pointer transition hover:opacity-50"
+            />
+          
+        >
+      )}
+    >
+  )
+}
diff --git a/web/components/subtitle.tsx b/web/components/subtitle.tsx
new file mode 100644
index 00000000..85d19778
--- /dev/null
+++ b/web/components/subtitle.tsx
@@ -0,0 +1,15 @@
+import clsx from 'clsx'
+
+export function Subtitle(props: { text: string; className?: string }) {
+  const { text, className } = props
+  return (
+    
+      {text}
+    
+  )
+}
diff --git a/web/get-manalink-url.ts b/web/get-manalink-url.ts
new file mode 100644
index 00000000..89a0c8a6
--- /dev/null
+++ b/web/get-manalink-url.ts
@@ -0,0 +1,3 @@
+export default function getManalinkUrl(slug: string) {
+  return `${location.protocol}//${location.host}/link/${slug}`
+}
diff --git a/web/pages/links.tsx b/web/pages/links.tsx
index 12cde274..ede997df 100644
--- a/web/pages/links.tsx
+++ b/web/pages/links.tsx
@@ -4,41 +4,29 @@ import { ChevronDownIcon, ChevronUpIcon } from '@heroicons/react/solid'
 import { Claim, Manalink } from 'common/manalink'
 import { formatMoney } from 'common/util/format'
 import { Col } from 'web/components/layout/col'
+import { Row } from 'web/components/layout/row'
 import { Page } from 'web/components/page'
 import { SEO } from 'web/components/SEO'
 import { Title } from 'web/components/title'
+import { Subtitle } from 'web/components/subtitle'
 import { useUser } from 'web/hooks/use-user'
-import { createManalink, useUserManalinks } from 'web/lib/firebase/manalinks'
+import { useUserManalinks } from 'web/lib/firebase/manalinks'
 import { fromNow } from 'web/lib/util/time'
 import { useUserById } from 'web/hooks/use-users'
 import { ManalinkTxn } from 'common/txn'
-import { User } from 'common/user'
-import { Tabs } from 'web/components/layout/tabs'
 import { Avatar } from 'web/components/avatar'
 import { RelativeTimestamp } from 'web/components/relative-timestamp'
 import { UserLink } from 'web/components/user-page'
-import { ManalinkCard, ManalinkInfo } from 'web/components/manalink-card'
-
-import Textarea from 'react-expanding-textarea'
+import { CreateLinksButton } from 'web/components/manalinks/create-links-button'
 
 import dayjs from 'dayjs'
 import customParseFormat from 'dayjs/plugin/customParseFormat'
 dayjs.extend(customParseFormat)
 
-function getLinkUrl(slug: string) {
+export function getManalinkUrl(slug: string) {
   return `${location.protocol}//${location.host}/link/${slug}`
 }
 
-// TODO: incredibly gross, but the tab component is wrongly designed and
-// keeps the tab state inside of itself, so this seems like the only
-// way we can tell it to switch tabs from outside after initial render.
-function setTabIndex(tabIndex: number) {
-  const tabHref = document.getElementById(`tab-${tabIndex}`)
-  if (tabHref) {
-    tabHref.click()
-  }
-}
-
 export default function LinkPage() {
   const user = useUser()
   const links = useUserManalinks(user?.id ?? '')
@@ -58,166 +46,31 @@ export default function LinkPage() {
     
       
       
-        
-         {
-                    const slug = await createManalink({
-                      fromId: user.id,
-                      amount: newManalink.amount,
-                      expiresTime: newManalink.expiresTime,
-                      maxUses: newManalink.maxUses,
-                      message: newManalink.message,
-                    })
-                    setTabIndex(1)
-                    setHighlightedSlug(slug || '')
-                  }}
-                />
-              ),
-            },
-            {
-              title: 'Unclaimed links',
-              content: (
-                
-              ),
-            },
-            // TODO: we have no use case for this atm and it's also really inefficient
-            // {
-            //   title: 'Claimed',
-            //   content: ,
-            // },
-          ]}
-        />
+        
+          
+          {user && (
+            
+          )}
+        
+        
+          You can use manalinks to send mana to other people, even if they
+          don't yet have a Manifold account.
+        
+        
+        
       
     
   )
 }
 
-function CreateManalinkForm(props: {
-  user: User
-  onCreate: (m: ManalinkInfo) => Promise
-}) {
-  const { user, onCreate } = props
-  const [isCreating, setIsCreating] = useState(false)
-  const [newManalink, setNewManalink] = useState({
-    expiresTime: null,
-    amount: 100,
-    maxUses: 1,
-    uses: 0,
-    message: '',
-  })
-  return (
-    <>
-      
-        You can use manalinks to send mana to other people, even if they
-        don't yet have a Manifold account.
-      
-      
-
-      
-      This is what the person you send the link to will see:
-      
-    >
-  )
-}
-
 export function ClaimsList(props: { txns: ManalinkTxn[] }) {
   const { txns } = props
   return (
@@ -334,8 +187,8 @@ function LinkSummaryRow(props: {
 }) {
   const { link, highlight, expanded, onToggle } = props
   const className = clsx(
-    'whitespace-nowrap text-sm hover:cursor-pointer',
-    highlight ? 'bg-primary' : 'text-gray-500 hover:bg-sky-50 bg-white'
+    'whitespace-nowrap text-sm hover:cursor-pointer text-gray-500 hover:bg-sky-50 bg-white',
+    highlight ? 'bg-indigo-100 rounded-lg animate-pulse' : ''
   )
   return (
     
@@ -350,7 +203,7 @@ function LinkSummaryRow(props: {
       | 
         {formatMoney(link.amount)}
        | 
-      {getLinkUrl(link.slug)} | 
+      {getManalinkUrl(link.slug)} | 
       {link.claimedUserIds.length} | 
       {link.maxUses == null ? '∞' : link.maxUses} | 
       
@@ -365,22 +218,27 @@ function LinksTable(props: { links: Manalink[]; highlightedSlug?: string }) {
   return links.length == 0 ? (
      You don't currently have any outstanding manalinks. 
   ) : (
-    
-      
-        
-           | 
-          Amount | 
-          Link | 
-          Uses | 
-          Max Uses | 
-          Expires | 
-         
-      
-      
-        {links.map((link) => (
-          
-        ))}
-      
-     
+    
+       
+        
+          
+             | 
+            Amount | 
+            Link | 
+            Uses | 
+            Max Uses | 
+            Expires | 
+           
+        
+        
+          {links.map((link) => (
+            
+          ))}
+        
+       
+      
   )
 }
 |