diff --git a/.gitignore b/.gitignore
index 68779bc..6a6b1e6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,7 +1,10 @@
app
+mikayla-moving
+
+tmp
+output.css
+
*.swp
*.test
*.out
-tmp
-output.css
-example.db
+*.db
diff --git a/Makefile b/Makefile
index 98a9197..2f37317 100644
--- a/Makefile
+++ b/Makefile
@@ -31,7 +31,16 @@ test:
## build: build a binary
.PHONY: build
build: test
- go build -o ./app -v
+ sudo rm -f mikayla-moving
+ go build -o ./mikayla-moving -v
+ sudo cp mikayla-moving /usr/bin/mikayla-moving
+
+# restart: rebuild and restart the systemd service running the project
+.PHONY: restart
+restart:
+ sudo systemctl stop mikayla-moving
+ make build
+ sudo systemctl restart mikayla-moving
## docker-build: build project into a docker container image
.PHONY: docker-build
diff --git a/css/input.css b/css/input.css
deleted file mode 100644
index bd6213e..0000000
--- a/css/input.css
+++ /dev/null
@@ -1,3 +0,0 @@
-@tailwind base;
-@tailwind components;
-@tailwind utilities;
\ No newline at end of file
diff --git a/css/output.css b/css/output.css
deleted file mode 100644
index 49acdd7..0000000
--- a/css/output.css
+++ /dev/null
@@ -1,984 +0,0 @@
-/*
-! tailwindcss v3.3.3 | MIT License | https://tailwindcss.com
-*/
-
-/*
-1. Prevent padding and border from affecting element width. (https://github.com/mozdevs/cssremedy/issues/4)
-2. Allow adding a border to an element by just adding a border-width. (https://github.com/tailwindcss/tailwindcss/pull/116)
-*/
-
-*,
-::before,
-::after {
- box-sizing: border-box;
- /* 1 */
- border-width: 0;
- /* 2 */
- border-style: solid;
- /* 2 */
- border-color: #e5e7eb;
- /* 2 */
-}
-
-::before,
-::after {
- --tw-content: '';
-}
-
-/*
-1. Use a consistent sensible line-height in all browsers.
-2. Prevent adjustments of font size after orientation changes in iOS.
-3. Use a more readable tab size.
-4. Use the user's configured `sans` font-family by default.
-5. Use the user's configured `sans` font-feature-settings by default.
-6. Use the user's configured `sans` font-variation-settings by default.
-*/
-
-html {
- line-height: 1.5;
- /* 1 */
- -webkit-text-size-adjust: 100%;
- /* 2 */
- -moz-tab-size: 4;
- /* 3 */
- -o-tab-size: 4;
- tab-size: 4;
- /* 3 */
- font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
- /* 4 */
- font-feature-settings: normal;
- /* 5 */
- font-variation-settings: normal;
- /* 6 */
-}
-
-/*
-1. Remove the margin in all browsers.
-2. Inherit line-height from `html` so users can set them as a class directly on the `html` element.
-*/
-
-body {
- margin: 0;
- /* 1 */
- line-height: inherit;
- /* 2 */
-}
-
-/*
-1. Add the correct height in Firefox.
-2. Correct the inheritance of border color in Firefox. (https://bugzilla.mozilla.org/show_bug.cgi?id=190655)
-3. Ensure horizontal rules are visible by default.
-*/
-
-hr {
- height: 0;
- /* 1 */
- color: inherit;
- /* 2 */
- border-top-width: 1px;
- /* 3 */
-}
-
-/*
-Add the correct text decoration in Chrome, Edge, and Safari.
-*/
-
-abbr:where([title]) {
- -webkit-text-decoration: underline dotted;
- text-decoration: underline dotted;
-}
-
-/*
-Remove the default font size and weight for headings.
-*/
-
-h1,
-h2,
-h3,
-h4,
-h5,
-h6 {
- font-size: inherit;
- font-weight: inherit;
-}
-
-/*
-Reset links to optimize for opt-in styling instead of opt-out.
-*/
-
-a {
- color: inherit;
- text-decoration: inherit;
-}
-
-/*
-Add the correct font weight in Edge and Safari.
-*/
-
-b,
-strong {
- font-weight: bolder;
-}
-
-/*
-1. Use the user's configured `mono` font family by default.
-2. Correct the odd `em` font sizing in all browsers.
-*/
-
-code,
-kbd,
-samp,
-pre {
- font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
- /* 1 */
- font-size: 1em;
- /* 2 */
-}
-
-/*
-Add the correct font size in all browsers.
-*/
-
-small {
- font-size: 80%;
-}
-
-/*
-Prevent `sub` and `sup` elements from affecting the line height in all browsers.
-*/
-
-sub,
-sup {
- font-size: 75%;
- line-height: 0;
- position: relative;
- vertical-align: baseline;
-}
-
-sub {
- bottom: -0.25em;
-}
-
-sup {
- top: -0.5em;
-}
-
-/*
-1. Remove text indentation from table contents in Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=999088, https://bugs.webkit.org/show_bug.cgi?id=201297)
-2. Correct table border color inheritance in all Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=935729, https://bugs.webkit.org/show_bug.cgi?id=195016)
-3. Remove gaps between table borders by default.
-*/
-
-table {
- text-indent: 0;
- /* 1 */
- border-color: inherit;
- /* 2 */
- border-collapse: collapse;
- /* 3 */
-}
-
-/*
-1. Change the font styles in all browsers.
-2. Remove the margin in Firefox and Safari.
-3. Remove default padding in all browsers.
-*/
-
-button,
-input,
-optgroup,
-select,
-textarea {
- font-family: inherit;
- /* 1 */
- font-feature-settings: inherit;
- /* 1 */
- font-variation-settings: inherit;
- /* 1 */
- font-size: 100%;
- /* 1 */
- font-weight: inherit;
- /* 1 */
- line-height: inherit;
- /* 1 */
- color: inherit;
- /* 1 */
- margin: 0;
- /* 2 */
- padding: 0;
- /* 3 */
-}
-
-/*
-Remove the inheritance of text transform in Edge and Firefox.
-*/
-
-button,
-select {
- text-transform: none;
-}
-
-/*
-1. Correct the inability to style clickable types in iOS and Safari.
-2. Remove default button styles.
-*/
-
-button,
-[type='button'],
-[type='reset'],
-[type='submit'] {
- -webkit-appearance: button;
- /* 1 */
- background-color: transparent;
- /* 2 */
- background-image: none;
- /* 2 */
-}
-
-/*
-Use the modern Firefox focus style for all focusable elements.
-*/
-
-:-moz-focusring {
- outline: auto;
-}
-
-/*
-Remove the additional `:invalid` styles in Firefox. (https://github.com/mozilla/gecko-dev/blob/2f9eacd9d3d995c937b4251a5557d95d494c9be1/layout/style/res/forms.css#L728-L737)
-*/
-
-:-moz-ui-invalid {
- box-shadow: none;
-}
-
-/*
-Add the correct vertical alignment in Chrome and Firefox.
-*/
-
-progress {
- vertical-align: baseline;
-}
-
-/*
-Correct the cursor style of increment and decrement buttons in Safari.
-*/
-
-::-webkit-inner-spin-button,
-::-webkit-outer-spin-button {
- height: auto;
-}
-
-/*
-1. Correct the odd appearance in Chrome and Safari.
-2. Correct the outline style in Safari.
-*/
-
-[type='search'] {
- -webkit-appearance: textfield;
- /* 1 */
- outline-offset: -2px;
- /* 2 */
-}
-
-/*
-Remove the inner padding in Chrome and Safari on macOS.
-*/
-
-::-webkit-search-decoration {
- -webkit-appearance: none;
-}
-
-/*
-1. Correct the inability to style clickable types in iOS and Safari.
-2. Change font properties to `inherit` in Safari.
-*/
-
-::-webkit-file-upload-button {
- -webkit-appearance: button;
- /* 1 */
- font: inherit;
- /* 2 */
-}
-
-/*
-Add the correct display in Chrome and Safari.
-*/
-
-summary {
- display: list-item;
-}
-
-/*
-Removes the default spacing and border for appropriate elements.
-*/
-
-blockquote,
-dl,
-dd,
-h1,
-h2,
-h3,
-h4,
-h5,
-h6,
-hr,
-figure,
-p,
-pre {
- margin: 0;
-}
-
-fieldset {
- margin: 0;
- padding: 0;
-}
-
-legend {
- padding: 0;
-}
-
-ol,
-ul,
-menu {
- list-style: none;
- margin: 0;
- padding: 0;
-}
-
-/*
-Reset default styling for dialogs.
-*/
-
-dialog {
- padding: 0;
-}
-
-/*
-Prevent resizing textareas horizontally by default.
-*/
-
-textarea {
- resize: vertical;
-}
-
-/*
-1. Reset the default placeholder opacity in Firefox. (https://github.com/tailwindlabs/tailwindcss/issues/3300)
-2. Set the default placeholder color to the user's configured gray 400 color.
-*/
-
-input::-moz-placeholder, textarea::-moz-placeholder {
- opacity: 1;
- /* 1 */
- color: #9ca3af;
- /* 2 */
-}
-
-input::placeholder,
-textarea::placeholder {
- opacity: 1;
- /* 1 */
- color: #9ca3af;
- /* 2 */
-}
-
-/*
-Set the default cursor for buttons.
-*/
-
-button,
-[role="button"] {
- cursor: pointer;
-}
-
-/*
-Make sure disabled buttons don't get the pointer cursor.
-*/
-
-:disabled {
- cursor: default;
-}
-
-/*
-1. Make replaced elements `display: block` by default. (https://github.com/mozdevs/cssremedy/issues/14)
-2. Add `vertical-align: middle` to align replaced elements more sensibly by default. (https://github.com/jensimmons/cssremedy/issues/14#issuecomment-634934210)
- This can trigger a poorly considered lint error in some tools but is included by design.
-*/
-
-img,
-svg,
-video,
-canvas,
-audio,
-iframe,
-embed,
-object {
- display: block;
- /* 1 */
- vertical-align: middle;
- /* 2 */
-}
-
-/*
-Constrain images and videos to the parent width and preserve their intrinsic aspect ratio. (https://github.com/mozdevs/cssremedy/issues/14)
-*/
-
-img,
-video {
- max-width: 100%;
- height: auto;
-}
-
-/* Make elements with the HTML hidden attribute stay hidden by default */
-
-[hidden] {
- display: none;
-}
-
-[type='text'],[type='email'],[type='url'],[type='password'],[type='number'],[type='date'],[type='datetime-local'],[type='month'],[type='search'],[type='tel'],[type='time'],[type='week'],[multiple],textarea,select {
- -webkit-appearance: none;
- -moz-appearance: none;
- appearance: none;
- background-color: #fff;
- border-color: #6b7280;
- border-width: 1px;
- border-radius: 0px;
- padding-top: 0.5rem;
- padding-right: 0.75rem;
- padding-bottom: 0.5rem;
- padding-left: 0.75rem;
- font-size: 1rem;
- line-height: 1.5rem;
- --tw-shadow: 0 0 #0000;
-}
-
-[type='text']:focus, [type='email']:focus, [type='url']:focus, [type='password']:focus, [type='number']:focus, [type='date']:focus, [type='datetime-local']:focus, [type='month']:focus, [type='search']:focus, [type='tel']:focus, [type='time']:focus, [type='week']:focus, [multiple]:focus, textarea:focus, select:focus {
- outline: 2px solid transparent;
- outline-offset: 2px;
- --tw-ring-inset: var(--tw-empty,/*!*/ /*!*/);
- --tw-ring-offset-width: 0px;
- --tw-ring-offset-color: #fff;
- --tw-ring-color: #2563eb;
- --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);
- --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);
- box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
- border-color: #2563eb;
-}
-
-input::-moz-placeholder, textarea::-moz-placeholder {
- color: #6b7280;
- opacity: 1;
-}
-
-input::placeholder,textarea::placeholder {
- color: #6b7280;
- opacity: 1;
-}
-
-::-webkit-datetime-edit-fields-wrapper {
- padding: 0;
-}
-
-::-webkit-date-and-time-value {
- min-height: 1.5em;
-}
-
-::-webkit-datetime-edit,::-webkit-datetime-edit-year-field,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-minute-field,::-webkit-datetime-edit-second-field,::-webkit-datetime-edit-millisecond-field,::-webkit-datetime-edit-meridiem-field {
- padding-top: 0;
- padding-bottom: 0;
-}
-
-select {
- background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e");
- background-position: right 0.5rem center;
- background-repeat: no-repeat;
- background-size: 1.5em 1.5em;
- padding-right: 2.5rem;
- -webkit-print-color-adjust: exact;
- print-color-adjust: exact;
-}
-
-[multiple] {
- background-image: initial;
- background-position: initial;
- background-repeat: unset;
- background-size: initial;
- padding-right: 0.75rem;
- -webkit-print-color-adjust: unset;
- print-color-adjust: unset;
-}
-
-[type='checkbox'],[type='radio'] {
- -webkit-appearance: none;
- -moz-appearance: none;
- appearance: none;
- padding: 0;
- -webkit-print-color-adjust: exact;
- print-color-adjust: exact;
- display: inline-block;
- vertical-align: middle;
- background-origin: border-box;
- -webkit-user-select: none;
- -moz-user-select: none;
- user-select: none;
- flex-shrink: 0;
- height: 1rem;
- width: 1rem;
- color: #2563eb;
- background-color: #fff;
- border-color: #6b7280;
- border-width: 1px;
- --tw-shadow: 0 0 #0000;
-}
-
-[type='checkbox'] {
- border-radius: 0px;
-}
-
-[type='radio'] {
- border-radius: 100%;
-}
-
-[type='checkbox']:focus,[type='radio']:focus {
- outline: 2px solid transparent;
- outline-offset: 2px;
- --tw-ring-inset: var(--tw-empty,/*!*/ /*!*/);
- --tw-ring-offset-width: 2px;
- --tw-ring-offset-color: #fff;
- --tw-ring-color: #2563eb;
- --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);
- --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);
- box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
-}
-
-[type='checkbox']:checked,[type='radio']:checked {
- border-color: transparent;
- background-color: currentColor;
- background-size: 100% 100%;
- background-position: center;
- background-repeat: no-repeat;
-}
-
-[type='checkbox']:checked {
- background-image: url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3cpath d='M12.207 4.793a1 1 0 010 1.414l-5 5a1 1 0 01-1.414 0l-2-2a1 1 0 011.414-1.414L6.5 9.086l4.293-4.293a1 1 0 011.414 0z'/%3e%3c/svg%3e");
-}
-
-[type='radio']:checked {
- background-image: url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3ccircle cx='8' cy='8' r='3'/%3e%3c/svg%3e");
-}
-
-[type='checkbox']:checked:hover,[type='checkbox']:checked:focus,[type='radio']:checked:hover,[type='radio']:checked:focus {
- border-color: transparent;
- background-color: currentColor;
-}
-
-[type='checkbox']:indeterminate {
- background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 16 16'%3e%3cpath stroke='white' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M4 8h8'/%3e%3c/svg%3e");
- border-color: transparent;
- background-color: currentColor;
- background-size: 100% 100%;
- background-position: center;
- background-repeat: no-repeat;
-}
-
-[type='checkbox']:indeterminate:hover,[type='checkbox']:indeterminate:focus {
- border-color: transparent;
- background-color: currentColor;
-}
-
-[type='file'] {
- background: unset;
- border-color: inherit;
- border-width: 0;
- border-radius: 0;
- padding: 0;
- font-size: unset;
- line-height: inherit;
-}
-
-[type='file']:focus {
- outline: 1px solid ButtonText;
- outline: 1px auto -webkit-focus-ring-color;
-}
-
-*, ::before, ::after {
- --tw-border-spacing-x: 0;
- --tw-border-spacing-y: 0;
- --tw-translate-x: 0;
- --tw-translate-y: 0;
- --tw-rotate: 0;
- --tw-skew-x: 0;
- --tw-skew-y: 0;
- --tw-scale-x: 1;
- --tw-scale-y: 1;
- --tw-pan-x: ;
- --tw-pan-y: ;
- --tw-pinch-zoom: ;
- --tw-scroll-snap-strictness: proximity;
- --tw-gradient-from-position: ;
- --tw-gradient-via-position: ;
- --tw-gradient-to-position: ;
- --tw-ordinal: ;
- --tw-slashed-zero: ;
- --tw-numeric-figure: ;
- --tw-numeric-spacing: ;
- --tw-numeric-fraction: ;
- --tw-ring-inset: ;
- --tw-ring-offset-width: 0px;
- --tw-ring-offset-color: #fff;
- --tw-ring-color: rgb(59 130 246 / 0.5);
- --tw-ring-offset-shadow: 0 0 #0000;
- --tw-ring-shadow: 0 0 #0000;
- --tw-shadow: 0 0 #0000;
- --tw-shadow-colored: 0 0 #0000;
- --tw-blur: ;
- --tw-brightness: ;
- --tw-contrast: ;
- --tw-grayscale: ;
- --tw-hue-rotate: ;
- --tw-invert: ;
- --tw-saturate: ;
- --tw-sepia: ;
- --tw-drop-shadow: ;
- --tw-backdrop-blur: ;
- --tw-backdrop-brightness: ;
- --tw-backdrop-contrast: ;
- --tw-backdrop-grayscale: ;
- --tw-backdrop-hue-rotate: ;
- --tw-backdrop-invert: ;
- --tw-backdrop-opacity: ;
- --tw-backdrop-saturate: ;
- --tw-backdrop-sepia: ;
-}
-
-::backdrop {
- --tw-border-spacing-x: 0;
- --tw-border-spacing-y: 0;
- --tw-translate-x: 0;
- --tw-translate-y: 0;
- --tw-rotate: 0;
- --tw-skew-x: 0;
- --tw-skew-y: 0;
- --tw-scale-x: 1;
- --tw-scale-y: 1;
- --tw-pan-x: ;
- --tw-pan-y: ;
- --tw-pinch-zoom: ;
- --tw-scroll-snap-strictness: proximity;
- --tw-gradient-from-position: ;
- --tw-gradient-via-position: ;
- --tw-gradient-to-position: ;
- --tw-ordinal: ;
- --tw-slashed-zero: ;
- --tw-numeric-figure: ;
- --tw-numeric-spacing: ;
- --tw-numeric-fraction: ;
- --tw-ring-inset: ;
- --tw-ring-offset-width: 0px;
- --tw-ring-offset-color: #fff;
- --tw-ring-color: rgb(59 130 246 / 0.5);
- --tw-ring-offset-shadow: 0 0 #0000;
- --tw-ring-shadow: 0 0 #0000;
- --tw-shadow: 0 0 #0000;
- --tw-shadow-colored: 0 0 #0000;
- --tw-blur: ;
- --tw-brightness: ;
- --tw-contrast: ;
- --tw-grayscale: ;
- --tw-hue-rotate: ;
- --tw-invert: ;
- --tw-saturate: ;
- --tw-sepia: ;
- --tw-drop-shadow: ;
- --tw-backdrop-blur: ;
- --tw-backdrop-brightness: ;
- --tw-backdrop-contrast: ;
- --tw-backdrop-grayscale: ;
- --tw-backdrop-hue-rotate: ;
- --tw-backdrop-invert: ;
- --tw-backdrop-opacity: ;
- --tw-backdrop-saturate: ;
- --tw-backdrop-sepia: ;
-}
-
-.m-2 {
- margin: 0.5rem;
-}
-
-.inline-block {
- display: inline-block;
-}
-
-.flex {
- display: flex;
-}
-
-.inline-flex {
- display: inline-flex;
-}
-
-.table {
- display: table;
-}
-
-.h-8 {
- height: 2rem;
-}
-
-.w-full {
- width: 100%;
-}
-
-.min-w-full {
- min-width: 100%;
-}
-
-.appearance-none {
- -webkit-appearance: none;
- -moz-appearance: none;
- appearance: none;
-}
-
-.flex-col {
- flex-direction: column;
-}
-
-.items-center {
- align-items: center;
-}
-
-.justify-end {
- justify-content: flex-end;
-}
-
-.overflow-hidden {
- overflow: hidden;
-}
-
-.overflow-x-auto {
- overflow-x: auto;
-}
-
-.whitespace-nowrap {
- white-space: nowrap;
-}
-
-.rounded {
- border-radius: 0.25rem;
-}
-
-.rounded-lg {
- border-radius: 0.5rem;
-}
-
-.border {
- border-width: 1px;
-}
-
-.border-b {
- border-bottom-width: 1px;
-}
-
-.bg-blue-700 {
- --tw-bg-opacity: 1;
- background-color: rgb(29 78 216 / var(--tw-bg-opacity));
-}
-
-.bg-red-700 {
- --tw-bg-opacity: 1;
- background-color: rgb(185 28 28 / var(--tw-bg-opacity));
-}
-
-.px-1 {
- padding-left: 0.25rem;
- padding-right: 0.25rem;
-}
-
-.px-3 {
- padding-left: 0.75rem;
- padding-right: 0.75rem;
-}
-
-.px-4 {
- padding-left: 1rem;
- padding-right: 1rem;
-}
-
-.px-6 {
- padding-left: 1.5rem;
- padding-right: 1.5rem;
-}
-
-.py-1 {
- padding-top: 0.25rem;
- padding-bottom: 0.25rem;
-}
-
-.py-2 {
- padding-top: 0.5rem;
- padding-bottom: 0.5rem;
-}
-
-.py-4 {
- padding-top: 1rem;
- padding-bottom: 1rem;
-}
-
-.text-left {
- text-align: left;
-}
-
-.text-3xl {
- font-size: 1.875rem;
- line-height: 2.25rem;
-}
-
-.text-sm {
- font-size: 0.875rem;
- line-height: 1.25rem;
-}
-
-.text-xl {
- font-size: 1.25rem;
- line-height: 1.75rem;
-}
-
-.font-light {
- font-weight: 300;
-}
-
-.font-medium {
- font-weight: 500;
-}
-
-.leading-tight {
- line-height: 1.25;
-}
-
-.text-blue-100 {
- --tw-text-opacity: 1;
- color: rgb(219 234 254 / var(--tw-text-opacity));
-}
-
-.text-blue-700 {
- --tw-text-opacity: 1;
- color: rgb(29 78 216 / var(--tw-text-opacity));
-}
-
-.text-gray-700 {
- --tw-text-opacity: 1;
- color: rgb(55 65 81 / var(--tw-text-opacity));
-}
-
-.text-red-100 {
- --tw-text-opacity: 1;
- color: rgb(254 226 226 / var(--tw-text-opacity));
-}
-
-.shadow {
- --tw-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1);
- --tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color);
- box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
-}
-
-.transition-colors {
- transition-property: color, background-color, border-color, text-decoration-color, fill, stroke;
- transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
- transition-duration: 150ms;
-}
-
-.duration-150 {
- transition-duration: 150ms;
-}
-
-@media (min-width: 768px) {
- .md\:container {
- width: 100%;
- }
-
- @media (min-width: 640px) {
- .md\:container {
- max-width: 640px;
- }
- }
-
- @media (min-width: 768px) {
- .md\:container {
- max-width: 768px;
- }
- }
-
- @media (min-width: 1024px) {
- .md\:container {
- max-width: 1024px;
- }
- }
-
- @media (min-width: 1280px) {
- .md\:container {
- max-width: 1280px;
- }
- }
-
- @media (min-width: 1536px) {
- .md\:container {
- max-width: 1536px;
- }
- }
-}
-
-.hover\:bg-blue-800:hover {
- --tw-bg-opacity: 1;
- background-color: rgb(30 64 175 / var(--tw-bg-opacity));
-}
-
-.hover\:bg-red-800:hover {
- --tw-bg-opacity: 1;
- background-color: rgb(153 27 27 / var(--tw-bg-opacity));
-}
-
-.hover\:underline:hover {
- text-decoration-line: underline;
-}
-
-.focus\:outline-none:focus {
- outline: 2px solid transparent;
- outline-offset: 2px;
-}
-
-@media (prefers-color-scheme: dark) {
- .dark\:border-neutral-500 {
- --tw-border-opacity: 1;
- border-color: rgb(115 115 115 / var(--tw-border-opacity));
- }
-}
-
-@media (min-width: 640px) {
- .sm\:-mx-6 {
- margin-left: -1.5rem;
- margin-right: -1.5rem;
- }
-
- .sm\:px-6 {
- padding-left: 1.5rem;
- padding-right: 1.5rem;
- }
-}
-
-@media (min-width: 768px) {
- .md\:mx-auto {
- margin-left: auto;
- margin-right: auto;
- }
-}
-
-@media (min-width: 1024px) {
- .lg\:-mx-8 {
- margin-left: -2rem;
- margin-right: -2rem;
- }
-
- .lg\:px-8 {
- padding-left: 2rem;
- padding-right: 2rem;
- }
-}
\ No newline at end of file
diff --git a/db/entities.go b/db/entities.go
index e2c2798..175f95c 100644
--- a/db/entities.go
+++ b/db/entities.go
@@ -22,26 +22,35 @@ const (
// entities
type Item struct {
- ID int
- Name string
- Notes *string
- Description *string
- Stage PackingStage
- Category Category
+ ID int `json:"id"`
+ Name string `json:"name"`
+ Notes *string `json:"notes"`
+ Description *string `json:"description"`
+ Stage PackingStage `json:"stage"`
+ Category Category `json:"category"`
}
type Box struct {
- ID int
- Name string
- Notes *string
- Description *string
- Stage PackingStage
- Category Category
+ ID int `json:"id"`
+ Name string `json:"name"`
+ Notes *string `json:"notes"`
+ Description *string `json:"description"`
+ Stage PackingStage `json:"stage"`
+ Category Category `json:"category"`
}
-// joins
+// joining tables and derivative data types
type BoxItem struct {
ID int
BoxID int
ItemID int
}
+
+type BoxItemWithItemInfo struct {
+ ID int
+ Name string
+ Stage PackingStage
+ Category Category
+ Description *string
+ Notes *string
+}
diff --git a/db/sql.go b/db/sql.go
index f2def63..e202155 100644
--- a/db/sql.go
+++ b/db/sql.go
@@ -38,61 +38,6 @@ func GetAllItems() (result []Item, err error) {
return
}
-func GetItemByID(id int) (item Item, err error) {
- db, err := CreateClient()
- if err != nil {
- return Item{}, err
- }
-
- defer db.Close()
-
- row := db.QueryRow("SELECT * FROM items WHERE id = ?", id)
- err = row.Scan(&item.ID, &item.Name, &item.Notes, &item.Description, &item.Stage, &item.Category)
-
- return
-}
-
-func PostItem(item Item) (int64, error) {
- db, err := CreateClient()
- if err != nil {
- return -1, err
- }
-
- defer db.Close()
-
- query := `INSERT INTO items (name, notes, description, stage, category)
- VALUES (?, ?, ?, ?, ?)`
-
- result, err := db.Exec(query, item.Name, item.Notes, item.Description, item.Stage, item.Category)
-
- if err != nil {
- return -1, err
- }
-
- return result.LastInsertId()
-}
-
-
-
-func PostBox(box Box) (int64, error) {
- db, err := CreateClient()
- if err != nil {
- return -1, err
- }
-
- defer db.Close()
-
- query := `INSERT INTO boxes (name, notes, description, stage, category) VALUES (?, ?, ?, ?, ?)`
-
- result, err := db.Exec(query, box.Name, box.Notes, box.Description, box.Stage, box.Category)
-
- if err != nil {
- return -1, err
- }
-
- return result.LastInsertId()
-}
-
func GetAllBoxes() (result []Box, err error) {
db, err := CreateClient()
if err != nil {
@@ -123,12 +68,285 @@ func GetAllBoxes() (result []Box, err error) {
return
}
-// func PostBoxItem(itemid int, boxid int) (int64, error) {
-// db, err := CreateClient()
-// if err != nil {
-// return -1, err
-// }
+func GetAllBoxItems() ([]BoxItem, error) {
+ db, err := CreateClient()
+ if err != nil {
+ return nil, err
+ }
-// defer db.Close()
-// // query :=
-// }
+ defer db.Close()
+
+ rows, err := db.Query("SELECT * FROM box_items")
+ if err != nil {
+ return nil, err
+ }
+
+ defer rows.Close()
+
+ var result []BoxItem
+
+ for rows.Next() {
+ boxItem := BoxItem{}
+
+ err = rows.Scan(&boxItem.ID, &boxItem.BoxID, &boxItem.ItemID)
+
+ if err != nil {
+ return nil, err
+ }
+
+ result = append(result, boxItem)
+ }
+
+ return result, nil
+}
+
+func GetItemByID(id int) (item Item, err error) {
+ db, err := CreateClient()
+ if err != nil {
+ return Item{}, err
+ }
+
+ defer db.Close()
+
+ row := db.QueryRow("SELECT * FROM items WHERE id = ?", id)
+ err = row.Scan(&item.ID, &item.Name, &item.Notes, &item.Description, &item.Stage, &item.Category)
+
+ return
+}
+
+func GetBoxByID(id int) (box Box, err error) {
+ db, err := CreateClient()
+ if err != nil {
+ return Box{}, err
+ }
+
+ defer db.Close()
+
+ row := db.QueryRow("SELECT * FROM boxes WHERE id = ?", id)
+ err = row.Scan(&box.ID, &box.Name, &box.Notes, &box.Description, &box.Stage, &box.Category)
+
+ return
+}
+
+func GetBoxItemByID(id int) (BoxItem, error) {
+ db, err := CreateClient()
+ if err != nil {
+ return BoxItem{}, err
+ }
+
+ defer db.Close()
+
+ row := db.QueryRow("SELECT * FROM box_items WHERE id = ?", id)
+
+ boxItem := BoxItem{}
+
+ err = row.Scan(&boxItem.ID, &boxItem.BoxID, &boxItem.ItemID)
+
+ return boxItem, err
+}
+
+func GetBoxItemsByBoxID(boxID int) ([]BoxItemWithItemInfo, error) {
+ db, err := CreateClient()
+ if err != nil {
+ return nil, err
+ }
+
+ defer db.Close()
+
+ // get all rows from box_items where boxid = boxID
+ // also get the item info for each item
+ rows, err := db.Query(
+ "SELECT id, items.name, items.stage, items.category, items.description, items.notes FROM boxitems JOIN items ON itemid=items.id WHERE boxid = ?",
+ boxID)
+
+ if err != nil {
+ return nil, err
+ }
+
+ defer rows.Close()
+
+ result := []BoxItemWithItemInfo{}
+
+ for rows.Next() {
+ boxItem := BoxItemWithItemInfo{}
+ if err = rows.Scan(&boxItem.ID, &boxItem.Name, &boxItem.Stage, &boxItem.Category, &boxItem.Description, &boxItem.Notes); err != nil {
+ return nil, err
+ }
+
+ result = append(result, boxItem)
+ }
+
+ return result, nil
+}
+
+func PostItem(item Item) (int64, error) {
+ db, err := CreateClient()
+ if err != nil {
+ return -1, err
+ }
+
+ defer db.Close()
+
+ query := `INSERT INTO items (name, notes, description, stage, category)
+ VALUES (?, ?, ?, ?, ?)`
+
+ result, err := db.Exec(query, item.Name, item.Notes, item.Description, item.Stage, item.Category)
+
+ if err != nil {
+ return -1, err
+ }
+
+ return result.LastInsertId()
+}
+
+func PostBox(box Box) (int64, error) {
+ db, err := CreateClient()
+ if err != nil {
+ return -1, err
+ }
+
+ defer db.Close()
+
+ query := `INSERT INTO boxes (name, notes, description, stage, category) VALUES (?, ?, ?, ?, ?)`
+
+ result, err := db.Exec(query, box.Name, box.Notes, box.Description, box.Stage, box.Category)
+
+ if err != nil {
+ return -1, err
+ }
+
+ return result.LastInsertId()
+}
+
+func PostBoxItem(boxItem BoxItem) (int64, error) {
+ db, err := CreateClient()
+ if err != nil {
+ return -1, err
+ }
+
+ defer db.Close()
+
+ query := `INSERT INTO box_items (boxid, item_id) VALUES (?, ?)`
+
+ result, err := db.Exec(query, boxItem.BoxID, boxItem.ItemID)
+
+ if err != nil {
+ return -1, err
+ }
+
+ return result.LastInsertId()
+}
+
+func PutItem(item Item) (int64, error) {
+ db, err := CreateClient()
+ if err != nil {
+ return -1, err
+ }
+
+ defer db.Close()
+
+ query := `UPDATE items SET name = ?, notes = ?, description = ?, stage = ?, category = ? WHERE id = ?`
+
+ result, err := db.Exec(query, item.Name, item.Notes, item.Description, item.Stage, item.Category, item.ID)
+
+ if err != nil {
+ return -1, err
+ }
+
+ return result.RowsAffected()
+}
+
+func PutBox(box Box) (int64, error) {
+ db, err := CreateClient()
+ if err != nil {
+ return -1, err
+ }
+
+ defer db.Close()
+
+ query := `UPDATE boxes SET name = ?, notes = ?, description = ?, stage = ?, category = ? WHERE id = ?`
+
+ result, err := db.Exec(query, box.Name, box.Notes, box.Description, box.Stage, box.Category, box.ID)
+
+ if err != nil {
+ return -1, err
+ }
+
+ return result.RowsAffected()
+}
+
+func PutBoxItem(boxItem BoxItem) (int64, error) {
+ db, err := CreateClient()
+ if err != nil {
+ return -1, err
+ }
+
+ defer db.Close()
+
+ query := `UPDATE box_items SET boxid = ?, item_id = ? WHERE id = ?`
+
+ result, err := db.Exec(query, boxItem.BoxID, boxItem.ItemID, boxItem.ID)
+
+ if err != nil {
+ return -1, err
+ }
+
+ return result.RowsAffected()
+}
+
+func DeleteItem(id int) (int64, error) {
+ db, err := CreateClient()
+ if err != nil {
+ return -1, err
+ }
+
+ defer db.Close()
+
+ query := `DELETE FROM items WHERE id = ?`
+
+ result, err := db.Exec(query, id)
+
+ if err != nil {
+ return -1, err
+ }
+
+ return result.RowsAffected()
+}
+
+func DeleteBox(id int) (int64, error) {
+ db, err := CreateClient()
+ if err != nil {
+ return -1, err
+ }
+
+ defer db.Close()
+
+ query := `DELETE FROM boxes WHERE id = ?`
+
+ result, err := db.Exec(query, id)
+
+ if err != nil {
+ return -1, err
+ }
+
+ return result.RowsAffected()
+}
+
+func DeleteBoxItem(id int) (int64, error) {
+ db, err := CreateClient()
+ if err != nil {
+ return -1, err
+ }
+
+ defer db.Close()
+
+ query := `DELETE FROM box_items WHERE id = ?`
+
+ result, err := db.Exec(query, id)
+
+ if err != nil {
+ return -1, err
+ }
+
+ return result.RowsAffected()
+}
diff --git a/main.go b/main.go
index bf8e72d..1e852d5 100644
--- a/main.go
+++ b/main.go
@@ -23,9 +23,6 @@ var (
//go:embed all:templates/*
templateFS embed.FS
- //go:embed css/output.css
- css embed.FS
-
//parsed templates
html *template.Template
)
@@ -45,14 +42,38 @@ func main() {
//add routes
router := http.NewServeMux()
- // router.Handle("/css/output.css", http.FileServer(http.FS(css)))
- // router.Handle("/company/add", web.Action(companyAdd))
- // router.Handle("/company/add/", web.Action(companyAdd))
+ itemActions := routes.Items(html)
+ boxActions := routes.Boxes(html)
+ boxItemActions := routes.BoxItems(html)
+
+
+
+ router.Handle("/items/edit", web.Action(itemActions.Edit))
+ router.Handle("/items/delete", web.Action(itemActions.Delete))
+ router.Handle("/items/save", web.Action(itemActions.Save))
+ router.Handle("/items/edit/", web.Action(itemActions.Edit))
+ router.Handle("/items/delete/", web.Action(itemActions.Delete))
+ router.Handle("/items/delete/:id", web.Action(itemActions.Delete))
+ router.Handle("/items/save/", web.Action(itemActions.Save))
+ router.Handle("/items/save/:id", web.Action(itemActions.Save))
+
+ router.Handle("/items/add", web.Action(itemActions.Post))
+ router.Handle("/items/add/", web.Action(itemActions.Post))
+
+ router.Handle("/box-items", web.Action(boxItemActions.Get))
+ router.Handle("/box-items/", web.Action(boxItemActions.Get))
+ router.Handle("/box-items/:id", web.Action(boxItemActions.Get))
+
+ router.Handle("/items", web.Action(itemActions.Get))
+ router.Handle("/boxes", web.Action(boxActions.GetAll))
+ router.Handle("/items/", web.Action(itemActions.Get))
+ router.Handle("/items/:id", web.Action(itemActions.Get))
+ router.Handle("/boxes/", web.Action(boxActions.GetAll))
+ router.Handle("/boxes/:id", web.Action(boxActions.GetAll))
router.Handle("/", web.Action(routes.HomePage))
- router.Handle("/items", web.Action(routes.Items(html).GetAll))
- router.Handle("/boxes", web.Action(routes.Boxes(html).GetAll))
+ router.Handle("/index.html", web.Action(routes.HomePage))
//logging/tracing
nextRequestID := func() string {
diff --git a/routes/base.go b/routes/base.go
deleted file mode 100644
index f304360..0000000
--- a/routes/base.go
+++ /dev/null
@@ -1,45 +0,0 @@
-package routes
-
-import (
- "net/http"
-
- "github.com/jritsema/gotoolbox/web"
-)
-
-type Entity int
-
-const (
- Item Entity = iota
- Box
- BoxItem
-)
-
-type RouterActions struct {
- GetAll func(r *http.Request) *web.Response
- GetByID func(r *http.Request) *web.Response
- Post func(r *http.Request) *web.Response
- Put func(r *http.Request) *web.Response
- Delete func(r *http.Request) *web.Response
-}
-
-type Router struct {
- Entity Entity
- Path string
- GetAll func(r *http.Request) *web.Response
- GetByID func(r *http.Request) *web.Response
- Post func(r *http.Request) *web.Response
- Put func(r *http.Request) *web.Response
- Delete func(r *http.Request) *web.Response
-}
-
-func NewRouter(entity Entity, path string, actions RouterActions) *Router {
- return &Router{
- Entity: entity,
- Path: path,
- GetAll: actions.GetAll,
- GetByID: actions.GetByID,
- Post: actions.Post,
- Put: actions.Put,
- Delete: actions.Delete,
- }
-}
diff --git a/routes/boxItems.go b/routes/boxItems.go
new file mode 100644
index 0000000..a91329e
--- /dev/null
+++ b/routes/boxItems.go
@@ -0,0 +1,100 @@
+package routes
+
+import (
+ "html/template"
+ "net/http"
+ "strconv"
+
+ "github.com/innocuous-symmetry/moving-mgmt/db"
+ "github.com/jritsema/gotoolbox/web"
+)
+
+type BoxItemActions struct {
+ Get func(r *http.Request) *web.Response
+ GetAll func(r *http.Request) *web.Response
+ GetByID func(r *http.Request) *web.Response
+ GetByBoxID func(r *http.Request) *web.Response
+}
+
+func BoxItems(_html *template.Template) *BoxItemActions {
+ html = _html
+
+ return &BoxItemActions{
+ Get: BoxItemsHandler,
+ GetAll: nil,
+ GetByID: nil,
+ }
+}
+
+func BoxItemsHandler(r *http.Request) *web.Response {
+ switch r.Method {
+
+ case http.MethodGet:
+ if r.URL.Query().Has("boxid") {
+ return GetBoxItemsByBoxID(r)
+ }
+
+ _, count := web.PathLast(r)
+ if count == 1 {
+ return GetAllBoxItems(r)
+ } else {
+ return GetBoxItemByID(r)
+ }
+ default:
+ return nil
+
+ }
+}
+
+func GetAllBoxItems(_ *http.Request) *web.Response {
+ items, err := db.GetAllBoxItems()
+ if err != nil {
+ return web.Error(
+ http.StatusBadRequest,
+ err,
+ nil,
+ )
+ }
+
+ return web.HTML(
+ http.StatusOK,
+ html,
+ "box-items/box-item-list.html",
+ items,
+ nil,
+ )
+}
+
+func GetBoxItemsByBoxID(r *http.Request) *web.Response {
+ boxID := r.URL.Query().Get("boxid")
+
+ if id, err := strconv.ParseInt(boxID, 10, 64); err != nil {
+ return web.Error(
+ http.StatusBadRequest,
+ err,
+ nil,
+ )
+ } else {
+ items, err := db.GetBoxItemsByBoxID(int(id))
+ if err != nil {
+ return web.Error(
+ http.StatusNotFound,
+ err,
+ nil,
+ )
+ }
+
+ return web.HTML(
+ http.StatusOK,
+ html,
+ "box-items/box-item-list.html",
+ items,
+ nil,
+ )
+
+ }
+}
+
+func GetBoxItemByID(_ *http.Request) *web.Response {
+ return nil
+}
diff --git a/routes/boxes.go b/routes/boxes.go
index c2a2414..e4b0441 100644
--- a/routes/boxes.go
+++ b/routes/boxes.go
@@ -8,20 +8,24 @@ import (
"github.com/jritsema/gotoolbox/web"
)
-func Boxes(_html *template.Template) *Router {
+type BoxActions struct {
+ GetAll func(r *http.Request) *web.Response
+ GetByID func(r *http.Request) *web.Response
+ Post func(r *http.Request) *web.Response
+ Put func(r *http.Request) *web.Response
+ Delete func(r *http.Request) *web.Response
+}
+
+func Boxes(_html *template.Template) *BoxActions {
html = _html
- return NewRouter(
- Box,
- "/boxes",
- RouterActions{
- GetAll: GetAllBoxes,
- GetByID: nil,
- Post: nil,
- Put: nil,
- Delete: nil,
- },
- )
+ return &BoxActions{
+ GetAll: GetAllBoxes,
+ GetByID: nil,
+ Post: nil,
+ Put: nil,
+ Delete: nil,
+ }
}
func GetAllBoxes(_ *http.Request) *web.Response {
@@ -33,7 +37,7 @@ func GetAllBoxes(_ *http.Request) *web.Response {
return web.HTML(
http.StatusOK,
html,
- "entity-list.html",
+ "boxes/box-list.html",
result,
nil,
)
diff --git a/routes/items.go b/routes/items.go
index 1f4018f..c426f1c 100644
--- a/routes/items.go
+++ b/routes/items.go
@@ -9,20 +9,38 @@ import (
"github.com/jritsema/gotoolbox/web"
)
-func Items(_html *template.Template) *Router {
+type ItemActions struct {
+ Get func(r *http.Request) *web.Response
+ GetAll func(r *http.Request) *web.Response
+ Edit func(r *http.Request) *web.Response
+ Delete func(r *http.Request) *web.Response
+ Save func(r *http.Request) *web.Response
+ Post func(r *http.Request) *web.Response
+ Add func(r *http.Request) *web.Response
+}
+
+func Items(_html *template.Template) *ItemActions {
html = _html
- return NewRouter(
- Item,
- "/items",
- RouterActions{
- GetAll: GetAllItems,
- GetByID: nil,
- Post: nil,
- Put: nil,
- Delete: nil,
- },
- )
+ return &ItemActions{
+ Get: Get,
+ GetAll: GetAllItems,
+ Edit: EditItem,
+ Delete: Delete,
+ Save: Put,
+ Post: Post,
+ Add: Add,
+ }
+}
+
+func Get(r *http.Request) *web.Response {
+ _, count := web.PathLast(r)
+
+ if count == 1 {
+ return GetAllItems(r)
+ } else {
+ return GetItemByID(r)
+ }
}
func GetAllItems(_ *http.Request) *web.Response {
@@ -34,20 +52,21 @@ func GetAllItems(_ *http.Request) *web.Response {
return web.HTML(
http.StatusOK,
html,
- "entity-list.html",
+ "items/entity-list.html",
result,
nil,
)
}
-func GetItemByID(r *http.Request) *web.Response {
- var id int
- id, err := strconv.Atoi(r.URL.Query().Get("id"))
+func EditItem(r *http.Request) *web.Response {
+ idFromPath, _ := web.PathLast(r)
+
+ id, err := strconv.ParseInt(idFromPath, 10, 64)
if err != nil {
return web.Error(http.StatusBadRequest, err, nil)
}
- result, err := db.GetItemByID(id)
+ result, err := db.GetItemByID(int(id))
if err != nil {
return web.Error(http.StatusInternalServerError, err, nil)
@@ -56,8 +75,168 @@ func GetItemByID(r *http.Request) *web.Response {
return web.HTML(
http.StatusOK,
html,
- "item-by-id.html",
+ "items/entity-edit.html",
result,
nil,
)
}
+
+func GetItemByID(r *http.Request) *web.Response {
+ idFromPath, _ := web.PathLast(r)
+
+ id, err := strconv.ParseInt(idFromPath, 10, 64)
+ if err != nil {
+ return web.Error(http.StatusBadRequest, err, nil)
+ }
+
+ result, err := db.GetItemByID(int(id))
+
+ if err != nil {
+ return web.Error(http.StatusInternalServerError, err, nil)
+ }
+
+ return web.HTML(
+ http.StatusOK,
+ html,
+ "items/entity-row.html",
+ result,
+ nil,
+ )
+}
+
+func Put(r *http.Request) *web.Response {
+ id, _ := web.PathLast(r)
+
+ if err := r.ParseForm(); 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")
+ stage := r.Form.Get("stage")
+ category := r.Form.Get("category")
+ description := r.Form.Get("description")
+ notes := r.Form.Get("notes")
+ // id := r.Form.Get("id")
+
+ item := db.Item{
+ ID: func() int {
+ idInt, err := strconv.ParseInt(id, 10, 64)
+
+ if err != nil {
+ return -1
+ }
+
+ return int(idInt)
+ }(),
+
+ Name: name,
+ Description: &description,
+ Notes: ¬es,
+
+ Stage: func() db.PackingStage {
+ stageInt, _ := strconv.Atoi(stage)
+ return db.PackingStage(stageInt)
+ }(),
+
+ Category: func() db.Category {
+ categoryInt, _ := strconv.Atoi(category)
+ return db.Category(categoryInt)
+ }(),
+ }
+
+ if _, err := db.PutItem(item); err != nil {
+ return web.Error(http.StatusInternalServerError, err, nil)
+ }
+
+ return web.HTML(
+ http.StatusOK,
+ html,
+ "items/entity-row.html",
+ item,
+ nil,
+ )
+}
+
+func Post(r *http.Request) *web.Response {
+ err := r.ParseForm()
+ if err != nil {
+ return web.Error(http.StatusBadRequest, err, nil)
+ }
+
+ name := r.Form.Get("name")
+ stage := r.Form.Get("stage")
+ category := r.Form.Get("category")
+ description := r.Form.Get("description")
+ notes := r.Form.Get("notes")
+
+ item := db.Item{
+ Name: name,
+ Description: &description,
+ Notes: ¬es,
+
+ Stage: func() db.PackingStage {
+ stageInt, _ := strconv.Atoi(stage)
+ return db.PackingStage(stageInt)
+ }(),
+
+ Category: func() db.Category {
+ categoryInt, _ := strconv.Atoi(category)
+ return db.Category(categoryInt)
+ }(),
+ }
+
+ _, err = db.PostItem(item)
+
+ if err != nil {
+ return web.Error(http.StatusInternalServerError, err, nil)
+ }
+
+ return web.HTML(
+ http.StatusOK,
+ html,
+ "items/entity-add-success.html",
+ item,
+ nil,
+ )
+}
+
+func Add(r *http.Request) *web.Response {
+ return web.HTML(
+ http.StatusOK,
+ html,
+ "items/items/entity-add.html",
+ nil,
+ nil,
+ )
+}
+
+func Delete(r *http.Request) *web.Response {
+ idFromPath, _ := web.PathLast(r)
+ id, err := strconv.ParseInt(idFromPath, 10, 64)
+
+ if err != nil {
+ return web.Error(http.StatusBadRequest, err, nil)
+ }
+
+ _, err = db.DeleteItem(int(id))
+
+ if err != nil {
+ return web.Error(http.StatusInternalServerError, err, nil)
+ }
+
+ return web.HTML(
+ http.StatusOK,
+ html,
+ "items/entity-row.html",
+ nil,
+ nil,
+ )
+}
diff --git a/scripts/index.js b/scripts/index.js
new file mode 100644
index 0000000..e69de29
diff --git a/templates/box-items/box-item-list.html b/templates/box-items/box-item-list.html
new file mode 100644
index 0000000..6447658
--- /dev/null
+++ b/templates/box-items/box-item-list.html
@@ -0,0 +1,23 @@
+
+
+
+
+
+ |
+ # |
+ Name |
+ Stage |
+ Category |
+ Description |
+ Notes |
+ |
+
+
+
+ {{range .}}
+ {{ template "box-items/box-item-row.html" . }}
+ {{end}}
+
+
+ |
+
diff --git a/templates/box-items/box-item-row.html b/templates/box-items/box-item-row.html
new file mode 100644
index 0000000..ddf60c3
--- /dev/null
+++ b/templates/box-items/box-item-row.html
@@ -0,0 +1,10 @@
+
+ | {{ .ID }} |
+ {{ .Name }} |
+
+ {{ template "components/parsed-packing-stage.html" .Stage }}
+ {{ template "components/parsed-category.html" .Category }}
+
+ {{ .Description }} |
+ {{ .Notes }} |
+
diff --git a/templates/boxes.html b/templates/boxes/box-list.html
similarity index 64%
rename from templates/boxes.html
rename to templates/boxes/box-list.html
index 2c8eed5..6cfa833 100644
--- a/templates/boxes.html
+++ b/templates/boxes/box-list.html
@@ -1,35 +1,25 @@
-
+
Processing...
-
+ |
# |
Name |
Stage |
Category |
Description |
Notes |
+ |
{{range .}}
- {{ template "entity-row.html". }}
+ {{ template "boxes/box-row.html" . }}
{{end}}
diff --git a/templates/boxes/box-row.html b/templates/boxes/box-row.html
new file mode 100644
index 0000000..44f121f
--- /dev/null
+++ b/templates/boxes/box-row.html
@@ -0,0 +1,40 @@
+
+ |
+
+ |
+ {{.ID}} |
+ {{.Name}} |
+
+ {{ template "components/parsed-packing-stage.html" .ID }}
+
+ {{ template "components/parsed-category.html" .ID }}
+
+ {{ if .Description }}
+ {{.Description}} |
+ {{ else }}
+ ... |
+ {{ end }}
+
+ {{ if .Notes }}
+ {{.Notes}} |
+ {{ else }}
+ ... |
+ {{ end }}
+
+
+
+ |
diff --git a/templates/companies.html b/templates/companies.html
deleted file mode 100644
index cbf5b65..0000000
--- a/templates/companies.html
+++ /dev/null
@@ -1,38 +0,0 @@
-
-
Processing...
-
-
-
-
-
-
-
-
-
-
- | # |
- Company |
- Contact |
- Country |
-
-
-
- {{range .}}
- {{ template "row.html". }}
- {{end}}
-
-
-
-
-
-
-
diff --git a/templates/company-add.html b/templates/company-add.html
deleted file mode 100644
index 3fab4c8..0000000
--- a/templates/company-add.html
+++ /dev/null
@@ -1,6 +0,0 @@
-
- {{ template "row-add.html" . }}
- {{range .}}
- {{ template "row.html". }}
- {{end}}
-
diff --git a/templates/components/add-category.html b/templates/components/add-category.html
new file mode 100644
index 0000000..dfc29c9
--- /dev/null
+++ b/templates/components/add-category.html
@@ -0,0 +1,8 @@
+
diff --git a/templates/components/add-packing-stage.html b/templates/components/add-packing-stage.html
new file mode 100644
index 0000000..c93db57
--- /dev/null
+++ b/templates/components/add-packing-stage.html
@@ -0,0 +1,7 @@
+
diff --git a/templates/components/edit-category.html b/templates/components/edit-category.html
new file mode 100644
index 0000000..11b293b
--- /dev/null
+++ b/templates/components/edit-category.html
@@ -0,0 +1,8 @@
+
diff --git a/templates/components/edit-packing-stage.html b/templates/components/edit-packing-stage.html
new file mode 100644
index 0000000..3088d46
--- /dev/null
+++ b/templates/components/edit-packing-stage.html
@@ -0,0 +1,7 @@
+
diff --git a/templates/components/parsed-category.html b/templates/components/parsed-category.html
new file mode 100644
index 0000000..5a892dd
--- /dev/null
+++ b/templates/components/parsed-category.html
@@ -0,0 +1,27 @@
+
+ {{ if eq . 0 }}
+
+ Bedroom
+
+ {{ else if eq . 1 }}
+
+ Bathroom
+
+ {{ else if eq . 2 }}
+
+ Kitchen
+
+ {{ else if eq . 3 }}
+
+ Office
+
+ {{ else if eq . 4 }}
+
+ Living Room
+
+ {{ else }}
+
+ Other
+
+ {{ end }}
+ |
diff --git a/templates/components/parsed-packing-stage.html b/templates/components/parsed-packing-stage.html
new file mode 100644
index 0000000..f4342ba
--- /dev/null
+++ b/templates/components/parsed-packing-stage.html
@@ -0,0 +1,23 @@
+
+ {{ if eq . 0 }}
+
+ Essentials
+
+ {{ else if eq . 1 }}
+
+ Stage One
+
+ {{ else if eq . 2 }}
+
+ Stage Two
+
+ {{ else if eq . 3 }}
+
+ Stage Three
+
+ {{ else }}
+
+ Determine Later
+
+ {{ end }}
+ |
diff --git a/templates/entity-row.html b/templates/entity-row.html
deleted file mode 100644
index 9469adb..0000000
--- a/templates/entity-row.html
+++ /dev/null
@@ -1,8 +0,0 @@
-
- | {{.ID}} |
- {{.Name}} |
- {{.Stage}} |
- {{.Category}} |
- {{.Description}} |
- {{.Notes}} |
-
diff --git a/templates/index.html b/templates/index.html
index e7d8f42..6a38143 100644
--- a/templates/index.html
+++ b/templates/index.html
@@ -4,13 +4,13 @@
+
Mikayla's Move Manager
-
-
Go + HTMX + Tailwind
+
-
+
Mikayla's Move Manager
-
Items
+
Items
- {{ template "entity-list.html" . }}
+ {{ template "items/entity-list.html" . }}
+
+