Browse Source

finished the trading screen

gdias 1 month ago
parent
commit
8dc37859a0

+ 104 - 276
package-lock.json

@@ -8,7 +8,12 @@
 			"name": "toeasy",
 			"version": "0.0.1",
 			"dependencies": {
-				"layerchart": "^1.0.12"
+				"@schedule-x/calendar": "^3.3.0",
+				"@schedule-x/svelte": "^3.0.0",
+				"@schedule-x/theme-default": "^3.3.0",
+				"flatpickr": "^4.6.13",
+				"layerchart": "^1.0.12",
+				"temporal-polyfill": "^0.3.0"
 			},
 			"devDependencies": {
 				"@sveltejs/adapter-static": "^3.0.8",
@@ -690,6 +695,34 @@
 			"dev": true,
 			"license": "MIT"
 		},
+		"node_modules/@preact/signals": {
+			"version": "2.3.2",
+			"resolved": "https://registry.npmjs.org/@preact/signals/-/signals-2.3.2.tgz",
+			"integrity": "sha512-Q22avIn4z0BQnmFeo6Y5HCnJTo8VufN84zN51OtqeNgZOVCYgdwEOcJKVX1x/IrjRVxUnOy6Ubn7H5aVFujXaQ==",
+			"license": "MIT",
+			"peer": true,
+			"dependencies": {
+				"@preact/signals-core": "^1.12.0"
+			},
+			"funding": {
+				"type": "opencollective",
+				"url": "https://opencollective.com/preact"
+			},
+			"peerDependencies": {
+				"preact": ">= 10.25.0 || >=11.0.0-0"
+			}
+		},
+		"node_modules/@preact/signals-core": {
+			"version": "1.12.1",
+			"resolved": "https://registry.npmjs.org/@preact/signals-core/-/signals-core-1.12.1.tgz",
+			"integrity": "sha512-BwbTXpj+9QutoZLQvbttRg5x3l5468qaV2kufh+51yha1c53ep5dY4kTuZR35+3pAZxpfQerGJiQqg34ZNZ6uA==",
+			"license": "MIT",
+			"peer": true,
+			"funding": {
+				"type": "opencollective",
+				"url": "https://opencollective.com/preact"
+			}
+		},
 		"node_modules/@rollup/rollup-android-arm-eabi": {
 			"version": "4.49.0",
 			"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.49.0.tgz",
@@ -970,6 +1003,44 @@
 				"win32"
 			]
 		},
+		"node_modules/@schedule-x/calendar": {
+			"version": "3.3.0",
+			"resolved": "https://registry.npmjs.org/@schedule-x/calendar/-/calendar-3.3.0.tgz",
+			"integrity": "sha512-wPzRM/zlTy1HTeqxJfGGp5PdhAyFEKvNb1Kcsdavig+X+80mWEpBbxvachoQgy5TUI9gSVdcPdxBIOmnW8bS9w==",
+			"license": "MIT",
+			"peerDependencies": {
+				"@preact/signals": "^2.0.2",
+				"preact": "^10.19.2",
+				"temporal-polyfill": "0.3.0"
+			}
+		},
+		"node_modules/@schedule-x/shared": {
+			"version": "3.3.0",
+			"resolved": "https://registry.npmjs.org/@schedule-x/shared/-/shared-3.3.0.tgz",
+			"integrity": "sha512-VbPsoXEmQUZlANFEs58yDUS6fizsKZ8T8RwcTk6D9hvaNdjblZdHF7vj94ZcDukIjC4eLGPjubxER0MI4czzVQ==",
+			"license": "MIT",
+			"peer": true,
+			"peerDependencies": {
+				"@preact/signals": "^2.0.2"
+			}
+		},
+		"node_modules/@schedule-x/svelte": {
+			"version": "3.0.0",
+			"resolved": "https://registry.npmjs.org/@schedule-x/svelte/-/svelte-3.0.0.tgz",
+			"integrity": "sha512-/p91n/sl3iR/pdgvu3QwWTU3OiQoZCm4ftchU8NUcG1exReSxyKnWkiLWc00eK0eS2oTC+cG2v8H8pwggIzIng==",
+			"license": "MIT",
+			"peerDependencies": {
+				"@schedule-x/calendar": "^3.0.0",
+				"@schedule-x/shared": "^3.0.0",
+				"svelte": "^4 || ^5"
+			}
+		},
+		"node_modules/@schedule-x/theme-default": {
+			"version": "3.3.0",
+			"resolved": "https://registry.npmjs.org/@schedule-x/theme-default/-/theme-default-3.3.0.tgz",
+			"integrity": "sha512-B9TT7+CQUFdZL2IfmT9Tt9GWfhB6Dxqerl07bPtuQebjHPuJcsYKVnyAc646x6rI6lzVhe2wnde4oa6PGGKz6g==",
+			"license": "MIT"
+		},
 		"node_modules/@standard-schema/spec": {
 			"version": "1.0.0",
 			"resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.0.0.tgz",
@@ -1796,18 +1867,6 @@
 				"robust-predicates": "^3.0.2"
 			}
 		},
-		"node_modules/detect-libc": {
-			"version": "2.0.4",
-			"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.4.tgz",
-			"integrity": "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==",
-			"dev": true,
-			"license": "Apache-2.0",
-			"optional": true,
-			"peer": true,
-			"engines": {
-				"node": ">=8"
-			}
-		},
 		"node_modules/devalue": {
 			"version": "5.3.2",
 			"resolved": "https://registry.npmjs.org/devalue/-/devalue-5.3.2.tgz",
@@ -1980,6 +2039,12 @@
 				"node": ">=8"
 			}
 		},
