-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathcontact-list-react.tsx
More file actions
126 lines (122 loc) · 3.63 KB
/
contact-list-react.tsx
File metadata and controls
126 lines (122 loc) · 3.63 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
import { Button, Theme } from '@radix-ui/themes';
import '@radix-ui/themes/styles.css';
import {
SingleTableInputViewComponent,
TextInputComponent,
} from '@reactlit/radix';
import {
QueryClient,
QueryClientProvider,
useMutation,
useQuery,
useQueryClient,
} from '@tanstack/react-query';
import { useEffect, useMemo, useState } from 'react';
import { TopRightLoader } from './components/loader';
import { ContactsMockService, type Contact } from './mocks/contacts';
const api = new ContactsMockService([], 1000);
const queryClient = new QueryClient();
export default function ContactList() {
return (
<QueryClientProvider client={queryClient}>
<Theme
style={{
position: 'relative',
}}
className="not-content"
data-is-root-theme={false}
>
<ContactListApp />
</Theme>
</QueryClientProvider>
);
}
function ContactListApp() {
const [name, setName] = useState('');
const [email, setEmail] = useState('');
const client = useQueryClient();
const { data: contacts, isFetching } = useQuery({
queryKey: ['contacts'],
queryFn: () => api.getContacts(),
});
const { mutateAsync: addContact, isPending: addingContact } = useMutation({
mutationFn: async () => await api.addContact(),
onSuccess: async (newContact) => {
await client.invalidateQueries({ queryKey: ['contacts'] });
setSelectedContactId(newContact.id);
},
});
const { mutateAsync: updateContact, isPending: updatingContact } =
useMutation({
mutationFn: (contact: Contact) => api.updateContact(contact.id, contact),
onSuccess: (data) => {
client.setQueryData(['contacts'], (contacts: Contact[]) =>
contacts.map((c) => (c.id === data.id ? data : c))
);
},
});
const [selectedContactId, setSelectedContactId] = useState<
string | undefined
>();
const selectedContact = useMemo(
() => contacts?.find((c) => c.id === selectedContactId),
[contacts, selectedContactId]
);
useEffect(() => {
if (selectedContact) {
setName(selectedContact.name);
setEmail(selectedContact.email);
}
}, [selectedContact, setName, setEmail]);
return (
<div>
{isFetching && <TopRightLoader text="Loading Contacts..." />}
{!isFetching && addingContact && (
<TopRightLoader text="Adding new contact..." />
)}
{!isFetching && updatingContact && (
<TopRightLoader text="Updating contact..." />
)}
<Button onClick={() => addContact()}>Add Contact</Button>
<SingleTableInputViewComponent
stateKey="selectedContact"
data={contacts ?? []}
columns={['name', 'email']}
value={selectedContactId}
setValue={(id) => setSelectedContactId(id)}
getRowId={(c) => c.id}
display={() => {}}
view={() => undefined as any}
/>
{selectedContact && (
<>
<h3 style={{ paddingTop: '1rem' }}>Selected Contact Details</h3>
<TextInputComponent
stateKey="name"
label="Name"
value={name}
setValue={setName}
display={() => {}}
view={() => undefined as any}
/>
<TextInputComponent
stateKey="email"
label="Email"
value={email}
setValue={setEmail}
display={() => {}}
view={() => undefined as any}
/>
<Button
disabled={isFetching}
onClick={() =>
updateContact({ name, email, id: selectedContact.id })
}
>
Update
</Button>
</>
)}
</div>
);
}