Browse Source
* ActivityPub admin pages for configuration * Fix dev build * Add support for requiring follow approval. Closes https://github.com/owncast/owncast/issues/1208 * Point at admin version of followers endpoint * Add setting for toggling displaying fediverse engagement in admin. https://github.com/owncast/owncast/issues/1404 * Add instance URL textfield to federation config and disable federation if it is empty * If instance URL is not https disable federation * Tweak federation toggle text. Make go live message optional * Add federation info modal. Closes https://github.com/owncast/owncast/issues/1544 * Add support for blocked federated domains. For https://github.com/owncast/owncast/issues/1209 * Simplify fediverse post input * Add placeholder Fediverse icon * Tweak federation logo in admin menu. Closes https://github.com/owncast/owncast/issues/1603 * Add global button for composing a fediverse post. Closes https://github.com/owncast/owncast/issues/1610 * Federation -> Social * Add page for listing federated actions. Closes https://github.com/owncast/owncast/issues/1573 * Auto-close social post modal after success * Make user modal action buttons look nicer * Center and reduce width and center count column. Closes https://github.com/owncast/owncast/issues/1580 * Update the followers table to be clearer * Fix exception thrown when passing undefined * Disable federation settings if feature is disabled * Update enable social modal. For https://github.com/owncast/owncast/issues/1594 * Fix type props * Quiet, linter * Move compose button to the left * Add tooltip for compose button * Add NSFW toggle to federation config. Closes https://github.com/owncast/owncast/issues/1628 * Add support for blocking/removing followers. For https://github.com/owncast/owncast/issues/1630 * Allow editing the server url field even when federation is disabled * Continue to update the copy around the social features * Use relative path to action images. Fixes https://github.com/owncast/owncast/issues/1646 * Link IRIs and make action verbse present tense * Update caniuse * Notifications configuration UI * Remove twilio add email notifications * WIP email support * Add support for managing twitter notifications * Mark fields as passwords * Continued WIP * Post merge cleanup * Cleanup * Remove email config. Handle disabled notifications state * Remove email related components * Remove email related settings propertiespull/1886/head
10 changed files with 797 additions and 1 deletions
@ -0,0 +1,129 @@ |
|||||||
|
import { Button, Typography } from 'antd'; |
||||||
|
import React, { useState, useContext, useEffect } from 'react'; |
||||||
|
import { ServerStatusContext } from '../../../utils/server-status-context'; |
||||||
|
import TextField, { TEXTFIELD_TYPE_TEXTAREA } from '../form-textfield'; |
||||||
|
import { |
||||||
|
postConfigUpdateToAPI, |
||||||
|
RESET_TIMEOUT, |
||||||
|
BROWSER_PUSH_CONFIG_FIELDS, |
||||||
|
} from '../../../utils/config-constants'; |
||||||
|
import ToggleSwitch from '../form-toggleswitch'; |
||||||
|
import { |
||||||
|
createInputStatus, |
||||||
|
StatusState, |
||||||
|
STATUS_ERROR, |
||||||
|
STATUS_SUCCESS, |
||||||
|
} from '../../../utils/input-statuses'; |
||||||
|
import { UpdateArgs } from '../../../types/config-section'; |
||||||
|
import FormStatusIndicator from '../form-status-indicator'; |
||||||
|
|
||||||
|
const { Title } = Typography; |
||||||
|
|
||||||
|
export default function ConfigNotify() { |
||||||
|
const serverStatusData = useContext(ServerStatusContext); |
||||||
|
const { serverConfig, setFieldInConfigState } = serverStatusData || {}; |
||||||
|
const { notifications } = serverConfig || {}; |
||||||
|
const { browser } = notifications || {}; |
||||||
|
|
||||||
|
const { enabled, goLiveMessage } = browser || {}; |
||||||
|
|
||||||
|
const [formDataValues, setFormDataValues] = useState<any>({}); |
||||||
|
const [submitStatus, setSubmitStatus] = useState<StatusState>(null); |
||||||
|
|
||||||
|
const [enableSaveButton, setEnableSaveButton] = useState<boolean>(false); |
||||||
|
|
||||||
|
useEffect(() => { |
||||||
|
setFormDataValues({ |
||||||
|
enabled, |
||||||
|
goLiveMessage, |
||||||
|
}); |
||||||
|
}, [notifications, browser]); |
||||||
|
|
||||||
|
const canSave = (): boolean => true; |
||||||
|
|
||||||
|
// update individual values in state
|
||||||
|
const handleFieldChange = ({ fieldName, value }: UpdateArgs) => { |
||||||
|
console.log(fieldName, value); |
||||||
|
setFormDataValues({ |
||||||
|
...formDataValues, |
||||||
|
[fieldName]: value, |
||||||
|
}); |
||||||
|
|
||||||
|
setEnableSaveButton(canSave()); |
||||||
|
}; |
||||||
|
|
||||||
|
// toggle switch.
|
||||||
|
const handleSwitchChange = (switchEnabled: boolean) => { |
||||||
|
// setShouldDisplayForm(storageEnabled);
|
||||||
|
handleFieldChange({ fieldName: 'enabled', value: switchEnabled }); |
||||||
|
}; |
||||||
|
|
||||||
|
let resetTimer = null; |
||||||
|
const resetStates = () => { |
||||||
|
setSubmitStatus(null); |
||||||
|
resetTimer = null; |
||||||
|
clearTimeout(resetTimer); |
||||||
|
}; |
||||||
|
|
||||||
|
const save = async () => { |
||||||
|
const postValue = formDataValues; |
||||||
|
|
||||||
|
await postConfigUpdateToAPI({ |
||||||
|
apiPath: '/notifications/browser', |
||||||
|
data: { value: postValue }, |
||||||
|
onSuccess: () => { |
||||||
|
setFieldInConfigState({ |
||||||
|
fieldName: 'browser', |
||||||
|
value: postValue, |
||||||
|
path: 'notifications', |
||||||
|
}); |
||||||
|
setSubmitStatus(createInputStatus(STATUS_SUCCESS, 'Updated.')); |
||||||
|
resetTimer = setTimeout(resetStates, RESET_TIMEOUT); |
||||||
|
}, |
||||||
|
onError: (message: string) => { |
||||||
|
setSubmitStatus(createInputStatus(STATUS_ERROR, message)); |
||||||
|
resetTimer = setTimeout(resetStates, RESET_TIMEOUT); |
||||||
|
}, |
||||||
|
}); |
||||||
|
}; |
||||||
|
|
||||||
|
return ( |
||||||
|
<> |
||||||
|
<Title>Browser Alerts</Title> |
||||||
|
<p className="description reduced-margins"> |
||||||
|
Viewers can opt into being notified when you go live with their browser. |
||||||
|
</p> |
||||||
|
<p className="description reduced-margins">Not all browsers support this.</p> |
||||||
|
<ToggleSwitch |
||||||
|
apiPath="" |
||||||
|
fieldName="enabled" |
||||||
|
label="Enable browser notifications" |
||||||
|
onChange={handleSwitchChange} |
||||||
|
checked={formDataValues.enabled} |
||||||
|
/> |
||||||
|
<div style={{ display: formDataValues.enabled ? 'block' : 'none' }}> |
||||||
|
<TextField |
||||||
|
{...BROWSER_PUSH_CONFIG_FIELDS.goLiveMessage} |
||||||
|
required |
||||||
|
type={TEXTFIELD_TYPE_TEXTAREA} |
||||||
|
value={formDataValues.goLiveMessage} |
||||||
|
onChange={handleFieldChange} |
||||||
|
/> |
||||||
|
</div> |
||||||
|
<Button |
||||||
|
type="primary" |
||||||
|
style={{ |
||||||
|
display: enableSaveButton ? 'inline-block' : 'none', |
||||||
|
position: 'relative', |
||||||
|
marginLeft: 'auto', |
||||||
|
right: '0', |
||||||
|
marginTop: '20px', |
||||||
|
}} |
||||||
|
onClick={save} |
||||||
|
> |
||||||
|
Save |
||||||
|
</Button> |
||||||
|
<FormStatusIndicator status={submitStatus} /> |
||||||
|
</> |
||||||
|
); |
||||||
|
} |
||||||
@ -0,0 +1,153 @@ |
|||||||
|
import { Button, Typography } from 'antd'; |
||||||
|
import React, { useState, useContext, useEffect } from 'react'; |
||||||
|
import { ServerStatusContext } from '../../../utils/server-status-context'; |
||||||
|
import TextField from '../form-textfield'; |
||||||
|
import FormStatusIndicator from '../form-status-indicator'; |
||||||
|
import { |
||||||
|
postConfigUpdateToAPI, |
||||||
|
RESET_TIMEOUT, |
||||||
|
DISCORD_CONFIG_FIELDS, |
||||||
|
} from '../../../utils/config-constants'; |
||||||
|
import ToggleSwitch from '../form-toggleswitch'; |
||||||
|
import { |
||||||
|
createInputStatus, |
||||||
|
StatusState, |
||||||
|
STATUS_ERROR, |
||||||
|
STATUS_SUCCESS, |
||||||
|
} from '../../../utils/input-statuses'; |
||||||
|
import { UpdateArgs } from '../../../types/config-section'; |
||||||
|
|
||||||
|
const { Title } = Typography; |
||||||
|
|
||||||
|
export default function ConfigNotify() { |
||||||
|
const serverStatusData = useContext(ServerStatusContext); |
||||||
|
const { serverConfig, setFieldInConfigState } = serverStatusData || {}; |
||||||
|
const { notifications } = serverConfig || {}; |
||||||
|
const { discord } = notifications || {}; |
||||||
|
|
||||||
|
const { enabled, webhook, goLiveMessage } = discord || {}; |
||||||
|
|
||||||
|
const [formDataValues, setFormDataValues] = useState<any>({}); |
||||||
|
const [submitStatus, setSubmitStatus] = useState<StatusState>(null); |
||||||
|
|
||||||
|
const [enableSaveButton, setEnableSaveButton] = useState<boolean>(false); |
||||||
|
|
||||||
|
useEffect(() => { |
||||||
|
setFormDataValues({ |
||||||
|
enabled, |
||||||
|
webhook, |
||||||
|
goLiveMessage, |
||||||
|
}); |
||||||
|
}, [notifications, discord]); |
||||||
|
|
||||||
|
const canSave = (): boolean => { |
||||||
|
if (webhook === '' || goLiveMessage === '') { |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
return true; |
||||||
|
}; |
||||||
|
|
||||||
|
// update individual values in state
|
||||||
|
const handleFieldChange = ({ fieldName, value }: UpdateArgs) => { |
||||||
|
setFormDataValues({ |
||||||
|
...formDataValues, |
||||||
|
[fieldName]: value, |
||||||
|
}); |
||||||
|
|
||||||
|
setEnableSaveButton(canSave()); |
||||||
|
}; |
||||||
|
|
||||||
|
let resetTimer = null; |
||||||
|
const resetStates = () => { |
||||||
|
setSubmitStatus(null); |
||||||
|
resetTimer = null; |
||||||
|
clearTimeout(resetTimer); |
||||||
|
}; |
||||||
|
|
||||||
|
const save = async () => { |
||||||
|
const postValue = formDataValues; |
||||||
|
|
||||||
|
await postConfigUpdateToAPI({ |
||||||
|
apiPath: '/notifications/discord', |
||||||
|
data: { value: postValue }, |
||||||
|
onSuccess: () => { |
||||||
|
setFieldInConfigState({ |
||||||
|
fieldName: 'discord', |
||||||
|
value: postValue, |
||||||
|
path: 'notifications', |
||||||
|
}); |
||||||
|
setSubmitStatus(createInputStatus(STATUS_SUCCESS, 'Updated.')); |
||||||
|
resetTimer = setTimeout(resetStates, RESET_TIMEOUT); |
||||||
|
}, |
||||||
|
onError: (message: string) => { |
||||||
|
setSubmitStatus(createInputStatus(STATUS_ERROR, message)); |
||||||
|
resetTimer = setTimeout(resetStates, RESET_TIMEOUT); |
||||||
|
}, |
||||||
|
}); |
||||||
|
}; |
||||||
|
|
||||||
|
// toggle switch.
|
||||||
|
const handleSwitchChange = (switchEnabled: boolean) => { |
||||||
|
// setShouldDisplayForm(storageEnabled);
|
||||||
|
handleFieldChange({ fieldName: 'enabled', value: switchEnabled }); |
||||||
|
}; |
||||||
|
|
||||||
|
return ( |
||||||
|
<> |
||||||
|
<Title>Discord</Title> |
||||||
|
<p className="description reduced-margins"> |
||||||
|
Let your Discord channel know each time you go live. |
||||||
|
</p> |
||||||
|
<p className="description reduced-margins"> |
||||||
|
<a |
||||||
|
href="https://support.discord.com/hc/en-us/articles/228383668" |
||||||
|
target="_blank" |
||||||
|
rel="noreferrer" |
||||||
|
> |
||||||
|
Create a webhook |
||||||
|
</a>{' '} |
||||||
|
under <i>Edit Channel / Integrations</i> on your Discord channel and provide it below. |
||||||
|
</p> |
||||||
|
|
||||||
|
<ToggleSwitch |
||||||
|
apiPath="" |
||||||
|
fieldName="discordEnabled" |
||||||
|
label="Enable Discord" |
||||||
|
checked={formDataValues.enabled} |
||||||
|
onChange={handleSwitchChange} |
||||||
|
/> |
||||||
|
<div style={{ display: formDataValues.enabled ? 'block' : 'none' }}> |
||||||
|
<TextField |
||||||
|
{...DISCORD_CONFIG_FIELDS.webhookUrl} |
||||||
|
required |
||||||
|
value={formDataValues.webhook} |
||||||
|
onChange={handleFieldChange} |
||||||
|
/> |
||||||
|
</div> |
||||||
|
<div style={{ display: formDataValues.enabled ? 'block' : 'none' }}> |
||||||
|
<TextField |
||||||
|
{...DISCORD_CONFIG_FIELDS.goLiveMessage} |
||||||
|
required |
||||||
|
value={formDataValues.goLiveMessage} |
||||||
|
onChange={handleFieldChange} |
||||||
|
/> |
||||||
|
</div> |
||||||
|
|
||||||
|
<Button |
||||||
|
type="primary" |
||||||
|
onClick={save} |
||||||
|
style={{ |
||||||
|
display: enableSaveButton ? 'inline-block' : 'none', |
||||||
|
position: 'relative', |
||||||
|
marginLeft: 'auto', |
||||||
|
right: '0', |
||||||
|
marginTop: '20px', |
||||||
|
}} |
||||||
|
> |
||||||
|
Save |
||||||
|
</Button> |
||||||
|
<FormStatusIndicator status={submitStatus} /> |
||||||
|
</> |
||||||
|
); |
||||||
|
} |
||||||
@ -0,0 +1,51 @@ |
|||||||
|
import { Button, Typography } from 'antd'; |
||||||
|
import React, { useState, useContext, useEffect } from 'react'; |
||||||
|
import Link from 'next/link'; |
||||||
|
import { ServerStatusContext } from '../../../utils/server-status-context'; |
||||||
|
|
||||||
|
const { Title } = Typography; |
||||||
|
|
||||||
|
export default function ConfigNotify() { |
||||||
|
const serverStatusData = useContext(ServerStatusContext); |
||||||
|
const { serverConfig } = serverStatusData || {}; |
||||||
|
const { federation } = serverConfig || {}; |
||||||
|
|
||||||
|
const { enabled } = federation || {}; |
||||||
|
const [formDataValues, setFormDataValues] = useState<any>({}); |
||||||
|
|
||||||
|
useEffect(() => { |
||||||
|
setFormDataValues({ |
||||||
|
enabled, |
||||||
|
}); |
||||||
|
}, [enabled]); |
||||||
|
|
||||||
|
return ( |
||||||
|
<> |
||||||
|
<Title>Fediverse Social</Title> |
||||||
|
<p className="description"> |
||||||
|
Enabling the Fediverse social features will not just alert people to when you go live, but |
||||||
|
also enable other functionality. |
||||||
|
</p> |
||||||
|
<p> |
||||||
|
Fediverse social features:{' '} |
||||||
|
<span style={{ color: federation.enabled ? 'green' : 'red' }}> |
||||||
|
{formDataValues.enabled ? 'Enabled' : 'Disabled'} |
||||||
|
</span> |
||||||
|
</p> |
||||||
|
|
||||||
|
<Link passHref href="/config-federation"> |
||||||
|
<Button |
||||||
|
type="primary" |
||||||
|
style={{ |
||||||
|
position: 'relative', |
||||||
|
marginLeft: 'auto', |
||||||
|
right: '0', |
||||||
|
marginTop: '20px', |
||||||
|
}} |
||||||
|
> |
||||||
|
Configure |
||||||
|
</Button> |
||||||
|
</Link> |
||||||
|
</> |
||||||
|
); |
||||||
|
} |
||||||
@ -0,0 +1,198 @@ |
|||||||
|
import { Button, Typography } from 'antd'; |
||||||
|
import React, { useState, useContext, useEffect } from 'react'; |
||||||
|
import { ServerStatusContext } from '../../../utils/server-status-context'; |
||||||
|
import TextField, { TEXTFIELD_TYPE_PASSWORD } from '../form-textfield'; |
||||||
|
import FormStatusIndicator from '../form-status-indicator'; |
||||||
|
import { |
||||||
|
postConfigUpdateToAPI, |
||||||
|
RESET_TIMEOUT, |
||||||
|
TWITTER_CONFIG_FIELDS, |
||||||
|
} from '../../../utils/config-constants'; |
||||||
|
import ToggleSwitch from '../form-toggleswitch'; |
||||||
|
import { |
||||||
|
createInputStatus, |
||||||
|
StatusState, |
||||||
|
STATUS_ERROR, |
||||||
|
STATUS_SUCCESS, |
||||||
|
} from '../../../utils/input-statuses'; |
||||||
|
import { UpdateArgs } from '../../../types/config-section'; |
||||||
|
import { TEXTFIELD_TYPE_TEXT } from '../form-textfield-with-submit'; |
||||||
|
|
||||||
|
const { Title } = Typography; |
||||||
|
|
||||||
|
export default function ConfigNotify() { |
||||||
|
const serverStatusData = useContext(ServerStatusContext); |
||||||
|
const { serverConfig, setFieldInConfigState } = serverStatusData || {}; |
||||||
|
const { notifications } = serverConfig || {}; |
||||||
|
const { twitter } = notifications || {}; |
||||||
|
|
||||||
|
const { enabled, apiKey, apiSecret, accessToken, accessTokenSecret, bearerToken, goLiveMessage } = |
||||||
|
twitter || {}; |
||||||
|
|
||||||
|
const [formDataValues, setFormDataValues] = useState<any>({}); |
||||||
|
const [submitStatus, setSubmitStatus] = useState<StatusState>(null); |
||||||
|
|
||||||
|
const [enableSaveButton, setEnableSaveButton] = useState<boolean>(false); |
||||||
|
|
||||||
|
useEffect(() => { |
||||||
|
setFormDataValues({ |
||||||
|
enabled, |
||||||
|
apiKey, |
||||||
|
apiSecret, |
||||||
|
accessToken, |
||||||
|
accessTokenSecret, |
||||||
|
bearerToken, |
||||||
|
goLiveMessage, |
||||||
|
}); |
||||||
|
}, [twitter]); |
||||||
|
|
||||||
|
const canSave = (): boolean => true; |
||||||
|
|
||||||
|
// update individual values in state
|
||||||
|
const handleFieldChange = ({ fieldName, value }: UpdateArgs) => { |
||||||
|
setFormDataValues({ |
||||||
|
...formDataValues, |
||||||
|
[fieldName]: value, |
||||||
|
}); |
||||||
|
|
||||||
|
setEnableSaveButton(canSave()); |
||||||
|
}; |
||||||
|
|
||||||
|
// toggle switch.
|
||||||
|
const handleSwitchChange = (switchEnabled: boolean) => { |
||||||
|
handleFieldChange({ fieldName: 'enabled', value: switchEnabled }); |
||||||
|
}; |
||||||
|
|
||||||
|
let resetTimer = null; |
||||||
|
const resetStates = () => { |
||||||
|
setSubmitStatus(null); |
||||||
|
resetTimer = null; |
||||||
|
clearTimeout(resetTimer); |
||||||
|
}; |
||||||
|
|
||||||
|
const save = async () => { |
||||||
|
const postValue = formDataValues; |
||||||
|
|
||||||
|
await postConfigUpdateToAPI({ |
||||||
|
apiPath: '/notifications/twitter', |
||||||
|
data: { value: postValue }, |
||||||
|
onSuccess: () => { |
||||||
|
setFieldInConfigState({ |
||||||
|
fieldName: 'twitter', |
||||||
|
value: postValue, |
||||||
|
path: 'notifications', |
||||||
|
}); |
||||||
|
setSubmitStatus(createInputStatus(STATUS_SUCCESS, 'Updated.')); |
||||||
|
resetTimer = setTimeout(resetStates, RESET_TIMEOUT); |
||||||
|
}, |
||||||
|
onError: (message: string) => { |
||||||
|
setSubmitStatus(createInputStatus(STATUS_ERROR, message)); |
||||||
|
resetTimer = setTimeout(resetStates, RESET_TIMEOUT); |
||||||
|
}, |
||||||
|
}); |
||||||
|
}; |
||||||
|
|
||||||
|
return ( |
||||||
|
<> |
||||||
|
<Title>Twitter</Title> |
||||||
|
<p className="description reduced-margins"> |
||||||
|
Let your Twitter followers know each time you go live. |
||||||
|
</p> |
||||||
|
<div style={{ display: formDataValues.enabled ? 'block' : 'none' }}> |
||||||
|
<p className="description reduced-margins"> |
||||||
|
<a |
||||||
|
href="https://developer.twitter.com/en/portal/dashboard" |
||||||
|
target="_blank" |
||||||
|
rel="noreferrer" |
||||||
|
> |
||||||
|
Read how to configure your Twitter account |
||||||
|
</a>{' '} |
||||||
|
to support posting from Owncast. |
||||||
|
</p> |
||||||
|
<p className="description reduced-margins"> |
||||||
|
<a |
||||||
|
href="https://developer.twitter.com/en/portal/dashboard" |
||||||
|
target="_blank" |
||||||
|
rel="noreferrer" |
||||||
|
> |
||||||
|
And then get your Twitter developer credentials |
||||||
|
</a>{' '} |
||||||
|
to fill in below. |
||||||
|
</p> |
||||||
|
</div> |
||||||
|
|
||||||
|
<ToggleSwitch |
||||||
|
apiPath="" |
||||||
|
fieldName="enabled" |
||||||
|
label="Enable Twitter" |
||||||
|
onChange={handleSwitchChange} |
||||||
|
checked={formDataValues.enabled} |
||||||
|
/> |
||||||
|
<div style={{ display: formDataValues.enabled ? 'block' : 'none' }}> |
||||||
|
<TextField |
||||||
|
{...TWITTER_CONFIG_FIELDS.apiKey} |
||||||
|
required |
||||||
|
value={formDataValues.apiKey} |
||||||
|
onChange={handleFieldChange} |
||||||
|
/> |
||||||
|
</div> |
||||||
|
<div style={{ display: formDataValues.enabled ? 'block' : 'none' }}> |
||||||
|
<TextField |
||||||
|
{...TWITTER_CONFIG_FIELDS.apiSecret} |
||||||
|
type={TEXTFIELD_TYPE_PASSWORD} |
||||||
|
required |
||||||
|
value={formDataValues.apiSecret} |
||||||
|
onChange={handleFieldChange} |
||||||
|
/> |
||||||
|
</div> |
||||||
|
<div style={{ display: formDataValues.enabled ? 'block' : 'none' }}> |
||||||
|
<TextField |
||||||
|
{...TWITTER_CONFIG_FIELDS.accessToken} |
||||||
|
required |
||||||
|
value={formDataValues.accessToken} |
||||||
|
onChange={handleFieldChange} |
||||||
|
/> |
||||||
|
</div> |
||||||
|
<div style={{ display: formDataValues.enabled ? 'block' : 'none' }}> |
||||||
|
<TextField |
||||||
|
{...TWITTER_CONFIG_FIELDS.accessTokenSecret} |
||||||
|
type={TEXTFIELD_TYPE_PASSWORD} |
||||||
|
required |
||||||
|
value={formDataValues.accessTokenSecret} |
||||||
|
onChange={handleFieldChange} |
||||||
|
/> |
||||||
|
</div> |
||||||
|
<div style={{ display: formDataValues.enabled ? 'block' : 'none' }}> |
||||||
|
<TextField |
||||||
|
{...TWITTER_CONFIG_FIELDS.bearerToken} |
||||||
|
required |
||||||
|
value={formDataValues.bearerToken} |
||||||
|
onChange={handleFieldChange} |
||||||
|
/> |
||||||
|
</div> |
||||||
|
<div style={{ display: formDataValues.enabled ? 'block' : 'none' }}> |
||||||
|
<TextField |
||||||
|
{...TWITTER_CONFIG_FIELDS.goLiveMessage} |
||||||
|
type={TEXTFIELD_TYPE_TEXT} |
||||||
|
required |
||||||
|
value={formDataValues.goLiveMessage} |
||||||
|
onChange={handleFieldChange} |
||||||
|
/> |
||||||
|
</div> |
||||||
|
<Button |
||||||
|
type="primary" |
||||||
|
onClick={save} |
||||||
|
style={{ |
||||||
|
display: enableSaveButton ? 'inline-block' : 'none', |
||||||
|
position: 'relative', |
||||||
|
marginLeft: 'auto', |
||||||
|
right: '0', |
||||||
|
marginTop: '20px', |
||||||
|
}} |
||||||
|
> |
||||||
|
Save |
||||||
|
</Button> |
||||||
|
<FormStatusIndicator status={submitStatus} /> |
||||||
|
</> |
||||||
|
); |
||||||
|
} |
||||||
@ -0,0 +1,135 @@ |
|||||||
|
import { Alert, Button, Col, Row, Typography } from 'antd'; |
||||||
|
import React, { useContext, useEffect, useState } from 'react'; |
||||||
|
import Link from 'next/link'; |
||||||
|
|
||||||
|
import Discord from '../components/config/notification/discord'; |
||||||
|
import Browser from '../components/config/notification/browser'; |
||||||
|
import Twitter from '../components/config/notification/twitter'; |
||||||
|
import Federation from '../components/config/notification/federation'; |
||||||
|
import TextFieldWithSubmit, { |
||||||
|
TEXTFIELD_TYPE_URL, |
||||||
|
} from '../components/config/form-textfield-with-submit'; |
||||||
|
import { TEXTFIELD_PROPS_FEDERATION_INSTANCE_URL } from '../utils/config-constants'; |
||||||
|
import { ServerStatusContext } from '../utils/server-status-context'; |
||||||
|
import { UpdateArgs } from '../types/config-section'; |
||||||
|
|
||||||
|
const { Title } = Typography; |
||||||
|
|
||||||
|
export default function ConfigNotify() { |
||||||
|
const [formDataValues, setFormDataValues] = useState(null); |
||||||
|
const serverStatusData = useContext(ServerStatusContext); |
||||||
|
const { serverConfig } = serverStatusData || {}; |
||||||
|
const { yp } = serverConfig; |
||||||
|
const { instanceUrl } = yp; |
||||||
|
|
||||||
|
useEffect(() => { |
||||||
|
setFormDataValues({ |
||||||
|
instanceUrl, |
||||||
|
}); |
||||||
|
}, [yp]); |
||||||
|
|
||||||
|
const handleSubmitInstanceUrl = () => { |
||||||
|
setFormDataValues({ |
||||||
|
...formDataValues, |
||||||
|
enabled: false, |
||||||
|
}); |
||||||
|
}; |
||||||
|
|
||||||
|
const handleFieldChange = ({ fieldName, value }: UpdateArgs) => { |
||||||
|
setFormDataValues({ |
||||||
|
...formDataValues, |
||||||
|
[fieldName]: value, |
||||||
|
}); |
||||||
|
}; |
||||||
|
|
||||||
|
const enabled = instanceUrl !== ''; |
||||||
|
console.log(enabled); |
||||||
|
const configurationWarning = !enabled && ( |
||||||
|
<> |
||||||
|
<Alert |
||||||
|
message="You must set your server URL before you can enable this feature." |
||||||
|
type="warning" |
||||||
|
showIcon |
||||||
|
/> |
||||||
|
<br /> |
||||||
|
<TextFieldWithSubmit |
||||||
|
fieldName="instanceUrl" |
||||||
|
{...TEXTFIELD_PROPS_FEDERATION_INSTANCE_URL} |
||||||
|
value={formDataValues?.instanceUrl || ''} |
||||||
|
initialValue={yp.instanceUrl} |
||||||
|
type={TEXTFIELD_TYPE_URL} |
||||||
|
onChange={handleFieldChange} |
||||||
|
onSubmit={handleSubmitInstanceUrl} |
||||||
|
required |
||||||
|
/> |
||||||
|
</> |
||||||
|
); |
||||||
|
|
||||||
|
return ( |
||||||
|
<> |
||||||
|
<Title>Notifications</Title> |
||||||
|
<p className="description"> |
||||||
|
Let your viewers know when you go live by supporting some of the following notification |
||||||
|
channels. |
||||||
|
</p> |
||||||
|
|
||||||
|
{configurationWarning} |
||||||
|
|
||||||
|
<Row> |
||||||
|
<Col |
||||||
|
span={10} |
||||||
|
className={`form-module ${enabled ? '' : 'disabled'}`} |
||||||
|
style={{ margin: '5px', display: 'flex', flexDirection: 'column' }} |
||||||
|
> |
||||||
|
<Browser /> |
||||||
|
</Col> |
||||||
|
<Col |
||||||
|
span={10} |
||||||
|
className={`form-module ${enabled ? '' : 'disabled'}`} |
||||||
|
style={{ margin: '5px', display: 'flex', flexDirection: 'column' }} |
||||||
|
> |
||||||
|
<Twitter /> |
||||||
|
</Col> |
||||||
|
|
||||||
|
<Col |
||||||
|
span={10} |
||||||
|
className={`form-module ${enabled ? '' : 'disabled'}`} |
||||||
|
style={{ margin: '5px', display: 'flex', flexDirection: 'column' }} |
||||||
|
> |
||||||
|
<Discord /> |
||||||
|
</Col> |
||||||
|
|
||||||
|
<Col |
||||||
|
span={10} |
||||||
|
className={`form-module ${enabled ? '' : 'disabled'}`} |
||||||
|
style={{ margin: '5px', display: 'flex', flexDirection: 'column' }} |
||||||
|
> |
||||||
|
<Federation /> |
||||||
|
</Col> |
||||||
|
|
||||||
|
<Col |
||||||
|
span={10} |
||||||
|
className={`form-module ${enabled ? '' : 'disabled'}`} |
||||||
|
style={{ margin: '5px', display: 'flex', flexDirection: 'column' }} |
||||||
|
> |
||||||
|
<Title>Custom</Title> |
||||||
|
<p className="description">Build your own notifications by using custom webhooks.</p> |
||||||
|
|
||||||
|
<Link passHref href="/webhooks"> |
||||||
|
<Button |
||||||
|
type="primary" |
||||||
|
style={{ |
||||||
|
position: 'relative', |
||||||
|
marginLeft: 'auto', |
||||||
|
right: '0', |
||||||
|
marginTop: '20px', |
||||||
|
}} |
||||||
|
> |
||||||
|
Create |
||||||
|
</Button> |
||||||
|
</Link> |
||||||
|
</Col> |
||||||
|
</Row> |
||||||
|
</> |
||||||
|
); |
||||||
|
} |
||||||
Loading…
Reference in new issue