+		"node_modules/flatpickr": {
+			"version": "4.6.13",
+			"resolved": "https://registry.npmjs.org/flatpickr/-/flatpickr-4.6.13.tgz",
+			"integrity": "sha512-97PMG/aywoYpB4IvbvUJi0RQi8vearvU0oov1WW3k0WZPBMrTQVqekSX5CjSG/M4Q3i6A/0FKXC7RyAoAUUSPw==",
+			"license": "MIT"
+		},
 		"node_modules/foreground-child": {
 			"version": "3.3.1",
 			"resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz",
@@ -2204,18 +2269,6 @@
 				"@pkgjs/parseargs": "^0.11.0"
 			}
 		},
-		"node_modules/jiti": {
-			"version": "2.5.1",
-			"resolved": "https://registry.npmjs.org/jiti/-/jiti-2.5.1.tgz",
-			"integrity": "sha512-twQoecYPiVA5K/h6SxtORw/Bs3ar+mLUtoPSc7iMXzQzK8d7eJ/R09wmTwAjiamETn1cXYPGfNnu7DMoHgu12w==",
-			"dev": true,
-			"license": "MIT",
-			"optional": true,
-			"peer": true,
-			"bin": {
-				"jiti": "lib/jiti-cli.mjs"
-			}
-		},
 		"node_modules/kleur": {
 			"version": "4.1.5",
 			"resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz",
@@ -2280,257 +2333,6 @@
 				"svelte": "^3.56.0 || ^4.0.0 || ^5.0.0"
 			}
 		},
