Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable "Updates" section on organization #3567

Merged
merged 19 commits into from Mar 24, 2020
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
7 changes: 6 additions & 1 deletion components/CollectiveNavbar.js
Expand Up @@ -222,6 +222,7 @@ const DEFAULT_SECTIONS = {
[CollectiveType.ORGANIZATION]: [
Sections.CONTRIBUTIONS,
Sections.CONTRIBUTORS,
Sections.UPDATES,
Sections.CONVERSATIONS,
Sections.TRANSACTIONS,
Sections.ABOUT,
Expand Down Expand Up @@ -293,7 +294,11 @@ export const getSectionsForCollective = (collective, isAdmin) => {
toRemove.add(Sections.ABOUT);
}
}

if (collective.type === CollectiveType.ORGANIZATION) {
if (!hasFeature(collective, FEATURES.UPDATES)) {
toRemove.add(Sections.UPDATES);
}
}
if (collective.type === CollectiveType.EVENT) {
// Should not see tickets section if you can't order them
if ((!collective.isApproved && !isAdmin) || !canOrderTicketsFromEvent(collective)) {
Expand Down
2 changes: 1 addition & 1 deletion components/EditUpdateForm.js
Expand Up @@ -260,7 +260,7 @@ class EditUpdateForm extends React.Component {
disabled={this.state.loading}
>
{this.state.loading && <FormattedMessage id="form.processing" defaultMessage="processing" />}
{!this.state.loading && <FormattedMessage id="update.new.post" defaultMessage="Post Update" />}
{!this.state.loading && <FormattedMessage id="update.new.preview" defaultMessage="Preview Update" />}
</StyledButton>
</ActionButtonWrapper>

Expand Down
3 changes: 3 additions & 0 deletions components/edit-collective/EditCollectiveForm.js
Expand Up @@ -38,6 +38,7 @@ import EditCollectiveHostAccount from './EditCollectiveHostAccount';
import EditUserEmailForm from './EditUserEmailForm';
import EditHostInvoice from './EditHostInvoice';
import EditCollectiveConversations from './EditCollectiveConversations';
import EditCollectiveUpdates from './EditCollectiveUpdates';
import EditHostSettings from './EditHostSettings';

import MenuEditCollective, { EDIT_COLLECTIVE_SECTIONS } from './MenuEditCollective';
Expand Down Expand Up @@ -352,6 +353,8 @@ class EditCollectiveForm extends React.Component {
return <EditMembers collective={collective} LoggedInUser={LoggedInUser} />;
} else if (section === EDIT_COLLECTIVE_SECTIONS.INVOICES) {
return <EditHostInvoice collective={collective} />;
} else if (section === EDIT_COLLECTIVE_SECTIONS.UPDATES) {
return <EditCollectiveUpdates collective={collective} />;
} else if (section === EDIT_COLLECTIVE_SECTIONS.CONVERSATIONS) {
return <EditCollectiveConversations collective={collective} />;
} else if (section === EDIT_COLLECTIVE_SECTIONS.WEBHOOKS) {
Expand Down
118 changes: 118 additions & 0 deletions components/edit-collective/EditCollectiveUpdates.js
@@ -0,0 +1,118 @@
import { Flex } from '@rebass/grid';
import { set, cloneDeep, pick } from 'lodash';
import PropTypes from 'prop-types';
import React from 'react';
import { useMutation } from '@apollo/react-hooks';
import { useIntl, defineMessages } from 'react-intl';
import styled from 'styled-components';

import imgPreviewList from '../../public/static/images/updates/updates-list-preview.png';
import imgPreviewNewUpdate from '../../public/static/images/updates/updates-new-preview.png';

import { getErrorFromGraphqlException } from '../../lib/errors';
import hasFeature, { FEATURES, FEATURE_FLAGS } from '../../lib/allowed-features';
import CreateUpdateFAQ from '../faqs/CreateUpdateFAQ';
import Container from '../Container';
import MessageBox from '../MessageBox';
import { H3, P } from '../Text';
import StyledCheckbox from '../StyledCheckbox';
import Link from '../Link';

import { updateSettingsMutation } from './mutations';

const messages = defineMessages({
title: {
id: 'updates',
defaultMessage: 'Updates',
},
mainDescription: {
id: 'EditCollective.Updates.description',
defaultMessage:
'Updates is a way to keep your community posted on your progress. Once enabled, a new "Updates" section will be added to your profile page and a dedicated page will be created on {updatesLink}.',
xdamman marked this conversation as resolved.
Show resolved Hide resolved
},
checkboxLabel: {
id: 'EditCollective.Updates.checkbox',
defaultMessage: 'Enable updates',
},
});

const ScreenshotPreview = styled.div`
display: block;
margin: 8px;
padding: 8px;
height: 240px;
border: 1px solid #ececec;
border-radius: 16px;

img {
max-height: 100%;
}
`;

/**
* A presentation of the updates feature, with a checkbox to (de-)activate it.
*/
const EditCollectiveUpdates = ({ collective }) => {
const defaultIsChecked = hasFeature(collective, FEATURES.UPDATES);
const { formatMessage } = useIntl();
const [setSettings, { loading, error }] = useMutation(updateSettingsMutation);

return (
<Container>
<H3>{formatMessage(messages.title)}</H3>
<Flex mb={2} flexWrap="wrap" justifyContent="center">
<Container mr={3} pr={3} flex="1 1" minWidth={300} maxWidth={700} borderRight={[null, '1px solid #dcdee0']}>
<P wordBreak="break-word">
{formatMessage(messages.mainDescription, {
updatesLink: (
<Link route="updates" params={{ collectiveSlug: collective.slug }}>
{process.env.WEBSITE_URL}/{collective.slug}/updates
</Link>
),
})}
</P>
</Container>
<Flex flexDirection="column" alignItems="center" justifyContent="center" minWidth={300}>
<StyledCheckbox
name="enable-updates"
label={formatMessage(messages.checkboxLabel)}
defaultChecked={defaultIsChecked}
width="auto"
isLoading={loading}
onChange={({ target }) => {
const updatedCollective = cloneDeep(collective);
set(updatedCollective, FEATURE_FLAGS.UPDATES, target.value);
return setSettings({ variables: pick(updatedCollective, ['id', 'settings']) });
}}
/>
</Flex>
</Flex>
{error && (
<MessageBox type="error" fontSize="Paragraph" withIcon mb={3}>
{getErrorFromGraphqlException(error).message}
</MessageBox>
)}
<Flex flexWrap="wrap" justifyContent="space-between" width="100%">
<ScreenshotPreview>
<img src={imgPreviewNewUpdate} alt="Preview new update" />
</ScreenshotPreview>
<ScreenshotPreview>
<img src={imgPreviewList} alt="Preview updates list" />
</ScreenshotPreview>
<hr />
</Flex>
<hr />
<CreateUpdateFAQ defaultOpen />
</Container>
);
};

EditCollectiveUpdates.propTypes = {
collective: PropTypes.shape({
id: PropTypes.number.isRequired,
settings: PropTypes.object,
slug: PropTypes.string.isRequired,
}).isRequired,
};

export default EditCollectiveUpdates;
6 changes: 6 additions & 0 deletions components/edit-collective/MenuEditCollective.js
Expand Up @@ -16,6 +16,7 @@ export const EDIT_COLLECTIVE_SECTIONS = {
INFO: 'info', // First on purpose
COLLECTIVE_GOALS: 'goals',
CONNECTED_ACCOUNTS: 'connected-accounts',
UPDATES: 'updates',
CONVERSATIONS: 'conversations',
EXPENSES: 'expenses',
EXPORT: 'export',
Expand Down Expand Up @@ -45,6 +46,10 @@ const SECTION_LABELS = defineMessages({
id: 'editCollective.menu.connectedAccounts',
defaultMessage: 'Connected Accounts',
},
[EDIT_COLLECTIVE_SECTIONS.UPDATES]: {
id: 'updates',
defaultMessage: 'Updates',
},
[EDIT_COLLECTIVE_SECTIONS.CONVERSATIONS]: {
id: 'conversations',
defaultMessage: 'Conversations',
Expand Down Expand Up @@ -123,6 +128,7 @@ const isOneOfTypes = (...collectiveTypes) => ({ type }) => collectiveTypes.inclu
const isFeatureAllowed = feature => ({ type }) => isFeatureAllowedForCollectiveType(type, feature);
const sectionsDisplayConditions = {
[EDIT_COLLECTIVE_SECTIONS.COLLECTIVE_GOALS]: isType(CollectiveType.COLLECTIVE),
[EDIT_COLLECTIVE_SECTIONS.UPDATES]: isFeatureAllowed(FEATURES.UPDATES),
[EDIT_COLLECTIVE_SECTIONS.CONVERSATIONS]: isFeatureAllowed(FEATURES.CONVERSATIONS),
[EDIT_COLLECTIVE_SECTIONS.EXPENSES]: isType(CollectiveType.COLLECTIVE),
[EDIT_COLLECTIVE_SECTIONS.EXPORT]: isType(CollectiveType.COLLECTIVE),
Expand Down
62 changes: 62 additions & 0 deletions components/faqs/CreateUpdateFAQ.js
@@ -0,0 +1,62 @@
import React from 'react';
import PropTypes from 'prop-types';
import { FormattedMessage } from 'react-intl';
import FAQ, { Entry, Title, Content } from './FAQ';

const CreateUpdateFAQ = ({ defaultOpen, ...props }) => (
<FAQ {...props}>
<Entry open={defaultOpen}>
<Title>
<FormattedMessage id="CreateUpdateFAQ.target" defaultMessage="Who can see updates?" />
</Title>
<Content>
<FormattedMessage
id="CreateUpdateFAQ.target.content"
defaultMessage="Updates can be public or private in which case only the contributors of the collective can see them. Whenever you post a new update, you can define whether it should be public or private."
/>
</Content>
</Entry>
<Entry open={defaultOpen}>
<Title>
<FormattedMessage
id="CreateUpdateFAQ.notification"
defaultMessage="Who gets a notification whenever there is a new update?"
/>
</Title>
<Content>
<FormattedMessage
id="CreateUpdateFAQ.notification.content"
defaultMessage="All contributors of the collective will receive a notification by default. They can easily unsubscribe with one click."
/>
</Content>
</Entry>
<Entry open={defaultOpen}>
<Title>
<FormattedMessage id="CreateUpdateFAQ.moderation" defaultMessage="Who can post an update?" />
</Title>
<Content>
<FormattedMessage
id="CreateUpdateFAQ.moderation.content"
defaultMessage="Only the administrators of this collective can post updates."
/>
</Content>
</Entry>
<Entry open={defaultOpen}>
<Title>
<FormattedMessage id="CreateUpdateFAQ.replies" defaultMessage="What should we use updates for?" />
</Title>
<Content>
<FormattedMessage
id="CreateUpdateFAQ.whatfor.content"
defaultMessage="Updates are great to keep your community of contributors up to date with what you do. They should preferably be low volume (at least once a month, ideally no more than once a week). If your contributors hear regularly from you, they will more likely engage, help you and continue to support you. Updates are also great for your fiscal sponsor and for writing reports for grants that you may have."
/>
</Content>
</Entry>
</FAQ>
);

CreateUpdateFAQ.propTypes = {
defaultOpen: PropTypes.bool,
};

export default CreateUpdateFAQ;
13 changes: 12 additions & 1 deletion lang/en.json
Expand Up @@ -501,6 +501,14 @@
"createProfile.faq.privacy.title": "What about privacy?",
"CreateProfile.OrgInfo": "Organization's information",
"CreateProfile.PersonalInfo": "Your personal information",
"CreateUpdateFAQ.moderation": "Who can post an update?",
"CreateUpdateFAQ.moderation.content": "Only the administrators of this collective can post updates.",
"CreateUpdateFAQ.notification": "Who gets a notification whenever there is a new update?",
"CreateUpdateFAQ.notification.content": "All contributors of the collective will receive a notification by default. They can easily unsubscribe with one click.",
"CreateUpdateFAQ.replies": "What should we use updates for?",
"CreateUpdateFAQ.target": "Who can see updates?",
"CreateUpdateFAQ.target.content": "Updates can be public or private in which case only the contributors of the collective can see them. Whenever you post a new update, you can define whether it should be public or private.",
"CreateUpdateFAQ.whatfor.content": "Updates are great to keep your community of contributors up to date with what you do. They should preferably be low volume (at least once a month, ideally no more than once a week). If your contributors hear regularly from you, they will more likely engage, help you and continue to support you. Updates are also great for your fiscal sponsor and for writing reports for grants that you may have.",
"CreateVirtualCardsSuccess.Download": "Download cards",
"CreateVirtualCardsSuccess.RedeemLinks": "Copy the links",
"creditcard.label": "Credit Card",
Expand Down Expand Up @@ -550,6 +558,8 @@
"editCollective.menu.virtualCards": "Gift Cards",
"editCollective.menu.webhooks": "Webhooks",
"editCollective.notFound": "No collective data to edit",
"EditCollective.Updates.checkbox": "Enable updates",
"EditCollective.Updates.description": "Updates is a way to keep your community posted on your progress. Once enabled, a new \"Updates\" section will be added to your profile page and a dedicated page will be created on {updatesLink}.",
"EditCollective.VAT": "VAT settings",
"EditCollective.VAT.Description": "European Value Added Tax",
"EditCollective.VAT.Host": "Use the host VAT settings",
Expand Down Expand Up @@ -1387,7 +1397,7 @@
"update.createdAtBy": "Created on {date} (draft) by {author}",
"update.delete": "delete",
"update.makePublicOn.label": "Automatically make public on this date",
"update.new.post": "Post Update",
"update.new.preview": "Preview Update",
"update.private.cannot_view_message": "Become a backer of {collective} to see this update",
"update.private.description": "Only contributors will be able to see the content of this update",
"update.private.lock_text": "This update is private",
Expand All @@ -1402,6 +1412,7 @@
"updatePaymentMethod.form.updatePaymentMethodSuccess.btn": "Go to Collective page",
"updatePaymentMethod.subtitle.line": "Please add a new payment method for the following subscriptions before your current one expires.",
"updatePaymentMethod.title": "Update Payment Method",
"updates": "Updates",
"updates.create.login": "You need to be logged in as a core contributor of this collective to be able to create an update.",
"updates.empty": "No updates",
"updates.new.error": "Update failed: {err}",
Expand Down