Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
fb5f2d5
toast context hook
ButteryCrumpet Nov 26, 2019
b67c2af
Toast Component
ButteryCrumpet Nov 26, 2019
2543863
added context provider, show toast message on sync fail
ButteryCrumpet Nov 26, 2019
0face0c
Add style
Dec 13, 2019
4d9ecb3
Set Up
ellekasai Dec 13, 2019
bf3a89c
Added Top Margin
ellekasai Dec 13, 2019
50874dd
Created styled.tsx in Toast
ellekasai Dec 13, 2019
c617f07
Added Logo
ellekasai Dec 12, 2019
126387c
Added Style Functions for About Page
ellekasai Dec 12, 2019
cab875d
Added Const for About Page
ellekasai Dec 12, 2019
c12323e
Styled About Page
ellekasai Dec 12, 2019
0bcb018
escape regexp
Davy-c Dec 12, 2019
21bca37
fix tutorials tree
Davy-c Dec 10, 2019
4dca852
redirect to create storage page
Davy-c Dec 10, 2019
9acfbd8
context menu to hide tutorials
Davy-c Dec 10, 2019
fc07381
change padding of no storage
Davy-c Dec 10, 2019
cc5c677
text color for no storage
Davy-c Dec 10, 2019
19080a2
tmp
Davy-c Dec 11, 2019
db5236d
fix lint command
Davy-c Dec 11, 2019
4a55ed7
first lint fixes
Davy-c Dec 11, 2019
fec3376
Modal Provider and download app modal
Davy-c Dec 11, 2019
29459bb
redirect to first storage on /app
Davy-c Dec 12, 2019
1789608
fix component singular name
Davy-c Dec 12, 2019
2f73ab9
change modal store to singular name
Davy-c Dec 12, 2019
da49277
changes to redirect controller
Davy-c Dec 12, 2019
a3c9fb2
replace instead of push
Davy-c Dec 12, 2019
fc2f3d3
Add themes (#132)
Dec 13, 2019
915169f
Added Billing Page (#114)
ellekasai Dec 13, 2019
37216d0
Testing
ellekasai Dec 13, 2019
5003cf2
Fixed Applying Style Bug
ellekasai Dec 13, 2019
4425bfa
Removed ModalsProvider
ellekasai Dec 13, 2019
705476d
Removed Toast Message Button
ellekasai Dec 13, 2019
076a306
Merge branch 'master' into toast
ellekasai Dec 13, 2019
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
287 changes: 154 additions & 133 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions src/components/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import '../lib/analytics'
import CodeMirrorStyle from './CodeMirrorStyle'
import { useGeneralStatus } from '../lib/generalStatus'
import Modal from './Modal'
import ToastList from './Toast'

const App = () => {
const { initialize, initialized } = useDb()
Expand Down Expand Up @@ -69,6 +70,7 @@ const App = () => {
<Dialog />
<PreferencesModal />
<Modal />
<ToastList />
<CodeMirrorStyle />
</StyledAppContainer>
</ThemeProvider>
Expand Down
4 changes: 4 additions & 0 deletions src/components/PreferencesModal/styled.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,10 @@ export const RightMargin = styled.span`
margin-right: 20px;
`

export const TopMargin = styled.div`
margin-top: 40px;
`

export const DeleteStorageButton = styled.button`
${secondaryButtonStyle}
padding: 0 16px;
Expand Down
25 changes: 16 additions & 9 deletions src/components/Storage/StorageCreate.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,20 @@ import {
SectionMargin,
SectionHeader1,
RightMargin,
TopMargin,
SectionPrimaryButton
} from '../PreferencesModal/styled'
import { useTranslation } from 'react-i18next'
import { useDb } from '../../lib/db'
import { CloudStorage } from '../../lib/accounts'
import LoginButton from '../atoms/LoginButton'
import CloudStorageSelector from './CloudStorageSelector'
import { useToast } from '../../lib/toast'

export default () => {
const db = useDb()
const { preferences } = usePreferences()
const { pushMessage } = useToast()
const { t } = useTranslation()
const [localName, setLocalName] = useState('')
const [storageType, setStorageType] = useState<'cloud' | 'local'>('cloud')
Expand All @@ -29,8 +32,10 @@ export default () => {
if (cloudStorage != null) {
const success = db.setCloudLink(newStorage.id, cloudStorage, user)
if (!success) {
console.error('sync failed')
// TODO: toast sync failure
pushMessage({
title: 'Sync Error',
description: 'The storage was unable to be synced with the cloud'
})
}
}
}
Expand Down Expand Up @@ -70,20 +75,22 @@ export default () => {

{storageType === 'local' && (
<>
<div>
<TopMargin>
<SectionPrimaryButton onClick={() => createStorageCallback()}>
Create Storage
</SectionPrimaryButton>
</div>
</TopMargin>
</>
)}
{!isLoggedIn && storageType === 'cloud' && (
<>
<p>You need to sign in to create a cloud storage.</p>
<LoginButton
onErr={console.error /* TODO: Toast error */}
ButtonComponent={SectionPrimaryButton}
/>
<TopMargin>
<p>You need to sign in to create a cloud storage.</p>
<LoginButton
onErr={console.error /* TODO: Toast error */}
ButtonComponent={SectionPrimaryButton}
/>
</TopMargin>
</>
)}
{isLoggedIn && storageType === 'cloud' && (
Expand Down
23 changes: 15 additions & 8 deletions src/components/Storage/StorageEdit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
SectionMargin,
SectionHeader1,
RightMargin,
TopMargin,
SectionPrimaryButton,
DeleteStorageButton
} from '../PreferencesModal/styled'
Expand All @@ -15,6 +16,7 @@ import { useRouter } from '../../lib/router'
import { useDebounce } from 'react-use'
import LoginButton from '../atoms/LoginButton'
import { useDialog, DialogIconTypes } from '../../lib/dialog'
import { useToast } from '../../lib/toast'

interface StorageEditProps {
storage: NoteStorage
Expand All @@ -23,6 +25,7 @@ interface StorageEditProps {
export default ({ storage }: StorageEditProps) => {
const db = useDb()
const router = useRouter()
const { pushMessage } = useToast()
const { preferences } = usePreferences()
const [name, setName] = useState(storage.name)
const { messageBox } = useDialog()
Expand All @@ -36,11 +39,13 @@ export default ({ storage }: StorageEditProps) => {
const linkCallback = useCallback(
(cloudStorage: CloudStorage) => {
db.setCloudLink(storage.id, cloudStorage, user).catch(() => {
//TODO: toast syncing failed
console.log('sync error')
pushMessage({
title: 'Sync Error',
description: 'The storage was unable to be synced with the cloud'
})
})
},
[storage.id, db, user]
[storage.id, db, user, pushMessage]
)

const unlinkCallback = useCallback(() => {
Expand Down Expand Up @@ -109,11 +114,13 @@ export default ({ storage }: StorageEditProps) => {
<div>
{user == null && (
<>
<p>You need to sign in to add a cloud storage.</p>
<LoginButton
onErr={console.error /* TODO: Toast error */}
ButtonComponent={SectionPrimaryButton}
/>
<TopMargin>
<p>You need to sign in to add a cloud storage.</p>
<LoginButton
onErr={console.error /* TODO: Toast error */}
ButtonComponent={SectionPrimaryButton}
/>
</TopMargin>
</>
)}
{user != null && (
Expand Down
48 changes: 48 additions & 0 deletions src/components/Toast/ToastItem.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import React, { useState, useEffect } from 'react'
import { ToastMessage } from '../../lib/toast'
import { dateToRelativeString } from '../../lib/utils/time'
import {
StyledToastContainer,
StyledToastTop,
StyledToastRight,
StyledToastTitle,
StyledToastTime,
StyledToastCloseButton,
StyledToastDescription
} from './styled'

interface ToastItemProps {
item: ToastMessage
onClose: (item: ToastMessage) => void
}

const ToastItem = ({ item, onClose }: ToastItemProps) => {

const [relativeTime, setRelativeTime] = useState(
dateToRelativeString(item.createdAt)
)

useEffect(() => {
const interval = setInterval(() => {
setRelativeTime(dateToRelativeString(item.createdAt))
}, 10000)

return () => clearInterval(interval)
}, [])

return (
<StyledToastContainer>
<StyledToastTop>
<StyledToastTitle>{item.title}</StyledToastTitle>
<StyledToastRight>
<StyledToastTime>{relativeTime}</StyledToastTime>
<StyledToastCloseButton>
<span onClick={() => onClose(item)}>&times;</span>
</StyledToastCloseButton>
</StyledToastRight>
</StyledToastTop>
<StyledToastDescription>{item.description}</StyledToastDescription>
</StyledToastContainer>
)
}
export default ToastItem
27 changes: 27 additions & 0 deletions src/components/Toast/ToastList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import React from 'react'
import { useToast } from '../../lib/toast'
import ToastItem from './ToastItem'
import styled from '../../lib/styled'

const StyledToastList = styled.ul`
position: fixed;
display: flex;
flex-direction: column-reverse;
right: 0;
bottom: 0;
list-style: none;
`

export default () => {
const { messages, removeMessage } = useToast()

return (
<StyledToastList>
{messages.map(message => (
<li key={message.id}>
<ToastItem item={message} onClose={removeMessage} />
</li>
))}
</StyledToastList>
)
}
1 change: 1 addition & 0 deletions src/components/Toast/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from './ToastList'
44 changes: 44 additions & 0 deletions src/components/Toast/styled.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import styled from '../../lib/styled'
import {
secondaryBackgroundColor,
iconColor
} from '../../lib/styled/styleFunctions'

export const StyledToastContainer = styled.div`
width: 350px;
margin: 40px;
padding: 10px 30px;
box-shadow: 0 0.25rem 0.75rem rgba(0, 0, 0, 0.1);
border-radius: 5px;
${secondaryBackgroundColor}
`
export const StyledToastTop = styled.div`
display: inline-flex;
border-bottom: 1px solid;
width: 100%;
`
export const StyledToastRight = styled.div`
position: absolute;
right: 60px;
display: inline-flex;
`
export const StyledToastTitle = styled.p`
font-size: 16px;
font-weight: 600:
`
export const StyledToastTime = styled.p`
font-size: 12px;
margin-right: 10px;
line-height: 25px;
`
export const StyledToastCloseButton = styled.button`
background-color: transparent;
font-size: 24px;
order: none;
cursor: pointer;
border: none;
${iconColor}
`
export const StyledToastDescription = styled.p`
font-size: 14px;
`
4 changes: 3 additions & 1 deletion src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { DbProvider } from './lib/db'
import { PreferencesProvider } from './lib/preferences'
import { GeneralStatusProvider } from './lib/generalStatus'
import { PreviewStyleProvider } from './lib/preview'
import { ToastProvider } from './lib/toast'

const CombinedProvider = combineProviders(
PreviewStyleProvider,
Expand All @@ -19,7 +20,8 @@ const CombinedProvider = combineProviders(
DialogProvider,
ContextMenuProvider,
DbProvider,
RouterProvider
RouterProvider,
ToastProvider,
)

function render(Component: typeof App) {
Expand Down
42 changes: 42 additions & 0 deletions src/lib/toast/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { createStoreContext } from '../utils/context'
import { useState } from 'react'
import { generateSecret } from '../utils/secret'

export interface ToastMessage {
id: string
title: string
description: string
createdAt: Date
}

interface ToastStore {
readonly messages: ToastMessage[]
pushMessage: (message: Omit<ToastMessage, 'id' | 'createdAt'>) => void
removeMessage: (message: ToastMessage) => void
}

const createToastMessage = (title: string, description: string) => {
return {
id: generateSecret(),
createdAt: new Date(),
title,
description
}
}

const useToastStore = (): ToastStore => {
const [messages, setMessages] = useState<ToastMessage[]>([])

return {
messages,
pushMessage: ({ title, description }) =>
setMessages([createToastMessage(title, description), ...messages]),
removeMessage: message =>
setMessages(messages.filter(({ id }) => id !== message.id))
}
}

export const {
StoreProvider: ToastProvider,
useStore: useToast
} = createStoreContext(useToastStore)
31 changes: 31 additions & 0 deletions src/lib/utils/time.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
const MS_PER_MINUTE = 60 * 1000
const MS_PER_HOUR = MS_PER_MINUTE * 60
const MS_PER_DAY = MS_PER_HOUR * 24
const MS_PER_MONTH = MS_PER_DAY * 30
const MS_PER_YEAR = MS_PER_DAY * 365

export const dateToRelativeString = (date: Date) => {
const diffMS = new Date().getTime() - date.getTime()

if (diffMS < MS_PER_MINUTE) {
return `${Math.floor(diffMS / 1000)} seconds ago`
}

if (diffMS < MS_PER_HOUR) {
return `${Math.floor(diffMS / MS_PER_MINUTE)} minutes ago`
}

if (diffMS < MS_PER_DAY) {
return `${Math.floor(diffMS / MS_PER_HOUR)} hours ago`
}

if (diffMS < MS_PER_MONTH) {
return `${Math.floor(diffMS / MS_PER_DAY)} days ago`
}

if (diffMS < MS_PER_YEAR) {
return `${Math.floor(diffMS / MS_PER_MONTH)} months ago`
}

return `${Math.floor(diffMS / MS_PER_YEAR)} years ago`
}