Skip to content
Snippets Groups Projects
Commit 17ae24e6 authored by Katarína Platková's avatar Katarína Platková
Browse files

Merge branch 'editor-injects' into 'dp-platkova'

Editor - injects page

See merge request inject/frontend!270
parents 24078f2b fc449fc7
No related branches found
No related tags found
No related merge requests found
import type { ButtonProps } from '@blueprintjs/core'
import {
Button,
Dialog,
DialogBody,
DialogFooter,
HTMLSelect,
InputGroup,
Label,
TextArea,
} from '@blueprintjs/core'
import { useNotifyContext } from '@inject/shared/notification/contexts/NotifyContext'
import type { FC } from 'react'
import { memo, useCallback, useEffect, useState } from 'react'
import { addInjectInfo, updateInjectInfo } from '../indexeddb/operations'
import type { InjectInfo } from '../indexeddb/types'
import { InjectType } from '../indexeddb/types'
import { INJECT_TYPES } from '../utils'
interface InjectFormProps {
inject?: InjectInfo
buttonProps: ButtonProps
}
const InjectForm: FC<InjectFormProps> = ({ inject, buttonProps }) => {
const [isOpen, setIsOpen] = useState(false)
const [name, setName] = useState<string>('')
const [description, setDescription] = useState<string>('')
const [type, setType] = useState<InjectType>(InjectType.INFORMATION)
const { notify } = useNotifyContext()
const clearInput = useCallback(() => {
setName('')
setDescription('')
}, [])
const handleAddButton = useCallback(
async (inject: Omit<InjectInfo, 'id'>) => {
try {
await addInjectInfo(inject)
clearInput()
setIsOpen(false)
} catch (err) {
notify(`Failed to add inject '${inject.name}': ${err}`, {
intent: 'danger',
})
}
},
[notify]
)
const handleUpdateButton = useCallback(
async (inject: InjectInfo) => {
try {
await updateInjectInfo(inject)
setIsOpen(false)
} catch (err) {
notify(`Failed to update inject '${inject.name}': ${err}`, {
intent: 'danger',
})
}
},
[notify]
)
useEffect(() => {
setName(inject?.name || '')
setDescription(inject?.description || '')
setType(inject?.type || InjectType.INFORMATION)
}, [inject])
return (
<>
<Button {...buttonProps} onClick={() => setIsOpen(true)} />
<Dialog
isOpen={isOpen}
onClose={() => setIsOpen(false)}
icon={inject ? 'edit' : 'plus'}
title={inject ? 'Edit inject' : 'New inject'}
>
<DialogBody>
<Label style={{ width: '100%' }}>
Title
<InputGroup
placeholder='Input text'
value={name}
onChange={e => setName(e.target.value)}
/>
</Label>
<Label style={{ width: '100%' }}>
What is this inject about? (optional)
<TextArea
value={description}
style={{
width: '100%',
height: '5rem',
resize: 'none',
overflowY: 'auto',
}}
placeholder='Input text'
onChange={e => setDescription(e.target.value)}
/>
</Label>
<Label style={{ width: '100%' }}>
Channel
<HTMLSelect
options={INJECT_TYPES}
value={type}
onChange={event =>
setType(event.currentTarget.value as InjectType)
}
/>
</Label>
</DialogBody>
<DialogFooter
actions={
inject ? (
<Button
disabled={!name}
onClick={() =>
handleUpdateButton({
id: inject.id,
name,
description,
type,
})
}
intent='primary'
icon='edit'
text='Save changes'
/>
) : (
<Button
disabled={!name}
onClick={() => handleAddButton({ name, description, type })}
intent='primary'
icon='plus'
text='Add'
/>
)
}
/>
</Dialog>
</>
)
}
export default memo(InjectForm)
import { Button, ButtonGroup, Card, Icon } from '@blueprintjs/core'
import { useNotifyContext } from '@inject/shared/notification/contexts/NotifyContext'
import type { FC } from 'react'
import { memo, useCallback } from 'react'
import InjectForm from '../InjectForm'
import { deleteInjectInfo } from '../indexeddb/operations'
import type { InjectInfo } from '../indexeddb/types'
import { InjectType } from '../indexeddb/types'
interface InjectItemProps {
inject: InjectInfo
}
const InjectItem: FC<InjectItemProps> = ({ inject }) => {
const { notify } = useNotifyContext()
const handleDeleteButton = useCallback(
async (inject: InjectInfo) => {
try {
await deleteInjectInfo(inject.id)
} catch (err) {
notify(`Failed to delete inject '${inject.name}': ${err}`, {
intent: 'danger',
})
}
},
[notify]
)
return (
<Card style={{ display: 'flex', justifyContent: 'space-between' }}>
<span style={{ height: '100%', flexGrow: 1 }}>
<Icon
icon={inject.type === InjectType.EMAIL ? 'envelope' : 'clipboard'}
style={{ marginRight: '1rem' }}
/>
{inject.name}
</span>
<ButtonGroup>
<InjectForm
inject={inject}
buttonProps={{
minimal: true,
icon: 'edit',
style: { marginRight: '1rem' },
}}
/>
<Button
minimal
icon='cross'
onClick={() => handleDeleteButton(inject)}
/>
</ButtonGroup>
</Card>
)
}
export default memo(InjectItem)
import Inject from '@/editor/Injects/Inject'
import { CardList } from '@blueprintjs/core'
import { useLiveQuery } from 'dexie-react-hooks'
import { memo } from 'react'
import { db } from '../indexeddb/db'
import type { InjectInfo } from '../indexeddb/types'
const Injects = () => {
const injects = useLiveQuery(() => db.injectInfos.toArray(), [], [])
return (
<CardList>
{injects?.map((inject: InjectInfo) => (
<Inject key={inject.id} inject={inject} />
))}
</CardList>
)
}
export default memo(Injects)
import Dexie, { type EntityTable } from 'dexie'
import type { LearningObjectiveInfo } from './types'
import type { InjectInfo, LearningObjectiveInfo } from './types'
const dbName = 'EditorDatabase'
const dbVersion = 1
const db = new Dexie(dbName) as Dexie & {
learningObjectives: EntityTable<LearningObjectiveInfo, 'id'>
injectInfos: EntityTable<InjectInfo, 'id'>
}
db.version(dbVersion).stores({
learningObjectives: '++id, &name',
injectInfos: '++id, &name, description, type',
})
export { db }
import { db } from './db'
import type { LearningObjectiveInfo } from './types'
import type { InjectInfo, LearningObjectiveInfo } from './types'
// learning objectives operations
export const addLearningObjective = async (
......@@ -11,3 +11,15 @@ export const addLearningObjective = async (
export const deleteLearningObjective = async (id: string) =>
await db.learningObjectives.delete(id)
// inject info operations
export const addInjectInfo = async (injectInfo: Omit<InjectInfo, 'id'>) =>
await db.transaction('rw', db.injectInfos, async () => {
await db.injectInfos.add(injectInfo)
})
export const updateInjectInfo = async (injectInfo: InjectInfo) =>
await db.injectInfos.put(injectInfo)
export const deleteInjectInfo = async (id: number) =>
await db.injectInfos.delete(id)
import type { LearningObjective } from '@inject/graphql/fragments/LearningObjective.generated'
export type LearningObjectiveInfo = Pick<LearningObjective, 'id' | 'name'>
export enum InjectType {
INFORMATION = 'Information',
EMAIL = 'Email',
}
export type InjectInfo = {
id: number
name: string
description: string
type: InjectType
}
import { InjectType } from './indexeddb/types'
export const INJECT_TYPES = Object.values(InjectType)
import InjectForm from '@/editor/InjectForm'
import Injects from '@/editor/Injects'
import { useNavigate } from '@/router'
import { Button } from '@blueprintjs/core'
import { css } from '@emotion/css'
import { memo } from 'react'
const injectsPage = css`
display: grid;
grid-template-rows: auto auto 1fr auto;
height: 100vh;
`
const InjectsPage = () => {
const nav = useNavigate()
return (
<div className={injectsPage}>
<h1>Define injects</h1>
<p style={{ marginBottom: '1rem' }}>Description.</p>
<div style={{ overflowY: 'auto' }}>
<Injects />
<InjectForm
buttonProps={{
minimal: true,
text: 'Add new inject',
alignText: 'left',
icon: 'plus',
style: { padding: '1rem', width: '100%' },
}}
/>
</div>
<div
style={{
display: 'flex',
justifyContent: 'center',
padding: '0.5rem 0',
}}
>
<Button
type='button'
onClick={() => nav('/editor/create/learning-objectives')}
text='Back'
icon='arrow-left'
style={{
marginRight: '0.5rem',
}}
/>
<Button
type='button'
text='Continue'
intent='primary'
rightIcon='arrow-right'
/>
</div>
</div>
)
}
export default memo(InjectsPage)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment