fix: send URL-encoded form data instead of multipart, show errors inline, default empty date to today
Build and Deploy / build-and-deploy (push) Successful in 15m46s
Build and Deploy / build-and-deploy (push) Successful in 15m46s
This commit is contained in:
+11
-5
@@ -658,11 +658,13 @@ cookLogJs =
|
||||
, "var form = document.getElementById('roux-record-form');"
|
||||
, "var dateInput = document.getElementById('roux-record-date');"
|
||||
, "var commentInput = document.getElementById('roux-record-comment');"
|
||||
, "var errorEl = document.getElementById('roux-record-error');"
|
||||
, "if (!btn || !modal || !form) return;"
|
||||
, ""
|
||||
, "function showModal() {"
|
||||
, " dateInput.value = new Date().toISOString().slice(0,10);"
|
||||
, " commentInput.value = '';"
|
||||
, " errorEl.style.display = 'none';"
|
||||
, " modal.style.display = 'block';"
|
||||
, " dateInput.focus();"
|
||||
, "}"
|
||||
@@ -681,20 +683,23 @@ cookLogJs =
|
||||
, ""
|
||||
, "form.addEventListener('submit', async function(e) {"
|
||||
, " e.preventDefault();"
|
||||
, " var date = dateInput.value;"
|
||||
, " var comment = commentInput.value;"
|
||||
, " var filename = btn.dataset.filename;"
|
||||
, " var fd = new FormData(form);"
|
||||
, " var body = 'cooked-date=' + encodeURIComponent(date);"
|
||||
, " if (comment) body += '&comment=' + encodeURIComponent(comment);"
|
||||
, " var res = await fetch('/cook-log/' + encodeURIComponent(filename), {"
|
||||
, " method: 'POST',"
|
||||
, " body: fd"
|
||||
, " headers: { 'Content-Type': 'application/x-www-form-urlencoded' },"
|
||||
, " body: body"
|
||||
, " });"
|
||||
, " if (!res.ok) {"
|
||||
, " var err = await res.json();"
|
||||
, " alert(err.error || 'Failed to log cooking');"
|
||||
, " errorEl.textContent = err.error || 'Failed to log cooking';"
|
||||
, " errorEl.style.display = 'block';"
|
||||
, " return;"
|
||||
, " }"
|
||||
, " hideModal();"
|
||||
, " var date = fd.get('cooked-date');"
|
||||
, " var comment = fd.get('comment');"
|
||||
, " var entryDiv = document.createElement('div');"
|
||||
, " entryDiv.style.margin = '0.3rem 0';"
|
||||
, " entryDiv.style.fontSize = '0.9rem';"
|
||||
@@ -983,6 +988,7 @@ renderRecipe filename recipe entries = do
|
||||
H.input ! A.type_ "date" ! A.id "roux-record-date" ! A.name "cooked-date" ! A.required ""
|
||||
H.label ! A.for "roux-record-comment" $ "Comment (optional)"
|
||||
H.textarea ! A.id "roux-record-comment" ! A.name "comment" ! A.placeholder "How did it go?" ! A.maxlength "500" $ ""
|
||||
H.p ! A.id "roux-record-error" ! A.style "color: var(--roux-accent); font-size: 0.8rem; margin: 0 0 0.5rem; display: none;" $ ""
|
||||
H.div ! A.class_ "roux-modal-actions" $ do
|
||||
H.button ! A.type_ "button" ! A.class_ "roux-modal-cancel" ! A.id "roux-modal-cancel" $ "Cancel"
|
||||
H.button ! A.type_ "submit" ! A.class_ "roux-modal-confirm" $ "Log it"
|
||||
|
||||
+22
-15
@@ -26,7 +26,6 @@ import qualified Data.Map.Strict as Map
|
||||
import Data.Text (Text)
|
||||
import qualified Data.Text as T
|
||||
import Data.Text.Encoding (encodeUtf8)
|
||||
import Data.Time.Clock (diffUTCTime, getCurrentTime)
|
||||
|
||||
import qualified Network.HTTP.Types as HTTP
|
||||
import qualified Network.Wai as Wai
|
||||
@@ -48,6 +47,7 @@ import qualified Data.ByteString as BS
|
||||
import Data.Maybe (fromMaybe, mapMaybe)
|
||||
import qualified Data.Text.Encoding as TE
|
||||
import Data.Time.Calendar (Day, fromGregorianValid)
|
||||
import Data.Time.Clock (diffUTCTime, getCurrentTime, utctDay)
|
||||
import qualified Data.Time.Format as Time
|
||||
import qualified Database.SQLite.Simple as SQL
|
||||
import Roux.Config (AnthropicConfig (..), RouxConfig (..))
|
||||
@@ -672,22 +672,29 @@ handleCookLogPost db filename request respond = do
|
||||
let params = parseFormBody body
|
||||
dateStr = fromMaybe "" (lookup "cooked-date" params)
|
||||
comment = lookup "comment" params
|
||||
let doInsert d = do
|
||||
_ <- CookLog.insertEntry db filename d comment
|
||||
respond $
|
||||
Wai.responseLBS
|
||||
HTTP.status200
|
||||
[("Content-Type", "application/json")]
|
||||
(LB.fromStrict (encodeUtf8 "{\"ok\":true}"))
|
||||
case parseDate dateStr of
|
||||
Just day -> do
|
||||
_ <- CookLog.insertEntry db filename day comment
|
||||
let resp =
|
||||
Wai.responseLBS
|
||||
HTTP.status200
|
||||
[("Content-Type", "application/json")]
|
||||
(LB.fromStrict (encodeUtf8 "{\"ok\":true}"))
|
||||
respond resp
|
||||
Just d -> doInsert d
|
||||
Nothing ->
|
||||
let resp =
|
||||
Wai.responseLBS
|
||||
HTTP.status400
|
||||
[("Content-Type", "application/json")]
|
||||
(LB.fromStrict (encodeUtf8 "{\"error\":\"Invalid date format\"}"))
|
||||
in respond resp
|
||||
if T.null dateStr
|
||||
then getCurrentDay >>= doInsert
|
||||
else
|
||||
let resp =
|
||||
Wai.responseLBS
|
||||
HTTP.status400
|
||||
[("Content-Type", "application/json")]
|
||||
(LB.fromStrict (encodeUtf8 "{\"error\":\"Invalid date format\"}"))
|
||||
in respond resp
|
||||
|
||||
-- | Get today's date.
|
||||
getCurrentDay :: IO Day
|
||||
getCurrentDay = utctDay <$> getCurrentTime
|
||||
|
||||
-- | Parse a YYYY-MM-DD date string.
|
||||
parseDate :: Text -> Maybe Day
|
||||
|
||||
Reference in New Issue
Block a user