Skip to content

Commit

Permalink
feat(ui): add swipe gesture for article cards
Browse files Browse the repository at this point in the history
  • Loading branch information
ncarlier committed Apr 21, 2019
1 parent 44200f9 commit 861afca
Show file tree
Hide file tree
Showing 9 changed files with 123 additions and 20 deletions.
36 changes: 29 additions & 7 deletions ui/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
"react-redux": "^6.0.1",
"react-router-dom": "^4.3.1",
"react-scripts": "^2.1.8",
"react-swipe-to-delete-component": "^0.4.0",
"react-use-form-state": "^0.7.0",
"redux": "^4.0.1",
"redux-devtools-extension": "^2.13.8",
Expand Down
Binary file added ui/public/logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
15 changes: 10 additions & 5 deletions ui/src/articles/components/ArticleList.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import React, { createRef } from 'react'
import ReactCSSTransitionGroup from 'react-addons-css-transition-group'

import { Article } from '../models'
import ArticleCard from './ArticleCard'

import styles from './ArticleList.module.css'
import Empty from '../../common/Empty'
import useInfiniteScroll from '../../hooks/useInfiniteScroll'
import Panel from '../../common/Panel'
import Center from '../../common/Center'
import Button from '../../common/Button';
import ButtonIcon from '../../common/ButtonIcon';
import ButtonIcon from '../../common/ButtonIcon'
import ArticleCard from './ArticleCard'
import { useMedia } from '../../hooks'
import SwipeableArticleCard from './SwipeableArticleCard'

type Props = {
articles: Article[]
Expand All @@ -34,6 +34,7 @@ export default (props: Props) => {
const ref = createRef<HTMLUListElement>()

const isFetching = useInfiniteScroll(ref, fetchMoreArticles)
const isMobileDisplay = useMedia('(max-width: 767px)')

const articles = props.articles.filter(filter)

Expand All @@ -53,7 +54,11 @@ export default (props: Props) => {
<ul className={styles.list} ref={ref}>
{articles.map(article => (
<li key={`article-${article.id}`}>
<ArticleCard article={article} readMoreBasePath={basePath} />
{
isMobileDisplay ?
<SwipeableArticleCard article={article} readMoreBasePath={basePath} /> :
<ArticleCard article={article} readMoreBasePath={basePath} />
}
</li>
))}
{isFetching && <li><Panel><Center>Fetching more articles...</Center></Panel></li>}
Expand Down
9 changes: 2 additions & 7 deletions ui/src/articles/components/MarkAsButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,14 @@
import React, { useState, useCallback } from 'react'
import { useMutation } from 'react-apollo-hooks'

import { Article } from '../models'
import { Article, UpdateArticleStatusRequest } from '../models'
import ButtonIcon from '../../common/ButtonIcon'

import { UpdateArticleStatus } from '../queries'
import { getGQLError } from '../../common/helpers'
import { connectMessageDispatch, IMessageDispatchProps } from '../../containers/MessageContainer';
import useKeyboard from '../../hooks/useKeyboard';

type UpdateArticleStatusFields = {
id: number
status: string
}

type Props = {
article: Article
floating?: boolean
Expand All @@ -30,7 +25,7 @@ export const MarkAsButton = (props: AllProps) => {
} = props

const [loading, setLoading] = useState(false)
const updateArticleStatusMutation = useMutation<UpdateArticleStatusFields>(UpdateArticleStatus)
const updateArticleStatusMutation = useMutation<UpdateArticleStatusRequest>(UpdateArticleStatus)

const updateArticleStatus = async (status: string) => {
try{
Expand Down
16 changes: 16 additions & 0 deletions ui/src/articles/components/SwipeableArticleCard.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
.background {
display: flex;
height: 100%;
background: green;
}

.background span {
flex: 1 1 auto;
}

.background i {
font-size: 3em;
align-self: center;
color: white;
padding: 0.5em;
}
57 changes: 57 additions & 0 deletions ui/src/articles/components/SwipeableArticleCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import React, { useCallback } from 'react'
import SwipeToDelete from 'react-swipe-to-delete-component'
import 'react-swipe-to-delete-component/dist/swipe-to-delete.css'

import styles from './SwipeableArticleCard.module.css'
import {Article, UpdateArticleStatusRequest} from '../models'
import ArticleCard from './ArticleCard'
import Icon from '../../common/Icon'
import { useMutation } from 'react-apollo-hooks';
import { UpdateArticleStatus } from '../queries';
import { getGQLError } from '../../common/helpers';
import { IMessageDispatchProps, connectMessageDispatch } from '../../containers/MessageContainer';

type Props = {
article: Article
readMoreBasePath: string
}

type AllProps = Props & IMessageDispatchProps

const Background = ({icon}: {icon: string}) => (
<div className={styles.background}>
<Icon name={icon} />
<span />
<Icon name={icon} />
</div>
)

export const SwipeableArticleCard = (props: AllProps) => {
const {article, readMoreBasePath, showMessage} = props
const updateArticleStatusMutation = useMutation<UpdateArticleStatusRequest>(UpdateArticleStatus)

const updateArticleStatus = async (status: string) => {
try{
const res = await updateArticleStatusMutation({
variables: {id: article.id, status},
})
} catch (err) {
showMessage(getGQLError(err), true)
}
}

const handleOnDelete = useCallback(() => {
const status = article.status === 'read' ? 'unread' : 'read'
updateArticleStatus(status)
}, [article])

const bgIcon = article.status === 'read' ? 'undo' : 'done'

return (
<SwipeToDelete background={<Background icon={bgIcon} />} onDelete={handleOnDelete}>
<ArticleCard article={article} readMoreBasePath={readMoreBasePath} />
</SwipeToDelete>
)
}

export default connectMessageDispatch(SwipeableArticleCard)
5 changes: 5 additions & 0 deletions ui/src/articles/models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@ export interface GetArticleResponse {
article: Article
}

export type UpdateArticleStatusRequest = {
id: number
status: string
}

export interface UpdateArticleStatusResponse {
updateArticleStatus: Article
}
Expand Down
4 changes: 3 additions & 1 deletion ui/src/types.d.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
interface Window {
initialReduxState: any
}
}

declare module 'react-swipe-to-delete-component'

0 comments on commit 861afca

Please sign in to comment.