added url on/off and css styles (#66)

* added basic styles css

* added toggle on/off for URL

* added loggedinuser check

* minor changes

* minor changes v2

* minor changes v3

* chore: stylistic fixes

---------

Co-authored-by: Giorgi Lekveishvili <lekva@gl-mbp-m1-max.local>
diff --git a/apps/url-shortener/index.html b/apps/url-shortener/index.html
index 15eee68..5861daf 100644
--- a/apps/url-shortener/index.html
+++ b/apps/url-shortener/index.html
@@ -1,42 +1,59 @@
 <!DOCTYPE html>
 <html lang="en">
-
 <head>
     <meta charset="UTF-8">
     <meta name="viewport" content="width=device-width, initial-scale=1.0">
     <title>URL Shortener</title>
+    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@picocss/pico@1/css/pico.min.css">
 </head>
-
 <body>
     <h1>URL Shortener</h1>
-
     <form action="/" method="post">
         <label for="address">Address:</label>
         <input type="text" id="address" name="address" required>
-
         <label for="custom">Custom Name (optional):</label>
         <input type="text" id="custom" name="custom">
-
         <button type="submit">Shorten URL</button>
     </form>
-
     <h2>Named Addresses:</h2>
     <table>
         <tr>
             <th>Name</th>
             <th>Address</th>
-            <th>Owner</th>
             <th>Active</th>
         </tr>
-        {{ range .NamedAddresses }}
+        {{- range .NamedAddresses -}}
         <tr>
             <td><a href="{{ .Name }}" target="_blank">{{ .Name }}</a></td>
             <td>{{ .Address }}</td>
-            <td>{{ .OwnerId }}</td>
-            <td>{{ .Active }}</td>
+            <td>
+                <input type="checkbox" role="switch" {{ if .Active }}checked{{ end }} onclick="toggle('{{ .Name }}', {{ not .Active }});">
+            </td>
         </tr>
-        {{ end }}
+        {{- end -}}
     </table>
 </body>
-
+<script type="application/javascript">
+    function toggle(name, status) {
+        const data = {
+            "name": name,
+            "active": status,
+        };
+        fetch("/api/update/", {
+            method: "POST",
+            headers: {
+                'Content-Type': 'application/json',
+            },
+            body: JSON.stringify(data),
+        })
+        .then(response => {
+            if (response.ok) {
+                window.location.reload();
+            }
+        })
+        .catch((error) => {
+            console.error('Error:', error);
+        });
+    }
+</script>
 </html>
diff --git a/apps/url-shortener/main.go b/apps/url-shortener/main.go
index 58c022b..8f2af45 100644
--- a/apps/url-shortener/main.go
+++ b/apps/url-shortener/main.go
@@ -3,6 +3,7 @@
 import (
 	"database/sql"
 	"embed"
+	"encoding/json"
 	"flag"
 	"fmt"
 	"html/template"
@@ -29,8 +30,7 @@
 type Store interface {
 	Create(addr NamedAddress) error
 	Get(name string) (NamedAddress, error)
-	Activate(name string) error
-	Deactivate(name string) error
+	UpdateStatus(name string, active bool) error
 	ChangeOwner(name, ownerId string) error
 	List(ownerId string) ([]NamedAddress, error)
 }
@@ -107,13 +107,12 @@
 	return namedAddress, nil
 }
 
-func (s *SQLiteStore) Activate(name string) error {
+func (s *SQLiteStore) UpdateStatus(name string, active bool) error {
 	//TODO
-	return nil
-}
-
-func (s *SQLiteStore) Deactivate(name string) error {
-	//TODO
+	_, err := s.db.Exec("UPDATE named_addresses SET active = ? WHERE name = ?", active, name)
+	if err != nil {
+		return err
+	}
 	return nil
 }
 
@@ -151,16 +150,27 @@
 	}
 }
 
+func getLoggedInUser(r *http.Request) (string, error) {
+	// TODO(dato): should make a request to get loggedin user
+	return "tabo", nil
+}
+
 type Server struct {
 	store Store
 }
 
 func (s *Server) Start() {
 	http.HandleFunc("/", s.handler)
+	http.HandleFunc("/api/update/", s.toggleHandler)
 	log.Fatal(http.ListenAndServe(":8080", nil))
 }
 
 func (s *Server) handler(w http.ResponseWriter, r *http.Request) {
+	loggedInUser, err := getLoggedInUser(r)
+	if err != nil {
+		http.Error(w, "User Not Logged In", http.StatusUnauthorized)
+		return
+	}
 	if r.Method == http.MethodPost {
 		customName := r.PostFormValue("custom")
 		address := r.PostFormValue("address")
@@ -173,11 +183,10 @@
 			if cn == "" {
 				cn = generateRandomURL()
 			}
-			// check if custom exists
 			namedAddress := NamedAddress{
 				Name:    cn,
 				Address: address,
-				OwnerId: "tabo", //TODO. Owner ID should be taken from http header
+				OwnerId: loggedInUser,
 				Active:  true,
 			}
 			if err := s.store.Create(namedAddress); err == nil {
@@ -201,17 +210,18 @@
 		if err != nil {
 			return
 		}
-		// Redirect to the address
+		if !namedAddress.Active {
+			http.Error(w, "address not found", http.StatusNotFound)
+			return
+		}
 		http.Redirect(w, r, namedAddress.Address, http.StatusSeeOther)
 		return
 	}
-	// Retrieve named addresses for the owner
-	namedAddresses, err := s.store.List("tabo")
+	namedAddresses, err := s.store.List(loggedInUser)
 	if err != nil {
 		http.Error(w, "Internal Server Error", http.StatusInternalServerError)
 		return
 	}
-	// Combine data for rendering
 	pageVariables := PageVariables{
 		NamedAddresses: namedAddresses,
 	}
@@ -228,6 +238,42 @@
 	renderHTML(w, r, tmpl, pageVariables)
 }
 
+type UpdateRequest struct {
+	Name   string `json:"name"`
+	Active bool   `json:"active"`
+}
+
+func (s *Server) toggleHandler(w http.ResponseWriter, r *http.Request) {
+	var data UpdateRequest
+	if r.Method == http.MethodPost {
+		loggedInUser, err := getLoggedInUser(r)
+		if err != nil {
+			http.Error(w, "User Not Logged In", http.StatusUnauthorized)
+			return
+		}
+		if err := json.NewDecoder(r.Body).Decode(&data); err != nil {
+			http.Error(w, "Failed to decode JSON data", http.StatusBadRequest)
+			return
+		}
+		namedAddress, err := s.store.Get(data.Name)
+		if err != nil {
+			http.Error(w, fmt.Sprintf("Failed to get named_address for name %s", data.Name), http.StatusInternalServerError)
+			return
+		}
+		if namedAddress.OwnerId != loggedInUser {
+			http.Error(w, "Invalid owner ID", http.StatusUnauthorized)
+			return
+		}
+		if err := s.store.UpdateStatus(data.Name, data.Active); err != nil {
+			http.Error(w, fmt.Sprintf("Failed to update status for name %s", data.Name), http.StatusInternalServerError)
+			return
+		}
+	} else {
+		http.Error(w, "Method Not Allowed", http.StatusMethodNotAllowed)
+		return
+	}
+}
+
 func main() {
 	flag.Parse()
 	db, err := NewSQLiteStore(*dbPath)