mirror of
https://github.com/tomru/pdfer.git
synced 2026-03-03 06:27:19 +01:00
add prettier and format all
This commit is contained in:
12
.editorconfig
Normal file
12
.editorconfig
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
; EditorConfig file: http://EditorConfig.org
|
||||||
|
; Install the "EditorConfig" plugin into Sublime Text to use
|
||||||
|
|
||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
charset = utf-8
|
||||||
|
end_of_line = lf
|
||||||
|
insert_final_newline = true
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
trim_trailing_whitespace = true
|
||||||
1
.prettierignore
Normal file
1
.prettierignore
Normal file
@@ -0,0 +1 @@
|
|||||||
|
.next
|
||||||
7
.prettierrc
Normal file
7
.prettierrc
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"trailingComma": "es5",
|
||||||
|
"tabWidth": 2,
|
||||||
|
"semi": false,
|
||||||
|
"singleQuote": true,
|
||||||
|
"printWidth": 120
|
||||||
|
}
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
import React from 'react';
|
import React from 'react'
|
||||||
import ReactDOM from 'react-dom';
|
import ReactDOM from 'react-dom'
|
||||||
import App from './App';
|
import App from './App'
|
||||||
|
|
||||||
it('renders without crashing', () => {
|
it('renders without crashing', () => {
|
||||||
const div = document.createElement('div');
|
const div = document.createElement('div')
|
||||||
ReactDOM.render(<App />, div);
|
ReactDOM.render(<App />, div)
|
||||||
});
|
})
|
||||||
|
|||||||
@@ -1,25 +1,27 @@
|
|||||||
import React, { Component } from 'react';
|
import React, { Component } 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 './App.css';
|
//import './App.css';
|
||||||
|
|
||||||
class App extends Component {
|
class App extends Component {
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
this._getLatest();
|
this._getLatest()
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const state = this.state || {};
|
const state = this.state || {}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="home">
|
<div className="home">
|
||||||
<div>
|
<div>
|
||||||
<LetterOptions onChange={this._onChange.bind(this)} {...state.options}/>
|
<LetterOptions onChange={this._onChange.bind(this)} {...state.options} />
|
||||||
<LatestList latest={state.latest} onSelect={this._onSelectLatest.bind(this)}
|
<LatestList
|
||||||
|
latest={state.latest}
|
||||||
|
onSelect={this._onSelectLatest.bind(this)}
|
||||||
onRemove={this._onRemoveLatest.bind(this)}
|
onRemove={this._onRemoveLatest.bind(this)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -28,73 +30,67 @@ class App extends Component {
|
|||||||
<Button onClick={this._onGenerate.bind(this)}>Backe PDF</Button>
|
<Button onClick={this._onGenerate.bind(this)}>Backe PDF</Button>
|
||||||
<Button onClick={this._onClear.bind(this)}>Alles Löschen</Button>
|
<Button onClick={this._onClear.bind(this)}>Alles Löschen</Button>
|
||||||
</div>
|
</div>
|
||||||
<Preview
|
<Preview pdfUrl={state.pdfUrl} pdfIsLoading={state.pdfIsLoading} pdfError={state.pdfError} />
|
||||||
pdfUrl={state.pdfUrl}
|
|
||||||
pdfIsLoading={state.pdfIsLoading}
|
|
||||||
pdfError={state.pdfError}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
_onSelectLatest(selectedOptions) {
|
_onSelectLatest(selectedOptions) {
|
||||||
this.setState({options: Object.assign({}, selectedOptions)});
|
this.setState({ options: Object.assign({}, selectedOptions) })
|
||||||
}
|
}
|
||||||
|
|
||||||
_onRemoveLatest(item) {
|
_onRemoveLatest(item) {
|
||||||
removeLatest(item)
|
removeLatest(item).then(() => {
|
||||||
.then(() => {
|
const latest = this.state.latest.filter((curr) => curr.id !== item.id)
|
||||||
const latest = this.state.latest
|
|
||||||
.filter(curr => curr.id !== item.id);
|
|
||||||
|
|
||||||
this.setState({ latest });
|
this.setState({ latest })
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
_onClear() {
|
_onClear() {
|
||||||
window.location.reload();
|
window.location.reload()
|
||||||
}
|
}
|
||||||
|
|
||||||
_onGenerate() {
|
_onGenerate() {
|
||||||
const state = this.state || {};
|
const state = this.state || {}
|
||||||
this.setState({
|
this.setState({
|
||||||
pdfIsLoading: true,
|
pdfIsLoading: true,
|
||||||
pdfError: null
|
pdfError: null,
|
||||||
})
|
})
|
||||||
|
|
||||||
generatePdf(state.options)
|
generatePdf(state.options)
|
||||||
.then((data) => {
|
.then((data) => {
|
||||||
const {id} = data;
|
const { id } = data
|
||||||
this.setState({
|
this.setState({
|
||||||
pdfIsLoading: false,
|
pdfIsLoading: false,
|
||||||
pdfUrl: `/api/pdf/${id}`
|
pdfUrl: `/api/pdf/${id}`,
|
||||||
});
|
})
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
this.setState({
|
this.setState({
|
||||||
pdfIsLoading: false,
|
pdfIsLoading: false,
|
||||||
pdfError: error.message,
|
pdfError: error.message,
|
||||||
pdfUrl: null
|
pdfUrl: null,
|
||||||
});
|
})
|
||||||
})
|
})
|
||||||
.then(() => this._getLatest())
|
.then(() => this._getLatest())
|
||||||
}
|
}
|
||||||
|
|
||||||
_getLatest() {
|
_getLatest() {
|
||||||
getLatest()
|
getLatest()
|
||||||
.then(latest => this.setState({latest}))
|
.then((latest) => this.setState({ latest }))
|
||||||
.catch(err => console.error('Unable to get latest:', err));
|
.catch((err) => console.error('Unable to get latest:', err))
|
||||||
}
|
}
|
||||||
|
|
||||||
_onChange(name, event) {
|
_onChange(name, event) {
|
||||||
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});
|
const options = Object.assign({}, this.state.options, { [name]: value || undefined })
|
||||||
this.setState({options});
|
this.setState({ options })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default App;
|
export default App
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
import React from 'react';
|
import React from 'react'
|
||||||
|
|
||||||
export default function(props) {
|
export default function (props) {
|
||||||
return (
|
return (
|
||||||
<button className="p-button" onClick={props.onClick}>{props.children}</button>
|
<button className="p-button" onClick={props.onClick}>
|
||||||
);
|
{props.children}
|
||||||
|
</button>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import React from 'react';
|
import React from 'react'
|
||||||
|
|
||||||
export default function() {
|
export default function () {
|
||||||
return (
|
return (
|
||||||
<header className="header">
|
<header className="header">
|
||||||
<h1>PDFer</h1>
|
<h1>PDFer</h1>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import React from 'react';
|
import React from 'react'
|
||||||
|
|
||||||
export default function(props) {
|
export default function (props) {
|
||||||
return (
|
return (
|
||||||
<label>
|
<label>
|
||||||
{props.text}
|
{props.text}
|
||||||
@@ -12,5 +12,5 @@ export default function(props) {
|
|||||||
value={props.value}
|
value={props.value}
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
);
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,24 +1,26 @@
|
|||||||
import React from 'react';
|
import React from 'react'
|
||||||
import Button from './Button';
|
import Button from './Button'
|
||||||
|
|
||||||
export default function(props) {
|
export default function (props) {
|
||||||
const latest = props.latest || [];
|
const latest = props.latest || []
|
||||||
const latestElements = latest.map(item => {
|
const latestElements = latest.map((item) => {
|
||||||
const created = new Date(item.created);
|
const created = new Date(item.created)
|
||||||
const hrefId = `#item-${item.id}`;
|
const hrefId = `#item-${item.id}`
|
||||||
return (
|
return (
|
||||||
<li key={item.id}>
|
<li key={item.id}>
|
||||||
<a href={hrefId} onClick={() => props.onSelect(item)}>{created.toLocaleString()}</a>
|
<a href={hrefId} onClick={() => props.onSelect(item)}>
|
||||||
|
{created.toLocaleString()}
|
||||||
|
</a>
|
||||||
<span> </span>
|
<span> </span>
|
||||||
<Button onClick={() => props.onRemove(item)}>Remove</Button>
|
<Button onClick={() => props.onRemove(item)}>Remove</Button>
|
||||||
</li>
|
</li>
|
||||||
);
|
)
|
||||||
});
|
})
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<h4>Vergangene Briefe:</h4>
|
<h4>Vergangene Briefe:</h4>
|
||||||
<ul>{latestElements}</ul>
|
<ul>{latestElements}</ul>
|
||||||
</div>
|
</div>
|
||||||
);
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,12 @@
|
|||||||
import React from 'react';
|
import React from 'react'
|
||||||
|
|
||||||
import Header from './Header';
|
import Header from './Header'
|
||||||
|
|
||||||
export default function(props) {
|
export default function (props) {
|
||||||
return (
|
return (
|
||||||
<div id="app">
|
<div id="app">
|
||||||
<Header />
|
<Header />
|
||||||
<div id="content">
|
<div id="content">{props.children}</div>
|
||||||
{ props.children }
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
)
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,33 +1,33 @@
|
|||||||
import React from 'react';
|
import React from 'react'
|
||||||
|
|
||||||
import Collapsible from 'react-collapsible';
|
import Collapsible from 'react-collapsible'
|
||||||
import Input from './Input';
|
import Input from './Input'
|
||||||
import TextAreaInput from './TextAreaInput';
|
import TextAreaInput from './TextAreaInput'
|
||||||
import Select from './Select';
|
import Select from './Select'
|
||||||
|
|
||||||
//import './LetterOptions.css';
|
//import './LetterOptions.css';
|
||||||
|
|
||||||
const EXAMPLE_ADDRESS = 'Max Mustermann\nMusterstr. 73\n12345 Musterstadt';
|
const EXAMPLE_ADDRESS = 'Max Mustermann\nMusterstr. 73\n12345 Musterstadt'
|
||||||
|
|
||||||
export default function(props) {
|
export default function (props) {
|
||||||
const templateTypeOptions = [
|
const templateTypeOptions = [
|
||||||
{
|
{
|
||||||
value: 'brief-fam',
|
value: 'brief-fam',
|
||||||
name: 'Familie'
|
name: 'Familie',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 'brief-valerie',
|
value: 'brief-valerie',
|
||||||
name: 'Valerie'
|
name: 'Valerie',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 'brief-rain',
|
value: 'brief-rain',
|
||||||
name: 'Rain Baumeister'
|
name: 'Rain Baumeister',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 'brief-thomas',
|
value: 'brief-thomas',
|
||||||
name: 'Thomas'
|
name: 'Thomas',
|
||||||
}
|
},
|
||||||
];
|
]
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="letter-options">
|
<div className="letter-options">
|
||||||
@@ -46,53 +46,16 @@ export default function(props) {
|
|||||||
onchange={props.onChange}
|
onchange={props.onChange}
|
||||||
value={props.address}
|
value={props.address}
|
||||||
/>
|
/>
|
||||||
<Input
|
<Input name="subject" text="Betreff" placeholder="Betreffzeile" onchange={props.onChange} value={props.subject} />
|
||||||
name="subject"
|
|
||||||
text="Betreff"
|
|
||||||
placeholder="Betreffzeile"
|
|
||||||
onchange={props.onChange}
|
|
||||||
value={props.subject}
|
|
||||||
/>
|
|
||||||
<Collapsible trigger="Bezugszeichenzeile">
|
<Collapsible trigger="Bezugszeichenzeile">
|
||||||
<Input
|
<Input name="yourRef" text="Ihr Zeichen" onchange={props.onChange} value={props.yourRef} />
|
||||||
name="yourRef"
|
<Input name="yourMail" text="Ihr Schreiben vom" onchange={props.onChange} value={props.yourMail} />
|
||||||
text="Ihr Zeichen"
|
<Input name="myRef" text="Unser Zeichen" onchange={props.onChange} value={props.myRef} />
|
||||||
onchange={props.onChange}
|
<Input name="customer" text="Kundernummer" onchange={props.onChange} value={props.customer} />
|
||||||
value={props.yourRef}
|
<Input name="invoice" text="Rechnung" onchange={props.onChange} value={props.invoice} />
|
||||||
/>
|
|
||||||
<Input
|
|
||||||
name="yourMail"
|
|
||||||
text="Ihr Schreiben vom"
|
|
||||||
onchange={props.onChange}
|
|
||||||
value={props.yourMail}
|
|
||||||
/>
|
|
||||||
<Input
|
|
||||||
name="myRef"
|
|
||||||
text="Unser Zeichen"
|
|
||||||
onchange={props.onChange}
|
|
||||||
value={props.myRef}
|
|
||||||
/>
|
|
||||||
<Input
|
|
||||||
name="customer"
|
|
||||||
text="Kundernummer"
|
|
||||||
onchange={props.onChange}
|
|
||||||
value={props.customer}
|
|
||||||
/>
|
|
||||||
<Input
|
|
||||||
name="invoice"
|
|
||||||
text="Rechnung"
|
|
||||||
onchange={props.onChange}
|
|
||||||
value={props.invoice}
|
|
||||||
/>
|
|
||||||
</Collapsible>
|
</Collapsible>
|
||||||
<Collapsible trigger="Sonstige Einstellungen">
|
<Collapsible trigger="Sonstige Einstellungen">
|
||||||
<Input
|
<Input name="date" text="Datum" placeholder="Heute" onchange={props.onChange} value={props.date} />
|
||||||
name="date"
|
|
||||||
text="Datum"
|
|
||||||
placeholder="Heute"
|
|
||||||
onchange={props.onChange}
|
|
||||||
value={props.date}
|
|
||||||
/>
|
|
||||||
<Input
|
<Input
|
||||||
name="opening"
|
name="opening"
|
||||||
text="Eröffnung"
|
text="Eröffnung"
|
||||||
@@ -107,12 +70,7 @@ export default function(props) {
|
|||||||
onchange={props.onChange}
|
onchange={props.onChange}
|
||||||
value={props.closing}
|
value={props.closing}
|
||||||
/>
|
/>
|
||||||
<Input
|
<Input name="specialMail" text="Versandhinweis" onchange={props.onChange} value={props.specialMail} />
|
||||||
name="specialMail"
|
|
||||||
text="Versandhinweis"
|
|
||||||
onchange={props.onChange}
|
|
||||||
value={props.specialMail}
|
|
||||||
/>
|
|
||||||
</Collapsible>
|
</Collapsible>
|
||||||
<TextAreaInput
|
<TextAreaInput
|
||||||
name="body"
|
name="body"
|
||||||
@@ -122,5 +80,5 @@ export default function(props) {
|
|||||||
value={props.body}
|
value={props.body}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
)
|
||||||
};
|
}
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
import React from 'react';
|
import React from 'react'
|
||||||
|
|
||||||
export default props => {
|
export default (props) => {
|
||||||
if (props.pdfIsLoading) {
|
if (props.pdfIsLoading) {
|
||||||
return (
|
return <div>Lade…</div>
|
||||||
<div>Lade…</div>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const errorStyles = {
|
const errorStyles = {
|
||||||
@@ -12,26 +10,27 @@ export default props => {
|
|||||||
color: 'white',
|
color: 'white',
|
||||||
backgroundColor: '#d81e1e',
|
backgroundColor: '#d81e1e',
|
||||||
borderRadius: '3px',
|
borderRadius: '3px',
|
||||||
};
|
}
|
||||||
|
|
||||||
if (props.pdfError) {
|
if (props.pdfError) {
|
||||||
return (
|
return (
|
||||||
<div style={errorStyles}><span role="img" aria-label="Crying Man">😢</span> {props.pdfError}</div>
|
<div style={errorStyles}>
|
||||||
);
|
<span role="img" aria-label="Crying Man">
|
||||||
|
😢
|
||||||
|
</span>{' '}
|
||||||
|
{props.pdfError}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!props.pdfUrl) {
|
if (!props.pdfUrl) {
|
||||||
return (
|
return <div>Knopf drücken dann gibts hier was zu sehen!</div>
|
||||||
<div>Knopf drücken dann gibts hier was zu sehen!</div>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const styles = {
|
const styles = {
|
||||||
width: '700px',
|
width: '700px',
|
||||||
height: '1050px'
|
height: '1050px',
|
||||||
};
|
}
|
||||||
|
|
||||||
return (
|
return <embed src={props.pdfUrl} style={styles} type="application/pdf" />
|
||||||
<embed src={props.pdfUrl} style={styles} type="application/pdf" />
|
}
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|||||||
@@ -1,18 +1,18 @@
|
|||||||
import React from 'react';
|
import React from 'react'
|
||||||
|
|
||||||
export default (props) => {
|
export default (props) => {
|
||||||
const { options = [] } = props;
|
const { options = [] } = props
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<label>
|
<label>
|
||||||
{props.text}
|
{props.text}
|
||||||
<select
|
<select className={props.name} onChange={props.onchange.bind(null, props.name)} value={props.value}>
|
||||||
className={props.name}
|
{options.map((option) => (
|
||||||
onChange={props.onchange.bind(null, props.name)}
|
<option value={option.value} key={option.value}>
|
||||||
value={props.value}
|
{option.name}
|
||||||
>
|
</option>
|
||||||
{options.map((option) => <option value={option.value} key={option.value}>{option.name}</option>)}
|
))}
|
||||||
</select>
|
</select>
|
||||||
</label>
|
</label>
|
||||||
);
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import React from 'react';
|
import React from 'react'
|
||||||
|
|
||||||
export default function(props) {
|
export default function (props) {
|
||||||
return (
|
return (
|
||||||
<label>
|
<label>
|
||||||
{props.text}
|
{props.text}
|
||||||
@@ -11,5 +11,5 @@ export default function(props) {
|
|||||||
value={props.value}
|
value={props.value}
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
);
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,32 +1,31 @@
|
|||||||
function checkStatus(res) {
|
function checkStatus(res) {
|
||||||
if (res.status < 200 || res.status >= 400) {
|
if (res.status < 200 || res.status >= 400) {
|
||||||
throw new Error(`Something went wrong (Status ${res.status}) - I do feel very sorry!`);
|
throw new Error(`Something went wrong (Status ${res.status}) - I do feel very sorry!`)
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
export function generatePdf(state){
|
export function generatePdf(state) {
|
||||||
const options = {
|
const options = {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json',
|
||||||
},
|
},
|
||||||
body: JSON.stringify(state)
|
body: JSON.stringify(state),
|
||||||
};
|
}
|
||||||
|
|
||||||
return fetch('/api/pdf/generate/brief', options)
|
return fetch('/api/pdf/generate/brief', options)
|
||||||
.then(checkStatus)
|
.then(checkStatus)
|
||||||
.then(res => res.json());
|
.then((res) => res.json())
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getLatest() {
|
export function getLatest() {
|
||||||
return fetch('/api/pdf/latest')
|
return fetch('/api/pdf/latest')
|
||||||
.then(checkStatus)
|
.then(checkStatus)
|
||||||
.then(res => res.json());
|
.then((res) => res.json())
|
||||||
}
|
}
|
||||||
|
|
||||||
export function removeLatest(item) {
|
export function removeLatest(item) {
|
||||||
return fetch(`/api/pdf/latest/${item.id}`, {method: 'DELETE'})
|
return fetch(`/api/pdf/latest/${item.id}`, { method: 'DELETE' }).then(checkStatus)
|
||||||
.then(checkStatus);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,6 @@
|
|||||||
import React from 'react';
|
import React from 'react'
|
||||||
import ReactDOM from 'react-dom';
|
import ReactDOM from 'react-dom'
|
||||||
import App from './App';
|
import App from './App'
|
||||||
import './index.css';
|
import './index.css'
|
||||||
|
|
||||||
ReactDOM.render(
|
ReactDOM.render(<App />, document.getElementById('root'))
|
||||||
<App />,
|
|
||||||
document.getElementById('root')
|
|
||||||
);
|
|
||||||
|
|||||||
@@ -2,50 +2,49 @@ import { mkdir, writeFile } from 'fs'
|
|||||||
import { spawn } from 'child_process'
|
import { spawn } from 'child_process'
|
||||||
import { v1 as uuidv1 } from 'uuid'
|
import { v1 as uuidv1 } from 'uuid'
|
||||||
|
|
||||||
import { getDirPath, getDocPath } from './utils';
|
import { getDirPath, getDocPath } from './utils'
|
||||||
|
|
||||||
|
|
||||||
function copyToTemp(id: string, texDocument: string): Promise<string> {
|
function copyToTemp(id: string, texDocument: string): Promise<string> {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const dirPath = getDirPath(id);
|
const dirPath = getDirPath(id)
|
||||||
|
|
||||||
mkdir(dirPath, (err) => {
|
mkdir(dirPath, (err) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
reject(err);
|
reject(err)
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const docPath = getDocPath(id);
|
const docPath = getDocPath(id)
|
||||||
writeFile(docPath, texDocument, (err) => {
|
writeFile(docPath, texDocument, (err) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
reject(err);
|
reject(err)
|
||||||
}
|
}
|
||||||
resolve(id);
|
resolve(id)
|
||||||
});
|
})
|
||||||
});
|
})
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function generateDoc(id: string) {
|
function generateDoc(id: string) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const pdflatex = spawn('pdflatex', ['-interaction', 'nonstopmode', getDocPath(id)], { cwd: getDirPath(id) });
|
const pdflatex = spawn('pdflatex', ['-interaction', 'nonstopmode', getDocPath(id)], { cwd: getDirPath(id) })
|
||||||
pdflatex.stderr.on('data', (data) => {
|
pdflatex.stderr.on('data', (data) => {
|
||||||
console.error('onData', data);
|
console.error('onData', data)
|
||||||
});
|
})
|
||||||
|
|
||||||
pdflatex.on('close', (code) => {
|
pdflatex.on('close', (code) => {
|
||||||
if (code > 0) {
|
if (code > 0) {
|
||||||
reject(`pdflatex returned with code ${code}`);
|
reject(`pdflatex returned with code ${code}`)
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
console.log(`PDF ${id} generated`);
|
console.log(`PDF ${id} generated`)
|
||||||
resolve(id);
|
resolve(id)
|
||||||
});
|
})
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function(texDocument: string) {
|
export default async function (texDocument: string) {
|
||||||
const id = uuidv1();
|
const id = uuidv1()
|
||||||
return copyToTemp(id, texDocument)
|
const id_2 = await copyToTemp(id, texDocument)
|
||||||
.then(generateDoc);
|
return generateDoc(id_2)
|
||||||
};
|
}
|
||||||
|
|||||||
16
lib/store.ts
16
lib/store.ts
@@ -1,14 +1,14 @@
|
|||||||
const storeDir = process.env.JSON_STORE || '/tmp/pdfer-store/';
|
const storeDir = process.env.JSON_STORE || '/tmp/pdfer-store/'
|
||||||
|
|
||||||
import { promisify } from 'util';
|
import { promisify } from 'util'
|
||||||
|
|
||||||
import JsonStore from 'json-fs-store'
|
import JsonStore from 'json-fs-store'
|
||||||
|
|
||||||
const store = JsonStore(storeDir);
|
const store = JsonStore(storeDir)
|
||||||
|
|
||||||
console.log(`using json-store at ${storeDir}`);
|
console.log(`using json-store at ${storeDir}`)
|
||||||
|
|
||||||
export const list = promisify(store.list);
|
export const list = promisify(store.list)
|
||||||
export const load = promisify(store.load);
|
export const load = promisify(store.load)
|
||||||
export const add = promisify(store.add);
|
export const add = promisify(store.add)
|
||||||
export const remove = promisify(store.remove);
|
export const remove = promisify(store.remove)
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
function convertLineBreaks(string) {
|
function convertLineBreaks(string) {
|
||||||
return string.replace(/\n/g, '\\\\');
|
return string.replace(/\n/g, '\\\\')
|
||||||
};
|
}
|
||||||
|
|
||||||
export function brief(options) {
|
export function brief(options) {
|
||||||
|
|
||||||
const {
|
const {
|
||||||
template = 'brief-fam',
|
template = 'brief-fam',
|
||||||
subject = '',
|
subject = '',
|
||||||
@@ -22,7 +21,7 @@ export function brief(options) {
|
|||||||
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}
|
||||||
@@ -56,5 +55,5 @@ export function brief(options) {
|
|||||||
%\\encl{${enclosing}}
|
%\\encl{${enclosing}}
|
||||||
|
|
||||||
\\end{letter}
|
\\end{letter}
|
||||||
\\end{document}`;
|
\\end{document}`
|
||||||
};
|
}
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
import path from 'path';
|
import path from 'path'
|
||||||
|
|
||||||
export function getDirPath(id) {
|
export function getDirPath(id) {
|
||||||
return `/tmp/pdfer-${id}`;
|
return `/tmp/pdfer-${id}`
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getDocPath(id) {
|
export function getDocPath(id) {
|
||||||
return path.join(getDirPath(id), 'doc.tex');
|
return path.join(getDirPath(id), 'doc.tex')
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getPdfPath(id) {
|
export function getPdfPath(id) {
|
||||||
return path.join(getDirPath(id), 'doc.pdf');
|
return path.join(getDirPath(id), 'doc.pdf')
|
||||||
}
|
}
|
||||||
|
|||||||
4
package-lock.json
generated
4
package-lock.json
generated
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "with-typescript",
|
"name": "pdfer",
|
||||||
"version": "1.0.0",
|
"version": "2.0.0",
|
||||||
"lockfileVersion": 1,
|
"lockfileVersion": 1,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|||||||
@@ -5,7 +5,8 @@
|
|||||||
"dev": "next",
|
"dev": "next",
|
||||||
"build": "next build",
|
"build": "next build",
|
||||||
"start": "next start",
|
"start": "next start",
|
||||||
"type-check": "tsc"
|
"type-check": "tsc",
|
||||||
|
"format": "prettier --write **/*.{ts,tsx,json}"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"json-fs-store": "^1.0.1",
|
"json-fs-store": "^1.0.1",
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import App from '../components/App'
|
|||||||
|
|
||||||
const IndexPage = () => (
|
const IndexPage = () => (
|
||||||
<Layout title="Home | Next.js + TypeScript Example">
|
<Layout title="Home | Next.js + TypeScript Example">
|
||||||
<App/>
|
<App />
|
||||||
</Layout>
|
</Layout>
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
function convertLineBreaks(string) {
|
function convertLineBreaks(string) {
|
||||||
return string.replace(/\n/g, '\\\\');
|
return string.replace(/\n/g, '\\\\')
|
||||||
};
|
}
|
||||||
|
|
||||||
export default (options) => {
|
export default (options) => {
|
||||||
|
|
||||||
const {
|
const {
|
||||||
template = 'brief-fam',
|
template = 'brief-fam',
|
||||||
subject = '',
|
subject = '',
|
||||||
@@ -22,7 +21,7 @@ export default (options) => {
|
|||||||
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}
|
||||||
@@ -56,5 +55,5 @@ export default (options) => {
|
|||||||
%\\encl{${enclosing}}
|
%\\encl{${enclosing}}
|
||||||
|
|
||||||
\\end{letter}
|
\\end{letter}
|
||||||
\\end{document}`;
|
\\end{document}`
|
||||||
};
|
}
|
||||||
Reference in New Issue
Block a user