Skip to content

Commit 7128cfa

Browse files
committed
feat: add Select component and Textarea component, update routing for sending messages page
1 parent d7e39b2 commit 7128cfa

File tree

8 files changed

+1189
-1122
lines changed

8 files changed

+1189
-1122
lines changed

package-lock.json

Lines changed: 690 additions & 1108 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
"@iexec/web3mail": "^1.2.0",
2828
"@iexec/web3telegram": "^0.0.2-alpha",
2929
"@radix-ui/react-dialog": "^1.1.6",
30+
"@radix-ui/react-select": "^2.1.6",
3031
"@radix-ui/react-slot": "^1.1.2",
3132
"@radix-ui/react-toast": "^1.2.6",
3233
"@reown/appkit": "^1.6.9",

src/components/ui/select.tsx

Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
import * as SelectPrimitive from '@radix-ui/react-select';
2+
import * as React from 'react';
3+
import { Check, ChevronDown, ChevronUp } from 'react-feather';
4+
import { cn } from '@/utils/style.utils.ts';
5+
6+
function Select({
7+
...props
8+
}: React.ComponentProps<typeof SelectPrimitive.Root>) {
9+
return <SelectPrimitive.Root data-slot="select" {...props} />;
10+
}
11+
12+
function SelectGroup({
13+
...props
14+
}: React.ComponentProps<typeof SelectPrimitive.Group>) {
15+
return <SelectPrimitive.Group data-slot="select-group" {...props} />;
16+
}
17+
18+
function SelectValue({
19+
...props
20+
}: React.ComponentProps<typeof SelectPrimitive.Value>) {
21+
return <SelectPrimitive.Value data-slot="select-value" {...props} />;
22+
}
23+
24+
function SelectTrigger({
25+
className,
26+
size = 'default',
27+
children,
28+
...props
29+
}: React.ComponentProps<typeof SelectPrimitive.Trigger> & {
30+
size?: 'sm' | 'default';
31+
}) {
32+
return (
33+
<SelectPrimitive.Trigger
34+
data-slot="select-trigger"
35+
data-size={size}
36+
className={cn(
37+
"border-grey-300 data-[placeholder]:text-muted-foreground [&_svg:not([class*='text-'])]:text-muted-foreground focus:border-primary text-md flex w-fit items-center justify-between gap-2 rounded-lg border bg-transparent p-3 whitespace-nowrap transition-[color,box-shadow] outline-none disabled:cursor-not-allowed disabled:opacity-50 *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-2 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
38+
className
39+
)}
40+
{...props}
41+
>
42+
{children}
43+
<SelectPrimitive.Icon asChild>
44+
<ChevronDown className="size-4 opacity-50" />
45+
</SelectPrimitive.Icon>
46+
</SelectPrimitive.Trigger>
47+
);
48+
}
49+
50+
function SelectContent({
51+
className,
52+
children,
53+
position = 'popper',
54+
...props
55+
}: React.ComponentProps<typeof SelectPrimitive.Content>) {
56+
return (
57+
<SelectPrimitive.Portal>
58+
<SelectPrimitive.Content
59+
data-slot="select-content"
60+
className={cn(
61+
'bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 border-grey-300 relative z-50 max-h-(--radix-select-content-available-height) min-w-[8rem] origin-(--radix-select-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-lg border shadow-md',
62+
position === 'popper' &&
63+
'data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1',
64+
className
65+
)}
66+
position={position}
67+
{...props}
68+
>
69+
<SelectScrollUpButton />
70+
<SelectPrimitive.Viewport
71+
className={cn(
72+
'p-1',
73+
position === 'popper' &&
74+
'h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)] scroll-my-1'
75+
)}
76+
>
77+
{children}
78+
</SelectPrimitive.Viewport>
79+
<SelectScrollDownButton />
80+
</SelectPrimitive.Content>
81+
</SelectPrimitive.Portal>
82+
);
83+
}
84+
85+
function SelectLabel({
86+
className,
87+
...props
88+
}: React.ComponentProps<typeof SelectPrimitive.Label>) {
89+
return (
90+
<SelectPrimitive.Label
91+
data-slot="select-label"
92+
className={cn('pb-2', className)}
93+
{...props}
94+
/>
95+
);
96+
}
97+
98+
function SelectItem({
99+
className,
100+
children,
101+
...props
102+
}: React.ComponentProps<typeof SelectPrimitive.Item>) {
103+
return (
104+
<SelectPrimitive.Item
105+
data-slot="select-item"
106+
className={cn(
107+
"focus:bg-grey-700 [&_svg:not([class*='text-'])]:text-muted-foreground relative flex w-full cursor-default items-center gap-2 rounded-sm py-2 pr-2 pl-8 outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2",
108+
className
109+
)}
110+
{...props}
111+
>
112+
<span className="absolute left-2 flex size-3.5 items-center justify-center">
113+
<SelectPrimitive.ItemIndicator>
114+
<Check className="size-4" />
115+
</SelectPrimitive.ItemIndicator>
116+
</span>
117+
<SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
118+
</SelectPrimitive.Item>
119+
);
120+
}
121+
122+
function SelectSeparator({
123+
className,
124+
...props
125+
}: React.ComponentProps<typeof SelectPrimitive.Separator>) {
126+
return (
127+
<SelectPrimitive.Separator
128+
data-slot="select-separator"
129+
className={cn(
130+
'bg-grey-300 pointer-events-none -mx-1 my-1 h-px',
131+
className
132+
)}
133+
{...props}
134+
/>
135+
);
136+
}
137+
138+
function SelectScrollUpButton({
139+
className,
140+
...props
141+
}: React.ComponentProps<typeof SelectPrimitive.ScrollUpButton>) {
142+
return (
143+
<SelectPrimitive.ScrollUpButton
144+
data-slot="select-scroll-up-button"
145+
className={cn(
146+
'flex cursor-default items-center justify-center py-1',
147+
className
148+
)}
149+
{...props}
150+
>
151+
<ChevronUp className="size-4" />
152+
</SelectPrimitive.ScrollUpButton>
153+
);
154+
}
155+
156+
function SelectScrollDownButton({
157+
className,
158+
...props
159+
}: React.ComponentProps<typeof SelectPrimitive.ScrollDownButton>) {
160+
return (
161+
<SelectPrimitive.ScrollDownButton
162+
data-slot="select-scroll-down-button"
163+
className={cn(
164+
'flex cursor-default items-center justify-center py-1',
165+
className
166+
)}
167+
{...props}
168+
>
169+
<ChevronDown className="size-4" />
170+
</SelectPrimitive.ScrollDownButton>
171+
);
172+
}
173+
174+
export {
175+
Select,
176+
SelectContent,
177+
SelectGroup,
178+
SelectItem,
179+
SelectLabel,
180+
SelectScrollDownButton,
181+
SelectScrollUpButton,
182+
SelectSeparator,
183+
SelectTrigger,
184+
SelectValue,
185+
};

src/components/ui/textarea.tsx

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import * as React from 'react';
2+
import { cn } from '@/utils/style.utils.ts';
3+
4+
function Textarea({ className, ...props }: React.ComponentProps<'textarea'>) {
5+
return (
6+
<textarea
7+
data-slot="textarea"
8+
className={cn(
9+
'border-grey-300 placeholder:text-muted-foreground focus:border-primary aria-invalid:ring-destructive/20 aria-invalid:border-destructive dark:bg-input/30 flex field-sizing-content min-h-32 w-full rounded-lg border bg-transparent p-3 text-base transition-[color,box-shadow] outline-none disabled:cursor-not-allowed disabled:opacity-50',
10+
className
11+
)}
12+
{...props}
13+
/>
14+
);
15+
}
16+
17+
export { Textarea };

src/config/config.ts

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,7 @@ export const ITEMS_PER_PAGE = 6;
22

33
export const LOCAL_STORAGE_PREFIX = 'Web3Messaging';
44

5-
/**
6-
* See smart-contract transactions:
7-
* https://blockscout-bellecour.iex.ec/address/0x781482C39CcE25546583EaC4957Fb7Bf04C277D2
8-
*
9-
* See all idapps in the whitelist:
10-
* https://explorer.iex.ec/bellecour/address/0x0c6c77a11068db9fadfba25182e02863361f58da
11-
*/
5+
export const WORKERPOOL_ADDRESS_OR_ENS = 'prod-v8-learn.main.pools.iexec.eth';
126
export const WEB3MAIL_IDAPPS_WHITELIST_SC =
137
'0x781482c39cce25546583eac4957fb7bf04c277d2';
148
export const WEB3TELEGRAM_IDAPPS_WHITELIST_SC =

src/router.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { createBrowserRouter, Navigate } from 'react-router-dom';
22
import MainLayout from './layouts/MainLayout.tsx';
33
import ContactList from './views/contact/contactList.tsx';
4+
import SendMessage from './views/contact/sendMessage.tsx';
45
import AddProtectedData from './views/myData/addProtectedData.tsx';
56
import ProtectedData from './views/myData/protectedData.tsx';
67
import ProtectedDataList from './views/myData/protectedDataList.tsx';
@@ -29,6 +30,10 @@ export const router = createBrowserRouter([
2930
path: '/contacts',
3031
element: <ContactList />,
3132
},
33+
{
34+
path: '/contacts/:protectedDataAddress/send-message',
35+
element: <SendMessage />,
36+
},
3237
],
3338
},
3439
]);

src/views/contact/contactList.tsx

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -142,12 +142,9 @@ export default function ContactList() {
142142

143143
return (
144144
<div className="space-y-6">
145-
<div className="flex items-center justify-between gap-2">
146-
<div>
147-
<h1 className="text-xl font-bold">Send Message to contact</h1>
148-
<p>Email or telegram contact info</p>
149-
</div>
150-
<Button>Add new contact TODO</Button>
145+
<div>
146+
<h1 className="text-xl font-bold">Send Message to contact</h1>
147+
<p>Email or telegram contact info</p>
151148
</div>
152149
<div className="flex flex-wrap gap-x-6 gap-y-3">
153150
{Object.keys(COLOR_CLASSES).map((key) => {
@@ -227,7 +224,13 @@ export default function ContactList() {
227224
{getDataType(contact.protectedData.schema)}
228225
</div>
229226
<div className="justify-end">
230-
<Button variant="discreet_outline">Send TODO</Button>
227+
<Button asChild variant="discreet_outline">
228+
<NavLink
229+
to={`/contacts/${contact.protectedData.address}/send-message`}
230+
>
231+
Send
232+
</NavLink>
233+
</Button>
231234
</div>
232235
</div>
233236
);

0 commit comments

Comments
 (0)