-		"node_modules/lightningcss": {
-			"version": "1.30.1",
-			"resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.1.tgz",
-			"integrity": "sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg==",
-			"dev": true,
-			"license": "MPL-2.0",
-			"optional": true,
-			"peer": true,
-			"dependencies": {
-				"detect-libc": "^2.0.3"
-			},
-			"engines": {
-				"node": ">= 12.0.0"
-			},
-			"funding": {
-				"type": "opencollective",
-				"url": "https://opencollective.com/parcel"
-			},
-			"optionalDependencies": {
-				"lightningcss-darwin-arm64": "1.30.1",
-				"lightningcss-darwin-x64": "1.30.1",
-				"lightningcss-freebsd-x64": "1.30.1",
-				"lightningcss-linux-arm-gnueabihf": "1.30.1",
-				"lightningcss-linux-arm64-gnu": "1.30.1",
-				"lightningcss-linux-arm64-musl": "1.30.1",
-				"lightningcss-linux-x64-gnu": "1.30.1",
-				"lightningcss-linux-x64-musl": "1.30.1",
-				"lightningcss-win32-arm64-msvc": "1.30.1",
-				"lightningcss-win32-x64-msvc": "1.30.1"
-			}
-		},
-		"node_modules/lightningcss-darwin-arm64": {
-			"version": "1.30.1",
-			"resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.30.1.tgz",
-			"integrity": "sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ==",
-			"cpu": [
-				"arm64"
-			],
-			"dev": true,
-			"license": "MPL-2.0",
-			"optional": true,
-			"os": [
-				"darwin"
-			],
-			"peer": true,
-			"engines": {
-				"node": ">= 12.0.0"
-			},
-			"funding": {
-				"type": "opencollective",
-				"url": "https://opencollective.com/parcel"
-			}
-		},
-		"node_modules/lightningcss-darwin-x64": {
-			"version": "1.30.1",
-			"resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.30.1.tgz",
-			"integrity": "sha512-k1EvjakfumAQoTfcXUcHQZhSpLlkAuEkdMBsI/ivWw9hL+7FtilQc0Cy3hrx0AAQrVtQAbMI7YjCgYgvn37PzA==",
-			"cpu": [
-				"x64"
-			],
-			"dev": true,
-			"license": "MPL-2.0",
-			"optional": true,
-			"os": [
-				"darwin"
-			],
-			"peer": true,
-			"engines": {
-				"node": ">= 12.0.0"
-			},
-			"funding": {
-				"type": "opencollective",
-				"url": "https://opencollective.com/parcel"
-			}
-		},
-		"node_modules/lightningcss-freebsd-x64": {
-			"version": "1.30.1",
-			"resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.30.1.tgz",
-			"integrity": "sha512-kmW6UGCGg2PcyUE59K5r0kWfKPAVy4SltVeut+umLCFoJ53RdCUWxcRDzO1eTaxf/7Q2H7LTquFHPL5R+Gjyig==",
-			"cpu": [
-				"x64"
-			],
-			"dev": true,
-			"license": "MPL-2.0",
-			"optional": true,
-			"os": [
-				"freebsd"
-			],
-			"peer": true,
-			"engines": {
-				"node": ">= 12.0.0"
-			},
-			"funding": {
-				"type": "opencollective",
-				"url": "https://opencollective.com/parcel"
-			}
-		},
-		"node_modules/lightningcss-linux-arm-gnueabihf": {
-			"version": "1.30.1",
-			"resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.30.1.tgz",
-			"integrity": "sha512-MjxUShl1v8pit+6D/zSPq9S9dQ2NPFSQwGvxBCYaBYLPlCWuPh9/t1MRS8iUaR8i+a6w7aps+B4N0S1TYP/R+Q==",
-			"cpu": [
-				"arm"
-			],
-			"dev": true,
-			"license": "MPL-2.0",
-			"optional": true,
-			"os": [
-				"linux"
-			],
-			"peer": true,
-			"engines": {
-				"node": ">= 12.0.0"
-			},
-			"funding": {
-				"type": "opencollective",
-				"url": "https://opencollective.com/parcel"
-			}
-		},
-		"node_modules/lightningcss-linux-arm64-gnu": {
-			"version": "1.30.1",
-			"resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.30.1.tgz",
-			"integrity": "sha512-gB72maP8rmrKsnKYy8XUuXi/4OctJiuQjcuqWNlJQ6jZiWqtPvqFziskH3hnajfvKB27ynbVCucKSm2rkQp4Bw==",
-			"cpu": [
-				"arm64"
-			],
-			"dev": true,
-			"license": "MPL-2.0",
-			"optional": true,
-			"os": [
-				"linux"
-			],
-			"peer": true,
-			"engines": {
-				"node": ">= 12.0.0"
-			},
-			"funding": {
-				"type": "opencollective",
-				"url": "https://opencollective.com/parcel"
-			}
-		},
-		"node_modules/lightningcss-linux-arm64-musl": {
-			"version": "1.30.1",
-			"resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.30.1.tgz",
-			"integrity": "sha512-jmUQVx4331m6LIX+0wUhBbmMX7TCfjF5FoOH6SD1CttzuYlGNVpA7QnrmLxrsub43ClTINfGSYyHe2HWeLl5CQ==",
-			"cpu": [
-				"arm64"
-			],
-			"dev": true,
-			"license": "MPL-2.0",
-			"optional": true,
-			"os": [
-				"linux"
-			],
-			"peer": true,
-			"engines": {
-				"node": ">= 12.0.0"
-			},
-			"funding": {
-				"type": "opencollective",
-				"url": "https://opencollective.com/parcel"
-			}
-		},
-		"node_modules/lightningcss-linux-x64-gnu": {
-			"version": "1.30.1",
-			"resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.30.1.tgz",
-			"integrity": "sha512-piWx3z4wN8J8z3+O5kO74+yr6ze/dKmPnI7vLqfSqI8bccaTGY5xiSGVIJBDd5K5BHlvVLpUB3S2YCfelyJ1bw==",
-			"cpu": [
-				"x64"
-			],
-			"dev": true,
-			"license": "MPL-2.0",
-			"optional": true,
-			"os": [
-				"linux"
-			],
-			"peer": true,
-			"engines": {
-				"node": ">= 12.0.0"
-			},
-			"funding": {
-				"type": "opencollective",
-				"url": "https://opencollective.com/parcel"
-			}
-		},
-		"node_modules/lightningcss-linux-x64-musl": {
-			"version": "1.30.1",
-			"resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.30.1.tgz",
-			"integrity": "sha512-rRomAK7eIkL+tHY0YPxbc5Dra2gXlI63HL+v1Pdi1a3sC+tJTcFrHX+E86sulgAXeI7rSzDYhPSeHHjqFhqfeQ==",
-			"cpu": [
-				"x64"
-			],
-			"dev": true,
-			"license": "MPL-2.0",
-			"optional": true,
-			"os": [
-				"linux"
-			],
-			"peer": true,
-			"engines": {
-				"node": ">= 12.0.0"
-			},
-			"funding": {
-				"type": "opencollective",
-				"url": "https://opencollective.com/parcel"
-			}
-		},
-		"node_modules/lightningcss-win32-arm64-msvc": {
-			"version": "1.30.1",
-			"resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.30.1.tgz",
-			"integrity": "sha512-mSL4rqPi4iXq5YVqzSsJgMVFENoa4nGTT/GjO2c0Yl9OuQfPsIfncvLrEW6RbbB24WtZ3xP/2CCmI3tNkNV4oA==",
-			"cpu": [
-				"arm64"
-			],
-			"dev": true,
-			"license": "MPL-2.0",
-			"optional": true,
-			"os": [
-				"win32"
-			],
-			"peer": true,
-			"engines": {
-				"node": ">= 12.0.0"
-			},
-			"funding": {
-				"type": "opencollective",
-				"url": "https://opencollective.com/parcel"
-			}
-		},
-		"node_modules/lightningcss-win32-x64-msvc": {
-			"version": "1.30.1",
-			"resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.30.1.tgz",
-			"integrity": "sha512-PVqXh48wh4T53F/1CCu8PIPCxLzWyCnn/9T5W1Jpmdy5h9Cwd+0YQS6/LwhHXSafuc61/xg9Lv5OrCby6a++jg==",
-			"cpu": [
-				"x64"
-			],
-			"dev": true,
-			"license": "MPL-2.0",
-			"optional": true,
-			"os": [
-				"win32"
-			],
-			"peer": true,
-			"engines": {
-				"node": ">= 12.0.0"
-			},
-			"funding": {
-				"type": "opencollective",
-				"url": "https://opencollective.com/parcel"
-			}
-		},
 		"node_modules/lilconfig": {
 			"version": "3.1.3",
 			"resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz",
@@ -2951,6 +2753,17 @@
 			"integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
 			"license": "MIT"
 		},
