Now a simple re-frame app
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -8,3 +8,5 @@ pom.xml.asc
|
|||||||
*.class
|
*.class
|
||||||
/.lein-*
|
/.lein-*
|
||||||
/.nrepl-port
|
/.nrepl-port
|
||||||
|
/resources/public/js/compiled
|
||||||
|
*.log
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
FROM tomcat:9.0-jre8-alpine
|
FROM openjdk:8-jre-alpine
|
||||||
RUN 'apk add poppler-utils'
|
RUN apk update
|
||||||
COPY target/auto-ap.war /usr/local/tomcat
|
RUN apk add poppler
|
||||||
|
RUN apk add poppler-utils
|
||||||
|
COPY target/auto-ap-0.1.0-SNAPSHOT-standalone.jar /usr/local/
|
||||||
|
CMD java -jar /usr/local/auto-ap-0.1.0-SNAPSHOT-standalone.jar
|
||||||
|
|||||||
68
project.clj
68
project.clj
@@ -3,11 +3,71 @@
|
|||||||
:url "http://example.com/FIXME"
|
:url "http://example.com/FIXME"
|
||||||
:min-lein-version "2.0.0"
|
:min-lein-version "2.0.0"
|
||||||
:dependencies [[org.clojure/clojure "1.8.0"]
|
:dependencies [[org.clojure/clojure "1.8.0"]
|
||||||
|
[org.clojure/clojurescript "1.9.908"]
|
||||||
|
[reagent "0.7.0"]
|
||||||
|
[re-frame "0.10.2"]
|
||||||
[compojure "1.6.0"]
|
[compojure "1.6.0"]
|
||||||
|
[secretary "1.2.3"]
|
||||||
[ring/ring-defaults "0.2.1"]
|
[ring/ring-defaults "0.2.1"]
|
||||||
[ring/ring-json "0.4.0"]]
|
[ring/ring-json "0.4.0"]
|
||||||
:plugins [[lein-ring "0.9.7"]]
|
[ring "1.4.0"]
|
||||||
|
[yogthos/config "0.8"]]
|
||||||
|
:plugins [[lein-ring "0.9.7"]
|
||||||
|
[lein-cljsbuild "1.1.5"]]
|
||||||
|
:clean-targets ^{:protect false} ["resources/public/js/compiled" "target"]
|
||||||
:ring {:handler auto-ap.handler/app}
|
:ring {:handler auto-ap.handler/app}
|
||||||
|
:source-paths ["src/clj"]
|
||||||
|
|
||||||
|
:figwheel {:css-dirs ["resources/public/css"]
|
||||||
|
:ring-handler auto-ap.handler/app}
|
||||||
|
|
||||||
|
:aliases {"dev" ["do" "clean"
|
||||||
|
["pdo" ["figwheel" "dev"]]]
|
||||||
|
"build" ["do" "clean"
|
||||||
|
["cljsbuild" "once" "min"]]}
|
||||||
|
|
||||||
:profiles
|
:profiles
|
||||||
{:dev {:dependencies [[javax.servlet/servlet-api "2.5"]
|
{:dev
|
||||||
[ring/ring-mock "0.3.0"]]}})
|
{:dependencies [[binaryage/devtools "0.9.4"]
|
||||||
|
[javax.servlet/servlet-api "2.5"]
|
||||||
|
[figwheel-sidecar "0.5.13"]
|
||||||
|
[com.cemerick/piggieback "0.2.2"]]
|
||||||
|
|
||||||
|
:plugins [[lein-figwheel "0.5.13"]
|
||||||
|
[lein-pdo "0.1.1"]]}}
|
||||||
|
|
||||||
|
:cljsbuild
|
||||||
|
{:builds
|
||||||
|
[{:id "dev"
|
||||||
|
:source-paths ["src/cljs"]
|
||||||
|
:figwheel {:on-jsload "auto-ap.core/mount-root"}
|
||||||
|
:compiler {:main auto-ap.core
|
||||||
|
:output-to "resources/public/js/compiled/app.js"
|
||||||
|
:output-dir "resources/public/js/compiled/out"
|
||||||
|
:asset-path "js/compiled/out"
|
||||||
|
:source-map-timestamp true
|
||||||
|
:preloads [devtools.preload]
|
||||||
|
:external-config {:devtools/config {:features-to-install :all}}
|
||||||
|
}}
|
||||||
|
|
||||||
|
{:id "min"
|
||||||
|
:source-paths ["src/cljs"]
|
||||||
|
:jar true
|
||||||
|
:compiler {:main auto-ap.core
|
||||||
|
:output-to "resources/public/js/compiled/app.js"
|
||||||
|
:optimizations :advanced
|
||||||
|
:closure-defines {goog.DEBUG false}
|
||||||
|
:pretty-print false}}
|
||||||
|
|
||||||
|
|
||||||
|
]}
|
||||||
|
|
||||||
|
:main auto-ap.server
|
||||||
|
|
||||||
|
:aot [auto-ap.server]
|
||||||
|
|
||||||
|
:uberjar-name "auto-ap.jar"
|
||||||
|
|
||||||
|
#_#_:prep-tasks [["cljsbuild" "once" "min"]"compile"])
|
||||||
|
|
||||||
|
;;
|
||||||
|
|||||||
@@ -1,37 +1,331 @@
|
|||||||
<!doctype html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<script src="https://cdn.jsdelivr.net/npm/dropzone@5.2.0/dist/dropzone.min.js"></script>
|
<meta charset="utf-8">
|
||||||
<script src="http://code.jquery.com/jquery-3.2.1.min.js" integrity="sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4=" crossorigin="anonymous"></script>
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.6.1/css/bulma.css" />
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<style>.dz-error-mark { display:none} .dz-details {display:none}
|
<title>Auto AP</title>
|
||||||
form { border: 3px solid lightgray; padding: 25px; width: 100%;}
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css" integrity="sha256-eZrrJcwDc/3uDhsdt61sL2oOBY362qM3lon1gyExkL0=" crossorigin="anonymous" />
|
||||||
.dz-success-mark {display:none} </style>
|
<link href="https://fonts.googleapis.com/css?family=Open+Sans:300,400,700" rel="stylesheet">
|
||||||
|
<script src="https://cdn.auth0.com/js/lock/10.24/lock.min.js"></script>
|
||||||
</head>
|
<!-- Bulma Version 0.6.0 -->
|
||||||
<body>
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.6.0/css/bulma.min.css" integrity="sha256-HEtF7HLJZSC3Le1HcsWbz1hDYFPZCqDhZa9QsCgVUdw=" crossorigin="anonymous" />
|
||||||
<div id="app" class="container">
|
|
||||||
<h1>Invoice Parsing Demo</h1>
|
|
||||||
<form action="/pdf-upload" id="my-dropzone">
|
|
||||||
<h3>Drop invoice pdfs here</h3>
|
|
||||||
<input type="file" name="file" style="display:none"/>
|
|
||||||
</form>
|
|
||||||
<h2 style="display:none">Found invoices:</h2>
|
|
||||||
<ul>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.dz-error-mark { display:none} .dz-details {display:none}
|
||||||
|
.dz-success-mark {display:none}
|
||||||
|
.dz-image {display:none}
|
||||||
|
form { width: 100% }
|
||||||
|
|
||||||
|
html,body {
|
||||||
|
font-family: 'Open Sans', serif;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 1.5;
|
||||||
|
height: 100%;
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
.left-nav {
|
||||||
|
width: 300px;
|
||||||
|
}
|
||||||
|
.nav.is-dark {
|
||||||
|
background-color: #232B2D;
|
||||||
|
color: #F6F7F7;
|
||||||
|
}
|
||||||
|
.nav.is-dark .nav-item a, .nav.is-dark a.nav-item {
|
||||||
|
color: #F6F7F7;
|
||||||
|
}
|
||||||
|
.nav.is-dark .nav-item a.button.is-default {
|
||||||
|
color: #F6F7F7;
|
||||||
|
background-color: transparent;
|
||||||
|
border-width: 2px;
|
||||||
|
}
|
||||||
|
.nav.menu {
|
||||||
|
border-bottom: 1px solid #e1e1e1;
|
||||||
|
}
|
||||||
|
.nav.menu .nav-item .icon-btn {
|
||||||
|
border: 3px solid #B7C6C9;
|
||||||
|
border-radius: 90px;
|
||||||
|
padding: 5px 7px;
|
||||||
|
color: #B7C6C9;
|
||||||
|
}
|
||||||
|
.nav.menu .nav-item.is-active .icon-btn {
|
||||||
|
color: #2EB398;
|
||||||
|
border: 3px solid #2EB398;
|
||||||
|
}
|
||||||
|
.nav.menu .nav-item .icon-btn .fa {
|
||||||
|
font-size: 20px;
|
||||||
|
color: #B7C6C9;
|
||||||
|
}
|
||||||
|
.nav.menu .nav-item.is-active .icon-btn .fa {
|
||||||
|
color: #2EB398;
|
||||||
|
}
|
||||||
|
.aside {
|
||||||
|
display:block;
|
||||||
|
background-color: #F9F9F9;
|
||||||
|
border-right: 1px solid #DEDEDE;
|
||||||
|
}
|
||||||
|
.messages {
|
||||||
|
display:block;
|
||||||
|
background-color: #fff;
|
||||||
|
border-right: 1px solid #DEDEDE;
|
||||||
|
}
|
||||||
|
.message {
|
||||||
|
display:block;
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
.aside .compose {
|
||||||
|
height: 95px;
|
||||||
|
margin:0 -10px;
|
||||||
|
padding: 25px 30px;
|
||||||
|
}
|
||||||
|
.aside .compose .button {
|
||||||
|
color: #F6F7F7;
|
||||||
|
}
|
||||||
|
.aside .compose .button .compose {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
.aside .main {
|
||||||
|
padding: 40px;
|
||||||
|
color: #6F7B7E;
|
||||||
|
}
|
||||||
|
.aside .title {
|
||||||
|
color: #6F7B7E;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: bold;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
.aside .main .item {
|
||||||
|
display: block;
|
||||||
|
padding: 10px 0;
|
||||||
|
color: #6F7B7E;
|
||||||
|
}
|
||||||
|
.aside .main .item.active {
|
||||||
|
background-color: #F1F1F1;
|
||||||
|
margin: 0 -50px;
|
||||||
|
padding-left: 50px;
|
||||||
|
}
|
||||||
|
.aside .main .item:active,.aside .main .item:hover {
|
||||||
|
background-color: #F2F2F2;
|
||||||
|
margin: 0 -50px;
|
||||||
|
padding-left: 50px;
|
||||||
|
}
|
||||||
|
.aside .main .icon {
|
||||||
|
font-size: 19px;
|
||||||
|
padding-right: 30px;
|
||||||
|
color: #A0A0A0;
|
||||||
|
}
|
||||||
|
.aside .main .name {
|
||||||
|
font-size: 15px;
|
||||||
|
color: #5D5D5D;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
.messages {
|
||||||
|
padding: 40px 20px;
|
||||||
|
}
|
||||||
|
.message {
|
||||||
|
padding: 40px 20px;
|
||||||
|
}
|
||||||
|
.messages .action-buttons {
|
||||||
|
padding: 0;
|
||||||
|
margin-top: -20px;
|
||||||
|
}
|
||||||
|
.message .action-buttons {
|
||||||
|
padding: 0;
|
||||||
|
margin-top: -5px;
|
||||||
|
}
|
||||||
|
.action-buttons .control.is-grouped {
|
||||||
|
display: inline-block;
|
||||||
|
margin-right: 30px;
|
||||||
|
}
|
||||||
|
.action-buttons .control.is-grouped:last-child {
|
||||||
|
margin-right: 0;
|
||||||
|
}
|
||||||
|
.action-buttons .control.is-grouped .button:first-child {
|
||||||
|
border-radius: 5px 0 0 5px;
|
||||||
|
}
|
||||||
|
.action-buttons .control.is-grouped .button:last-child {
|
||||||
|
border-radius: 0 5px 5px 0;
|
||||||
|
}
|
||||||
|
.action-buttons .control.is-grouped .button {
|
||||||
|
margin-right: -5px;
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
.pg {
|
||||||
|
display: inline-block;
|
||||||
|
top:10px;
|
||||||
|
}
|
||||||
|
.action-buttons .pg .title {
|
||||||
|
display: block;
|
||||||
|
margin-top: 0;
|
||||||
|
padding-top: 0;
|
||||||
|
margin-bottom: 3px;
|
||||||
|
font-size:12px;
|
||||||
|
color: #AAAAA;
|
||||||
|
}
|
||||||
|
.action-buttons .pg a{
|
||||||
|
font-size:12px;
|
||||||
|
color: #AAAAAA;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
.is-grouped .button {
|
||||||
|
background-image: linear-gradient(#F8F8F8, #F1F1F1);
|
||||||
|
}
|
||||||
|
.is-grouped .button .fa {
|
||||||
|
font-size: 15px;
|
||||||
|
color: #AAAAAA;
|
||||||
|
}
|
||||||
|
.inbox-messages .card {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.inbox-messages strong {
|
||||||
|
color: #5D5D5D;
|
||||||
|
}
|
||||||
|
.inbox-messages .msg-check {
|
||||||
|
padding: 0 20px;
|
||||||
|
}
|
||||||
|
.inbox-messages .msg-subject {
|
||||||
|
padding: 10px 0;
|
||||||
|
color: #5D5D5D;
|
||||||
|
}
|
||||||
|
.inbox-messages .msg-attachment {
|
||||||
|
float:right;
|
||||||
|
}
|
||||||
|
.inbox-messages .msg-snippet {
|
||||||
|
padding: 5px 20px 0px 5px;
|
||||||
|
}
|
||||||
|
.inbox-messages .msg-subject .fa {
|
||||||
|
font-size: 14px;
|
||||||
|
padding:3px 0;
|
||||||
|
}
|
||||||
|
.inbox-messages .msg-timestamp {
|
||||||
|
float: right;
|
||||||
|
padding: 0 20px;
|
||||||
|
color: #5D5D5D;
|
||||||
|
}
|
||||||
|
.message-preview .avatar {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
.message-preview .top .address {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 0 20px;
|
||||||
|
}
|
||||||
|
.avatar img {
|
||||||
|
width: 40px;
|
||||||
|
border-radius: 50px;
|
||||||
|
border: 2px solid #999;
|
||||||
|
padding: 2px;
|
||||||
|
}
|
||||||
|
.address .name {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.address .email {
|
||||||
|
font-weight: bold;
|
||||||
|
color: #B6C7D1;
|
||||||
|
}
|
||||||
|
.card.active {
|
||||||
|
background-color:#F5F5F5;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="app">
|
||||||
|
<nav class="navbar has-shadow">
|
||||||
|
<div class="container">
|
||||||
|
<div class="navbar-brand">
|
||||||
|
<a class="navbar-item" href="../">
|
||||||
|
<h1>Auto-ap</h1>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</nav>
|
||||||
|
<div class="has-text-centered hero is-fullheight is-vertically-centered" id="mail-app">
|
||||||
|
<div class="is-vertically-centered">
|
||||||
|
<h1 class="title"><i class="fa fa-spin fa-spinner"></i></h1>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<footer class="footer">
|
||||||
|
<div class="container">
|
||||||
|
<div class="content has-text-centered">
|
||||||
|
<p>
|
||||||
|
<strong>Auto-AP</strong>
|
||||||
|
by <a href="https://github.com/">Integreat</a>.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<a class="icon" href="https://github.com/dansup/bulma-templates">
|
||||||
|
<i class="fa fa-github"></i>
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js" integrity="sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8=" crossorigin="anonymous"></script>
|
||||||
|
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.0.3/vue.min.js" integrity="sha256-5CEXP4Sh+bwJYBngjYYh2TEev9kTDwcjw60jZatTHtY=" crossorigin="anonymous"></script>
|
||||||
|
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/Faker/3.1.0/faker.min.js" integrity="sha256-QHdJObhDO++VITP6S4tMlDHRWMaUOk+s/xWIRgF/YY0=" crossorigin="anonymous"></script>
|
||||||
|
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.15.1/moment.min.js" integrity="sha256-4PIvl58L9q7iwjT654TQJM+C/acEyoG738iL8B8nhXg=" crossorigin="anonymous"></script>
|
||||||
|
|
||||||
|
<script src="http://code.jquery.com/jquery-3.2.1.min.js" integrity="sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4=" crossorigin="anonymous"></script>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/dropzone@5.2.0/dist/dropzone.min.js"></script>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
var myDropzone = new Dropzone("#my-dropzone");
|
/*
|
||||||
myDropzone.on("success", function(file, a) {
|
$(function() {
|
||||||
$("h2").show();
|
var lock = new Auth0Lock(
|
||||||
JSON.parse(a).map(function(x) {
|
"twbXfoLvL0tKTR6GWORoM-ss51wM1zXZ",
|
||||||
|
"app82488100.auth0.com",
|
||||||
|
{
|
||||||
|
rememberLastLogin: false,
|
||||||
|
socialButtonStyle: "big",
|
||||||
|
oidcConformant: true,
|
||||||
|
auth: {
|
||||||
|
audience: "https://app82488100.auth0.com/api/v2/",
|
||||||
|
params: {scope: 'openid email profile'},
|
||||||
|
responseType: "token",
|
||||||
|
redirect: true,
|
||||||
|
redirectUrl: "http://localhost:3000",
|
||||||
|
},
|
||||||
|
languageDictionary: {"title":"Auto AP"},
|
||||||
|
language: "en",
|
||||||
|
theme: {"primaryColor":"#3A99D8"}
|
||||||
|
} );
|
||||||
|
|
||||||
$("ul").append($("<li>").text(x));
|
$(".login").click(function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
lock.show();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
lock.on("authenticated", function(result, other) {
|
||||||
|
console.log(result.accessToken, other);
|
||||||
|
lock.getUserInfo(result.accessToken, function(err, profile) {
|
||||||
|
|
||||||
|
$(".login").text(profile.nickname);
|
||||||
|
console.log(profile);
|
||||||
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
var myDropzone = new Dropzone("#my-dropzone");
|
||||||
|
myDropzone.on("success", function(file, a) {
|
||||||
|
$("h2").show();
|
||||||
|
$(".found-invoices").show();
|
||||||
|
JSON.parse(a).map(function(x) {
|
||||||
|
console.log(x);
|
||||||
|
var tr = $("<tr>");
|
||||||
|
tr.append($("<td>").text(x['customer-identifier']));
|
||||||
|
tr.append($("<td>").text(x['invoice-number']));
|
||||||
|
tr.append($("<td>").text(x['date']));
|
||||||
|
tr.append($("<td>").text(x['total']));
|
||||||
|
$("tbody").append(tr);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
*/
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</div>
|
||||||
|
<script src="js/compiled/app.js"></script>
|
||||||
|
<script>auto_ap.core.init();</script>
|
||||||
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -9,15 +9,18 @@
|
|||||||
[ring.middleware.json :refer [wrap-json-response]]))
|
[ring.middleware.json :refer [wrap-json-response]]))
|
||||||
|
|
||||||
(defroutes app-routes
|
(defroutes app-routes
|
||||||
|
(GET "/hi" [] "hello")
|
||||||
(GET "/" [] (response/resource-response "index.html" {:root "public"}))
|
(GET "/" [] (response/resource-response "index.html" {:root "public"}))
|
||||||
(POST "/pdf-upload"
|
(POST "/pdf-upload"
|
||||||
{{ files "file"} :params :as params}
|
{{ files "file"} :params :as params}
|
||||||
(let [{:keys [filename tempfile]} (second files)]
|
(let [{:keys [filename tempfile]} (second files)]
|
||||||
(io/copy tempfile (io/file "resources" "public" filename))
|
(println tempfile)
|
||||||
(for [{:keys [total date invoice-number customer-identifier]} (parse/parse-file (str "resources/public/" filename))]
|
#_(io/copy tempfile (io/file "resources" "public" filename))
|
||||||
(do
|
(for [{:keys [total date invoice-number customer-identifier]} (parse/parse-file (.getPath tempfile))]
|
||||||
(println (str "An invoice #" invoice-number " on " date " for " total))
|
{"customer-identifier" customer-identifier
|
||||||
(str "An invoice for customer " customer-identifier " #" invoice-number " on " date " for " total )))))
|
"invoice-number" invoice-number
|
||||||
|
"date" date
|
||||||
|
"total" total})))
|
||||||
(route/resources "/")
|
(route/resources "/")
|
||||||
(route/not-found "Not Found"))
|
(route/not-found "Not Found"))
|
||||||
|
|
||||||
9
src/clj/auto_ap/server.clj
Normal file
9
src/clj/auto_ap/server.clj
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
(ns auto-ap.server
|
||||||
|
(:require [auto-ap.handler :refer [app]]
|
||||||
|
[config.core :refer [env]]
|
||||||
|
[ring.adapter.jetty :refer [run-jetty]])
|
||||||
|
(:gen-class))
|
||||||
|
|
||||||
|
(defn -main [& args]
|
||||||
|
(let [port (Integer/parseInt (or (env :port) "3000"))]
|
||||||
|
(run-jetty app {:port port :join? false})))
|
||||||
4
src/cljs/auto_ap/config.cljs
Normal file
4
src/cljs/auto_ap/config.cljs
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
(ns auto-ap.config)
|
||||||
|
|
||||||
|
(def debug?
|
||||||
|
^boolean goog.DEBUG)
|
||||||
23
src/cljs/auto_ap/core.cljs
Normal file
23
src/cljs/auto_ap/core.cljs
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
(ns auto-ap.core
|
||||||
|
(:require [reagent.core :as reagent]
|
||||||
|
[re-frame.core :as re-frame]
|
||||||
|
[auto-ap.events :as events]
|
||||||
|
[auto-ap.views :as views]
|
||||||
|
[auto-ap.config :as config]))
|
||||||
|
|
||||||
|
|
||||||
|
(defn dev-setup []
|
||||||
|
(when config/debug?
|
||||||
|
(enable-console-print!)
|
||||||
|
(println "dev mode")))
|
||||||
|
|
||||||
|
(defn mount-root []
|
||||||
|
(re-frame/clear-subscription-cache!)
|
||||||
|
(reagent/render [views/main-panel]
|
||||||
|
(.getElementById js/document "app")))
|
||||||
|
|
||||||
|
(defn ^:export init []
|
||||||
|
(re-frame/dispatch-sync [::events/initialize-db])
|
||||||
|
(dev-setup)
|
||||||
|
|
||||||
|
(mount-root))
|
||||||
5
src/cljs/auto_ap/db.cljs
Normal file
5
src/cljs/auto_ap/db.cljs
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
(ns auto-ap.db)
|
||||||
|
|
||||||
|
(def default-db
|
||||||
|
{:company {:name "Campbell brewery"}
|
||||||
|
:invoices #{}})
|
||||||
13
src/cljs/auto_ap/events.cljs
Normal file
13
src/cljs/auto_ap/events.cljs
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
(ns auto-ap.events
|
||||||
|
(:require [re-frame.core :as re-frame]
|
||||||
|
[auto-ap.db :as db]))
|
||||||
|
|
||||||
|
(re-frame/reg-event-db
|
||||||
|
::initialize-db
|
||||||
|
(fn [_ _]
|
||||||
|
db/default-db))
|
||||||
|
|
||||||
|
(re-frame/reg-event-db
|
||||||
|
::imported-invoices
|
||||||
|
(fn [db [_ new-invoices]]
|
||||||
|
(update-in db [:invoices] into new-invoices)))
|
||||||
13
src/cljs/auto_ap/subs.cljs
Normal file
13
src/cljs/auto_ap/subs.cljs
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
(ns auto-ap.subs
|
||||||
|
(:require [re-frame.core :as re-frame]))
|
||||||
|
|
||||||
|
(re-frame/reg-sub
|
||||||
|
::name
|
||||||
|
(fn [db]
|
||||||
|
(:name (:company db))))
|
||||||
|
|
||||||
|
|
||||||
|
(re-frame/reg-sub
|
||||||
|
::invoices
|
||||||
|
(fn [db]
|
||||||
|
(:invoices db)))
|
||||||
149
src/cljs/auto_ap/views.cljs
Normal file
149
src/cljs/auto_ap/views.cljs
Normal file
@@ -0,0 +1,149 @@
|
|||||||
|
(ns auto-ap.views
|
||||||
|
(:require [re-frame.core :as re-frame]
|
||||||
|
[reagent.core :as reagent]
|
||||||
|
[auto-ap.subs :as subs]
|
||||||
|
[auto-ap.events :as events]))
|
||||||
|
|
||||||
|
(def dropzone
|
||||||
|
(with-meta
|
||||||
|
(fn []
|
||||||
|
[:form {:action "/pdf-upload" :class ".dropzone"}
|
||||||
|
[:div {:class "card"}
|
||||||
|
[:div {:class "card-header"}
|
||||||
|
[:span {:class "card-header-title"} "Upload Invoices"]]
|
||||||
|
[:div {:class "card-content"}
|
||||||
|
[:span {:class "icon"}
|
||||||
|
[:i {:class "fa fa-cloud-download"}]]
|
||||||
|
"Drop invoice pdfs here"
|
||||||
|
[:input {:type "file", :name "file", :style {:display "none"}}]]]])
|
||||||
|
{:component-did-mount (fn [this]
|
||||||
|
(-> (js/$ (reagent/dom-node this))
|
||||||
|
(.dropzone (clj->js {:init (fn []
|
||||||
|
(this-as t
|
||||||
|
(.on t "success" (fn [_ files]
|
||||||
|
(re-frame/dispatch [::events/imported-invoices (js->clj (.parse js/JSON files))])
|
||||||
|
))))
|
||||||
|
:url "/pdf-upload"}))))})
|
||||||
|
)
|
||||||
|
|
||||||
|
(defn main-panel []
|
||||||
|
(let [name (re-frame/subscribe [::subs/name])
|
||||||
|
invoices (re-frame/subscribe [::subs/invoices])]
|
||||||
|
(println name)
|
||||||
|
[:div
|
||||||
|
[:nav {:class "navbar has-shadow"}
|
||||||
|
[:div {:class "container"}
|
||||||
|
[:div {:class "navbar-brand"}
|
||||||
|
[:a {:class "navbar-item", :href "../"}
|
||||||
|
[:h1 (str "Auto-ap - " @name)]]
|
||||||
|
[:div {:class "navbar-burger burger", :data-target "navMenu"}
|
||||||
|
[:span]
|
||||||
|
[:span]
|
||||||
|
[:span]]]
|
||||||
|
[:div {:id "navMenu", :class "navbar-menu"}
|
||||||
|
[:div {:class "navbar-end"}
|
||||||
|
[:div {:class "navbar-item has-dropdown is-active"}
|
||||||
|
[:a {:class "navbar-link login"} ]
|
||||||
|
[:div {:class "navbar-dropdown", :style {:display "none"}}
|
||||||
|
[:a {:class "navbar-item"} ]
|
||||||
|
[:a {:class "navbar-item"} ]
|
||||||
|
[:a {:class "navbar-item"} ]
|
||||||
|
[:hr {:class "navbar-divider"}]
|
||||||
|
[:div {:class "navbar-item"} ]]]]]]]
|
||||||
|
[:div {:class "columns", :id "mail-app"}
|
||||||
|
[:aside {:class "column is-narrow aside hero is-fullheight"}
|
||||||
|
[:div.left-nav
|
||||||
|
[:div {:class "compose has-text-centered"}
|
||||||
|
[:a {:class "button is-danger is-block is-bold"}
|
||||||
|
[:span {:class "compose"} "New Invoice"]]]
|
||||||
|
[:div {:class "main"}
|
||||||
|
[:a {:href "#", :class "item active"}
|
||||||
|
[:span {:class "icon"}
|
||||||
|
[:i {:class "fa fa-inbox"}]]
|
||||||
|
[:span {:class "name"} "Upload\n Invoices"]]
|
||||||
|
[:a {:href "#", :class "item"}
|
||||||
|
[:span {:class "icon"}
|
||||||
|
[:i {:class "fa fa-star"}]]
|
||||||
|
[:span {:class "name"} "Unpaid Invoices"]]
|
||||||
|
[:a {:href "#", :class "item"}
|
||||||
|
[:span {:class "icon"}
|
||||||
|
[:i {:class "fa fa-envelope-o"}]]
|
||||||
|
[:span {:class "name"} "Paid Invoices"]]]]]
|
||||||
|
[:div {:class "column messages hero is-fullheight", :id "message-feed"}
|
||||||
|
[:div {:class "inbox-messages"}
|
||||||
|
[dropzone]
|
||||||
|
|
||||||
|
[:div {:class "section"}]
|
||||||
|
[:div {:class "card found-invoices", :style {:display (if (seq @invoices) "block" "none")}}
|
||||||
|
[:div {:class "card-header"}
|
||||||
|
[:span {:class "card-header-title"} "Found Invoices"]]
|
||||||
|
[:div {:class "card-content"}
|
||||||
|
[:table {:class "table", :style {:width "100%"}}
|
||||||
|
[:thead
|
||||||
|
[:tr
|
||||||
|
[:th "Customer"]
|
||||||
|
[:th "Invoice #"]
|
||||||
|
[:th "Date"]
|
||||||
|
[:th "Amount"]]]
|
||||||
|
[:tbody (for [{:strs [customer-identifier invoice-number date total]} @invoices]
|
||||||
|
^{:key (str customer-identifier "-" invoice-number)}
|
||||||
|
[:tr
|
||||||
|
[:td customer-identifier]
|
||||||
|
[:td invoice-number]
|
||||||
|
[:td date]
|
||||||
|
[:td total]])]]]]]]]
|
||||||
|
[:footer {:class "footer"}
|
||||||
|
[:div {:class "container"}
|
||||||
|
[:div {:class "content has-text-centered"}
|
||||||
|
[:p
|
||||||
|
[:strong "Auto-AP"]"by "
|
||||||
|
[:a {:href "https://github.com/"} "Integreat"]"."]
|
||||||
|
[:p
|
||||||
|
[:a {:class "icon", :href "https://github.com/dansup/bulma-templates"}
|
||||||
|
[:i {:class "fa fa-github"}]]]]]]]))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
;;
|
||||||
|
;; <nav class="navbar has-shadow">
|
||||||
|
;; <div class="container">
|
||||||
|
;; <div class="navbar-brand">
|
||||||
|
;; <a class="navbar-item" href="../">
|
||||||
|
;; <h1>Auto-ap</h1>
|
||||||
|
;; </a>
|
||||||
|
;;
|
||||||
|
;; <div class="navbar-burger burger" data-target="navMenu">
|
||||||
|
;; <span></span>
|
||||||
|
;; <span></span>
|
||||||
|
;; <span></span>
|
||||||
|
;; </div>
|
||||||
|
;; </div>
|
||||||
|
;;
|
||||||
|
;; <div id="navMenu" class="navbar-menu">
|
||||||
|
;; <div class="navbar-end">
|
||||||
|
;; <div class="navbar-item has-dropdown is-active">
|
||||||
|
;; <a class="navbar-link login">
|
||||||
|
;; Login
|
||||||
|
;; </a>
|
||||||
|
;;
|
||||||
|
;; <div class="navbar-dropdown" style="display:none">
|
||||||
|
;; <a class="navbar-item">
|
||||||
|
;; Dashboard
|
||||||
|
;; </a>
|
||||||
|
;; <a class="navbar-item">
|
||||||
|
;; Profile
|
||||||
|
;; </a>
|
||||||
|
;; <a class="navbar-item">
|
||||||
|
;; Settings
|
||||||
|
;; </a>
|
||||||
|
;; <hr class="navbar-divider">
|
||||||
|
;; <div class="navbar-item">
|
||||||
|
;; Logout
|
||||||
|
;; </div>
|
||||||
|
;; </div>
|
||||||
|
;; </div>
|
||||||
|
;; </div>
|
||||||
|
;; </div>
|
||||||
|
;; </div>
|
||||||
|
;; </nav>
|
||||||
|
|
||||||
Reference in New Issue
Block a user