Skip to content
This repository has been archived by the owner on Jan 2, 2025. It is now read-only.

Commit

Permalink
feat(draft): new draft logic (#1489)
Browse files Browse the repository at this point in the history
  • Loading branch information
horacioh authored Oct 30, 2023
1 parent 6c47188 commit d871961
Show file tree
Hide file tree
Showing 15 changed files with 1,194 additions and 805 deletions.
1 change: 1 addition & 0 deletions frontend/apps/site/server/routers/_app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,7 @@ const publicationRouter = router({
}),
})

// TODO: Duplicate (packages/app/models/documents.ts#209)
function sortDocuments(a?: string, b?: string) {
let dateA = a ? new Date(a) : 0
let dateB = b ? new Date(b) : 1
Expand Down
96 changes: 93 additions & 3 deletions frontend/packages/app/components/commit-draft-button.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,30 @@
import {useNavRoute} from '@mintter/app/utils/navigation'
import {useNavigate} from '@mintter/app/utils/useNavigate'
import {Button} from '@mintter/ui'
import {Document, formattedDate, formattedDateMedium} from '@mintter/shared'
import {
AlertCircle,
Button,
SizableText,
Spinner,
YStack,
YStackProps,
} from '@mintter/ui'
import {Check} from '@tamagui/lucide-icons'
import {useGRPCClient} from '../app-context'
import {usePublishDraft} from '../models/documents'
import {useDraft, usePublishDraft} from '../models/documents'
import {useDaemonReady} from '../node-status-context'
import {toast} from '../toast'
import {useMediaDialog} from './media-dialog'
import {DraftStatusContext} from '../models/draft-machine'
import {PropsWithChildren, useState} from 'react'

export default function CommitDraftButton() {
const route = useNavRoute()
if (route.key !== 'draft')
throw new Error('DraftPublicationButtons requires draft route')
const draftId = route.key == 'draft' ? route.draftId : null
const {data} = useDraft({documentId: draftId})

const navReplace = useNavigate('replace')
const navBack = useNavigate('backplace')
const grpcClient = useGRPCClient()
Expand All @@ -22,6 +34,7 @@ export default function CommitDraftButton() {

const mediaDialog = useMediaDialog()
const isDaemonReady = useDaemonReady()
const isSaving = DraftStatusContext.useSelector((s) => s.matches('saving'))
const publish = usePublishDraft({
onSuccess: ({pub: publishedDoc, pubContext, isFirstPublish}) => {
if (!publishedDoc || !draftId) return
Expand Down Expand Up @@ -52,9 +65,10 @@ export default function CommitDraftButton() {
return (
<>
{mediaDialog.content}
<DraftStatus updateAt={data?.updatedAt} />
<Button
size="$2"
disabled={!isDaemonReady}
disabled={!isDaemonReady || isSaving}
onPress={() => {
grpcClient.drafts.getDraft({documentId: draftId}).then((draft) => {
const hasEmptyMedia = draft.children.find((block) => {
Expand Down Expand Up @@ -82,3 +96,79 @@ export default function CommitDraftButton() {
</>
)
}

function StatusWrapper({children, ...props}: PropsWithChildren<YStackProps>) {
return (
<YStack zIndex={1000} space="$2">
{children}
</YStack>
)
}

function DraftStatus({updateAt}: {updateAt: any}) {
const [errorInfo, toggleErrorInfo] = useState(false)
const state = DraftStatusContext.useSelector((s) => s)

if (state.matches('lastUpdate') && updateAt) {
return (
<StatusWrapper>
<Button chromeless size="$1">
Last update: {formattedDateMedium(updateAt)}
</Button>
</StatusWrapper>
)
}

if (state.matches('saving')) {
return (
<StatusWrapper>
<Button chromeless size="$1" icon={<Spinner />}>
saving...
</Button>
</StatusWrapper>
)
}

if (state.matches('saved')) {
return (
<StatusWrapper>
<Button chromeless size="$1" icon={<Check />} disabled>
saved!
</Button>
</StatusWrapper>
)
}

if (state.matches('error')) {
return (
<StatusWrapper alignItems="flex-end">
<Button
chromeless
size="$1"
theme="red"
icon={<AlertCircle />}
alignSelf="end"
flex="none"
onPress={() => toggleErrorInfo((v) => !v)}
>
Error
</Button>
{errorInfo ? (
<YStack
borderRadius="$3"
padding="$2"
maxWidth={200}
backgroundColor="$backgroundStrong"
>
<SizableText size="$1">
An error ocurred while trying to save the latest changes. please
reload to make sure you do not loose any data.
</SizableText>
</YStack>
) : null}
</StatusWrapper>
)
}

return null
}
3 changes: 1 addition & 2 deletions frontend/packages/app/components/edit-group-info.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import {Group} from '@mintter/shared'
import {Button, Form, Input, Label, Spinner} from '@mintter/ui'
import {Button, Form, Input, Label, Spinner, TextInput} from '@mintter/ui'
import {useRef} from 'react'
import {toast} from 'react-hot-toast'
import {TextInput} from 'react-native-web'
import {useGroup, useUpdateGroup} from '../models/groups'
import {DialogTitle, useAppDialog} from './dialog'

Expand Down
3 changes: 1 addition & 2 deletions frontend/packages/app/components/list-item.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import {Button, ButtonProps, ButtonText, Link, Tooltip} from '@mintter/ui'
import {ReactElement} from 'react'
import {copyUrlToClipboardWithFeedback} from '../copy-to-clipboard'
import {MenuItemType, OptionsDropdown} from './options-dropdown'
import {GestureResponderEvent} from 'react-native'

export function ListItem({
accessory,
Expand Down Expand Up @@ -63,7 +62,7 @@ export function TimeAccessory({
onPress,
}: {
time: Timestamp | undefined
onPress: (e: GestureResponderEvent) => void
onPress: (e) => void
}) {
return (
<Tooltip content={formattedDateLong(time)}>
Expand Down
34 changes: 34 additions & 0 deletions frontend/packages/app/models/__tests__/draft.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import {Block, BlockNode, Document} from '@mintter/shared'
import {describe, expect, test} from 'vitest'
import {createBlocksMap} from '../documents'

describe('Draft transformations', () => {
describe('backend to blockMap', () => {
test('single block', () => {
let inputBlock = new Block({
id: '1',
text: 'hello',
annotations: [],
attributes: {},
})
let input = new Document({
children: [
new BlockNode({
block: inputBlock,
children: [],
}),
],
})

let output = {
'1': {
parent: '',
left: '',
block: inputBlock,
},
}

expect(createBlocksMap(input)).toEqual(output)
})
})
})
Loading

0 comments on commit d871961

Please sign in to comment.