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> |