From 62b88ed8d0f8f1dddb9b69aeb9b1d1d46d2ff226 Mon Sep 17 00:00:00 2001 From: tudi2d Date: Thu, 12 Mar 2020 15:36:28 +0100 Subject: [PATCH 01/17] Remove image caption - Remove references & tests for image caption - Remove old unnecessary .save file --- cypress/fixtures/seed/howtos.json | 5 +- cypress/integration/howto/write.spec.ts | 18 +- cypress/support/custom-assertions.ts | 5 +- src/models/howto.models.tsx | 3 - src/pages/Howto/Content/Common/Howto.form.tsx | 8 - .../Howto/Content/Common/Howto.form.tsx.save | 451 ------------------ .../Howto/Content/Common/HowtoStep.form.tsx | 8 - .../Howto/Content/CreateHowto/Template.tsx | 3 - .../Howto/Content/EditHowto/Template.tsx | 3 - .../Howto/Content/Howto/Step/ImageGallery.tsx | 3 - src/pages/Howto/Content/Howto/Step/Step.tsx | 1 - 11 files changed, 4 insertions(+), 504 deletions(-) delete mode 100644 src/pages/Howto/Content/Common/Howto.form.tsx.save diff --git a/cypress/fixtures/seed/howtos.json b/cypress/fixtures/seed/howtos.json index 1f877ac264..3392e6b0b3 100644 --- a/cypress/fixtures/seed/howtos.json +++ b/cypress/fixtures/seed/howtos.json @@ -2002,7 +2002,6 @@ ], "text": "Alright so before starting, here some basics to check out and prepare first.\n\nFor this technique you will need:\nMachines: Shredder (or already shredded plastic), Extrusion machine, Oven\nTools: Scissors / Knife, Pliers, Weighing scales and two containers, Silicone oil, Clamps, Spanner\nMaterials: Polystyrene and pigment\n\nIf you haven't extruded beams before, learn more in the How-to \"Make a mould for beams\".\n(https://community.preciousplastic.com/how-to/make-a-mould-for-extruding-beams)", "_animationKey": "unique1", - "caption": "", "title": "Get ready" }, { @@ -2020,7 +2019,6 @@ ], "text": "When melting plastic, bad fumes can be released. In order to work safer, make sure to use a breathing mask with ABEK filters to prevent inhaling possibly toxic fumes. Special attention on plastics like PS (polystyrene) and PVC. Also when handling with heated elements and plastic we recommend to wear working gloves.\n\nRecommended safety equipment: ABEK mask, gloves and glasses", "_animationKey": "unique2", - "caption": "", "title": "Stay safe" }, { @@ -2038,8 +2036,7 @@ } ], "text": "Selecting the right material is crucial when it comes to aesthetics. What properties does the material have, what colour is it? \nAs PS stays transparent in the recycling process, it has the perfect quality to make a light. Collect your clean PS, which is typically found in old CD and cassette cases. Make sure to shred enough, the required amount will vary depending on the size of your mould.", - "_animationKey": "unique3", - "caption": "" + "_animationKey": "unique3" }, { "text": "Now we use pigment to add colour to the transparent polystyrene. You can find it online (search for 'pigment for polystyrene'), but do check out if you can find it in a local shop. Using pigment has the advantage that it keeps the translucency of your material. If you only have access to coloured PS plastic, you will probably not get the same effect (unless the plastic is also translucent), so this will need some testing.\nโ€จStart by cutting one pellet of pigment into smaller pieces. The pigment we use (___) has a really strong affect so you only need a small amount to mix with.", diff --git a/cypress/integration/howto/write.spec.ts b/cypress/integration/howto/write.spec.ts index 6e77b874dc..ba422816ca 100644 --- a/cypress/integration/howto/write.spec.ts +++ b/cypress/integration/howto/write.spec.ts @@ -30,7 +30,6 @@ describe('[How To]', () => { stepNumber: number, title: string, description: string, - caption: string, images: string[], ) => { const stepIndex = stepNumber - 1 @@ -42,9 +41,6 @@ describe('[How To]', () => { cy.get('[data-cy=step-description]') .clear() .type(`Description for step ${stepNumber}`) - cy.get('[data-cy=step-caption]') - .clear() - .type('What a step caption') cy.step('Uploading pics') const hasExistingPics = Cypress.$($step).find('[data-cy=delete-step-img]').length > 0 @@ -76,7 +72,6 @@ describe('[How To]', () => { const expected = { _createdBy: 'howto_creator', _deleted: false, - caption: 'Intro caption goes here ...', description: 'After creating, the how-to will be deleted', difficulty_level: 'Medium', time: '1-2 weeks', @@ -95,7 +90,6 @@ describe('[How To]', () => { steps: [ { _animationKey: 'unique1', - caption: 'What a step caption', images: [ { contentType: 'image/jpeg', @@ -115,7 +109,6 @@ describe('[How To]', () => { }, { _animationKey: 'unique2', - caption: 'What a step caption', images: [], text: 'Description for step 2', title: 'Step 2 is easy', @@ -144,14 +137,13 @@ describe('[How To]', () => { selectDifficultLevel(expected.difficulty_level as Difficulty) cy.get('[data-cy=intro-description]').type(expected.description) - cy.get('[data-cy=intro-caption]').type(expected.caption) cy.step('Upload a cover for the intro') cy.get('[data-cy=intro-cover]') .find(':file') .uploadFiles('images/howto-intro.jpg') expected.steps.forEach((step, index) => { - fillStep(index + 1, step.title, step.text, step.caption, [ + fillStep(index + 1, step.title, step.text, [ 'images/howto-step-pic1.jpg', 'images/howto-step-pic2.jpg', ]) @@ -185,7 +177,6 @@ describe('[How To]', () => { const expected = { _createdBy: 'howto_editor', _deleted: false, - caption: 'Caption edited!', description: 'After editing, all changes are reverted', difficulty_level: 'Hard', files: [], @@ -202,7 +193,6 @@ describe('[How To]', () => { steps: [ { _animationKey: 'unique1', - caption: 'What a step caption', images: [ { contentType: 'image/jpeg', @@ -222,7 +212,6 @@ describe('[How To]', () => { }, { _animationKey: 'unique3', - caption: 'What a step caption', images: [ { contentType: 'image/jpeg', @@ -277,9 +266,6 @@ describe('[How To]', () => { cy.get('[data-cy=intro-description]') .clear() .type(expected.description) - cy.get('[data-cy=intro-caption]') - .clear() - .type(expected.caption) cy.step('Update a new cover for the intro') @@ -292,7 +278,7 @@ describe('[How To]', () => { deleteStep(2) expected.steps.forEach((step, index) => { - fillStep(index + 1, step.title, step.text, step.caption, [ + fillStep(index + 1, step.title, step.text, [ 'images/howto-step-pic1.jpg', 'images/howto-step-pic2.jpg', ]) diff --git a/cypress/support/custom-assertions.ts b/cypress/support/custom-assertions.ts index c5fd2839cd..b7ec899c1d 100644 --- a/cypress/support/custom-assertions.ts +++ b/cypress/support/custom-assertions.ts @@ -18,7 +18,6 @@ const eqHowto = (chaiObj, utils) => { const { _createdBy, _deleted, - caption, description, difficulty_level, slug, @@ -29,7 +28,6 @@ const eqHowto = (chaiObj, utils) => { expect(subject, 'Basic info').to.containSubset({ _createdBy, _deleted, - caption, description, difficulty_level, slug, @@ -53,10 +51,9 @@ const eqHowto = (chaiObj, utils) => { const eqHowtoStep = (chaiObj, utils) => { function compare(this: any, expected: any, index: number) { const subject: IHowtoStep = this._obj - const { _animationKey, caption, text, title } = expected + const { _animationKey, text, title } = expected expect(subject, `Step ${index} with info`).to.containSubset({ _animationKey, - caption, text, title, }) diff --git a/src/models/howto.models.tsx b/src/models/howto.models.tsx index 42c60e0031..fd0cefe637 100644 --- a/src/models/howto.models.tsx +++ b/src/models/howto.models.tsx @@ -22,7 +22,6 @@ export interface IHowtoStep extends IHowToStepFormInput { images: Array title: string text: string - caption?: string _animationKey?: string } @@ -30,7 +29,6 @@ export interface IHowToStepFormInput { images: Array title: string text: string - caption?: string _animationKey?: string } @@ -46,5 +44,4 @@ export interface IHowtoFormInput extends IModerable { slug: string // note, tags will remain optional as if populated {} will be stripped by db (firestore) tags?: ISelectedTags - caption?: string } diff --git a/src/pages/Howto/Content/Common/Howto.form.tsx b/src/pages/Howto/Content/Common/Howto.form.tsx index 73c2e63bb5..41d62079be 100644 --- a/src/pages/Howto/Content/Common/Howto.form.tsx +++ b/src/pages/Howto/Content/Common/Howto.form.tsx @@ -357,14 +357,6 @@ export class HowtoForm extends React.Component { This image should be landscape. We advise 1280x960px - - - diff --git a/src/pages/Howto/Content/Common/Howto.form.tsx.save b/src/pages/Howto/Content/Common/Howto.form.tsx.save deleted file mode 100644 index 165d3848d9..0000000000 --- a/src/pages/Howto/Content/Common/Howto.form.tsx.save +++ /dev/null @@ -1,451 +0,0 @@ -import * as React from 'react' -import { RouteComponentProps, Prompt } from 'react-router' -import { Form, Field } from 'react-final-form' -import styled from 'styled-components' -import { FieldArray } from 'react-final-form-arrays' -import arrayMutators from 'final-form-arrays' -import createDecorator from 'final-form-calculate' -import { IHowtoFormInput, IHowto } from 'src/models/howto.models' -import Text from 'src/components/Text' -import { UploadedFile } from 'src/pages/common/UploadedFile/UploadedFile' -import { InputField, TextAreaField } from 'src/components/Form/Fields' -import { SelectField } from 'src/components/Form/Select.field' -import { HowtoStep } from './HowtoStep.form' -import { Button } from 'src/components/Button' -import { HowtoStore } from 'src/stores/Howto/howto.store' -import Heading from 'src/components/Heading' -import Flex from 'src/components/Flex' -import { TagsSelectField } from 'src/components/Form/TagsSelect.field' -import { ImageInputField } from 'src/components/Form/ImageInput.field' -import { FileInputField } from 'src/components/Form/FileInput.field' -import posed, { PoseGroup } from 'react-pose' -import { inject, observer } from 'mobx-react' -import { stripSpecialCharacters } from 'src/utils/helpers' -import { PostingGuidelines } from './PostingGuidelines' -import theme from 'src/themes/styled.theme' -import { DIFFICULTY_OPTIONS, TIME_OPTIONS } from './FormSettings' -import { Image, Box } from 'rebass' -import { FileInfo } from 'src/components/FileInfo/FileInfo' -import { HowToSubmitStatus } from './SubmitStatus' -import { required } from 'src/utils/validators' - -interface IState { - formSaved: boolean - _toDocsList: boolean - showSubmitModal?: boolean - editCoverImg?: boolean - fileEditMode?: boolean - draft?: boolean -} -interface IProps extends RouteComponentProps { - formValues: any - parentType: 'create' | 'edit' -} -interface IInjectedProps extends IProps { - howtoStore: HowtoStore -} - -const AnimationContainer = posed.div({ - // use flip pose to prevent default spring action on list item removed - flip: { - transition: { - // type: 'tween', - // ease: 'linear', - }, - }, - // use a pre-enter pose as otherwise default will be the exit state and so will animate - // horizontally as well - preEnter: { - opacity: 0, - }, - enter: { - opacity: 1, - duration: 200, - applyAtStart: { display: 'block' }, - }, - exit: { - applyAtStart: { display: 'none' }, - duration: 200, - }, -}) - -const Label = styled.label` - font-size: ${theme.fontSizes[2] + 'px'}; - margin-bottom: ${theme.space[2] + 'px'}; - display: block; -` - -@inject('howtoStore') -@observer -export class HowtoForm extends React.Component { - uploadRefs: { [key: string]: UploadedFile | null } = {} - constructor(props: any) { - super(props) - this.state = { - formSaved: false, - _toDocsList: false, - editCoverImg: false, - fileEditMode: false, - showSubmitModal: false, - } - } - - private trySubmitForm = (draft: boolean) => { - this.setState({ draft: draft}) - const form = document.getElementById('howtoForm') - if (typeof form !== 'undefined' && form !== null) { - console.log(draft); - form.dispatchEvent( - new Event('submit', { cancelable: true }), - ) - this.setState({ showSubmitModal: true, draft: draft}) - } - } - public onSubmit = async (formValues: IHowtoFormInput) => { - console.log('\n\nState:'); - console.log(this.state.draft); - formValues.moderation = this.state.draft ? 'draft' : 'awaiting-moderation'; - console.log(formValues.moderation); - await this.store.uploadHowTo(formValues) - console.log(this.state.draft); - } - - get injected() { - return this.props as IInjectedProps - } - get store() { - return this.injected.howtoStore - } - - public validateTitle = async (value: any) => { - return this.store.validateTitle(value, 'v3_howtos') - } - - // automatically generate the slug when the title changes - private calculatedFields = createDecorator({ - field: 'title', - updates: { - slug: title => stripSpecialCharacters(title).toLowerCase(), - }, - }) - public render() { - const { formValues, parentType } = this.props - const { fileEditMode, showSubmitModal } = this.state - return ( - <> - {showSubmitModal && ( - { - this.setState({ showSubmitModal: false }) - this.injected.howtoStore.resetUploadStatus() - }} - /> - )} - -
{ - this.onSubmit(v as IHowtoFormInput) - }} - initialValues={formValues} - mutators={{ - ...arrayMutators, - }} - validateOnBlur - decorators={[this.calculatedFields]} - render={({ submitting, values, invalid, errors, handleSubmit }) => { - const disabled = invalid || submitting - return ( - - - - {/* How To Info */} - - - - {this.props.parentType === 'create' ? ( - Create - ) : ( - Edit - )}{' '} - your How-To - - - - {/* Left Side */} - - Intro - - - - - - - this.props.parentType === 'create' - ? this.validateTitle(value) - : false - } - component={InputField} - placeholder="Make a chair from... - " - /> - - - - - - - - - - - - - - - - - - - - {formValues.files.length !== 0 && - parentType === 'edit' && - !fileEditMode ? ( - - {formValues.files.map(file => ( - - ))} - - - ) : ( - <> - - - )} - - - {/* Right side */} - - - - - - - - This image should be landscape. We advise - 1280x960px - - - - - - - - - {/* Steps Info */} - - {({ fields }) => ( - <> - - {fields.map((name, index: number) => ( - - { - fields.remove(fieldIndex) - }} - /> - - ))} - - - - - - )} - - - - - {/* post guidelines container */} - - - - - - - -
- ) - }} - /> - - ) - } -} diff --git a/src/pages/Howto/Content/Common/HowtoStep.form.tsx b/src/pages/Howto/Content/Common/HowtoStep.form.tsx index af6582e8ef..11918d09cd 100644 --- a/src/pages/Howto/Content/Common/HowtoStep.form.tsx +++ b/src/pages/Howto/Content/Common/HowtoStep.form.tsx @@ -159,14 +159,6 @@ class HowtoStep extends Component { /> - - - ) } diff --git a/src/pages/Howto/Content/CreateHowto/Template.tsx b/src/pages/Howto/Content/CreateHowto/Template.tsx index ccccd1dfa9..b2ac45ec62 100644 --- a/src/pages/Howto/Content/CreateHowto/Template.tsx +++ b/src/pages/Howto/Content/CreateHowto/Template.tsx @@ -7,21 +7,18 @@ const INITIAL_VALUES: Partial = { title: '', text: '', images: [], - caption: '', _animationKey: 'unique1', }, { title: '', text: '', images: [], - caption: '', _animationKey: 'unique2', }, { title: '', text: '', images: [], - caption: '', _animationKey: 'unique3', }, ], diff --git a/src/pages/Howto/Content/EditHowto/Template.tsx b/src/pages/Howto/Content/EditHowto/Template.tsx index db60a259dc..6d49811a30 100644 --- a/src/pages/Howto/Content/EditHowto/Template.tsx +++ b/src/pages/Howto/Content/EditHowto/Template.tsx @@ -7,21 +7,18 @@ const INITIAL_VALUES: Partial = { title: 'EDITABLE', text: '', images: [], - caption: '', _animationKey: 'unique1', }, { title: 'EDITABLE', text: '', images: [], - caption: '', _animationKey: 'unique2', }, { title: 'EDITABLE', text: '', images: [], - caption: '', _animationKey: 'unique3', }, ], diff --git a/src/pages/Howto/Content/Howto/Step/ImageGallery.tsx b/src/pages/Howto/Content/Howto/Step/ImageGallery.tsx index 83b5fc1d21..b203bf7ca7 100644 --- a/src/pages/Howto/Content/Howto/Step/ImageGallery.tsx +++ b/src/pages/Howto/Content/Howto/Step/ImageGallery.tsx @@ -7,7 +7,6 @@ import styled from 'styled-components' interface IProps { images: IUploadedFileMeta[] - caption?: string } interface IState { @@ -77,7 +76,6 @@ export default class ImageGallery extends React.PureComponent { render() { const images = this.state.images const imageNumber = images.length - const { caption } = this.props return this.state.activeImage ? ( @@ -110,7 +108,6 @@ export default class ImageGallery extends React.PureComponent { {this.state.showLightbox && ( { From fe48dd6c0745f404d797a5a31ea611c5617c39c8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 14 Mar 2020 12:57:40 +0000 Subject: [PATCH 02/17] Bump acorn from 5.7.3 to 5.7.4 Bumps [acorn](https://github.com/acornjs/acorn) from 5.7.3 to 5.7.4. - [Release notes](https://github.com/acornjs/acorn/releases) - [Commits](https://github.com/acornjs/acorn/compare/5.7.3...5.7.4) Signed-off-by: dependabot[bot] --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index 95c623eb2f..61c22cf87d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4273,9 +4273,9 @@ acorn-walk@^6.0.1: integrity sha512-7evsyfH1cLOCdAzZAd43Cic04yKydNx0cF+7tiA19p1XnLLPU4dpCQOqpjqwokFe//vS0QqfqqjCS2JkiIs0cA== acorn@^5.0.0, acorn@^5.2.1, acorn@^5.5.3, acorn@^5.6.2: - version "5.7.3" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.3.tgz#67aa231bf8812974b85235a96771eb6bd07ea279" - integrity sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw== + version "5.7.4" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.4.tgz#3e8d8a9947d0599a1796d10225d7432f4a4acf5e" + integrity sha512-1D++VG7BhrtvQpNbBzovKNc1FLGGEE/oGe7b9xJm/RFHMBeUaUGpluV9RLjZa47YFdPcDAenEYuq9pQPcMdLJg== acorn@^6.0.1, acorn@^6.0.7, acorn@^6.2.1: version "6.3.0" From f85708c0a9314b2db2c48815467b8514cd684810 Mon Sep 17 00:00:00 2001 From: Benjamin Gammaire Date: Mon, 23 Mar 2020 18:18:48 +0000 Subject: [PATCH 03/17] filter howto list by _created field instead of _modified --- src/stores/Howto/howto.store.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/stores/Howto/howto.store.tsx b/src/stores/Howto/howto.store.tsx index c40edb521d..73110292bf 100644 --- a/src/stores/Howto/howto.store.tsx +++ b/src/stores/Howto/howto.store.tsx @@ -31,7 +31,7 @@ export class HowtoStore extends ModuleStore { // the given endpoint and emits changes as data is retrieved from cache and live collection super(rootStore, COLLECTION_NAME) this.allDocs$.subscribe((docs: IHowtoDB[]) => { - this.allHowtos = docs.sort((a, b) => (a._modified < b._modified ? 1 : -1)) + this.allHowtos = docs.sort((a, b) => (a._created < b._created ? 1 : -1)) }) this.selectedTags = {} } From f828108611f72cebb2554c983768c4f22cbe604b Mon Sep 17 00:00:00 2001 From: Alejandro Romero Herrera Date: Tue, 24 Mar 2020 20:57:47 +0200 Subject: [PATCH 04/17] Disable embed page in message for discord webhooks fixes #902 --- functions/src/Integrations/firebase-discord.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/functions/src/Integrations/firebase-discord.ts b/functions/src/Integrations/firebase-discord.ts index d3f06a8ef1..c80d1c0dcd 100644 --- a/functions/src/Integrations/firebase-discord.ts +++ b/functions/src/Integrations/firebase-discord.ts @@ -17,7 +17,7 @@ export const notifyPinAccepted = functions.firestore const { _id, type } = info await axios .post(DISCORD_WEBHOOK_URL, { - content: `๐Ÿ“ *New ${type}* pin from ${_id}. \n Location here ${SITE_URL}/map/#${_id}`, + content: `๐Ÿ“ *New ${type}* pin from ${_id}. \n Location here <${SITE_URL}/map/#${_id}>`, }) .then(handleResponse, handleErr) .catch(handleErr) @@ -34,7 +34,7 @@ export const notifyHowToAccepted = functions.firestore await axios .post(DISCORD_WEBHOOK_URL, { content: `๐Ÿ““ Yeah! New How To **${title}** by *${_createdBy}* - check it out: ${SITE_URL}/how-to/${slug}`, + check it out: <${SITE_URL}/how-to/${slug}>`, }) .then(handleResponse, handleErr) .catch(handleErr) @@ -53,7 +53,7 @@ export const notifyEventAccepted = functions.firestore await axios .post(DISCORD_WEBHOOK_URL, { content: `๐Ÿ“… Jeej new event in **${location}** by *${user}* posted here: - ${url}`, + <${url}>`, }) .then(handleResponse, handleErr) .catch(handleErr) From f1461bb46d007631415aa674d4800611344f73c5 Mon Sep 17 00:00:00 2001 From: Alejandro Romero Herrera Date: Tue, 24 Mar 2020 21:58:08 +0200 Subject: [PATCH 05/17] Avoid redundant notifications in slack when new pin needs moderation --- functions/src/Integrations/firebase-slack.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/functions/src/Integrations/firebase-slack.ts b/functions/src/Integrations/firebase-slack.ts index c9fb4276c9..9c3ee7012a 100644 --- a/functions/src/Integrations/firebase-slack.ts +++ b/functions/src/Integrations/firebase-slack.ts @@ -11,7 +11,9 @@ export const notifyNewPin = functions.firestore .document('v3_mappins/{pinId}') .onWrite((change, context) => { const info = change.after.exists ? change.after.data() : null - if (info === null || info.moderation !== 'awaiting-moderation') { + const prevInfo = change.before.exists ? change.before.data() : null + const prevModeration = (prevInfo !== null) ? prevInfo.moderation : null; + if (info === null || info.moderation !== 'awaiting-moderation' || prevModeration === 'awaiting-moderation') { return } From 6d212b295177b0fec72112334c9e68600e22f48c Mon Sep 17 00:00:00 2001 From: Dave Hakkens Date: Fri, 27 Mar 2020 10:54:02 +0800 Subject: [PATCH 06/17] Improved how-to guidelines Added guidelines URL --- .../Content/Common/PostingGuidelines.tsx | 31 ++++++++++++++++--- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/src/pages/Howto/Content/Common/PostingGuidelines.tsx b/src/pages/Howto/Content/Common/PostingGuidelines.tsx index 87096687d8..6cdc2d0203 100644 --- a/src/pages/Howto/Content/Common/PostingGuidelines.tsx +++ b/src/pages/Howto/Content/Common/PostingGuidelines.tsx @@ -2,6 +2,8 @@ import * as React from 'react' import Flex from 'src/components/Flex' import Heading from 'src/components/Heading' import Text from 'src/components/Text' +import { Link } from 'rebass' +import theme from 'src/themes/styled.theme' export const PostingGuidelines = () => ( @@ -9,19 +11,38 @@ export const PostingGuidelines = () => ( How-to Guidelines - 1. Titles are powerful. Choose wisely. + How does it work? - 2. Use tags, that's how we stay organised. + 1. Choose what you want to share ๐Ÿ™Œ - 3. Upload minimum 3 steps. + 2. Read{' '} + + our guidelines! + - 4. Try to keep it short but informative. + 3. Prepare your text & images. - 5. For each steps try to use an image. + 4. Create your How-to. + + + 5. Click on โ€œPublishโ€. + + + 6. We will either send you feedback, or + + + 7. Approve if everything is okay :) + + + 8. Be proud :) ) From e2a9fb8e4c61c528f4b948a2538ec160e24883ec Mon Sep 17 00:00:00 2001 From: Benjamin Gammaire Date: Fri, 27 Mar 2020 07:50:35 +0000 Subject: [PATCH 07/17] use relative path for link --- src/pages/Howto/Content/Common/PostingGuidelines.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/Howto/Content/Common/PostingGuidelines.tsx b/src/pages/Howto/Content/Common/PostingGuidelines.tsx index 6cdc2d0203..ea6ce24613 100644 --- a/src/pages/Howto/Content/Common/PostingGuidelines.tsx +++ b/src/pages/Howto/Content/Common/PostingGuidelines.tsx @@ -21,7 +21,7 @@ export const PostingGuidelines = () => ( our guidelines! From 3e0d06f613f1213ee3d6fa3fbf5e17c38fdadb1f Mon Sep 17 00:00:00 2001 From: Benjamin Gammaire Date: Fri, 27 Mar 2020 08:06:11 +0000 Subject: [PATCH 08/17] use emojie s in how-to guidelines --- .../Howto/Content/Common/PostingGuidelines.tsx | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/src/pages/Howto/Content/Common/PostingGuidelines.tsx b/src/pages/Howto/Content/Common/PostingGuidelines.tsx index ea6ce24613..8072edab14 100644 --- a/src/pages/Howto/Content/Common/PostingGuidelines.tsx +++ b/src/pages/Howto/Content/Common/PostingGuidelines.tsx @@ -8,11 +8,8 @@ import theme from 'src/themes/styled.theme' export const PostingGuidelines = () => ( - How-to Guidelines - - How does it work? - + 1. Choose what you want to share ๐Ÿ™Œ @@ -23,26 +20,26 @@ export const PostingGuidelines = () => ( target="_blank" href="/academy/create/howto" > - our guidelines! + our guidelines ๐Ÿค“ - 3. Prepare your text & images. + 3. Prepare your text & images ๐Ÿ—„๏ธ - 4. Create your How-to. + 4. Create your How-to โœ๏ธ - 5. Click on โ€œPublishโ€. + 5. Click on โ€œPublishโ€ ๐Ÿ–ฑ๏ธ 6. We will either send you feedback, or - 7. Approve if everything is okay :) + 7. Approve if everything is okay โœ… - 8. Be proud :) + 8. Be proud ๐Ÿ™‚ ) From e50e5e6cde5f34f808b51750091135c33235e377 Mon Sep 17 00:00:00 2001 From: Alejandro Romero Herrera Date: Fri, 27 Mar 2020 14:23:30 +0300 Subject: [PATCH 09/17] Fix #903 Show new pin accepted only the first time in Discord --- functions/src/Integrations/firebase-discord.ts | 4 +++- src/models/common.models.tsx | 1 + src/stores/Maps/maps.store.ts | 4 +++- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/functions/src/Integrations/firebase-discord.ts b/functions/src/Integrations/firebase-discord.ts index c80d1c0dcd..eee86fbf34 100644 --- a/functions/src/Integrations/firebase-discord.ts +++ b/functions/src/Integrations/firebase-discord.ts @@ -11,7 +11,9 @@ export const notifyPinAccepted = functions.firestore .document('v3_mappins/{pinId}') .onWrite(async (change, context) => { const info = change.after.exists ? change.after.data() : null - if (info === null || info.moderation !== 'accepted') { + const prevInfo = change.before.exists ? change.before.data() : null + const beenAccepted = (prevInfo !== null) ? prevInfo.hasBeenAccepted : null; + if (info === null || info.moderation !== 'accepted' || beenAccepted) { return } const { _id, type } = info diff --git a/src/models/common.models.tsx b/src/models/common.models.tsx index 87431a4444..d0b6b95886 100644 --- a/src/models/common.models.tsx +++ b/src/models/common.models.tsx @@ -27,6 +27,7 @@ export type IModerationStatus = export interface IModerable { moderation: IModerationStatus + hasBeenAccepted?: boolean _createdBy?: string _id?: string } diff --git a/src/stores/Maps/maps.store.ts b/src/stores/Maps/maps.store.ts index ad7788f7fb..dde5e5aafe 100644 --- a/src/stores/Maps/maps.store.ts +++ b/src/stores/Maps/maps.store.ts @@ -163,6 +163,9 @@ export class MapsStore extends ModuleStore { if (!hasAdminRights(this.activeUser)) { return false } + if (pin.moderation === 'accepted') { + pin.hasBeenAccepted = true + } this.setPin(pin) } public needsModeration(pin: IMapPin) { @@ -177,7 +180,6 @@ export class MapsStore extends ModuleStore { _id: user.userName, location: user.location!.latlng, type: user.profileType ? user.profileType : 'member', - // TODO: keep moderation status ... ' Should we being duplicating info ยฟ?(user/pin)' moderation: 'awaiting-moderation', } if (user.workspaceType) { From a2c4adbaa71237ade2210d203a3bcdba894c00e4 Mon Sep 17 00:00:00 2001 From: Benjamin Gammaire Date: Fri, 27 Mar 2020 11:50:56 +0000 Subject: [PATCH 10/17] add method getPinsNumberByFilterType & separate filterMapPinsByType as private method --- src/stores/Maps/maps.store.ts | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/stores/Maps/maps.store.ts b/src/stores/Maps/maps.store.ts index ad7788f7fb..60baeda98c 100644 --- a/src/stores/Maps/maps.store.ts +++ b/src/stores/Maps/maps.store.ts @@ -105,13 +105,18 @@ export class MapsStore extends ModuleStore { return } + const mapPins = this.filterMapPinsByType(filters) + this.filteredPins = mapPins + } + + private filterMapPinsByType(filters: Array) { // filter pins to include matched pin type or subtype - const mapPins = this.mapPins.filter(pin => { + const filteredMapPins = this.mapPins.filter(pin => { return pin.subType ? filters.includes(pin.subType) : filters.includes(pin.type) }) - this.filteredPins = mapPins + return filteredMapPins } /** @@ -224,6 +229,11 @@ export class MapsStore extends ModuleStore { profileUrl: `${location.origin}/u/${u.userName}`, } } + @action + public getPinsNumberByFilterType(filter: Array) { + const pinsNumber = this.filterMapPinsByType(filter) + return pinsNumber.length + } } /********************************************************************************** From a0b811e18bab79106c36f1306787f143c7e6d206 Mon Sep 17 00:00:00 2001 From: Benjamin Gammaire Date: Fri, 27 Mar 2020 11:52:16 +0000 Subject: [PATCH 11/17] add map store to desktop & mobile filter view and display number of pins per filter type --- .../Content/Controls/GroupingFilterDesktop.tsx | 16 ++++++++++++++-- .../Content/Controls/GroupingFilterMobile.tsx | 15 ++++++++++++++- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/src/pages/Maps/Content/Controls/GroupingFilterDesktop.tsx b/src/pages/Maps/Content/Controls/GroupingFilterDesktop.tsx index b0380c43a0..bda0802a95 100644 --- a/src/pages/Maps/Content/Controls/GroupingFilterDesktop.tsx +++ b/src/pages/Maps/Content/Controls/GroupingFilterDesktop.tsx @@ -4,6 +4,8 @@ import MultiSelect from '@khanacademy/react-multi-select' import './GroupingFilter.css' import ElWithBeforeIcon from 'src/components/ElWithBeforeIcon' import { IMapGrouping } from 'src/models/maps.models' +import { inject } from 'mobx-react' +import { MapsStore } from 'src/stores/Maps/maps.store' import { Box } from 'rebass' interface IProps { @@ -16,6 +18,9 @@ interface IState { initialItems: Array selectedItems: Array } +interface IInjectedProps extends IProps { + mapsStore: MapsStore +} const ItemRenderer = ({ checked, option, onClick }) => { return ( @@ -42,13 +47,13 @@ const ItemRenderer = ({ checked, option, onClick }) => { paddingBottom: '2px', }} > - {option.label} + {option.label} ({option.number}) ) } - +@inject('mapsStore') class GroupingFilterDesktop extends React.Component { constructor(props: IProps) { super(props) @@ -57,6 +62,9 @@ class GroupingFilterDesktop extends React.Component { selectedItems: [], } } + get injected() { + return this.props as IInjectedProps + } handleChange(selectedItems: Array) { this.setState({ selectedItems }) @@ -74,6 +82,10 @@ class GroupingFilterDesktop extends React.Component { label: item.displayName, value: item.subType ? item.subType : item.type, icon: item.icon, + // add split(' ') method to convert to array + number: this.injected.mapsStore.getPinsNumberByFilterType( + item.subType ? item.subType.split(' ') : item.type.split(' '), + ), })) } diff --git a/src/pages/Maps/Content/Controls/GroupingFilterMobile.tsx b/src/pages/Maps/Content/Controls/GroupingFilterMobile.tsx index 51c29e1344..d450615fe7 100644 --- a/src/pages/Maps/Content/Controls/GroupingFilterMobile.tsx +++ b/src/pages/Maps/Content/Controls/GroupingFilterMobile.tsx @@ -3,6 +3,8 @@ import Text from 'src/components/Text' import { IMapGrouping } from 'src/models/maps.models' import checkmarkIcon from 'src/assets/icons/icon-checkmark.svg' import { Flex, Image } from 'rebass' +import { inject } from 'mobx-react' +import { MapsStore } from 'src/stores/Maps/maps.store' interface IProps { items: Array @@ -14,7 +16,11 @@ interface IProps { interface IState { initialItems: Array } +interface IInjectedProps extends IProps { + mapsStore: MapsStore +} +@inject('mapsStore') class GroupingFilterMobile extends React.Component { constructor(props: IProps) { super(props) @@ -23,6 +29,10 @@ class GroupingFilterMobile extends React.Component { } } + get injected() { + return this.props as IInjectedProps + } + addOrRemove = (array, item) => { // from https://stackoverflow.com/a/52531625 const exists = array.includes(item) @@ -52,6 +62,9 @@ class GroupingFilterMobile extends React.Component { label: item.displayName, value: item.subType ? item.subType : item.type, icon: item.icon, + number: this.injected.mapsStore.getPinsNumberByFilterType( + item.subType ? item.subType.split(' ') : item.type.split(' '), + ), })) } @@ -80,7 +93,7 @@ class GroupingFilterMobile extends React.Component { - {filter.label} + {filter.label} ({filter.number}) {selectedItems.includes(filter.value) && ( From 2047e51b111edd8d617c8a8f8fca5c3f4730ac2a Mon Sep 17 00:00:00 2001 From: Dave Hakkens Date: Sat, 28 Mar 2020 00:03:23 +0300 Subject: [PATCH 12/17] Change feedback to Discord Stop using trello. Hard to keep track of feedback. Go straight to Discord #feedback channel --- src/pages/index.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/index.tsx b/src/pages/index.tsx index fa24442370..923e86cd6b 100644 --- a/src/pages/index.tsx +++ b/src/pages/index.tsx @@ -75,7 +75,7 @@ export class Routes extends React.Component { @@ -83,7 +83,7 @@ export class Routes extends React.Component { sx={{ position: 'fixed', bottom: '30px', right: '30px' }} variant="primary" > - Have feedback ? + #Feedback? Join our chat ๐Ÿ’ฌ From caad9bfb8715fa5a05ecb193bb6c076f92f939c1 Mon Sep 17 00:00:00 2001 From: Dave Hakkens Date: Sat, 28 Mar 2020 00:07:56 +0300 Subject: [PATCH 13/17] Change Feedback to Discord Hard to keep track of Trello, go straight to our Discord --- src/pages/index.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/index.tsx b/src/pages/index.tsx index fa24442370..923e86cd6b 100644 --- a/src/pages/index.tsx +++ b/src/pages/index.tsx @@ -75,7 +75,7 @@ export class Routes extends React.Component { @@ -83,7 +83,7 @@ export class Routes extends React.Component { sx={{ position: 'fixed', bottom: '30px', right: '30px' }} variant="primary" > - Have feedback ? + #Feedback? Join our chat ๐Ÿ’ฌ From f05a38b6b5c301768bbd0434b191f6bfbb4a71e9 Mon Sep 17 00:00:00 2001 From: Benjamin Gammaire Date: Sat, 28 Mar 2020 11:55:35 +0000 Subject: [PATCH 14/17] remove hasBeenAccepted boolean from IModerable interface & update condition in discord webhook --- functions/src/Integrations/firebase-discord.ts | 3 ++- src/models/common.models.tsx | 1 - src/stores/Maps/maps.store.ts | 3 --- 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/functions/src/Integrations/firebase-discord.ts b/functions/src/Integrations/firebase-discord.ts index eee86fbf34..54ccb370d5 100644 --- a/functions/src/Integrations/firebase-discord.ts +++ b/functions/src/Integrations/firebase-discord.ts @@ -12,7 +12,8 @@ export const notifyPinAccepted = functions.firestore .onWrite(async (change, context) => { const info = change.after.exists ? change.after.data() : null const prevInfo = change.before.exists ? change.before.data() : null - const beenAccepted = (prevInfo !== null) ? prevInfo.hasBeenAccepted : null; + const beenAccepted = + prevInfo !== null ? prevInfo.moderation === 'accepted' : null if (info === null || info.moderation !== 'accepted' || beenAccepted) { return } diff --git a/src/models/common.models.tsx b/src/models/common.models.tsx index d0b6b95886..87431a4444 100644 --- a/src/models/common.models.tsx +++ b/src/models/common.models.tsx @@ -27,7 +27,6 @@ export type IModerationStatus = export interface IModerable { moderation: IModerationStatus - hasBeenAccepted?: boolean _createdBy?: string _id?: string } diff --git a/src/stores/Maps/maps.store.ts b/src/stores/Maps/maps.store.ts index dde5e5aafe..84c7fdc1b0 100644 --- a/src/stores/Maps/maps.store.ts +++ b/src/stores/Maps/maps.store.ts @@ -163,9 +163,6 @@ export class MapsStore extends ModuleStore { if (!hasAdminRights(this.activeUser)) { return false } - if (pin.moderation === 'accepted') { - pin.hasBeenAccepted = true - } this.setPin(pin) } public needsModeration(pin: IMapPin) { From d16cf930aed5993c48dc94d8fdc266bccdadc02a Mon Sep 17 00:00:00 2001 From: Benjamin Gammaire Date: Sat, 28 Mar 2020 12:03:57 +0000 Subject: [PATCH 15/17] clear IndexDB database before starting automated test --- cypress/support/hooks.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cypress/support/hooks.ts b/cypress/support/hooks.ts index 92fa2148bb..a36afdcc6f 100644 --- a/cypress/support/hooks.ts +++ b/cypress/support/hooks.ts @@ -9,6 +9,8 @@ import { Firestore } from './db/firebase' */ before(() => { + indexedDB.deleteDatabase('OneArmyCache') + cy.clearLocalStorage() cy.wrap('Initialising Database').then({ timeout: 60000 }, doc => { // large initial timeout in case server slow to respond return new Cypress.Promise(async resolve => { From 67abef75a6163942b68ee75dea217e0167de9e1e Mon Sep 17 00:00:00 2001 From: Benjamin Gammaire Date: Sat, 28 Mar 2020 16:07:58 +0000 Subject: [PATCH 16/17] delete firebaseLocalStorageDb from test browser --- cypress/support/hooks.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cypress/support/hooks.ts b/cypress/support/hooks.ts index a36afdcc6f..0c3f0d0316 100644 --- a/cypress/support/hooks.ts +++ b/cypress/support/hooks.ts @@ -9,8 +9,9 @@ import { Firestore } from './db/firebase' */ before(() => { + indexedDB.deleteDatabase('firebaseLocalStorageDb') indexedDB.deleteDatabase('OneArmyCache') - cy.clearLocalStorage() + cy.clearLocalStorage('CLear local storage and indexDB') cy.wrap('Initialising Database').then({ timeout: 60000 }, doc => { // large initial timeout in case server slow to respond return new Cypress.Promise(async resolve => { From 75478457220a15d2ac4a8e273831aeab01ff828d Mon Sep 17 00:00:00 2001 From: Benjamin Gammaire Date: Sat, 28 Mar 2020 16:16:22 +0000 Subject: [PATCH 17/17] restore only OneArmyCache indexDB reset for test --- cypress/support/hooks.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/cypress/support/hooks.ts b/cypress/support/hooks.ts index 0c3f0d0316..8a6e790573 100644 --- a/cypress/support/hooks.ts +++ b/cypress/support/hooks.ts @@ -9,7 +9,6 @@ import { Firestore } from './db/firebase' */ before(() => { - indexedDB.deleteDatabase('firebaseLocalStorageDb') indexedDB.deleteDatabase('OneArmyCache') cy.clearLocalStorage('CLear local storage and indexDB') cy.wrap('Initialising Database').then({ timeout: 60000 }, doc => {