Browse Source
- update constants - add instanceUrl field to public details; if empty, then turn off yp.enabled. - edit YP/Directory settings; hide if instanceUrl is empty - update toggleswitch logicpull/1886/head
6 changed files with 393 additions and 105 deletions
@ -0,0 +1,36 @@
@@ -0,0 +1,36 @@
|
||||
# Config |
||||
|
||||
|
||||
TODO: explain how to use <Form> and how the custom `form-xxxx` components work together. |
||||
|
||||
|
||||
## Misc notes |
||||
- `instanceDetails` needs to be filled out before `yp.enabled` can be turned on. |
||||
|
||||
|
||||
|
||||
## Config data structure (with default values) |
||||
``` |
||||
{ |
||||
streamKey: '', |
||||
instanceDetails: { |
||||
tags: [], |
||||
nsfw: false, |
||||
}, |
||||
yp: { |
||||
enabled: false, |
||||
instance: '', |
||||
}, |
||||
videoSettings: { |
||||
videoQualityVariants: [ |
||||
{ |
||||
audioPassthrough: false, |
||||
videoPassthrough: false, |
||||
videoBitrate: 0, |
||||
audioBitrate: 0, |
||||
framerate: 0, |
||||
}, |
||||
], |
||||
} |
||||
}; |
||||
``` |
||||
@ -0,0 +1,60 @@
@@ -0,0 +1,60 @@
|
||||
// rename to "directory"
|
||||
import React, { useContext, useEffect } from 'react'; |
||||
import { Typography, Form } from 'antd'; |
||||
|
||||
import ToggleSwitch from './form-toggleswitch'; |
||||
|
||||
import { ServerStatusContext } from '../../../utils/server-status-context'; |
||||
|
||||
const { Title } = Typography; |
||||
|
||||
export default function EditYPDetails() { |
||||
const [form] = Form.useForm(); |
||||
|
||||
const serverStatusData = useContext(ServerStatusContext); |
||||
const { serverConfig } = serverStatusData || {}; |
||||
|
||||
const { yp, instanceDetails } = serverConfig; |
||||
const { nsfw } = instanceDetails; |
||||
const { enabled, instanceUrl } = yp; |
||||
|
||||
const initialValues = { |
||||
...yp, |
||||
enabled, |
||||
nsfw, |
||||
}; |
||||
|
||||
const hasInstanceUrl = instanceUrl !== ''; |
||||
|
||||
useEffect(() => { |
||||
form.setFieldsValue(initialValues); |
||||
}, [yp]); |
||||
|
||||
const extraProps = { |
||||
initialValues, |
||||
disabled: !hasInstanceUrl, |
||||
}; |
||||
|
||||
// TODO: DISABLE THIS SECTION UNTIL instanceURL is populated
|
||||
return ( |
||||
<div className="config-directory-details-form"> |
||||
<Title level={3}>Owncast Directory Settings</Title> |
||||
|
||||
<p>Would you like to appear in the <a href="https://directory.owncast.online" target="_blank" rel="noreferrer"><strong>Owncast Directory</strong></a>?</p> |
||||
|
||||
<p><em>NOTE: You will need to have a URL specified in the <code>Instance URL</code> field to be able to use this.</em></p> |
||||
|
||||
<div className="config-yp-container"> |
||||
<Form |
||||
form={form} |
||||
layout="vertical" |
||||
> |
||||
<ToggleSwitch fieldName="enabled" configPath="yp" {...extraProps}/> |
||||
<ToggleSwitch fieldName="nsfw" configPath="instanceDetails" {...extraProps} /> |
||||
</Form> |
||||
</div> |
||||
</div> |
||||
); |
||||
} |
||||
|
||||
|
||||
@ -0,0 +1,112 @@
@@ -0,0 +1,112 @@
|
||||
import React, { useState, useContext } from 'react'; |
||||
import { Form, Switch, Tooltip } from 'antd'; |
||||
import { FormItemProps } from 'antd/es/form'; |
||||
|
||||
import { InfoCircleOutlined } from '@ant-design/icons'; |
||||
|
||||
import { TEXTFIELD_DEFAULTS, RESET_TIMEOUT, SUCCESS_STATES } from './constants'; |
||||
|
||||
import { ToggleSwitchProps } from '../../../types/config-section'; |
||||
import { fetchData, SERVER_CONFIG_UPDATE_URL } from '../../../utils/apis'; |
||||
import { ServerStatusContext } from '../../../utils/server-status-context'; |
||||
|
||||
export const TEXTFIELD_TYPE_TEXT = 'default'; |
||||
export const TEXTFIELD_TYPE_PASSWORD = 'password'; // Input.Password
|
||||
export const TEXTFIELD_TYPE_NUMBER = 'numeric'; |
||||
export const TEXTFIELD_TYPE_TEXTAREA = 'textarea'; |
||||
|
||||
|
||||
export default function ToggleSwitch(props: ToggleSwitchProps) { |
||||
const [submitStatus, setSubmitStatus] = useState<FormItemProps['validateStatus']>(''); |
||||
const [submitStatusMessage, setSubmitStatusMessage] = useState(''); |
||||
|
||||
let resetTimer = null; |
||||
|
||||
const serverStatusData = useContext(ServerStatusContext); |
||||
const { setConfigField } = serverStatusData || {}; |
||||
|
||||
const { |
||||
fieldName, |
||||
initialValues = {}, |
||||
configPath = '', |
||||
disabled = false, |
||||
} = props; |
||||
|
||||
const initialValue = initialValues[fieldName] || false; |
||||
|
||||
const defaultDetails = TEXTFIELD_DEFAULTS[configPath] || TEXTFIELD_DEFAULTS; |
||||
|
||||
const { |
||||
apiPath = '', |
||||
label = '', |
||||
tip = '', |
||||
} = defaultDetails[fieldName] || {}; |
||||
|
||||
const resetStates = () => { |
||||
setSubmitStatus(''); |
||||
clearTimeout(resetTimer); |
||||
resetTimer = null; |
||||
} |
||||
|
||||
const postUpdateToAPI = async (postValue: any) => { |
||||
setSubmitStatus('validating'); |
||||
const result = await fetchData(`${SERVER_CONFIG_UPDATE_URL}${apiPath}`, { |
||||
data: { value: postValue }, |
||||
method: 'POST', |
||||
auth: true, |
||||
}); |
||||
|
||||
if (result.success) { |
||||
setConfigField({ fieldName, value: postValue, path: configPath }); |
||||
setSubmitStatus('success'); |
||||
} else { |
||||
setSubmitStatus('error'); |
||||
setSubmitStatusMessage(`There was an error: ${result.message}`); |
||||
} |
||||
resetTimer = setTimeout(resetStates, RESET_TIMEOUT); |
||||
}; |
||||
|
||||
const handleChange = checked => { |
||||
postUpdateToAPI(checked); |
||||
} |
||||
|
||||
const { |
||||
icon: newStatusIcon = null, |
||||
message: newStatusMessage = '', |
||||
} = SUCCESS_STATES[submitStatus] || {}; |
||||
|
||||
const tipComponent = tip ? ( |
||||
<span className="info"> |
||||
<Tooltip title={tip}> |
||||
<InfoCircleOutlined /> |
||||
</Tooltip> |
||||
</span> |
||||
) : null; |
||||
|
||||
return ( |
||||
<div className="toggleswitch-container"> |
||||
<div className="toggleswitch"> |
||||
<Form.Item |
||||
name={fieldName} |
||||
validateStatus={submitStatus} |
||||
> |
||||
<Switch |
||||
className="switch" |
||||
loading={submitStatus === 'validating'} |
||||
onChange={handleChange} |
||||
checked={initialValue} |
||||
checkedChildren="ON" |
||||
unCheckedChildren="OFF" |
||||
disabled={disabled} |
||||
/> |
||||
</Form.Item> |
||||
|
||||
<span className="label">{label}</span> |
||||
{tipComponent} |
||||
</div> |
||||
<div className={`status-message ${submitStatus || ''}`}> |
||||
{newStatusIcon} {newStatusMessage} {submitStatusMessage} |
||||
</div> |
||||
</div> |
||||
); |
||||
} |
||||
Loading…
Reference in new issue