/* eslint-disable react/no-unescaped-entities */ import { Typography, Modal, Button, Row, Col, Alert } from 'antd'; import React, { ReactElement, useContext, useEffect, useState, FC } from 'react'; import { TEXTFIELD_TYPE_TEXT, TEXTFIELD_TYPE_TEXTAREA, TEXTFIELD_TYPE_URL, } from '../../components/admin/TextField'; import { TextFieldWithSubmit } from '../../components/admin/TextFieldWithSubmit'; import { ToggleSwitch } from '../../components/admin/ToggleSwitch'; import { EditValueArray } from '../../components/admin/EditValueArray'; import { UpdateArgs } from '../../types/config-section'; import { FIELD_PROPS_ENABLE_FEDERATION, TEXTFIELD_PROPS_FEDERATION_LIVE_MESSAGE, TEXTFIELD_PROPS_FEDERATION_DEFAULT_USER, FIELD_PROPS_FEDERATION_IS_PRIVATE, FIELD_PROPS_SHOW_FEDERATION_ENGAGEMENT, TEXTFIELD_PROPS_FEDERATION_INSTANCE_URL, FIELD_PROPS_FEDERATION_BLOCKED_DOMAINS, postConfigUpdateToAPI, RESET_TIMEOUT, API_FEDERATION_BLOCKED_DOMAINS, FIELD_PROPS_FEDERATION_NSFW, } from '../../utils/config-constants'; import { ServerStatusContext } from '../../utils/server-status-context'; import { createInputStatus, STATUS_ERROR, STATUS_SUCCESS } from '../../utils/input-statuses'; import { AdminLayout } from '../../components/layouts/AdminLayout'; export type FederationInfoModalProps = { cancelPressed: () => void; okPressed: () => void; }; const FederationInfoModal: FC = ({ cancelPressed, okPressed }) => ( } > How do Owncast's social features work? Owncast's social features are accomplished by having your server join The{' '} Fediverse , a decentralized, open, collection of independent servers, like yours. Please{' '} read more {' '} about these features, the details behind them, and how they work. What do you need to know?
  • These features are brand new. Given the variability of interfacing with the rest of the world, bugs are possible. Please report anything that you think isn't working quite right.
  • You must always host your Owncast server with SSL using a https url.
  • You should not change your server name URL or social username once people begin following you, as your server will be seen as a completely different user on the Fediverse, and the old user will disappear.
  • Turning on Private mode will allow you to manually approve each follower and limit the visibility of your posts to followers only.
Learn more about The Fediverse If these concepts are new you should discover more about what this functionality has to offer. Visit{' '} our documentation {' '} to be pointed at some resources that will help get you started on The Fediverse.
); const ConfigFederation = () => { const { Title } = Typography; const [formDataValues, setFormDataValues] = useState(null); const [isInfoModalOpen, setIsInfoModalOpen] = useState(false); const serverStatusData = useContext(ServerStatusContext); const { serverConfig, setFieldInConfigState } = serverStatusData || {}; const [blockedDomainSaveState, setBlockedDomainSaveState] = useState(null); const { federation, yp, instanceDetails } = serverConfig; const { enabled, isPrivate, username, goLiveMessage, showEngagement, blockedDomains } = federation; const { instanceUrl } = yp; const { nsfw } = instanceDetails; const handleFieldChange = ({ fieldName, value }: UpdateArgs) => { setFormDataValues({ ...formDataValues, [fieldName]: value, }); }; const handleUsernameChange = ({ fieldName, value }: UpdateArgs) => { handleFieldChange({ fieldName, value, }); setFormDataValues({ ...formDataValues, username: value.replace(/\W/g, ''), }); }; const handleEnabledSwitchChange = (value: boolean) => { if (!value) { setFormDataValues({ ...formDataValues, enabled: false, }); } else { setIsInfoModalOpen(true); } }; // if instanceUrl is empty, we should also turn OFF the `enabled` field of directory. const handleSubmitInstanceUrl = () => { const hasInstanceUrl = formDataValues.instanceUrl !== ''; const isInstanceUrlSecure = formDataValues.instanceUrl.startsWith('https://'); if (!hasInstanceUrl || !isInstanceUrlSecure) { postConfigUpdateToAPI({ apiPath: FIELD_PROPS_ENABLE_FEDERATION.apiPath, data: { value: false }, }); setFormDataValues({ ...formDataValues, enabled: false, }); } }; function federationInfoModalCancelPressed() { setIsInfoModalOpen(false); setFormDataValues({ ...formDataValues, enabled: false, }); } function federationInfoModalOkPressed() { setIsInfoModalOpen(false); setFormDataValues({ ...formDataValues, enabled: true, }); } function resetBlockedDomainsSaveState() { setBlockedDomainSaveState(null); } function saveBlockedDomains() { try { postConfigUpdateToAPI({ apiPath: API_FEDERATION_BLOCKED_DOMAINS, data: { value: formDataValues.blockedDomains }, onSuccess: () => { setFieldInConfigState({ fieldName: 'forbiddenUsernames', value: formDataValues.forbiddenUsernames, }); setBlockedDomainSaveState(STATUS_SUCCESS); setTimeout(resetBlockedDomainsSaveState, RESET_TIMEOUT); }, onError: (message: string) => { setBlockedDomainSaveState(createInputStatus(STATUS_ERROR, message)); setTimeout(resetBlockedDomainsSaveState, RESET_TIMEOUT); }, }); } catch (e) { console.error(e); setBlockedDomainSaveState(STATUS_ERROR); } } function handleDeleteBlockedDomain(index: number) { formDataValues.blockedDomains.splice(index, 1); saveBlockedDomains(); } function handleCreateBlockedDomain(domain: string) { let newDomain; try { const u = new URL(domain); newDomain = u.host; } catch (_) { newDomain = domain; } formDataValues.blockedDomains.push(newDomain); handleFieldChange({ fieldName: 'blockedDomains', value: formDataValues.blockedDomains, }); saveBlockedDomains(); } useEffect(() => { setFormDataValues({ enabled, isPrivate, username, goLiveMessage, showEngagement, blockedDomains, nsfw, instanceUrl: yp.instanceUrl, }); }, [serverConfig, yp]); if (!formDataValues) { return null; } const hasInstanceUrl = instanceUrl !== ''; const isInstanceUrlSecure = instanceUrl.startsWith('https://'); const configurationWarning = !isInstanceUrlSecure && ( <>
); const invalidPortWarning = ( ); const hasInvalidPort = instanceUrl && new URL(instanceUrl).port !== '' && new URL(instanceUrl).port !== '443'; return (
Configure Social Features

Owncast provides the ability for people to follow and engage with your instance. It's a great way to promote alerting, sharing and engagement of your stream.

Once enabled you'll alert your followers when you go live as well as gain the ability to compose custom posts to share any information you like.

Read more about the specifics of these social features.

{configurationWarning} {hasInvalidPort && invalidPortWarning} {isInfoModalOpen && ( )}
); }; ConfigFederation.getLayout = function getLayout(page: ReactElement) { return ; }; export default ConfigFederation;