Page 1 of 1

ejemplo mantenimiento dbf usando webview2

Posted: Sun Oct 06, 2024 7:20 pm
by leandro
Hola buenas tardes para todos, montamos este ejemplo en donde podemos hacer mantenimiento a la dbf customers.dbf que esta en la carpeta samples de fivewin.

La idea era poder entender el funcionamiento del webview2, para poder aplicarlo a mediano plazo en nuestras aplicaciones, esta creado en html5, css y javascript puro, para los maestros, es posible que se pueda simplificar mucho el código usado, sobre todo del lado de javascript; ya teniendo otros recursos como un servidor, podemos enlazar librerías como jquery y boostrap.

Como digo fue montado para entender el funcionamiento webview2, lo compartimos por si alguien algún día llega a necesitarlo, le interesa y quizás le sirva de guía.

Con esto lo que pretendemos es poder mejorar en MUCHO la parte visual o interfase de usuario de nuestras apps, apoyándonos en las maravillas que permite el html y sus amigos jejejeje.

Esperamos les sirva.

Pdta. Apenas nos quede un tiempito vamos a generar un reporte tipo html para ser enviado a la impresora.

Image
Image
Image

webview_custo.prg

Code: Select all | Expand

#include "FiveWin.ch"

static oWebView
static d_custo

function Main()

    Local oWnd,cHtml 

    USE "customer.dbf" ALIAS d_custo NEW EXCLUSIVE VIA "DBFCDX"
    INDEX ON d_custo->id TAG "id"
    d_custo->(OrdSetFocus("id"))
    
    cHtml := buildHtml()

    DEFINE WINDOW oWnd TITLE "Information maintenance" SIZE 1200, 800
        oWebView = TWebView2():New( oWnd )
        oWebView:SetHtml( cHtml )
        oWebView:InjectJavascript( cJavascript() )
        oWebView:bOnBind = { | cJson, cCalls | whatscoming( cJson ) }       
        //oWebView:OpenDevToolsWindow()
    ACTIVATE WINDOW oWnd CENTER ON RESIZE oWebView:SetSize( nWidth, nHeight ) VALID (d_custo->(DbCloseArea()),.T.)

    oWebView:End()

return nil

function whatscoming( cJson )
    Local oDlg,oGId,oGNm,oGAp,oGDi,oGEd,oGCi,oGSa
    Local cName, cLast,cStreet,cCity,cAge,cSalary,cIdBack
    Local nGId := 0 
    Local nGEd := 0 
    Local nGSa := 0
    Local nIdDbf := 0
    Local cGNm := space(0)
    Local cGAp := space(0)
    Local cGDi := space(0)
    Local cGCi := space(0)
    Local cIdRow := space(0)
    Local cInsRow := space(0)
    Local nAction := cJson[1]["action"]

    if nAction==1

        nGId := cJson[1]["datos"][1]
        cGNm := cJson[1]["datos"][2]
        cGAp := cJson[1]["datos"][3]
        cGDi := cJson[1]["datos"][4]
        cGCi := cJson[1]["datos"][5]
        nGEd := val(cJson[1]["datos"][6])
        nGSa := val(strtran(cJson[1]["datos"][7],",",""))
        
        DEFINE DIALOG oDlg SIZE 350,250 PIXEL TRUEPIXEL TITLE "Edit Row"
            @ 14,  15 SAY "Id :" SIZE 100,24 PIXEL OF oDlg
            @ 10,  88 GET oGId VAR nGId SIZE 50,24 PIXEL OF oDlg PICTURE "999" RIGHT

            @ 40,  15 SAY "Name :" SIZE 100,24 PIXEL OF oDlg
            @ 36,  88 GET oGNm VAR cGNm SIZE 140,24 PIXEL OF oDlg PICTURE "@N" 

            @ 66,  15 SAY "Last :" SIZE 100,24 PIXEL OF oDlg
            @ 62,  88 GET oGAp VAR cGAp SIZE 140,24 PIXEL OF oDlg PICTURE "@N" 

            @ 92,  15 SAY "Adress :" SIZE 100,24 PIXEL OF oDlg
            @ 88,  88 GET oGDi VAR cGDi SIZE 200,24 PIXEL OF oDlg PICTURE "@N" 

            @ 118,  15 SAY "City :" SIZE 100,24 PIXEL OF oDlg
            @ 114,  88 GET oGCi VAR cGCi SIZE 140,24 PIXEL OF oDlg PICTURE "@N" 

            @ 144,  15 SAY "Age :" SIZE 100,24 PIXEL OF oDlg
            @ 140,  88 GET oGEd VAR nGEd SIZE 40,24 PIXEL OF oDlg PICTURE "999" SPINNER

            @ 170,  15 SAY "Salary :" SIZE 100,24 PIXEL OF oDlg
            @ 166,  88 GET oGSa VAR nGSa SIZE 100,24 PIXEL OF oDlg PICTURE "999,999.99" RIGHT

            
            @ 220,15 BUTTONBMP OF oDlg PIXEL size 95, 24 PROMPT "Close" ACTION oDlg:End() 
            @ 220,120 BUTTONBMP OF oDlg PIXEL size 120, 24 PROMPT "Update" //ACTION oDlg:End() 
            
            oGId:disable()
            oDlg:lHelpIcon := .F.
        
        ACTIVATE DIALOG oDlg CENTERED   
    
    elseif nAction==2
        if msgnoyes("Confirm delete row ?","Confirm")
        
            nIdDbf := val(cJson[1]["datos"][1])
            
            SELECT d_custo
            DELETE FOR d_custo->id = nIdDbf
            PACK
        
            cIdRow := "row_"+alltrim(cJson[1]["datos"][1])
            oWebView:Eval( "deleterowhtmltable( '"+cIdRow+"' )" )
    
        endif
    elseif nAction==0
    
        nIdDbf := cJson[1]["datos"][1]
        cName := cJson[1]["datos"][2]
        cLast := cJson[1]["datos"][3]
        cStreet := cJson[1]["datos"][4]
        cCity := cJson[1]["datos"][5]
        cAge := val(cJson[1]["datos"][6])
        cSalary := val(cJson[1]["datos"][7])
    
        SELECT d_custo
        Dbgotop()
        if !dbseek(nIdDbf)
            dbappend()
            //d_custo->id := nIdDbf //Incremental
            d_custo->first := cName
            d_custo->last := cLast
            d_custo->street := cStreet
            d_custo->city := cCity
            d_custo->age := cAge
            d_custo->salary := cSalary
            
            cIdBack := cValtochar(d_custo->id)
            
            oWebView:Eval( "insertrowhtmltable('"+cIdBack+"','"+transform(cSalary,"999,999.99")+"');")
        else 
            //With any of these options you can inform the user that the id already exists
            
            //msginfo("The id you are trying to enter already exists","Error")
            //oWebView:Eval( "document.getElementById('spn_id').innerHTML='<br>Exists'")
            oWebView:Eval( "alert('The id you are trying to enter already exists');")
        endif
        
        
        
    endif
    
