diff --git a/web/invite-links/manage-invite-links-modal.react.js b/web/invite-links/manage-invite-links-modal.react.js index fda766fc8..48feafe14 100644 --- a/web/invite-links/manage-invite-links-modal.react.js +++ b/web/invite-links/manage-invite-links-modal.react.js @@ -1,40 +1,56 @@ // @flow import * as React from 'react'; import { useModalContext } from 'lib/components/modal-provider.react.js'; import { primaryInviteLinksSelector } from 'lib/selectors/invite-links-selectors.js'; import type { InviteLink } from 'lib/types/link-types.js'; +import EditLinkModal from './manage/edit-link-modal.react.js'; import EmptyLinkContent from './manage/empty-link-content.react.js'; import ExistingLinkContent from './manage/existing-link-content.react.js'; import css from './manage/manage-invite-links-modal.css'; import Modal from '../modals/modal.react.js'; import { useSelector } from '../redux/redux-utils.js'; type Props = { +communityID: string, }; function ManageInviteLinksModal(props: Props): React.Node { const { communityID } = props; const inviteLink: ?InviteLink = useSelector(primaryInviteLinksSelector)[ communityID ]; const { popModal } = useModalContext(); + const [modalStage, setModalStage] = React.useState('view'); + const enterEditMode = React.useCallback(() => setModalStage('edit'), []); + const enterViewMode = React.useCallback(() => setModalStage('view'), []); + + if (modalStage === 'edit') { + return ( + + ); + } + let content; if (inviteLink) { - content = ; + content = ( + + ); } else { - content = ; + content = ; } return (
{content}
); } export default ManageInviteLinksModal; diff --git a/web/invite-links/manage/edit-link-modal.react.js b/web/invite-links/manage/edit-link-modal.react.js new file mode 100644 index 000000000..db1af5595 --- /dev/null +++ b/web/invite-links/manage/edit-link-modal.react.js @@ -0,0 +1,67 @@ +// @flow + +import classnames from 'classnames'; +import * as React from 'react'; + +import { useModalContext } from 'lib/components/modal-provider.react.js'; +import { inviteLinkUrl } from 'lib/facts/links.js'; +import type { InviteLink } from 'lib/types/link-types.js'; + +import css from './manage-invite-links-modal.css'; +import Button from '../../components/button.react.js'; +import Input from '../../modals/input.react.js'; +import Modal from '../../modals/modal.react.js'; + +type Props = { + +inviteLink: ?InviteLink, + +enterViewMode: () => mixed, +}; + +function EditLinkModal(props: Props): React.Node { + const { inviteLink, enterViewMode } = props; + const [name, setName] = React.useState( + inviteLink?.name ?? Math.random().toString(36).slice(-9), + ); + const { popModal } = useModalContext(); + + const onChangeName = React.useCallback( + (event: SyntheticEvent) => { + setName(event.currentTarget.value); + }, + [], + ); + + return ( + +
+
+

+ Invite links make it easy for your friends to join your community. + Anybody who knows your community’s invite link will be able to join + it. +

+

+ Note that if you change your public link’s URL, other communities + will be able to claim the old URL. +

+
+
+
+ Invite URL +
+ {inviteLinkUrl('')} + +
+
+
+ + +
+
+
+ ); +} + +export default EditLinkModal; diff --git a/web/invite-links/manage/empty-link-content.react.js b/web/invite-links/manage/empty-link-content.react.js index ebec414d8..0ab80a7eb 100644 --- a/web/invite-links/manage/empty-link-content.react.js +++ b/web/invite-links/manage/empty-link-content.react.js @@ -1,23 +1,28 @@ // @flow import * as React from 'react'; import css from './manage-invite-links-modal.css'; import Button from '../../components/button.react.js'; const buttonColor = { color: 'var(--purple-link)', }; -function EmptyLinkContent(): React.Node { +type Props = { + +enterEditMode: () => mixed, +}; + +function EmptyLinkContent(props: Props): React.Node { + const { enterEditMode } = props; return (
Public link
-
); } export default EmptyLinkContent; diff --git a/web/invite-links/manage/existing-link-content.react.js b/web/invite-links/manage/existing-link-content.react.js index d43ddbf5e..6d32e0e35 100644 --- a/web/invite-links/manage/existing-link-content.react.js +++ b/web/invite-links/manage/existing-link-content.react.js @@ -1,42 +1,44 @@ // @flow import * as React from 'react'; import type { InviteLink } from 'lib/types/link-types.js'; import css from './manage-invite-links-modal.css'; import Button from '../../components/button.react.js'; import CopyInviteLinkButton from '../copy-invite-link-button.react.js'; const buttonColor = { color: 'var(--purple-link)', }; type Props = { +inviteLink: InviteLink, + +enterEditMode: () => mixed, }; function ExistingLinkContent(props: Props): React.Node { - const { inviteLink } = props; + const { inviteLink, enterEditMode } = props; return ( <>
Public link
{'Public links allow unlimited uses and never expire. '}
); } export default ExistingLinkContent; diff --git a/web/invite-links/manage/manage-invite-links-modal.css b/web/invite-links/manage/manage-invite-links-modal.css index 8d18e84d9..425c93633 100644 --- a/web/invite-links/manage/manage-invite-links-modal.css +++ b/web/invite-links/manage/manage-invite-links-modal.css @@ -1,27 +1,71 @@ .container { font-size: var(--m-font-16); padding: 24px 32px; } .sectionHeaderRow { display: flex; flex-direction: row; justify-content: space-between; align-items: center; } .sectionHeaderText { color: var(--fg); margin-bottom: 16px; } .description { font-size: var(--s-font-14); color: var(--fg); margin-top: 8px; } .inlineButton { display: inline; font-size: var(--s-font-14); } + +.editLinkContainer { + display: flex; + flex-direction: column; + gap: 32px; + color: var(--modal-fg); + font-size: var(--s-font-14); +} + +.editLinkDescription { + font-weight: var(--semi-bold); + color: var(--modal-fg); + display: flex; + flex-direction: column; + gap: 12px; +} + +.editLinkDescription p { + font-size: var(--s-font-14); +} + +.separator { + border-color: var(--border-color); + margin: 0; +} + +.linkSection { + display: flex; + flex-direction: column; + gap: 16px; +} + +.linkRow { + display: flex; + font-size: var(--m-font-16); + align-items: center; + gap: 8px; +} + +.buttonRow { + display: flex; + justify-content: flex-end; + gap: 8px; +} diff --git a/web/modals/input.react.js b/web/modals/input.react.js index 5b4ad0bec..a93de01dc 100644 --- a/web/modals/input.react.js +++ b/web/modals/input.react.js @@ -1,62 +1,62 @@ // @flow import classNames from 'classnames'; import * as React from 'react'; import css from './input.css'; export type BaseInputProps = { +value: string, +onChange: (value: SyntheticEvent) => mixed, +onBlur?: (value: SyntheticEvent) => mixed, +disabled?: boolean, +label?: string, +id?: string, +className?: string, }; export type InputProps = { ...BaseInputProps, +type: string, - +placeholder: string, + +placeholder?: string, +maxLength?: number, }; function Input(props: InputProps, ref): React.Node { const { label: labelProp, disabled = false, className = '', id, ...rest } = props; let label; if (labelProp) { label = ( ); } const inputClassName = classNames(css.input, className); return ( <> {label} ); } const ForwardedInput: React.AbstractComponent = React.forwardRef(Input); export default ForwardedInput;