fix all type errors

This commit is contained in:
Thomas Ruoff
2021-02-15 23:29:25 +01:00
parent 85a7b54a13
commit 3386fb3928
14 changed files with 123 additions and 132 deletions

View File

@@ -1,96 +1,83 @@
import React, { Component } from 'react' import React, { useState, useEffect } from 'react'
import LetterOptions from './LetterOptions' import LetterOptions from './LetterOptions'
import Button from './Button' import Button from './Button'
import Preview from './Preview' import Preview from './Preview'
import LatestList from './LatestList' import LatestList from './LatestList'
import { generatePdf, getLatest, removeLatest } from './apiHelper' import { generatePdf, getLatest, removeLatest } from './apiHelper'
import { ILatest } from '../interfaces/ILatest'
import { IDocProps } from '../interfaces/IDocProps'
//import './App.css'; //import './App.css';
class App extends Component { export default function App() {
componentDidMount() { const [options, setOptions] = useState<IDocProps>({
this._getLatest() template: 'brief-fam',
} subject: '',
body: '',
render() { address: '',
const state: Record<string, unknown> = this.state || {}
return (
<div className="home">
<div>
<LetterOptions onChange={this._onChange.bind(this)} {...state.options} />
<LatestList
latest={state.latest}
onSelect={this._onSelectLatest.bind(this)}
onRemove={this._onRemoveLatest.bind(this)}
/>
</div>
<div>
<div>
<Button onClick={this._onGenerate.bind(this)}>Backe PDF</Button>
<Button onClick={this._onClear.bind(this)}>Alles Löschen</Button>
</div>
<Preview pdfUrl={state.pdfUrl} pdfIsLoading={state.pdfIsLoading} pdfError={state.pdfError} />
</div>
</div>
)
}
_onSelectLatest(selectedOptions) {
this.setState({ options: Object.assign({}, selectedOptions) })
}
_onRemoveLatest(item) {
removeLatest(item).then(() => {
const latest = this.state.latest.filter((curr) => curr.id !== item.id)
this.setState({ latest })
}) })
} const [latest, setLatest] = useState<ILatest[]>([])
const [pdfUrl, setPdfUrl] = useState<string | null>(null)
const [pdfIsLoading, setPdfIsLoading] = useState<boolean>(false)
const [pdfError, setPdfError] = useState<string | null>(null)
_onClear() { useEffect(() => {
window.location.reload()
}
_onGenerate() {
const state = this.state || {}
this.setState({
pdfIsLoading: true,
pdfError: null,
})
generatePdf(state.options)
.then((data) => {
const { id } = data
this.setState({
pdfIsLoading: false,
pdfUrl: `/api/pdf/${id}`,
})
})
.catch((error) => {
this.setState({
pdfIsLoading: false,
pdfError: error.message,
pdfUrl: null,
})
})
.then(() => this._getLatest())
}
_getLatest() {
getLatest() getLatest()
.then((latest) => this.setState({ latest })) .then((latest) => setLatest(latest))
.catch((err) => console.error('Unable to get latest:', err)) .catch((err) => console.error('Unable to get latest:', err))
} }, [pdfUrl])
_onChange(name, event) { const _onChange = (name: string, event: React.ChangeEvent<{ value: string }>) => {
if (!name) { if (!name) {
return return
} }
const value = event && event.target && event.target.value const value = event && event.target && event.target.value
const options = Object.assign({}, this.state.options, { [name]: value || undefined }) setOptions({ ...options, [name]: value || undefined })
this.setState({ options })
}
} }
export default App const _onSelectLatest = (selectedOption: ILatest) => {
setOptions({ ...selectedOption })
}
const _onRemoveLatest = (item: ILatest) => {
removeLatest(item).then(() => setLatest(latest.filter((curr) => curr.id !== item.id)))
}
const _onClear = () => {
window.location.reload()
}
const _onGenerate = () => {
setPdfIsLoading(true)
setPdfError(null)
generatePdf(options)
.then((data) => {
const { id } = data
setPdfIsLoading(false)
setPdfUrl(`/api/pdf/${id}`)
})
.catch((error) => {
setPdfIsLoading(false)
setPdfError(error.message)
setPdfUrl(null)
})
}
return (
<div className="home">
<div>
<LetterOptions onChange={_onChange} {...options} />
<LatestList latest={latest} onSelect={_onSelectLatest} onRemove={_onRemoveLatest} />
</div>
<div>
<div>
<Button onClick={_onGenerate}>Backe PDF</Button>
<Button onClick={_onClear}>Alles Löschen</Button>
</div>
<Preview pdfUrl={pdfUrl} pdfIsLoading={pdfIsLoading} pdfError={pdfError} />
</div>
</div>
)
}

View File