+		"node_modules/preact": {
+			"version": "10.27.2",
+			"resolved": "https://registry.npmjs.org/preact/-/preact-10.27.2.tgz",
+			"integrity": "sha512-5SYSgFKSyhCbk6SrXyMpqjb5+MQBgfvEKE/OC+PujcY34sOpqtr+0AZQtPYx5IA6VxynQ7rUPCtKzyovpj9Bpg==",
+			"license": "MIT",
+			"peer": true,
+			"funding": {
+				"type": "opencollective",
+				"url": "https://opencollective.com/preact"
+			}
+		},
 		"node_modules/prettier": {
 			"version": "3.6.2",
 			"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz",
@@ -3517,6 +3330,21 @@
 				"jiti": "bin/jiti.js"
 			}
 		},
+		"node_modules/temporal-polyfill": {
+			"version": "0.3.0",
+			"resolved": "https://registry.npmjs.org/temporal-polyfill/-/temporal-polyfill-0.3.0.tgz",
+			"integrity": "sha512-qNsTkX9K8hi+FHDfHmf22e/OGuXmfBm9RqNismxBrnSmZVJKegQ+HYYXT+R7Ha8F/YSm2Y34vmzD4cxMu2u95g==",
+			"license": "MIT",
+			"dependencies": {
+				"temporal-spec": "0.3.0"
+			}
+		},
+		"node_modules/temporal-spec": {
+			"version": "0.3.0",
+			"resolved": "https://registry.npmjs.org/temporal-spec/-/temporal-spec-0.3.0.tgz",
+			"integrity": "sha512-n+noVpIqz4hYgFSMOSiINNOUOMFtV5cZQNCmmszA6GiVFVRt3G7AqVyhXjhCSmowvQn+NsGn+jMDMKJYHd3bSQ==",
+			"license": "ISC"
+		},
 		"node_modules/thenify": {
 			"version": "3.3.1",
 			"resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz",

+ 6 - 1
package.json

@@ -26,6 +26,11 @@
 		"vite": "^7.0.4"
 	},
 	"dependencies": {
-		"layerchart": "^1.0.12"
+		"@schedule-x/calendar": "^3.3.0",
+		"@schedule-x/svelte": "^3.0.0",
+		"@schedule-x/theme-default": "^3.3.0",
+		"flatpickr": "^4.6.13",
+		"layerchart": "^1.0.12",
+		"temporal-polyfill": "^0.3.0"
 	}
 }

+ 250 - 25
src/lib/components/trading/BoletaCompra.svelte

@@ -1,66 +1,291 @@
 <script>
   import ModalBase from './ModalBase.svelte';
+  import flatpickr from 'flatpickr';
+  import 'flatpickr/dist/flatpickr.min.css';
+  import { Portuguese } from 'flatpickr/dist/l10n/pt.js';
+
   export let visible = false;
   export let onClose = () => {};
   export let state = '';
   export let commodity = '';
+  export let prefill = null;
+
   let valorSaca = '';
   let quantidade = '';
-  let referencia = 'BRL : 12';
-  let validade = '';
-  let calendario = '';
+  let referencia = '';
+  let validade = new Date();
+  let validadeInput = validade.toISOString().slice(0, 10);
+
   $: total = (Number(valorSaca) || 0) * (Number(quantidade) || 0);
+
+  $: if (visible && prefill) {
+    if (prefill.valorSaca != null || prefill.valor != null) {
+      valorSaca = String(prefill.valorSaca ?? prefill.valor ?? '');
+    }
+    if (prefill.quantidade != null) {
+      quantidade = String(prefill.quantidade ?? '');
+    }
+  }
+
+  let calendarEl;
+
+  // Inicializa Flatpickr
+  function initCalendar() {
+    flatpickr(calendarEl, {
+      inline: true,
+      appendTo: calendarEl,
+      defaultDate: validade,
+      locale: Portuguese,
+      dateFormat: 'Y-m-d',
+      onChange: (selectedDates) => {
+        validade = selectedDates[0];
+        validadeInput = validade.toISOString().slice(0, 10);
+      }
+    });
+  }
+
+  function handleValidadeInput(event) {
+    const str = event.target.value;
+    validade = str ? new Date(str) : new Date();
+    if (calendarEl._flatpickr) {
+      calendarEl._flatpickr.setDate(validade);
+    }
+  }
+
   function confirmar() {
-    const dados = { tipo: 'compra', valorSaca: Number(valorSaca)||0, quantidade: Number(quantidade)||0, referencia, total, validade, calendario, estado: state, commodity };
+    const dados = {
+      tipo: 'compra',
+      valorSaca: Number(valorSaca) || 0,
+      quantidade: Number(quantidade) || 0,
+      referencia,
+      total,
+      validade: validadeInput,
+      estado: state,
+      commodity
+    };
     console.log('BoletaCompra confirmada', dados);
     try { onClose?.(); } catch {}
   }
-  function formatBRL(n) { return new Intl.NumberFormat('pt-BR', { style: 'currency', currency: 'BRL' }).format(Number(n||0)); }
+
+  function formatBRL(n) {
+    return new Intl.NumberFormat('pt-BR', { style: 'currency', currency: 'BRL' }).format(Number(n || 0));
+  }
 </script>
+
 <ModalBase title="Boleta de Compra" {visible} {onClose}>
   <div class="space-y-4">
+
+    <!-- VALOR E QUANTIDADE -->
     <div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
       <div>
         <label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Valor/saca</label>
-        <input type="number" min="0" step="0.01" bind:value={valorSaca} class="mt-1 block w-full rounded border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700/70 text-gray-900 dark:text-gray-200 px-3 py-2 focus:outline-none focus:ring-2 focus:ring-green-500" />
+        <input type="number" min="0" step="0.01" bind:value={valorSaca}
+          class="mt-1 block w-full rounded border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700/70 text-gray-900 dark:text-gray-200 px-3 py-2 focus:outline-none focus:ring-2 focus:ring-green-500" />
       </div>
       <div>
         <label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Quantidade em saca</label>