return nil

function buildHtml()

    Local cHead,cFoot 
    Local cHtml := space(0)
    Local cTable := space(0)
    
    TEXT INTO cHead
        <!DOCTYPE html>
        <html lang="es">
        <head>
            <meta charset="UTF-8">
            <style>
                body {
                    background-color: #e4f2ff;
                    display: flex;
                    flex-direction: column;
                    min-height: 100vh;
                }
                .main-content {
                    padding: 20px;
                    flex-grow: 1;
                    overflow-y: auto;
                }
                .table-container {
                    overflow-x: auto;
                }
                .table {
                    background-color: #fff;
                    min-width: 600px; /* Asegura que la tabla no se comprima demasiado en móviles */
                }
                h2 {
                    color: #0064a5;
                }
                footer {
                    background-color: #0064a5;
                    color: #fff;
                    text-align: center;
                    padding: 2rem 0;
                    margin-top: auto;
                }

                .btntbl {
                  border: none; 
                  color: white; 
                  padding: 5px 10px; 
                  cursor: pointer; 
                  border-radius: 5px; 
                }
                .primary {background-color: #007bff;} 
                .primary:hover {background: #0b7dda;}
                .secondary {background-color: #e7e7e7; color: black;} 
                .secondary:hover {background: #ddd;}
                .success {background-color: #04AA6D;} 
                .success:hover {background-color: #46a049;}
                .warning {background-color: #ff9800;} 
                .warning:hover {background: #e68a00;}
                .danger {background-color: #f44336;} 
                .danger:hover {background: #da190b;}
                
                .form-group {
                    margin-bottom: 15px;
                }

                .form-group label {
                    display: flex;
                    font-size: 16px;
                    font-weight: bold;
                    margin-bottom: 2px;
                    color: #0693e3;
                }

                .form-group input {
                    width: 90%;
                    padding: 5px;
                    font-size: 14px;
                    border-radius: 5px;
                    border: 1px solid #0693e3;
                }   

                .msg{
                    color: #f44336;
                }
                
                /* The Modal (background) */
                .modal {
                  display: none; /* Hidden by default */
                  position: fixed; /* Stay in place */
                  z-index: 1; /* Sit on top */
                  padding-top: 20px; /* Location of the box */
                  left: 0;
                  top: 0;
                  width: 100%; /* Full width */
                  height: 100%; /* Full height */
                  overflow: auto; /* Enable scroll if needed */
                  background-color: rgb(0,0,0); /* Fallback color */
                  background-color: rgba(0,0,0,0.4); /* Black w/ opacity */
                }

                /* Modal Content */
                .modal-content {
                  background-color: #fefefe;
                  margin: auto;
                  padding: 20px;
                  border: 1px solid #888;
                  width: 40%;
                }

                /* The Close Button */
                .close {
                  color: #aaaaaa;
                  float: right;
                  font-size: 28px;
                  font-weight: bold;
                }

                .close:hover,
                .close:focus {
                  color: #000;
                  text-decoration: none;
                  cursor: pointer;
                }   

                table.tableSection {
                  display: table;
                  width: 100%;
                }

                table.tableSection thead,
                table.tableSection tbody {
                  width: 100%;
                }

                table.tableSection thead {
                  overflow-y: scroll;
                  display: table;
                  table-layout: fixed;
                  width: calc(100% - 16px); /* assuming scrollbar width as 16px */
                }

                table.tableSection tbody {
                  overflow: auto;
                  height: 500px;
                  display: block;
                }

                table.tableSection tr {
                  width: 100%;
                  text-align: left;
                  display: table;
                  table-layout: fixed;
                }
                
                table.tableSection tr:hover {
                    background-color: #f8f9fa;
                }               
                
                
                
            </style>
        </head>
        <body>
            <div class="container-fluid">
                <div class="row">
                    <!-- Contenido principal -->
                    <main class="col-md-9 ms-sm-auto col-lg-10 px-md-4 main-content">
                        <!-- Trigger/Open The Modal -->
                        <button id="myBtn" onclick="openmodal();" class="btntbl success">New</button>
                        <h2 class="mb-4">Customer Table </h2>
                        <div class="table-container">
                            <table class="tableSection" id="tbl_cstm">
                                <thead>
                                    <tr>
                                        <th style="width:25px">ID</th>
                                        <th style="width:100px">Name</th>
                                        <th style="width:100px">Last</th>
                                        <th style="width:220px">Adress</th>
                                        <th>City</th>
                                        <th>Age</th>
                                        <th>Salary</th>
                                        <th colspan="2">Actions</th>
                                    </tr>
                                </thead>
                                <tbody id="tableBody">
    ENDTEXT
    
    
    TEXT INTO cFoot

                                </tbody>
                            </table>
                        </div>
                    </main>
                </div>
            </div>

            <footer>
                <p>© 2024 My App. All rights reserved.</p>
            </footer>
            
            <!-- The Modal -->
            <div id="myModal" class="modal">

              <!-- Modal content -->
              <div class="modal-content">
                <span class="close" role="button" onclick="closemodal();" title="Close Modal (Cancel)">×</span>
                <h2>Customer data</h2>
                <div id="form_data">
                    <div class="form-group">
                        <label for="id">Id:</label>
                        <input type="text" id="id" name="id" class="myinput" value="0" disabled></input>
                        <span id="spn_id" class="msg"></span>
                    </div>
                    <div class="form-group">
                        <label for="name">Name:</label>
                        <input type="text" id="name" name="name" class="myinput" >
                        <span id="spn_name" class="msg"></span>
                    </div>
                    <div class="form-group">
                        <label for="last">Last:</label>
                        <input type="text" id="last" name="last" class="myinput" >
                        <span id="spn_last" class="msg"></span>
                    </div>
                    <div class="form-group">
                        <label for="adress">Adress:</label>
                        <input type="text" id="adress" name="adress" class="myinput" >
                        <span id="spn_adress" class="msg"></span>
                    </div>
                    <div class="form-group">
                        <label for="city">City:</label>
                        <input type="text" id="city" name="city" class="myinput" >
                        <span id="spn_city" class="msg"></span>
                    </div>
                    <div class="form-group">
                        <label for="age">Age:</label>
                        <input type="number" id="age" name="age" class="myinput" >
                        <span id="spn_age" class="msg"></span>
                    </div>
                    <div class="form-group">
                        <label for="salary">Salary:</label>
                        <input type="number" id="salary" name="salary" class="myinput" >
                        <span id="spn_salary" class="msg"></span>
                    </div>
                    <div class="form-group" >
                        <button type="submit" class="btntbl success" onclick="newdata();">Acept</button>
                    </div>

                </div>
              </div>

            </div>  

        </body>
        </html> 
    ENDTEXT 

    SELECT d_custo
    Dbgotop()   
    Do While !EOF()
        
        cTable += "<tr id='row_"+cValtochar(d_custo->id)+"'>"
            cTable += "<td style='width:25px'>"+transform(d_custo->id,"999")+"</td>"
            cTable += "<td style='width:100px'>"+alltrim(d_custo->first)+"</td>"
            cTable += "<td style='width:100px'>"+alltrim(d_custo->last)+"</td>"
            cTable += "<td style='width:220px'>"+alltrim(d_custo->street)+"</td>"
            cTable += "<td>"+alltrim(d_custo->city)+"</td>"
            cTable += "<td>"+transform(d_custo->age,"999")+"</td>"
            cTable += "<td align='right'>"+transform(d_custo->salary,"999,999.99")+"</td>"
            cTable += "<td>"
                cTable += "<button onclick='how("+cValtochar(d_custo->id)+",1)' title='Edit' class='btntbl primary'>Edit</button>"
            cTable += "</td>"
            cTable += "<td>"
                cTable += "<button onclick='how("+cValtochar(d_custo->id)+",2)' title='Delete' class='btntbl danger'>Delete</button>"
            cTable += "</td>"
        cTable += "</tr>"
        d_custo->(DBSKIP())

    EndDo   
    
    cHtml := cHead+cTable+cFoot


return cHtml

function cJavascript()
    Local cInyec
    TEXT INTO cInyec
        function how(id,acc){
            var id_row = "row_"+id;
            var therow = document.getElementById(id_row);
            var aDatos = new Array();
            var objeto = { action : 0 ,id : "", datos : []};
            var elementsrow = therow.getElementsByTagName("td");
            for(i=0;i<7;i++){
                aDatos.push(elementsrow[i].innerHTML);
            }           
            objeto.action = acc;
            objeto.id = id;
            objeto.datos = aDatos;
            SendToFWH(objeto);  
        }
        
        function openmodal(){
            var lamodal = document.getElementById("myModal");
            lamodal.style.display = "block";
        }
        
        function closemodal(){
            var lamodal = document.getElementById("myModal");
            lamodal.style.display = "none";
        }
        
        function newdata(){
            var id_row = "row_0";
            var aDatos = new Array();
            var objeto = { action : 0 ,id : 0, datos : []};
            var aErrores = new Array();
            
            var theform = document.getElementById("form_data");
            var theinputs = theform.getElementsByTagName("input");
            for(i=0;i<theinputs.length;i++){
                
                var idname = theinputs[i].id;
                var id_span = "spn_"+idname;
                var oSpan = document.getElementById(id_span);
                if(theinputs[i].value==""){
                    var cErro = "Please input "+idname;
                    aErrores.push(cErro);
                    oSpan.innerHTML = cErro;
                }else{
                    oSpan.innerHTML = "";
                }           
            }
            
            if (aErrores.length==0){
                aDatos.push(document.getElementById("id").value);
                aDatos.push(document.getElementById("name").value);
                aDatos.push(document.getElementById("last").value);
                aDatos.push(document.getElementById("adress").value);
                aDatos.push(document.getElementById("city").value);
                aDatos.push(document.getElementById("age").value);
                aDatos.push(document.getElementById("salary").value);
                objeto.datos = aDatos;
                SendToFWH(objeto);  
            }
        }

        function deleterowhtmltable(id){
            var idrowdel = document.getElementById(id);
            idrowdel.remove();
        }

        function insertrowhtmltable(idDbf,cSal){
            var cIdRow = "row_"+idDbf;
            var tbldata = document.getElementById("tbl_cstm").insertRow(-1);
            tbldata.setAttribute("id", cIdRow );
            var oCol1 = tbldata.insertCell(0);
            var oCol2 = tbldata.insertCell(1);
            var oCol3 = tbldata.insertCell(2);
            var oCol4 = tbldata.insertCell(3);
            var oCol5 = tbldata.insertCell(4);
            var oCol6 = tbldata.insertCell(5);
            var oCol7 = tbldata.insertCell(6);
            var oCol8 = tbldata.insertCell(7);
            var oCol9 = tbldata.insertCell(8);

            oCol1.innerHTML = idDbf;
            oCol1.style.width = "25px";
            oCol2.innerHTML = document.getElementById("name").value;
            oCol2.style.width = "100px";
            oCol3.innerHTML = document.getElementById("last").value;
            oCol3.style.width = "100px";
            oCol4.innerHTML = document.getElementById("adress").value;
            oCol4.style.width = "220px";
            oCol5.innerHTML = document.getElementById("city").value;
            oCol6.innerHTML = document.getElementById("age").value;
            oCol7.innerHTML = cSal;
            oCol7.setAttribute("align", "right");
            
            oCol8.innerHTML = "<button onclick='how("+idDbf+",1)' title='Edit' class='btntbl primary'>Edit</button>";
            oCol9.innerHTML = "<button onclick='how("+idDbf+",2)' title='Delete' class='btntbl danger'>Delete</button>";

            location.hash = "#"+cIdRow;
            
            closemodal();
        
        }

    ENDTEXT

Return cInyec
 

Re: ejemplo mantenimiento dbf usando webview2

Posted: Mon Oct 07, 2024 3:09 am
by Antonio Linares
muy bien! :-)

Re: ejemplo mantenimiento dbf usando webview2

Posted: Mon Oct 07, 2024 2:28 pm
by cpheraclio
Application
===========
Path and name: C:\Users\Admin\Documents\fwh64\proyects\ContaSic.exe (64 bits)
Size: 8,997,888 bytes
Compiler version: Harbour 3.2.0dev (r2407221137)
FiveWin version: FWH 24.07
C compiler version: Microsoft Visual C 19.32.31329 (64-bit)
Windows 11 64 Bits, version: 6.2, Build 9200

Time from start: 0 hours 0 mins 3 secs
Error occurred at: 07/10/24, 08:24:32
Error description: Error BASE/1070 Error de argumento: ==
Args:
[ 1] = N 0
[ 2] = P 0x2682DD5DD18

Stack Calls
===========
Called from: .\source\classes\twebview2.prg => (b)WEBVIEW2_ONEVAL( 0 )
Called from: .\source\ContaSic.prg => ASCAN( 0 )
Called from: .\source\classes\twebview2.prg => WEBVIEW2_ONEVAL( 0 )
Called from: .\source\classes\window.prg => WINRUN( 0 )
Called from: .\source\classes\window.prg => TWINDOW:ACTIVATE( 0 )
Called from: .\source\ContaSic.prg => MAIN( 43 )

Re: ejemplo mantenimiento dbf usando webview2

Posted: Mon Oct 07, 2024 7:13 pm
by cpheraclio
Modificando twebview2

//----------------------------------------------------------------------------//

//function WebView2_OnEval( cJson, hWebView )
//
// local nAt := AScan( aWebViews, { | o | o:hWebView == hWebView } ), nResult
//
// if nAt != 0 .and. ! Empty( aWebViews[ nAt ]:bOnEval )
// nResult = Eval( aWebViews[ nAt ]:bOnEval, cJson, hWebView )
// endif
//
//return nResult

function WebView2_OnEval( cJson, hWebView )

local nAt := AScan( aWebViews, { | o | MsgInfo( o:hWebView ), MsgInfo( hWebView ), o:hWebView == hWebView } ), nResult

if nAt != 0 .and. ! Empty( aWebViews[ nAt ]:bOnEval )
nResult = Eval( aWebViews[ nAt ]:bOnEval, cJson, hWebView )
endif

return nResult


Con el ejemplo de Leandro
Application
===========
Path and name: C:\Users\Admin\Documents\fwh64\proyects\ContaSic.exe (64 bits)
Size: 8,997,376 bytes
Compiler version: Harbour 3.2.0dev (r2407221137)
FiveWin version: FWH 24.07
C compiler version: Microsoft Visual C 19.32.31329 (64-bit)
Windows 11 64 Bits, version: 6.2, Build 9200

Time from start: 0 hours 0 mins 6 secs
Error occurred at: 07/10/24, 12:50:31
Error description: Error BASE/1070 Error de argumento: ==
Args:
[ 1] = N 0
[ 2] = P 0x220A5201928

Stack Calls
===========
Called from: .\source\twebview2.prg => (b)WEBVIEW2_ONEVAL( 138 )
Called from: .\source\ContaSic.prg => ASCAN( 0 )
Called from: .\source\twebview2.prg => WEBVIEW2_ONEVAL( 138 )
Called from: .\source\classes\window.prg => WINRUN( 0 )
Called from: .\source\classes\window.prg => TWINDOW:ACTIVATE( 0 )
Called from: .\source\ContaSic.prg => MAIN( 43 )

Re: ejemplo mantenimiento dbf usando webview2

Posted: Mon Oct 07, 2024 7:35 pm
by leandro
Hola buenas tardes, gracias por reportarlo, creo que únicamente funciona con la nueva versión de fw 2409, el error ya lo estamos intentando solucionar en otro POST, con la ayuda de Antonio.

https://forums.fivetechsupport.com/view ... a7#p274391

Re: ejemplo mantenimiento dbf usando webview2

Posted: Mon Oct 07, 2024 8:11 pm
by cpheraclio
leandro wrote:Hola buenas tardes, gracias por reportarlo, creo que únicamente funciona con la nueva versión de fw 2409, el error ya lo estamos intentando solucionar en otro POST, con la ayuda de Antonio.

https://forums.fivetechsupport.com/view ... d3#p274391
Buenas tardes:

Es con la versión 64-2409 (fue Lib que me pasó Antonio Linares), no tengo idea de porque aparece 64-2407

Sigo al pendiente de la solución, gracias.

Re: ejemplo mantenimiento dbf usando webview2

Posted: Tue Oct 08, 2024 3:47 am
by Antonio Linares
> Es con la versión 64-2409 (fue Lib que me pasó Antonio Linares), no tengo idea de porque aparece 64-2407

La versión la toma de FiveWin.ch

Re: ejemplo mantenimiento dbf usando webview2

Posted: Tue Oct 08, 2024 11:41 am
by cpheraclio
Antonio Linares wrote:> Es con la versión 64-2409 (fue Lib que me pasó Antonio Linares), no tengo idea de porque aparece 64-2407

La versión la toma de FiveWin.ch
Contenido de fivewin.ch

/*
!short: FiveWin main Header File */

#ifndef _FIVEWIN_CH
#define _FIVEWIN_CH

#define FWCOPYRIGHT "(c) FiveTech Software, 1993-2023"

#define FWVERSION "FWH 24.09"
#define FW_VersionNo 24090

#ifdef __XHARBOUR__
#ifndef __64__
#define FWDESCRIPTION "FiveWin for xHarbour"
#else
#define FWDESCRIPTION "FiveWin for xHarbour 64"
#endif
#else
#ifndef __64__
#define FWDESCRIPTION "FiveWin for Harbour"
#else
#define FWDESCRIPTION "FiveWin for Harbour 64"
#endif
#endif

Re: ejemplo mantenimiento dbf usando webview2

Posted: Tue Oct 08, 2024 11:42 am
by acuellar
Gracias Leandro

Funciona Perfecto.

Faltaría lo de la actualización de los datos

Re: ejemplo mantenimiento dbf usando webview2

Posted: Wed Oct 09, 2024 6:40 pm
by leandro
Adhemar buenas tardes como estas?

Vale, lo reviso y la publico.

Re: ejemplo mantenimiento dbf usando webview2

Posted: Fri Oct 11, 2024 10:07 pm
by leandro
Listo Adhemar ya quedo, con la actualización del registro. Que pena habia colocado la versión que no era. :oops:

Code: Select all | Expand

#include "FiveWin.ch"

static oWebView
static d_custo

function Main()

    Local oWnd,cHtml 

    USE "customer.dbf" ALIAS d_custo NEW EXCLUSIVE VIA "DBFCDX"
    INDEX ON d_custo->id TAG "id"
    d_custo->(OrdSetFocus("id"))
    
    cHtml := buildHtml()

    DEFINE WINDOW oWnd TITLE "Information maintenance" SIZE 1200, 800
        oWebView = TWebView2():New( oWnd )
        oWebView:SetHtml( cHtml )
        oWebView:InjectJavascript( cJavascript() )
        oWebView:bOnBind = { | cJson, cCalls | whatscoming( cJson ) }       
        oWebView:OpenDevToolsWindow()
    ACTIVATE WINDOW oWnd CENTER ON RESIZE oWebView:SetSize( nWidth, nHeight ) VALID (d_custo->(DbCloseArea()),.T.)

    oWebView:End()

return nil

function whatscoming( cJson )
    Local oDlg,oGId,oGNm,oGAp,oGDi,oGEd,oGCi,oGSa
    Local cName, cLast,cStreet,cCity,cAge,cSalary,cIdBack
    Local nGId := 0 
    Local nGEd := 0 
    Local nGSa := 0
    Local nIdDbf := 0
    Local cGNm := space(0)
    Local cGAp := space(0)
    Local cGDi := space(0)
    Local cGCi := space(0)
    Local cIdRow := space(0)
    Local cInsRow := space(0)
    Local nAction := cJson[1]["action"]
    Local bUpdateRow := <||
    
        SELECT d_custo
        Dbgotop()
        if dbseek(nGId)
            d_custo->first := cGNm
            d_custo->last := cGAp
            d_custo->street := cGDi
            d_custo->city := cGCi
            d_custo->age := nGEd
            d_custo->salary := nGSa
            
            //oWebView:Eval( "alert('listo en la dbf');")
            oWebView:Eval( "updaterowhtmltable('"+cValtochar(nGId)+"','"+cGNm+"','"+cGAp+"','"+cGDi+"','"+cGCi+"','"+cValtochar(nGEd)+"','"+transform(nGSa,"999,999.99")+"');")
        endif 
        
        oDlg:end()
        
    >
    
    Local bComplete := <|cCnd,nLen|
        Local cCmp := alltrim(cCnd)
        Local nLac := len(cCmp)
        cCmp += space(nLen-nLac)
        return cCmp
    >
    
    if nAction==1

        nGId := val(cJson[1]["datos"][1])
        cGNm := EVAL(bComplete,cJson[1]["datos"][2],20)
        cGAp := EVAL(bComplete,cJson[1]["datos"][3],20)
        cGDi := EVAL(bComplete,cJson[1]["datos"][4],30)
        cGCi := EVAL(bComplete,cJson[1]["datos"][5],30)
        nGEd := val(cJson[1]["datos"][6])
        nGSa := val(strtran(cJson[1]["datos"][7],",",""))
        
        DEFINE DIALOG oDlg SIZE 350,250 PIXEL TRUEPIXEL TITLE "Edit Row"
            @ 14,  15 SAY "Id :" SIZE 100,24 PIXEL OF oDlg
            @ 10,  88 GET oGId VAR nGId SIZE 50,24 PIXEL OF oDlg PICTURE "999" RIGHT

            @ 40,  15 SAY "Name :" SIZE 100,24 PIXEL OF oDlg
            @ 36,  88 GET oGNm VAR cGNm SIZE 140,24 PIXEL OF oDlg PICTURE "@N" 

            @ 66,  15 SAY "Last :" SIZE 100,24 PIXEL OF oDlg
            @ 62,  88 GET oGAp VAR cGAp SIZE 140,24 PIXEL OF oDlg PICTURE "@N" 

            @ 92,  15 SAY "Adress :" SIZE 100,24 PIXEL OF oDlg
            @ 88,  88 GET oGDi VAR cGDi SIZE 200,24 PIXEL OF oDlg PICTURE "@N" 

            @ 118,  15 SAY "City :" SIZE 100,24 PIXEL OF oDlg
            @ 114,  88 GET oGCi VAR cGCi SIZE 140,24 PIXEL OF oDlg PICTURE "@N" 

            @ 144,  15 SAY "Age :" SIZE 100,24 PIXEL OF oDlg
            @ 140,  88 GET oGEd VAR nGEd SIZE 40,24 PIXEL OF oDlg PICTURE "99" SPINNER

            @ 170,  15 SAY "Salary :" SIZE 100,24 PIXEL OF oDlg
            @ 166,  88 GET oGSa VAR nGSa SIZE 100,24 PIXEL OF oDlg PICTURE "999,999.99" RIGHT

            
            @ 220,15 BUTTONBMP OF oDlg PIXEL size 95, 24 PROMPT "Close" ACTION oDlg:End() 
            @ 220,120 BUTTONBMP OF oDlg PIXEL size 120, 24 PROMPT "Update" ACTION EVAL(bUpdateRow) 
            
            oGId:disable()
            oDlg:lHelpIcon := .F.
        
        ACTIVATE DIALOG oDlg CENTERED   
    
    elseif nAction==2
        if msgnoyes("Confirm delete row ?","Confirm")
        
            nIdDbf := val(cJson[1]["datos"][1])
            
            SELECT d_custo
            DELETE FOR d_custo->id = nIdDbf
            PACK
        
            cIdRow := "row_"+alltrim(cJson[1]["datos"][1])
            oWebView:Eval( "deleterowhtmltable( '"+cIdRow+"' )" )
    
        endif
    elseif nAction==0
    
        nIdDbf := cJson[1]["datos"][1]
        cName := cJson[1]["datos"][2]
        cLast := cJson[1]["datos"][3]
        cStreet := cJson[1]["datos"][4]
        cCity := cJson[1]["datos"][5]
        cAge := val(cJson[1]["datos"][6])
        cSalary := val(cJson[1]["datos"][7])
    
        SELECT d_custo
        Dbgotop()
        if !dbseek(nIdDbf)
            dbappend()
            //d_custo->id := nIdDbf //Incremental
            d_custo->first := cName
            d_custo->last := cLast
            d_custo->street := cStreet
            d_custo->city := cCity
            d_custo->age := cAge
            d_custo->salary := cSalary
            
            cIdBack := cValtochar(d_custo->id)
            
            oWebView:Eval( "insertrowhtmltable('"+cIdBack+"','"+transform(cSalary,"999,999.99")+"');")
        else 
            //With any of these options you can inform the user that the id already exists
            
            //msginfo("The id you are trying to enter already exists","Error")
            //oWebView:Eval( "document.getElementById('spn_id').innerHTML='<br>Exists'")
            oWebView:Eval( "alert('The id you are trying to enter already exists');")
        endif
        
        
        
    endif
    
return nil

function buildHtml()

    Local cHead,cFoot 
    Local cHtml := space(0)
    Local cTable := space(0)
    
    TEXT INTO cHead
        <!DOCTYPE html>
        <html lang="es">
        <head>
            <meta charset="UTF-8">
            <style>
                body {
                    background-color: #e4f2ff;
                    display: flex;
                    flex-direction: column;
                    min-height: 100vh;
                }
                .main-content {
                    padding: 20px;
                    flex-grow: 1;
                    overflow-y: auto;
                }
                .table-container {
                    overflow-x: auto;
                }
                .table {
                    background-color: #fff;
                    min-width: 600px; /* Asegura que la tabla no se comprima demasiado en móviles */
                }
                h2 {
                    color: #0064a5;
                }
                footer {
                    background-color: #0064a5;
                    color: #fff;
                    text-align: center;
                    padding: 2rem 0;
                    margin-top: auto;
                }

                .btntbl {
                  border: none; 
                  color: white; 
                  padding: 5px 10px; 
                  cursor: pointer; 
                  border-radius: 5px; 
                }
                .primary {background-color: #007bff;} 
                .primary:hover {background: #0b7dda;}
                .secondary {background-color: #e7e7e7; color: black;} 
                .secondary:hover {background: #ddd;}
                .success {background-color: #04AA6D;} 
                .success:hover {background-color: #46a049;}
                .warning {background-color: #ff9800;} 
                .warning:hover {background: #e68a00;}
                .danger {background-color: #f44336;} 
                .danger:hover {background: #da190b;}
                
                .form-group {
                    margin-bottom: 15px;
                }

                .form-group label {
                    display: flex;
                    font-size: 16px;
                    font-weight: bold;
                    margin-bottom: 2px;
                    color: #0693e3;
                }

                .form-group input {
                    width: 90%;
                    padding: 5px;
                    font-size: 14px;
                    border-radius: 5px;
                    border: 1px solid #0693e3;
                }   

                .msg{
                    color: #f44336;
                }
                
                /* The Modal (background) */
                .modal {
                  display: none; /* Hidden by default */
                  position: fixed; /* Stay in place */
                  z-index: 1; /* Sit on top */
                  padding-top: 20px; /* Location of the box */
                  left: 0;
                  top: 0;
                  width: 100%; /* Full width */
                  height: 100%; /* Full height */
                  overflow: auto; /* Enable scroll if needed */
                  background-color: rgb(0,0,0); /* Fallback color */
                  background-color: rgba(0,0,0,0.4); /* Black w/ opacity */
                }

                /* Modal Content */
                .modal-content {
                  background-color: #fefefe;
                  margin: auto;
                  padding: 20px;
                  border: 1px solid #888;
                  width: 40%;
                }

                /* The Close Button */
                .close {
                  color: #aaaaaa;
                  float: right;
                  font-size: 28px;
                  font-weight: bold;
                }

                .close:hover,
                .close:focus {
                  color: #000;
                  text-decoration: none;
                  cursor: pointer;
                }   

                table.tableSection {
                  display: table;
                  width: 100%;
                }

                table.tableSection thead,
                table.tableSection tbody {
                  width: 100%;
                }

                table.tableSection thead {
                  overflow-y: scroll;
                  display: table;
                  table-layout: fixed;
                  width: calc(100% - 16px); /* assuming scrollbar width as 16px */
                }

                table.tableSection tbody {
                  overflow: auto;
                  height: 500px;
                  display: block;
                }

                table.tableSection tr {
                  width: 100%;
                  text-align: left;
                  display: table;
                  table-layout: fixed;
                }
                
                table.tableSection tr:hover {
                    background-color: #f8f9fa;
                }               
                
                
                
            </style>
        </head>
        <body>
            <div class="container-fluid">
                <div class="row">
                    <!-- Contenido principal -->
                    <main class="col-md-9 ms-sm-auto col-lg-10 px-md-4 main-content">
                        <!-- Trigger/Open The Modal -->
                        <button id="myBtn" onclick="openmodal();" class="btntbl success">New</button>
                        <h2 class="mb-4">Customer Table </h2>
                        <div class="table-container">
                            <table class="tableSection" id="tbl_cstm">
                                <thead>
                                    <tr>
                                        <th style="width:25px">ID</th>
                                        <th style="width:100px">Name</th>
                                        <th style="width:100px">Last</th>
                                        <th style="width:220px">Adress</th>
                                        <th>City</th>
                                        <th>Age</th>
                                        <th>Salary</th>
                                        <th colspan="2">Actions</th>
                                    </tr>
                                </thead>
                                <tbody id="tableBody">
    ENDTEXT
    
    
    TEXT INTO cFoot

                                </tbody>
                            </table>
                        </div>
                    </main>
                </div>
            </div>

            <footer>
                <p>© 2024 My App. All rights reserved.</p>
            </footer>
            
            <!-- The Modal -->
            <div id="myModal" class="modal">

              <!-- Modal content -->
              <div class="modal-content">
                <span class="close" role="button" onclick="closemodal();" title="Close Modal (Cancel)">×</span>
                <h2>Customer data</h2>
                <div id="form_data">
                    <div class="form-group">
                        <label for="id">Id:</label>
                        <input type="text" id="id" name="id" class="myinput" value="0" disabled></input>
                        <span id="spn_id" class="msg"></span>
                    </div>
                    <div class="form-group">
                        <label for="name">Name:</label>
                        <input type="text" id="name" name="name" class="myinput" size="20">
                        <span id="spn_name" class="msg"></span>
                    </div>
                    <div class="form-group">
                        <label for="last">Last:</label>
                        <input type="text" id="last" name="last" class="myinput" size="20">
                        <span id="spn_last" class="msg"></span>
                    </div>
                    <div class="form-group">
                        <label for="adress">Adress:</label>
                        <input type="text" id="adress" name="adress" class="myinput" size="30">
                        <span id="spn_adress" class="msg"></span>
                    </div>
                    <div class="form-group">
                        <label for="city">City:</label>
                        <input type="text" id="city" name="city" class="myinput" size="30">
                        <span id="spn_city" class="msg"></span>
                    </div>
                    <div class="form-group">
                        <label for="age">Age:</label>
                        <input type="number" id="age" name="age" class="myinput" size="2">
                        <span id="spn_age" class="msg"></span>
                    </div>
                    <div class="form-group">
                        <label for="salary">Salary:</label>
                        <input type="number" id="salary" name="salary" class="myinput" size="9">
                        <span id="spn_salary" class="msg"></span>
                    </div>
                    <div class="form-group" >
                        <button type="submit" class="btntbl success" onclick="newdata();">Acept</button>
                    </div>

                </div>
              </div>

            </div>  

        </body>
        </html> 
    ENDTEXT 

    SELECT d_custo
    Dbgotop()   
    Do While !EOF()
        
        cTable += "<tr id='row_"+cValtochar(d_custo->id)+"'>"
            cTable += "<td style='width:25px'>"+transform(d_custo->id,"999")+"</td>"
            cTable += "<td style='width:100px'>"+alltrim(d_custo->first)+"</td>"
            cTable += "<td style='width:100px'>"+alltrim(d_custo->last)+"</td>"
            cTable += "<td style='width:220px'>"+alltrim(d_custo->street)+"</td>"
            cTable += "<td>"+alltrim(d_custo->city)+"</td>"
            cTable += "<td>"+transform(d_custo->age,"999")+"</td>"
            cTable += "<td align='right'>"+transform(d_custo->salary,"999,999.99")+"</td>"
            cTable += "<td>"
                cTable += "<button onclick='how("+cValtochar(d_custo->id)+",1)' title='Edit' class='btntbl primary'>Edit</button>"
            cTable += "</td>"
            cTable += "<td>"
                cTable += "<button onclick='how("+cValtochar(d_custo->id)+",2)' title='Delete' class='btntbl danger'>Delete</button>"
            cTable += "</td>"
        cTable += "</tr>"
        d_custo->(DBSKIP())

    EndDo   
    
    cHtml := cHead+cTable+cFoot


return cHtml

function cJavascript()
    Local cInyec
    TEXT INTO cInyec
        function how(id,acc){
            var id_row = "row_"+id;
            var therow = document.getElementById(id_row);
            var aDatos = new Array();
            var objeto = { action : 0 ,id : "", datos : []};
            var elementsrow = therow.getElementsByTagName("td");
            for(i=0;i<7;i++){
                aDatos.push(elementsrow[i].innerHTML);
            }           
            objeto.action = acc;
            objeto.id = id;
            objeto.datos = aDatos;
            SendToFWH(objeto);  
        }
        
        function openmodal(){
            var lamodal = document.getElementById("myModal");
            lamodal.style.display = "block";
        }
        
        function closemodal(){
            var lamodal = document.getElementById("myModal");
            lamodal.style.display = "none";
        }
        
        function newdata(){
            var id_row = "row_0";
            var aDatos = new Array();
            var objeto = { action : 0 ,id : 0, datos : []};
            var aErrores = new Array();
            
            var theform = document.getElementById("form_data");
            var theinputs = theform.getElementsByTagName("input");
            for(i=0;i<theinputs.length;i++){
                
                var idname = theinputs[i].id;
                var id_span = "spn_"+idname;
                var oSpan = document.getElementById(id_span);
                if(theinputs[i].value==""){
                    var cErro = "Please input "+idname;
                    aErrores.push(cErro);
                    oSpan.innerHTML = cErro;
                }else{
                    oSpan.innerHTML = "";
                }           
            }
            
            if (aErrores.length==0){
                aDatos.push(document.getElementById("id").value);
                aDatos.push(document.getElementById("name").value);
                aDatos.push(document.getElementById("last").value);
                aDatos.push(document.getElementById("adress").value);
                aDatos.push(document.getElementById("city").value);
                aDatos.push(document.getElementById("age").value);
                aDatos.push(document.getElementById("salary").value);
                objeto.datos = aDatos;
                SendToFWH(objeto);  
            }
        }

        function deleterowhtmltable(id){
            var idrowdel = document.getElementById(id);
            idrowdel.remove();
        }

        function insertrowhtmltable(idDbf,cSal){
            var cIdRow = "row_"+idDbf;
            var tbldata = document.getElementById("tbl_cstm").insertRow(-1);
            tbldata.setAttribute("id", cIdRow );
            var oCol1 = tbldata.insertCell(0);
            var oCol2 = tbldata.insertCell(1);
            var oCol3 = tbldata.insertCell(2);
            var oCol4 = tbldata.insertCell(3);
            var oCol5 = tbldata.insertCell(4);
            var oCol6 = tbldata.insertCell(5);
            var oCol7 = tbldata.insertCell(6);
            var oCol8 = tbldata.insertCell(7);
            var oCol9 = tbldata.insertCell(8);

            oCol1.innerHTML = idDbf;
            oCol1.style.width = "25px";
            oCol2.innerHTML = document.getElementById("name").value;
            oCol2.style.width = "100px";
            oCol3.innerHTML = document.getElementById("last").value;
            oCol3.style.width = "100px";
            oCol4.innerHTML = document.getElementById("adress").value;
            oCol4.style.width = "220px";
            oCol5.innerHTML = document.getElementById("city").value;
            oCol6.innerHTML = document.getElementById("age").value;
            oCol7.innerHTML = cSal;
            oCol7.setAttribute("align", "right");
            
            oCol8.innerHTML = "<button onclick='how("+idDbf+",1)' title='Edit' class='btntbl primary'>Edit</button>";
            oCol9.innerHTML = "<button onclick='how("+idDbf+",2)' title='Delete' class='btntbl danger'>Delete</button>";

            location.hash = "#"+cIdRow;
            
            closemodal();
        
        }
        
        function updaterowhtmltable(idDbf,cNm,cLs,cSt,cCt,cEd,cSal){
            var id_row = "row_"+idDbf;
            var therow = document.getElementById(id_row);
            var elementsrow = therow.getElementsByTagName("td");

            elementsrow[1].innerHTML = cNm;
            elementsrow[2].innerHTML = cLs;
            elementsrow[3].innerHTML = cSt;
            elementsrow[4].innerHTML = cCt;
            elementsrow[5].innerHTML = cEd;
            elementsrow[6].innerHTML = cSal;
        }
        
        

    ENDTEXT

Return cInyec