6cc2d8af58
* Set up Firestore structure for mana bounty links
* Split up manalinks into successes and failures
* Allow clients to create manalinks
* Track txnId and successful users
* Store custom amounts in the link
* List all manalinks you've created
* Support backend for claiming manalinks
* Add some more error handling
* Tweak readme
* Fix typescript breakage
* Revert "Convert common imports in functions to be absolute"
This reverts commit c03518e906
.
* Scaffolding so `claimManalink` works
* Clean up imports
* Barebones endpoint to claim mana
* Fix rules to only allow link creators to query
* Design out claim giftcard
* List all claimed transactions
* Style in a more awesome card
* Fix import
* Padding tweak
* Fix useManalinkTxns hook
* /send -> /link
* Tidy up some details
* Do a bunch of random manalinks work
* Fix up LinksTable to build
* Clean up LinksTable an absurd amount
* Basic details functionality on manalinks table
* Work on manalink claim stuff
* Fix up some merge mess
* Not-signed-in flow implemented
* Better manalinks table
* Only show outstanding links in table
* Use new `ManalinkTxn` type
* /link -> /links
* Change manalinks page UI to use nice looking tabs
* Many fixes to manalinks UI
* Default to 1 use
* Tidying up
* Some copy changes based on feedback
* Add required index
Co-authored-by: Marshall Polaris <marshall@pol.rs>
70 lines
1.9 KiB
TypeScript
70 lines
1.9 KiB
TypeScript
import clsx from 'clsx'
|
|
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'
|
|
|
|
export type ManalinkInfo = {
|
|
expiresTime: number | null
|
|
maxUses: number | null
|
|
uses: number
|
|
amount: number
|
|
message: string
|
|
}
|
|
|
|
export function ManalinkCard(props: {
|
|
className?: string
|
|
info: ManalinkInfo
|
|
defaultMessage: string
|
|
isClaiming: boolean
|
|
onClaim?: () => void
|
|
}) {
|
|
const { className, defaultMessage, isClaiming, info, onClaim } = props
|
|
const { expiresTime, maxUses, uses, amount, message } = info
|
|
return (
|
|
<div
|
|
className={clsx(
|
|
className,
|
|
'min-h-20 group flex flex-col rounded-xl bg-gradient-to-br from-indigo-200 via-indigo-400 to-indigo-800 shadow-lg transition-all'
|
|
)}
|
|
>
|
|
<Col className="mx-4 mt-2 -mb-4 text-right text-sm text-gray-100">
|
|
<div>
|
|
{maxUses != null
|
|
? `${maxUses - uses}/${maxUses} uses left`
|
|
: `Unlimited use`}
|
|
</div>
|
|
<div>
|
|
{expiresTime != null
|
|
? `Expires ${fromNow(expiresTime)}`
|
|
: 'Never expires'}
|
|
</div>
|
|
</Col>
|
|
|
|
<img
|
|
className="mb-6 block self-center transition-all group-hover:rotate-12"
|
|
src="/logo-white.svg"
|
|
width={200}
|
|
height={200}
|
|
/>
|
|
<Row className="justify-end rounded-b-xl bg-white p-4">
|
|
<Col>
|
|
<div className="mb-1 text-xl text-indigo-500">
|
|
{formatMoney(amount)}
|
|
</div>
|
|
<div>{message || defaultMessage}</div>
|
|
</Col>
|
|
|
|
<div className="ml-auto">
|
|
<button
|
|
className={clsx('btn', isClaiming ? 'loading disabled' : '')}
|
|
onClick={onClaim}
|
|
>
|
|
{isClaiming ? '' : 'Claim'}
|
|
</button>
|
|
</div>
|
|
</Row>
|
|
</div>
|
|
)
|
|
}
|