-        <input type="number" min="0" step="1" bind:value={quantidade} class="mt-1 block w-full rounded border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700/70 text-gray-900 dark:text-gray-200 px-3 py-2 focus:outline-none focus:ring-2 focus:ring-green-500" />
+        <input type="number" min="0" step="1" bind:value={quantidade}
+          class="mt-1 block w-full rounded border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700/70 text-gray-900 dark:text-gray-200 px-3 py-2 focus:outline-none focus:ring-2 focus:ring-green-500" />
       </div>
     </div>
+
+    <!-- REFERÊNCIA E TOTAL -->
     <div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
       <div>
-        <label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Referência</label>
-        <input type="text" bind:value={referencia} class="mt-1 block w-full rounded border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700/70 text-gray-900 dark:text-gray-200 px-3 py-2 focus:outline-none focus:ring-2 focus:ring-green-500" />
+        <label class="block text-sm font-medium text-gray-700 dark:text-gray-300">eBRL: {referencia}</label>
       </div>
       <div>
-        <label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Referência valor total</label>
-        <input value={formatBRL(total)} readonly class="mt-1 block w-full rounded border border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-700/40 text-gray-900 dark:text-gray-200 px-3 py-2" />
+        <label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Valor total: {formatBRL(total)}</label>
       </div>
     </div>
+
+    <!-- VALIDADE E CALENDÁRIO -->
     <div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
+      <!-- input de validade -->
       <div>
         <label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Validade</label>
-        <input type="date" bind:value={validade} class="mt-1 block w-full rounded border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700/70 text-gray-900 dark:text-gray-200 px-3 py-2 focus:outline-none focus:ring-2 focus:ring-green-500" />
+        <input type="date" bind:value={validadeInput} on:input={handleValidadeInput}
+          class="mt-1 block w-full rounded border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700/70 text-gray-900 dark:text-gray-200 px-3 py-2 focus:outline-none focus:ring-2 focus:ring-green-500" />
+
+        <!-- ESTADO E COMMODITY -->
+        <div class="mt-4">
+          <label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Estado</label>
+          <input value={state} readonly
+            class="mt-1 block w-full rounded border border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-700/40 text-gray-900 dark:text-gray-200 px-3 py-2" />
+        </div>
+        <div class="mt-4">
+          <label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Commodity</label>
+          <input value={commodity} readonly
+            class="mt-1 block w-full rounded border border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-700/40 text-gray-900 dark:text-gray-200 px-3 py-2" />
+        </div>
       </div>
+
+      <!-- Calendário inline -->
       <div>
         <label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Calendário</label>
-        <input type="date" bind:value={calendario} class="mt-1 block w-full rounded border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700/70 text-gray-900 dark:text-gray-200 px-3 py-2 focus:outline-none focus:ring-2 focus:ring-green-500" />
-      </div>
-    </div>
-    <div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
-      <div>
-        <label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Estado</label>
-        <input value={state} readonly class="mt-1 block w-full rounded border border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-700/40 text-gray-900 dark:text-gray-200 px-3 py-2" />
-      </div>
-      <div>
-        <label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Commodity</label>
-        <input value={commodity} readonly class="mt-1 block w-full rounded border border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-700/40 text-gray-900 dark:text-gray-200 px-3 py-2" />
+        <div bind:this={calendarEl} class="mt-1 w-56 text-sm calendar-override rounded border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700/70 text-gray-900 dark:text-gray-200 p-2" use:initCalendar></div>
       </div>
     </div>
-    <div class="flex justify-end">
-      <button class="px-4 py-2 rounded bg-green-600 hover:bg-green-700 text-white focus:outline-none focus:ring-2 focus:ring-green-500" on:click={confirmar}>Confirmar Compra</button>
+
+
+    <!-- BOTÃO CONFIRMAR -->
+    <div class="flex justify-end pt-2">
+      <button class="px-4 py-2 rounded bg-green-600 hover:bg-green-700 text-white focus:outline-none focus:ring-2 focus:ring-green-500"
+        on:click={confirmar}>
+        Confirmar Compra
+      </button>
     </div>
   </div>
 </ModalBase>