@@ -3,15 +3,15 @@ import React from 'react'
export default function Input({ export default function Input({
text, text,
name, name,
value, value = '',
placeholder, placeholder,
onchange, onchange,
}: { }: {
text: string text: string
name: string name: string
value: string value?: string
placeholder: string placeholder?: string
onchange: () => void onchange: (name: string, event: React.ChangeEvent<HTMLInputElement>) => void
}) { }) {
return ( return (
<label> <label>

View File

@@ -11,7 +11,7 @@ import { IDocProps } from '../interfaces/IDocProps'
const EXAMPLE_ADDRESS = 'Max Mustermann\nMusterstr. 73\n12345 Musterstadt' const EXAMPLE_ADDRESS = 'Max Mustermann\nMusterstr. 73\n12345 Musterstadt'
interface IProps extends IDocProps { interface IProps extends IDocProps {
onChange: () => void onChange: (name: string, event: React.ChangeEvent<{ value: string }>) => void
} }
export default function LetterOptions(props: IProps) { export default function LetterOptions(props: IProps) {

View File

@@ -1,14 +1,7 @@
import React from 'react' import React from 'react'
import { IPdfProps } from '../interfaces/IPdfProps'
export default function Preview({ export default function Preview({ pdfIsLoading, pdfError, pdfUrl }: IPdfProps) {
pdfIsLoading,
pdfError,
pdfUrl,
}: {
pdfIsLoading: boolean
pdfError: string
pdfUrl: string
}) {
if (pdfIsLoading) { if (pdfIsLoading) {
return <div>Lade&hellip;</div> return <div>Lade&hellip;</div>
} }

View File

@@ -10,7 +10,7 @@ export default function Select({
name: string name: string
text: string text: string
value: string value: string
onchange: () => void onchange: (name: string, event: React.ChangeEvent<{ value: string }>) => void
options: { name: string; value: string }[] options: { name: string; value: string }[]
}) { }) {
return ( return (

View File

@@ -10,7 +10,7 @@ export default function TextAreaInput({
text: string text: string
name: string name: string
placeholder: string placeholder: string
onchange: () => void onchange: (name: string, event: React.ChangeEvent<HTMLTextAreaElement>) => void
value: string value: string
}) { }) {
return ( return (

View File

@@ -1,3 +1,4 @@
import { IDocProps } from '../interfaces/IDocProps'
import { ILatest } from '../interfaces/ILatest' import { ILatest } from '../interfaces/ILatest'
function checkStatus(res: Response) { function checkStatus(res: Response) {
@@ -6,7 +7,7 @@ function checkStatus(res: Response) {
} }
} }
export async function generatePdf(state: Record<string, string>) { export async function generatePdf(state: IDocProps) {
const options = { const options = {
method: 'POST', method: 'POST',
headers: { headers: {

5
interfaces/IPdfProps.ts Normal file
View File

@@ -0,0 +1,5 @@
export interface IPdfProps {
pdfUrl: string | null
pdfIsLoading: boolean
pdfError: string | null
}

View File

@@ -2,6 +2,7 @@ const storeDir = process.env.JSON_STORE || '/tmp/pdfer-store/'
import { promisify } from 'util' import { promisify } from 'util'
// @ts-ignore
import JsonStore from 'json-fs-store' import JsonStore from 'json-fs-store'
const store = JsonStore(storeDir) const store = JsonStore(storeDir)

View File

@@ -1,8 +1,10 @@
import { IDocProps } from '../interfaces/IDocProps'
function convertLineBreaks(lines: string) { function convertLineBreaks(lines: string) {
return lines.replace(/\n/g, '\\\\') return lines.replace(/\n/g, '\\\\')
} }
export function brief(options: Record<string, string>) { export function brief(options: IDocProps) {
const { const {
template = 'brief-fam', template = 'brief-fam',
subject = '', subject = '',
@@ -21,7 +23,7 @@ export function brief(options: Record<string, string>) {
closing = 'Mit freundlichen Grüßen', closing = 'Mit freundlichen Grüßen',
ps = '', ps = '',
enclosing = '', enclosing = '',
} = options } = { ...options }
return `% brief document return `% brief document
\\documentclass{scrlttr2} \\documentclass{scrlttr2}

View File

@@ -5,7 +5,7 @@ import {remove as storeRemove} from '../../../lib/store'
import { getPdfPath } from '../../../lib/utils' import { getPdfPath } from '../../../lib/utils'
const handler = async (req: NextApiRequest, res: NextApiResponse) => { const handler = async (req: NextApiRequest, res: NextApiResponse) => {
const { method } = req; const { method } = req
switch (req.method) { switch (req.method) {
case 'GET': case 'GET':
@@ -14,14 +14,16 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
query: { id: idArg }, query: { id: idArg },
} = req } = req
const fileContent = await promises.readFile(getPdfPath(idArg)) const id = Array.isArray(idArg) ? idArg[0] : idArg
const fileContent = await promises.readFile(getPdfPath(id))
res.setHeader('Content-Type', 'application/pdf') res.setHeader('Content-Type', 'application/pdf')
res.status(200).send(fileContent); res.status(200).send(fileContent)
} catch (error) { } catch (error) {
console.error(error) console.error(error)
res.status(404).json({ statusCode: 404, message: 'Method Not Allowed' }) res.status(404).json({ statusCode: 404, message: 'Method Not Allowed' })
} }
break; break
case 'DELETE': case 'DELETE':
try { try {
const { const {
@@ -35,11 +37,11 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
console.error(error) console.error(error)
res.status(404).json({ statusCode: 404, message: 'Method Not Allowed' }) res.status(404).json({ statusCode: 404, message: 'Method Not Allowed' })
} }
break; break
default: default:
res.setHeader('Allow', ['GET', 'DELETE']) res.setHeader('Allow', ['GET', 'DELETE'])
res.status(405).end(`Method ${method} Not Allowed`) res.status(405).end(`Method ${method} Not Allowed`)
} }
} }
export default handler; export default handler

View File

@@ -2,7 +2,7 @@ import Layout from '../components/Layout'
import App from '../components/App' import App from '../components/App'
const IndexPage = () => ( const IndexPage = () => (
<Layout title="Home | Next.js + TypeScript Example"> <Layout>
<App /> <App />
</Layout> </Layout>
) )