feat: invitations tips and confirm modal
This commit is contained in:
parent
7a5000f205
commit
c919e5907b
|
|
@ -3,9 +3,11 @@ import {
|
|||
AvatarFallback,
|
||||
AvatarImage,
|
||||
} from "@renderer/components/ui/avatar"
|
||||
import { Button, MotionButtonBase } from "@renderer/components/ui/button"
|
||||
import { Button } from "@renderer/components/ui/button"
|
||||
import { CopyButton } from "@renderer/components/ui/code-highlighter"
|
||||
import { Divider } from "@renderer/components/ui/divider"
|
||||
import { LoadingCircle } from "@renderer/components/ui/loading"
|
||||
import { useModalStack } from "@renderer/components/ui/modal"
|
||||
import { ScrollArea } from "@renderer/components/ui/scroll-area"
|
||||
import {
|
||||
Table,
|
||||
|
|
@ -46,121 +48,146 @@ export const SettingInvitations = () => {
|
|||
},
|
||||
})
|
||||
const presentUserProfile = usePresentUserProfileModal("drawer")
|
||||
const { present } = useModalStack()
|
||||
|
||||
return (
|
||||
<>
|
||||
<SettingsTitle />
|
||||
<div className="absolute inset-x-0 bottom-10 top-4 flex flex-col">
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<MotionButtonBase
|
||||
type="button"
|
||||
onClick={() => {
|
||||
newInvitation.mutate()
|
||||
}}
|
||||
className="center absolute bottom-0 right-2 z-10 size-10 rounded-full bg-accent text-white drop-shadow"
|
||||
>
|
||||
<i className="i-mingcute-user-add-2-line size-4" />
|
||||
</MotionButtonBase>
|
||||
</TooltipTrigger>
|
||||
|
||||
<TooltipContent>New invitation</TooltipContent>
|
||||
</Tooltip>
|
||||
<ScrollArea.ScrollArea
|
||||
scrollbarClassName="w-1"
|
||||
rootClassName="flex grow"
|
||||
>
|
||||
{invitations.data?.length ? (
|
||||
<Table className="mt-4">
|
||||
<TableHeader className="border-b">
|
||||
<TableRow className="[&_*]:!font-semibold">
|
||||
<TableHead className="w-16 text-center" size="sm">
|
||||
Code
|
||||
</TableHead>
|
||||
<TableHead className="text-center" size="sm">
|
||||
Creation Time
|
||||
</TableHead>
|
||||
<TableHead className="text-center" size="sm">
|
||||
Used by
|
||||
</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody className="border-t-[12px] border-transparent">
|
||||
{invitations.data?.map((row) => (
|
||||
<TableRow key={row.code}>
|
||||
<TableCell align="center" size="sm">
|
||||
<div className="group relative flex items-center justify-center gap-2 font-mono">
|
||||
<span>{row.code}</span>
|
||||
<CopyButton
|
||||
value={row.code}
|
||||
className="absolute -right-6 p-1 opacity-0 group-hover:opacity-100 [&_i]:size-3"
|
||||
/>
|
||||
</div>
|
||||
</TableCell>
|
||||
<TableCell
|
||||
align="center"
|
||||
className="tabular-nums"
|
||||
size="sm"
|
||||
>
|
||||
{row.createdAt &&
|
||||
new Date(row.createdAt).toLocaleString()}
|
||||
</TableCell>
|
||||
<TableCell align="center" size="sm">
|
||||
{row.users ? (
|
||||
<Tooltip>
|
||||
<TooltipTrigger>
|
||||
<button
|
||||
type="button"
|
||||
className="cursor-pointer"
|
||||
onClick={() => {
|
||||
presentUserProfile(row.users?.id)
|
||||
}}
|
||||
>
|
||||
<Avatar className="aspect-square size-5 border border-border ring-1 ring-background">
|
||||
<AvatarImage
|
||||
src={row.users?.image || undefined}
|
||||
/>
|
||||
<AvatarFallback>
|
||||
{row.users?.name?.slice(0, 2)}
|
||||
</AvatarFallback>
|
||||
</Avatar>
|
||||
</button>
|
||||
</TooltipTrigger>
|
||||
{row.users?.name && (
|
||||
<TooltipPortal>
|
||||
<TooltipContent>{row.users?.name}</TooltipContent>
|
||||
</TooltipPortal>
|
||||
)}
|
||||
</Tooltip>
|
||||
) : (
|
||||
"Not used"
|
||||
)}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
) : invitations.isLoading ?
|
||||
(
|
||||
<LoadingCircle size="large" className="center absolute inset-0" />
|
||||
) :
|
||||
(
|
||||
<div className="mt-36 w-full text-center text-sm text-zinc-400">
|
||||
<p>No invitations</p>
|
||||
|
||||
<div className="mt-6">
|
||||
<section className="mt-4">
|
||||
<div className="mb-4 space-y-2 text-sm">
|
||||
<p>
|
||||
Follow is currently in
|
||||
{" "}
|
||||
<strong>early access</strong>
|
||||
{" "}
|
||||
and
|
||||
requires an invitation code to use.
|
||||
</p>
|
||||
<p className="flex items-center"><span>You can spend 10 </span><i className="i-mgc-power ml-1 mr-0.5 text-base" /><span> Power to generate an invitation code for your friends.</span></p>
|
||||
</div>
|
||||
<Button
|
||||
onClick={() => {
|
||||
present({
|
||||
title: "Confirm",
|
||||
content: ({ dismiss }) => (
|
||||
<>
|
||||
<div className="flex items-center">
|
||||
<span>Generating an invitation code will cost you 10 </span><i className="i-mgc-power mx-1 text-base" /><span>Power. Are you sure you want to continue?</span>
|
||||
</div>
|
||||
<div className="mt-4 flex items-center justify-end gap-3">
|
||||
<Button variant="outline" onClick={dismiss}>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => {
|
||||
newInvitation.mutate()
|
||||
}}
|
||||
isLoading={newInvitation.isPending}
|
||||
onClick={() => newInvitation.mutateAsync().then(() => dismiss())}
|
||||
>
|
||||
Create Invitation
|
||||
Continue
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</ScrollArea.ScrollArea>
|
||||
</div>
|
||||
</>
|
||||
),
|
||||
})
|
||||
}}
|
||||
>
|
||||
<i className="i-mgc-heart-hand-cute-re mr-1" />
|
||||
Generate new code
|
||||
</Button>
|
||||
<Divider className="mb-6 mt-8" />
|
||||
<div className="flex flex-1 flex-col">
|
||||
<ScrollArea.ScrollArea viewportClassName="max-h-[380px]">
|
||||
{invitations.data?.length ? (
|
||||
<Table className="mt-4">
|
||||
<TableHeader className="border-b">
|
||||
<TableRow className="[&_*]:!font-semibold">
|
||||
<TableHead className="w-16 text-center" size="sm">
|
||||
Code
|
||||
</TableHead>
|
||||
<TableHead className="text-center" size="sm">
|
||||
Creation Time
|
||||
</TableHead>
|
||||
<TableHead className="text-center" size="sm">
|
||||
Used by
|
||||
</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody className="border-t-[12px] border-transparent">
|
||||
{invitations.data?.map((row) => (
|
||||
<TableRow key={row.code}>
|
||||
<TableCell align="center" size="sm">
|
||||
<div className="group relative flex items-center justify-center gap-2 font-mono">
|
||||
<span>{row.code}</span>
|
||||
<CopyButton
|
||||
value={row.code}
|
||||
className="absolute -right-6 p-1 opacity-0 group-hover:opacity-100 [&_i]:size-3"
|
||||
/>
|
||||
</div>
|
||||
</TableCell>
|
||||
<TableCell
|
||||
align="center"
|
||||
className="tabular-nums"
|
||||
size="sm"
|
||||
>
|
||||
{row.createdAt &&
|
||||
new Date(row.createdAt).toLocaleString()}
|
||||
</TableCell>
|
||||
<TableCell align="center" size="sm">
|
||||
{row.users ? (
|
||||
<Tooltip>
|
||||
<TooltipTrigger>
|
||||
<button
|
||||
type="button"
|
||||
className="cursor-pointer"
|
||||
onClick={() => {
|
||||
presentUserProfile(row.users?.id)
|
||||
}}
|
||||
>
|
||||
<Avatar className="aspect-square size-5 border border-border ring-1 ring-background">
|
||||
<AvatarImage
|
||||
src={row.users?.image || undefined}
|
||||
/>
|
||||
<AvatarFallback>
|
||||
{row.users?.name?.slice(0, 2)}
|
||||
</AvatarFallback>
|
||||
</Avatar>
|
||||
</button>
|
||||
</TooltipTrigger>
|
||||
{row.users?.name && (
|
||||
<TooltipPortal>
|
||||
<TooltipContent>{row.users?.name}</TooltipContent>
|
||||
</TooltipPortal>
|
||||
)}
|
||||
</Tooltip>
|
||||
) : (
|
||||
"Not used"
|
||||
)}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
) : invitations.isLoading ?
|
||||
(
|
||||
<LoadingCircle size="large" className="center absolute inset-0" />
|
||||
) :
|
||||
(
|
||||
<div className="mt-36 w-full text-center text-sm text-zinc-400">
|
||||
<p>No invitations</p>
|
||||
|
||||
<div className="mt-6">
|
||||
<Button
|
||||
onClick={() => {
|
||||
newInvitation.mutate()
|
||||
}}
|
||||
>
|
||||
Create Invitation
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</ScrollArea.ScrollArea>
|
||||
</div>
|
||||
</section>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
import { Divider } from "@renderer/components/ui/divider"
|
||||
|
||||
import { SettingsTitle } from "../../title"
|
||||
import { MyWalletSection } from "./my-wallet-section"
|
||||
import { TransactionsSection } from "./transaction-section"
|
||||
|
|
@ -8,6 +10,8 @@ export const SettingWallet = () => (
|
|||
|
||||
<MyWalletSection />
|
||||
|
||||
<Divider className="my-8" />
|
||||
|
||||
<TransactionsSection />
|
||||
</div>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import {
|
|||
import { MotionButtonBase } from "@renderer/components/ui/button"
|
||||
import { RelativeTime } from "@renderer/components/ui/datetime"
|
||||
import { LoadingCircle } from "@renderer/components/ui/loading"
|
||||
import { ScrollArea } from "@renderer/components/ui/scroll-area"
|
||||
import {
|
||||
Table,
|
||||
TableBody,
|
||||
|
|
@ -45,7 +46,7 @@ export const TransactionsSection = () => {
|
|||
<div className="mt-8">
|
||||
<SettingSectionTitle title="Transactions" />
|
||||
|
||||
<div className="overflow-x-auto">
|
||||
<ScrollArea.ScrollArea viewportClassName="max-h-[210px]">
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow className="[&_*]:!font-semibold">
|
||||
|
|
@ -97,7 +98,7 @@ export const TransactionsSection = () => {
|
|||
No transactions
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</ScrollArea.ScrollArea>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue