Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
F
frontend
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
vicotor
frontend
Commits
46508f65
Commit
46508f65
authored
Jan 17, 2025
by
tom
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
fix user wallet menu
parent
0eb4ffd8
Changes
9
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
105 additions
and
71 deletions
+105
-71
drawer.tsx
toolkit/chakra/drawer.tsx
+8
-1
button.recipe.ts
toolkit/theme/recipes/button.recipe.ts
+5
-0
IdenticonGithub.tsx
ui/shared/IdenticonGithub.tsx
+8
-9
AddressIdenticon.tsx
ui/shared/entities/address/AddressIdenticon.tsx
+3
-2
NetworkMenu.tsx
ui/snippets/topBar/NetworkMenu.tsx
+1
-1
UserWalletButton.tsx
ui/snippets/user/wallet/UserWalletButton.tsx
+10
-13
UserWalletDesktop.tsx
ui/snippets/user/wallet/UserWalletDesktop.tsx
+21
-9
UserWalletMenuContent.tsx
ui/snippets/user/wallet/UserWalletMenuContent.tsx
+6
-4
UserWalletMobile.tsx
ui/snippets/user/wallet/UserWalletMobile.tsx
+43
-32
No files found.
toolkit/chakra/drawer.tsx
View file @
46508f65
/* eslint-disable no-restricted-imports */
import
{
Drawer
as
ChakraDrawer
,
Portal
}
from
'
@chakra-ui/react
'
;
import
{
Drawer
as
ChakraDrawer
,
Portal
}
from
'
@chakra-ui/react
'
;
import
*
as
React
from
'
react
'
;
import
*
as
React
from
'
react
'
;
...
@@ -42,8 +43,14 @@ export const DrawerCloseTrigger = React.forwardRef<
...
@@ -42,8 +43,14 @@ export const DrawerCloseTrigger = React.forwardRef<
);
);
});
});
const
EMPTY_ELEMENT
=
()
=>
null
;
export
const
DrawerRoot
=
(
props
:
ChakraDrawer
.
RootProps
)
=>
{
const
{
initialFocusEl
=
EMPTY_ELEMENT
,
...
rest
}
=
props
;
return
<
ChakraDrawer
.
Root
{
...
rest
}
initialFocusEl=
{
initialFocusEl
}
/>;
};
export
const
DrawerTrigger
=
ChakraDrawer
.
Trigger
;
export
const
DrawerTrigger
=
ChakraDrawer
.
Trigger
;
export
const
DrawerRoot
=
ChakraDrawer
.
Root
;
export
const
DrawerFooter
=
ChakraDrawer
.
Footer
;
export
const
DrawerFooter
=
ChakraDrawer
.
Footer
;
export
const
DrawerHeader
=
ChakraDrawer
.
Header
;
export
const
DrawerHeader
=
ChakraDrawer
.
Header
;
export
const
DrawerBody
=
ChakraDrawer
.
Body
;
export
const
DrawerBody
=
ChakraDrawer
.
Body
;
...
...
toolkit/theme/recipes/button.recipe.ts
View file @
46508f65
...
@@ -10,6 +10,11 @@ export const recipe = defineRecipe({
...
@@ -10,6 +10,11 @@ export const recipe = defineRecipe({
_disabled
:
{
_disabled
:
{
opacity
:
0.2
,
opacity
:
0.2
,
},
},
// FIXME have to override the Chakra UI styles for the SVG icon inside the button
// try to find a better solution
'
& svg
'
:
{
boxSize
:
'
auto
'
,
},
},
},
variants
:
{
variants
:
{
visual
:
{
visual
:
{
...
...
ui/shared/IdenticonGithub.tsx
View file @
46508f65
import
{
useColorModeValue
,
useToken
,
Box
,
chakra
}
from
'
@chakra-ui/react
'
;
import
{
Box
,
chakra
}
from
'
@chakra-ui/react
'
;
import
dynamic
from
'
next/dynamic
'
;
import
dynamic
from
'
next/dynamic
'
;
import
React
from
'
react
'
;
import
React
from
'
react
'
;
import
Skeleton
from
'
ui/shared/chakra/S
keleton
'
;
import
{
Skeleton
}
from
'
toolkit/chakra/s
keleton
'
;
const
Identicon
=
dynamic
<
{
bg
:
string
;
string
:
string
;
size
:
number
}
>
(
const
Identicon
=
dynamic
<
{
bg
:
string
;
string
:
string
;
size
:
number
}
>
(
async
()
=>
{
async
()
=>
{
...
@@ -17,26 +17,25 @@ const Identicon = dynamic<{ bg: string; string: string; size: number }>(
...
@@ -17,26 +17,25 @@ const Identicon = dynamic<{ bg: string; string: string; size: number }>(
interface
Props
{
interface
Props
{
className
?:
string
;
className
?:
string
;
s
ize
:
number
;
iconS
ize
:
number
;
seed
:
string
;
seed
:
string
;
}
}
const
IdenticonGithub
=
({
size
,
seed
}:
Props
)
=>
{
const
IdenticonGithub
=
({
iconSize
,
seed
}:
Props
)
=>
{
const
bgColor
=
useToken
(
'
colors
'
,
useColorModeValue
(
'
gray.100
'
,
'
white
'
));
return
(
return
(
<
Box
<
Box
boxSize=
{
`${
s
ize * 2 }px`
}
boxSize=
{
`${
iconS
ize * 2 }px`
}
transformOrigin=
"left top"
transformOrigin=
"left top"
transform=
"scale(0.5)"
transform=
"scale(0.5)"
borderRadius=
"full"
borderRadius=
"full"
overflow=
"hidden"
overflow=
"hidden"
bg=
{
{
_light
:
'
gray.100
'
,
_dark
:
'
white
'
}
}
>
>
<
Identicon
<
Identicon
bg=
{
bgColor
}
bg=
"transparent"
string=
{
seed
}
string=
{
seed
}
// the displayed size is doubled for retina displays and then scaled down
// the displayed size is doubled for retina displays and then scaled down
size=
{
s
ize
*
2
}
size=
{
iconS
ize
*
2
}
/>
/>
</
Box
>
</
Box
>
);
);
...
...
ui/shared/entities/address/AddressIdenticon.tsx
View file @
46508f65
import
{
Box
,
Image
}
from
'
@chakra-ui/react
'
;
import
{
Box
}
from
'
@chakra-ui/react
'
;
import
dynamic
from
'
next/dynamic
'
;
import
dynamic
from
'
next/dynamic
'
;
import
React
from
'
react
'
;
import
React
from
'
react
'
;
import
config
from
'
configs/app
'
;
import
config
from
'
configs/app
'
;
import
*
as
cookies
from
'
lib/cookies
'
;
import
*
as
cookies
from
'
lib/cookies
'
;
import
{
Image
}
from
'
toolkit/chakra/image
'
;
import
IdenticonGithub
from
'
ui/shared/IdenticonGithub
'
;
import
IdenticonGithub
from
'
ui/shared/IdenticonGithub
'
;
interface
IconProps
{
interface
IconProps
{
...
@@ -17,7 +18,7 @@ const Icon = dynamic(
...
@@ -17,7 +18,7 @@ const Icon = dynamic(
switch
(
type
)
{
switch
(
type
)
{
case
'
github
'
:
{
case
'
github
'
:
{
return
(
props
:
IconProps
)
=>
<
IdenticonGithub
s
ize=
{
props
.
size
}
seed=
{
props
.
hash
}
/>;
return
(
props
:
IconProps
)
=>
<
IdenticonGithub
iconS
ize=
{
props
.
size
}
seed=
{
props
.
hash
}
/>;
}
}
case
'
blockie
'
:
{
case
'
blockie
'
:
{
...
...
ui/snippets/topBar/NetworkMenu.tsx
View file @
46508f65
...
@@ -11,7 +11,7 @@ const NetworkMenu = () => {
...
@@ -11,7 +11,7 @@ const NetworkMenu = () => {
return
(
return
(
<
PopoverRoot
<
PopoverRoot
positioning=
{
{
placement
:
'
bottom-start
'
}
}
positioning=
{
{
placement
:
'
bottom-start
'
,
offset
:
{
mainAxis
:
6
}
}
}
lazyMount
lazyMount
open=
{
menu
.
open
}
open=
{
menu
.
open
}
onOpenChange=
{
menu
.
onOpenChange
}
onOpenChange=
{
menu
.
onOpenChange
}
...
...
ui/snippets/user/wallet/UserWalletButton.tsx
View file @
46508f65
import
type
{
ButtonProps
}
from
'
@chakra-ui/react
'
;
import
type
{
ButtonProps
}
from
'
@chakra-ui/react
'
;
import
{
B
utton
,
Box
,
HStack
,
Tooltip
}
from
'
@chakra-ui/react
'
;
import
{
B
ox
,
HStack
}
from
'
@chakra-ui/react
'
;
import
React
from
'
react
'
;
import
React
from
'
react
'
;
import
useIsMobile
from
'
lib/hooks/useIsMobile
'
;
import
useIsMobile
from
'
lib/hooks/useIsMobile
'
;
import
shortenString
from
'
lib/shortenString
'
;
import
shortenString
from
'
lib/shortenString
'
;
import
{
Button
}
from
'
toolkit/chakra/button
'
;
import
{
Tooltip
}
from
'
toolkit/chakra/tooltip
'
;
import
UserIdenticon
from
'
../UserIdenticon
'
;
import
UserIdenticon
from
'
../UserIdenticon
'
;
interface
Props
{
interface
Props
{
size
?:
ButtonProps
[
'
size
'
];
size
?:
ButtonProps
[
'
size
'
];
variant
?:
ButtonProps
[
'
variant
'
];
visual
?:
ButtonProps
[
'
visual
'
];
onClick
?:
()
=>
void
;
isPending
?:
boolean
;
isPending
?:
boolean
;
isAutoConnectDisabled
?:
boolean
;
isAutoConnectDisabled
?:
boolean
;
address
?:
string
;
address
?:
string
;
domain
?:
string
;
domain
?:
string
;
}
}
const
UserWalletButton
=
({
size
,
v
ariant
,
onClick
,
isPending
,
isAutoConnectDisabled
,
address
,
domain
}:
Props
,
ref
:
React
.
ForwardedRef
<
HTMLButtonElement
>
)
=>
{
const
UserWalletButton
=
({
size
,
v
isual
,
isPending
,
isAutoConnectDisabled
,
address
,
domain
}:
Props
,
ref
:
React
.
ForwardedRef
<
HTMLButtonElement
>
)
=>
{
const
isMobile
=
useIsMobile
();
const
isMobile
=
useIsMobile
();
...
@@ -38,24 +39,20 @@ const UserWalletButton = ({ size, variant, onClick, isPending, isAutoConnectDisa
...
@@ -38,24 +39,20 @@ const UserWalletButton = ({ size, variant, onClick, isPending, isAutoConnectDisa
return
(
return
(
<
Tooltip
<
Tooltip
label=
{
<
span
>
Connect your wallet
<
br
/>
to Blockscout for
<
br
/>
full-featured access
</
span
>
}
content=
{
<
span
>
Connect your wallet
<
br
/>
to Blockscout for
<
br
/>
full-featured access
</
span
>
}
textAlign=
"center"
disabled=
{
isMobile
||
Boolean
(
address
)
}
padding=
{
2
}
isDisabled=
{
isMobile
||
Boolean
(
address
)
}
openDelay=
{
500
}
openDelay=
{
500
}
>
>
<
Button
<
Button
ref=
{
ref
}
ref=
{
ref
}
size=
{
size
}
size=
{
size
}
variant=
{
variant
}
visual=
{
visual
}
onClick=
{
onClick
}
data
-
selected=
{
Boolean
(
address
)
}
data
-
selected=
{
Boolean
(
address
)
}
data
-
warning=
{
isAutoConnectDisabled
}
data
-
warning=
{
isAutoConnectDisabled
}
fontSize=
"sm"
textStyle=
"sm"
lineHeight=
{
5
}
px=
{
address
?
2.5
:
4
}
px=
{
address
?
2.5
:
4
}
fontWeight=
{
address
?
700
:
600
}
fontWeight=
{
address
?
700
:
600
}
isL
oading=
{
isPending
}
l
oading=
{
isPending
}
loadingText=
{
isMobile
?
undefined
:
'
Connecting
'
}
loadingText=
{
isMobile
?
undefined
:
'
Connecting
'
}
>
>
{
content
}
{
content
}
...
...
ui/snippets/user/wallet/UserWalletDesktop.tsx
View file @
46508f65
import
{
PopoverBody
,
PopoverContent
,
PopoverTrigger
,
useDisclosure
,
type
ButtonProps
}
from
'
@chakra-ui/react
'
;
import
{
type
ButtonProps
}
from
'
@chakra-ui/react
'
;
import
React
from
'
react
'
;
import
React
from
'
react
'
;
import
{
useMarketplaceContext
}
from
'
lib/contexts/marketplace
'
;
import
{
useMarketplaceContext
}
from
'
lib/contexts/marketplace
'
;
import
useWeb3AccountWithDomain
from
'
lib/web3/useAccountWithDomain
'
;
import
useWeb3AccountWithDomain
from
'
lib/web3/useAccountWithDomain
'
;
import
useWeb3Wallet
from
'
lib/web3/useWallet
'
;
import
useWeb3Wallet
from
'
lib/web3/useWallet
'
;
import
Popover
from
'
ui/shared/chakra/Popover
'
;
import
{
PopoverBody
,
PopoverContent
,
PopoverRoot
,
PopoverTrigger
}
from
'
toolkit/chakra/popover
'
;
import
{
useDisclosure
}
from
'
toolkit/hooks/useDisclosure
'
;
import
UserWalletButton
from
'
./UserWalletButton
'
;
import
UserWalletButton
from
'
./UserWalletButton
'
;
import
UserWalletMenuContent
from
'
./UserWalletMenuContent
'
;
import
UserWalletMenuContent
from
'
./UserWalletMenuContent
'
;
interface
Props
{
interface
Props
{
buttonSize
?:
ButtonProps
[
'
size
'
];
buttonSize
?:
ButtonProps
[
'
size
'
];
buttonV
ariant
?:
ButtonProps
[
'
variant
'
];
buttonV
isual
?:
ButtonProps
[
'
visual
'
];
}
}
// TODO @tom2drum check this component
const
UserWalletDesktop
=
({
buttonSize
,
buttonVisual
=
'
header
'
}:
Props
)
=>
{
const
UserWalletDesktop
=
({
buttonSize
,
buttonVariant
=
'
header
'
}:
Props
)
=>
{
const
walletMenu
=
useDisclosure
();
const
walletMenu
=
useDisclosure
();
const
web3Wallet
=
useWeb3Wallet
({
source
:
'
Header
'
});
const
web3Wallet
=
useWeb3Wallet
({
source
:
'
Header
'
});
...
@@ -36,13 +36,25 @@ const UserWalletDesktop = ({ buttonSize, buttonVariant = 'header' }: Props) => {
...
@@ -36,13 +36,25 @@ const UserWalletDesktop = ({ buttonSize, buttonVariant = 'header' }: Props) => {
walletMenu
.
onClose
();
walletMenu
.
onClose
();
},
[
web3Wallet
,
walletMenu
]);
},
[
web3Wallet
,
walletMenu
]);
const
handleOpenChange
=
React
.
useCallback
(({
open
}:
{
open
:
boolean
})
=>
{
if
(
!
web3Wallet
.
isConnected
)
{
web3Wallet
.
openModal
();
return
;
}
if
(
open
)
{
walletMenu
.
onOpen
();
}
else
{
walletMenu
.
onClose
();
}
},
[
walletMenu
,
web3Wallet
]);
return
(
return
(
<
Popover
openDelay=
{
300
}
placement=
"bottom-end"
isLazy
isOpen=
{
walletMenu
.
isOpen
}
onClose=
{
walletMenu
.
onClos
e
}
>
<
Popover
Root
positioning=
{
{
placement
:
'
bottom-end
'
}
}
lazyMount
open=
{
walletMenu
.
open
}
onOpenChange=
{
handleOpenChang
e
}
>
<
PopoverTrigger
>
<
PopoverTrigger
>
<
UserWalletButton
<
UserWalletButton
size=
{
buttonSize
}
size=
{
buttonSize
}
variant=
{
buttonVariant
}
visual=
{
buttonVisual
}
onClick=
{
web3Wallet
.
isConnected
?
walletMenu
.
onOpen
:
web3Wallet
.
openModal
}
address=
{
web3AccountWithDomain
.
address
}
address=
{
web3AccountWithDomain
.
address
}
domain=
{
web3AccountWithDomain
.
domain
}
domain=
{
web3AccountWithDomain
.
domain
}
isPending=
{
isPending
}
isPending=
{
isPending
}
...
@@ -63,7 +75,7 @@ const UserWalletDesktop = ({ buttonSize, buttonVariant = 'header' }: Props) => {
...
@@ -63,7 +75,7 @@ const UserWalletDesktop = ({ buttonSize, buttonVariant = 'header' }: Props) => {
</
PopoverBody
>
</
PopoverBody
>
</
PopoverContent
>
</
PopoverContent
>
)
}
)
}
</
Popover
>
</
Popover
Root
>
);
);
};
};
...
...
ui/snippets/user/wallet/UserWalletMenuContent.tsx
View file @
46508f65
import
{
Box
,
Button
,
Flex
,
IconButton
,
Spinner
,
Text
}
from
'
@chakra-ui/react
'
;
import
{
Box
,
Flex
,
Spinner
,
Text
}
from
'
@chakra-ui/react
'
;
import
React
from
'
react
'
;
import
React
from
'
react
'
;
import
delay
from
'
lib/delay
'
;
import
delay
from
'
lib/delay
'
;
import
{
Button
}
from
'
toolkit/chakra/button
'
;
import
{
IconButton
}
from
'
toolkit/chakra/icon-button
'
;
import
AddressEntity
from
'
ui/shared/entities/address/AddressEntity
'
;
import
AddressEntity
from
'
ui/shared/entities/address/AddressEntity
'
;
import
IconSvg
from
'
ui/shared/IconSvg
'
;
import
IconSvg
from
'
ui/shared/IconSvg
'
;
...
@@ -41,13 +43,13 @@ const UserWalletMenuContent = ({ isAutoConnectDisabled, address, domain, isRecon
...
@@ -41,13 +43,13 @@ const UserWalletMenuContent = ({ isAutoConnectDisabled, address, domain, isRecon
{
isReconnecting
?
<
Spinner
size=
"sm"
m=
"2px"
flexShrink=
{
0
}
/>
:
(
{
isReconnecting
?
<
Spinner
size=
"sm"
m=
"2px"
flexShrink=
{
0
}
/>
:
(
<
IconButton
<
IconButton
aria
-
label=
"Open wallet"
aria
-
label=
"Open wallet"
icon=
{
<
IconSvg
name=
"gear_slim"
boxSize=
{
5
}
/>
}
variant=
"simple"
color=
"icon_info"
color=
"icon_info"
boxSize=
{
5
}
boxSize=
{
5
}
onClick=
{
handleOpenWalletClick
}
onClick=
{
handleOpenWalletClick
}
flexShrink=
{
0
}
flexShrink=
{
0
}
/>
>
<
IconSvg
name=
"gear_slim"
boxSize=
{
5
}
/>
</
IconButton
>
)
}
)
}
</
Flex
>
</
Flex
>
<
Button
size=
"sm"
width=
"full"
variant=
"outline"
onClick=
{
onDisconnect
}
mt=
{
6
}
>
<
Button
size=
"sm"
width=
"full"
variant=
"outline"
onClick=
{
onDisconnect
}
mt=
{
6
}
>
...
...
ui/snippets/user/wallet/UserWalletMobile.tsx
View file @
46508f65
import
{
Drawer
,
DrawerBody
,
DrawerContent
,
DrawerOverlay
,
useDisclosure
}
from
'
@chakra-ui/react
'
;
import
React
from
'
react
'
;
import
React
from
'
react
'
;
import
{
useMarketplaceContext
}
from
'
lib/contexts/marketplace
'
;
import
{
useMarketplaceContext
}
from
'
lib/contexts/marketplace
'
;
import
useWeb3AccountWithDomain
from
'
lib/web3/useAccountWithDomain
'
;
import
useWeb3AccountWithDomain
from
'
lib/web3/useAccountWithDomain
'
;
import
useWeb3Wallet
from
'
lib/web3/useWallet
'
;
import
useWeb3Wallet
from
'
lib/web3/useWallet
'
;
import
{
DrawerTrigger
,
DrawerRoot
,
DrawerBackdrop
,
DrawerContent
,
DrawerBody
}
from
'
toolkit/chakra/drawer
'
;
import
{
useDisclosure
}
from
'
toolkit/hooks/useDisclosure
'
;
import
UserWalletButton
from
'
./UserWalletButton
'
;
import
UserWalletButton
from
'
./UserWalletButton
'
;
import
UserWalletMenuContent
from
'
./UserWalletMenuContent
'
;
import
UserWalletMenuContent
from
'
./UserWalletMenuContent
'
;
...
@@ -29,38 +30,48 @@ const UserWalletMobile = () => {
...
@@ -29,38 +30,48 @@ const UserWalletMobile = () => {
walletMenu
.
onClose
();
walletMenu
.
onClose
();
},
[
web3Wallet
,
walletMenu
]);
},
[
web3Wallet
,
walletMenu
]);
const
handleOpenChange
=
React
.
useCallback
(({
open
}:
{
open
:
boolean
})
=>
{
if
(
!
web3Wallet
.
isConnected
)
{
web3Wallet
.
openModal
();
return
;
}
if
(
open
)
{
walletMenu
.
onOpen
();
}
else
{
walletMenu
.
onClose
();
}
},
[
walletMenu
,
web3Wallet
]);
return
(
return
(
<>
<
DrawerRoot
<
UserWalletButton
open=
{
walletMenu
.
open
}
variant=
"header"
onOpenChange=
{
handleOpenChange
}
onClick=
{
web3Wallet
.
isConnected
?
walletMenu
.
onOpen
:
web3Wallet
.
openModal
}
>
address=
{
web3AccountWithDomain
.
address
}
<
DrawerBackdrop
/>
domain=
{
web3AccountWithDomain
.
domain
}
<
DrawerTrigger
>
isPending=
{
isPending
}
<
UserWalletButton
/>
visual=
"header"
{
web3AccountWithDomain
.
address
&&
(
address=
{
web3AccountWithDomain
.
address
}
<
Drawer
domain=
{
web3AccountWithDomain
.
domain
}
isOpen=
{
walletMenu
.
isOpen
}
isPending=
{
isPending
}
placement=
"right"
/>
onClose=
{
walletMenu
.
onClose
}
</
DrawerTrigger
>
autoFocus=
{
false
}
<
DrawerContent
maxWidth=
"300px"
>
>
<
DrawerBody
p=
{
6
}
>
<
DrawerOverlay
/>
{
web3AccountWithDomain
.
address
&&
(
<
DrawerContent
maxWidth=
"300px"
>
<
UserWalletMenuContent
<
DrawerBody
p=
{
6
}
>
address=
{
web3AccountWithDomain
.
address
}
<
UserWalletMenuContent
domain=
{
web3AccountWithDomain
.
domain
}
address=
{
web3AccountWithDomain
.
address
}
isAutoConnectDisabled=
{
isAutoConnectDisabled
}
domain=
{
web3AccountWithDomain
.
domain
}
isReconnecting=
{
web3Wallet
.
isReconnecting
}
isAutoConnectDisabled=
{
isAutoConnectDisabled
}
onOpenWallet=
{
handleOpenWalletClick
}
isReconnecting=
{
web3Wallet
.
isReconnecting
}
onDisconnect=
{
handleDisconnectClick
}
onOpenWallet=
{
handleOpenWalletClick
}
/>
onDisconnect=
{
handleDisconnectClick
}
)
}
/>
</
DrawerBody
>
</
DrawerBody
>
</
DrawerContent
>
</
DrawerContent
>
</
DrawerRoot
>
</
Drawer
>
)
}
</>
);
);
};
};
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment