mirror of
https://github.com/owncast/owncast.git
synced 2024-10-10 19:16:02 +00:00
Add remote fediverse follow modal. Closes #1862
This commit is contained in:
parent
3c1ac58799
commit
1a9b9f53fc
@ -11,7 +11,8 @@ import { ClientConfig } from '../../interfaces/client-config.model';
|
|||||||
export default function FollowButton(props: any) {
|
export default function FollowButton(props: any) {
|
||||||
const [showModal, setShowModal] = useState(false);
|
const [showModal, setShowModal] = useState(false);
|
||||||
const clientConfig = useRecoilValue<ClientConfig>(clientConfigStateAtom);
|
const clientConfig = useRecoilValue<ClientConfig>(clientConfigStateAtom);
|
||||||
const { name } = clientConfig;
|
const { name, federation } = clientConfig;
|
||||||
|
const { account } = federation;
|
||||||
|
|
||||||
const buttonClicked = () => {
|
const buttonClicked = () => {
|
||||||
setShowModal(true);
|
setShowModal(true);
|
||||||
@ -28,8 +29,14 @@ export default function FollowButton(props: any) {
|
|||||||
>
|
>
|
||||||
Follow
|
Follow
|
||||||
</Button>
|
</Button>
|
||||||
<Modal title={`Follow ${name}`} visible={showModal} handleCancel={() => setShowModal(false)}>
|
<Modal
|
||||||
<FollowModal handleClose={() => setShowModal(false)} />
|
title={`Follow ${name}`}
|
||||||
|
visible={showModal}
|
||||||
|
handleCancel={() => setShowModal(false)}
|
||||||
|
width="550px"
|
||||||
|
height="200px"
|
||||||
|
>
|
||||||
|
<FollowModal account={account} name={name} handleClose={() => setShowModal(false)} />
|
||||||
</Modal>
|
</Modal>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -19,7 +19,6 @@
|
|||||||
padding-left: 0.35em;
|
padding-left: 0.35em;
|
||||||
padding-right: 0.35em;
|
padding-right: 0.35em;
|
||||||
color: var(--theme-text-highlight);
|
color: var(--theme-text-highlight);
|
||||||
background-color: var(--color-bg-highlight);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
44
web/components/modals/Follow/FollowModal.module.scss
Normal file
44
web/components/modals/Follow/FollowModal.module.scss
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
.header {
|
||||||
|
font-family: var(--theme-text-display-font-family);
|
||||||
|
font-size: 0.8rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.buttons {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.instructions {
|
||||||
|
font-family: var(--theme-text-display-font-family);
|
||||||
|
font-size: 0.7rem;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer {
|
||||||
|
font-size: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.account {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
margin-top: 5px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
border-radius: 50%;
|
||||||
|
width: 4em;
|
||||||
|
height: 4em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.username {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
margin-left: 10px;
|
||||||
|
margin-top: 5px;
|
||||||
|
.name {
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,10 +1,13 @@
|
|||||||
import { Input, Button, Alert, Spin } from 'antd';
|
import { Input, Button, Alert, Spin, Space } from 'antd';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
|
import s from './FollowModal.module.scss';
|
||||||
|
|
||||||
const ENDPOINT = '/api/remotefollow';
|
const ENDPOINT = '/api/remotefollow';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
handleClose: () => void;
|
handleClose: () => void;
|
||||||
|
account: string;
|
||||||
|
name: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
function validateAccount(a) {
|
function validateAccount(a) {
|
||||||
@ -15,14 +18,14 @@ function validateAccount(a) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default function FollowModal(props: Props) {
|
export default function FollowModal(props: Props) {
|
||||||
const { handleClose } = props;
|
const { handleClose, account, name } = props;
|
||||||
const [account, setAccount] = useState(null);
|
const [remoteAccount, setRemoteAccount] = useState(null);
|
||||||
const [valid, setValid] = useState(false);
|
const [valid, setValid] = useState(false);
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [errorMessage, setErrorMessage] = useState(null);
|
const [errorMessage, setErrorMessage] = useState(null);
|
||||||
|
|
||||||
const handleAccountChange = a => {
|
const handleAccountChange = a => {
|
||||||
setAccount(a);
|
setRemoteAccount(a);
|
||||||
if (validateAccount(a)) {
|
if (validateAccount(a)) {
|
||||||
setValid(true);
|
setValid(true);
|
||||||
} else {
|
} else {
|
||||||
@ -30,6 +33,10 @@ export default function FollowModal(props: Props) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const joinButtonPressed = () => {
|
||||||
|
window.open('https://owncast.online/join-fediverse', '_blank');
|
||||||
|
};
|
||||||
|
|
||||||
const remoteFollowButtonPressed = async () => {
|
const remoteFollowButtonPressed = async () => {
|
||||||
if (!valid) {
|
if (!valid) {
|
||||||
return;
|
return;
|
||||||
@ -38,7 +45,7 @@ export default function FollowModal(props: Props) {
|
|||||||
setLoading(true);
|
setLoading(true);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const sanitizedAccount = account.replace(/^@+/, '');
|
const sanitizedAccount = remoteAccount.replace(/^@+/, '');
|
||||||
const request = { account: sanitizedAccount };
|
const request = { account: sanitizedAccount };
|
||||||
const rawResponse = await fetch(ENDPOINT, {
|
const rawResponse = await fetch(ENDPOINT, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
@ -67,10 +74,30 @@ export default function FollowModal(props: Props) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<Space direction="vertical">
|
||||||
|
<div className={s.header}>
|
||||||
|
By following this stream you'll get notified on the Fediverse when it goes live. Now is a
|
||||||
|
great time to{' '}
|
||||||
|
<a href="https://owncast.online/join-fediverse" target="_blank" rel="noreferrer">
|
||||||
|
learn about the Fediverse
|
||||||
|
</a>{' '}
|
||||||
|
if it's new to you.
|
||||||
|
</div>
|
||||||
|
|
||||||
<Spin spinning={loading}>
|
<Spin spinning={loading}>
|
||||||
{errorMessage && (
|
{errorMessage && (
|
||||||
<Alert message="Follow Error" description={errorMessage} type="error" showIcon />
|
<Alert message="Follow Error" description={errorMessage} type="error" showIcon />
|
||||||
)}
|
)}
|
||||||
|
<div className={s.account}>
|
||||||
|
<img src="/logo" alt="logo" className={s.logo} />
|
||||||
|
<div className={s.username}>
|
||||||
|
<div className={s.name}>{name}</div>
|
||||||
|
<div>{account}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<div className={s.instructions}>Enter your username @server to follow</div>
|
||||||
<Input
|
<Input
|
||||||
value={account}
|
value={account}
|
||||||
size="large"
|
size="large"
|
||||||
@ -78,13 +105,17 @@ export default function FollowModal(props: Props) {
|
|||||||
placeholder="Your fediverse account @account@server"
|
placeholder="Your fediverse account @account@server"
|
||||||
defaultValue={account}
|
defaultValue={account}
|
||||||
/>
|
/>
|
||||||
|
<div className={s.footer}>
|
||||||
|
You'll be redirected to your Fediverse server and asked to confirm the action.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<Space className={s.buttons}>
|
||||||
<Button disabled={!valid} onClick={remoteFollowButtonPressed}>
|
<Button disabled={!valid} onClick={remoteFollowButtonPressed}>
|
||||||
Follow
|
Follow
|
||||||
</Button>
|
</Button>
|
||||||
<div>
|
<Button onClick={joinButtonPressed}>Join the Fediverse</Button>
|
||||||
Information about following a Fediverse account and next steps how to create a Fediverse
|
</Space>
|
||||||
account goes here.
|
|
||||||
</div>
|
|
||||||
</Spin>
|
</Spin>
|
||||||
|
</Space>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,15 +11,17 @@ interface Props {
|
|||||||
afterClose?: () => void;
|
afterClose?: () => void;
|
||||||
children?: ReactNode;
|
children?: ReactNode;
|
||||||
height?: string;
|
height?: string;
|
||||||
|
width?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Modal(props: Props) {
|
export default function Modal(props: Props) {
|
||||||
const { title, url, visible, handleOk, handleCancel, afterClose, height, children } = props;
|
const { title, url, visible, handleOk, handleCancel, afterClose, height, width, children } =
|
||||||
|
props;
|
||||||
const [loading, setLoading] = useState(!!url);
|
const [loading, setLoading] = useState(!!url);
|
||||||
|
|
||||||
const modalStyle = {
|
const modalStyle = {
|
||||||
padding: '0px',
|
padding: '0px',
|
||||||
minHeight: height || '40vh',
|
minHeight: height,
|
||||||
};
|
};
|
||||||
|
|
||||||
const iframe = url && (
|
const iframe = url && (
|
||||||
@ -45,7 +47,7 @@ export default function Modal(props: Props) {
|
|||||||
onCancel={handleCancel}
|
onCancel={handleCancel}
|
||||||
afterClose={afterClose}
|
afterClose={afterClose}
|
||||||
bodyStyle={modalStyle}
|
bodyStyle={modalStyle}
|
||||||
width="70%"
|
width={width}
|
||||||
zIndex={9999}
|
zIndex={9999}
|
||||||
footer={null}
|
footer={null}
|
||||||
centered
|
centered
|
||||||
@ -70,5 +72,6 @@ Modal.defaultProps = {
|
|||||||
handleOk: undefined,
|
handleOk: undefined,
|
||||||
handleCancel: undefined,
|
handleCancel: undefined,
|
||||||
afterClose: undefined,
|
afterClose: undefined,
|
||||||
height: undefined,
|
height: '40vh',
|
||||||
|
width: '70%',
|
||||||
};
|
};
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user