Skip to content

Commit

Permalink
feat(keymaps): add all the CRUD stuff for mappings
Browse files Browse the repository at this point in the history
  • Loading branch information
scottmckendry committed Aug 22, 2024
1 parent 3a2f8d9 commit 777b9ac
Show file tree
Hide file tree
Showing 6 changed files with 513 additions and 1 deletion.
77 changes: 77 additions & 0 deletions data/data.go
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,83 @@ func (s *Storage) GetMappings(email string) []Mapping {
return mappings
}

func (s *Storage) GetMapping(mappingID string, email string) *Mapping {
mapping := &Mapping{}
row := s.db.QueryRow(
`SELECT mappings.id, keymap, maps_to
FROM mappings
INNER JOIN users
ON mappings.user_id = users.id
WHERE mappings.id = ?
AND users.email = ?`,
mappingID,
email,
)
err := row.Scan(&mapping.ID, &mapping.Keymap, &mapping.MapsTo)
if err != nil {
return nil
}

return mapping
}

func (s *Storage) AddMapping(email string, keymap string, mapsTo string) error {
_, err := s.db.Exec(
`INSERT INTO mappings (user_id, keymap, maps_to)
VALUES (
(SELECT id FROM users WHERE email = ?),
?,
?
)`,
email,
keymap,
mapsTo,
)
if err != nil {
return err
}

return nil
}

func (s *Storage) UpdateMapping(
mappingID string,
email string,
keymap string,
mapsTo string,
) error {
_, err := s.db.Exec(
`UPDATE mappings
SET keymap = ?, maps_to = ?
WHERE id = ?
AND user_id = (SELECT id FROM users WHERE email = ?)`,
keymap,
mapsTo,
mappingID,
email,
)
if err != nil {
return err
}

return nil
}

func (s *Storage) DeleteMapping(mappingID string, email string) error {
_, err := s.db.Exec(
`DELETE FROM mappings
WHERE id = ?
AND user_id = (SELECT id FROM users WHERE email = ?)`,
mappingID,
email,
)
if err != nil {
return err
}

return nil
}

