Skip to content

Commit

Permalink
feat(SPV-1005): added loading state, improved loading logic
Browse files Browse the repository at this point in the history
  • Loading branch information
Nazarii-4chain committed Sep 30, 2024
1 parent 2025b5d commit 5114b65
Show file tree
Hide file tree
Showing 15 changed files with 245 additions and 118 deletions.
22 changes: 13 additions & 9 deletions src/components/AddAccessKeyDialog/AddAccessKeyDialog.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,3 @@
import { Metadata } from '@bsv/spv-wallet-js-client';
import { QuestionMarkCircleIcon as Question } from '@heroicons/react/24/outline';
import { useMutation, useQueryClient } from '@tanstack/react-query';
import { CirclePlus } from 'lucide-react';
import React, { useState } from 'react';

import { toast } from 'sonner';

import {
Button,
Dialog,
Expand All @@ -14,6 +6,7 @@ import {
DialogTitle,
DialogTrigger,
Label,
LoadingSpinner,
Textarea,
Tooltip,
TooltipContent,
Expand All @@ -23,6 +16,13 @@ import {
import { useSpvWalletClient } from '@/contexts';

import { errorWrapper } from '@/utils';
import { Metadata } from '@bsv/spv-wallet-js-client';
import { QuestionMarkCircleIcon as Question } from '@heroicons/react/24/outline';
import { useMutation, useQueryClient } from '@tanstack/react-query';
import { CirclePlus } from 'lucide-react';
import React, { useState } from 'react';

import { toast } from 'sonner';

export interface AddAccessKeyDialogProps {
className?: string;
Expand Down Expand Up @@ -69,6 +69,8 @@ export const AddAccessKeyDialog = ({ className }: AddAccessKeyDialogProps) => {
}
};

const { isPending } = mutation;

return (
<Dialog open={isAddDialogOpen} onOpenChange={handleDialogOpen}>
<DialogTrigger asChild className={className}>
Expand Down Expand Up @@ -98,7 +100,9 @@ export const AddAccessKeyDialog = ({ className }: AddAccessKeyDialogProps) => {

<Textarea placeholder="Metadata" id="metadata" value={metadata} onChange={handleMetadataChange} />
<div className="grid grid-cols-2 gap-4">
<Button onClick={handleAdd}>Add</Button>
<Button onClick={handleAdd} disabled={isPending}>
Add {isPending && <LoadingSpinner className="ml-2" />}
</Button>
<Button variant="ghost" onClick={handleDialogOpen}>
Cancel
</Button>
Expand Down
21 changes: 13 additions & 8 deletions src/components/AddPaymailDialog/AddPaymailDialog.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,4 @@
import { HD } from '@bsv/sdk';
import { useMutation, useQueryClient } from '@tanstack/react-query';
import { CirclePlus } from 'lucide-react';

import React, { useState } from 'react';

import { toast } from 'sonner';
import { LoadingSpinner } from '@/components';

import { Button } from '@/components/ui';
import {
Expand All @@ -20,6 +14,13 @@ import { Input } from '@/components/ui/input.tsx';
import { Label } from '@/components/ui/label.tsx';
import { useSpvWalletClient } from '@/contexts';
import { errorWrapper } from '@/utils';
import { HD } from '@bsv/sdk';
import { useMutation, useQueryClient } from '@tanstack/react-query';
import { CirclePlus } from 'lucide-react';

import React, { useState } from 'react';

import { toast } from 'sonner';

interface AddPaymailDialogProps {
className?: string;
Expand Down Expand Up @@ -92,6 +93,8 @@ export const AddPaymailDialog = ({ className }: AddPaymailDialogProps) => {
errorWrapper(error);
}
};

const { isPending } = mutation;
return (
<Dialog>
<DialogTrigger asChild className={className}>
Expand Down Expand Up @@ -150,7 +153,9 @@ export const AddPaymailDialog = ({ className }: AddPaymailDialogProps) => {
</div>
</div>
<DialogFooter>
<Button onClick={onSubmit}>Add Paymail</Button>
<Button onClick={onSubmit} disabled={isPending}>
Add Paymail {isPending && <LoadingSpinner className="ml-2" />}
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
Expand Down
7 changes: 6 additions & 1 deletion src/components/AddXpubDialog/AddXpubDialog.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { LoadingSpinner } from '@/components';
import { Button } from '@/components/ui';
import {
Dialog,
Expand Down Expand Up @@ -147,6 +148,8 @@ export const AddXpubDialog = ({ className }: AddXpubDialogProps) => {
}
};

const { isPending } = mutation;

return (
<Dialog open={isOpen} onOpenChange={handeDialogToggle}>
<DialogTrigger asChild className={className}>
Expand Down Expand Up @@ -203,7 +206,9 @@ export const AddXpubDialog = ({ className }: AddXpubDialogProps) => {
name="xPub"
/>
<DialogFooter className="mt-4">
<Button type="submit">Add xPub</Button>
<Button type="submit" disabled={isPending}>
Add xPub {isPending && <LoadingSpinner className="ml-2" />}
</Button>
</DialogFooter>
</form>
</Form>
Expand Down
46 changes: 30 additions & 16 deletions src/components/ContactAcceptDialog/ContactAcceptDialog.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,4 @@
import { useQueryClient } from '@tanstack/react-query';
import { Row } from '@tanstack/react-table';
import { UserRoundCheck } from 'lucide-react';
import { useState } from 'react';

import { toast } from 'sonner';
import { LoadingSpinner } from '@/components';

import { Button } from '@/components/ui';
import {
Expand All @@ -18,6 +13,12 @@ import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/comp
import { useSpvWalletClient } from '@/contexts';
import { errorWrapper } from '@/utils';
import { Contact } from '@bsv/spv-wallet-js-client';
import { useMutation, useQueryClient } from '@tanstack/react-query';
import { Row } from '@tanstack/react-table';
import { UserRoundCheck } from 'lucide-react';
import { useState } from 'react';

import { toast } from 'sonner';

export interface ContactAcceptDialogProps {
row: Row<Contact>;
Expand All @@ -30,21 +31,32 @@ export const ContactAcceptDialog = ({ row }: ContactAcceptDialogProps) => {

const queryClient = useQueryClient();

const handleAcceptDialogOpen = () => {
setIsAcceptDialogOpen((prev) => !prev);
};

const handleAcceptContact = async () => {
try {
await spvWalletClient?.AdminAcceptContact(row.original.id);
const acceptContactMutation = useMutation({
mutationFn: async (id: string) => {
// At this point, spvWalletClient is defined; using non-null assertion.
return await spvWalletClient!.AdminAcceptContact(id);
},
onSuccess: async () => {
await queryClient.invalidateQueries();
setIsAcceptDialogOpen(false);
toast.success('Contact accepted');
} catch (err) {
},
onError: (err) => {
toast.error('Failed to accept contact');
errorWrapper(err);
}
},
});

const handleAcceptDialogOpen = () => {
setIsAcceptDialogOpen((prev) => !prev);
};

const handleAcceptContact = () => {
acceptContactMutation.mutate(row.original.id);
};

const { isPending } = acceptContactMutation;

return (
<Dialog open={isAcceptDialogOpen} onOpenChange={handleAcceptDialogOpen}>
<DialogTrigger>
Expand All @@ -68,7 +80,9 @@ export const ContactAcceptDialog = ({ row }: ContactAcceptDialogProps) => {
</DialogDescription>
</DialogHeader>
<div className="grid grid-cols-2 gap-4">
<Button onClick={handleAcceptContact}>Accept</Button>
<Button onClick={handleAcceptContact} disabled={isPending}>
Accept {isPending && <LoadingSpinner className="ml-2" />}
</Button>
<Button variant="outline" onClick={handleAcceptDialogOpen}>
Cancel
</Button>
Expand Down
36 changes: 23 additions & 13 deletions src/components/ContactDeleteDialog/ContactDeleteDialog.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
import { useQueryClient } from '@tanstack/react-query';
import { Row } from '@tanstack/react-table';
import { useState } from 'react';

import { toast } from 'sonner';
import { LoadingSpinner } from '@/components';

import { Button } from '@/components/ui';
import {
Expand All @@ -17,6 +13,11 @@ import { DropdownMenuItem } from '@/components/ui/dropdown-menu.tsx';
import { useSpvWalletClient } from '@/contexts';
import { errorWrapper } from '@/utils';
import { Contact } from '@bsv/spv-wallet-js-client';
import { useMutation, useQueryClient } from '@tanstack/react-query';
import { Row } from '@tanstack/react-table';
import { useState } from 'react';

import { toast } from 'sonner';

export interface ContactDeleteDialogProps {
row: Row<Contact>;
Expand All @@ -32,19 +33,28 @@ export const ContactDeleteDialog = ({ row }: ContactDeleteDialogProps) => {
setIsDeleteDialogOpen((prev) => !prev);
};

const handleDelete = async () => {
try {
await spvWalletClient?.AdminDeleteContact(row.original.id);
const deleteMutation = useMutation({
mutationFn: async (id: string) => {
// At this point, spvWalletClient is defined; using non-null assertion.
return await spvWalletClient!.AdminDeleteContact(id);
},
onSuccess: async () => {
await queryClient.invalidateQueries();

toast.success('Contact deleted');
setIsDeleteDialogOpen(false);
} catch (error) {
},
onError: (error) => {
toast.error('Failed to delete contact');
errorWrapper(error);
}
},
});

const handleDelete = () => {
deleteMutation.mutate(row.original.id);
};

const { isPending } = deleteMutation;

return (
<Dialog open={isDeleteDialogOpen} onOpenChange={handleDeleteDialogOpen}>
<DialogTrigger className="w-full">
Expand All @@ -56,8 +66,8 @@ export const ContactDeleteDialog = ({ row }: ContactDeleteDialogProps) => {
<DialogDescription>This action cannot be undone. Please confirm your decision to proceed.</DialogDescription>
</DialogHeader>
<div className="grid grid-cols-2 gap-4">
<Button variant="destructive" onClick={handleDelete}>
Delete
<Button variant="destructive" onClick={handleDelete} disabled={isPending}>
Delete {isPending && <LoadingSpinner className="ml-2" />}
</Button>
<Button variant="ghost" onClick={handleDeleteDialogOpen}>
Cancel
Expand Down
39 changes: 24 additions & 15 deletions src/components/ContactEditDialog/ContactEditDialog.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,3 @@
import { Contact, Metadata } from '@bsv/spv-wallet-js-client';
import { useQueryClient } from '@tanstack/react-query';
import { Row } from '@tanstack/react-table';
import React, { useState } from 'react';

import { toast } from 'sonner';

import {
Button,
Dialog,
Expand All @@ -15,10 +8,17 @@ import {
DropdownMenuItem,
Input,
Label,
LoadingSpinner,
Textarea,
} from '@/components';
import { useSpvWalletClient } from '@/contexts';
import { errorWrapper } from '@/utils';
import { Contact, Metadata } from '@bsv/spv-wallet-js-client';
import { useMutation, useQueryClient } from '@tanstack/react-query';
import { Row } from '@tanstack/react-table';
import React, { useState } from 'react';

import { toast } from 'sonner';

export interface ContactEditDialogProps {
row: Row<Contact>;
Expand All @@ -36,19 +36,24 @@ export const ContactEditDialog = ({ row }: ContactEditDialogProps) => {
setIsEditDialogOpen((prev) => !prev);
};

const handleEdit = async () => {
try {
const editMutation = useMutation({
mutationFn: async ({ id, fullName, metadata }: { id: string; fullName: string; metadata: string }) => {
const metadataParsed = JSON.parse(metadata) as Metadata;

await spvWalletClient?.AdminUpdateContact(row.original.id, fullName, metadataParsed);
return await spvWalletClient!.AdminUpdateContact(id, fullName, metadataParsed);
},
onSuccess: async () => {
await queryClient.invalidateQueries();

toast.success('Contact updated');
setIsEditDialogOpen(false);
} catch (error) {
},
onError: (error) => {
toast.error('Failed to update contact');
errorWrapper(error);
}
},
});

const handleEdit = () => {
editMutation.mutate({ id: row.original.id, fullName, metadata });
};

const handleFullNameChange = (e: React.ChangeEvent<HTMLInputElement>) => {
Expand All @@ -59,6 +64,8 @@ export const ContactEditDialog = ({ row }: ContactEditDialogProps) => {
setMetadata(e.target.value);
};

const { isPending } = editMutation;

return (
<Dialog open={isEditDialogOpen} onOpenChange={handleEditDialogOpen}>
<DialogTrigger className="w-full">
Expand All @@ -75,7 +82,9 @@ export const ContactEditDialog = ({ row }: ContactEditDialogProps) => {
<Label htmlFor="metadata">Metadata</Label>
<Textarea placeholder="Metadata" id="metadata" value={metadata} onChange={handleMetadataChange} />
<div className="grid grid-cols-2 gap-4">
<Button onClick={handleEdit}>Edit</Button>
<Button onClick={handleEdit} disabled={isPending}>
Edit {isPending && <LoadingSpinner className="ml-2" />}
</Button>
<Button variant="ghost" onClick={handleEditDialogOpen}>
Cancel
</Button>
Expand Down
Loading

0 comments on commit 5114b65

Please sign in to comment.