+
+<style>
+  :global(.calendar-override .flatpickr-calendar) {
+    position: static !important;
+    background: transparent !important;
+    border: 0 !important;
+    box-shadow: none !important;
+  }
+  :global(.calendar-override .flatpickr-months) {
+    border-bottom: 1px solid #e5e7eb;
+  }
+  :global(.dark .calendar-override .flatpickr-months) {
+    border-color: #374151;
+  }
+  :global(.calendar-override .flatpickr-current-month .cur-month),
+  :global(.calendar-override .flatpickr-current-month .numInputWrapper input) {
+    color: #111827;
+    font-weight: 600;
+  }
+  :global(.dark .calendar-override .flatpickr-current-month .cur-month),
+  :global(.dark .calendar-override .flatpickr-current-month .numInputWrapper input) {
+    color: #e5e7eb;
+  }
+  :global(.calendar-override .flatpickr-weekday) {
+    color: #6b7280;
+    font-weight: 500;
+  }
+  :global(.dark .calendar-override .flatpickr-weekday) {
+    color: #9ca3af;
+  }
+  :global(.calendar-override .flatpickr-day) {
+    color: #111827;
+    border-radius: 0.375rem;
+  }
+  :global(.dark .calendar-override .flatpickr-day) {
+    color: #e5e7eb;
+  }
+  :global(.calendar-override .flatpickr-day:hover) {
+    background: #f3f4f6;
+  }
+  :global(.dark .calendar-override .flatpickr-day:hover) {
+    background: #374151;
+  }
+  :global(.calendar-override .flatpickr-day.selected),
+  :global(.calendar-override .flatpickr-day.startRange),
+  :global(.calendar-override .flatpickr-day.endRange) {
+    background: #16a34a !important; /* green-600 */
+    color: #ffffff !important;
+    border-color: transparent !important;
+  }
+  :global(.calendar-override .flatpickr-day.selected:hover),
+  :global(.calendar-override .flatpickr-day.startRange:hover),
+  :global(.calendar-override .flatpickr-day.endRange:hover) {
+    background: #15803d !important; /* green-700 */
+  }
+  :global(.calendar-override .flatpickr-day.today) {
+    box-shadow: inset 0 -2px 0 #16a34a;
+  }
+  :global(.calendar-override .flatpickr-day.disabled),
+  :global(.calendar-override .flatpickr-day.prevMonthDay),
+  :global(.calendar-override .flatpickr-day.nextMonthDay) {
+    color: #9ca3af;
+  }
+  :global(.dark .calendar-override .flatpickr-day.disabled),
+  :global(.dark .calendar-override .flatpickr-day.prevMonthDay),
+  :global(.dark .calendar-override .flatpickr-day.nextMonthDay) {
+    color: #6b7280;
+  }
+  :global(.calendar-override .flatpickr-prev-month svg),
+  :global(.calendar-override .flatpickr-next-month svg) {
+    fill: #6b7280;
+  }
+  :global(.calendar-override .flatpickr-prev-month:hover svg),
+  :global(.calendar-override .flatpickr-next-month:hover svg) {
+    fill: #111827;
+  }
+  :global(.dark .calendar-override .flatpickr-prev-month svg),
+  :global(.dark .calendar-override .flatpickr-next-month svg) {
+    fill: #9ca3af;
+  }
+  :global(.dark .calendar-override .flatpickr-prev-month:hover svg),
+  :global(.dark .calendar-override .flatpickr-next-month:hover svg) {
+    fill: #e5e7eb;
+  }
+  :global(.calendar-override .flatpickr-calendar) {
+    width: 100% !important;
+  }
+  :global(.calendar-override .flatpickr-months) {
+    padding: 0.25rem 0.25rem;
+  }
+  :global(.calendar-override .flatpickr-current-month) {
+    font-size: 0.875rem; /* text-sm */
+  }
+  :global(.calendar-override .flatpickr-weekday) {
+    font-size: 0.75rem; /* text-xs */
+  }
+  :global(.calendar-override .dayContainer) {
+    padding: 0.25rem !important;
+  }
+  :global(.calendar-override .flatpickr-day) {
+    width: 1.75rem;
+    height: 1.75rem;
+    line-height: 1.75rem;
+    max-width: 1.75rem;
+    font-size: 0.875rem; /* text-sm */
+    margin: 0.125rem;
+  }
+  :global(.calendar-override .flatpickr-prev-month),
+  :global(.calendar-override .flatpickr-next-month) {
+    top: 0.35rem;
+  }
+  :global(.calendar-override .flatpickr-current-month .numInputWrapper input) {
+    max-width: 3.5rem;
+  }
+  /* Ensure smaller footprint and dark-friendly backgrounds */
+  :global(.calendar-override .flatpickr-calendar) {
+    max-width: none !important;
+    min-width: 0 !important;
+  }
+  :global(.calendar-override .flatpickr-innerContainer),
+  :global(.calendar-override .flatpickr-months),
+  :global(.calendar-override .flatpickr-weekdays),
+  :global(.calendar-override .flatpickr-days) {
+    background: transparent !important;
+  }
+  :global(.calendar-override .flatpickr-days),
+  :global(.calendar-override .dayContainer) {
+    width: auto !important;
+    min-width: 0 !important;
+  }
+  :global(.calendar-override .dayContainer) {
+    padding: 0.125rem !important;
+  }
+  :global(.calendar-override .flatpickr-day) {
+    width: 1.5rem;
+    height: 1.5rem;
+    line-height: 1.5rem;
+    max-width: 1.5rem;
+    font-size: 0.875rem; /* text-sm */
+    margin: 0.1rem;
+  }
+  :global(.calendar-override .flatpickr-prev-month svg),
+  :global(.calendar-override .flatpickr-next-month svg) {
+    width: 0.875rem;
+    height: 0.875rem;
+  }
+  /* Hide top navigation arrows */
+  :global(.calendar-override .flatpickr-prev-month),
+  :global(.calendar-override .flatpickr-next-month) {
+    display: none !important;
+  }
+</style>

+ 91 - 19
src/lib/components/trading/BoletaVenda.svelte

@@ -1,5 +1,8 @@
 <script>
   import ModalBase from './ModalBase.svelte';
+  import flatpickr from 'flatpickr';
+  import 'flatpickr/dist/flatpickr.min.css';
+  import { Portuguese } from 'flatpickr/dist/l10n/pt.js';
   export let visible = false;
   export let onClose = () => {};
   export let state = '';
@@ -7,11 +10,35 @@
   let valorSaca = '';
   let quantidade = '';
   let referencia = 'BRL : 12';
