set up better ux for using categories
This commit is contained in:
@@ -51,4 +51,6 @@ type BoxItemWithItemInfo struct {
|
|||||||
Name string
|
Name string
|
||||||
Stage PackingStage
|
Stage PackingStage
|
||||||
Category Category
|
Category Category
|
||||||
|
Description *string
|
||||||
|
Notes *string
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -156,7 +156,7 @@ func GetBoxItemsByBoxID(boxID int) ([]BoxItemWithItemInfo, error) {
|
|||||||
// get all rows from box_items where boxid = boxID
|
// get all rows from box_items where boxid = boxID
|
||||||
// also get the item info for each item
|
// also get the item info for each item
|
||||||
rows, err := db.Query(
|
rows, err := db.Query(
|
||||||
"SELECT id, items.name, items.stage, items.category FROM boxitems JOIN items ON itemid=items.id WHERE boxid = ?",
|
"SELECT id, items.name, items.stage, items.category, items.description, items.notes FROM boxitems JOIN items ON itemid=items.id WHERE boxid = ?",
|
||||||
boxID)
|
boxID)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -169,7 +169,7 @@ func GetBoxItemsByBoxID(boxID int) ([]BoxItemWithItemInfo, error) {
|
|||||||
|
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
boxItem := BoxItemWithItemInfo{}
|
boxItem := BoxItemWithItemInfo{}
|
||||||
if err = rows.Scan(&boxItem.ID, &boxItem.Name, &boxItem.Stage, &boxItem.Category); err != nil {
|
if err = rows.Scan(&boxItem.ID, &boxItem.Name, &boxItem.Stage, &boxItem.Category, &boxItem.Description, &boxItem.Notes); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
2
main.go
2
main.go
@@ -47,6 +47,8 @@ func main() {
|
|||||||
boxActions := routes.Boxes(html)
|
boxActions := routes.Boxes(html)
|
||||||
boxItemActions := routes.BoxItems(html)
|
boxItemActions := routes.BoxItems(html)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
router.Handle("/items/edit", web.Action(itemActions.Edit))
|
router.Handle("/items/edit", web.Action(itemActions.Edit))
|
||||||
router.Handle("/items/delete", web.Action(itemActions.Delete))
|
router.Handle("/items/delete", web.Action(itemActions.Delete))
|
||||||
router.Handle("/items/save", web.Action(itemActions.Save))
|
router.Handle("/items/save", web.Action(itemActions.Save))
|
||||||
|
|||||||
@@ -107,11 +107,18 @@ func GetItemByID(r *http.Request) *web.Response {
|
|||||||
func Put(r *http.Request) *web.Response {
|
func Put(r *http.Request) *web.Response {
|
||||||
id, _ := web.PathLast(r)
|
id, _ := web.PathLast(r)
|
||||||
|
|
||||||
err := r.ParseForm()
|
if err := r.ParseForm(); err != nil {
|
||||||
if err != nil {
|
|
||||||
return web.Error(http.StatusBadRequest, err, nil)
|
return web.Error(http.StatusBadRequest, err, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if r.Form.Get("category") == "" {
|
||||||
|
panic(r.Form.Get(""))
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.Form.Get("stage") == "" {
|
||||||
|
panic(r.Form.Get(""))
|
||||||
|
}
|
||||||
|
|
||||||
name := r.Form.Get("name")
|
name := r.Form.Get("name")
|
||||||
stage := r.Form.Get("stage")
|
stage := r.Form.Get("stage")
|
||||||
category := r.Form.Get("category")
|
category := r.Form.Get("category")
|
||||||
@@ -145,9 +152,7 @@ func Put(r *http.Request) *web.Response {
|
|||||||
}(),
|
}(),
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = db.PutItem(item)
|
if _, err := db.PutItem(item); err != nil {
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return web.Error(http.StatusInternalServerError, err, nil)
|
return web.Error(http.StatusInternalServerError, err, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
0
scripts/index.js
Normal file
0
scripts/index.js
Normal file
@@ -1,3 +1,23 @@
|
|||||||
<tr id="box-item-list">
|
<tr class="box-item-list">
|
||||||
<td>Hooray!</td>
|
<td>
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th scope="col" class="px-6 py-4"></th>
|
||||||
|
<th scope="col" class="px-6 py-4">#</th>
|
||||||
|
<th scope="col" class="px-6 py-4">Name</th>
|
||||||
|
<th scope="col" class="px-6 py-4">Stage</th>
|
||||||
|
<th scope="col" class="px-6 py-4">Category</th>
|
||||||
|
<th scope="col" class="px-6 py-4">Description</th>
|
||||||
|
<th scope="col" class="px-6 py-4">Notes</th>
|
||||||
|
<th scope="col" class="px-6 py-4"></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="table-body">
|
||||||
|
{{range .}}
|
||||||
|
{{ template "box-items/box-item-row.html" . }}
|
||||||
|
{{end}}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|||||||
10
templates/box-items/box-item-row.html
Normal file
10
templates/box-items/box-item-row.html
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<tr class="box-item-row border-b dark:border-neutral-500 hover:bg-slate-300 hover:bg-opacity-20">
|
||||||
|
<td class="whitespace-nowrap px-6 py-4">{{ .ID }}</td>
|
||||||
|
<td class="whitespace-nowrap px-6 py-4">{{ .Name }}</td>
|
||||||
|
|
||||||
|
{{ template "components/parsed-packing-stage.html" .Stage }}
|
||||||
|
{{ template "components/parsed-category.html" .Category }}
|
||||||
|
|
||||||
|
<td class="whitespace-nowrap px-6 py-4">{{ .Description }}</td>
|
||||||
|
<td class="whitespace-nowrap px-6 py-4">{{ .Notes }}</td>
|
||||||
|
</tr>
|
||||||
@@ -3,6 +3,7 @@
|
|||||||
<button
|
<button
|
||||||
hx-get="/box-items?boxid={{ .ID }}"
|
hx-get="/box-items?boxid={{ .ID }}"
|
||||||
hx-target="#boxrow-{{ .ID }}"
|
hx-target="#boxrow-{{ .ID }}"
|
||||||
|
hx-swap="afterend"
|
||||||
class="inline-flex items-center h-8 px-4 m-2 text-sm text-stone-100 transition-colors duration-150 bg-stone-700 rounded-lg focus:shadow-outline hover:bg-stone-800"
|
class="inline-flex items-center h-8 px-4 m-2 text-sm text-stone-100 transition-colors duration-150 bg-stone-700 rounded-lg focus:shadow-outline hover:bg-stone-800"
|
||||||
>
|
>
|
||||||
>
|
>
|
||||||
@@ -11,9 +12,9 @@
|
|||||||
<td class="whitespace-nowrap px-6 py-4">{{.ID}}</td>
|
<td class="whitespace-nowrap px-6 py-4">{{.ID}}</td>
|
||||||
<td class="whitespace-nowrap px-6 py-4">{{.Name}}</td>
|
<td class="whitespace-nowrap px-6 py-4">{{.Name}}</td>
|
||||||
|
|
||||||
{{ template "components/parsed-packing-stage.html" .Stage }}
|
{{ template "components/parsed-packing-stage.html" .ID }}
|
||||||
|
|
||||||
{{ template "components/parsed-category.html" .Category }}
|
{{ template "components/parsed-category.html" .ID }}
|
||||||
|
|
||||||
{{ if .Description }}
|
{{ if .Description }}
|
||||||
<td class="whitespace-nowrap px-6 py-4">{{.Description}}</td>
|
<td class="whitespace-nowrap px-6 py-4">{{.Description}}</td>
|
||||||
|
|||||||
8
templates/components/edit-category.html
Normal file
8
templates/components/edit-category.html
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<select class="category-selector" data-include-edit="{{.ID}}" value="{{.Category}}" name="category">
|
||||||
|
<option value="0">Bedroom</option>
|
||||||
|
<option value="1">Bathroom</option>
|
||||||
|
<option value="2">Kitchen</option>
|
||||||
|
<option value="3">Office</option>
|
||||||
|
<option value="4">Living Room</option>
|
||||||
|
<option value="5">Other</option>
|
||||||
|
</select>
|
||||||
7
templates/components/edit-packing-stage.html
Normal file
7
templates/components/edit-packing-stage.html
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
<select class="packing-stage-selector" data-include-edit="{{.ID}}" value="{{.Stage}}" name="stage">
|
||||||
|
<option value="0">Essentials</option>
|
||||||
|
<option value="1">Stage One</option>
|
||||||
|
<option value="2">Stage Two</option>
|
||||||
|
<option value="3">Stage Three</option>
|
||||||
|
<option value="4">Determine Later</option>
|
||||||
|
</select>
|
||||||
@@ -18,6 +18,7 @@
|
|||||||
hx-get="/items"
|
hx-get="/items"
|
||||||
hx-target="#home-page-container"
|
hx-target="#home-page-container"
|
||||||
hx-swap="innerHTML"
|
hx-swap="innerHTML"
|
||||||
|
onclick="handleLabelUpdate"
|
||||||
class="inline-flex items-center h-8 px-4 m-2 text-sm text-blue-100 transition-colors duration-150 bg-blue-700 rounded-lg focus:shadow-outline hover:bg-blue-800"
|
class="inline-flex items-center h-8 px-4 m-2 text-sm text-blue-100 transition-colors duration-150 bg-blue-700 rounded-lg focus:shadow-outline hover:bg-blue-800"
|
||||||
>
|
>
|
||||||
Items
|
Items
|
||||||
@@ -26,6 +27,7 @@
|
|||||||
hx-get="/boxes"
|
hx-get="/boxes"
|
||||||
hx-target="#home-page-container"
|
hx-target="#home-page-container"
|
||||||
hx-swap="innerHTML"
|
hx-swap="innerHTML"
|
||||||
|
onclick="handleLabelUpdate"
|
||||||
class="inline-flex items-center h-8 px-4 m-2 text-sm text-blue-100 transition-colors duration-150 bg-blue-700 rounded-lg focus:shadow-outline hover:bg-blue-800"
|
class="inline-flex items-center h-8 px-4 m-2 text-sm text-blue-100 transition-colors duration-150 bg-blue-700 rounded-lg focus:shadow-outline hover:bg-blue-800"
|
||||||
>
|
>
|
||||||
Boxes
|
Boxes
|
||||||
@@ -34,11 +36,18 @@
|
|||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<br/>
|
<br/>
|
||||||
<span class="text-xl">Items</span>
|
<span id="page-label" class="text-xl">Items</span>
|
||||||
<div id="home-page-container">
|
<div id="home-page-container">
|
||||||
{{ template "items/entity-list.html" . }}
|
{{ template "items/entity-list.html" . }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
function handleLabelUpdate() {
|
||||||
|
const prev = document.getElementById('page-label').innerText;
|
||||||
|
document.getElementById('page-label').innerText = prev === 'Items' ? 'Boxes' : 'Items';
|
||||||
|
}
|
||||||
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -1,39 +1,40 @@
|
|||||||
<tr id="datarow-{{.ID}}" class="datarow border-b dark:border-neutral-500">
|
<tr id="datarow-{{.ID}}" class="datarow border-b dark:border-neutral-500">
|
||||||
<td class="whitespace-nowrap px-6 py-4">
|
<td class="whitespace-nowrap px-6 py-4">
|
||||||
<input hidden disabled type="text" name="id" value="{{.ID}}" data-include-edit="{{.ID}}" />
|
<input class="data-input-{{.ID}}" hidden disabled type="text" name="id" value="{{.ID}}" data-include-edit="{{.ID}}" />
|
||||||
<span>{{.ID}}</span>
|
<span>{{.ID}}</span>
|
||||||
</td>
|
</td>
|
||||||
<td class="whitespace-nowrap px-6 py-4">
|
<td class="whitespace-nowrap px-6 py-4">
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"
|
class="data-input-{{.ID}} shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"
|
||||||
data-include-edit="{{.ID}}"
|
data-include-edit="{{.ID}}"
|
||||||
name="name"
|
name="name"
|
||||||
value="{{.Name}}"
|
value="{{.Name}}"
|
||||||
/>
|
/>
|
||||||
</td>
|
</td>
|
||||||
<td class="whitespace-nowrap px-6 py-4">
|
<td class="whitespace-nowrap px-6 py-4">
|
||||||
<input
|
<select class="data-input-{{.ID}}" id="packing-stage-selector-{{.ID}}" data-include-edit="{{.ID}}" value="{{.Stage}}" name="stage">
|
||||||
type="text"
|
<option value="0">Essentials</option>
|
||||||
class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"
|
<option value="1">Stage One</option>
|
||||||
data-include-edit="{{.ID}}"
|
<option value="2">Stage Two</option>
|
||||||
name="stage"
|
<option value="3">Stage Three</option>
|
||||||
value="{{.Stage}}"
|
<option value="4">Determine Later</option>
|
||||||
/>
|
</select>
|
||||||
|
</td>
|
||||||
|
<td class="whitespace-nowrap px-6 py-4">
|
||||||
|
<select class="data-input-{{.ID}}" id="category-selector-{{.ID}}" data-include-edit="{{.ID}}" value="{{.Category}}" name="category">
|
||||||
|
<option value="0">Bedroom</option>
|
||||||
|
<option value="1">Bathroom</option>
|
||||||
|
<option value="2">Kitchen</option>
|
||||||
|
<option value="3">Office</option>
|
||||||
|
<option value="4">Living Room</option>
|
||||||
|
<option value="5">Other</option>
|
||||||
|
</select>
|
||||||
</td>
|
</td>
|
||||||
<td class="whitespace-nowrap px-6 py-4">
|
<td class="whitespace-nowrap px-6 py-4">
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"
|
class="data-input-{{.ID}} shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"
|
||||||
data-include-edit="{{.ID}}"
|
|
||||||
name="category"
|
|
||||||
value="{{.Category}}"
|
|
||||||
/>
|
|
||||||
</td>
|
|
||||||
<td class="whitespace-nowrap px-6 py-4">
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"
|
|
||||||
data-include-edit="{{.ID}}"
|
data-include-edit="{{.ID}}"
|
||||||
name="description"
|
name="description"
|
||||||
value="{{.Description}}"
|
value="{{.Description}}"
|
||||||
@@ -42,7 +43,7 @@
|
|||||||
<td class="whitespace-nowrap px-6 py-4">
|
<td class="whitespace-nowrap px-6 py-4">
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"
|
class="data-input-{{.ID}} shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"
|
||||||
data-include-edit="{{.ID}}"
|
data-include-edit="{{.ID}}"
|
||||||
name="notes"
|
name="notes"
|
||||||
value="{{.Notes}}"
|
value="{{.Notes}}"
|
||||||
@@ -54,7 +55,7 @@
|
|||||||
hx-target="#datarow-{{.ID}}"
|
hx-target="#datarow-{{.ID}}"
|
||||||
hx-swap="outerHTML"
|
hx-swap="outerHTML"
|
||||||
hx-indicator="#processing"
|
hx-indicator="#processing"
|
||||||
hx-include="input[data-include-edit='{{.ID}}']"
|
hx-include=".data-input-{{.ID}}"
|
||||||
class="inline-flex items-center h-8 px-4 m-2 text-sm text-blue-100 transition-colors duration-150 bg-blue-700 rounded-lg focus:shadow-outline hover:bg-blue-800"
|
class="inline-flex items-center h-8 px-4 m-2 text-sm text-blue-100 transition-colors duration-150 bg-blue-700 rounded-lg focus:shadow-outline hover:bg-blue-800"
|
||||||
href=""
|
href=""
|
||||||
>Save</a
|
>Save</a
|
||||||
@@ -71,4 +72,13 @@
|
|||||||
>Cancel</a
|
>Cancel</a
|
||||||
>
|
>
|
||||||
</td>
|
</td>
|
||||||
|
<script>
|
||||||
|
document.getElementById("category-selector-{{.ID}}").onchange = (e) => {
|
||||||
|
console.log(e.target.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
document.getElementById("packing-stage-selector-{{.ID}}").onchange = (e) => {
|
||||||
|
console.log(e.target.value);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
</tr>
|
</tr>
|
||||||
|
|||||||
Reference in New Issue
Block a user