Merge pull request #3171 from urbit/mp/toggle-public

groups: add private group toggle
This commit is contained in:
matildepark 2020-07-24 00:21:46 -04:00 committed by GitHub
commit 3f78392c2c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 69 additions and 42 deletions

View File

@ -6,6 +6,7 @@ import { Spinner } from '../../../components/Spinner';
import { ChatTabBar } from './lib/chat-tabbar'; import { ChatTabBar } from './lib/chat-tabbar';
import { InviteSearch } from '../../../components/InviteSearch'; import { InviteSearch } from '../../../components/InviteSearch';
import SidebarSwitcher from '../../../components/SidebarSwitch'; import SidebarSwitcher from '../../../components/SidebarSwitch';
import Toggle from '../../../components/toggle';
export class SettingsScreen extends Component { export class SettingsScreen extends Component {
constructor(props) { constructor(props) {
@ -195,18 +196,12 @@ export class SettingsScreen extends Component {
} else { } else {
let inclusiveToggle = <div />; let inclusiveToggle = <div />;
if (state.targetGroup) { if (state.targetGroup) {
// TODO toggle component into /lib
const inclusiveClasses = state.inclusive
? 'relative checked bg-green2 br3 h1 toggle v-mid z-0'
: 'relative bg-gray4 bg-gray1-d br3 h1 toggle v-mid z-0';
inclusiveToggle = ( inclusiveToggle = (
<div className="mt4"> <div className="mt4">
<input <Toggle
type="checkbox" boolean={state.inclusive}
style={{ WebkitAppearance: 'none', width: 28 }} change={this.changeInclusive}
className={inclusiveClasses} />
onChange={this.changeInclusive}
/>
<span className="dib f9 white-d inter ml3"> <span className="dib f9 white-d inter ml3">
Add all members to group Add all members to group
</span> </span>

View File

@ -1,8 +1,10 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import { Spinner } from '../../../../components/Spinner'; import { Spinner } from '../../../../components/Spinner';
import { Toggle } from '../../../../components/toggle';
import { GroupView } from '../../../../components/Group'; import { GroupView } from '../../../../components/Group';
import { deSig, uxToHex, writeText } from '../../../../lib/util'; import { deSig, uxToHex, writeText } from '../../../../lib/util';
import { roleForShip, resourceFromPath } from '../../../../lib/group';
export class GroupDetail extends Component { export class GroupDetail extends Component {
constructor(props) { constructor(props) {
@ -15,6 +17,7 @@ export class GroupDetail extends Component {
}; };
this.changeTitle = this.changeTitle.bind(this); this.changeTitle = this.changeTitle.bind(this);
this.changeDescription = this.changeDescription.bind(this); this.changeDescription = this.changeDescription.bind(this);
this.changePolicy = this.changePolicy.bind(this);
} }
componentDidMount() { componentDidMount() {
@ -47,6 +50,17 @@ export class GroupDetail extends Component {
this.setState({ description: event.target.value }); this.setState({ description: event.target.value });
} }
changePolicy() {
this.setState({ awaiting: true }, () => {
this.props.api.groups.changePolicy(resourceFromPath(this.props.path),
Boolean(this.props.group?.policy?.open)
? { replace: { invite: { pending: [] } } }
: { replace: { open: { banned: [], banRanks: [] } } }
).then(() => this.setState({ awaiting: false }));
}
);
}
renderDetail() { renderDetail() {
const { props } = this; const { props } = this;
@ -175,7 +189,8 @@ export class GroupDetail extends Component {
const { group, association } = props; const { group, association } = props;
const groupOwner = (deSig(props.match.params.ship) === window.ship); const ourRole = roleForShip(group, window.ship);
const groupOwner = (ourRole === 'admin');
const deleteButtonClasses = (groupOwner) ? 'b--red2 red2 pointer bg-gray0-d' : 'b--gray3 gray3 bg-gray0-d c-default'; const deleteButtonClasses = (groupOwner) ? 'b--red2 red2 pointer bg-gray0-d' : 'b--gray3 gray3 bg-gray0-d c-default';
@ -280,7 +295,17 @@ export class GroupDetail extends Component {
}} }}
/> />
</div> </div>
<p className="f9 mt3 lh-copy">Delete Group</p> <div className="relative w-100 mt6" style={{ maxWidth: '29rem' }}>
<Toggle
boolean={(Boolean(group?.policy?.invite))}
change={this.changePolicy}
/>
<span className="dib f9 white-d inter ml3">Private Group</span>
<p className="f9 gray2 pt1" style={{ paddingLeft: 40 }}>
If private, members must be invited
</p>
</div>
<p className="f9 mt6 lh-copy">Delete Group</p>
<p className="f9 gray2 mb2"> <p className="f9 gray2 mb2">
Permanently delete this group. All current members will no longer see this group. Permanently delete this group. All current members will no longer see this group.
</p> </p>

View File

@ -3,6 +3,7 @@ import React, { Component } from 'react';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import { InviteSearch, Invites } from '../../../components/InviteSearch'; import { InviteSearch, Invites } from '../../../components/InviteSearch';
import { Spinner } from '../../../components/Spinner'; import { Spinner } from '../../../components/Spinner';
import { Toggle } from '../../../components/toggle';
import { RouteComponentProps } from 'react-router-dom'; import { RouteComponentProps } from 'react-router-dom';
import { Groups, GroupPolicy, Resource } from '../../../types/group-update'; import { Groups, GroupPolicy, Resource } from '../../../types/group-update';
import { Contacts, Rolodex } from '../../../types/contact-update'; import { Contacts, Rolodex } from '../../../types/contact-update';
@ -129,9 +130,6 @@ export class NewScreen extends Component<NewScreenProps, NewScreenState> {
</span> </span>
); );
} }
const privacySwitchClasses = this.state.privacy
? 'relative checked bg-green2 br3 h1 toggle v-mid z-0'
: 'relative bg-gray4 bg-gray1-d br3 h1 toggle v-mid z-0';
return ( return (
<div className='h-100 w-100 mw6 pa3 pt4 overflow-x-hidden bg-gray0-d white-d flex flex-column'> <div className='h-100 w-100 mw6 pa3 pt4 overflow-x-hidden bg-gray0-d white-d flex flex-column'>
@ -174,11 +172,9 @@ export class NewScreen extends Component<NewScreenProps, NewScreenState> {
onChange={this.descriptionChange} onChange={this.descriptionChange}
/> />
<div className='mv7'> <div className='mv7'>
<input <Toggle
type='checkbox' boolean={this.state.privacy}
style={{ WebkitAppearance: 'none', width: 28 }} change={this.groupPrivacyChange}
onChange={this.groupPrivacyChange}
className={privacySwitchClasses}
/> />
<span className='dib f9 white-d inter ml3'>Private Group</span> <span className='dib f9 white-d inter ml3'>Private Group</span>
<p className='f9 gray2 pt1' style={{ paddingLeft: 40 }}> <p className='f9 gray2 pt1' style={{ paddingLeft: 40 }}>

View File

@ -1,7 +1,7 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import { writeText } from '../../../../lib/util';
import { Spinner } from '../../../../components/Spinner'; import { Spinner } from '../../../../components/Spinner';
import { InviteSearch } from '../../../../components/InviteSearch'; import { InviteSearch } from '../../../../components/InviteSearch';
import Toggle from '../../../../components/toggle';
export class Settings extends Component { export class Settings extends Component {
constructor(props) { constructor(props) {
@ -133,22 +133,16 @@ export class Settings extends Component {
// don't give the option to make inclusive if we don't own the target // don't give the option to make inclusive if we don't own the target
// group // group
const targetOwned = (state.targetGroup) const targetOwned = (state.targetGroup)
? state.targetGroup.slice(0, window.ship.length+3) === `/~${window.ship}/` ? Boolean(state.targetGroup.includes(`/~${window.ship}/`))
: false; : false;
let inclusiveToggle = <div />; let inclusiveToggle = <div />;
if (targetOwned) { if (targetOwned) {
// TODO toggle component into /lib
const inclusiveClasses = state.inclusive
? 'relative checked bg-green2 br3 h1 toggle v-mid z-0'
: 'relative bg-gray4 bg-gray1-d br3 h1 toggle v-mid z-0';
inclusiveToggle = ( inclusiveToggle = (
<div className="mt4"> <div className="mt4">
<input <Toggle
type="checkbox" boolean={state.inclusive}
style={{ WebkitAppearance: 'none', width: 28 }} change={this.changeInclusive}
className={inclusiveClasses} />
onChange={this.changeInclusive}
/>
<span className="dib f9 white-d inter ml3"> <span className="dib f9 white-d inter ml3">
Add all members to group Add all members to group
</span> </span>
@ -201,10 +195,6 @@ export class Settings extends Component {
} }
render() { render() {
const commentsSwitchClasses = (this.state.comments)
? 'relative checked bg-green2 br3 h1 toggle v-mid z-0'
: 'relative bg-gray4 bg-gray1-d br3 h1 toggle v-mid z-0';
if (this.props.host.slice(1) === window.ship) { if (this.props.host.slice(1) === window.ship) {
return ( return (
<div className="flex-column"> <div className="flex-column">
@ -274,11 +264,9 @@ export class Settings extends Component {
/> />
</div> </div>
<div className="mv6"> <div className="mv6">
<input <Toggle
type="checkbox" boolean={this.state.comments}
style={{ WebkitAppearance: 'none', width: 28 }} change={this.changeComments}
className={commentsSwitchClasses}
onChange={this.changeComments}
/> />
<span className="dib f9 white-d inter ml3">Comments</span> <span className="dib f9 white-d inter ml3">Comments</span>
<p className="f9 gray2 pt1" style={{ paddingLeft: 40 }}> <p className="f9 gray2 pt1" style={{ paddingLeft: 40 }}>
@ -293,7 +281,7 @@ export class Settings extends Component {
</div> </div>
); );
} else { } else {
return copyShortcode; return '';
} }
} }
} }

View File

@ -0,0 +1,20 @@
import React, { Component } from 'react';
export class Toggle extends Component {
render() {
const switchClasses = (this.props.boolean)
? 'relative checked bg-green2 br3 h1 toggle v-mid z-0'
: 'relative bg-gray4 bg-gray1-d br3 h1 toggle v-mid z-0';
return (
<input
type="checkbox"
style={{ WebkitAppearance: 'none', width: 28 }}
className={switchClasses}
onChange={this.props.change}
/>
);
}
}
export default Toggle;

View File

@ -6,6 +6,7 @@ import {
Group, Group,
Tags, Tags,
GroupPolicy, GroupPolicy,
GroupPolicyDiff,
OpenPolicyDiff, OpenPolicyDiff,
OpenPolicy, OpenPolicy,
InvitePolicyDiff, InvitePolicyDiff,
@ -179,6 +180,8 @@ export default class GroupReducer<S extends GroupState> {
this.openChangePolicy(diff.open, policy); this.openChangePolicy(diff.open, policy);
} else if ('invite' in policy && 'invite' in diff) { } else if ('invite' in policy && 'invite' in diff) {
this.inviteChangePolicy(diff.invite, policy); this.inviteChangePolicy(diff.invite, policy);
} else if ('replace' in diff) {
state.groups[resourcePath].policy = diff.replace;
} else { } else {
console.log('bad policy diff'); console.log('bad policy diff');
} }