func (s *Storage) GetUserSettings(email string) *UserSettings {
settings := &UserSettings{}
rows, err := s.db.Query(
Expand Down
84 changes: 84 additions & 0 deletions handlers/settings.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import (
"log"
"net/http"

"github.com/go-chi/chi/v5"

"github.com/scottmckendry/mnemstart/views"
)

Expand All @@ -29,6 +31,88 @@ func (h *Handler) HandleMappings(w http.ResponseWriter, r *http.Request) {
views.Mappings(user, mappings).Render(r.Context(), w)
}

func (h *Handler) HandleMapping(w http.ResponseWriter, r *http.Request) {
user, err := h.auth.GetSessionUser(r)
if err != nil {
log.Println(err)
return
}

mappingID := chi.URLParam(r, "id")
mapping := h.store.GetMapping(mappingID, user.Email)
views.MappingRow(mapping).Render(r.Context(), w)
}

func (h *Handler) HandleMappingNew(w http.ResponseWriter, r *http.Request) {
views.NewMapping().Render(r.Context(), w)
}

func (h *Handler) HandleMappingAdd(w http.ResponseWriter, r *http.Request) {
user, err := h.auth.GetSessionUser(r)
if err != nil {
log.Println(err)
return
}

err = r.ParseForm()
if err != nil {
log.Println(err)
return
}

keymap := r.FormValue("keymap")
mapsTo := r.FormValue("mapsto")
h.store.AddMapping(user.Email, keymap, mapsTo)
mappings := h.store.GetMappings(user.Email)
views.Mappings(user, mappings).Render(r.Context(), w)
}

func (h *Handler) HandleMappingDelete(w http.ResponseWriter, r *http.Request) {
user, err := h.auth.GetSessionUser(r)
if err != nil {
log.Println(err)
return
}

mappingID := chi.URLParam(r, "id")
h.store.DeleteMapping(mappingID, user.Email)
mappings := h.store.GetMappings(user.Email)
views.Mappings(user, mappings).Render(r.Context(), w)
}

func (h *Handler) HandleMappingEdit(w http.ResponseWriter, r *http.Request) {
user, err := h.auth.GetSessionUser(r)
if err != nil {
log.Println(err)
return
}

mappingID := chi.URLParam(r, "id")
mapping := h.store.GetMapping(mappingID, user.Email)
views.EditMapping(user, mapping).Render(r.Context(), w)
}

func (h *Handler) HandleMappingUpdate(w http.ResponseWriter, r *http.Request) {
user, err := h.auth.GetSessionUser(r)
if err != nil {
log.Println(err)
return
}

err = r.ParseForm()
if err != nil {
log.Println(err)
return
}

mappingID := chi.URLParam(r, "id")
keymap := r.FormValue("keymap")
mapsTo := r.FormValue("mapsto")
h.store.UpdateMapping(mappingID, user.Email, keymap, mapsTo)
mappings := h.store.GetMappings(user.Email)
views.Mappings(user, mappings).Render(r.Context(), w)
}

func (h *Handler) HandleSettingsUpdate(w http.ResponseWriter, r *http.Request) {
user, err := h.auth.GetSessionUser(r)
if err != nil {
Expand Down
14 changes: 13 additions & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,20 @@ func main() {
// app routes
r.HandleFunc("/", auth.RequireAuth(handler.HandleRoot, authService))
r.HandleFunc("/settings", auth.RequireAuth(handler.HandleSettings, authService))
r.HandleFunc("/mappings", auth.RequireAuth(handler.HandleMappings, authService))
r.HandleFunc("/update-settings", auth.RequireAuth(handler.HandleSettingsUpdate, authService))
r.HandleFunc("/mappings", auth.RequireAuth(handler.HandleMappings, authService))
r.HandleFunc("/mappings/{id}", auth.RequireAuth(handler.HandleMapping, authService))
r.HandleFunc("/mappings/new", auth.RequireAuth(handler.HandleMappingNew, authService))
r.HandleFunc("/mappings/add", auth.RequireAuth(handler.HandleMappingAdd, authService))
r.HandleFunc("/mappings/edit/{id}", auth.RequireAuth(handler.HandleMappingEdit, authService))
r.HandleFunc(
"/mappings/update/{id}",
auth.RequireAuth(handler.HandleMappingUpdate, authService),
)
r.HandleFunc(
"/mappings/delete/{id}",
auth.RequireAuth(handler.HandleMappingDelete, authService),
)

// auth
r.HandleFunc("/auth/{provider}", handler.HandleProviderLogin)
Expand Down
5 changes: 5 additions & 0 deletions public/js/input.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,11 @@ document.addEventListener("keydown", (event) => {

// 'i' focuses the search input - i.e. 'insert mode'
document.addEventListener("keydown", (event) => {
const activeElement = document.activeElement;
if (activeElement && activeElement.tagName.toLowerCase() === "input") {
return;
}

if (event.key === "i" && !leaderMode) {
event.preventDefault();
document.getElementById("search").focus();
Expand Down
88 changes: 88 additions & 0 deletions views/mappings.templ
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package views

import (
"strconv"
"github.com/markbates/goth"
"github.com/scottmckendry/mnemstart/data"
)

templ Mappings(user goth.User, mappings []data.Mapping) {
<div id="modal" _="on closeModal add .closing then wait for animationend then remove me then go to location.reload()">
<div class="modal-underlay" _="on click trigger closeModal"></div>
<div class="modal-content">
<h2>Mappings</h2>
<table id="mappings-table">
<thead>
<tr>
<th>Keymap</th>
<th>URL</th>
<th>Actions</th>
</tr>
</thead>
<tbody hx-target="closest tr" hx-swap="outerHTML">
for _, mapping := range mappings {
@MappingRow(&mapping)
}
<tr>
<td colspan="3">
<button class="button" hx-get="/mappings/new" hx-swap="outerHTML">New Mapping</button>
</td>
</tr>
</tbody>
</table>
<button class="button" _="on click trigger closeModal">Close</button>
</div>
</div>
}

templ MappingRow(mapping *data.Mapping) {
<tr>
<td>{ mapping.Keymap }</td>
<td>{ mapping.MapsTo }</td>
<td>
<button
class="button"
hx-get={ "/mappings/edit/" + strconv.Itoa(mapping.ID) }
hx-trigger="edit"
onClick="
let editing = document.querySelector('.editing')
if(editing) {
htmx.trigger(editing, 'cancel')
htmx.trigger(this, 'edit')
} else {
htmx.trigger(this, 'edit')
}"
>Edit</button>
<button class="button" hx-delete={ "/mappings/delete/" + strconv.Itoa(mapping.ID) } hx-confirm="Are you sure?" hx-target="#mappings-table">Delete</button>
</td>
</tr>
}

templ NewMapping() {
<tr>
<td>
<input type="text" id="keymap" name="keymap" data-include-add="" required/>
</td>
<td>
<input type="text" id="mapsto" name="mapsto" data-include-add="" required/>
</td>
<td>
<button class="button" hx-post="/mappings/add" hx-target="#mappings-table" hx-include="input[data-include-add]" hx-swap="outerHTML">Save</button>
</td>
</tr>
}

templ EditMapping(user goth.User, mapping *data.Mapping) {
<tr hx-trigger="cancel" class="editing" hx-get={ "/mappings/" + strconv.Itoa(mapping.ID) }>
<td>
<input type="text" id="keymap" name="keymap" data-include-edit="" value={ mapping.Keymap } required/>
</td>
<td>
<input type="text" id="mapsto" name="mapsto" data-include-edit="" value={ mapping.MapsTo } required/>
</td>
<td>
<button class="button" hx-get={ "/mappings/" + strconv.Itoa(mapping.ID) }>Cancel</button>
<button class="button" hx-put={ "/mappings/update/" + strconv.Itoa(mapping.ID) } hx-target="#mappings-table" hx-include="input[data-include-edit]">Save</button>
</td>
</tr>
}
Loading

0 comments on commit 777b9ac

Please sign in to comment.