4 changed files with 101 additions and 13 deletions
@ -0,0 +1,90 @@
@@ -0,0 +1,90 @@
|
||||
import { Input, Button, Alert, Spin } from 'antd'; |
||||
import { useState } from 'react'; |
||||
|
||||
const ENDPOINT = '/api/remotefollow'; |
||||
|
||||
interface Props { |
||||
handleClose: () => void; |
||||
} |
||||
|
||||
function validateAccount(a) { |
||||
const sanitized = a.replace(/^@+/, ''); |
||||
const regex = |
||||
/^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; |
||||
return regex.test(String(sanitized).toLowerCase()); |
||||
} |
||||
|
||||
export default function FollowModal(props: Props) { |
||||
const { handleClose } = props; |
||||
const [account, setAccount] = useState(null); |
||||
const [valid, setValid] = useState(false); |
||||
const [loading, setLoading] = useState(false); |
||||
const [errorMessage, setErrorMessage] = useState(null); |
||||
|
||||
const handleAccountChange = a => { |
||||
setAccount(a); |
||||
if (validateAccount(a)) { |
||||
setValid(true); |
||||
} else { |
||||
setValid(false); |
||||
} |
||||
}; |
||||
|
||||
const remoteFollowButtonPressed = async () => { |
||||
if (!valid) { |
||||
return; |
||||
} |
||||
|
||||
setLoading(true); |
||||
|
||||
try { |
||||
const sanitizedAccount = account.replace(/^@+/, ''); |
||||
const request = { account: sanitizedAccount }; |
||||
const rawResponse = await fetch(ENDPOINT, { |
||||
method: 'POST', |
||||
body: JSON.stringify(request), |
||||
}); |
||||
const result = await rawResponse.json(); |
||||
|
||||
if (result.redirectUrl) { |
||||
window.open(result.redirectUrl, '_blank'); |
||||
handleClose(); |
||||
} |
||||
if (!result.success) { |
||||
setErrorMessage(result.message); |
||||
setLoading(false); |
||||
return; |
||||
} |
||||
if (!result.redirectUrl) { |
||||
setErrorMessage('Unable to follow.'); |
||||
setLoading(false); |
||||
return; |
||||
} |
||||
} catch (e) { |
||||
setErrorMessage(e.message); |
||||
} |
||||
setLoading(false); |
||||
}; |
||||
|
||||
return ( |
||||
<Spin spinning={loading}> |
||||
{errorMessage && ( |
||||
<Alert message="Follow Error" description={errorMessage} type="error" showIcon /> |
||||
)} |
||||
<Input |
||||
value={account} |
||||
size="large" |
||||
onChange={e => handleAccountChange(e.target.value)} |
||||
placeholder="Your fediverse account @account@server" |
||||
defaultValue={account} |
||||
/> |
||||
<Button disabled={!valid} onClick={remoteFollowButtonPressed}> |
||||
Follow |
||||
</Button> |
||||
<div> |
||||
Information about following a Fediverse account and next steps how to create a Fediverse |
||||
account goes here. |
||||
</div> |
||||
</Spin> |
||||
); |
||||
} |
@ -1,6 +0,0 @@
@@ -1,6 +0,0 @@
|
||||
/* eslint-disable @typescript-eslint/no-unused-vars */ |
||||
interface Props {} |
||||
|
||||
export default function FollowModal(props: Props) { |
||||
return <div>Component goes here</div>; |
||||
} |
Loading…
Reference in new issue