Skip to content

Commit

Permalink
feature(unlock-app): Improve attendees UX (#15525)
Browse files Browse the repository at this point in the history
* update applicant info component

* update attendees info component

* update members component

* update attendees component

* add selection context

* update members component

* update applicants info component

* update attendees action to ue context

* update attendees component

* cleanup
  • Loading branch information
0xTxbi authored Feb 13, 2025
1 parent 16d918a commit 3044efe
Show file tree
Hide file tree
Showing 6 changed files with 478 additions and 515 deletions.
224 changes: 103 additions & 121 deletions unlock-app/src/components/content/event/attendees/ApplicantInfo.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
import { Button, Detail, Checkbox } from '@unlock-protocol/ui'
import { useEffect, useState } from 'react'
import useEns from '~/hooks/useEns'
import { addressMinify } from '~/utils/strings'
import { BiCopy as CopyIcon } from 'react-icons/bi'
import useClipboard from 'react-use-clipboard'
import { ToastHelper } from '~/components/helpers/toast.helper'
import React, { useState, useCallback } from 'react'
import { ApproveAttendeeModal } from './ApproveAttendeeModal'
import { DenyAttendeeModal } from './DenyAttendeeModal'
import { WrappedAddress } from '~/components/interface/WrappedAddress'
import { useSelection } from './SelectionContext'

interface ApplicantInfoProps {
network: number
Expand All @@ -17,127 +14,112 @@ interface ApplicantInfoProps {
setIsSelected: (selected: boolean) => void
}

export const ApplicantInfo = ({
network,
lockAddress,
owner,
metadata,
setIsSelected,
isSelected,
}: ApplicantInfoProps) => {
const [approveAttendeeModalOpen, setApproveAttendeeModalOpen] =
useState(false)
const [denyAttendeeModalOpen, setDenyAttendeeModalOpen] = useState(false)
const addressToEns = useEns(owner)
const resolvedAddress =
addressToEns === owner ? addressMinify(owner) : addressToEns
const addressToCopy = addressToEns === owner ? owner : addressToEns
export const ApplicantInfo = React.memo(
({
network,
lockAddress,
owner,
metadata,
}: Omit<ApplicantInfoProps, 'isSelected' | 'setIsSelected'>) => {
const { isSelected, toggleSelection } = useSelection()
const [approveAttendeeModalOpen, setApproveAttendeeModalOpen] =
useState(false)
const [denyAttendeeModalOpen, setDenyAttendeeModalOpen] = useState(false)

const [isCopied, setCopied] = useClipboard(addressToCopy, {
successDuration: 2000,
})
const handleCheckboxChange = useCallback(() => {
toggleSelection(owner)
}, [owner, toggleSelection])

useEffect(() => {
if (!isCopied) return
ToastHelper.success('Address copied')
}, [isCopied])
// Get the current checked state for this owner
const checked = isSelected(owner)

return (
<>
<ApproveAttendeeModal
network={network}
isOpen={approveAttendeeModalOpen}
setIsOpen={setApproveAttendeeModalOpen}
lockAddress={lockAddress}
attendees={[
{
keyholderAddress: owner,
...metadata,
},
]}
/>
<DenyAttendeeModal
network={network}
isOpen={denyAttendeeModalOpen}
setIsOpen={setDenyAttendeeModalOpen}
lockAddress={lockAddress}
attendees={[
{
keyholderAddress: owner,
...metadata,
},
]}
/>
return (
<>
<ApproveAttendeeModal
network={network}
isOpen={approveAttendeeModalOpen}
setIsOpen={setApproveAttendeeModalOpen}
lockAddress={lockAddress}
attendees={[
{
keyholderAddress: owner,
...metadata,
},
]}
/>
<DenyAttendeeModal
network={network}
isOpen={denyAttendeeModalOpen}
setIsOpen={setDenyAttendeeModalOpen}
lockAddress={lockAddress}
attendees={[
{
keyholderAddress: owner,
...metadata,
},
]}
/>

<div className="flex md:flex-row flex-col gap-4 space-between w-full group relative">
<div className="flex items-start pt-2 md:pt-1 mr-auto md:ml-2">
<Checkbox
label=" "
checked={isSelected}
onChange={(event: any) => {
setIsSelected(event.target.checked)
}}
/>
</div>
<Detail
label="Full Name"
valueSize="medium"
className="w-full overflow-auto min-w-24"
>
{metadata.fullname}
</Detail>
<div className="flex md:flex-row flex-col gap-4 space-between w-full group relative">
<div className="flex items-start pt-2 md:pt-1 mr-auto md:ml-2">
<Checkbox
label=" "
onChange={handleCheckboxChange}
checked={checked}
/>
</div>
<Detail
label="Full Name"
valueSize="medium"
className="w-full overflow-auto min-w-24"
>
{metadata.fullname}
</Detail>

<Detail
label="Email"
valueSize="medium"
className="w-full overflow-auto min-w-24"
>
{metadata.email}
</Detail>
<Detail
label="Email"
valueSize="medium"
className="w-full overflow-auto min-w-24"
>
{metadata.email}
</Detail>

<Detail
label="Wallet"
valueSize="medium"
className="w-full overflow-auto"
>
<div className="flex self-start gap-2">
<div>{resolvedAddress}</div>
<div className="mt-auto">
<Button
variant="borderless"
onClick={setCopied}
aria-label="copy"
>
<CopyIcon size={20} />
</Button>
</div>
</div>
</Detail>
<Detail
label="Wallet"
valueSize="medium"
className="w-full overflow-auto"
>
<WrappedAddress address={owner} showExternalLink={false} />
</Detail>

<div className="md:hidden group-hover:flex absolute top-0 right-0">
<div className="gap-2 flex flex-col ">
{metadata.approval !== 'approved' && (
<Button
size="tiny"
onClick={() => setApproveAttendeeModalOpen(true)}
className="w-full"
>
Approve
</Button>
)}
{metadata.approval !== 'denied' && (
<Button
variant="secondary"
size="tiny"
onClick={() => setDenyAttendeeModalOpen(true)}
className="w-full"
>
Deny
</Button>
)}
<div className="md:hidden group-hover:flex absolute top-0 right-0">
<div className="gap-2 flex flex-col ">
{metadata.approval !== 'approved' && (
<Button
size="tiny"
onClick={() => setApproveAttendeeModalOpen(true)}
className="w-full"
>
Approve
</Button>
)}
{metadata.approval !== 'denied' && (
<Button
variant="secondary"
size="tiny"
onClick={() => setDenyAttendeeModalOpen(true)}
className="w-full"
>
Deny
</Button>
)}
</div>
</div>
</div>
</div>
</>
)
}
</>
)
}
)

ApplicantInfo.displayName = 'ApplicantInfo'
export default ApplicantInfo
27 changes: 2 additions & 25 deletions unlock-app/src/components/content/event/attendees/AttendeeInfo.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
import { Button, Detail } from '@unlock-protocol/ui'
import { useEffect, useState } from 'react'
import { useState } from 'react'
import { ExpireAndRefundModal } from '~/components/interface/ExpireAndRefundModal'
import useEns from '~/hooks/useEns'
import { addressMinify } from '~/utils/strings'
import { BiCopy as CopyIcon } from 'react-icons/bi'
import useClipboard from 'react-use-clipboard'
import { ToastHelper } from '~/components/helpers/toast.helper'
import { Metadata } from '@unlock-protocol/core'

interface AttendeeInfoProps {
Expand All @@ -25,20 +21,6 @@ export const AttendeeInfo = ({
}: AttendeeInfoProps) => {
const [expireAndRefundOpen, setExpireAndRefundOpen] = useState(false)

const addressToEns = useEns(owner)
const resolvedAddress =
addressToEns === owner ? addressMinify(owner) : addressToEns
const addressToCopy = addressToEns === owner ? owner : addressToEns

const [isCopied, setCopied] = useClipboard(addressToCopy, {
successDuration: 2000,
})

useEffect(() => {
if (!isCopied) return
ToastHelper.success('Address copied')
}, [isCopied])

return (
<>
<ExpireAndRefundModal
Expand Down Expand Up @@ -81,13 +63,8 @@ export const AttendeeInfo = ({
className="w-full overflow-auto min-w-24"
>
<div className="flex self-start gap-2">
<div>{resolvedAddress}</div>
<div className="mt-auto">
<Button
variant="borderless"
onClick={setCopied}
aria-label="copy"
>
<Button variant="borderless" aria-label="copy">
<CopyIcon size={20} />
</Button>
</div>
Expand Down
Loading

0 comments on commit 3044efe

Please sign in to comment.