Improve messages
This commit is contained in:
parent
e7b2bc13d2
commit
34729c763f
|
@ -2,7 +2,8 @@ import React, { Component } from 'react'
|
|||
import gql from 'graphql-tag'
|
||||
import { Mutation, Query } from 'react-apollo'
|
||||
import { Redirect } from 'react-router-dom'
|
||||
import { Button, Form, Message, Container, Header } from 'semantic-ui-react'
|
||||
import { Button, Form, Message, Header } from 'semantic-ui-react'
|
||||
import { Container } from './LoginPage'
|
||||
|
||||
import { checkInitialSetupQuery, login } from './loginUtilFunctions'
|
||||
|
||||
|
|
|
@ -2,7 +2,14 @@ import React, { Component } from 'react'
|
|||
import gql from 'graphql-tag'
|
||||
import { Mutation, Query } from 'react-apollo'
|
||||
import { Redirect } from 'react-router-dom'
|
||||
import { Button, Form, Message, Container, Header } from 'semantic-ui-react'
|
||||
import styled from 'styled-components'
|
||||
import {
|
||||
Button,
|
||||
Form,
|
||||
Message,
|
||||
Container as SemanticContainer,
|
||||
Header,
|
||||
} from 'semantic-ui-react'
|
||||
import { checkInitialSetupQuery, login } from './loginUtilFunctions'
|
||||
|
||||
const authorizeMutation = gql`
|
||||
|
@ -15,6 +22,10 @@ const authorizeMutation = gql`
|
|||
}
|
||||
`
|
||||
|
||||
export const Container = styled(SemanticContainer)`
|
||||
margin-top: 80px;
|
||||
`
|
||||
|
||||
class LoginPage extends Component {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
|
@ -49,7 +60,7 @@ class LoginPage extends Component {
|
|||
<div>
|
||||
<Container>
|
||||
<Header as="h1" textAlign="center">
|
||||
Welcome
|
||||
Welcome to Photoview
|
||||
</Header>
|
||||
<Query query={checkInitialSetupQuery}>
|
||||
{({ loading, error, data }) => {
|
||||
|
|
|
@ -6,6 +6,7 @@ import { onError } from 'apollo-link-error'
|
|||
import { setContext } from 'apollo-link-context'
|
||||
import { ApolloLink, split } from 'apollo-link'
|
||||
import { getMainDefinition } from 'apollo-utilities'
|
||||
import { MessageState } from './components/messages/Messages'
|
||||
|
||||
const httpLink = new HttpLink({
|
||||
uri: process.env.GRAPHQL_ENDPOINT,
|
||||
|
@ -44,7 +45,9 @@ const link = split(
|
|||
)
|
||||
|
||||
const linkError = onError(({ graphQLErrors, networkError }) => {
|
||||
if (graphQLErrors)
|
||||
let errorMessages = []
|
||||
|
||||
if (graphQLErrors) {
|
||||
graphQLErrors.map(({ message, locations, path }) =>
|
||||
console.log(
|
||||
`[GraphQL error]: Message: ${message}, Location: ${JSON.stringify(
|
||||
|
@ -52,9 +55,49 @@ const linkError = onError(({ graphQLErrors, networkError }) => {
|
|||
)} Path: ${path}`
|
||||
)
|
||||
)
|
||||
|
||||
if (graphQLErrors.length == 1) {
|
||||
errorMessages.push({
|
||||
header: 'Something went wrong',
|
||||
content: graphQLErrors[0].message,
|
||||
})
|
||||
} else if (graphQLErrors.length > 1) {
|
||||
errorMessages.push({
|
||||
header: 'Multiple things went wrong',
|
||||
content: `Received ${graphQLErrors.length} errors from the server. See the console for more information`,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if (networkError) {
|
||||
console.log(`[Network error]: ${JSON.stringify(networkError)}`)
|
||||
localStorage.removeItem('token')
|
||||
|
||||
const errors = networkError.result.errors
|
||||
|
||||
if (errors.length == 1) {
|
||||
errorMessages.push({
|
||||
header: 'Server error',
|
||||
content: `You are being logged out in an attempt to recover.\n${errors[0].message}`,
|
||||
})
|
||||
} else if (errors.length > 1) {
|
||||
errorMessages.push({
|
||||
header: 'Multiple server errors',
|
||||
content: `Received ${graphQLErrors.length} errors from the server. You are being logged out in an attempt to recover.`,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if (errorMessages.length > 0) {
|
||||
const newMessages = errorMessages.map(msg => ({
|
||||
key: Math.random().toString(26),
|
||||
type: 'message',
|
||||
props: {
|
||||
negative: true,
|
||||
...msg,
|
||||
},
|
||||
}))
|
||||
MessageState.set(messages => [...messages, ...newMessages])
|
||||
}
|
||||
})
|
||||
|
||||
|
|
|
@ -1,22 +1,10 @@
|
|||
import React, { useState, useEffect } from 'react'
|
||||
import { useSubscription } from 'react-apollo'
|
||||
import { useTransition, animated } from 'react-spring'
|
||||
import PropTypes from 'prop-types'
|
||||
import styled from 'styled-components'
|
||||
import { Message } from 'semantic-ui-react'
|
||||
import gql from 'graphql-tag'
|
||||
import MessageProgress from './MessageProgress'
|
||||
|
||||
const syncSubscription = gql`
|
||||
subscription syncSubscription {
|
||||
scannerStatusUpdate {
|
||||
finished
|
||||
success
|
||||
message
|
||||
progress
|
||||
}
|
||||
}
|
||||
`
|
||||
import MessageProgress from './MessageProgress'
|
||||
import SubscriptionsHook from './SubscriptionsHook'
|
||||
|
||||
const Container = styled.div`
|
||||
position: fixed;
|
||||
|
@ -25,66 +13,27 @@ const Container = styled.div`
|
|||
width: 500px;
|
||||
`
|
||||
|
||||
export let MessageState = {
|
||||
set: null,
|
||||
get: null,
|
||||
add: message => {
|
||||
MessageState.set(messages => [...messages, message])
|
||||
},
|
||||
}
|
||||
|
||||
const Messages = () => {
|
||||
if (!localStorage.getItem('token')) {
|
||||
return null
|
||||
}
|
||||
|
||||
const { data, error } = useSubscription(syncSubscription)
|
||||
console.log('Rendering messages')
|
||||
|
||||
const [messages, setMessages] = useState([])
|
||||
MessageState.set = setMessages
|
||||
MessageState.get = messages
|
||||
|
||||
const [refMap] = useState(() => new WeakMap())
|
||||
|
||||
useEffect(() => {
|
||||
if (error) {
|
||||
setMessages(state => [
|
||||
...state,
|
||||
{
|
||||
key: Math.random().toString(26),
|
||||
type: 'message',
|
||||
props: {
|
||||
header: 'Network error',
|
||||
content: error.message,
|
||||
negative: true,
|
||||
},
|
||||
},
|
||||
])
|
||||
}
|
||||
|
||||
if (!data) return
|
||||
|
||||
const update = data.scannerStatusUpdate
|
||||
const newMessages = [...messages]
|
||||
|
||||
if (update.success) {
|
||||
newMessages[0] = {
|
||||
key: 'primary',
|
||||
type: 'progress',
|
||||
props: {
|
||||
header: update.finished ? 'Synced' : 'Syncing',
|
||||
content: update.message,
|
||||
percent: update.progress,
|
||||
positive: update.finished,
|
||||
},
|
||||
}
|
||||
|
||||
if (!update.finished) newMessages[0].props.onDismiss = null
|
||||
} else {
|
||||
const key = Math.random().toString(26)
|
||||
newMessages.push({
|
||||
key,
|
||||
type: 'message',
|
||||
props: {
|
||||
header: 'Sync error',
|
||||
content: update.message,
|
||||
negative: true,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
setMessages(newMessages)
|
||||
}, [data, error])
|
||||
|
||||
const getMessageElement = (message, ref) => {
|
||||
const dismissMessage = key => {
|
||||
setMessages(messages => messages.filter(msg => msg.key != key))
|
||||
|
@ -119,12 +68,35 @@ const Messages = () => {
|
|||
}
|
||||
}
|
||||
|
||||
let refHooks = new Map()
|
||||
messages.forEach(message => {
|
||||
let resolveFunc = null
|
||||
|
||||
const waitPromise = new Promise((resolve, reject) => {
|
||||
resolveFunc = resolve
|
||||
})
|
||||
|
||||
console.log(resolveFunc, waitPromise)
|
||||
refHooks.set(message.key, {
|
||||
done: resolveFunc,
|
||||
promise: waitPromise,
|
||||
})
|
||||
})
|
||||
|
||||
const transitions = useTransition(messages.slice().reverse(), x => x.key, {
|
||||
from: {
|
||||
opacity: 0,
|
||||
height: '0px',
|
||||
},
|
||||
enter: item => async next => {
|
||||
console.log('HERE', refMap, item)
|
||||
|
||||
const refPromise = refHooks.get(item.key).promise
|
||||
console.log('promise', refPromise)
|
||||
|
||||
await refPromise
|
||||
console.log('AFTER PROMISE', refMap, item)
|
||||
|
||||
await next({
|
||||
opacity: 1,
|
||||
height: `${refMap.get(item).offsetHeight + 10}px`,
|
||||
|
@ -137,7 +109,11 @@ const Messages = () => {
|
|||
<Container>
|
||||
{transitions.map(({ item, props: style, key }) => {
|
||||
const getRef = ref => {
|
||||
console.log('GET REF', refMap, refHooks, item.key)
|
||||
refMap.set(item, ref)
|
||||
if (refHooks.has(item.key)) {
|
||||
refHooks.get(item.key).done()
|
||||
}
|
||||
}
|
||||
const MessageElement = getMessageElement(item, getRef)
|
||||
|
||||
|
@ -149,6 +125,7 @@ const Messages = () => {
|
|||
</animated.div>
|
||||
)
|
||||
})}
|
||||
<SubscriptionsHook messages={messages} setMessages={setMessages} />
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,78 @@
|
|||
import React, { useState, useEffect } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { useSubscription } from 'react-apollo'
|
||||
import gql from 'graphql-tag'
|
||||
|
||||
const syncSubscription = gql`
|
||||
subscription syncSubscription {
|
||||
scannerStatusUpdate {
|
||||
finished
|
||||
success
|
||||
message
|
||||
progress
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
const SubscriptionsHook = ({ messages, setMessages }) => {
|
||||
const { data, error } = useSubscription(syncSubscription)
|
||||
|
||||
useEffect(() => {
|
||||
if (error) {
|
||||
setMessages(state => [
|
||||
...state,
|
||||
{
|
||||
key: Math.random().toString(26),
|
||||
type: 'message',
|
||||
props: {
|
||||
header: 'Network error',
|
||||
content: error.message,
|
||||
negative: true,
|
||||
},
|
||||
},
|
||||
])
|
||||
}
|
||||
|
||||
if (!data) return
|
||||
|
||||
const update = data.scannerStatusUpdate
|
||||
const newMessages = [...messages]
|
||||
|
||||
if (update.success) {
|
||||
newMessages[0] = {
|
||||
key: 'primary',
|
||||
type: 'progress',
|
||||
props: {
|
||||
header: update.finished ? 'Synced' : 'Syncing',
|
||||
content: update.message,
|
||||
percent: update.progress,
|
||||
positive: update.finished,
|
||||
},
|
||||
}
|
||||
|
||||
if (!update.finished) newMessages[0].props.onDismiss = null
|
||||
} else {
|
||||
const key = Math.random().toString(26)
|
||||
newMessages.push({
|
||||
key,
|
||||
type: 'message',
|
||||
props: {
|
||||
header: 'Sync error',
|
||||
content: update.message,
|
||||
negative: true,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
setMessages(newMessages)
|
||||
}, [data, error])
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
SubscriptionsHook.propTypes = {
|
||||
messages: PropTypes.array.isRequired,
|
||||
setMessages: PropTypes.func.isRequired,
|
||||
}
|
||||
|
||||
export default SubscriptionsHook
|
|
@ -19,7 +19,7 @@ const StyledPhoto = styled(ProtectedImage)`
|
|||
min-width: 100%;
|
||||
position: relative;
|
||||
object-fit: cover;
|
||||
opacity: ${props => (props.loaded ? 1 : 0)};
|
||||
opacity: ${({ loaded }) => (loaded ? 1 : 0)};
|
||||
|
||||
transition: opacity 300ms;
|
||||
`
|
||||
|
@ -30,7 +30,7 @@ const PhotoImg = photoProps => {
|
|||
return (
|
||||
<StyledPhoto
|
||||
{...photoProps}
|
||||
loaded={loaded}
|
||||
loaded={loaded ? 1 : 0}
|
||||
onLoad={() => {
|
||||
setLoaded(true)
|
||||
}}
|
||||
|
|
|
@ -18,5 +18,4 @@ const Main = () => (
|
|||
|
||||
ReactDOM.render(<Main />, document.getElementById('root'))
|
||||
|
||||
// TODO: Get Service Worker up and running
|
||||
registerServiceWorker()
|
||||
|
|
Loading…
Reference in New Issue