Skip to content

Commit 7919ba1

Browse files
authored
Send emails with PDF attachments (#9)
* Change text * SMTP config * Read for email edit * Ready for send mails * Tag subject & body * Send success * Refactor mail merge * Bump version
1 parent 0f08a29 commit 7919ba1

File tree

17 files changed

+1101
-190
lines changed

17 files changed

+1101
-190
lines changed

.erb/assets/demo.png

26.2 KB
Loading

.erb/scripts/Notarize.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
exports.default = async function notarizeMacos(context) {
2-
console.warn('Skipping notarizing step. Packaging is not running in CI');
2+
console.warn('Skipping notarizing step.');
33
return;
44
};

README.md

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
[![Test](https://github.com/plainlab/plainmerge/actions/workflows/test.yml/badge.svg)](https://github.com/plainlab/plainmerge/actions/workflows/test.yml)
2-
![GitHub release (latest SemVer)](https://img.shields.io/github/v/release/plainlab/plainmerge)
2+
[![Release](https://img.shields.io/github/v/release/plainlab/plainmerge)](https://github.com/plainlab/plainmerge/releases)
33

44
# PlainMerge - An offline PDF mail merger
55

66
![PlainMerge](./.erb/assets/plainmerge.png)
77

8-
98
## What is this?
109

1110
Imagine you want to fill a PDF form for 100 employees with a specific name and address
@@ -21,12 +20,13 @@ You got 100 different PDFs for each employee now.
2120

2221
## Features
2322

24-
- Drag & drop fields to customize PDF template
25-
- Support native PDF forms
26-
- Edit multiple-pages PDFs
27-
- Support `.xlsx`, `.xls` and `.ods` Excel files
28-
- Cross-platform: macOS, Windows, Linux
29-
- Work offline
23+
- [x] Drag & drop fields to customize PDF template
24+
- [x] Support native PDF forms
25+
- [x] Support multiple-pages PDFs
26+
- [x] Support `.xlsx`, `.xls` and `.ods` Excel files
27+
- [x] Send out emails with PDF attachments
28+
- [x] Cross-platform: macOS, Windows, Linux
29+
- [x] Work offline
3030

3131
## Demo
3232

package.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,7 @@
172172
"@types/history": "4.7.6",
173173
"@types/jest": "^26.0.15",
174174
"@types/node": "14.14.10",
175+
"@types/qs": "^6.9.7",
175176
"@types/react": "^16.9.44",
176177
"@types/react-color": "^3.0.5",
177178
"@types/react-dom": "^16.9.9",
@@ -180,6 +181,7 @@
180181
"@types/react-router-dom": "^5.1.6",
181182
"@types/react-test-renderer": "^16.9.3",
182183
"@types/webpack-env": "^1.15.2",
184+
"@types/yaireo__tagify": "^4.7.0",
183185
"@typescript-eslint/eslint-plugin": "^4.8.1",
184186
"@typescript-eslint/parser": "^4.8.1",
185187
"autoprefixer": "^10.3.1",
@@ -252,14 +254,18 @@
252254
"@fortawesome/free-regular-svg-icons": "^5.15.3",
253255
"@fortawesome/free-solid-svg-icons": "^5.15.3",
254256
"@fortawesome/react-fontawesome": "^0.1.14",
257+
"@yaireo/tagify": "^4.7.2",
255258
"caniuse-lite": "^1.0.30001246",
256259
"electron-debug": "^3.1.0",
257260
"electron-log": "^4.2.4",
261+
"electron-store": "^8.0.1",
258262
"electron-updater": "^4.3.4",
259263
"glob": "^7.1.7",
260264
"history": "^5.0.0",
261265
"jsqr": "^1.4.0",
266+
"nodemailer": "^6.6.3",
262267
"pdf-lib": "^1.16.0",
268+
"qs": "^6.10.1",
263269
"react": "^17.0.1",
264270
"react-color": "^2.19.3",
265271
"react-dom": "^17.0.1",

src/App.global.css

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
@import '@yaireo/tagify/dist/tagify.css';
2+
13
@tailwind base;
24
@tailwind components;
35
@tailwind utilities;
@@ -11,15 +13,22 @@
1113
@apply outline-none hover:opacity-80 active:text-gray-300 active:outline-none focus:outline-none;
1214
}
1315

14-
input[type='radio'] {
15-
@apply focus:outline-none;
16+
.tagify {
17+
@apply rounded focus:ring-blue-500 focus:outline-none focus:ring-2 focus:ring-inset border bg-white;
1618
}
1719

18-
input {
20+
input[type='radio'] {
1921
@apply focus:outline-none;
2022
}
2123

24+
input[type='text'],
25+
input[type='number'],
26+
input[type='password'],
2227
textarea {
23-
@apply rounded focus:ring-blue-500 focus:outline-none focus:ring-2 focus:ring-inset;
28+
@apply rounded focus:ring-blue-500 focus:outline-none focus:ring-2 focus:ring-inset border py-1 px-2;
29+
}
30+
31+
select {
32+
@apply rounded outline-none active:outline-none focus:ring-2 focus:outline-none focus:ring-blue-500 border py-1 px-2;
2433
}
2534
}

src/App.tsx

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,28 @@
11
import React from 'react';
2-
import {
3-
BrowserRouter as Router,
4-
Switch,
5-
Route,
6-
Redirect,
7-
} from 'react-router-dom';
2+
import { BrowserRouter as Router, Switch, Route } from 'react-router-dom';
3+
import qs from 'qs';
84
import Main from './components/Main';
95
import './App.global.css';
106
import './helpers/fontAwesome';
7+
import MailMerge from './components/merge/MailMerge';
118

129
export default function App() {
1310
return (
1411
<Router>
1512
<Switch>
16-
<Route path="/" component={Main} />
13+
<Route
14+
path="*"
15+
render={(props) => {
16+
const { search } = props.location;
17+
const so = qs.parse(search.slice(search.lastIndexOf('?') + 1));
18+
return so.page === 'merge' ? (
19+
<MailMerge configPath={decodeURIComponent(so.config as string)} />
20+
) : (
21+
<Main />
22+
);
23+
}}
24+
/>
1725
</Switch>
18-
<Redirect from="*" to="/new" />
1926
</Router>
2027
);
2128
}

src/components/Main.tsx

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
import React from 'react';
2-
import { NavLink, Route } from 'react-router-dom';
1+
import React, { useEffect } from 'react';
2+
import { NavLink, Route, useHistory, useLocation } from 'react-router-dom';
33
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
44
import { Helmet } from 'react-helmet';
55

66
import MergeList from './merge/MergeList';
77
import MergeNew from './merge/MergeNew';
8+
import Config from './email/Config';
89

910
const allRoutes = [
1011
{
@@ -14,14 +15,29 @@ const allRoutes = [
1415
Component: MergeNew,
1516
},
1617
{
17-
icon: <FontAwesomeIcon icon="list" />,
18+
icon: <FontAwesomeIcon icon="history" />,
1819
path: '/list',
1920
name: 'Mail merge list',
2021
Component: MergeList,
2122
},
23+
{
24+
icon: <FontAwesomeIcon icon="cog" />,
25+
path: '/config',
26+
name: 'Configuration',
27+
Component: Config,
28+
},
2229
];
2330

2431
const Main = () => {
32+
const history = useHistory();
33+
const location = useLocation();
34+
35+
useEffect(() => {
36+
if (location.pathname.endsWith('index.html')) {
37+
history.push('/new');
38+
}
39+
}, []);
40+
2541
return (
2642
<div className="absolute inset-0 flex">
2743
{/* Left sidebar */}

0 commit comments

Comments
 (0)