Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 29 additions & 67 deletions src/components/AccessKeysColumns/AccessKeysColumnsMobile.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from '@/components/ui/accordion';
import { AccordionContent, AccordionItem, AccordionTrigger } from '@/components/ui/accordion';
import { Badge } from '@/components/ui/badge';
import { toast } from 'sonner';
import { Button } from '@/components/ui/button';
import { EllipsisVertical, ChevronDown, ChevronUp } from 'lucide-react';
import { EllipsisVertical } from 'lucide-react';
import {
DropdownMenu,
DropdownMenuContent,
Expand All @@ -12,14 +12,13 @@ import {
} from '@/components/ui/dropdown-menu';
import { ViewDialogMobile } from '@/components/ViewDialog/ViewDialogMobile';
import { RevokeKeyDialog } from '@/components';
import { useState } from 'react';
import { Row } from '@tanstack/react-table';
import { getCoreRowModel, getPaginationRowModel, getSortedRowModel, useReactTable } from '@tanstack/react-table';
import { MobileDataTablePagination } from '@/components/DataTable/MobileDataTablePagination';
import { MobileDataTable } from '@/components/DataTable/MobileDataTable';
import { AccessKeysColumns } from './AccessKeysColumns';
import { useIsUser } from '@/store/clientStore';
import { truncateId } from '@/utils/string';
import { createToggleExpandAll } from '@/utils/expandUtils';
import { PaginationProps } from '../DataTable/DataTable';
import { AccessKey } from '@bsv/spv-wallet-js-client';

const onClickCopy = (value: string, label: string) => async () => {
if (!value) {
Expand All @@ -31,6 +30,7 @@ const onClickCopy = (value: string, label: string) => async () => {

interface AccessKeyMobileItemProps {
accessKey: AccessKeysColumns;
expandedState: { expandedItems: string[]; setExpandedItems: (value: string[]) => void };
}

export const AccessKeyMobileItem = ({ accessKey }: AccessKeyMobileItemProps) => {
Expand All @@ -55,10 +55,10 @@ export const AccessKeyMobileItem = ({ accessKey }: AccessKeyMobileItemProps) =>
}
};

const mobileRow: Row<AccessKeysColumns> = {
const mobileRow = {
original: accessKey,
getValue: (key: string) => (key === 'status' ? accessKey.status : undefined),
} as Row<AccessKeysColumns>;
} as unknown as Row<AccessKey>;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this necessary ? (The unknown casting)


return (
<AccordionItem value={accessKey.id} className="px-2">
Expand All @@ -69,7 +69,7 @@ export const AccessKeyMobileItem = ({ accessKey }: AccessKeyMobileItemProps) =>
<span className="shrink-0">ID:</span>
<span className="truncate">{truncateId(accessKey.id)}</span>
</p>
<p className="text-sm text-muted-foreground">{getStatusBadge()}</p>
<div className="text-sm text-muted-foreground">{getStatusBadge()}</div>
</div>
</div>
</AccordionTrigger>
Expand Down Expand Up @@ -123,66 +123,28 @@ export const AccessKeyMobileItem = ({ accessKey }: AccessKeyMobileItemProps) =>

export interface AccessKeysMobileListProps {
accessKeys: AccessKeysColumns[];
value?: string[];
onValueChange?: (value: string[]) => void;
pagination?: PaginationProps;
}

export const AccessKeysMobileList = ({ accessKeys, value, onValueChange }: AccessKeysMobileListProps) => {
const [expandedItems, setExpandedItems] = useState<string[]>(value || []);
const [isAllExpanded, setIsAllExpanded] = useState(false);

const table = useReactTable({
data: accessKeys,
columns: [],
getCoreRowModel: getCoreRowModel(),
getPaginationRowModel: getPaginationRowModel(),
getSortedRowModel: getSortedRowModel(),
});

const currentPageData = table.getRowModel().rows.map((row) => row.original);

const toggleExpandAll = () => {
createToggleExpandAll(
currentPageData,
isAllExpanded,
(ids) => {
setExpandedItems(ids);
onValueChange?.(ids);
},
setIsAllExpanded,
(accessKey) => accessKey.id,
);
};

const handleValueChange = (newValue: string[]) => {
setExpandedItems(newValue);
onValueChange?.(newValue);
setIsAllExpanded(newValue.length === currentPageData.length);
};

export const AccessKeysMobileList = ({ accessKeys, pagination }: AccessKeysMobileListProps) => {
// Use the MobileDataTable component to handle pagination
return (
<div className="rounded-md border">
<div className="p-2 border-b">
<Button variant="ghost" onClick={toggleExpandAll} className="w-full flex items-center justify-center gap-2">
{isAllExpanded ? (
<>
<ChevronUp className="h-4 w-4" /> Collapse All
</>
) : (
<>
<ChevronDown className="h-4 w-4" /> Expand All
</>
)}
</Button>
</div>
<div className="p-1">
<Accordion type="multiple" value={expandedItems} onValueChange={handleValueChange} className="w-full">
{currentPageData.map((accessKey) => (
<AccessKeyMobileItem key={accessKey.id} accessKey={accessKey} />
))}
</Accordion>
</div>
<MobileDataTablePagination table={table} />
</div>
<MobileDataTable
columns={[
{
accessorKey: 'id',
header: 'ID',
},
]}
data={accessKeys}
renderMobileItem={(accessKey, expandedState) => (
<AccessKeyMobileItem
key={accessKey.id}
accessKey={accessKey as AccessKeysColumns}
expandedState={expandedState}
/>
)}
pagination={pagination}
/>
);
};
7 changes: 5 additions & 2 deletions src/components/AccessKeysTabContent/AccessKeysTabContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,15 @@ import {
} from '@/components';
import { AccessKeysMobileList } from '@/components/AccessKeysColumns/AccessKeysColumnsMobile';
import { AccessKeyExtended } from '@/interfaces';
import { PaginationProps } from '@/components/DataTable/DataTable';

export interface AccessKeysTabContentProps {
accessKeys: AccessKeyExtended[];
hasRevokeKeyDialog?: boolean;
pagination?: PaginationProps;
}

export const AccessKeysTabContent = ({ accessKeys, hasRevokeKeyDialog }: AccessKeysTabContentProps) => {
export const AccessKeysTabContent = ({ accessKeys, hasRevokeKeyDialog, pagination }: AccessKeysTabContentProps) => {
return (
<Card>
<CardHeader>
Expand All @@ -36,10 +38,11 @@ export const AccessKeysTabContent = ({ accessKeys, hasRevokeKeyDialog }: AccessK
{hasRevokeKeyDialog && <RevokeKeyDialog row={row} />}
</>
)}
pagination={pagination}
/>
</div>
<div className="sm:hidden">
<AccessKeysMobileList accessKeys={accessKeys} />
<AccessKeysMobileList accessKeys={accessKeys} pagination={pagination} />
</div>
</>
) : (
Expand Down
2 changes: 2 additions & 0 deletions src/components/AddAccessKeyDialog/AddAccessKeyDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
TooltipContent,
TooltipProvider,
TooltipTrigger,
DialogDescription,
} from '@/components';
import { errorWrapper } from '@/utils';
import { Metadata } from '@bsv/spv-wallet-js-client';
Expand Down Expand Up @@ -136,6 +137,7 @@ export const AddAccessKeyDialog = ({ className }: AddAccessKeyDialogProps) => {
<>
<DialogHeader>
<DialogTitle>Add Access Key</DialogTitle>
<DialogDescription>Create a new access key for your account</DialogDescription>
</DialogHeader>

<div className="flex">
Expand Down
2 changes: 2 additions & 0 deletions src/components/ContactEditDialog/ContactEditDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
Label,
LoadingSpinner,
Textarea,
DialogDescription,
} from '@/components';
import { errorWrapper } from '@/utils';
import { Contact, Metadata } from '@bsv/spv-wallet-js-client';
Expand Down Expand Up @@ -76,6 +77,7 @@ export const ContactEditDialog = ({ row }: ContactEditDialogProps) => {
<DialogContent>
<DialogHeader>
<DialogTitle>Edit Contact Information</DialogTitle>
<DialogDescription>Update the details for this contact</DialogDescription>
</DialogHeader>
<Label htmlFor="fullName">Full Name</Label>
<Input placeholder="Full Name" id="fullName" value={fullName} onChange={handleFullNameChange} />
Expand Down
87 changes: 22 additions & 65 deletions src/components/ContactsColumns/ContactsColumnsMobile.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { Contact } from '@bsv/spv-wallet-js-client';
import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from '@/components/ui/accordion';
import { AccordionContent, AccordionItem, AccordionTrigger } from '@/components/ui/accordion';
import { Badge } from '@/components/ui/badge';
import { toast } from 'sonner';
import { ContactStatus } from './ContactsColumns';
import { ContactAcceptDialog, ContactRejectDialog, ContactEditDialog, ContactDeleteDialog } from '@/components';
import { Button } from '@/components/ui/button';
import { EllipsisVertical, ChevronDown, ChevronUp } from 'lucide-react';
import { EllipsisVertical } from 'lucide-react';
import {
DropdownMenu,
DropdownMenuContent,
Expand All @@ -14,12 +14,10 @@ import {
DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu';
import { ViewDialogMobile } from '@/components/ViewDialog/ViewDialogMobile';
import { useState } from 'react';
import { Row } from '@tanstack/react-table';
import { getCoreRowModel, getPaginationRowModel, getSortedRowModel, useReactTable } from '@tanstack/react-table';
import { MobileDataTablePagination } from '@/components/DataTable/MobileDataTablePagination';
import { truncateId } from '@/utils/string';
import { createToggleExpandAll } from '@/utils/expandUtils';
import { MobileDataTable } from '@/components/DataTable/MobileDataTable';
import { PaginationProps } from '@/components/DataTable/DataTable';

const onClickCopy = (value: string, label: string) => async () => {
if (!value) {
Expand All @@ -31,6 +29,7 @@ const onClickCopy = (value: string, label: string) => async () => {

interface ContactMobileItemProps {
contact: Contact;
expandedState?: { expandedItems: string[]; setExpandedItems: (value: string[]) => void };
}

export const ContactMobileItem = ({ contact }: ContactMobileItemProps) => {
Expand Down Expand Up @@ -74,7 +73,7 @@ export const ContactMobileItem = ({ contact }: ContactMobileItemProps) => {
<span className="shrink-0">Name:</span>
<span className="truncate">{truncateId(contact.paymail)}</span>
</p>
<p className="text-sm text-muted-foreground">{getStatusBadge()}</p>
<div className="text-sm text-muted-foreground">{getStatusBadge()}</div>
</div>
</div>
</AccordionTrigger>
Expand Down Expand Up @@ -147,66 +146,24 @@ export const ContactMobileItem = ({ contact }: ContactMobileItemProps) => {

export interface ContactsMobileListProps {
contacts: Contact[];
value?: string[];
onValueChange?: (value: string[]) => void;
pagination?: PaginationProps;
}

export const ContactsMobileList = ({ contacts, value, onValueChange }: ContactsMobileListProps) => {
const [expandedItems, setExpandedItems] = useState<string[]>(value || []);
const [isAllExpanded, setIsAllExpanded] = useState(false);

const table = useReactTable({
data: contacts,
columns: [],
getCoreRowModel: getCoreRowModel(),
getPaginationRowModel: getPaginationRowModel(),
getSortedRowModel: getSortedRowModel(),
});

const currentPageData = table.getRowModel().rows.map((row) => row.original);

const toggleExpandAll = () => {
createToggleExpandAll(
currentPageData,
isAllExpanded,
(ids) => {
setExpandedItems(ids);
onValueChange?.(ids);
},
setIsAllExpanded,
(contact) => contact.id,
);
};

const handleValueChange = (newValue: string[]) => {
setExpandedItems(newValue);
onValueChange?.(newValue);
setIsAllExpanded(newValue.length === currentPageData.length);
};

export const ContactsMobileList = ({ contacts, pagination }: ContactsMobileListProps) => {
// Use MobileDataTable for pagination support
return (
<div className="rounded-md border">
<div className="p-2 border-b">
<Button variant="ghost" onClick={toggleExpandAll} className="w-full flex items-center justify-center gap-2">
{isAllExpanded ? (
<>
<ChevronUp className="h-4 w-4" /> Collapse All
</>
) : (
<>
<ChevronDown className="h-4 w-4" /> Expand All
</>
)}
</Button>
</div>
<div className="p-1">
<Accordion type="multiple" value={expandedItems} onValueChange={handleValueChange} className="w-full">
{currentPageData.map((contact) => (
<ContactMobileItem key={contact.id} contact={contact} />
))}
</Accordion>
</div>
<MobileDataTablePagination table={table} />
</div>
<MobileDataTable
data={contacts}
columns={[
{
accessorKey: 'id',
header: 'ID',
},
]}
renderMobileItem={(item: Contact, expandedState) => (
<ContactMobileItem contact={item} expandedState={expandedState} />
)}
pagination={pagination}
/>
);
};
29 changes: 6 additions & 23 deletions src/components/ContactsTabContent/ContactsTabContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,36 +16,18 @@ import {
import { ContactsMobileList } from '@/components/ContactsColumns/ContactsColumnsMobile';
import { ContactExtended } from '@/interfaces/contacts.ts';
import { useState } from 'react';
import { PaginationProps } from '@/components/DataTable/DataTable';

export interface ContactsTabContentProps {
contacts: ContactExtended[];
pagination?: PaginationProps;
}

export const ContactsTabContent = ({ contacts }: ContactsTabContentProps) => {
const [currentTab] = useState('all');
export const ContactsTabContent = ({ contacts, pagination }: ContactsTabContentProps) => {
const [searchQuery] = useState('');

const filteredContacts = contacts.filter((contact) => {
// First apply status filter
if (currentTab !== 'all') {
if (currentTab === 'unconfirmed' && contact.status !== ContactStatus.Unconfirmed) {
return false;
}
if (currentTab === 'awaiting' && contact.status !== ContactStatus.Awaiting) {
return false;
}
if (currentTab === 'confirmed' && contact.status !== ContactStatus.Confirmed) {
return false;
}
if (currentTab === 'rejected' && contact.status !== ContactStatus.Rejected) {
return false;
}
if (currentTab === 'deleted' && !contact.deletedAt) {
return false;
}
}

// Then apply search filter
// Apply search filter
if (searchQuery) {
const searchLower = searchQuery.toLowerCase();
return (
Expand Down Expand Up @@ -88,10 +70,11 @@ export const ContactsTabContent = ({ contacts }: ContactsTabContentProps) => {
{row.original.deletedAt == null && <ContactDeleteDialog row={row} />}
</>
)}
pagination={pagination}
/>
</div>
<div className="sm:hidden">
<ContactsMobileList contacts={filteredContacts} />
<ContactsMobileList contacts={filteredContacts} pagination={pagination} />
</div>
</>
) : (
Expand Down
Loading