-  let validade = '';
-  let calendario = '';
+  let validade = new Date();
+  let validadeInput = validade.toISOString().slice(0, 10);
+  $: calendario = validadeInput;
   $: total = (Number(valorSaca) || 0) * (Number(quantidade) || 0);
+
+  let calendarEl;
+  function initCalendar() {
+    flatpickr(calendarEl, {
+      inline: true,
+      appendTo: calendarEl,
+      defaultDate: validade,
+      locale: Portuguese,
+      dateFormat: 'Y-m-d',
+      onChange: (selectedDates) => {
+        validade = selectedDates[0];
+        validadeInput = validade.toISOString().slice(0, 10);
+      }
+    });
+  }
+  function handleValidadeInput(event) {
+    const str = event.target.value;
+    validade = str ? new Date(str) : new Date();
+    if (calendarEl && calendarEl._flatpickr) {
+      calendarEl._flatpickr.setDate(validade);
+    }
+  }
+
   function confirmar() {
-    const dados = { tipo: 'venda', valorSaca: Number(valorSaca)||0, quantidade: Number(quantidade)||0, referencia, total, validade, calendario, estado: state, commodity };
+    const dados = { tipo: 'venda', valorSaca: Number(valorSaca)||0, quantidade: Number(quantidade)||0, referencia, total, validade: validadeInput, calendario, estado: state, commodity };
     console.log('BoletaVenda confirmada', dados);
     try { onClose?.(); } catch {}
   }
@@ -31,32 +58,30 @@
     </div>
     <div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
       <div>
-        <label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Referência</label>
-        <input type="text" bind:value={referencia} class="mt-1 block w-full rounded border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700/70 text-gray-900 dark:text-gray-200 px-3 py-2 focus:outline-none focus:ring-2 focus:ring-red-500" />
+        <label class="block text-sm font-medium text-gray-700 dark:text-gray-300">eBRL: {referencia}</label>
       </div>
       <div>
-        <label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Referência valor total</label>
-        <input value={formatBRL(total)} readonly class="mt-1 block w-full rounded border border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-700/40 text-gray-900 dark:text-gray-200 px-3 py-2" />
+        <label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Valor total: {formatBRL(total)}</label>
       </div>
     </div>
     <div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
       <div>
         <label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Validade</label>
-        <input type="date" bind:value={validade} class="mt-1 block w-full rounded border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700/70 text-gray-900 dark:text-gray-200 px-3 py-2 focus:outline-none focus:ring-2 focus:ring-red-500" />
+        <input type="date" bind:value={validadeInput} on:input={handleValidadeInput} class="mt-1 block w-full rounded border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700/70 text-gray-900 dark:text-gray-200 px-3 py-2 focus:outline-none focus:ring-2 focus:ring-red-500" />
+
+        <!-- ESTADO E COMMODITY -->
+        <div class="mt-4">
+          <label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Estado</label>
+          <input value={state} readonly class="mt-1 block w-full rounded border border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-700/40 text-gray-900 dark:text-gray-200 px-3 py-2" />
+        </div>
+        <div class="mt-4">
+          <label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Commodity</label>
+          <input value={commodity} readonly class="mt-1 block w-full rounded border border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-700/40 text-gray-900 dark:text-gray-200 px-3 py-2" />
+        </div>
       </div>
       <div>
         <label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Calendário</label>
-        <input type="date" bind:value={calendario} class="mt-1 block w-full rounded border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700/70 text-gray-900 dark:text-gray-200 px-3 py-2 focus:outline-none focus:ring-2 focus:ring-red-500" />
-      </div>
-    </div>
-    <div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
-      <div>
-        <label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Estado</label>
-        <input value={state} readonly class="mt-1 block w-full rounded border border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-700/40 text-gray-900 dark:text-gray-200 px-3 py-2" />
-      </div>
-      <div>
-        <label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Commodity</label>
-        <input value={commodity} readonly class="mt-1 block w-full rounded border border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-700/40 text-gray-900 dark:text-gray-200 px-3 py-2" />
+        <div bind:this={calendarEl} class="mt-1 w-56 text-sm calendar-override rounded border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700/70 text-gray-900 dark:text-gray-200 p-2" use:initCalendar></div>
       </div>
     </div>
     <div class="flex justify-end">
@@ -64,3 +89,50 @@
     </div>
   </div>
 </ModalBase>
