Whalebird-desktop-client-ma.../renderer/components/accounts/New.tsx

175 lines
5.4 KiB
TypeScript
Raw Normal View History

import { Label, Modal, TextInput, Button, Alert, Spinner } from 'flowbite-react'
import generator, { MegalodonInterface, OAuth, detector } from 'megalodon'
2023-11-01 17:20:27 +01:00
import { useState } from 'react'
import { db } from '@/db'
import { FormattedMessage, useIntl } from 'react-intl'
2023-11-01 17:20:27 +01:00
type NewProps = {
opened: boolean
close: () => void
}
export default function New(props: NewProps) {
const [sns, setSNS] = useState<'mastodon' | 'pleroma' | 'firefish' | 'friendica' | null>(null)
const [domain, setDomain] = useState<string>('')
const [client, setClient] = useState<MegalodonInterface>()
const [appData, setAppData] = useState<OAuth.AppData>()
const [error, setError] = useState("")
const [loading, setLoading] = useState(false)
const { formatMessage } = useIntl()
2023-11-01 17:20:27 +01:00
2023-11-02 16:50:17 +01:00
const close = () => {
setSNS(null)
setDomain('')
setClient(undefined)
setAppData(undefined)
setError("")
setLoading(false)
2023-11-02 16:50:17 +01:00
props.close()
}
2023-11-01 17:20:27 +01:00
const checkDomain = async () => {
setError("")
setLoading(true)
2023-11-01 17:20:27 +01:00
const input = document.getElementById('domain') as HTMLInputElement
setDomain(input.value)
const url = `https://${input.value}`
const sns = await detector(url).catch(() => {
setError(formatMessage({ id: 'accounts.new.detector_error' }, { domain: input.value}))
return undefined
})
if (!sns) {
setLoading(false)
return
}
2023-11-01 17:20:27 +01:00
setSNS(sns)
const client = generator(sns, url)
setClient(client)
const appData = await client.registerApp('Whalebird', {}).catch(() => {
setError(formatMessage({ id: "accounts.new.register_error" }))
return undefined
})
setLoading(false)
if (!appData) {
return
}
setAppData(appData)
2023-11-01 17:20:27 +01:00
global.ipc.invoke('open-browser', appData.url)
}
const authorize = async () => {
setError("")
setLoading(true)
if (!client || !appData) return
2023-11-01 17:20:27 +01:00
const input = document.getElementById('authorization') as HTMLInputElement
let authorizationCode = null
if (appData.session_token) {
authorizationCode = appData.session_token
} else {
authorizationCode = input.value
}
const tokenData = await client.fetchAccessToken(appData.client_id, appData.client_secret, authorizationCode).catch(() => {
setError(formatMessage({ id: "accounts.new.token_error" }))
return undefined
})
if (!tokenData) {
setLoading(false)
return
}
if (!sns) {
setLoading(false)
return
}
2023-11-01 17:20:27 +01:00
const cli = generator(sns, `https://${domain}`, tokenData.access_token, 'Whalebird')
const acct = await cli.verifyAccountCredentials().catch(() => {
setError(formatMessage({ id: "accounts.new.credential_error" }))
return undefined
})
setLoading(false)
if (!acct) {
return
}
2023-11-01 17:20:27 +01:00
await db.accounts.add({
username: acct.data.username,
account_id: acct.data.id,
avatar: acct.data.avatar,
client_id: appData.client_id,
client_secret: appData.client_secret,
2023-11-01 17:20:27 +01:00
access_token: tokenData.access_token,
refresh_token: tokenData.refresh_token,
url: `https://${domain}`,
domain: domain,
sns: sns
})
2023-11-02 16:50:17 +01:00
close()
2023-11-01 17:20:27 +01:00
}
return (
<>
2023-11-02 16:50:17 +01:00
<Modal dismissible={false} show={props.opened} onClose={close}>
2023-11-04 07:32:37 +01:00
<Modal.Header>
<FormattedMessage id="accounts.new.title" />
</Modal.Header>
2023-11-01 17:20:27 +01:00
<Modal.Body>
{error && (
<Alert color="failure">
<span>{error}</span>
</Alert>
)}
2023-11-01 17:20:27 +01:00
<form className="flex max-w-md flex-col gap-2">
{sns === null ? (
2023-11-01 17:20:27 +01:00
<>
<div className="block">
2023-12-04 17:17:52 +01:00
<Label htmlFor="domain">
<FormattedMessage id="accounts.new.domain" />
</Label>
2023-11-01 17:20:27 +01:00
</div>
<TextInput id="domain" placeholder="mastodon.social" required type="text" />
<Button onClick={checkDomain} disabled={loading}>
2023-11-04 07:32:37 +01:00
<FormattedMessage id="accounts.new.sign_in" />
</Button>
2023-11-01 17:20:27 +01:00
</>
) : (
2023-11-01 17:20:27 +01:00
<>
{appData ? (
<>
{appData.session_token ? (
<>
<div className="block text-gray-600">
<FormattedMessage id="accounts.new.without_code_authorize" />
</div>
</>
) : (
<>
<div className="block">
<Label htmlFor="authorization">
<FormattedMessage id="accounts.new.authorization_code" />
</Label>
<p className="text-sm text-gray-600">
<FormattedMessage id="accounts.new.authorization_helper" />
</p>
</div>
<TextInput id="authorization" required type="text" />
</>
)}
<Button onClick={authorize} disabled={loading}>
<FormattedMessage id="accounts.new.authorize" />
</Button>
</>
) : (
<div className="text-center">
<Spinner aria-label="Loading" />
</div>
)}
2023-11-01 17:20:27 +01:00
</>
2023-11-01 17:20:27 +01:00
)}
</form>
</Modal.Body>
</Modal>
</>
)
}