Mercurial > titip
comparison index.html @ 16:1f999668080f
Migrate to eu central bank data and use local jquery
| author | nanaya <me@nanaya.pro> |
|---|---|
| date | Fri, 08 Jun 2018 22:11:01 +0900 |
| parents | 72ee98d173a4 |
| children | aef027838046 |
comparison
equal
deleted
inserted
replaced
| 15:4391020b8ebd | 16:1f999668080f |
|---|---|
| 1 <!doctype html> | 1 <!doctype html> |
| 2 <head> | 2 <head> |
| 3 <title>Kalkulator</title> | 3 <title>Kalkulator</title> |
| 4 <meta name="viewport" content="width=device-width"> | 4 <meta name="viewport" content="width=device-width"> |
| 5 <meta http-equiv="Content-Type" content="text/html;charset=utf-8"> | 5 <meta http-equiv="Content-Type" content="text/html;charset=utf-8"> |
| 6 <style type="text/css"> | 6 <style type="text/css"> |
| 7 body { | 7 * { |
| 8 font-size: 12px; | 8 box-sizing: border-box; |
| 9 font-family: Helvetica Neue, Helvetica, Arial, sans-serif; | 9 } |
| 10 line-height: 1.5; | 10 body { |
| 11 margin: 0px; | 11 font-size: 12px; |
| 12 background-color: #eee; | 12 font-family: Arial, sans-serif; |
| 13 } | 13 line-height: 1.5; |
| 14 #content { | 14 margin: 0; |
| 15 width: 100%; | 15 background-color: #eee; |
| 16 min-height: 100vh; | 16 } |
| 17 padding: 10px; | 17 .content { |
| 18 margin: auto; | 18 width: 100%; |
| 19 background-color: #fff; | 19 max-width: 500px; |
| 20 } | 20 min-height: 100vh; |
| 21 @media (min-width: 600px) { | 21 padding: 10px; |
| 22 #content { | 22 margin: auto; |
| 23 width: 500px; | 23 background-color: #fff; |
| 24 } | 24 } |
| 25 } | 25 |
| 26 * { box-sizing: border-box; } | 26 input, button, select, option, .js { font-size: 150%; } |
| 27 ul { padding-left: 20px; } | 27 .input { |
| 28 #n, .js { display: none; } | 28 font-size: 16px; |
| 29 input, button, select, option, .js { font-size: 150%; } | 29 width: 100%; |
| 30 </style> | 30 } |
| 31 | |
| 32 .button { | |
| 33 font-size: 16px; | |
| 34 padding: 5px 10px; | |
| 35 } | |
| 36 | |
| 37 .result { | |
| 38 font-size: 16px; | |
| 39 padding: 10px; | |
| 40 background-color: #eee; | |
| 41 } | |
| 42 | |
| 43 .result__title { | |
| 44 padding: 0; | |
| 45 margin: 0 0 10px; | |
| 46 } | |
| 47 | |
| 48 .result__list { | |
| 49 margin: 0; | |
| 50 } | |
| 51 | |
| 52 .list { | |
| 53 padding-left: 20px; | |
| 54 } | |
| 55 | |
| 56 .u-hidden { | |
| 57 display: none !important; | |
| 58 } | |
| 59 </style> | |
| 60 <script src="jquery-3.3.1.min.js"></script> | |
| 61 | |
| 62 <script> | |
| 63 $(document).ready(function () { | |
| 64 var $loading = $(".js-x-loading"); | |
| 65 var $ok = $(".js-x-ok"); | |
| 66 var $error = $(".js-x-error"); | |
| 67 | |
| 68 var $form = $(".js-x-form"); | |
| 69 var $submit = $(".js-x-submit"); | |
| 70 var $reset = $(".js-x-reset"); | |
| 71 var $input = $(".js-x-input"); | |
| 72 var $rateEu = $(".js-x-rate-eu"); | |
| 73 var $resultEu = $(".js-x-result-eu"); | |
| 74 var $rateBni = $(".js-x-rate-bni"); | |
| 75 var $resultBni = $(".js-x-result-bni"); | |
| 76 var $resultPaypal = $(".js-x-result-paypal"); | |
| 77 | |
| 78 var locks = {}; | |
| 79 var rates = {}; | |
| 80 | |
| 81 var val = function() { | |
| 82 return parseFloat($input.val()); | |
| 83 } | |
| 84 | |
| 85 var lock = function(isLoading) { | |
| 86 if (!isLoading && (locks.eu || locks.bni)) { | |
| 87 return; | |
| 88 } | |
| 89 | |
| 90 show(isLoading ? $loading : null); | |
| 91 $submit.attr("disabled", isLoading); | |
| 92 }; | |
| 93 | |
| 94 var displayResult = function() { | |
| 95 if (rates.eu == null || rates.bni == null) { | |
| 96 return; | |
| 97 } | |
| 98 | |
| 99 var x = val(); | |
| 100 | |
| 101 var resultEu = (Math.ceil(x * 1.07 * rates.eu / 1000) * 1000).toLocaleString(); | |
| 102 | |
| 103 $rateEu.text(rates.eu.toLocaleString()); | |
| 104 $resultEu.text(resultEu); | |
| 105 | |
| 106 var resultBni; | |
| 107 var rateBni; | |
| 108 | |
| 109 if (rates.bni !== 0) { | |
| 110 rateBni = rates.bni.toLocaleString(); | |
| 111 resultBni = (Math.ceil(x * 1.04 * rates.bni / 1000) * 1000 + (25000 * Math.ceil(x / 35000))).toLocaleString(); | |
| 112 } else { | |
| 113 rateBni = "x"; | |
| 114 resultBni = "x"; | |
| 115 }; | |
| 116 | |
| 117 $rateBni.text(rateBni); | |
| 118 $resultBni.text(resultBni); | |
| 119 | |
| 120 $resultPaypal.text((Math.round(x * 1.05)).toLocaleString()); | |
| 121 lock(false); | |
| 122 show($ok); | |
| 123 }; | |
| 124 | |
| 125 var fetchEu = function() { | |
| 126 if (rates.fixer != null) { | |
| 127 return; | |
| 128 } | |
| 129 | |
| 130 lock(true); | |
| 131 locks.fixer = true; | |
| 132 | |
| 133 $.get("eu-daily.xml") | |
| 134 .always(function() { | |
| 135 locks.fixer = false; | |
| 136 lock(false); | |
| 137 }).done(function(data) { | |
| 138 var $data = $(data); | |
| 139 var idrEur = parseFloat($data.find("[currency=IDR]").attr("rate")); | |
| 140 var jpyEur = parseFloat($data.find("[currency=JPY]").attr("rate")); | |
| 141 rates.eu = idrEur / jpyEur; | |
| 142 | |
| 143 displayResult(); | |
| 144 }).fail(function() { | |
| 145 error("connection"); | |
| 146 }); | |
| 147 }; | |
| 148 | |
| 149 var fetchBni = function() { | |
| 150 if (rates.bni != null) { | |
| 151 return; | |
| 152 } | |
| 153 | |
| 154 lock(true); | |
| 155 locks.bni = true; | |
| 156 | |
| 157 $.get("bni-jpyidr.txt") | |
| 158 .always(function() { | |
| 159 locks.bni = false; | |
| 160 lock(false); | |
| 161 }).done(function(data) { | |
| 162 if (data === "") { | |
| 163 rates.bni = 0; | |
| 164 } else { | |
| 165 rates.bni = parseFloat(data); | |
| 166 } | |
| 167 | |
| 168 displayResult(); | |
| 169 }).fail(function() { | |
| 170 error("connection"); | |
| 171 }); | |
| 172 }; | |
| 173 | |
| 174 var error = function(err) { | |
| 175 var message; | |
| 176 | |
| 177 if (err === "connection") { | |
| 178 message = "Koneksi ke server nilai tukar bermasalah."; | |
| 179 } else if (err === "missing") { | |
| 180 message = "Masukkan jumlah."; | |
| 181 } | |
| 182 | |
| 183 $error.text(message); | |
| 184 show($error); | |
| 185 } | |
| 186 | |
| 187 var show = function($el) { | |
| 188 $error.toggleClass("u-hidden", $el !== $error); | |
| 189 $ok.toggleClass("u-hidden", $el !== $ok); | |
| 190 $loading.toggleClass("u-hidden", $el !== $loading); | |
| 191 } | |
| 192 | |
| 193 var action = function(e) { | |
| 194 e.preventDefault(); | |
| 195 | |
| 196 show(); | |
| 197 | |
| 198 if (!isFinite(val())) { | |
| 199 error("missing"); | |
| 200 return; | |
| 201 }; | |
| 202 | |
| 203 fetchEu(); | |
| 204 fetchBni(); | |
| 205 | |
| 206 displayResult(); | |
| 207 }; | |
| 208 | |
| 209 $form.submit(action) | |
| 210 | |
| 211 $reset.click(function() { | |
| 212 $input.focus(); | |
| 213 }); | |
| 214 }); | |
| 215 </script> | |
| 31 </head> | 216 </head> |
| 32 <body> | 217 <body> |
| 33 <div id="content"> | 218 <div class="content"> |
| 34 <h1>Konversi buat nitip</h1> | 219 <h1>Konversi buat nitip</h1> |
| 35 <form> | 220 <form class="js-x-form"> |
| 36 <p> | 221 <label> |
| 37 <label for="x">Jumlah dalam yen:</label> | 222 <p> |
| 38 <br> | 223 Jumlah dalam yen: |
| 39 <input id="x" name="x" type="number" autofocus> | 224 <br> |
| 40 </p> | 225 <input class="input js-x-input" type="number" autofocus> |
| 41 <p> | 226 </p> |
| 42 <button type="submit">Hitung</button> | 227 </label> |
| 43 <button type="reset">Hapus</button> | 228 <p> |
| 44 </p> | 229 <button type="submit" class="button js-x-submit">Hitung</button> |
| 45 </form> | 230 <button type="reset" class="button js-x-reset">Hapus</button> |
| 46 <div class="js" id="loading"> | 231 </p> |
| 47 <p>Memuat data nilai tukar...</p> | 232 </form> |
| 233 | |
| 234 <div class="result js-x-loading u-hidden"> | |
| 235 Memuat data nilai tukar... | |
| 236 </div> | |
| 237 | |
| 238 <div class="result js-x-ok u-hidden"> | |
| 239 <p class="result__title"> | |
| 240 Biaya: | |
| 241 </p> | |
| 242 <ul class="result__list"> | |
| 243 <li> | |
| 244 Bank transfer: | |
| 245 <strong><span class="js-x-result-eu"></span> IDR</strong> | |
| 246 (<span class="js-x-rate-eu"></span> IDR/JPY) | |
| 247 | |
| 248 <li> | |
| 249 Bank transfer (alt): | |
| 250 <strong><span class="js-x-result-bni"></span> IDR</strong> | |
| 251 (<span class="js-x-rate-bni"></span> IDR/JPY) | |
| 252 | |
| 253 <li> | |
| 254 PayPal: | |
| 255 <strong><span class="js-x-result-paypal"></span> JPY</strong> | |
| 256 </ul> | |
| 257 </div> | |
| 258 | |
| 259 <div class="result js-x-error u-hidden"> | |
| 260 </div> | |
| 261 | |
| 262 <hr> | |
| 263 | |
| 264 <ul class="list"> | |
| 265 <li>Ongkir, cukai, dll tidak termasuk. | |
| 266 <li>Berhubung sudah punya timbangan, ongkir (estimasi) bisa dihitung sebelum dikirim. | |
| 267 <li><a href="http://www.post.japanpost.jp/int/charge/list/ems1_en.html">Tabel ongkir EMS</a>. | |
| 268 <li>Perhitungan: | |
| 269 <ul class="list"> | |
| 270 <li>Bank: <code>jumlah × 1.07 × nilai_tukar</code>, dibulatkan ke seribuan terdekat. | |
| 271 <li>Bank (alt): <code>jumlah × 1.04 × nilai_tukar + (25000 * ceil(jumlah / 35000))</code>, dibulatkan ke seribuan terdekat. Rekeningnya sama. | |
| 272 <li>PayPal: <code>jumlah × 1.05</code>, dibulatkan ke satuan terdekat. | |
| 273 </ul> | |
| 274 <li>Jangan lupa memastikan jumlah setelah pajak dan ongkir (lokal). | |
| 275 <li>Data nilai tukar didapat dari <a href="https://www.ecb.europa.eu/stats/policy_and_exchange_rates/euro_reference_exchange_rates/html/index.en.html">Bank Sentral Eropa</a>. | |
| 276 <li>Data nilai tukar "(alt)" didapat dari <a href="http://bni.co.id/informasivalas.aspx">BNI</a>. | |
| 277 </ul> | |
| 48 </div> | 278 </div> |
| 49 <div class="js" id="ok"> | |
| 50 <p> | |
| 51 Biaya: | |
| 52 </p> | |
| 53 <ul> | |
| 54 <li> | |
| 55 Bank transfer: | |
| 56 <span id="result-bank"></span> IDR | |
| 57 (<span id="rate-text"></span> IDR/JPY) | |
| 58 </li> | |
| 59 | |
| 60 <li> | |
| 61 Bank transfer (alt): | |
| 62 <span id="result-bank-bni"></span> IDR | |
| 63 (<span id="rate-text-bni"></span> IDR/JPY) | |
| 64 </li> | |
| 65 | |
| 66 <li> | |
| 67 PayPal: | |
| 68 <span id="result-paypal"></span> JPY | |
| 69 </li> | |
| 70 </ul> | |
| 71 </div> | |
| 72 <div class="js" id="error"> | |
| 73 <p>Koneksi ke server nilai tukar bermasalah.</p> | |
| 74 </div> | |
| 75 | |
| 76 <hr> | |
| 77 <ul> | |
| 78 <li>Ongkir, cukai, dll tidak termasuk.</li> | |
| 79 <li>Berhubung sudah punya timbangan, ongkir (estimasi) bisa dihitung sebelum dikirim.</li> | |
| 80 <li><a href="http://www.post.japanpost.jp/int/charge/list/ems1_en.html">Tabel ongkir EMS</a>.</li> | |
| 81 <li>Perhitungan: | |
| 82 <ul> | |
| 83 <li>Bank: <code>jumlah × 1.07 × nilai_tukar</code>, dibulatkan ke seribuan terdekat.</li> | |
| 84 <li>Bank (alt): <code>jumlah × 1.04 × nilai_tukar + (25000 * ceil(jumlah / 35000))</code>, dibulatkan ke seribuan terdekat. Rekeningnya sama.</li> | |
| 85 <li>PayPal: <code>jumlah × 1.05</code>, dibulatkan ke satuan terdekat.</li> | |
| 86 </ul> | |
| 87 </li> | |
| 88 <li>Jangan lupa memastikan jumlah setelah pajak dan ongkir (lokal).</li> | |
| 89 <li>Data nilai tukar didapat dari layanan <a href="http://fixer.io/">Fixer.io</a>.</li> | |
| 90 <li>Data nilai tukar "(alt)" didapat dari <a href="http://bni.co.id/informasivalas.aspx">BNI</a>.</li> | |
| 91 </ul> | |
| 92 </div> | |
| 93 | |
| 94 <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script> | |
| 95 <script> | |
| 96 var input = function() { return parseFloat($xForm.val()); } | |
| 97 | |
| 98 var $loading = $("#loading"); | |
| 99 var $doButton = $("button[type=submit]"); | |
| 100 var $xForm = $("#x"); | |
| 101 | |
| 102 var locks = {}; | |
| 103 var lock = function(isLoading) { | |
| 104 if (!isLoading && (locks.fixer === true || locks.bni === true)) { return; } | |
| 105 $loading.toggle(isLoading); | |
| 106 $doButton.attr("disabled", isLoading); | |
| 107 }; | |
| 108 | |
| 109 var rates = {}; | |
| 110 | |
| 111 var displayResult = function() { | |
| 112 if (rates.fixer === undefined || rates.bni === undefined) { return; } | |
| 113 var x = input(); | |
| 114 | |
| 115 $("#rate-text").text(rates.fixer.toLocaleString()); | |
| 116 $("#result-bank").text((Math.ceil(x * 1.07 * rates.fixer / 1000) * 1000).toLocaleString()); | |
| 117 | |
| 118 if (rates.bni !== 0) { | |
| 119 $("#rate-text-bni").text(rates.bni.toLocaleString()); | |
| 120 $("#result-bank-bni").text((Math.ceil(x * 1.04 * rates.bni / 1000) * 1000 + (25000 * Math.ceil(x / 35000))).toLocaleString()); | |
| 121 } else { | |
| 122 $("#rate-text-bni").text('x'); | |
| 123 $("#result-bank-bni").text('x'); | |
| 124 }; | |
| 125 | |
| 126 $("#result-paypal").text((Math.round(x * 1.05)).toLocaleString()); | |
| 127 $("#ok").show(); | |
| 128 lock(false); | |
| 129 }; | |
| 130 | |
| 131 var fetchFixer = function() { | |
| 132 if (rates.fixer !== undefined) { return; } | |
| 133 | |
| 134 lock(true); | |
| 135 locks.fixer = true; | |
| 136 | |
| 137 $.getJSON("https://api.fixer.io/latest", { base: "JPY", symbols: "IDR" }) | |
| 138 .done(function(data) { | |
| 139 rates.fixer = parseFloat(data.rates["IDR"]); | |
| 140 | |
| 141 displayResult(); | |
| 142 }) | |
| 143 .fail(function() { | |
| 144 $("#error").show(); | |
| 145 }) | |
| 146 .always(function() { | |
| 147 locks.fixer = false; | |
| 148 lock(false); | |
| 149 }); | |
| 150 }; | |
| 151 | |
| 152 var fetchBni = function() { | |
| 153 if (rates.bni !== undefined) { return; } | |
| 154 | |
| 155 lock(true); | |
| 156 locks.bni = true; | |
| 157 | |
| 158 $.get("bni-jpyidr.txt") | |
| 159 .done(function(data) { | |
| 160 if (data === "") { | |
| 161 rates.bni = 0; | |
| 162 } else { | |
| 163 rates.bni = parseFloat(data); | |
| 164 } | |
| 165 | |
| 166 displayResult(); | |
| 167 }) | |
| 168 .fail(function() { | |
| 169 $("#error").show(); | |
| 170 }) | |
| 171 .always(function() { | |
| 172 locks.bni = false; | |
| 173 lock(false); | |
| 174 }); | |
| 175 }; | |
| 176 | |
| 177 var action = function(e) { | |
| 178 e.preventDefault() | |
| 179 $(".js").hide() | |
| 180 | |
| 181 var x = input(); | |
| 182 | |
| 183 if (x === NaN || x === undefined) { return false; }; | |
| 184 | |
| 185 fetchFixer(); | |
| 186 fetchBni(); | |
| 187 | |
| 188 displayResult(); | |
| 189 }; | |
| 190 | |
| 191 $("form").submit(action) | |
| 192 $("button[type=reset]").click(function(e) { xForm.focus(); }); | |
| 193 </script> | |
| 194 </body> | 279 </body> |