+
+<style>
+  :global(.calendar-override .flatpickr-calendar) {
+    position: static !important;
+    background: transparent !important;
+    border: 0 !important;
+    box-shadow: none !important;
+    width: 100% !important;
+  }
+  :global(.calendar-override .flatpickr-months) {
+    border-bottom: 1px solid #e5e7eb;
+    padding: 0.25rem 0.25rem;
+  }
+  :global(.dark .calendar-override .flatpickr-months) { border-color: #374151; }
+  :global(.calendar-override .flatpickr-current-month .cur-month),
+  :global(.calendar-override .flatpickr-current-month .numInputWrapper input) {
+    color: #111827; font-weight: 600; font-size: 0.875rem;
+  }
+  :global(.dark .calendar-override .flatpickr-current-month .cur-month),
+  :global(.dark .calendar-override .flatpickr-current-month .numInputWrapper input) { color: #e5e7eb; }
+  :global(.calendar-override .flatpickr-weekday) { color: #6b7280; font-weight: 500; font-size: 0.75rem; }
+  :global(.dark .calendar-override .flatpickr-weekday) { color: #9ca3af; }
+  :global(.calendar-override .flatpickr-days),
+  :global(.calendar-override .dayContainer) { width: auto !important; min-width: 0 !important; }
+  :global(.calendar-override .dayContainer) { padding: 0.125rem !important; }
+  :global(.calendar-override .flatpickr-day) {
+    color: #111827; border-radius: 0.375rem; width: 1.5rem; height: 1.5rem; line-height: 1.5rem; max-width: 1.5rem; font-size: 0.875rem; margin: 0.1rem;
+  }
+  :global(.dark .calendar-override .flatpickr-day) { color: #e5e7eb; }
+  :global(.calendar-override .flatpickr-day:hover) { background: #f3f4f6; }
+  :global(.dark .calendar-override .flatpickr-day:hover) { background: #374151; }
+  :global(.calendar-override .flatpickr-day.selected),
+  :global(.calendar-override .flatpickr-day.startRange),
+  :global(.calendar-override .flatpickr-day.endRange) { background: #dc2626 !important; color: #ffffff !important; border-color: transparent !important; }
+  :global(.calendar-override .flatpickr-day.selected:hover),
+  :global(.calendar-override .flatpickr-day.startRange:hover),
+  :global(.calendar-override .flatpickr-day.endRange:hover) { background: #b91c1c !important; }
+  :global(.calendar-override .flatpickr-day.today) { box-shadow: inset 0 -2px 0 #dc2626; }
+  :global(.calendar-override .flatpickr-day.disabled),
+  :global(.calendar-override .flatpickr-day.prevMonthDay),
+  :global(.calendar-override .flatpickr-day.nextMonthDay) { color: #9ca3af; }
+  :global(.dark .calendar-override .flatpickr-day.disabled),
+  :global(.dark .calendar-override .flatpickr-day.prevMonthDay),
+  :global(.dark .calendar-override .flatpickr-day.nextMonthDay) { color: #6b7280; }
+  :global(.calendar-override .flatpickr-prev-month),
+  :global(.calendar-override .flatpickr-next-month) { display: none !important; }
+</style>

+ 3 - 1
src/lib/components/trading/TabelaOrdens.svelte

@@ -1,7 +1,9 @@
 <script>
+  import { createEventDispatcher } from 'svelte';
   export let ordensCompra = [];
   export let ordensVenda = [];
   export let ultimaVenda = { valor: 0, quantidade: 0 };
+  const dispatch = createEventDispatcher();
   function formatBRL(n) { return new Intl.NumberFormat('pt-BR', { style: 'currency', currency: 'BRL' }).format(Number(n || 0)); }
   function formatQty(n) { return new Intl.NumberFormat('pt-BR', { minimumFractionDigits: 0, maximumFractionDigits: 0 }).format(Number(n || 0)); }
 
@@ -67,7 +69,7 @@
       </div>
       <div class="space-y-1">
         {#each listaVendaView as o}
-        <div class={`flex items-center justify-between text-sm rounded px-1 py-0.5 transition-colors duration-700 ${flashVenda.has(o.__idx) ? 'bg-red-100 dark:bg-red-900/30' : ''}`}>
+        <div class={`flex items-center justify-between text-sm rounded px-1 py-0.5 transition-colors duration-700 cursor-pointer hover:bg-red-50 dark:hover:bg-red-900/40 ${flashVenda.has(o.__idx) ? 'bg-red-100 dark:bg-red-900/30' : ''}`} on:click={() => dispatch('selectSellOrder', { valor: o.valor, quantidade: o.quantidade })}>
           <span class="text-red-600">{formatBRL(o.valor)}</span>
           <span class="text-gray-700 dark:text-gray-200">{formatQty(o.quantidade)}</span>
         </div>

+ 5 - 2
src/routes/trading/+page.svelte

@@ -138,6 +138,7 @@ $: displayPendingSells = pendingSells.map((o) => ({
 
   let showBuyModal = false;
   let showSellModal = false;
+  let prefillBuy = null;
 
   $: selectedCommodityObj = tokens.find((t) => t.id === selectedCommodity);
   $: selectedCommodityLabel = selectedCommodityObj?.label || selectedCommodityObj?.name;
@@ -222,7 +223,9 @@ $: displayPendingSells = pendingSells.map((o) => ({
   <div class="p-4 space-y-4">
     <div class="grid grid-cols-1 md:grid-cols-3 gap-4">
       <div class="md:col-span-1">
-        <TabelaOrdens {ordensCompra} {ordensVenda} {ultimaVenda} />
+        <TabelaOrdens {ordensCompra} {ordensVenda} {ultimaVenda}
+          on:selectSellOrder={(e) => { const { valor, quantidade } = e.detail; prefillBuy = { valorSaca: valor, quantidade }; showBuyModal = true; }}
+        />
       </div>
       <div class="md:col-span-2">
         <GraficoCandlestick {dadosMock} />
@@ -230,6 +233,6 @@ $: displayPendingSells = pendingSells.map((o) => ({
     </div>
   </div>
 
-  <BoletaCompra visible={showBuyModal} onClose={() => (showBuyModal = false)} state={selectedState} commodity={selectedCommodityLabel} />
+  <BoletaCompra visible={showBuyModal} onClose={() => (showBuyModal = false)} state={selectedState} commodity={selectedCommodityLabel} prefill={prefillBuy} />
   <BoletaVenda visible={showSellModal} onClose={() => (showSellModal = false)} state={selectedState} commodity={selectedCommodityLabel} />
 </div>