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鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: adds redirect for 404 how tos #1225

Merged
merged 4 commits into from
Oct 7, 2021
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
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
16 changes: 16 additions & 0 deletions cypress/integration/howto/read.spec.ts
@@ -1,3 +1,5 @@
import crypto from 'crypto'

describe('[How To]', () => {
const SKIP_TIMEOUT = { timeout: 300 }
const totalHowTo = 7
Expand Down Expand Up @@ -195,4 +197,18 @@ describe('[How To]', () => {
.should('include', `${specificHowtoUrl}/edit`)
})
})

describe('[Fail to find a How-to]', () => {
const uuid = crypto.randomBytes(16).toString('hex')
const howToNotFoundUrl = `/how-to/this-how-to-does-not-exist-${uuid}`
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

馃 Perhaps unneccessary as I think the datastore is completely reset between test runs so there are unlikely to be any collisions due to leaky state between test runs.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should do (cypress by default clears localstorage and we have manual methods to clear indexeddb), we also use a custom prefix in case of tests running in parallel. That being said, no real harm to include


it('[Redirects to search]', () => {
cy.visit(howToNotFoundUrl)
cy.location('pathname').should('eq', '/how-to')
cy.location('search').should(
'eq',
`?search=this+how+to+does+not+exist+${uuid}`,
)
})
})
})
19 changes: 15 additions & 4 deletions src/pages/Howto/Content/Howto/Howto.tsx
@@ -1,5 +1,5 @@
import * as React from 'react'
import { RouteComponentProps } from 'react-router'
import { RouteComponentProps, Redirect } from 'react-router'
// TODO add loader (and remove this material-ui dep)
import { inject, observer } from 'mobx-react'
import { HowtoStore } from 'src/stores/Howto/howto.store'
Expand All @@ -19,8 +19,6 @@ import WhiteBubble3 from 'src/assets/images/white-bubble_3.svg'
import { Link } from 'src/components/Links'
import { zIndex } from 'src/themes/styled.theme'
import { Loader } from 'src/components/Loader'
import { Route } from 'react-router-dom'
import { NotFoundPage } from '../../../NotFound/NotFound'
import { UserStore } from 'src/stores/User/user.store'
import { HowToComments } from './HowToComments/HowToComments'
// The parent container injects router props along with a custom slug parameter (RouteComponentProps<IRouterCustomParams>).
Expand Down Expand Up @@ -122,6 +120,7 @@ export class Howto extends React.Component<
const { isLoading } = this.state
const loggedInUser = this.injected.userStore.activeUser
const { activeHowto } = this.store

if (activeHowto) {
return (
<>
Expand Down Expand Up @@ -158,7 +157,19 @@ export class Howto extends React.Component<
</>
)
} else {
return isLoading ? <Loader /> : <Route component={NotFoundPage} />
return isLoading ? (
<Loader />
) : (
<Redirect
to={{
pathname: '/how-to',
search:
'?search=' +
(this.props?.match?.params?.slug).replace(/\-/gi, ' ') +
'&source=how-to-not-found',
}}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested this out and really like the functionality, nice idea to also replace the dashes and make it look more human-readable

/>
)
}
}
}
29 changes: 25 additions & 4 deletions src/pages/Howto/Content/HowtoList/HowtoList.tsx
Expand Up @@ -50,6 +50,7 @@ export class HowtoList extends React.Component<any, IState> {
this.state = {
isLoading: true,
}

if (props.location.search) {
const searchParams = new URLSearchParams(props.location.search)

Expand All @@ -67,21 +68,41 @@ export class HowtoList extends React.Component<any, IState> {
if (searchQuery) {
this.props.howtoStore.updateSearchValue(searchQuery)
}

this.props.howtoStore.updateReferrerSource(
searchParams.get('source')?.toString(),
)
}
}
get injected() {
return this.props as InjectedProps
}

public render() {
const { filteredHowtos, selectedTags, searchValue } = this.props.howtoStore
const {
filteredHowtos,
selectedTags,
searchValue,
referrerSource,
} = this.props.howtoStore

return (
<>
<Flex py={26}>
<Heading medium bold txtcenter width={1} my={20}>
Learn & share how to recycle, build and work with plastic
</Heading>
{referrerSource ? (
<Box width={1}>
<Heading medium bold txtcenter mt={20}>
The page you were looking for was moved or doesn't exist.
</Heading>
<Heading small txtcenter mt={3} mb={10}>
Search all of our how-to's below
</Heading>
</Box>
) : (
<Heading medium bold txtcenter width={1} my={20}>
Learn & share how to recycle, build and work with plastic
</Heading>
)}
</Flex>
<Flex
flexWrap={'nowrap'}
Expand Down
8 changes: 8 additions & 0 deletions src/stores/Howto/howto.store.tsx
Expand Up @@ -42,8 +42,11 @@ export class HowtoStore extends ModuleStore {
@observable
public searchValue: string
@observable
public referrerSource: string
@observable
public uploadStatus: IHowToUploadStatus = getInitialUploadStatus()
@observable howtoStats: IHowtoStats | undefined

constructor(rootStore: RootStore) {
// call constructor on common ModuleStore (with db endpoint), which automatically fetches all docs at
// the given endpoint and emits changes as data is retrieved from cache and live collection
Expand All @@ -52,6 +55,7 @@ export class HowtoStore extends ModuleStore {
this.allDocs$.subscribe((docs: IHowtoDB[]) => this.setAllHowtos(docs))
this.selectedTags = {}
this.searchValue = ''
this.referrerSource = ''
}

@action
Expand Down Expand Up @@ -121,6 +125,10 @@ export class HowtoStore extends ModuleStore {
this.searchValue = query
}

public updateReferrerSource(source: string) {
this.referrerSource = source
}

public updateSelectedTags(tagKey: ISelectedTags) {
this.selectedTags = tagKey
}
Expand Down