diff --git a/cmd/widgetwasm/main.go b/cmd/widgetwasm/main.go
index 931c4d1..222aa6f 100644
--- a/cmd/widgetwasm/main.go
+++ b/cmd/widgetwasm/main.go
@@ -3,6 +3,7 @@
package main
import (
+ "net/url"
"regexp"
"strings"
"syscall/js"
@@ -23,12 +24,128 @@ func main() {
js.Global().Set("__eli_nps_wasm_decidir", js.FuncOf(decidir))
js.Global().Set("__eli_nps_wasm_cooldown_ativo", js.FuncOf(cooldownAtivo))
js.Global().Set("__eli_nps_wasm_set_cooldown", js.FuncOf(setCooldown))
+ js.Global().Set("__eli_nps_wasm_painel_init", js.FuncOf(painelInit))
js.Global().Set("__eli_nps_wasm_ready", true)
// Mantém o módulo vivo.
select {}
}
+func painelInit(this js.Value, args []js.Value) any {
+ // Painel: persistência de filtros no localStorage.
+ // Regras (.agent): lógica no WASM (Go). Aqui é best-effort e fail-open.
+ //
+ // - Salva: produto selecionado + checkbox "baixas".
+ // - Restaura: se a URL não tiver parâmetros e houver valor salvo,
+ // redireciona para /painel?produto=...&baixas=1.
+ //
+ // Importante: não roda fora do /painel.
+ loc := js.Global().Get("location")
+ if loc.IsUndefined() || loc.IsNull() {
+ return nil
+ }
+ path := loc.Get("pathname").String()
+ if path == "" || !strings.HasPrefix(path, "/painel") {
+ return nil
+ }
+
+ storage := js.Global().Get("localStorage")
+ if storage.IsUndefined() || storage.IsNull() {
+ return nil
+ }
+
+ const keyProd = "eli_nps_painel_produto"
+ const keyBaixas = "eli_nps_painel_baixas"
+
+ // Aguarda o DOM estar pronto para conseguirmos acessar o form/option list.
+ doc := js.Global().Get("document")
+ if doc.IsUndefined() || doc.IsNull() {
+ return nil
+ }
+
+ handler := js.FuncOf(func(this js.Value, args []js.Value) any {
+ // Best-effort: evita exceptions se APIs não existirem.
+ defer func() { _ = recover() }()
+
+ form := doc.Call("querySelector", `form[action="/painel"]`)
+ if form.IsUndefined() || form.IsNull() {
+ return nil
+ }
+
+ sel := form.Call("querySelector", `select[name="produto"]`)
+ chk := form.Call("querySelector", `input[name="baixas"]`)
+
+ // Helper: verifica se option existe.
+ optionExists := func(selectEl js.Value, value string) bool {
+ if selectEl.IsUndefined() || selectEl.IsNull() {
+ return false
+ }
+ opts := selectEl.Get("options")
+ ln := opts.Get("length").Int()
+ for i := 0; i < ln; i++ {
+ opt := opts.Index(i)
+ if opt.Get("value").String() == value {
+ return true
+ }
+ }
+ return false
+ }
+
+ persist := func() {
+ if !sel.IsUndefined() && !sel.IsNull() {
+ v := strings.TrimSpace(sel.Get("value").String())
+ if v != "" {
+ storage.Call("setItem", keyProd, v)
+ }
+ }
+ baixas := "0"
+ if !chk.IsUndefined() && !chk.IsNull() && chk.Get("checked").Truthy() {
+ baixas = "1"
+ }
+ storage.Call("setItem", keyBaixas, baixas)
+ }
+
+ // Restaura/redirect apenas se não há query string.
+ s := loc.Get("search").String()
+ if strings.TrimSpace(s) == "" {
+ storedProd := strings.TrimSpace(storage.Call("getItem", keyProd).String())
+ storedBaixas := strings.TrimSpace(storage.Call("getItem", keyBaixas).String())
+ if storedProd != "" && optionExists(sel, storedProd) {
+ q := "?produto=" + url.QueryEscape(storedProd)
+ if storedBaixas == "1" {
+ q += "&baixas=1"
+ }
+ loc.Call("replace", path+q)
+ return nil
+ }
+ // Se só baixas estiver setado, aplica também.
+ if storedBaixas == "1" {
+ loc.Call("replace", path+"?baixas=1")
+ return nil
+ }
+ }
+
+ // Liga listeners para persistência.
+ onSubmit := js.FuncOf(func(this js.Value, args []js.Value) any { persist(); return nil })
+ onChange := js.FuncOf(func(this js.Value, args []js.Value) any { persist(); return nil })
+ form.Call("addEventListener", "submit", onSubmit)
+ form.Call("addEventListener", "change", onChange)
+
+ return nil
+ })
+
+ // DOMContentLoaded
+ readyState := doc.Get("readyState").String()
+ if readyState != "loading" {
+ // Se o WASM foi carregado depois do DOM pronto (comum no painel),
+ // rodamos imediatamente.
+ handler.Invoke()
+ } else {
+ doc.Call("addEventListener", "DOMContentLoaded", handler)
+ }
+ return nil
+}
+
func cooldownAtivo(this js.Value, args []js.Value) any {
if len(args) < 1 {
return false
diff --git a/internal/elinps/painel.go b/internal/elinps/painel.go
index 5f997d4..690617b 100644
--- a/internal/elinps/painel.go
+++ b/internal/elinps/painel.go
@@ -321,6 +321,10 @@ th,td{padding:8px;border-bottom:1px solid #eee;text-align:left;vertical-align:to
b.WriteString("")
+ // JS do painel: apenas bootstrap para executar a lógica no WASM.
+ // Regras (.agent): sem dependências externas. A lógica fica no WASM.
+ b.WriteString(``)
+
b.WriteString("