react-bootstrap#Dropdown TypeScript Examples
The following examples show how to use
react-bootstrap#Dropdown.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: Searchbar.tsx From devex with GNU General Public License v3.0 | 5 votes |
Searchbar: React.FC<IProps> = ({ isHeaderSearchbar, isISSearchbar }) => {
const history = useHistory()
const location = useLocation()
const [input, setInput] = useState("")
const [searchType, setSearchType] = useState('Txn/Addr')
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => (
setInput(e.target.value)
)
const handleSubmit = (e: React.SyntheticEvent) => {
e.preventDefault()
const trimmedInput = input.trim()
switch (searchType) {
case 'Txn/Addr':
if (isValidAddr(trimmedInput))
history.push({
pathname: `/address/${trimmedInput}`,
search: location.search
})
else
history.push({
pathname: `/tx/${trimmedInput}`,
search: location.search
})
break
case 'Tx Block':
history.push({
pathname: `/txbk/${trimmedInput}`,
search: location.search
})
break
case 'DS Block':
history.push({
pathname: `/dsbk/${trimmedInput}`,
search: location.search
})
break
}
setInput('')
}
return <>
<Form onSubmit={handleSubmit}>
<InputGroup className="searchbar-ig" id={isHeaderSearchbar ? "header-searchbar-ig" : "searchbar-ig"}>
{isISSearchbar
? <InputGroup.Prepend>
<DropdownButton id='searchbar-dropdown' title={searchType}>
<Dropdown.Item onClick={() => setSearchType('Txn/Addr')}>Txn/Addr</Dropdown.Item>
<Dropdown.Item onClick={() => setSearchType('Tx Block')}>Tx Block</Dropdown.Item>
</DropdownButton>
</InputGroup.Prepend>
:
<InputGroup.Prepend>
<DropdownButton id='searchbar-dropdown' title={searchType}>
<Dropdown.Item onClick={() => setSearchType('Txn/Addr')}>Txn/Addr</Dropdown.Item>
<Dropdown.Item onClick={() => setSearchType('Tx Block')}>Tx Block</Dropdown.Item>
<Dropdown.Item onClick={() => setSearchType('DS Block')}>DS Block</Dropdown.Item>
</DropdownButton>
</InputGroup.Prepend>
}
<Form.Control type="text" value={input} autoFocus={!isHeaderSearchbar}
placeholder={
searchType === 'Txn/Addr'
? 'Search for a transaction or an address'
: searchType === 'Tx Block'
? 'Search by Tx Block height'
: 'Search by DS Block height'}
onChange={handleChange} />
<InputGroup.Append>
<Button type="submit">
{isHeaderSearchbar ? <FontAwesomeIcon icon={faSearch} /> : <div>Search</div>}
</Button>
</InputGroup.Append>
</InputGroup>
</Form>
</>
}
Example #2
Source File: SideNavbar.tsx From 3Speak-app with GNU General Public License v3.0 | 4 votes |
export function SideNavbar(props: any) {
const [login, setLogin] = useState('')
const [myChannelLink, setMyChannelLink] = useState('')
useEffect(() => {
const load = async () => {
const login = localStorage.getItem('SNProfileID')
if (login) {
const user = (await AccountService.getAccount(login)) as any
const ringItem = user.keyring[0]
setLogin(user.nickname)
setMyChannelLink(`${ringItem.type}:${ringItem.username}`)
}
}
void load()
}, [])
const logOut = async () => {
//TODO: logout logic
const profileID = localStorage.getItem('SNProfileID')
const user = await AccountService.logout(profileID)
const accountsInit = (await AccountService.getAccounts()) as any
localStorage.removeItem('SNProfileID')
console.log(accountsInit)
if (accountsInit.length > 0) {
localStorage.setItem('SNProfileID', accountsInit[0]._id)
}
window.location.reload()
}
return (
<Navbar bg="white" expand="lg" id="layoutNav" className="bg_white fixed-left">
<Navbar.Brand>
<img src={SpeakLogo} />
</Navbar.Brand>
<Navbar.Toggle aria-controls="basic-navbar-nav">
<span className="navbar-toggler-icon"></span>
</Navbar.Toggle>
<Navbar.Collapse>
<Nav className="mr-auto nav_dist">
{login && (
<NavDropdown
id="nav-dropdown"
title={
<>
<div className="nav_icons">
<VscKey size="21px" />
</div>
<span>@{login}</span>
</>
}
>
<NavDropdown.Item href="#/accounts">Switch account</NavDropdown.Item>
<NavDropdown.Item href={`#/user/${myChannelLink}`}>Go to my channel</NavDropdown.Item>
<NavDropdown.Item href="#/login">Add account</NavDropdown.Item>
{login && (
<NavDropdown.Item
onClick={() => {
logOut()
}}
>
Log out
</NavDropdown.Item>
)}
</NavDropdown>
)}
{!login && (
<Nav.Link href="#/login" className="display-mobile">
<button className="btn btn-dark text-white btn-sm">Add account</button>
</Nav.Link>
)}
<hr />
<Nav.Link href="#/">
<div className="nav_icons">
<img src={iconHome} height="14px" />
</div>
Home
</Nav.Link>
<Nav.Item></Nav.Item>
<Nav.Link href="#/trends">
<div className="nav_icons">
<img src={iconTrend} height="21px" />
</div>
Trending Content
</Nav.Link>
<Nav.Link href="#/new">
<div className="nav_icons">
<img src={iconNewContent} height="17px" />
</div>
New Content
</Nav.Link>
<NavDropdown
id="nav-dropdown"
title={
<>
<div className="nav_icons">
<img src={shakeHands} style={{ height: '21px' }} />
</div>
Communities
</>
}
>
<Nav.Link href="#/communities">
<FaGlobe /> All Communities...
</Nav.Link>
<NavDropdown.Item href="#/community/hive:hive-181335">
<FaUsers /> Threespeak
</NavDropdown.Item>
<NavDropdown.Item href="#/community/hive:hive-153014">
<FaUsers /> Citizen Journalists
</NavDropdown.Item>
<NavDropdown.Item href="#/community/hive:hive-112355">
<FaUsers /> Threeshorts
</NavDropdown.Item>
<NavDropdown.Item href="#/community/hive:hive-129768">
<FaUsers />
Coronavirus Pandemic
</NavDropdown.Item>
<NavDropdown.Item href="#/community/hive:hive-196427">
<FaUsers /> COVID-19
</NavDropdown.Item>
</NavDropdown>
<Nav.Link href="#/leaderboard">
<div className="nav_icons">
<img src={iconLeaderboard} height="12px" />
</div>
Leaderboard
</Nav.Link>
<Nav.Link href="#/newcomers">
<div className="nav_icons">
<img src={iconNewcomer} height="19px" />
</div>
First Uploads
</Nav.Link>
<Nav.Link href="#/uploader">
<div className="nav_icons">
<FaToolbox />
</div>
Uploader
</Nav.Link>
<Nav.Link href="#/creatorstudio">
<div className="nav_icons">
<FaToolbox />
</div>
Creator Studio
</Nav.Link>
<NavDropdown
id="nav-dropdown"
title={
<>
<div className="nav_icons">
<BsFillGearFill style={{ height: '21px' }} />
</div>
Settings
</>
}
>
<Nav.Link href="#/blocklist">
<FaGlobe /> Blocklist
</Nav.Link>
<Nav.Link href="#/pins">
<FaGlobe /> Pins
</Nav.Link>
<Nav.Link href="#/ipfsconsole">
<FaGlobe /> Ipfs Console
</Nav.Link>
</NavDropdown>
</Nav>
<Nav>
<li className="nav-item">
<div className="pad_l">
<h5>3Speak</h5>
</div>
</li>
<li className="nav-item">
<a className="nav-link" href="https://3speak.co/intl/about_us">
About us
</a>
</li>
<li className="nav-item">
<a className="nav-link" href="https://3speak.co/intl/about_us">
FAQ
</a>
</li>
<li className="nav-item text-center">
<a
className=""
target="_blank"
href="https://twitter.com/3speakonline?utm_source=3speak.co"
>
<FaTwitter size={28} />
</a>
<a className="ml-2" target="_blank" href="https://t.me/threespeak?utm_source=3speak.co">
<FaTelegram size={28} />
</a>
<a
className="ml-2"
target="_blank"
href="https://discord.me/3speak?utm_source=3speak.co"
>
<i className="fab fa-discord text-muted fa-2x"></i>
<FaDiscord size={28} />
</a>
<a
className="ml-2"
target="_blank"
title="Visit Our Blog"
href="https://hive.blog/@threespeak"
>
<img
style={{ width: '32px', marginTop: '-15px', color: 'black' }}
src={iconBlog}
alt=""
/>
</a>
</li>
<Dropdown title="Find us" className="nav-item dropdown mt-2 display-mobile">
<Dropdown.Toggle
className="btn btn-secondary btn-sm dropdown-toggle"
variant="secondary"
data-toggle="dropdown"
aria-haspopup="true"
>
Find us
</Dropdown.Toggle>
<Dropdown.Menu>
<a className="dropdown-item" href="https://t.me/threespeak?utm_source=3speak.co">
Telegram
</a>
<a className="dropdown-item" href="https://discord.me/3speak?utm_source=3speak.co">
Discord
</a>
<a
className="dropdown-item"
target="_blank"
href="https://twitter.com/3speakonline?utm_source=3speak.co"
>
Twitter
</a>
</Dropdown.Menu>
</Dropdown>
</Nav>
</Navbar.Collapse>
</Navbar>
)
}
Example #3
Source File: TopNavbar.tsx From 3Speak-app with GNU General Public License v3.0 | 4 votes |
export function TopNavbar() {
const [inEdit, setInEdit] = useState(false)
const urlForm = useRef<any>()
const [urlSplit, setUrlSplit] = useState([])
const startEdit = () => {
setInEdit(true)
}
useEffect(() => {
if (inEdit) {
urlForm.current?.focus()
}
}, [inEdit])
const exitEdit = () => {
setInEdit(false)
}
const finishEdit = (e) => {
if (e.keyCode === 13) {
if (location.hash !== `#${e.target.value}`) {
location.replace(`#${e.target.value}`)
location.reload()
}
setInEdit(false)
} else if (e.keyCode === 27) {
exitEdit()
}
}
const updateUrlSplit = () => {
const hash = window.location.hash
const theUrlSplit = hash.split('/')
theUrlSplit.splice(0, 1)
if (theUrlSplit[0] === 'watch') {
const pagePerm = theUrlSplit[1]
const pagePermSpliced = pagePerm.split(':')
pagePermSpliced.splice(0, 1)
theUrlSplit.pop()
pagePermSpliced.forEach((onePagePerm) => {
theUrlSplit.push(onePagePerm)
})
setUrlSplit(theUrlSplit)
} else {
setUrlSplit(theUrlSplit)
}
}
useEffect(() => {
updateUrlSplit()
}, [])
useEffect(() => {
window.addEventListener('hashchange', function (event) {
updateUrlSplit()
})
}, [])
const userProfileUrl = useMemo(() => {
const windowLocationHash = window.location.hash
const windowLocationSearch = windowLocationHash.search('#')
const windowLocationHref = windowLocationHash.slice(windowLocationSearch)
const hrefSegments = windowLocationHref.split('/')
hrefSegments.splice(0, 1)
let userProfileUrl = '#/user/'
if (hrefSegments[0] === 'watch') {
const userProfileUrlInit = hrefSegments[1]
const userProfileUrlSpliced = userProfileUrlInit.split(':')
userProfileUrlSpliced.pop()
userProfileUrlSpliced.forEach((one) => {
if (one === userProfileUrlSpliced[0]) {
userProfileUrl = userProfileUrl + one + ':'
} else {
userProfileUrl = userProfileUrl + one
}
})
}
return userProfileUrl
}, [])
return (
<div>
<Navbar bg="light" expand="lg">
<Navbar.Collapse id="basic-navbar-nav">
<Nav className="mr-auto">
{!inEdit ? (
<>
<Breadcrumb>
<Breadcrumb.Item href="#/">Home</Breadcrumb.Item>
{urlSplit.map((el) =>
el === updateUrlSplit[1] && updateUrlSplit[0] === 'watch' ? (
<Breadcrumb.Item href={userProfileUrl} key={el} id={el}>
{el}
</Breadcrumb.Item>
) : (
<Breadcrumb.Item href={'#'} key={el} id={el}>
{el}
</Breadcrumb.Item>
),
)}
</Breadcrumb>
<Button
className="btn btn-light btn-sm"
style={{
marginLeft: '5px',
width: '40px',
height: '40px',
padding: '3.5%',
verticalAlign: 'baseline',
}}
onClick={startEdit}
>
<FaEdit style={{ textAlign: 'center', verticalAlign: 'initial' }} />
</Button>
</>
) : (
<FormControl
ref={urlForm}
defaultValue={(() => {
return location.hash.slice(1)
})()}
onKeyDown={finishEdit}
onBlur={exitEdit}
/>
)}
</Nav>
<Dropdown>
<Dropdown.Toggle variant="secondary" size="lg">
Options
</Dropdown.Toggle>
<Dropdown.Menu>
<Dropdown.Item onClick={() => copyToClip(window.location.hash)}>
Copy Current URL{' '}
<FaCopy size={28} onClick={() => copyToClip(window.location.hash)} />
</Dropdown.Item>
<Dropdown.Item onClick={goToClip}>
Go to Copied URL <FaArrowRight size={28} />
</Dropdown.Item>
</Dropdown.Menu>
</Dropdown>
<Nav>
<Nav.Link>
<FaAngleLeft size={28} onClick={goBack} />
</Nav.Link>
<Nav.Link>
<FaAngleRight size={28} onClick={goForth} />
</Nav.Link>
</Nav>
</Navbar.Collapse>
</Navbar>
</div>
)
}
Example #4
Source File: PostComment.tsx From 3Speak-app with GNU General Public License v3.0 | 4 votes |
/**
* @todo Implement displaying numbers of comments and comment value. Requires support on backend to count votes.
* @todo Implement interactibility.
* @todo Implement 3 dot action menu.
*/
export function PostComment(props: any) {
const [commentInfo, setCommentInfo] = useState({ description: '', creation: 0 })
const [replying, setReplying] = useState(false)
const [profilePicture, setProfilePicture] = useState('')
useEffect(() => {
const load = async () => {
let info
let profilePicture
if (props.commentInfo) {
info = props.commentInfo
} else {
info = await AccountService.permalinkToVideoInfo(props.reflink)
}
if (info) {
profilePicture = setProfilePicture(await AccountService.getProfilePictureURL(info.reflink))
setCommentInfo(info)
}
}
void load()
}, [])
const handleAction = async (eventKey) => {
const reflink = props.reflink
switch (eventKey) {
case 'block_post': {
await electronIpc.send('blocklist.add', reflink, {
reason: 'manual block',
})
break
}
case 'block_user': {
const ref = RefLink.parse(reflink) as any as any
await electronIpc.send('blocklist.add', `${ref.source.value}:${ref.root}`, {
reason: 'manual block',
})
break
}
case 'copy_reflink': {
clipboard.writeText(reflink, clipboard as any)
break
}
default: {
throw new Error(`Unrecognized action: ${eventKey}!`)
}
}
}
const postTimeDistance = useMemo(() => {
return millisecondsAsString((new Date() as any) - (new Date(commentInfo.creation) as any))
}, [commentInfo])
const postTime = useMemo(() => {
return DateAndTime.format(new Date(commentInfo.creation), 'YYYY/MM/DD HH:mm:ss')
}, [commentInfo])
return (
<div>
<div className="col">
<div className="thumbnail mr-2 float-left">
<img className="img-responsive user-photo" width="24" src={profilePicture} />
</div>
</div>
<div className="col" style={{ zIndex: 1000 }}>
<div className="mr-3 float-right">
<Dropdown onSelect={handleAction}>
<Dropdown.Toggle as={CustomToggle}></Dropdown.Toggle>
<Dropdown.Menu>
<Dropdown.Item style={{ color: 'red' }} eventKey="block_post">
Block post
</Dropdown.Item>
<Dropdown.Item style={{ color: 'red' }} eventKey="block_user">
Block user
</Dropdown.Item>
<Dropdown.Item eventKey="copy_reflink">Copy to clipboard permlink</Dropdown.Item>
</Dropdown.Menu>
</Dropdown>
</div>
</div>
<div className="col-12">
<div className="panel ml-2 panel-default">
<div className="panel-heading ml-4">
<strong>
<a href={`#/user?=${props.reflink}`}>{RefLink.parse(props.reflink).root}</a>{' '}
</strong>
•{' '}
<span className="text-muted">
<OverlayTrigger overlay={<Tooltip id="post-time">{postTime}</Tooltip>}>
<div>{postTimeDistance}</div>
</OverlayTrigger>
</span>
</div>
<div className="panel-body mt-1">
<ReactMarkdown
escapeHtml={false}
source={DOMPurify.sanitize(commentInfo.description)}
></ReactMarkdown>
</div>
<div className="panel-footer ml-0 ml-md-4">
<hr />
<ul className="list-inline list-inline-separate">
<li className="list-inline-item">
<VoteWidget reflink={props.reflink} />
</li>
<li
className="list-inline-item"
style={{ cursor: 'pointer' }}
onClick={() => {
setReplying(!replying)
}}
>
{replying ? 'Cancel' : 'Reply'}
</li>
</ul>
</div>
</div>
</div>
{replying ? (
<div className="box mb-3 clearfix">
<CommentForm parent_reflink={props.reflink} onCommentPost={props.onCommentPost} />
</div>
) : null}
</div>
)
}
Example #5
Source File: LoginView.tsx From 3Speak-app with GNU General Public License v3.0 | 4 votes |
export function LoginView() {
const submitRef = useRef<any>()
const [username, setUsername] = useState('')
const [key, setKey] = useState('')
const [profile, setProfile] = useState('')
const [encryption, setEncryption] = useState(false)
const [symKey, setSymKey] = useState('')
const [accountType, setAccountType] = useState('hive')
const [submitting, setSubmitting] = useState(false)
const resetForm = () => {
console.log(`resetting form`)
setUsername('')
setKey('')
}
const onUsernameChange = useCallback(async (event) => {
console.log(`username change ${event.target.value}`)
setUsername(event.target.value)
}, [])
const onKeyChange = useCallback(async (event) => {
setKey(event.target.value)
}, [])
const onProfileChange = useCallback(async (event) => {
setProfile(event.target.value)
}, [])
const onEncryptionChange = useCallback(async (event) => {
setEncryption(event.target.checked)
}, [])
const onSymKeyChange = useCallback(async (event) => {
setSymKey(event.target.value)
}, [])
const handleSubmit = useCallback(
async (event) => {
event.preventDefault()
const login = {
username: username,
key: key,
profile: profile,
accountType: accountType,
symKey: symKey,
isEncrypted: encryption,
}
setSubmitting(true)
submitRef?.current?.setAttribute('disabled', 'disabled')
try {
const loginHandler = (await AccountService.login(login)) as any
console.log(loginHandler)
if (loginHandler.nickname === login.username) {
window.location.reload()
} else {
console.log({ loginHandler, response: 'unsucessful' })
}
} catch (ex) {
NotificationManager.error(ex.toString())
throw ex
}
setSubmitting(false)
resetForm()
submitRef.current.removeAttribute('disabled')
},
[username, key, profile, accountType, symKey, encryption],
)
return (
<>
<Form
id="contact-form"
onSubmit={(event) => {
void handleSubmit(event)
}}
style={{
maxWidth: '600px',
width: '100%',
padding: '20px',
alignItems: 'center',
}}
>
<div className="p-3" style={{ width: '100%' }}>
<Form.Label className="text-secondary">Account type</Form.Label>
<Dropdown className="mb-2">
<Dropdown.Toggle variant="secondary">{accountType}</Dropdown.Toggle>
<Dropdown.Menu>
<Dropdown.Item
onClick={() => {
setAccountType('hive')
}}
>
Hive
</Dropdown.Item>
<Dropdown.Item
onClick={() => {
setAccountType('IDX')
}}
>
IDX
</Dropdown.Item>
<Dropdown.Item
onClick={() => {
setAccountType('other')
}}
>
Other
</Dropdown.Item>
</Dropdown.Menu>
</Dropdown>
{accountType !== 'hive' ? (
<OverlayTrigger
placement={'top'}
overlay={<Tooltip id="coming-soon">Disabled (Coming Soon!)</Tooltip>}
>
<div>
<Form.Group>
<Form.Label className="text-secondary">Profile name</Form.Label>
<Form.Control
type="text"
value={profile}
onChange={onProfileChange}
className="bg-secondary text-light"
disabled
required
/>
</Form.Group>
<Form.Group>
<Form.Label className="text-secondary">Username</Form.Label>
<Form.Control
type="text"
value={username}
onChange={onUsernameChange}
className="bg-secondary text-light"
disabled
required
/>
</Form.Group>
</div>
</OverlayTrigger>
) : (
<>
<Form.Group>
<Form.Label className="text-secondary">Profile name</Form.Label>
<Form.Control
type="text"
value={profile}
onChange={onProfileChange}
className="bg-secondary text-light"
required
/>
</Form.Group>
<Form.Group>
<Form.Label className="text-secondary">Username</Form.Label>
<Form.Control
type="text"
value={username}
onChange={onUsernameChange}
className="bg-secondary text-light"
required
/>
</Form.Group>
</>
)}
{accountType === 'hive' && (
<Form.Group>
<Form.Label className="text-secondary">Hive Private Posting Key</Form.Label>
<Form.Control
type="password"
value={key}
onChange={onKeyChange}
className="bg-secondary text-light"
pattern="5[HJK][1-9A-HJ-NP-Za-km-z]{49}"
required
/>
</Form.Group>
)}
<OverlayTrigger
placement={'top'}
overlay={<Tooltip id="coming-soon">Disabled (Coming Soon!)</Tooltip>}
>
<div>
<label className="text-secondary mr-2" htmlFor="enable-encryption">
Enable Encryption
</label>
<input
name="enable-encryption"
type="checkbox"
checked={encryption}
disabled
onChange={onEncryptionChange}
/>
</div>
</OverlayTrigger>
{encryption && (
<Form.Group>
<Form.Label className="text-secondary">Symmetric Key</Form.Label>
<Form.Control
type="text"
value={symKey}
onChange={onSymKeyChange}
className="bg-secondary text-light"
/>
</Form.Group>
)}
<br />
<span className="tag-wrap">
<Button type="submit" ref={submitRef} variant="secondary">
{submitting ? <FontAwesomeIcon icon={faSpinner as any} spin /> : 'Submit'}
</Button>
</span>
</div>
</Form>
</>
)
}
Example #6
Source File: PinsView.tsx From 3Speak-app with GNU General Public License v3.0 | 4 votes |
export function PinsView() {
const [pinList, setPinList] = useState([])
const [newVideos, setNewVideos] = useState([])
const [trendingVideos, setTrendingVideos] = useState([])
const [showExplorer, setShowExplorer] = useState(false)
const pid = useRef<any>()
const updateSearchTables = (community = null, creator = null) => {
const ids = pinList.map((x) => {
return x._id
})
console.log(ids)
const params = '?limit=10&ipfsOnly=true'
let newUrl = `https://3speak.tv/apiv2/feeds/new${params}`
let trendingUrl = `https://3speak.tv/apiv2/feeds/trending${params}`
if (community) {
newUrl = `https://3speak.tv/apiv2/feeds/community/${community}/new${params}`
trendingUrl = `https://3speak.tv/apiv2/feeds/community/${community}/trending${params}`
} else if (creator && creator.length > 2) {
newUrl = `https://3speak.tv/apiv2/feeds/@${creator}`
trendingUrl = null
}
fetch(newUrl)
.then((r) => r.json())
.then((r) => {
for (const video of r) {
const id = `hive:${video.author}:${video.permlink}`
video.isPinned = ids.includes(id)
video.id = id
}
console.log(r)
setNewVideos(r)
})
if (!trendingUrl) {
setTrendingVideos([])
} else {
fetch(trendingUrl)
.then((r) => r.json())
.then((r) => {
for (const video of r) {
const id = `hive:${video.author}:${video.permlink}`
video.isPinned = ids.includes(id)
video.id = id
}
setTrendingVideos(r)
})
}
}
const generate = async () => {
// type error - 2 arguments expected
setPinList(await PromiseIpc.send('pins.ls', undefined as any))
}
const PinLocally = async (cids, title, _id) => {
debug(`CIDs to store ${JSON.stringify(cids)}`)
if (cids.length !== 0) {
NotificationManager.info('Pinning in progress')
await PromiseIpc.send('pins.add', {
_id,
source: 'Pins page',
cids,
expire: null,
meta: {
title,
},
} as any)
NotificationManager.success(
`Video with title of ${title} has been successfully pinned! Thank you for contributing!`,
'Pin Successful',
)
} else {
NotificationManager.warning('This video is not available on IPFS')
}
await generate()
}
const actionSelect = async (key) => {
console.log(key)
switch (key) {
case '1': {
const func = () =>
new Promise(async (resolve, reject) => {
const ref = React.createRef() as any
Popup.create({
content: (
<div>
<Form ref={ref}>
<Form.Label>Reflink</Form.Label>
<FormControl
name="reflink"
placeholder="hive:username:123permlink"
></FormControl>
</Form>
</div>
),
buttons: {
left: [
{
text: 'Cancel',
className: 'secondary',
action: function () {
Popup.close()
},
},
],
right: [
{
text: 'Done',
className: 'success',
action: function () {
resolve(FormUtils.formToObj(new FormData(ref.current)))
Popup.close()
},
},
],
},
})
})
const ret = (await func()) as any
const video_info = await AccountService.permalinkToVideoInfo(ret.reflink)
const cids = []
for (const source of video_info.sources) {
const url = new (require('url').URL)(source.url)
try {
new CID(url.host)
cids.push(url.host)
} catch (ex) {
console.error(ex)
}
}
if (cids.length !== 0) {
NotificationManager.info('Pinning in progress')
await PromiseIpc.send('pins.add', {
_id: ret.reflink,
source: 'Manual Add',
cids,
expire: null,
meta: {
title: video_info.title,
},
} as any)
NotificationManager.success(
`Video with reflink of ${ret.reflink} has been successfully pinned! Thank you for contributing!`,
'Pin Successful',
)
} else {
NotificationManager.warning('This video is not available on IPFS')
}
break
}
case '2': {
NotificationManager.info('GC has started')
const { ipfs } = await IpfsHandler.getIpfs()
ipfs.repo.gc()
break
}
default: {
}
}
}
const removePin = async (reflink) => {
try {
await PromiseIpc.send('pins.rm', reflink)
NotificationManager.success('IPFS pin removal complete')
await generate()
} catch (ex) {
NotificationManager.error('IPFS pin removal resulted in error')
console.error(ex)
}
}
useEffect(() => {
document.title = '3Speak - Tokenised video communities'
void generate()
pid.current = setInterval(generate, 1500)
updateSearchTables()
return () => {
clearInterval(pid.current)
}
}, [])
const pinRows = useMemo(() => {
const rows = []
for (const pin of pinList) {
const sizeBest = bytesAsString(pin.size)
rows.push(
<tr key={pin._id}>
<td>
<a href={`#/watch/${pin._id}`}>{pin._id}</a>
<br />(<strong>{RefLink.parse(pin._id).root}</strong>)
</td>
<td>
<a href={`#/watch/${pin._id}`}>{pin.meta ? pin.meta.title : null} </a>
</td>
<td>
{pin.cids.length > 1 ? (
<a
onClick={() => {
Popup.create({
title: 'CIDs',
content: (
<div>
<Editor value={pin.cids} ace={ace} theme="ace/theme/github"></Editor>
</div>
),
buttons: {
left: [],
right: [
{
text: 'close',
key: '⌘+s',
className: 'success',
action: function () {
Popup.close()
},
},
],
},
})
}}
>
View ({pin.cids.length})
</a>
) : (
pin.cids
)}
</td>
<td>{pin.source}</td>
<td>
{pin.expire
? (() => {
console.log(pin.expire)
return 'In ' + millisecondsAsString((pin.expire = new Date().getTime()))
})()
: 'Permanent'}
</td>
<td>
{pin.meta.pin_date
? (() => {
console.log(pin.meta.pin_date)
return new Date(pin.meta.pin_date).toLocaleString()
})()
: null}
</td>
<td>{pin.size === 0 ? <strong>Pinning In Progress</strong> : sizeBest}</td>
<td>
<Button variant="danger" onClick={() => removePin(pin._id)}>
X
</Button>
</td>
</tr>,
)
}
return rows
}, [pinList])
return (
<div>
<Row>
<Col style={{ textAlign: 'right' }}>
<Dropdown onSelect={actionSelect}>
<Dropdown.Toggle as={CustomPinsViewToggle} id="dropdown-custom-components">
<Button>Actions</Button>
</Dropdown.Toggle>
<Dropdown.Menu as={CustomPinsViewMenu}>
<Dropdown.Item eventKey="1">Manual Pin</Dropdown.Item>
<Dropdown.Item eventKey="2">Manual GC</Dropdown.Item>
</Dropdown.Menu>
</Dropdown>
</Col>
</Row>
<Table striped bordered hover size="sm">
<thead>
<tr>
<th>Reflink</th>
<th>Title</th>
<th>CID(s)</th>
<th>Source</th>
<th>Expiration</th>
<th>Pin Date</th>
<th>Size/Status</th>
<th>Remove?</th>
</tr>
</thead>
<tbody>{pinRows}</tbody>
</Table>
<Button
onClick={() => {
setShowExplorer(!showExplorer)
}}
>
Toggle pin explorer
</Button>
{showExplorer && (
<>
<h6>Select to pin and help secure the network by backing up videos</h6>
<input
type="text"
placeholder="Enter community ID..."
onChange={(event) => {
if (event.target.value.match(/\bhive-\d{6}\b/g)) {
updateSearchTables(event.target.value, null)
}
}}
/>
<input
type="text"
placeholder="Enter a username"
onChange={(event) => {
updateSearchTables(null, event.target.value)
}}
/>
<Row>
{['new', 'trending'].map((type: 'new' | 'trending') => (
<Col key={type}>
<Table striped bordered hover size="sm">
<thead>
<tr>
<th>{type} videos</th>
<th>Title</th>
<th>Creator</th>
<th>pinned</th>
</tr>
</thead>
<tbody>
{/* {this.state[`${type}Videos`].map((video) => ( */}
{(type === 'new' ? newVideos : trendingVideos).map((video) => (
<tr key={`${type}-${video.author}-${video.permlink}`}>
<td>
<div className="teaser_holder video-card-image">
<div className="card-label">
{(() => {
const pattern = DateTime.compile('mm:ss')
return DateTime.format(new Date(video.duration * 1000), pattern)
})()}
</div>
<a href={`#/watch/hive:${video.author}:${video.permlink}`}>
<img
className="img-fluid bg-dark"
src={video.images.thumbnail}
alt=""
/>
</a>
</div>
</td>
<td>{video.title}</td>
<td>{video.author}</td>
<td>
{video.isPinned ? (
<Button
variant="danger"
onClick={async () => {
await removePin(video.id)
updateSearchTables()
}}
>
X
</Button>
) : (
<Button
variant="success"
onClick={async () => {
await PinLocally([video.ipfs], video.title, video.id)
updateSearchTables()
}}
>
O
</Button>
)}
</td>
</tr>
))}
</tbody>
</Table>
</Col>
))}
</Row>
</>
)}
</div>
)
}
Example #7
Source File: WatchView.tsx From 3Speak-app with GNU General Public License v3.0 | 4 votes |
export function WatchView(props: any) {
const player = useRef<any>()
const [videoInfo, setVideoInfo] = useState<any>({})
const [postInfo, setPostInfo] = useState<any>({})
const [profilePictureURL, setProfilePictureUrl] = useState(EmptyProfile)
const [commentGraph, setCommentGraph] = useState()
const [videoLink, setVideoLink] = useState('')
const [recommendedVideos, setRecommendedVideos] = useState([])
const [loaded, setLoaded] = useState(false)
const [loadingMessage, setLoadingMessage] = useState('')
const [rootCid, setRootCid] = useState()
const reflink = useMemo(() => {
return props.match.params.reflink
}, [])
const reflinkParsed = useMemo(() => {
return RefLink.parse(reflink) as any
}, [reflink])
const generalFetch = async () => {
const info = await AccountService.permalinkToVideoInfo(reflink, { type: 'video' })
setVideoInfo(info)
setPostInfo(await AccountService.permalinkToPostInfo(reflink))
try {
//Leave profileURL default if error is thrown when attempting to retrieve profile picture
setProfilePictureUrl(await AccountService.getProfilePictureURL(reflink))
} catch (ex) {
console.error(ex)
throw ex
}
document.title = `3Speak - ${info.title}`
const cids = []
for (const source of info.sources) {
const url = new URL(source.url)
try {
new CID(url.host)
cids.push(url.host)
} catch {}
}
setRootCid(cids[0])
}
const mountPlayer = async () => {
try {
const playerType = 'standard'
switch (playerType) {
case 'standard': {
setVideoLink(await VideoService.getVideoSourceURL(reflink))
}
}
recordView()
} catch (ex) {
console.error(ex)
}
}
const recordView = async () => {
return
/*let cids = [];
for(const source of videoInfo.sources) {
const url = new (require('url').URL)(source.url)
try {
new CID(url.host)
cids.push(url.host)
} catch {
}
}
console.log(`CIDs to cache ${JSON.stringify(cids)}`)
if(cids.length !== 0) {
await PromiseIpc.send("pins.add", {
_id: reflink,
source: "Watch Page",
cids,
expire: (new Date().getTime()) + convert("1").from("d").to("ms"),
meta: {
title: videoInfo.title
}
})
}*/
}
const gearSelect = async (eventKey) => {
switch (eventKey) {
case 'mute_post': {
await PromiseIpc.send('blocklist.add', reflinkParsed.toString())
break
}
case 'mute_user': {
await PromiseIpc.send(
'blocklist.add',
`${reflinkParsed.source.value}:${reflinkParsed.root}` as any,
)
break
}
}
}
const retrieveRecommended = async () => {
const query = knex.raw(
`SELECT TOP 25 x.* FROM DBHive.dbo.Comments x WHERE CONTAINS(json_metadata , '3speak/video') AND category LIKE '${postInfo.category}' ORDER BY NEWID()`,
)
const blob = []
query.stream().on('data', async (val) => {
if (await PromiseIpc.send('blocklist.has', `hive:${val.author}:${val.permlink}` as any)) {
console.log(`${val.author} is blocked`)
return
}
val.json_metadata = JSON.parse(val.json_metadata)
//console.log(val)
if (!val.json_metadata.video) {
val.json_metadata.video = {
info: {},
}
}
let thumbnail
if (val.json_metadata.sourceMap) {
thumbnail = Finder.one.in(val.json_metadata.sourceMap).with({ type: 'thumbnail' }).url
console.log(thumbnail)
}
blob.push({
reflink: `hive:${val.author}:${val.permlink}`,
created: val.created,
author: val.author,
permlink: val.permlink,
tags: val.json_metadata.tags,
title: val.title,
duration: val.json_metadata.video.info.duration || val.json_metadata.video.duration,
isIpfs: val.json_metadata.video.info.ipfs || thumbnail ? true : false,
ipfs: val.json_metadata.video.info.ipfs,
images: {
ipfs_thumbnail: thumbnail
? `/ipfs/${thumbnail.slice(7)}`
: `/ipfs/${val.json_metadata.video.info.ipfsThumbnail}`,
thumbnail: `https://threespeakvideo.b-cdn.net/${val.permlink}/thumbnails/default.png`,
poster: `https://threespeakvideo.b-cdn.net/${val.permlink}/poster.png`,
post: `https://threespeakvideo.b-cdn.net/${val.permlink}/post.png`,
},
views: val.total_vote_weight ? Math.log(val.total_vote_weight / 1000).toFixed(2) : 0,
})
setRecommendedVideos(blob)
})
query.on('query-response', (ret, det, aet) => {
console.log(ret, det, aet)
})
query.on('end', (err) => {
console.log(err)
})
/*
let ref = RefLink.parse(reflink)
let data = (await axios.get(`https://3speak.tv/apiv2/recommended?v=${ref.root}/${ref.permlink}`)).data
data.forEach((value => {
let link = value.link.split("=")[1].split("/")
value.reflink = `hive:${link[0]}:${link[1]}`
}))*/
}
const PinLocally = async () => {
const cids = []
for (const source of videoInfo.sources) {
const url = new URL(source.url)
try {
new CID(url.host)
cids.push(url.host)
} catch {}
}
debug(`CIDs to store ${JSON.stringify(cids)}`)
if (cids.length !== 0) {
NotificationManager.info('Pinning in progress')
await PromiseIpc.send('pins.add', {
_id: reflink,
source: 'Watch Page',
cids,
expire: null,
meta: {
title: videoInfo.title,
},
} as any)
NotificationManager.success(
`Video with reflink of ${reflink} has been successfully pinned! Thank you for contributing!`,
'Pin Successful',
)
} else {
NotificationManager.warning('This video is not available on IPFS')
}
}
const showDebug = () => {
const metadata = videoInfo
Popup.registerPlugin('watch_debug', async function () {
this.create({
content: (
<div>
<Tabs defaultActiveKey="meta" id="uncontrolled-tab-example">
<Tab eventKey="meta" title="Metadata">
<Editor value={metadata} ace={ace} theme="ace/theme/github"></Editor>
</Tab>
</Tabs>
</div>
),
buttons: {
right: [
{
text: 'Close',
className: 'success',
action: function () {
Popup.close()
},
},
],
},
})
})
Popup.plugins().watch_debug()
}
useEffect(() => {
const load = async () => {
try {
await generalFetch()
setLoadingMessage('Loading: Mounting player...')
await mountPlayer()
} catch (ex) {
setLoadingMessage('Loading resulted in error')
throw ex
}
setLoaded(true)
await retrieveRecommended()
}
void load()
}, [])
useEffect(() => {
window.scrollTo(0, 0)
const update = async () => {
await generalFetch()
await mountPlayer()
await retrieveRecommended()
player.current?.ExecUpdate()
}
void update()
}, [reflink])
return (
<div>
{loaded ? (
<Container fluid>
{/* <Container fluid pb={0}> */}
{/* <Row fluid="md"> */}
<Row>
<Col md={8}>
<div>
<Player reflink={reflink}></Player>
</div>
<div className="single-video-title box mb-3 clearfix">
<div className="float-left">
<h2 style={{ fontSize: '18px' }}>
<a>{videoInfo.title}</a>
</h2>
<DHTProviders rootCid={rootCid} />
</div>
<div
className="float-right"
style={
{
textAlign: 'right !important',
float: 'right !important',
display: 'inline-block !important',
} as any
}
>
<span>
<VoteWidget reflink={reflink} />
</span>
<Dropdown onSelect={gearSelect} style={{ paddingTop: '10px' }}>
<Dropdown.Toggle
as={CustomToggle}
id="dropdown-custom-components"
></Dropdown.Toggle>
<Dropdown.Menu>
<Dropdown.Item eventKey="mute_post">
<p style={{ color: 'red' }}>Mute Post</p>
</Dropdown.Item>
<Dropdown.Item eventKey="mute_user">
<p style={{ color: 'red' }}>Mute User</p>
</Dropdown.Item>
</Dropdown.Menu>
</Dropdown>
</div>
</div>
<div className="single-video-author box mb-3">
<div className="float-right">
<Row>
<FollowWidget reflink={reflink} />
<a
target="_blank"
style={{ marginRight: '5px', marginLeft: '5px' }}
className="btn btn-light btn-sm"
onClick={PinLocally}
>
<FaDownload /> Download to IPFS node
</a>
<a
target="_blank"
style={{ marginRight: '5px' }}
className="btn btn-light btn-sm"
href={(() => {
const videoSource = Finder.one.in(videoInfo.sources).with({
format: 'mp4',
})
if (videoSource) {
return videoSource.url
}
})()}
>
<FaDownload /> Download
</a>
</Row>
</div>
<img className="img-fluid" src={profilePictureURL} alt="" />
<p>
<a href={`#/user/${reflinkParsed.source.value}:${reflinkParsed.root}`}>
<strong>{postInfo.author}</strong>
</a>
</p>
<small>
Published on{' '}
{(() => {
const pattern = DateTime.compile('MMMM D, YYYY')
return DateTime.format(new Date(videoInfo.creation), pattern)
})()}
</small>
</div>
<div className="single-video-info-content box mb-3">
<h6>About :</h6>
<CollapsibleText>
<ReactMarkdown
escapeHtml={false}
source={DOMPurify.sanitize(videoInfo.description)}
></ReactMarkdown>
<hr />
<Container style={{ marginBottom: '10px', textAlign: 'center' }}>
<a
target="_blank"
style={{ marginRight: '5px' }}
className="btn btn-light btn-sm"
onClick={() => showDebug()}
>
<BsInfoSquare /> Debug Info
</a>
</Container>
</CollapsibleText>
<h6>Tags: </h6>
<p className="tags mb-0">
{(() => {
const out = []
if (videoInfo.tags) {
for (const tag of videoInfo.tags) {
out.push(
<span style={{ paddingLeft: '3px' }} key={tag}>
<a>{tag}</a>
</span>,
)
}
}
return out
})()}
</p>
</div>
<CommentSection reflink={reflink.toString()} />
</Col>
<Col md={4}>
<Row>
<Col md={12}>
{recommendedVideos.map((value) => (
<VideoTeaser key={value.reflink} reflink={value.reflink} />
))}
</Col>
</Row>
</Col>
</Row>
</Container>
) : (
<div>
<LoopCircleLoading />
<div
style={{
textAlign: 'center',
margin: 'auto',
position: 'absolute',
left: '0px',
right: '0px',
top: '60%',
bottom: '0px',
}}
>
<h1 style={{ top: '60%', fontSize: '20px' }}>{loadingMessage}</h1>
</div>
</div>
)}
</div>
)
}
Example #8
Source File: LabelsPage.tsx From devex with GNU General Public License v3.0 | 4 votes |
LabelsPage: React.FC = () => {
const userPrefContext = useContext(UserPrefContext)
const { labelMap, networkMap, setLabelMap } = userPrefContext!
const [searchFilter, setSearchFilter] = useState('')
const [typefilter, setTypefilter] = useState('All')
const [networkNameFilter, setNetworkNameFilter] = useState('All')
return (
<>
<Container>
<Row className='m-0'>
<h4>
Labels
</h4>
</Row>
<Row className='m-0 pb-3'>
<span className='subtext'>Label data is stored in your browser's local storage.</span>
</Row>
<Row className='justify-content-between flex-nowrap m-0'>
<div className='filter-div'>
<span>
Network:
</span>
<Dropdown className="ml-3">
<Dropdown.Toggle id="label-network-toggle">
{networkMap.get(networkNameFilter) || defaultNetworks.get(networkNameFilter) || networkNameFilter}
</Dropdown.Toggle>
<Dropdown.Menu>
<Dropdown.Item onClick={() => setNetworkNameFilter('All')}>All</Dropdown.Item>
{
[...new Set(Object.values(labelMap).map(label => label.networkName))]
.map((labelName, index) => (
<Dropdown.Item onClick={() => setNetworkNameFilter(labelName)} key={index}>{labelName}</Dropdown.Item>
))
}
</Dropdown.Menu>
</Dropdown>
<span className='ml-3'>
Label Type:
</span>
<Dropdown className="ml-3">
<Dropdown.Toggle id="label-type-toggle">{typefilter}</Dropdown.Toggle>
<Dropdown.Menu>
<Dropdown.Item onClick={() => setTypefilter('All')}>All</Dropdown.Item>
<Dropdown.Item onClick={() => setTypefilter('Account')}>Accounts</Dropdown.Item>
<Dropdown.Item onClick={() => setTypefilter('Contract')}>Contracts</Dropdown.Item>
<Dropdown.Item onClick={() => setTypefilter('Transaction')}>Transactions</Dropdown.Item>
<Dropdown.Item onClick={() => setTypefilter('Tx Block')}>Tx Blocks</Dropdown.Item>
<Dropdown.Item onClick={() => setTypefilter('DS Block')}>DS Blocks</Dropdown.Item>
</Dropdown.Menu>
</Dropdown>
<Form.Control
className='search-filter-form'
type="text"
value={searchFilter}
autoFocus
placeholder='Search for label'
onChange={(e: React.ChangeEvent<HTMLInputElement>) => { setSearchFilter(e.target.value) }} />
</div>
<ImportExport
type='labels'
map={labelMap}
setMapCb={setLabelMap}
/>
</Row>
<Row className='mt-3'>
{Object.entries(labelMap).length === 0
? <Dropzone
fromJson={(x: any) => x}
dropCb={setLabelMap} />
: Object.entries(labelMap)
.filter(([, v]) => (typefilter === 'All' || v.type === typefilter))
.filter(([, v]) => (networkNameFilter === 'All' || v.networkName === networkNameFilter))
.filter(([, v]) => (v.name.includes(searchFilter)))
.map(([k, v]) => (
<Col className='my-3' key={k} md={6} lg={4} >
<LabelCard k={k} v={v} />
</Col>
))}
</Row>
</Container>
</>
)
}
Example #9
Source File: Shop.tsx From apps with MIT License | 4 votes |
ShopTab = ({ region, shops, filters, onChange, itemCache, questCache }: IProps) => {
let [forceEnablePlanner, setForceEnablePlanner] = useState<boolean | undefined>(undefined);
let [itemFilters, setItemFilters] = useState(new Set<number>());
const allItems = new Map(shops.map((shop) => [shop.cost.item.id, shop.cost.item]));
let shopEnabled = forceEnablePlanner === undefined ? Manager.shopPlannerEnabled() : forceEnablePlanner;
let counted = shops
.filter((shop) => (shopEnabled ? filters.has(shop.id) : true))
.map(
(shop) =>
[shop.cost.item, (shopEnabled ? filters.get(shop.id)! : shop.limitNum) * shop.cost.amount] as const
);
let items = new Map(counted.map((tuple) => [tuple[0].id, tuple[0]]));
let amounts = new Map<number, number>();
for (let [item, amount] of counted)
if (amounts.has(item.id)) amounts.set(item.id, (amounts.get(item.id) ?? 0) + amount);
else amounts.set(item.id, amount);
// reset filter if nothing is chosen
if (!amounts.size && itemFilters.size) setItemFilters(new Set());
const excludeItemIds = (itemIds: number[]) => {
return new Map(
shops
.filter((shop) => shop.payType !== Shop.PayType.FREE)
.filter((shop) => shop.limitNum !== 0)
.filter((shop) => !itemIds.includes(shop.targetIds[0]) || shop.purchaseType !== Shop.PurchaseType.ITEM)
.map((shop) => [shop.id, shop.limitNum])
);
};
return (
<>
<Alert variant="success" style={{ margin: "1em 0", display: "flex" }}>
<div style={{ flexGrow: 1 }}>
{shopEnabled
? amounts.size > 0
? "Total amount for chosen items: "
: "No item was chosen. Choose at least one to get calculations."
: "Total currency amount needed to clear the shop: "}
{[...amounts]
.filter(([_, amount]) => amount > 0)
.map(([itemId, amount]) => (
<span style={{ whiteSpace: "nowrap", paddingRight: "1ch" }} key={itemId}>
<IconLink region={region} item={items.get(itemId)!} />
<b>×{amount.toLocaleString()}</b>
</span>
))}
</div>
<div style={{ flexBasis: "auto", paddingLeft: "10px" }}>
<Button
variant={shopEnabled ? "dark" : "success"}
onClick={() => setForceEnablePlanner(!forceEnablePlanner)}
>
<FontAwesomeIcon icon={faEdit} title={shopEnabled ? "Disable planner" : "Enable planner"} />
</Button>
</div>
</Alert>
{shopEnabled && (
<>
<ButtonGroup>
<Button disabled variant="outline-dark">
Quick toggle
</Button>
<Button variant="outline-success" onClick={() => onChange?.(excludeItemIds([]))}>
All
</Button>
<Button variant="outline-success" onClick={() => onChange?.(new Map())}>
None
</Button>
<Dropdown as={ButtonGroup}>
<Dropdown.Toggle variant="outline-success">Exclude</Dropdown.Toggle>
<Dropdown.Menu>
<Dropdown.Item
as={Button}
onClick={() =>
onChange?.(excludeItemIds([...gemIds, ...magicGemIds, ...secretGemIds]))
}
>
Gems
</Dropdown.Item>
<Dropdown.Item
as={Button}
onClick={() => onChange?.(excludeItemIds([...monumentIds, ...pieceIds]))}
>
Monuments & Pieces
</Dropdown.Item>
<Dropdown.Item as={Button} onClick={() => onChange?.(excludeItemIds(monumentIds))}>
Monuments
</Dropdown.Item>
<Dropdown.Item as={Button} onClick={() => onChange?.(excludeItemIds(pieceIds))}>
Pieces
</Dropdown.Item>
</Dropdown.Menu>
</Dropdown>
</ButtonGroup>
<div> </div>
</>
)}
<Table hover responsive className="shopTable">
<thead>
<tr>
<th style={{ textAlign: "left" }}>Detail</th>
<th style={{ whiteSpace: "nowrap" }}>
Currency
<Dropdown as={ButtonGroup}>
<Dropdown.Toggle size="sm">
<FontAwesomeIcon style={{ display: "inline" }} icon={faFilter} />
</Dropdown.Toggle>
<Dropdown.Menu>
{/* Actually a checkbox is the best here */}
<Dropdown.Item
as={Button}
onClick={() => {
setItemFilters(new Set());
}}
>
Reset
</Dropdown.Item>
{[...allItems].map(([itemId, item]) => (
<Dropdown.Item
key={item.id}
as={Button}
onClick={() => {
setItemFilters(new Set([itemId]));
}}
>
<ItemIcon region={region} item={item} height={40} />
{item.name}
</Dropdown.Item>
))}
</Dropdown.Menu>
</Dropdown>
</th>
<th>Cost</th>
<th>Item</th>
<th>Set</th>
<th>Limit</th>
{shopEnabled && <th>Target</th>}
</tr>
</thead>
<tbody>
{shops
.filter((shop) =>
itemFilters.size && amounts.size ? itemFilters.has(shop.cost.item.id) : true
)
.sort((a, b) => a.priority - b.priority)
.map((shop) => {
let limitNumIndicator = shopEnabled ? (
<Button
variant="light"
onClick={() => {
filters.set(shop.id, shop.limitNum);
onChange?.(filters);
}}
>
{shop.limitNum.toLocaleString()}
</Button>
) : (
<>{shop.limitNum.toLocaleString()}</>
);
return (
<tr key={shop.id}>
<td style={{ minWidth: "10em" }}>
<b>{shop.name}</b>
<div style={{ fontSize: "0.75rem" }} className="newline">
{colorString(shop.detail)}
<ScriptLink region={region} shop={shop} />
<br />
<div>
{shop.releaseConditions.length ? (
<ul className="condition-list">
{shop.releaseConditions.map((cond, index) => (
<li key={index} style={{ fontSize: "0.75rem" }}>
{cond.closedMessage && `${cond.closedMessage} — `}
<CondTargetNumDescriptor
region={region}
cond={cond.condType}
targets={cond.condValues}
num={cond.condNum}
quests={questCache}
items={itemCache}
/>
</li>
))}
</ul>
) : (
""
)}
</div>
</div>
</td>
<td style={{ textAlign: "center" }}>
{shop.payType !== Shop.PayType.FREE ? (
<IconLink region={region} item={shop.cost.item} />
) : null}
</td>
<td style={{ textAlign: "center" }}>
{shop.payType !== Shop.PayType.FREE ? shop.cost.amount.toLocaleString() : null}
</td>
<td>
<ShopPurchaseDescriptor region={region} shop={shop} itemMap={itemCache} />
</td>
<td style={{ textAlign: "center" }}>{shop.setNum.toLocaleString()}</td>
<td style={{ textAlign: "center" }}>
{shop.limitNum === 0 ? <>Unlimited</> : limitNumIndicator}
</td>
{shopEnabled && (
<>
<td style={{ textAlign: "center", maxWidth: "5em" }}>
<InputGroup size="sm">
<Form.Control
type="number"
value={filters.get(shop.id) ?? 0}
min={0}
max={shop.limitNum || undefined}
onChange={(event) => {
let value = +event.target.value;
if (value) filters.set(shop.id, value);
else filters.delete(shop.id);
onChange?.(filters);
}}
/>
</InputGroup>
</td>
</>
)}
</tr>
);
})}
</tbody>
</Table>
</>
);
}
Example #10
Source File: ServantVoiceLines.tsx From apps with MIT License | 4 votes |
VoiceLinesTable = ({
region,
voice,
mergedDownloadNamePrefix,
servants,
costumes,
}: {
region: Region;
voice: Profile.VoiceGroup;
mergedDownloadNamePrefix: string;
servants: Map<number, Servant.ServantBasic>;
costumes?: {
[key: string]: Profile.CostumeDetail;
};
}) => {
const voiceLines = voice.voiceLines.sort((a, b) => (b.priority || 0) - (a.priority || 0));
const voiceLineNames: string[] = [];
const voiceNameCount: Record<string, number> = {};
for (const line of voiceLines) {
line.conds = line.conds.filter(
(cond) => !(cond.condType === Profile.VoiceCondType.EVENT_END && cond.value === 0)
);
let lineName = line.overwriteName || line.name || "";
if (lineName in voiceNameCount) {
voiceNameCount[lineName]++;
} else {
voiceNameCount[lineName] = 1;
}
voiceLineNames.push(lineName.replace("{0}", voiceNameCount[lineName].toString()));
}
return (
<Table bordered className="mb-0">
<tbody>
{voiceLines.map((line, index) => (
<tr key={`line_${index}`}>
<td style={{ verticalAlign: "middle" }}>
<b className="newline">{voiceLineNames[index]}</b>
<br />
<div className="newline">
{voiceTextField(region, voice.type) ? (
line.text.map((line, i) => (
<VoiceSubtitleFormat key={i} region={region} inputString={line} />
))
) : (
<VoiceSubtitleFormat region={region} inputString={line.subtitle} />
)}
</div>
{line.conds.length || line.playConds.length || line.summonScript ? (
<>
<Alert variant="info" style={{ marginBottom: 0, marginTop: "1em" }}>
{line.summonScript === undefined ? null : (
<>
Summoning Script:{" "}
<ScriptDescriptor
region={region}
scriptId={line.summonScript.scriptId}
scriptType=""
/>
</>
)}
{line.conds.length > 1 && (
<>
<b>Unlock Requirements (all of the following):</b>
<br />
<ul style={{ marginBottom: 0 }}>
{line.conds.map((cond, index) => (
<li key={index}>
<VoiceCondTypeDescriptor
region={region}
servants={servants}
costumes={costumes}
cond={cond}
/>
</li>
))}
</ul>
</>
)}
{line.conds.length === 1 && (
<>
<b>Unlock Requirement:</b>
<br />
<VoiceCondTypeDescriptor
region={region}
servants={servants}
costumes={costumes}
cond={line.conds[0]}
/>
<br />
</>
)}
<VoicePlayCondDescriptor
region={region}
playConds={line.playConds}
servants={servants}
/>
</Alert>
</>
) : (
""
)}
</td>
<td style={{ verticalAlign: "middle", width: "1px" }}>
<ButtonGroup>
<VoiceLinePlayer
audioAssetUrls={line.audioAssets}
delay={line.delay}
title={voiceLineNames[index]}
/>
<Dropdown as={ButtonGroup}>
<Dropdown.Toggle variant={"info"} title={`Download ${voiceLineNames[index]}`}>
<FontAwesomeIcon icon={faFileAudio} />
</Dropdown.Toggle>
<Dropdown.Menu title={`Download ${voiceLineNames[index]}`}>
<Dropdown.Item
title={`Download ${voiceLineNames[index]} merged file`}
onClick={() => {
const fileName = `${mergedDownloadNamePrefix} - ${voiceLineNames[index]}`;
mergeVoiceLine(line.audioAssets, line.delay, fileName);
}}
>
Merged
</Dropdown.Item>
{line.audioAssets.map((asset, i) => (
<Dropdown.Item
key={i}
href={asset}
target="_blank"
title={`Download ${voiceLineNames[index]} part ${i + 1}`}
>
Part {i + 1}
</Dropdown.Item>
))}
</Dropdown.Menu>
</Dropdown>
</ButtonGroup>
</td>
</tr>
))}
</tbody>
</Table>
);
}
Example #11
Source File: group-modal.component.tsx From cwa-quick-test-frontend with Apache License 2.0 | 4 votes |
GroupModal = (props: any) => { const [btnOkDisabled, setBtnOkDisabled] = React.useState(true); const { t } = useTranslation(); const { keycloak } = useKeycloak(); const [data, setData] = React.useState(''); const [validated, setValidated] = React.useState(false); const [isReady, setIsReady] = React.useState(false); const [isNew, setIsNew] = React.useState(true); const [options, setOptions] = React.useState<JSX.Element[]>(); const [dropdownItems, setDropdownItems] = React.useState<JSX.Element[]>(); const [dropdownList] = React.useState<string[]>(['https://', 'http://']); const [selectedDropdownValue, setSelectedDropdownValue] = React.useState<string>(dropdownList[0]); const [websiteValue, setWebsiteValue] = React.useState(''); const [displayOpeningHours, setDisplayOpeningHours] = React.useState(''); const [errorOpeningHour, setErrorOpeningHour] = React.useState(''); const groupReloaded = (group: IGroupDetails) => { if (group) { setData(unpackData(group.pocDetails)) group.parentGroup = props.parentGroupId; if (group.website) { let website = ''; for (const item of dropdownList) { if (group.website.startsWith(item)) { website = group.website.slice(item.length, group.website.length); setSelectedDropdownValue(item); } } setWebsiteValue(website); } else { setWebsiteValue(''); setSelectedDropdownValue(dropdownList[0]); } } setBtnOkDisabled(false); } const [group, updateGroup, setGroup] = useGetGroupDetails(groupReloaded, props.handleError); React.useEffect(() => { getDropdownItems(); // eslint-disable-next-line react-hooks/exhaustive-deps }, []) React.useEffect(() => { if (group) { setOptions(getOptions()); setDisplayOpeningHours( group.openingHours?.map( (element: string) => element) .join('\n') ); setIsReady(true); } setIsNew(!(group && group.id)); // eslint-disable-next-line react-hooks/exhaustive-deps }, [group]) React.useEffect(() => { setValidated(props.isSuccess) // eslint-disable-next-line react-hooks/exhaustive-deps }, [props.isSuccess]); React.useEffect(() => { if (props.isCreationError) { setBtnOkDisabled(false) } // eslint-disable-next-line react-hooks/exhaustive-deps }, [props.isCreationError]); const handleCancel = () => { setErrorOpeningHour(''); props.onCancel(); } const unpackData = (data: string) => { if (data) { data = data.replaceAll(',', '\n') } else { data = '' } return data; } const packData = (data: string) => { if (data) { data = data.replaceAll('\n', ',') } return data; } const handleOk = () => { if (props.handleOk) { setBtnOkDisabled(true); group.pocDetails = packData(data); if (websiteValue && ( websiteValue.startsWith('www.') || !( websiteValue.startsWith(dropdownList[0]) || websiteValue.startsWith(dropdownList[1]) ) )) { group.website = selectedDropdownValue + websiteValue; } else { group.website = websiteValue; } props.handleOk(group); } } const handleEnter = () => { if (props.onEnter) { props.onEnter(); } setBtnOkDisabled(false); if (props.groupId) { updateGroup(props.groupId); } else { setGroup({ ...emptyGroup }); setSelectedDropdownValue(dropdownList[0]); setData(''); setWebsiteValue(''); } } const handleExited = () => { setIsReady(false); props.onExit(); } const handleSubmit = (event: React.FormEvent<HTMLFormElement>) => { const form = event.currentTarget; event.preventDefault(); event.stopPropagation(); if (errorOpeningHour) { document.getElementById('formPocOpeningHours')?.focus(); return; } if (form.checkValidity()) { handleOk(); } } const updateGroupProp = (name: string, value: any) => { const ngroup = { ...group, [name]: value }; setGroup({ ...ngroup }); } const changeOpeningHoursHandler = (name: string, value: string) => { setDisplayOpeningHours(value); let error = undefined; const openingHours = value.split('\n'); if (openingHours.length > 7) { setErrorOpeningHour('opening-hours-to-much-lines-error'); return; } error = openingHours.find(element => { return !utils.isOpeningHoursValid(element); }); if (error) { setErrorOpeningHour('openening-hours-to-long-error'); } else { setErrorOpeningHour(''); updateGroupProp("openingHours", openingHours); } } const updateSearchPortalConsent = (name: string, value: any) => { const ngroup: IGroupDetails = { ...group, [name]: value }; if (value === false) { ngroup.email = ''; ngroup.website = ''; ngroup.openingHours = []; ngroup.appointmentRequired = false; } setGroup(ngroup); } const collectChildren = (idlist: string[], parentNode: IGroup) => { if (parentNode) { idlist.push(parentNode.id); parentNode.children.forEach(child => collectChildren(idlist, child as IGroup)); } } const getOptions = (): JSX.Element[] => { let result: JSX.Element[] = []; if (group && group.id) { const node = props.groups.find((groupNode: IGroupNode) => groupNode.group.id === group.id); const selfIdOrChildren: string[] = []; if (node) { collectChildren(selfIdOrChildren, node.group); } const fList = props.groups.filter((groupNode: IGroupNode) => selfIdOrChildren.indexOf(groupNode.group.id) < 0) result = fList.map((groupNode: IGroupNode) => <option key={groupNode.group.id} value={groupNode.group.id}>{"\u00A0\u00A0\u00A0\u00A0".repeat(groupNode.level) + groupNode.group.name}</option> ); // result.push(<option key="empty" value="empty">{t('translation:no-parentgroup-option')}</option>); } return result; } const getDropdownItems = () => { setDropdownItems( dropdownList.map( (item: string) => <Dropdown.Item onSelect={(eventKey: any) => setSelectedDropdownValue(eventKey)} eventKey={item} key={item} > {item} </Dropdown.Item>)); } return ( <Modal contentClassName='data-modal' size="lg" show={props.show} backdrop="static" keyboard={false} centered onEnter={handleEnter} onExited={handleExited} > {!isReady ? <CwaSpinner background='#eeeeee' /> : <Fade appear={true} in={true} > <Form className='form-flex' onSubmit={handleSubmit} validated={validated} > <Modal.Header id='data-header' className='pb-0' > <Modal.Title>{isNew ? t('translation:add-group') : t('translation:edit-group')}</Modal.Title> </Modal.Header> <Modal.Body className='bg-light'> {isNew ? <></> : <> <FormGroupSelect controlId='formGroupSelect' title={t('translation:parentgroup')} placeholder={t('translation:no-parentgroup-option')} value={group.parentGroup} onChange={(ent: any) => updateGroupProp('parentGroup', ent.target.value)} options={options} /> <hr /> </> } < FormGroupInput controlId='formFirstName' title={t('translation:name')} value={group ? group.name : ''} required onChange={(evt: any) => { updateGroupProp('name', evt.target.value); props.resetError(); }} maxLength={45} isInvalid={props.isCreationError} InvalidText={t('translation:group-conflict-error')} /> {/* <hr /> */} < FormGroupTextarea controlId='formAdressData' title={t('translation:address-testcenter')} placeholder={t('translation:address-testcenter-placeholder')} value={data} required onChange={(evt: any) => setData(evt.target.value)} type='textarea' maxLength={300} /> {utils.hasRole(keycloak, 'c19_quick_test_poc_nat_admin') ? <FormGroupPermissionCkb controlId='formenablePcr' title={t('translation:enablePcr')} //label={t('translation:for-counter')} onChange={(evt: any) => updateSearchPortalConsent('enablePcr', evt.currentTarget.checked)} type='checkbox' checked={group.enablePcr} /> : <></> } <hr /> {/* < FormGroupInput controlId='formBSNRInput' title={t('translation:bsnr')} placeholder={t('translation:bsnr-placeholder')} value={group ? group.bsnr : ''} onChange={(evt: any) => { updateGroupProp('bsnr', evt.target.value); props.resetError(); }} maxLength={9} prepend='i' tooltip={t('translation:bsnr-tooltip')} pattern={utils.pattern.BSNR} /> */} <FormGroupPermissionCkb controlId='formsearchPortalConsent' title={t('translation:searchPortalConsent')} //label={t('translation:for-counter')} onChange={(evt: any) => updateSearchPortalConsent('searchPortalConsent', evt.currentTarget.checked)} type='checkbox' checked={group.searchPortalConsent} /> <Collapse in={group.searchPortalConsent}> <div> < FormGroupInput controlId='formEmailInput' title={t('translation:email-address')} value={group?.email ? group.email : ''} onChange={(evt: any) => { updateGroupProp('email', evt.target.value); props.resetError(); }} type='email' pattern={utils.pattern.eMail} minLength={5} maxLength={255} /> < FormGroupInput controlId='formPocWebsite' title={t('translation:searchPortalWebsite')} placeholder={t('translation:searchPortalWebsitePlaceholder')} value={websiteValue} dropdown={dropdownItems} dropdownTitle={selectedDropdownValue} prepend='i' tooltip={t('translation:searchPortalWebsiteTooltip')} onChange={(evt: any) => { setWebsiteValue(evt.target.value); props.resetError(); }} maxLength={100} pattern={utils.pattern.url} /> < FormGroupTextarea controlId='formPocOpeningHours' title={t('translation:searchPortalOpeningHours')} value={displayOpeningHours} onChange={(evt: any) => { changeOpeningHoursHandler('openingHours', evt.target.value); props.resetError(); }} type='textarea' rows={7} pattern={utils.pattern.email} isInvalid={errorOpeningHour} invalidText={errorOpeningHour && t('translation:' + errorOpeningHour)} /> <FormGroupPermissionCkb controlId='formAppointmentRequired' title={t('translation:searchPortalAppointmentRequired')} onChange={(evt: any) => updateGroupProp('appointmentRequired', evt.currentTarget.checked)} type='checkbox' checked={group?.appointmentRequired ? group.appointmentRequired : false} /> </div> </Collapse> {!(group && group.pocId) ? <></> : <> <hr /> < FormGroupInput controlId='formPocId' title={t('translation:poc-id')} value={group && group.pocId ? group.pocId : ''} readOnly /> </> } </Modal.Body> <Modal.Footer id='data-footer'> <Container className='p-0'> <Row> <Col sm='6' lg='4' className='mb-2 mb-sm-0 p-0 pr-sm-2'> <Button className='p-0' block variant='outline-primary' onClick={handleCancel} > {t('translation:cancel')} </Button> </Col> <Col sm='6' lg='4' className='p-0 pl-sm-2'> <Button className='p-0' block type='submit' disabled={btnOkDisabled} > {isNew ? t('translation:add') : t('translation:edit')} <Spinner as="span" className='btn-spinner' animation="border" hidden={!btnOkDisabled} size="sm" role="status" aria-hidden="true" /> </Button> </Col> </Row> </Container> </Modal.Footer> </Form> </Fade> } </Modal> ) }
Example #12
Source File: index.tsx From nouns-monorepo with GNU General Public License v3.0 | 4 votes |
NavLocaleSwitcher: React.FC<NavLocalSwitcherProps> = props => {
const { buttonStyle } = props;
const [buttonUp, setButtonUp] = useState(false);
const history = useHistory();
const [showLanguagePickerModal, setShowLanguagePickerModal] = useState(false);
const activeLocale = useActiveLocale();
const statePrimaryButtonClass = usePickByState(
navDropdownClasses.whiteInfo,
navDropdownClasses.coolInfo,
navDropdownClasses.warmInfo,
history,
);
const stateSelectedDropdownClass = usePickByState(
navDropdownClasses.whiteInfoSelected,
navDropdownClasses.dropdownActive,
navDropdownClasses.dropdownActive,
history,
);
const buttonStyleTop = usePickByState(
navDropdownClasses.whiteInfoSelectedTop,
navDropdownClasses.coolInfoSelected,
navDropdownClasses.warmInfoSelected,
history,
);
const buttonStyleBottom = usePickByState(
navDropdownClasses.whiteInfoSelectedBottom,
navDropdownClasses.coolInfoSelected,
navDropdownClasses.warmInfoSelected,
history,
);
const customDropdownToggle = React.forwardRef<RefType, Props>(({ onClick, value }, ref) => (
<>
<div
className={clsx(
navDropdownClasses.wrapper,
buttonUp ? stateSelectedDropdownClass : statePrimaryButtonClass,
)}
onClick={e => {
e.preventDefault();
onClick(e);
}}
>
<div className={navDropdownClasses.button}>
<div className={navDropdownClasses.dropdownBtnContent}>
{<FontAwesomeIcon icon={faGlobe} />}
</div>
<div className={buttonUp ? navDropdownClasses.arrowUp : navDropdownClasses.arrowDown}>
<FontAwesomeIcon icon={buttonUp ? faSortUp : faSortDown} />{' '}
</div>
</div>
</div>
</>
));
const CustomMenu = React.forwardRef((props: CustomMenuProps, ref: React.Ref<HTMLDivElement>) => {
return (
<div
ref={ref}
style={props.style}
className={props.className}
aria-labelledby={props.labeledBy}
>
{SUPPORTED_LOCALES.map((locale: SupportedLocale, index: number) => {
let dropDownStyle;
let buttonStyle;
switch (index) {
case 0:
dropDownStyle = classes.dropDownTop;
buttonStyle = buttonStyleTop;
break;
case SUPPORTED_LOCALES.length - 1:
dropDownStyle = classes.dropDownBottom;
buttonStyle = buttonStyleBottom;
break;
default:
dropDownStyle = classes.dropDownInterior;
buttonStyle = buttonStyleBottom;
}
return (
<div
className={clsx(
navDropdownClasses.button,
navDropdownClasses.dropdownPrimaryText,
buttonStyle,
dropDownStyle,
classes.desktopLanguageButton,
)}
onClick={() => setLocale(locale)}
>
{LOCALE_LABEL[locale]}
{activeLocale === locale && <FontAwesomeIcon icon={faCheck} height={24} width={24} />}
</div>
);
})}
</div>
);
});
return (
<>
{showLanguagePickerModal && (
<LanguageSelectionModal onDismiss={() => setShowLanguagePickerModal(false)} />
)}
<div
className={clsx(navDropdownClasses.nounsNavLink, responsiveUiUtilsClasses.mobileOnly)}
onClick={() => setShowLanguagePickerModal(true)}
>
<NavBarButton
buttonText={<Trans>Language</Trans>}
buttonIcon={<FontAwesomeIcon icon={faGlobe} />}
buttonStyle={buttonStyle}
/>
</div>
<Dropdown
className={clsx(navDropdownClasses.nounsNavLink, responsiveUiUtilsClasses.desktopOnly)}
onToggle={() => setButtonUp(!buttonUp)}
autoClose={true}
>
<Dropdown.Toggle as={customDropdownToggle} id="dropdown-custom-components" />
<Dropdown.Menu className={`${navDropdownClasses.desktopDropdown} `} as={CustomMenu} />
</Dropdown>
</>
);
}
Example #13
Source File: index.tsx From nouns-monorepo with GNU General Public License v3.0 | 4 votes |
NavWallet: React.FC<NavWalletProps> = props => {
const { address, buttonStyle } = props;
const [buttonUp, setButtonUp] = useState(false);
const [showConnectModal, setShowConnectModal] = useState(false);
const history = useHistory();
const { library: provider } = useEthers();
const activeAccount = useAppSelector(state => state.account.activeAccount);
const { deactivate } = useEthers();
const ens = useReverseENSLookUp(address);
const shortAddress = useShortAddress(address);
const activeLocale = useActiveLocale();
const setModalStateHandler = (state: boolean) => {
setShowConnectModal(state);
};
const switchWalletHandler = () => {
setShowConnectModal(false);
setButtonUp(false);
deactivate();
setShowConnectModal(false);
setShowConnectModal(true);
};
const disconectWalletHandler = () => {
setShowConnectModal(false);
setButtonUp(false);
deactivate();
};
const statePrimaryButtonClass = usePickByState(
navDropdownClasses.whiteInfo,
navDropdownClasses.coolInfo,
navDropdownClasses.warmInfo,
history,
);
const stateSelectedDropdownClass = usePickByState(
navDropdownClasses.whiteInfoSelected,
navDropdownClasses.dropdownActive,
navDropdownClasses.dropdownActive,
history,
);
const mobileTextColor = usePickByState(
'rgba(140, 141, 146, 1)',
'rgba(121, 128, 156, 1)',
'rgba(142, 129, 127, 1)',
history,
);
const mobileBorderColor = usePickByState(
'rgba(140, 141, 146, .5)',
'rgba(121, 128, 156, .5)',
'rgba(142, 129, 127, .5)',
history,
);
const connectWalletButtonStyle = usePickByState(
NavBarButtonStyle.WHITE_WALLET,
NavBarButtonStyle.COOL_WALLET,
NavBarButtonStyle.WARM_WALLET,
history,
);
const customDropdownToggle = React.forwardRef<RefType, Props>(({ onClick, value }, ref) => (
<>
<div
className={clsx(
navDropdownClasses.wrapper,
buttonUp ? stateSelectedDropdownClass : statePrimaryButtonClass,
)}
onClick={e => {
e.preventDefault();
onClick(e);
}}
>
<div className={navDropdownClasses.button}>
<div className={classes.icon}>
{' '}
<Davatar size={21} address={address} provider={provider} />
</div>
<div className={navDropdownClasses.dropdownBtnContent}>{ens ? ens : shortAddress}</div>
<div className={buttonUp ? navDropdownClasses.arrowUp : navDropdownClasses.arrowDown}>
<FontAwesomeIcon icon={buttonUp ? faSortUp : faSortDown} />{' '}
</div>
</div>
</div>
</>
));
const CustomMenu = React.forwardRef((props: CustomMenuProps, ref: React.Ref<HTMLDivElement>) => {
return (
<div
ref={ref}
style={props.style}
className={props.className}
aria-labelledby={props.labeledBy}
>
<div>
<div
onClick={switchWalletHandler}
className={clsx(
classes.dropDownTop,
navDropdownClasses.button,
navDropdownClasses.dropdownPrimaryText,
usePickByState(
navDropdownClasses.whiteInfoSelectedTop,
navDropdownClasses.coolInfoSelected,
navDropdownClasses.warmInfoSelected,
history,
),
)}
>
<Trans>Switch wallet</Trans>
</div>
<div
onClick={disconectWalletHandler}
className={clsx(
classes.dropDownBottom,
navDropdownClasses.button,
usePickByState(
navDropdownClasses.whiteInfoSelectedBottom,
navDropdownClasses.coolInfoSelected,
navDropdownClasses.warmInfoSelected,
history,
),
classes.disconnectText,
)}
>
<Trans>Disconnect</Trans>
</div>
</div>
</div>
);
});
const renderENS = (ens: string) => {
if (activeLocale === 'ja-JP') {
return veryShortENS(ens);
}
return shortENS(ens);
};
const renderAddress = (address: string) => {
if (activeLocale === 'ja-JP') {
return veryShortAddress(address);
}
return shortAddress;
};
const walletConnectedContentMobile = (
<div className={clsx(navDropdownClasses.nounsNavLink, responsiveUiUtilsClasses.mobileOnly)}>
<div
className={'d-flex flex-row justify-content-between'}
style={{
justifyContent: 'space-between',
}}
>
<div className={navDropdownClasses.connectContentMobileWrapper}>
<div className={clsx(navDropdownClasses.wrapper, getNavBarButtonVariant(buttonStyle))}>
<div className={navDropdownClasses.button}>
<div className={classes.icon}>
{' '}
<Davatar size={21} address={address} provider={provider} />
</div>
<div className={navDropdownClasses.dropdownBtnContent}>
{ens ? renderENS(ens) : renderAddress(address)}
</div>
</div>
</div>
</div>
<div className={`d-flex flex-row ${classes.connectContentMobileText}`}>
<div
style={{
borderRight: `1px solid ${mobileBorderColor}`,
color: mobileTextColor,
}}
className={classes.mobileSwitchWalletText}
onClick={switchWalletHandler}
>
<Trans>Switch</Trans>
</div>
<div className={classes.disconnectText} onClick={disconectWalletHandler}>
<Trans>Sign out</Trans>
</div>
</div>
</div>
</div>
);
const walletConnectedContentDesktop = (
<Dropdown
className={clsx(navDropdownClasses.nounsNavLink, responsiveUiUtilsClasses.desktopOnly)}
onToggle={() => setButtonUp(!buttonUp)}
>
<Dropdown.Toggle as={customDropdownToggle} id="dropdown-custom-components" />
<Dropdown.Menu className={`${navDropdownClasses.desktopDropdown} `} as={CustomMenu} />
</Dropdown>
);
return (
<>
{showConnectModal && activeAccount === undefined && (
<WalletConnectModal onDismiss={() => setModalStateHandler(false)} />
)}
{activeAccount ? (
<>
{walletConnectedContentDesktop}
{walletConnectedContentMobile}
</>
) : (
<WalletConnectButton
className={clsx(navDropdownClasses.nounsNavLink, navDropdownClasses.connectBtn)}
onClickHandler={() => setModalStateHandler(true)}
buttonStyle={connectWalletButtonStyle}
/>
)}
</>
);
}